Update DB schema to include an ID and split overview and content. Progressing on ContentEditor with the ID fixing many issues. Adding modal and sync features.

This commit is contained in:
2025-03-31 01:19:58 +02:00
parent 227d7224e5
commit 1d41514b26
48 changed files with 922 additions and 1156 deletions

View File

@@ -1,10 +1,10 @@
import type { SitemapUrlInput } from '#sitemap/types'
import { explorerContentTable } from '~/db/schema';
import { projectFilesTable as files } from '~/db/schema';
import useDatabase from '~/composables/useDatabase';
export default defineSitemapEventHandler(() => {
const db = useDatabase();
const pages = db.select({ path: explorerContentTable.path, lastMod: explorerContentTable.timestamp, navigable: explorerContentTable.navigable, private: explorerContentTable.private, type: explorerContentTable.type }).from(explorerContentTable).all();
const pages = db.select({ path: files.path, lastMod: files.timestamp, navigable: files.navigable, private: files.private, type: files.type }).from(files).all();
return pages.filter(e => e.type !== 'folder' && e.navigable && !e.private && e.path.split('/').map((_, i, a) => a.slice(0, i).join('/')).every(p => !pages.find(_p => _p.path === p)?.private)).map(e => ({
loc: `/explore/${encodeURIComponent(e.path)}`,

View File

@@ -1,7 +1,6 @@
import { ne, sql } from 'drizzle-orm';
import useDatabase from '~/composables/useDatabase';
import { explorerContentTable } from '~/db/schema';
import { hasPermissions } from '~/shared/auth.util';
import { projectFilesTable } from '~/db/schema';
import { hasPermissions } from '#shared/auth.util';
export default defineEventHandler(async (e) => {
const session = await getUserSession(e);
@@ -16,17 +15,15 @@ export default defineEventHandler(async (e) => {
const db = useDatabase();
const content = db.select({
path: explorerContentTable.path,
owner: explorerContentTable.owner,
title: explorerContentTable.title,
type: explorerContentTable.type,
size: sql<number>`CASE WHEN ${explorerContentTable.content} IS NULL THEN 0 ELSE length(${explorerContentTable.content}) END`.as('size'),
navigable: explorerContentTable.navigable,
private: explorerContentTable.private,
order: explorerContentTable.order,
visit: explorerContentTable.visit,
timestamp: explorerContentTable.timestamp,
}).from(explorerContentTable).all();
path: projectFilesTable.path,
owner: projectFilesTable.owner,
title: projectFilesTable.title,
type: projectFilesTable.type,
navigable: projectFilesTable.navigable,
private: projectFilesTable.private,
order: projectFilesTable.order,
timestamp: projectFilesTable.timestamp,
}).from(projectFilesTable).all();
content.sort((a, b) => {
return a.path.split('/').length - b.path.split('/').length;

View File

@@ -1,6 +1,4 @@
import { sql } from 'drizzle-orm';
import useDatabase from '~/composables/useDatabase';
import { userSessionsTable } from '~/db/schema';
import { hasPermissions } from '~/shared/auth.util';
export default defineEventHandler(async (e) => {

View File

@@ -93,8 +93,6 @@ export default defineEventHandler(async (e): Promise<Return> => {
}
}) as UserSessionRequired);
db.update(usersDataTable).set({ logCount: user.data.logCount + 1 }).where(eq(usersDataTable.id, user.id)).run();
setResponseStatus(e, 201);
return { success: true, session: data };
}

View File

@@ -71,7 +71,7 @@ export default defineEventHandler(async (e): Promise<Return> => {
db.insert(usersDataTable).values({ id: sql.placeholder('id') }).prepare().run({ id: id.id });
logSession(e, await setUserSession(e, { user: { id: id.id, username: body.data.username, email: body.data.email, state: 0, signin: new Date(), permissions: [], lastTimestamp: new Date(), logCount: 1 } }) as UserSessionRequired);
logSession(e, await setUserSession(e, { user: { id: id.id, username: body.data.username, email: body.data.email, state: 0, signin: new Date(), permissions: [], lastTimestamp: new Date() } }) as UserSessionRequired);
const emailId = Bun.hash('register' + id.id + hash, Date.now());
const timestamp = Date.now() + 1000 * 60 * 60;

View File

@@ -71,7 +71,7 @@ export default defineEventHandler(async (e): Promise<Return> => {
db.insert(usersDataTable).values({ id: sql.placeholder('id') }).prepare().run({ id: id.id });
logSession(e, await setUserSession(e, { user: { id: id.id, username: body.data.username, email: body.data.email, state: 0, signin: new Date(), permissions: [], lastTimestamp: new Date(), logCount: 1 } }) as UserSessionRequired);
logSession(e, await setUserSession(e, { user: { id: id.id, username: body.data.username, email: body.data.email, state: 0, signin: new Date(), permissions: [], lastTimestamp: new Date() } }) as UserSessionRequired);
await runTask('mail', {
payload: {

View File

@@ -1,37 +0,0 @@
import useDatabase from '~/composables/useDatabase';
import { explorerContentTable } from '~/db/schema';
import { schema } from '~/schemas/file';
import { parsePath } from '~/shared/general.util';
export default defineEventHandler(async (e) => {
const body = await readValidatedBody(e, schema.safeParse);
if(!body.success)
{
setResponseStatus(e, 403);
throw body.error;
}
const db = useDatabase();
const buffer = Buffer.from(convertToStorableLinks(body.data.content, db.select({ path: explorerContentTable.path }).from(explorerContentTable).all().map(e => e.path)), 'utf-8');
const content = db.insert(explorerContentTable).values({ ...body.data, content: buffer }).onConflictDoUpdate({ target: explorerContentTable.path, set: { ...body.data, content: buffer, timestamp: new Date() } });
if(content !== undefined)
{
return content;
}
setResponseStatus(e, 404);
return;
});
export function convertToStorableLinks(content: string, path: string[]): string
{
return content.replaceAll(/!?\[\[([^\[\]\|\#]+)?(#+[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/g, (e: string, a1?: string, a2?: string , a3?: string) => {
const parsed = parsePath(a1 ?? '%%%%----%%%%----%%%%');
const replacer = path.find(e => e.endsWith(parsed));
const value = `[[${a1 ? (replacer ?? '') : ''}${a2 ?? ''}${(!a3 && a1 && replacer !== parsed ? '|' + a1 : a3) ?? ''}]]`;
return value;
});
}

View File

@@ -0,0 +1,47 @@
import { eq, sql } from 'drizzle-orm';
import useDatabase from '~/composables/useDatabase';
import { projectFilesTable as files, projectContentTable as content } from '~/db/schema';
export default defineEventHandler(async (e) => {
try
{
const id = getRouterParam(e, "id") ?? '';
if(!id)
{
setResponseStatus(e, 404);
return;
}
const db = useDatabase();
const data = db.select({ content: sql<string>`cast(${content.content} as TEXT)`.as('content'), private: files.private, owner: files.owner, }).from(content).leftJoin(files, eq(content.id, files.id)).where(eq(content.id, id)).get();
if(data && data.content)
{
const session = await getUserSession(e);
if(!session || !session.user || session.user.id !== data.owner)
{
if(data.private)
{
setResponseStatus(e, 404);
return;
}
else
{
return data.content.replace(/%%(.+?)%%/g, "");
}
}
return data.content;
}
setResponseStatus(e, 404);
return;
}
catch(_e)
{
console.error(_e);
setResponseStatus(e, 500);
return;
}
});

View File

@@ -0,0 +1,43 @@
import useDatabase from '~/composables/useDatabase';
import { hasPermissions } from '#shared/auth.util';
import { projectContentTable, projectFilesTable } from '~/db/schema';
import { eq } from 'drizzle-orm';
export default defineEventHandler(async (e) => {
const { user } = await getUserSession(e);
if(!user || !hasPermissions(user.permissions, ['admin', 'editor']))
{
throw createError({ statusCode: 401, statusText: 'Unauthorized' });
}
try
{
const id = getRouterParam(e, "id") ?? '';
const body = await readRawBody(e);
if(!id)
{
setResponseStatus(e, 404);
return;
}
const db = useDatabase();
const item = db.select({ id: projectFilesTable.id }).from(projectFilesTable).where(eq(projectFilesTable.id, id)).get();
if(!item)
{
setResponseStatus(e, 404);
return;
}
db.insert(projectContentTable).values({ id: id, content: body }).onConflictDoUpdate({ set: { content: body }, target: projectContentTable.id }).run();
db.update(projectFilesTable).set({ timestamp: new Date() }).where(eq(projectFilesTable.id, id)).run()
}
catch(_e)
{
console.error(_e);
setResponseStatus(e, 500);
return;
}
});

View File

@@ -1,76 +0,0 @@
import { eq, sql } from 'drizzle-orm';
import useDatabase from '~/composables/useDatabase';
import { explorerContentTable } from '~/db/schema';
import { Content } from '~/shared/content.util';
export default defineEventHandler(async (e) => {
try
{
const path = decodeURIComponent(getRouterParam(e, "path") ?? '');
const query = getQuery(e);
if(!path)
{
setResponseStatus(e, 404);
return;
}
const db = useDatabase();
const content = db.select({
'content': sql<string>`cast(${explorerContentTable.content} as TEXT)`.as('content'),
'private': explorerContentTable.private,
'type': explorerContentTable.type,
'owner': explorerContentTable.owner,
'visit': explorerContentTable.visit,
}).from(explorerContentTable).where(eq(explorerContentTable.path, sql.placeholder('path'))).prepare().get({ path });
if(content != undefined && content.content != undefined)
{
const session = await getUserSession(e);
if(!session || !session.user || session.user.id !== content.owner)
{
if(content.private)
{
setResponseStatus(e, 404);
return;
}
else
{
content.content = content.content.replace(/%%(.+)%%/g, "");
}
}
if(query?.type === 'view')
{
db.update(explorerContentTable).set({ visit: content.visit + 1 }).where(eq(explorerContentTable.path, path)).run();
}
if(query?.type === 'editing')
{
content.content = convertFromStorableLinks(content.content);
}
return Content.fromString(content as any, content.content);
}
console.log(content);
setResponseStatus(e, 404);
return;
}
catch(_e)
{
console.error(_e);
setResponseStatus(e, 500);
return;
}
});
export function convertFromStorableLinks(content: string): string
{
/*return content.replaceAll(/!?\[\[([^\[\]\|\#]+)?(#+[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/g, (e: string, a1?: string, a2?: string , a3?: string) => {
const parsed = parsePath(a1 ?? '%%%%----%%%%----%%%%');
const replacer = path.find(e => e.endsWith(parsed)) ?? parsed;
const value = `[[${replacer}${a2 ?? ''}${(!a3 && replacer !== parsed ? '|' + a1 : a3) ?? ''}]]`;
return value;
});*/
return content;
}

View File

@@ -1,13 +1,11 @@
import useDatabase from '~/composables/useDatabase';
import { getTableColumns } from 'drizzle-orm';
import { explorerContentTable } from '~/db/schema';
import { projectFilesTable } from '~/db/schema';
export default defineEventHandler(async (e) => {
const { user } = await getUserSession(e);
const db = useDatabase();
const { content: _, ...columns } = getTableColumns(explorerContentTable);
const content = db.select(columns).from(explorerContentTable).all();
const content = db.select().from(projectFilesTable).all();
content.sort((a, b) => {
return a.path.split('/').length - b.path.split('/').length;
@@ -36,6 +34,5 @@ export default defineEventHandler(async (e) => {
return content.filter(e => !!e);
}
setResponseStatus(e, 404);
return;
return [];
});

View File

@@ -0,0 +1,76 @@
import useDatabase from '~/composables/useDatabase';
import { hasPermissions } from "#shared/auth.util";
import { eq, sql } from "drizzle-orm";
import { projectFilesTable } from "~/db/schema";
import { Project } from "~/schemas/project";
export default defineEventHandler(async (e) => {
const { user } = await getUserSession(e);
if(!user || !hasPermissions(user.permissions, ['admin', 'editor']))
{
throw createError({ statusCode: 401, statusText: 'Unauthorized' });
}
const body = await readValidatedBody(e, Project.safeParse);
if(!body.success)
{
throw body.error;
}
const db = useDatabase(), items = body.data, blocked: string[] = [];
db.transaction((tx) => {
const data = tx.select({ id: projectFilesTable.id, timestamp: projectFilesTable.timestamp }).from(projectFilesTable).all();
const deletion = tx.delete(projectFilesTable).where(eq(projectFilesTable.id, sql.placeholder('id'))).prepare();
for(let i = 0; i < items.length; i++)
{
const item = items[i];
const index = data.findIndex(e => e.id === item.id);
if(index !== -1)
{
if(data[index].timestamp > new Date(item.timestamp))
{
blocked.push(item.id);
continue;
}
data.splice(index, 1);
}
tx.insert(projectFilesTable).values({
id: item.id,
path: item.path,
owner: user.id,
title: item.title,
type: item.type,
navigable: item.navigable,
private: item.private,
order: item.order,
}).onConflictDoUpdate({
set: {
id: item.id,
path: item.path,
title: item.title,
type: item.type,
navigable: item.navigable,
private: item.private,
order: item.order,
timestamp: new Date(),
},
target: projectFilesTable.id,
}).run();
}
for(let i = 0; i < data.length; i++)
{
deletion.run({ id: data[i].id });
}
});
return blocked;
});

View File

@@ -1,11 +1,11 @@
import { eq, sql } from 'drizzle-orm';
import useDatabase from '~/composables/useDatabase';
import { explorerContentTable } from '~/db/schema';
import { projectFilesTable } from '~/db/schema';
export default defineEventHandler(async (e) => {
const path = decodeURIComponent(getRouterParam(e, "path") ?? '');
export default defineCachedEventHandler(async (e) => {
const id = getRouterParam(e, "id") ?? '';
if(!path)
if(!id)
{
setResponseStatus(e, 404);
return;
@@ -14,13 +14,14 @@ export default defineEventHandler(async (e) => {
const db = useDatabase();
const content = db.select({
'path': explorerContentTable.path,
'owner': explorerContentTable.owner,
'title': explorerContentTable.title,
'type': explorerContentTable.type,
'navigable': explorerContentTable.navigable,
'private': explorerContentTable.private,
}).from(explorerContentTable).where(eq(explorerContentTable.path, sql.placeholder('path'))).prepare().get({ path });
'id': projectFilesTable.id,
'path': projectFilesTable.path,
'owner': projectFilesTable.owner,
'title': projectFilesTable.title,
'type': projectFilesTable.type,
'navigable': projectFilesTable.navigable,
'private': projectFilesTable.private,
}).from(projectFilesTable).where(eq(projectFilesTable.id, sql.placeholder('id'))).prepare().get({ id });
if(content !== undefined)
{
@@ -47,4 +48,4 @@ export default defineEventHandler(async (e) => {
setResponseStatus(e, 404);
return;
});
}, { getKey: (e) => getRouterParam(e, "id") ?? '', });

View File

@@ -1,77 +0,0 @@
import useDatabase from '~/composables/useDatabase';
import { explorerContentTable } from '~/db/schema';
import type { NavigationItem } from '~/schemas/navigation';
export type NavigationTreeItem = NavigationItem & { children?: NavigationTreeItem[] };
export default defineEventHandler(async (e) => {
const { user } = await getUserSession(e);
const db = useDatabase();
const content = db.select({
path: explorerContentTable.path,
type: explorerContentTable.type,
owner: explorerContentTable.owner,
title: explorerContentTable.title,
navigable: explorerContentTable.navigable,
private: explorerContentTable.private,
order: explorerContentTable.order,
}).from(explorerContentTable).all();
content.sort((a, b) => {
return a.path.split('/').length - b.path.split('/').length;
});
if(content.length > 0)
{
const navigation: NavigationTreeItem[] = [];
for(const idx in content)
{
const item = content[idx];
if(!!item.private && (user?.id ?? -1) !== item.owner || !item.navigable)
{
delete content[idx];
continue;
}
const parent = item.path.includes('/') ? item.path.substring(0, item.path.lastIndexOf('/')) : undefined;
if(parent && !content.find(e => e && e.path === parent))
{
delete content[idx];
continue;
}
}
for(const item of content.filter(e => !!e))
{
addChild(navigation, item);
}
return navigation;
}
setResponseStatus(e, 404);
return;
});
function addChild(arr: NavigationTreeItem[], e: NavigationItem): void
{
const parent = arr.find(f => e.path.startsWith(f.path));
if(parent)
{
if(!parent.children)
parent.children = [];
addChild(parent.children, e);
}
else
{
arr.push({ ...e });
arr.sort((a, b) => {
if(a.order !== b.order)
return a.order - b.order;
return a.title.localeCompare(b.title);
});
}
}

View File

@@ -1,80 +0,0 @@
import useDatabase from '~/composables/useDatabase';
import { explorerContentTable } from '~/db/schema';
import type { NavigationItem } from '~/schemas/navigation';
import type { ProjectItem, Project } from '~/schemas/project';
import { hasPermissions } from '~/shared/auth.util';
export default defineEventHandler(async (e) => {
const { user } = await getUserSession(e);
if(!user || !hasPermissions(user.permissions, ['editor', 'admin']))
{
throw createError({
statusCode: 401,
statusMessage: 'Unauthorized',
});
}
const db = useDatabase();
const content = db.select({
path: explorerContentTable.path,
type: explorerContentTable.type,
owner: explorerContentTable.owner,
title: explorerContentTable.title,
navigable: explorerContentTable.navigable,
private: explorerContentTable.private,
order: explorerContentTable.order,
}).from(explorerContentTable).prepare().all();
content.sort((a, b) => {
return a.path.split('/').length - b.path.split('/').length;
});
if(content.length > 0)
{
const project: Project = {
items: [],
}
for(const item of content.filter(e => !!e))
{
addChild(project.items, item);
}
return project;
}
setResponseStatus(e, 404);
return;
});
function addChild(arr: ProjectItem[], e: NavigationItem): void
{
const parent = arr.find(f => e.path.startsWith(f.path));
if(parent)
{
if(!parent.children)
parent.children = [];
addChild(parent.children, e);
}
else
{
arr.push({
path: e.path,
parent: e.path.substring(0, e.path.lastIndexOf('/')),
name: e.path.substring(e.path.lastIndexOf('/') + 1),
title: e.title,
type: e.type,
navigable: e.navigable,
private: e.private,
order: e.order,
});
arr.sort((a, b) => {
if(a.order !== b.order)
return a.order - b.order;
return a.title.localeCompare(b.title);
});
}
}

View File

@@ -1,106 +0,0 @@
import { hasPermissions } from "#shared/auth.util";
import useDatabase from '~/composables/useDatabase';
import { explorerContentTable } from '~/db/schema';
import { project, type ProjectItem } from '~/schemas/project';
import { parsePath } from "#shared/general.util";
import { eq, getTableColumns, sql } from "drizzle-orm";
import type { ExploreContent, TreeItem } from "~/types/content";
import type { TreeItemEditable } from "~/pages/explore/edit/index.vue";
export default defineEventHandler(async (e) => {
const { user } = await getUserSession(e);
if(!user || !hasPermissions(user.permissions, ['admin', 'editor']))
{
throw createError({ statusCode: 401, statusText: 'Unauthorized' });
}
const body = await readValidatedBody(e, project.safeParse);
if(!body.success)
{
throw body.error;
}
const items = buildOrder(body.data) as Array<TreeItemEditable & { match?: number }>;
const db = useDatabase();
const { ...cols } = getTableColumns(explorerContentTable);
const full = db.select(cols).from(explorerContentTable).all() as Record<string, any>[];
for(let i = full.length - 1; i >= 0; i--)
{
const item = items.find(e => (e.path === '' ? [e.parent, parsePath(e.name === '' ? e.title : e.name)].filter(e => !!e).join('/') : e.path) === full[i].path);
if(item)
{
item.match = i;
full[i].include = true;
}
}
db.transaction((tx) => {
for(let i = 0; i < items.length; i++)
{
const item = items[i];
const old = full[item.match!];
const path = [item.parent, parsePath(item.name === '' ? item.title : item.name)].filter(e => !!e).join('/');
tx.insert(explorerContentTable).values({
path: item.path || path,
owner: user.id,
title: item.title,
type: item.type,
navigable: item.navigable,
private: item.private,
order: item.order,
content: item.content ?? old?.content ?? null,
}).onConflictDoUpdate({
set: {
path: path,
title: item.title,
type: item.type,
navigable: item.navigable,
private: item.private,
order: item.order,
timestamp: new Date(),
content: item.content ?? old?.content ?? null,
},
target: explorerContentTable.path,
}).run();
if(item.path !== path && !old)
{
tx.update(explorerContentTable).set({ content: sql`replace(${explorerContentTable.content}, ${sql.placeholder('old')}, ${sql.placeholder('new')})` }).prepare().run({ 'old': item.path, 'new': path });
}
}
for(let i = 0; i < full.length; i++)
{
if(full[i].include !== true)
tx.delete(explorerContentTable).where(eq(explorerContentTable.path, full[i].path)).run();
}
});
return items.map(e => ({
path: e.path,
owner: e.owner,
title: e.title,
type: e.type,
content: e.content,
navigable: e.navigable,
private: e.private,
order: e.order,
visit: e.visit,
timestamp: e.timestamp,
})) as ExploreContent[];
});
function buildOrder(items: ProjectItem[]): ProjectItem[]
{
items.forEach((e, i) => {
e.order = i;
if(e.children) e.children = buildOrder(e.children);
});
return items.flatMap(e => [e, ...(e.children ?? [])]);
}

View File

@@ -1,9 +1,9 @@
import useDatabase from "~/composables/useDatabase";
import { extname, basename } from 'node:path';
import type { FileType } from '~/types/content';
import type { CanvasColor, CanvasContent } from "~/types/canvas";
import { explorerContentTable } from "~/db/schema";
import { convertToStorableLinks } from "../api/file.post";
import type { FileType, ProjectContent } from "#shared/content.util";
import { getID, ID_SIZE } from "#shared/general.util";
import { projectContentTable, projectFilesTable } from "~/db/schema";
const typeMapping: Record<string, FileType> = {
".md": "markdown",
@@ -17,6 +17,7 @@ export default defineTask({
},
async run(event) {
try {
//@ts-ignore
const tree = await $fetch('https://git.peaceultime.com/api/v1/repos/peaceultime/system-aspect/git/trees/master', {
method: 'get',
headers: {
@@ -28,21 +29,23 @@ export default defineTask({
}
}) as { tree: any[] } & Record<string, any>;
const files: typeof explorerContentTable.$inferInsert[] = await Promise.all(tree.tree.filter((e: any) => !e.path.startsWith(".")).map(async (e, i) => {
const files: ProjectContent[] = await Promise.all(tree.tree.filter((e: any) => !e.path.startsWith(".")).map(async (e, i) => {
if(e.type === 'tree')
{
const title = basename(e.path);
const order = /(\d+)\. ?(.+)/gsmi.exec(title);
const path = (e.path as string).split('/').map(f => { const check = /(\d+)\. ?(.+)/gsmi.exec(f); return check && check[2] ? check[2] : f }).join('/');
return {
id: getID(ID_SIZE),
path: path.toLowerCase().replaceAll(" ", "-").normalize("NFD").replace(/[\u0300-\u036f]/g, ""),
order: i,
title: order && order[2] ? order[2] : title,
type: 'folder',
content: null,
owner: '1',
owner: 1,
navigable: true,
private: e.path.startsWith('98.Privé'),
timestamp: new Date(),
}
}
@@ -53,28 +56,26 @@ export default defineTask({
const content = (await $fetch(`https://git.peaceultime.com/api/v1/repos/peaceultime/system-aspect/raw/${encodeURIComponent(e.path)}`));
return {
id: getID(ID_SIZE),
path: (extension === '.md' ? path.replace(extension, '') : path).toLowerCase().replaceAll(" ", "-").normalize("NFD").replace(/[\u0300-\u036f]/g, ""),
order: i,
title: order && order[2] ? order[2] : title,
type: (typeMapping[extension] ?? 'file'),
content: reshapeContent(content as string, typeMapping[extension] ?? 'File'),
owner: '1',
owner: 1,
navigable: true,
private: e.path.startsWith('98.Privé')
private: e.path.startsWith('98.Privé'),
timestamp: new Date(),
}
}));
const pathList = files.map(e => e.path);
files.forEach(e => {
if(e.type !== 'folder' && e.content)
{
e.content = Buffer.from(convertToStorableLinks(e.content.toString('utf-8'), files.map(e => e.path)), 'utf-8');
}
})
const db = useDatabase();
db.delete(explorerContentTable).run();
db.insert(explorerContentTable).values(files).run();
db.transaction(tx => {
db.delete(projectFilesTable).run();
db.insert(projectFilesTable).values(files.map(e => {const { content, ...rest } = e; return rest; })).run();
db.delete(projectContentTable).run();
db.insert(projectContentTable).values(files.map(e => ({ content: e.content ? Buffer.from(e.content as string) : null, id: e.id }))).run();
});
return { result: true };
}
@@ -99,8 +100,8 @@ function reshapeContent(content: string, type: FileType): string | null
return content;
case "canvas":
const data = JSON.parse(content) as CanvasContent;
data.edges.forEach(e => e.color = typeof e.color === 'string' ? getColor(e.color) : undefined);
data.nodes.forEach(e => e.color = typeof e.color === 'string' ? getColor(e.color) : undefined);
data.edges?.forEach(e => e.color = typeof e.color === 'string' ? getColor(e.color) : undefined);
data.nodes?.forEach(e => e.color = typeof e.color === 'string' ? getColor(e.color) : undefined);
return JSON.stringify(data);
default:
case 'folder':

View File

@@ -1,4 +1,4 @@
import useDatabase from "~/composables/useDatabase";
/*import useDatabase from "~/composables/useDatabase";
import type { FileType } from '~/types/content';
import { explorerContentTable } from "~/db/schema";
import { eq, ne } from "drizzle-orm";
@@ -27,4 +27,4 @@ export default defineTask({
return { result: false, error: e };
}
},
})
})*/