feat(directories): import/export hierarchical data tables with template button

- server/storage/data-tables-core.storage.ts: support parentId in sync operations
- server/routes/data-tables-sync.routes.ts: validate parent references and cycles for hierarchical rows
- client/TableEditor.tsx: export/import _id/_parent_id/_position, add Download Template button
This commit is contained in:
2026-07-12 23:29:35 +03:00
parent 09861fc966
commit d91dd2bd92
3 changed files with 253 additions and 40 deletions

View File

@@ -315,9 +315,9 @@ export class DataTablesCoreStorage extends BotsStorage {
async applyDataTableSync(
tableId: number,
deleted: { id: number }[],
added: { values: string[]; position: number }[],
reordered: { id: number; newPosition: number }[],
positionUpdates: { id: number; position: number }[]
added: { values: string[]; position: number; parentId?: number | null }[],
reordered: { id: number; newPosition: number; parentId?: number | null }[],
positionUpdates: { id: number; position: number; parentId?: number | null }[]
): Promise<void> {
await db.transaction(async (tx) => {
for (const row of deleted) {
@@ -329,18 +329,22 @@ export class DataTablesCoreStorage extends BotsStorage {
for (const row of added) {
await tx
.insert(dataTableRows)
.values({ tableId, values: row.values, position: row.position });
.values({ tableId, values: row.values, position: row.position, parentId: row.parentId ?? null });
}
for (const row of reordered) {
const updates: Partial<typeof dataTableRows.$inferInsert> = { position: row.newPosition, updatedAt: new Date() };
if (row.parentId !== undefined) updates.parentId = row.parentId;
await tx
.update(dataTableRows)
.set({ position: row.newPosition, updatedAt: new Date() })
.set(updates)
.where(and(eq(dataTableRows.id, row.id), eq(dataTableRows.tableId, tableId)));
}
for (const row of positionUpdates) {
const updates: Partial<typeof dataTableRows.$inferInsert> = { position: row.position, updatedAt: new Date() };
if (row.parentId !== undefined) updates.parentId = row.parentId;
await tx
.update(dataTableRows)
.set({ position: row.position, updatedAt: new Date() })
.set(updates)
.where(and(eq(dataTableRows.id, row.id), eq(dataTableRows.tableId, tableId)));
}
});