/
ncit
/
c4panelmodel
Обзор
Документация
Войти
/
ncit
/
c4panelmodel
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/lib/server/services/export.ts
232 строки
8 KB
ncit
feat: rewrite hooks.server.ts to use Supabase Auth
07 июн 2026, 19:32
07 июн 2026, 19:32
b6162ab
Код
Авторство
О чём код?
import { db } from '../db'; export interface ProjectExport { format: 'c4panel'; version: 1; project: { name: string; description: string | null }; objects: any[]; connections: any[]; diagrams: any[]; flows: any[]; tagGroups: any[]; technologies: any[]; } export async function exportProjectJSON(projectId: string): Promise<ProjectExport> { const project = await db.project.findUniqueOrThrow({ where: { id: projectId } }); const [objects, connections, diagrams, flows, tagGroups, technologies] = await Promise.all([ db.modelObject.findMany({ where: { projectId }, include: { technologies: { include: { technology: true } }, tags: { include: { tag: true } }, links: true } }), db.connection.findMany({ where: { projectId } }), db.diagram.findMany({ where: { projectId }, include: { nodes: true, edges: true } }), db.flow.findMany({ where: { projectId }, include: { steps: true } }), db.tagGroup.findMany({ where: { projectId }, include: { tags: true } }), db.technology.findMany({ where: { projectId } }) ]); return { format: 'c4panel', version: 1, project: { name: project.name, description: project.description }, objects: objects.map((o) => ({ id: o.id, type: o.type, name: o.name, parentId: o.parentId, displayDescription: o.displayDescription, detailedDescription: o.detailedDescription, status: o.status, isExternal: o.isExternal, technologies: o.technologies.map((t) => t.technology.name), tags: o.tags.map((t) => t.tag.name), links: o.links.map((l) => ({ label: l.label, url: l.url })) })), connections: connections.map((c) => ({ id: c.id, sourceId: c.sourceId, targetId: c.targetId, label: c.label, description: c.description, direction: c.direction, lineStyle: c.lineStyle, technology: c.technology })), diagrams: diagrams.map((d) => ({ id: d.id, name: d.name, level: d.level, parentObjectId: d.parentObjectId, nodes: d.nodes.map((n) => ({ objectId: n.objectId, x: n.x, y: n.y, width: n.width, height: n.height })), edges: d.edges.map((e) => ({ connectionId: e.connectionId })) })), flows: flows.map((f) => ({ id: f.id, name: f.name, description: f.description, diagramId: f.diagramId, steps: f.steps.map((s) => ({ id: s.id, type: s.type, order: s.order, label: s.label, description: s.description, sourceObjectId: s.sourceObjectId, targetObjectId: s.targetObjectId, connectionId: s.connectionId })) })), tagGroups: tagGroups.map((g) => ({ name: g.name, allowMultiple: g.allowMultiple, exclusive: g.exclusive, tags: g.tags.map((t) => ({ name: t.name, color: t.color })) })), technologies: technologies.map((t) => ({ name: t.name, category: t.category, iconUrl: t.iconUrl, docUrl: t.docUrl })) }; } /** Import into a NEW project (replace semantics). Returns the created project + its first diagram. */ export async function importProjectJSON( workspaceId: string, userId: string, data: ProjectExport, nameOverride?: string ) { if (data.format !== 'c4panel') throw new Error('Unsupported format'); const project = await db.project.create({ data: { workspaceId, name: nameOverride || data.project.name || 'Imported project', description: data.project.description ?? null } }); // 1. Tag groups + tags. const tagIdByName = new Map<string, string>(); for (const g of data.tagGroups ?? []) { const group = await db.tagGroup.create({ data: { projectId: project.id, name: g.name, allowMultiple: g.allowMultiple ?? true, exclusive: g.exclusive ?? false } }); for (const t of g.tags ?? []) { const tag = await db.tag.create({ data: { groupId: group.id, name: t.name, color: t.color } }); tagIdByName.set(t.name, tag.id); } } // 2. Technologies (project-scoped). const techIdByName = new Map<string, string>(); for (const t of data.technologies ?? []) { const tech = await db.technology.create({ data: { projectId: project.id, name: t.name, category: t.category ?? 'Other', iconUrl: t.iconUrl, docUrl: t.docUrl, isCustom: true } }); techIdByName.set(t.name, tech.id); } // 3. Objects — two passes for parent relationships. const objectIdMap = new Map<string, string>(); const ordered = topoSortByParent(data.objects ?? []); for (const o of ordered) { const created = await db.modelObject.create({ data: { projectId: project.id, type: o.type, name: o.name, parentId: o.parentId ? objectIdMap.get(o.parentId) ?? null : null, displayDescription: o.displayDescription ?? null, detailedDescription: o.detailedDescription ?? null, status: o.status ?? 'LIVE', isExternal: o.isExternal ?? false } }); objectIdMap.set(o.id, created.id); for (const techName of o.technologies ?? []) { let techId = techIdByName.get(techName); if (!techId) { const tech = await db.technology.create({ data: { projectId: project.id, name: techName, category: 'Other', isCustom: true } }); techId = tech.id; techIdByName.set(techName, techId); } await db.objectTechnology.create({ data: { objectId: created.id, technologyId: techId } }).catch(() => {}); } for (const tagName of o.tags ?? []) { const tagId = tagIdByName.get(tagName); if (tagId) await db.objectTag.create({ data: { objectId: created.id, tagId } }).catch(() => {}); } for (const link of o.links ?? []) { await db.objectLink.create({ data: { objectId: created.id, label: link.label, url: link.url } }); } } // 4. Connections. const connIdMap = new Map<string, string>(); for (const c of data.connections ?? []) { const src = objectIdMap.get(c.sourceId); const tgt = objectIdMap.get(c.targetId); if (!src || !tgt) continue; const conn = await db.connection.create({ data: { projectId: project.id, sourceId: src, targetId: tgt, label: c.label ?? null, description: c.description ?? null, direction: c.direction ?? 'OUTGOING', lineStyle: c.lineStyle ?? 'SOLID', technology: c.technology ?? null } }); connIdMap.set(c.id, conn.id); } // 5. Diagrams + nodes + edges. let firstDiagramId: string | null = null; for (const d of data.diagrams ?? []) { const diagram = await db.diagram.create({ data: { projectId: project.id, name: d.name, level: d.level ?? 'CONTEXT', parentObjectId: d.parentObjectId ? objectIdMap.get(d.parentObjectId) ?? null : null } }); if (!firstDiagramId) firstDiagramId = diagram.id; for (const n of d.nodes ?? []) { const objId = objectIdMap.get(n.objectId); if (objId) await db.diagramNode.create({ data: { diagramId: diagram.id, objectId: objId, x: n.x, y: n.y, width: n.width, height: n.height } }).catch(() => {}); } for (const e of d.edges ?? []) { const connId = connIdMap.get(e.connectionId); if (connId) await db.diagramEdge.create({ data: { diagramId: diagram.id, connectionId: connId } }).catch(() => {}); } } if (!firstDiagramId) { const d = await db.diagram.create({ data: { projectId: project.id, name: 'System Context', level: 'CONTEXT' } }); firstDiagramId = d.id; } await db.activity.create({ data: { projectId: project.id, userId, type: 'CREATED', entityType: 'project', entityId: project.id, metadata: { name: project.name, imported: true } } }); return { project, firstDiagramId }; } // Sort objects so parents come before children. function topoSortByParent(objects: any[]): any[] { const byId = new Map(objects.map((o) => [o.id, o])); const result: any[] = []; const visited = new Set<string>(); function visit(o: any) { if (visited.has(o.id)) return; if (o.parentId && byId.has(o.parentId)) visit(byId.get(o.parentId)); visited.add(o.id); result.push(o); } for (const o of objects) visit(o); return result; }