[agent-pipeline] pipe-20260329010534-qgv9 round-3

This commit is contained in:
DDD1542
2026-03-29 13:56:36 +09:00
parent 18d237c95e
commit 3bcb0d2c01
16 changed files with 160 additions and 160 deletions
+17 -17
View File
@@ -51,9 +51,9 @@ const escapeRegExp = (str: string): string => {
};
interface LinkedModalScreen {
screenId: number;
screenName: string;
screenCode: string;
screen_id: number;
screen_name: string;
screen_code: string;
newScreenName?: string;
newScreenCode?: string;
}
@@ -237,7 +237,7 @@ export default function CopyScreenModal({
setLinkedScreens((prev) =>
prev.map((screen) => ({
...screen,
newScreenName: applyBulkRename(screen.screenName),
newScreenName: applyBulkRename(screen.screen_name),
}))
);
} else {
@@ -247,7 +247,7 @@ export default function CopyScreenModal({
setLinkedScreens((prev) =>
prev.map((screen) => ({
...screen,
newScreenName: screen.screenName,
newScreenName: screen.screen_name,
}))
);
}
@@ -344,7 +344,7 @@ export default function CopyScreenModal({
setLinkedScreens(
linked.map((screen) => ({
...screen,
newScreenName: `${screen.screenName} (복사본)`,
newScreenName: `${screen.screen_name} (복사본)`,
}))
);
@@ -394,7 +394,7 @@ export default function CopyScreenModal({
setLinkedScreens(updatedLinkedScreens);
console.log("✅ 모달 화면 코드 할당 완료:", updatedLinkedScreens.map(s => ({
name: s.screenName,
name: s.screen_name,
code: s.newScreenCode
})));
}
@@ -408,14 +408,14 @@ export default function CopyScreenModal({
const updateLinkedScreenName = (screenId: number, newName: string) => {
setLinkedScreens((prev) =>
prev.map((screen) =>
screen.screenId === screenId ? { ...screen, newScreenName: newName } : screen
screen.screen_id === screenId ? { ...screen, newScreenName: newName } : screen
)
);
};
// 연결된 화면 제거 (복사하지 않음)
const removeLinkedScreen = (screenId: number) => {
setLinkedScreens((prev) => prev.filter((screen) => screen.screenId !== screenId));
setLinkedScreens((prev) => prev.filter((screen) => screen.screen_id !== screenId));
};
// 화면명 일괄 변경 적용
@@ -448,8 +448,8 @@ export default function CopyScreenModal({
preview: applyBulkRename(sourceScreen.screen_name), // (복사본) 없음
},
modals: linkedScreens.map((screen) => ({
original: screen.screenName,
preview: applyBulkRename(screen.screenName),
original: screen.screen_name,
preview: applyBulkRename(screen.screen_name),
})),
};
};
@@ -548,11 +548,11 @@ export default function CopyScreenModal({
// 연결된 화면들의 이름 검증
for (const linked of linkedScreens) {
if (!linked.newScreenName?.trim()) {
toast.error(`"${linked.screenName}" 모달 화면의 새 이름을 입력해주세요.`);
toast.error(`"${linked.screen_name}" 모달 화면의 새 이름을 입력해주세요.`);
return;
}
if (!linked.newScreenCode?.trim()) {
toast.error(`"${linked.screenName}" 모달 화면의 코드가 생성되지 않았습니다.`);
toast.error(`"${linked.screen_name}" 모달 화면의 코드가 생성되지 않았습니다.`);
return;
}
}
@@ -599,7 +599,7 @@ export default function CopyScreenModal({
description: description.trim(),
},
modalScreens: linkedScreens.map((screen) => ({
sourceScreenId: screen.screenId,
sourceScreenId: screen.screen_id,
screenName: screen.newScreenName!.trim(),
screenCode: screen.newScreenCode!.trim(),
})),
@@ -1785,11 +1785,11 @@ export default function CopyScreenModal({
</div>
<div className="space-y-2 max-h-[150px] overflow-y-auto">
{linkedScreens.map((linked) => (
<div key={linked.screenId} className="flex items-center justify-between text-xs bg-muted rounded p-2">
<div key={linked.screen_id} className="flex items-center justify-between text-xs bg-muted rounded p-2">
<div className="flex-1 min-w-0">
<Input
value={linked.newScreenName || ""}
onChange={(e) => updateLinkedScreenName(linked.screenId, e.target.value)}
onChange={(e) => updateLinkedScreenName(linked.screen_id, e.target.value)}
className="h-7 text-xs"
placeholder="모달 화면명"
/>
@@ -1798,7 +1798,7 @@ export default function CopyScreenModal({
variant="ghost"
size="icon"
className="h-7 w-7 ml-1 text-destructive"
onClick={() => removeLinkedScreen(linked.screenId)}
onClick={() => removeLinkedScreen(linked.screen_id)}
>
<Trash2 className="h-3 w-3" />
</Button>
+1 -1
View File
@@ -264,7 +264,7 @@ export const EditModal: React.FC<EditModalProps> = ({ className }) => {
let detailTableName = eventTableName;
if (!detailTableName) {
const screenInfo = await screenApi.getScreen(targetScreenId);
detailTableName = screenInfo?.table_name ?? screenInfo?.tableName;
detailTableName = screenInfo?.table_name;
}
if (!detailTableName) {
+40 -40
View File
@@ -1350,7 +1350,7 @@ export default function ScreenDesigner({
const tableListResponse = await tableManagementApi.getTableList();
const currentTable =
tableListResponse.success && tableListResponse.data
? tableListResponse.data.find((t) => t.tableName === tableName)
? tableListResponse.data.find((t) => t.table_name === tableName)
: null;
const tableLabel = currentTable?.display_name || tableName;
@@ -1359,11 +1359,11 @@ export default function ScreenDesigner({
const columns: ColumnInfo[] = (columnsResponse || []).map((col: any) => {
// widgetType 결정: inputType(entity 등) > webType > widget_type
const inputType = col.inputType || col.input_type;
const widgetType = inputType || col.widgetType || col.widget_type || col.webType || col.web_type;
const inputType = col.input_type;
const widgetType = inputType || col.widget_type || col.web_type;
// detailSettings 파싱 (문자열이면 JSON 파싱)
let detailSettings = col.detailSettings || col.detail_settings;
let detailSettings = col.detail_settings;
if (typeof detailSettings === "string") {
// JSON 형식인 경우에만 파싱 시도 (중괄호로 시작하는 경우)
if (detailSettings.trim().startsWith("{")) {
@@ -1382,33 +1382,33 @@ export default function ScreenDesigner({
// 엔티티 타입 디버깅
if (inputType === "entity" || widgetType === "entity") {
console.log("🔍 엔티티 컬럼 감지:", {
columnName: col.columnName || col.column_name,
columnName: col.column_name,
inputType,
widgetType,
detailSettings,
referenceTable: detailSettings?.referenceTable || col.referenceTable || col.reference_table,
referenceTable: detailSettings?.referenceTable || col.reference_table,
});
}
return {
tableName: col.tableName || tableName,
columnName: col.columnName || col.column_name,
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
dataType: col.dataType || col.data_type || col.dbType,
webType: col.webType || col.web_type,
tableName: col.table_name || tableName,
columnName: col.column_name,
columnLabel: col.display_name || col.column_label || col.column_name,
dataType: col.data_type || col.db_type,
webType: col.web_type,
input_type: inputType,
inputType: inputType,
widgetType,
isNullable: col.isNullable || col.is_nullable,
required: col.required !== undefined ? col.required : col.isNullable === "NO" || col.is_nullable === "NO",
columnDefault: col.columnDefault || col.column_default,
characterMaximumLength: col.characterMaximumLength || col.character_maximum_length,
codeCategory: col.codeCategory || col.code_category,
codeValue: col.codeValue || col.code_value,
isNullable: col.is_nullable,
required: col.required !== undefined ? col.required : col.is_nullable === "NO",
columnDefault: col.column_default,
characterMaximumLength: col.character_maximum_length,
codeCategory: col.code_category,
codeValue: col.code_value,
// 엔티티 타입용 참조 테이블 정보 (detailSettings에서 추출)
referenceTable: detailSettings?.referenceTable || col.referenceTable || col.reference_table,
referenceColumn: detailSettings?.referenceColumn || col.referenceColumn || col.reference_column,
displayColumn: detailSettings?.displayColumn || col.displayColumn || col.display_column,
referenceTable: detailSettings?.referenceTable || col.reference_table,
referenceColumn: detailSettings?.referenceColumn || col.reference_column,
displayColumn: detailSettings?.displayColumn || col.display_column,
// detailSettings 전체 보존 (V2 컴포넌트용)
detailSettings,
};
@@ -1455,7 +1455,7 @@ export default function ScreenDesigner({
const tableListResponse = await tableManagementApi.getTableList();
const currentTable =
tableListResponse.success && tableListResponse.data
? tableListResponse.data.find((t: any) => (t.tableName || t.table_name) === tableName)
? tableListResponse.data.find((t: any) => t.table_name === tableName)
: null;
const tableLabel = currentTable?.display_name || currentTable?.table_label || tableName;
@@ -1463,10 +1463,10 @@ export default function ScreenDesigner({
const columnsResponse = await tableTypeApi.getColumns(tableName, true);
const columns: ColumnInfo[] = (columnsResponse || []).map((col: any) => {
const inputType = col.inputType || col.input_type;
const widgetType = inputType || col.widgetType || col.widget_type || col.webType || col.web_type;
const inputType = col.input_type;
const widgetType = inputType || col.widget_type || col.web_type;
let detailSettings = col.detailSettings || col.detail_settings;
let detailSettings = col.detail_settings;
if (typeof detailSettings === "string") {
try {
detailSettings = JSON.parse(detailSettings);
@@ -1476,23 +1476,23 @@ export default function ScreenDesigner({
}
return {
tableName: col.tableName || tableName,
columnName: col.columnName || col.column_name,
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
dataType: col.dataType || col.data_type || col.dbType,
webType: col.webType || col.web_type,
tableName: col.table_name || tableName,
columnName: col.column_name,
columnLabel: col.display_name || col.column_label || col.column_name,
dataType: col.data_type || col.db_type,
webType: col.web_type,
input_type: inputType,
inputType: inputType,
widgetType,
isNullable: col.isNullable || col.is_nullable,
required: col.required !== undefined ? col.required : col.isNullable === "NO" || col.is_nullable === "NO",
columnDefault: col.columnDefault || col.column_default,
characterMaximumLength: col.characterMaximumLength || col.character_maximum_length,
codeCategory: col.codeCategory || col.code_category,
codeValue: col.codeValue || col.code_value,
referenceTable: detailSettings?.referenceTable || col.referenceTable || col.reference_table,
referenceColumn: detailSettings?.referenceColumn || col.referenceColumn || col.reference_column,
displayColumn: detailSettings?.displayColumn || col.displayColumn || col.display_column,
isNullable: col.is_nullable,
required: col.required !== undefined ? col.required : col.is_nullable === "NO",
columnDefault: col.column_default,
characterMaximumLength: col.character_maximum_length,
codeCategory: col.code_category,
codeValue: col.code_value,
referenceTable: detailSettings?.referenceTable || col.reference_table,
referenceColumn: detailSettings?.referenceColumn || col.reference_column,
displayColumn: detailSettings?.displayColumn || col.display_column,
detailSettings,
};
});
@@ -2174,8 +2174,8 @@ export default function ScreenDesigner({
if (Array.isArray(columns)) {
columnLabelMap[tableName] = {};
columns.forEach((col: any) => {
const colName = col.columnName || col.column_name || col.name;
const colLabel = col.displayName || col.columnLabel || col.column_label || colName;
const colName = col.column_name || col.name;
const colLabel = col.display_name || col.column_label || colName;
if (colName) {
columnLabelMap[tableName][colName] = colLabel;
}
+5 -5
View File
@@ -273,12 +273,12 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
// 최고 관리자이고 특정 회사를 선택한 경우
if (isSuperAdmin && selectedCompanyCode !== "all") {
params.companyCode = selectedCompanyCode;
params.company_code = selectedCompanyCode;
}
// 그룹 필터
if (selectedGroupId !== "all") {
params.groupId = selectedGroupId;
params.group_id = selectedGroupId;
}
console.log("🔍 화면 목록 API 호출:", params); // 디버깅용
@@ -325,9 +325,9 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
// 최고 관리자이고 특정 회사를 선택한 경우
if (isSuperAdmin && selectedCompanyCode !== "all") {
params.companyCode = selectedCompanyCode;
params.company_code = selectedCompanyCode;
}
const resp = await screenApi.getScreens(params);
setScreens(resp.data || []);
setTotalPages(Math.max(1, Math.ceil((resp.total || 0) / 20)));
@@ -740,7 +740,7 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
<SelectItem value="ungrouped"></SelectItem>
{groups.map((group) => (
<SelectItem key={group.id} value={String(group.id)}>
{group.groupName}
{group.group_name}
</SelectItem>
))}
</SelectContent>
@@ -189,18 +189,18 @@ export function ScreenRelationView({ screen }: ScreenRelationViewProps) {
className="flex items-center gap-2 p-2 rounded-md bg-muted/50 text-sm"
>
<div className="flex items-center gap-1">
<span className="font-mono text-xs">{join.sourceTable}</span>
<span className="font-mono text-xs">{join.save_table}</span>
<span className="text-muted-foreground">.</span>
<span className="font-mono text-xs text-primary">{join.sourceColumn}</span>
<span className="font-mono text-xs text-primary">{join.save_column}</span>
</div>
<ArrowRight className="h-3 w-3 text-muted-foreground" />
<div className="flex items-center gap-1">
<span className="font-mono text-xs">{join.targetTable}</span>
<span className="font-mono text-xs">{join.join_table}</span>
<span className="text-muted-foreground">.</span>
<span className="font-mono text-xs text-emerald-600">{join.targetColumn}</span>
<span className="font-mono text-xs text-emerald-600">{join.join_column}</span>
</div>
<Badge variant="outline" className="ml-auto text-xs">
{join.joinType}
{join.join_type}
</Badge>
</div>
))}
@@ -231,14 +231,14 @@ export function ScreenRelationView({ screen }: ScreenRelationViewProps) {
className="flex items-center gap-2 p-2 rounded-md bg-muted/50 text-sm"
>
<Monitor className="h-4 w-4 text-primary" />
<span className="truncate">{flow.flowName || "이름 없음"}</span>
<span className="truncate">{flow.flow_label || "이름 없음"}</span>
<ArrowRight className="h-3 w-3 text-muted-foreground" />
<Monitor className="h-4 w-4 text-emerald-500" />
<span className="text-muted-foreground truncate">
#{flow.targetScreenId}
#{flow.target_screen_id}
</span>
<Badge variant="outline" className="ml-auto text-xs">
{flow.flowType}
{flow.flow_type}
</Badge>
</div>
))}
@@ -269,11 +269,11 @@ export function ScreenRelationView({ screen }: ScreenRelationViewProps) {
className="flex items-center gap-2 p-2 rounded-md bg-muted/50 text-sm"
>
<Table className="h-4 w-4 text-muted-foreground" />
<span className="font-mono text-xs">{relation.parentTable}</span>
<span className="font-mono text-xs">{screen.table_name}</span>
<ArrowRight className="h-3 w-3 text-muted-foreground" />
<span className="font-mono text-xs">{relation.childTable}</span>
<span className="font-mono text-xs">{relation.table_name}</span>
<Badge variant="outline" className="ml-auto text-xs">
{relation.relationType}
{relation.relation_type}
</Badge>
</div>
))}
+13 -13
View File
@@ -61,10 +61,10 @@ export const dataApi = {
try {
const params: any = {};
if (enableEntityJoin) {
params.enableEntityJoin = true;
params.enable_entity_join = true;
}
if (groupByColumns.length > 0) {
params.groupByColumns = JSON.stringify(groupByColumns);
params.group_by_columns = JSON.stringify(groupByColumns);
}
console.log("🌐 [dataApi.getRecordDetail] API 호출:", {
@@ -123,14 +123,14 @@ export const dataApi = {
): Promise<any[]> => {
const response = await apiClient.get(`/data/join`, {
params: {
leftTable,
rightTable,
leftColumn,
rightColumn,
leftValue,
dataFilter: dataFilter ? JSON.stringify(dataFilter) : undefined,
enableEntityJoin: enableEntityJoin ?? true,
displayColumns: displayColumns ? JSON.stringify(displayColumns) : undefined, // 🆕 표시 컬럼 전달
left_table: leftTable,
right_table: rightTable,
left_column: leftColumn,
right_column: rightColumn,
left_value: leftValue,
data_filter: dataFilter ? JSON.stringify(dataFilter) : undefined,
enable_entity_join: enableEntityJoin ?? true,
display_columns: displayColumns ? JSON.stringify(displayColumns) : undefined, // 🆕 표시 컬럼 전달
deduplication: deduplication ? JSON.stringify(deduplication) : undefined, // 🆕 중복 제거 설정 전달
},
});
@@ -215,7 +215,7 @@ export const dataApi = {
try {
const params: any = {};
if (enableEntityJoin) {
params.enableEntityJoin = "true";
params.enable_entity_join = "true";
}
const response = await apiClient.get(`/data/${tableName}/${id}`, { params });
return response.data; // { success: true, data: ... } 형식 그대로 반환
@@ -249,10 +249,10 @@ export const dataApi = {
});
const requestBody = {
tableName,
table_name: tableName,
parentKeys,
records,
deleteOrphans: options?.deleteOrphans ?? true, // 기본값: true (기존 동작 유지)
delete_orphans: options?.deleteOrphans ?? true, // 기본값: true (기존 동작 유지)
};
console.log("📦 [dataApi.upsertGroupedRecords] 요청 본문 (JSON):", JSON.stringify(requestBody, null, 2));
+36 -36
View File
@@ -64,7 +64,7 @@ export const loadDataflowRelationship = async (diagramId: number) => {
let relationshipsData;
// Case 1: 현재 구조 - relationships 자체가 관계 데이터
if (diagram.relationships && (diagram.relationships.connection_type || diagram.relationships.connectionType)) {
if (diagram.relationships && diagram.relationships.connection_type) {
relationshipsData = diagram.relationships;
console.log("✅ 현재 구조 감지 (relationships 직접):", relationshipsData);
}
@@ -85,22 +85,22 @@ export const loadDataflowRelationship = async (diagramId: number) => {
// 기존 구조를 redesigned 구조로 변환
relationshipsData = {
description: firstRelation.note || "",
connectionType: firstRelation.connection_type || firstRelation.connectionType || "data_save",
fromConnection: { id: 0, name: "메인 데이터베이스 (현재 시스템)" }, // 기본값
toConnection: { id: 0, name: "메인 데이터베이스 (현재 시스템)" }, // 기본값
fromTable: firstRelation.from_table || firstRelation.fromTable,
toTable: firstRelation.to_table || firstRelation.toTable,
actionType: "insert", // 기본값
controlConditions: [],
actionConditions: [],
fieldMappings: [],
connection_type: firstRelation.connection_type || "data_save",
from_connection: { id: 0, name: "메인 데이터베이스 (현재 시스템)" }, // 기본값
to_connection: { id: 0, name: "메인 데이터베이스 (현재 시스템)" }, // 기본값
from_table: firstRelation.from_table,
to_table: firstRelation.to_table,
action_type: "insert", // 기본값
control_conditions: [],
action_conditions: [],
field_mappings: [],
};
// 기존 control 및 plan 데이터를 변환
if (diagram.control && diagram.control.length > 0) {
const control = diagram.control.find((c) => c.id === firstRelation.id);
if (control && control.conditions) {
relationshipsData.controlConditions = control.conditions;
relationshipsData.control_conditions = control.conditions;
}
}
@@ -108,9 +108,9 @@ export const loadDataflowRelationship = async (diagramId: number) => {
const plan = diagram.plan.find((p) => p.id === firstRelation.id);
if (plan && plan.actions && plan.actions.length > 0) {
const firstAction = plan.actions[0];
relationshipsData.actionType = firstAction.action_type || firstAction.actionType || "insert";
relationshipsData.fieldMappings = firstAction.field_mappings || firstAction.fieldMappings || [];
relationshipsData.actionConditions = firstAction.action_conditions || firstAction.conditions || [];
relationshipsData.action_type = firstAction.action_type || "insert";
relationshipsData.field_mappings = firstAction.field_mappings || [];
relationshipsData.action_conditions = firstAction.action_conditions || firstAction.conditions || [];
}
}
}
@@ -121,18 +121,18 @@ export const loadDataflowRelationship = async (diagramId: number) => {
// 현재 DB에 저장된 구조 처리 (relationships 객체에 모든 데이터가 있음)
relationshipsData = {
description: diagram.relationships.description || "",
connection_type: diagram.relationships.connection_type || diagram.relationships.connectionType || "data_save",
from_connection: diagram.relationships.from_connection || diagram.relationships.fromConnection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
to_connection: diagram.relationships.to_connection || diagram.relationships.toConnection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
from_table: diagram.relationships.from_table || diagram.relationships.fromTable,
to_table: diagram.relationships.to_table || diagram.relationships.toTable,
action_type: diagram.relationships.action_type || diagram.relationships.actionType || "insert",
control_conditions: diagram.relationships.control_conditions || diagram.relationships.controlConditions || [],
action_conditions: diagram.relationships.action_conditions || diagram.relationships.actionConditions || [],
field_mappings: diagram.relationships.field_mappings || diagram.relationships.fieldMappings || [],
connection_type: diagram.relationships.connection_type || "data_save",
from_connection: diagram.relationships.from_connection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
to_connection: diagram.relationships.to_connection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
from_table: diagram.relationships.from_table,
to_table: diagram.relationships.to_table,
action_type: diagram.relationships.action_type || "insert",
control_conditions: diagram.relationships.control_conditions || [],
action_conditions: diagram.relationships.action_conditions || [],
field_mappings: diagram.relationships.field_mappings || [],
// 🔧 멀티 액션 그룹 데이터 로드
action_groups: diagram.relationships.action_groups || diagram.relationships.actionGroups || null,
external_call_config: diagram.relationships.external_call_config || diagram.relationships.externalCallConfig,
action_groups: diagram.relationships.action_groups || null,
external_call_config: diagram.relationships.external_call_config,
};
console.log("✅ 현재 DB 구조 처리 완료:", relationshipsData);
} else {
@@ -146,19 +146,19 @@ export const loadDataflowRelationship = async (diagramId: number) => {
diagramId: diagram.diagram_id, // 🔧 수정 모드를 위한 diagramId 추가
relationshipName: diagram.diagram_name,
description: relationshipsData.description || diagram.description || "", // 🔧 diagram.description도 확인
connectionType: relationshipsData.connection_type || relationshipsData.connectionType || "data_save",
fromConnection: relationshipsData.from_connection || relationshipsData.fromConnection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
toConnection: relationshipsData.to_connection || relationshipsData.toConnection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
fromTable: relationshipsData.from_table || relationshipsData.fromTable,
toTable: relationshipsData.to_table || relationshipsData.toTable,
actionType: relationshipsData.action_type || relationshipsData.actionType || "insert",
controlConditions: relationshipsData.control_conditions || relationshipsData.controlConditions || [],
actionConditions: relationshipsData.action_conditions || relationshipsData.actionConditions || [],
fieldMappings: relationshipsData.field_mappings || relationshipsData.fieldMappings || [],
connectionType: relationshipsData.connection_type || "data_save",
fromConnection: relationshipsData.from_connection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
toConnection: relationshipsData.to_connection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
fromTable: relationshipsData.from_table,
toTable: relationshipsData.to_table,
actionType: relationshipsData.action_type || "insert",
controlConditions: relationshipsData.control_conditions || [],
actionConditions: relationshipsData.action_conditions || [],
fieldMappings: relationshipsData.field_mappings || [],
// 🔧 멀티 액션 그룹 데이터 포함
actionGroups: relationshipsData.action_groups || relationshipsData.actionGroups,
actionGroups: relationshipsData.action_groups,
// 🔧 외부호출 설정 데이터 포함
externalCallConfig: relationshipsData.external_call_config || relationshipsData.externalCallConfig,
externalCallConfig: relationshipsData.external_call_config,
};
console.log("✨ 변환된 로드 데이터:", loadedData);
+11 -11
View File
@@ -247,8 +247,8 @@ export class DynamicFormApi {
page?: number;
size?: number;
search?: string;
sortBy?: string;
sortOrder?: "asc" | "desc";
sort_by?: string;
sort_order?: "asc" | "desc";
},
): Promise<
ApiResponse<{
@@ -433,12 +433,12 @@ export class DynamicFormApi {
tableName: string,
params?: {
page?: number;
pageSize?: number;
page_size?: number;
search?: string;
sortBy?: string;
sortOrder?: "asc" | "desc";
sort_by?: string;
sort_order?: "asc" | "desc";
filters?: Record<string, any>;
autoFilter?: {
auto_filter?: {
enabled: boolean;
filter_column?: string;
user_field?: string;
@@ -452,8 +452,8 @@ export class DynamicFormApi {
// pageSize를 size로 변환 (백엔드 파라미터명 호환)
const requestParams = {
...params,
size: params?.pageSize || params?.size || 100, // 기본값 100
autoFilter: params?.autoFilter ?? {
size: params?.page_size || params?.size || 100, // 기본값 100
auto_filter: params?.auto_filter ?? {
enabled: true,
filter_column: "company_code",
user_field: "company_code",
@@ -533,10 +533,10 @@ export class DynamicFormApi {
* @returns 업로드 결과
*/
static async uploadExcelData(payload: {
tableName: string;
table_name: string;
data: any[];
uploadMode: "insert" | "update" | "upsert";
keyColumn?: string;
upload_mode: "insert" | "update" | "upsert";
key_column?: string;
}): Promise<ApiResponse<any>> {
try {
console.log("📤 엑셀 업로드 요청:", payload);
+3 -3
View File
@@ -22,7 +22,7 @@ export interface FileUploadResponse {
export interface FileDownloadParams {
fileId: string;
server_filename: string;
originalName: string;
original_name: string;
}
/**
@@ -89,7 +89,7 @@ export const downloadFile = async (params: FileDownloadParams): Promise<void> =>
const response = await apiClient.get(`/files/download/${params.fileId}`, {
params: {
server_filename: params.server_filename,
originalName: params.originalName,
original_name: params.original_name,
},
responseType: "blob", // 파일 다운로드를 위해 blob 타입으로 설정
});
@@ -103,7 +103,7 @@ export const downloadFile = async (params: FileDownloadParams): Promise<void> =>
// 다운로드 링크 생성 및 클릭
const link = document.createElement("a");
link.href = url;
link.download = params.originalName;
link.download = params.original_name;
document.body.appendChild(link);
link.click();
+1 -1
View File
@@ -358,7 +358,7 @@ export const screenApi = {
// 연결된 모달 화면 감지
detectLinkedModals: async (
screenId: number,
): Promise<Array<{ screenId: number; screenName: string; screenCode: string }>> => {
): Promise<Array<{ screen_id: number; screen_name: string; screen_code: string }>> => {
const response = await apiClient.get(`/screen-management/screens/${screenId}/linked-modals`);
return response.data.data || [];
},
@@ -823,8 +823,8 @@ const FileUploadComponent: React.FC<FileUploadComponentProps> = ({
try {
await downloadFile({
fileId: file.objid,
serverFilename: file.savedFileName,
originalName: file.realFileName,
server_filename: file.savedFileName,
original_name: file.realFileName,
});
toast.success(`${file.realFileName} 다운로드 완료`);
} catch (error) {
@@ -934,7 +934,7 @@ const FileUploadComponent: React.FC<FileUploadComponentProps> = ({
// 🔑 previewUrl 상대 경로 대신 apiClient를 사용하여 Docker 환경에서도 정상 동작
const response = await apiClient.get(`/files/preview/${file.objid}`, {
params: {
serverFilename: file.savedFileName,
server_filename: file.savedFileName,
},
responseType: "blob",
});
@@ -1656,7 +1656,7 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
required: col.required !== undefined ? col.required : col.is_nullable === "NO",
columnDefault: col.column_default,
characterMaximumLength: col.character_maximum_length,
isPrimaryKey: col.isPrimaryKey || false, // PK 여부 추가
isPrimaryKey: col.is_primary_key || false, // PK 여부 추가
codeCategory: col.code_category,
codeValue: col.code_value,
referenceTable: col.reference_table, // 🆕 참조 테이블
@@ -1776,8 +1776,8 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
// 🆕 좌측/우측 테이블이 모두 선택되면 엔티티 관계 자동 감지
const [autoDetectedRelations, setAutoDetectedRelations] = useState<
Array<{
leftColumn: string;
rightColumn: string;
left_column: string;
right_column: string;
direction: "left_to_right" | "right_to_left";
inputType: string;
displayColumn?: string;
@@ -1818,8 +1818,8 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
useMultipleKeys: true,
keys: [
{
leftColumn: firstRel.leftColumn,
rightColumn: firstRel.rightColumn,
leftColumn: firstRel.left_column,
rightColumn: firstRel.right_column,
},
],
},
@@ -116,10 +116,10 @@ export const LeftPanelConfigTab: React.FC<LeftPanelConfigTabProps> = ({
)}
<CommandGroup heading="전체 테이블">
{allTables
.filter((t) => (t.tableName || t.table_name) !== screenTableName)
.filter((t) => t.table_name !== screenTableName)
.map((table) => {
const tableName = table.tableName || table.table_name;
const displayName = table.tableLabel || table.displayName || tableName;
const tableName = table.table_name;
const displayName = table.table_label || table.display_name || tableName;
return (
<CommandItem
key={tableName}
+2 -2
View File
@@ -264,8 +264,8 @@ export class DataflowJobQueue {
try {
const response = await apiClient.post("/api/button-dataflow/execute-background", {
buttonId: job.buttonId,
actionType: job.actionType,
button_id: job.buttonId,
action_type: job.actionType,
buttonConfig: config,
contextData,
companyCode,
@@ -484,8 +484,8 @@ export class ImprovedButtonActionExecutor {
// 백엔드 프록시 API 호출 - GenericApiSettings 형식에 맞게 전달
const requestPayload = {
diagramId: relationships.diagramId || 45, // 관계 ID 사용
relationshipId: relationships.relationshipId || "relationship-45",
diagram_id: relationships.diagramId || 45, // 관계 ID 사용
relationship_id: relationships.relationshipId || "relationship-45",
settings: {
callType: "rest-api",
apiType: "generic",
@@ -497,7 +497,7 @@ export class ImprovedButtonActionExecutor {
timeout: restApiSettings.timeout || 30000,
retryCount: restApiSettings.retryCount || 3,
},
templateData: restApiSettings.httpMethod !== "GET" && requestBody ? JSON.parse(requestBody) : formData,
template_data: restApiSettings.httpMethod !== "GET" && requestBody ? JSON.parse(requestBody) : formData,
};
console.log("📤 백엔드로 전송할 데이터:", requestPayload);
@@ -706,9 +706,9 @@ export class ImprovedButtonActionExecutor {
// 데이터 저장 API 호출 (apiClient 사용)
const response = await apiClient.post("/dataflow/execute-data-action", {
tableName,
table_name: tableName,
data,
actionType,
action_type: actionType,
connection,
});
+4 -4
View File
@@ -136,13 +136,13 @@ async function fetchBatchTranslations(
const response = await apiClient.post(
"/multilang/batch",
{
langKeys: keys,
lang_keys: keys,
},
{
params: {
companyCode,
menuCode,
userLang,
company_code: companyCode,
menu_code: menuCode,
user_lang: userLang,
},
},
);