테이블 노드 위치정보 저장 구현
This commit is contained in:
parent
db509bb3d9
commit
72b0d2ee98
|
|
@ -5327,6 +5327,7 @@ model dataflow_diagrams {
|
||||||
diagram_id Int @id @default(autoincrement())
|
diagram_id Int @id @default(autoincrement())
|
||||||
diagram_name String @db.VarChar(255)
|
diagram_name String @db.VarChar(255)
|
||||||
relationships Json // 모든 관계 정보를 JSON으로 저장
|
relationships Json // 모든 관계 정보를 JSON으로 저장
|
||||||
|
node_positions Json? // 테이블 노드의 캔버스 위치 정보 (JSON 형태)
|
||||||
company_code String @db.VarChar(50)
|
company_code String @db.VarChar(50)
|
||||||
created_at DateTime? @default(now()) @db.Timestamp(6)
|
created_at DateTime? @default(now()) @db.Timestamp(6)
|
||||||
updated_at DateTime? @default(now()) @updatedAt @db.Timestamp(6)
|
updated_at DateTime? @default(now()) @updatedAt @db.Timestamp(6)
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,17 @@ export const getDataflowDiagrams = async (req: Request, res: Response) => {
|
||||||
const page = parseInt(req.query.page as string) || 1;
|
const page = parseInt(req.query.page as string) || 1;
|
||||||
const size = parseInt(req.query.size as string) || 20;
|
const size = parseInt(req.query.size as string) || 20;
|
||||||
const searchTerm = req.query.searchTerm as string;
|
const searchTerm = req.query.searchTerm as string;
|
||||||
const companyCode = (req.query.companyCode as string) || req.headers["x-company-code"] as string || "*";
|
const companyCode =
|
||||||
|
(req.query.companyCode as string) ||
|
||||||
|
(req.headers["x-company-code"] as string) ||
|
||||||
|
"*";
|
||||||
|
|
||||||
const result = await getDataflowDiagramsService(companyCode, page, size, searchTerm);
|
const result = await getDataflowDiagramsService(
|
||||||
|
companyCode,
|
||||||
|
page,
|
||||||
|
size,
|
||||||
|
searchTerm
|
||||||
|
);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -41,7 +49,10 @@ export const getDataflowDiagrams = async (req: Request, res: Response) => {
|
||||||
export const getDataflowDiagramById = async (req: Request, res: Response) => {
|
export const getDataflowDiagramById = async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const diagramId = parseInt(req.params.diagramId);
|
const diagramId = parseInt(req.params.diagramId);
|
||||||
const companyCode = (req.query.companyCode as string) || req.headers["x-company-code"] as string || "*";
|
const companyCode =
|
||||||
|
(req.query.companyCode as string) ||
|
||||||
|
(req.headers["x-company-code"] as string) ||
|
||||||
|
"*";
|
||||||
|
|
||||||
if (isNaN(diagramId)) {
|
if (isNaN(diagramId)) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
|
|
@ -78,9 +89,24 @@ export const getDataflowDiagramById = async (req: Request, res: Response) => {
|
||||||
*/
|
*/
|
||||||
export const createDataflowDiagram = async (req: Request, res: Response) => {
|
export const createDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { diagram_name, relationships, company_code, created_by, updated_by } = req.body;
|
const {
|
||||||
const companyCode = company_code || (req.query.companyCode as string) || req.headers["x-company-code"] as string || "*";
|
diagram_name,
|
||||||
const userId = created_by || updated_by || req.headers["x-user-id"] as string || "SYSTEM";
|
relationships,
|
||||||
|
node_positions,
|
||||||
|
company_code,
|
||||||
|
created_by,
|
||||||
|
updated_by,
|
||||||
|
} = req.body;
|
||||||
|
const companyCode =
|
||||||
|
company_code ||
|
||||||
|
(req.query.companyCode as string) ||
|
||||||
|
(req.headers["x-company-code"] as string) ||
|
||||||
|
"*";
|
||||||
|
const userId =
|
||||||
|
created_by ||
|
||||||
|
updated_by ||
|
||||||
|
(req.headers["x-user-id"] as string) ||
|
||||||
|
"SYSTEM";
|
||||||
|
|
||||||
if (!diagram_name || !relationships) {
|
if (!diagram_name || !relationships) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
|
|
@ -92,6 +118,7 @@ export const createDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
const newDiagram = await createDataflowDiagramService({
|
const newDiagram = await createDataflowDiagramService({
|
||||||
diagram_name,
|
diagram_name,
|
||||||
relationships,
|
relationships,
|
||||||
|
node_positions,
|
||||||
company_code: companyCode,
|
company_code: companyCode,
|
||||||
created_by: userId,
|
created_by: userId,
|
||||||
updated_by: userId,
|
updated_by: userId,
|
||||||
|
|
@ -128,8 +155,12 @@ export const updateDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const diagramId = parseInt(req.params.diagramId);
|
const diagramId = parseInt(req.params.diagramId);
|
||||||
const { updated_by } = req.body;
|
const { updated_by } = req.body;
|
||||||
const companyCode = (req.query.companyCode as string) || req.headers["x-company-code"] as string || "*";
|
const companyCode =
|
||||||
const userId = updated_by || req.headers["x-user-id"] as string || "SYSTEM";
|
(req.query.companyCode as string) ||
|
||||||
|
(req.headers["x-company-code"] as string) ||
|
||||||
|
"*";
|
||||||
|
const userId =
|
||||||
|
updated_by || (req.headers["x-user-id"] as string) || "SYSTEM";
|
||||||
|
|
||||||
if (isNaN(diagramId)) {
|
if (isNaN(diagramId)) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
|
|
@ -143,7 +174,11 @@ export const updateDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
updated_by: userId,
|
updated_by: userId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const updatedDiagram = await updateDataflowDiagramService(diagramId, updateData, companyCode);
|
const updatedDiagram = await updateDataflowDiagramService(
|
||||||
|
diagramId,
|
||||||
|
updateData,
|
||||||
|
companyCode
|
||||||
|
);
|
||||||
|
|
||||||
if (!updatedDiagram) {
|
if (!updatedDiagram) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
@ -173,7 +208,10 @@ export const updateDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
export const deleteDataflowDiagram = async (req: Request, res: Response) => {
|
export const deleteDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const diagramId = parseInt(req.params.diagramId);
|
const diagramId = parseInt(req.params.diagramId);
|
||||||
const companyCode = (req.query.companyCode as string) || req.headers["x-company-code"] as string || "*";
|
const companyCode =
|
||||||
|
(req.query.companyCode as string) ||
|
||||||
|
(req.headers["x-company-code"] as string) ||
|
||||||
|
"*";
|
||||||
|
|
||||||
if (isNaN(diagramId)) {
|
if (isNaN(diagramId)) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
|
|
@ -211,9 +249,18 @@ export const deleteDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
export const copyDataflowDiagram = async (req: Request, res: Response) => {
|
export const copyDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const diagramId = parseInt(req.params.diagramId);
|
const diagramId = parseInt(req.params.diagramId);
|
||||||
const { new_name, companyCode: bodyCompanyCode, userId: bodyUserId } = req.body;
|
const {
|
||||||
const companyCode = bodyCompanyCode || (req.query.companyCode as string) || req.headers["x-company-code"] as string || "*";
|
new_name,
|
||||||
const userId = bodyUserId || req.headers["x-user-id"] as string || "SYSTEM";
|
companyCode: bodyCompanyCode,
|
||||||
|
userId: bodyUserId,
|
||||||
|
} = req.body;
|
||||||
|
const companyCode =
|
||||||
|
bodyCompanyCode ||
|
||||||
|
(req.query.companyCode as string) ||
|
||||||
|
(req.headers["x-company-code"] as string) ||
|
||||||
|
"*";
|
||||||
|
const userId =
|
||||||
|
bodyUserId || (req.headers["x-user-id"] as string) || "SYSTEM";
|
||||||
|
|
||||||
if (isNaN(diagramId)) {
|
if (isNaN(diagramId)) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
|
|
@ -222,7 +269,12 @@ export const copyDataflowDiagram = async (req: Request, res: Response) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const copiedDiagram = await copyDataflowDiagramService(diagramId, companyCode, new_name, userId);
|
const copiedDiagram = await copyDataflowDiagramService(
|
||||||
|
diagramId,
|
||||||
|
companyCode,
|
||||||
|
new_name,
|
||||||
|
userId
|
||||||
|
);
|
||||||
|
|
||||||
if (!copiedDiagram) {
|
if (!copiedDiagram) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ const prisma = new PrismaClient();
|
||||||
interface CreateDataflowDiagramData {
|
interface CreateDataflowDiagramData {
|
||||||
diagram_name: string;
|
diagram_name: string;
|
||||||
relationships: any; // JSON 데이터
|
relationships: any; // JSON 데이터
|
||||||
|
node_positions?: any; // JSON 데이터 (노드 위치 정보)
|
||||||
company_code: string;
|
company_code: string;
|
||||||
created_by: string;
|
created_by: string;
|
||||||
updated_by: string;
|
updated_by: string;
|
||||||
|
|
@ -15,6 +16,7 @@ interface CreateDataflowDiagramData {
|
||||||
interface UpdateDataflowDiagramData {
|
interface UpdateDataflowDiagramData {
|
||||||
diagram_name?: string;
|
diagram_name?: string;
|
||||||
relationships?: any; // JSON 데이터
|
relationships?: any; // JSON 데이터
|
||||||
|
node_positions?: any; // JSON 데이터 (노드 위치 정보)
|
||||||
updated_by: string;
|
updated_by: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,6 +118,7 @@ export const createDataflowDiagram = async (
|
||||||
data: {
|
data: {
|
||||||
diagram_name: data.diagram_name,
|
diagram_name: data.diagram_name,
|
||||||
relationships: data.relationships,
|
relationships: data.relationships,
|
||||||
|
node_positions: data.node_positions || null,
|
||||||
company_code: data.company_code,
|
company_code: data.company_code,
|
||||||
created_by: data.created_by,
|
created_by: data.created_by,
|
||||||
updated_by: data.updated_by,
|
updated_by: data.updated_by,
|
||||||
|
|
@ -164,6 +167,9 @@ export const updateDataflowDiagram = async (
|
||||||
data: {
|
data: {
|
||||||
...(data.diagram_name && { diagram_name: data.diagram_name }),
|
...(data.diagram_name && { diagram_name: data.diagram_name }),
|
||||||
...(data.relationships && { relationships: data.relationships }),
|
...(data.relationships && { relationships: data.relationships }),
|
||||||
|
...(data.node_positions !== undefined && {
|
||||||
|
node_positions: data.node_positions,
|
||||||
|
}),
|
||||||
updated_by: data.updated_by,
|
updated_by: data.updated_by,
|
||||||
updated_at: new Date(),
|
updated_at: new Date(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import {
|
||||||
DataFlowDiagram,
|
DataFlowDiagram,
|
||||||
JsonRelationship,
|
JsonRelationship,
|
||||||
CreateDiagramRequest,
|
CreateDiagramRequest,
|
||||||
|
NodePositions,
|
||||||
} from "@/lib/api/dataflow";
|
} from "@/lib/api/dataflow";
|
||||||
import SaveDiagramModal from "./SaveDiagramModal";
|
import SaveDiagramModal from "./SaveDiagramModal";
|
||||||
import { useAuth } from "@/hooks/useAuth";
|
import { useAuth } from "@/hooks/useAuth";
|
||||||
|
|
@ -313,10 +314,16 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||||
|
|
||||||
console.log("🔌 연결된 컬럼 정보:", connectedColumnsInfo);
|
console.log("🔌 연결된 컬럼 정보:", connectedColumnsInfo);
|
||||||
|
|
||||||
// 테이블을 노드로 변환 (자동 레이아웃)
|
// 저장된 노드 위치 정보 가져오기
|
||||||
|
const savedNodePositions = jsonDiagram.node_positions || {};
|
||||||
|
console.log("📍 저장된 노드 위치:", savedNodePositions);
|
||||||
|
|
||||||
|
// 테이블을 노드로 변환 (저장된 위치 우선 사용, 없으면 자동 레이아웃)
|
||||||
const tableNodes = tableDefinitions.map((table, index) => {
|
const tableNodes = tableDefinitions.map((table, index) => {
|
||||||
const x = (index % 3) * 400 + 100; // 3열 배치
|
// 저장된 위치가 있으면 사용, 없으면 자동 배치
|
||||||
const y = Math.floor(index / 3) * 300 + 100;
|
const savedPosition = savedNodePositions[table.tableName];
|
||||||
|
const x = savedPosition ? savedPosition.x : (index % 3) * 400 + 100; // 3열 배치
|
||||||
|
const y = savedPosition ? savedPosition.y : Math.floor(index / 3) * 300 + 100;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: `table-${table.tableName}`,
|
id: `table-${table.tableName}`,
|
||||||
|
|
@ -782,6 +789,17 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||||
new Set([...tempRelationships.map((rel) => rel.fromTable), ...tempRelationships.map((rel) => rel.toTable)]),
|
new Set([...tempRelationships.map((rel) => rel.fromTable), ...tempRelationships.map((rel) => rel.toTable)]),
|
||||||
).sort();
|
).sort();
|
||||||
|
|
||||||
|
// 현재 노드 위치 추출
|
||||||
|
const nodePositions: NodePositions = {};
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
if (node.data?.table?.tableName) {
|
||||||
|
nodePositions[node.data.table.tableName] = {
|
||||||
|
x: node.position.x,
|
||||||
|
y: node.position.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 저장 요청 데이터 생성
|
// 저장 요청 데이터 생성
|
||||||
const createRequest: CreateDiagramRequest = {
|
const createRequest: CreateDiagramRequest = {
|
||||||
diagram_name: diagramName,
|
diagram_name: diagramName,
|
||||||
|
|
@ -789,6 +807,7 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||||
relationships: tempRelationships,
|
relationships: tempRelationships,
|
||||||
tables: connectedTables,
|
tables: connectedTables,
|
||||||
},
|
},
|
||||||
|
node_positions: nodePositions,
|
||||||
};
|
};
|
||||||
|
|
||||||
let savedDiagram;
|
let savedDiagram;
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,16 @@ export interface DataFlowDiagramsResponse {
|
||||||
hasPrev: boolean;
|
hasPrev: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 노드 위치 정보 타입
|
||||||
|
export interface NodePosition {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodePositions {
|
||||||
|
[tableName: string]: NodePosition;
|
||||||
|
}
|
||||||
|
|
||||||
// 새로운 JSON 기반 타입들
|
// 새로운 JSON 기반 타입들
|
||||||
export interface JsonDataFlowDiagram {
|
export interface JsonDataFlowDiagram {
|
||||||
diagram_id: number;
|
diagram_id: number;
|
||||||
|
|
@ -123,6 +133,7 @@ export interface JsonDataFlowDiagram {
|
||||||
relationships: JsonRelationship[];
|
relationships: JsonRelationship[];
|
||||||
tables: string[];
|
tables: string[];
|
||||||
};
|
};
|
||||||
|
node_positions?: NodePositions;
|
||||||
company_code: string;
|
company_code: string;
|
||||||
created_at?: string;
|
created_at?: string;
|
||||||
updated_at?: string;
|
updated_at?: string;
|
||||||
|
|
@ -147,6 +158,7 @@ export interface CreateDiagramRequest {
|
||||||
relationships: JsonRelationship[];
|
relationships: JsonRelationship[];
|
||||||
tables: string[];
|
tables: string[];
|
||||||
};
|
};
|
||||||
|
node_positions?: NodePositions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface JsonDataFlowDiagramsResponse {
|
export interface JsonDataFlowDiagramsResponse {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue