diff --git a/frontend/components/common/ExcelUploadModal.tsx b/frontend/components/common/ExcelUploadModal.tsx index 6785eac8..6eda1594 100644 --- a/frontend/components/common/ExcelUploadModal.tsx +++ b/frontend/components/common/ExcelUploadModal.tsx @@ -84,6 +84,11 @@ export interface ExcelUploadModalProps { }; // ๐Ÿ†• ๋งˆ์Šคํ„ฐ-๋””ํ…Œ์ผ ์—‘์…€ ์—…๋กœ๋“œ ์„ค์ • masterDetailExcelConfig?: MasterDetailExcelConfig; + // ๐Ÿ†• ๋‹จ์ผ ํ…Œ์ด๋ธ” ์ฑ„๋ฒˆ ์„ค์ • + numberingRuleId?: string; + numberingTargetColumn?: string; + // ๐Ÿ†• ์—…๋กœ๋“œ ํ›„ ์ œ์–ด ์‹คํ–‰ ์„ค์ • + afterUploadFlows?: Array<{ flowId: string; order: number }>; } interface ColumnMapping { @@ -103,6 +108,11 @@ export const ExcelUploadModal: React.FC = ({ isMasterDetail = false, masterDetailRelation, masterDetailExcelConfig, + // ๋‹จ์ผ ํ…Œ์ด๋ธ” ์ฑ„๋ฒˆ ์„ค์ • + numberingRuleId, + numberingTargetColumn, + // ์—…๋กœ๋“œ ํ›„ ์ œ์–ด ์‹คํ–‰ ์„ค์ • + afterUploadFlows, }) => { const [currentStep, setCurrentStep] = useState(1); @@ -695,13 +705,48 @@ export const ExcelUploadModal: React.FC = ({ } } else { // ๊ธฐ์กด ๋‹จ์ผ ํ…Œ์ด๋ธ” ์—…๋กœ๋“œ ๋กœ์ง + console.log("๐Ÿ“Š ๋‹จ์ผ ํ…Œ์ด๋ธ” ์—…๋กœ๋“œ ์‹œ์ž‘:", { + tableName, + uploadMode, + numberingRuleId, + numberingTargetColumn, + dataCount: filteredData.length, + }); + let successCount = 0; let failCount = 0; + // ๐Ÿ†• ๋‹จ์ผ ํ…Œ์ด๋ธ” ์ฑ„๋ฒˆ ์„ค์ • ํ™•์ธ + const hasNumbering = numberingRuleId && numberingTargetColumn; + console.log("๐Ÿ“Š ์ฑ„๋ฒˆ ์„ค์ •:", { hasNumbering, numberingRuleId, numberingTargetColumn }); + for (const row of filteredData) { try { + let dataToSave = { ...row }; + + // ๐Ÿ†• ์ฑ„๋ฒˆ ์ ์šฉ: ๊ฐ ํ–‰๋งˆ๋‹ค ์ฑ„๋ฒˆ API ํ˜ธ์ถœ + if (hasNumbering && uploadMode === "insert") { + try { + const { apiClient } = await import("@/lib/api/client"); + console.log(`๐Ÿ“Š ์ฑ„๋ฒˆ API ํ˜ธ์ถœ: /numbering-rules/${numberingRuleId}/allocate`); + const numberingResponse = await apiClient.post(`/numbering-rules/${numberingRuleId}/allocate`); + console.log(`๐Ÿ“Š ์ฑ„๋ฒˆ API ์‘๋‹ต:`, numberingResponse.data); + // ์‘๋‹ต ๊ตฌ์กฐ: { success: true, data: { generatedCode: "..." } } + const generatedCode = numberingResponse.data?.data?.generatedCode || numberingResponse.data?.data?.code; + if (numberingResponse.data?.success && generatedCode) { + dataToSave[numberingTargetColumn] = generatedCode; + console.log(`โœ… ์ฑ„๋ฒˆ ์ ์šฉ: ${numberingTargetColumn} = ${generatedCode}`); + } else { + console.warn(`โš ๏ธ ์ฑ„๋ฒˆ ์‹คํŒจ: ์‘๋‹ต์— ์ฝ”๋“œ ์—†์Œ`, numberingResponse.data); + } + } catch (numError) { + console.error("์ฑ„๋ฒˆ ์˜ค๋ฅ˜:", numError); + // ์ฑ„๋ฒˆ ์‹คํŒจ ์‹œ์—๋„ ๊ณ„์† ์ง„ํ–‰ (์ฑ„๋ฒˆ ์ปฌ๋Ÿผ๋งŒ ๋น„์›Œ๋‘ ) + } + } + if (uploadMode === "insert") { - const formData = { screenId: 0, tableName, data: row }; + const formData = { screenId: 0, tableName, data: dataToSave }; const result = await DynamicFormApi.saveFormData(formData); if (result.success) { successCount++; @@ -714,6 +759,24 @@ export const ExcelUploadModal: React.FC = ({ } } + // ๐Ÿ†• ์—…๋กœ๋“œ ํ›„ ์ œ์–ด ์‹คํ–‰ + if (afterUploadFlows && afterUploadFlows.length > 0 && successCount > 0) { + console.log("๐Ÿ”„ ์—…๋กœ๋“œ ํ›„ ์ œ์–ด ์‹คํ–‰:", afterUploadFlows); + try { + const { apiClient } = await import("@/lib/api/client"); + // ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ + const sortedFlows = [...afterUploadFlows].sort((a, b) => a.order - b.order); + for (const flow of sortedFlows) { + await apiClient.post(`/dataflow/node-flows/${flow.flowId}/execute`, { + sourceData: { tableName, uploadedCount: successCount }, + }); + console.log(`โœ… ์ œ์–ด ์‹คํ–‰ ์™„๋ฃŒ: flowId=${flow.flowId}`); + } + } catch (controlError) { + console.error("์ œ์–ด ์‹คํ–‰ ์˜ค๋ฅ˜:", controlError); + } + } + if (successCount > 0) { toast.success( `${successCount}๊ฐœ ํ–‰์ด ์—…๋กœ๋“œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.${failCount > 0 ? ` (์‹คํŒจ: ${failCount}๊ฐœ)` : ""}` diff --git a/frontend/components/common/ScreenModal.tsx b/frontend/components/common/ScreenModal.tsx index f7926f43..44685dc0 100644 --- a/frontend/components/common/ScreenModal.tsx +++ b/frontend/components/common/ScreenModal.tsx @@ -175,13 +175,21 @@ export const ScreenModal: React.FC = ({ className }) => { if (editData) { console.log("๐Ÿ“ [ScreenModal] ์ˆ˜์ • ๋ฐ์ดํ„ฐ ์„ค์ •:", editData); - // ๐Ÿ†• ๋ฐฐ์—ด์ธ ๊ฒฝ์šฐ (๊ทธ๋ฃน ๋ ˆ์ฝ”๋“œ) vs ๋‹จ์ผ ๊ฐ์ฒด ์ฒ˜๋ฆฌ + // ๐Ÿ†• ๋ฐฐ์—ด์ธ ๊ฒฝ์šฐ ๋‘ ๊ฐ€์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์„ค์ •: + // 1. formData: ์ฒซ ๋ฒˆ์งธ ์š”์†Œ(๊ฐ์ฒด) - ์ผ๋ฐ˜ ์ž…๋ ฅ ํ•„๋“œ์šฉ (TextInput ๋“ฑ) + // 2. selectedData: ์ „์ฒด ๋ฐฐ์—ด - ๋‹ค์ค‘ ํ•ญ๋ชฉ ์ปดํฌ๋„ŒํŠธ์šฉ (SelectedItemsDetailInput ๋“ฑ) if (Array.isArray(editData)) { - console.log(`๐Ÿ“ [ScreenModal] ๊ทธ๋ฃน ๋ ˆ์ฝ”๋“œ ${editData.length}๊ฐœ ์„ค์ •`); - setFormData(editData as any); // ๋ฐฐ์—ด ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ (SelectedItemsDetailInput์—์„œ ์ฒ˜๋ฆฌ) - setOriginalData(editData[0] || null); // ์ฒซ ๋ฒˆ์งธ ๋ ˆ์ฝ”๋“œ๋ฅผ ์›๋ณธ์œผ๋กœ ์ €์žฅ + const firstRecord = editData[0] || {}; + console.log(`๐Ÿ“ [ScreenModal] ๊ทธ๋ฃน ๋ ˆ์ฝ”๋“œ ${editData.length}๊ฐœ ์„ค์ •:`, { + formData: "์ฒซ ๋ฒˆ์งธ ๋ ˆ์ฝ”๋“œ (์ผ๋ฐ˜ ์ž…๋ ฅ ํ•„๋“œ์šฉ)", + selectedData: "์ „์ฒด ๋ฐฐ์—ด (๋‹ค์ค‘ ํ•ญ๋ชฉ ์ปดํฌ๋„ŒํŠธ์šฉ)", + }); + setFormData(firstRecord); // ๐Ÿ”ง ์ผ๋ฐ˜ ์ž…๋ ฅ ํ•„๋“œ์šฉ (๊ฐ์ฒด) + setSelectedData(editData); // ๐Ÿ”ง ๋‹ค์ค‘ ํ•ญ๋ชฉ ์ปดํฌ๋„ŒํŠธ์šฉ (๋ฐฐ์—ด) - groupedData๋กœ ์ „๋‹ฌ๋จ + setOriginalData(firstRecord); // ์ฒซ ๋ฒˆ์งธ ๋ ˆ์ฝ”๋“œ๋ฅผ ์›๋ณธ์œผ๋กœ ์ €์žฅ } else { setFormData(editData); + setSelectedData([editData]); // ๐Ÿ”ง ๋‹จ์ผ ๊ฐ์ฒด๋„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ setOriginalData(editData); // ๐Ÿ†• ์›๋ณธ ๋ฐ์ดํ„ฐ ์ €์žฅ (UPDATE ํŒ๋‹จ์šฉ) } } else { diff --git a/frontend/components/screen/config-panels/ButtonConfigPanel.tsx b/frontend/components/screen/config-panels/ButtonConfigPanel.tsx index 8d8c4df9..eabeb59f 100644 --- a/frontend/components/screen/config-panels/ButtonConfigPanel.tsx +++ b/frontend/components/screen/config-panels/ButtonConfigPanel.tsx @@ -5,7 +5,6 @@ import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; -import { Checkbox } from "@/components/ui/checkbox"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { Button } from "@/components/ui/button"; @@ -2026,7 +2025,12 @@ export const ButtonConfigPanel: React.FC = ({ {/* ์—‘์…€ ์—…๋กœ๋“œ ์•ก์…˜ ์„ค์ • */} {(component.componentConfig?.action?.type || "save") === "excel_upload" && ( - + )} {/* ๋ฐ”์ฝ”๋“œ ์Šค์บ” ์•ก์…˜ ์„ค์ • */} @@ -3311,7 +3315,6 @@ const MasterDetailExcelUploadConfig: React.FC<{ onUpdateProperty: (path: string, value: any) => void; allComponents: ComponentData[]; }> = ({ config, onUpdateProperty, allComponents }) => { - const [numberingRules, setNumberingRules] = useState([]); const [relationInfo, setRelationInfo] = useState<{ masterTable: string; detailTable: string; @@ -3319,7 +3322,6 @@ const MasterDetailExcelUploadConfig: React.FC<{ detailFkColumn: string; } | null>(null); const [loading, setLoading] = useState(false); - const [numberingRuleOpen, setNumberingRuleOpen] = useState(false); const [masterColumns, setMasterColumns] = useState< Array<{ columnName: string; @@ -3357,22 +3359,6 @@ const MasterDetailExcelUploadConfig: React.FC<{ const masterTable = splitPanelInfo?.leftPanel?.tableName || ""; const detailTable = splitPanelInfo?.rightPanel?.tableName || ""; - // ์ฑ„๋ฒˆ ๊ทœ์น™ ๋กœ๋“œ - useEffect(() => { - const loadNumberingRules = async () => { - try { - const { apiClient } = await import("@/lib/api/client"); - const response = await apiClient.get("/numbering-rules"); - if (response.data?.success && response.data?.data) { - setNumberingRules(response.data.data); - } - } catch (error) { - console.error("์ฑ„๋ฒˆ ๊ทœ์น™ ๋กœ๋“œ ์‹คํŒจ:", error); - } - }; - loadNumberingRules(); - }, []); - // ๋งˆ์Šคํ„ฐ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ๋กœ๋“œ useEffect(() => { if (!masterTable) { @@ -3547,86 +3533,12 @@ const MasterDetailExcelUploadConfig: React.FC<{ )} - {/* ์ฑ„๋ฒˆ ๊ทœ์น™ ์„ ํƒ - ์œ ์ผํ•˜๊ฒŒ ์‚ฌ์šฉ์ž๊ฐ€ ์„ค์ •ํ•˜๋Š” ํ•ญ๋ชฉ */} + {/* ๋งˆ์Šคํ„ฐ ํ‚ค ์ž๋™ ์ƒ์„ฑ ์•ˆ๋‚ด */} {relationInfo && ( -
- - - - - - - - - - ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์—†์Œ - - { - updateMasterDetailConfig({ numberingRuleId: undefined }); - setNumberingRuleOpen(false); - }} - className="text-xs" - > - - ์ฑ„๋ฒˆ ์—†์Œ (์ˆ˜๋™ ์ž…๋ ฅ) - - {numberingRules - .filter((rule) => rule.table_name === masterTable || !rule.table_name) - .map((rule, idx) => { - const ruleId = String(rule.rule_id || rule.ruleId || `rule-${idx}`); - const ruleName = rule.rule_name || rule.ruleName || "(์ด๋ฆ„ ์—†์Œ)"; - return ( - { - updateMasterDetailConfig({ numberingRuleId: ruleId }); - setNumberingRuleOpen(false); - }} - className="text-xs" - > - - {ruleName} - - ); - })} - - - - - -

- ๋งˆ์Šคํ„ฐ ํ…Œ์ด๋ธ”์˜ {relationInfo.masterKeyColumn} ๊ฐ’์„ ์ž๋™ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค -

-
+

+ ๋งˆ์Šคํ„ฐ ํ…Œ์ด๋ธ”์˜ {relationInfo.masterKeyColumn} ๊ฐ’์€ ์œ„์—์„œ ์„ค์ •ํ•œ ์ฑ„๋ฒˆ ๊ทœ์น™์œผ๋กœ ์ž๋™ + ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. +

)} {/* ๋งˆ์Šคํ„ฐ ํ•„๋“œ ์„ ํƒ - ์‚ฌ์šฉ์ž๊ฐ€ ์—‘์…€ ์—…๋กœ๋“œ ์‹œ ์ž…๋ ฅํ•  ํ•„๋“œ */} @@ -3726,14 +3638,6 @@ const MasterDetailExcelUploadConfig: React.FC<{

์ฐธ์กฐ ํ…Œ์ด๋ธ”์—์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œํ•  ์ปฌ๋Ÿผ์„ ์„ ํƒํ•˜์„ธ์š”.

)} - - {/* ์—…๋กœ๋“œ ํ›„ ์ œ์–ด ์‹คํ–‰ ์„ค์ • */} - )} @@ -3741,23 +3645,181 @@ const MasterDetailExcelUploadConfig: React.FC<{ }; /** - * ์—…๋กœ๋“œ ํ›„ ์ œ์–ด ์‹คํ–‰ ์„ค์ • ์ปดํฌ๋„ŒํŠธ - * ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ œ์–ด๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์› + * ์—‘์…€ ์—…๋กœ๋“œ ์ฑ„๋ฒˆ ๊ทœ์น™ ์„ค์ • (๋‹จ์ผ ํ…Œ์ด๋ธ”/๋งˆ์Šคํ„ฐ-๋””ํ…Œ์ผ ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅ) */ -const AfterUploadControlConfig: React.FC<{ - config: any; - onUpdateProperty: (path: string, value: any) => void; - masterDetailConfig: any; - updateMasterDetailConfig: (updates: any) => void; -}> = ({ masterDetailConfig, updateMasterDetailConfig }) => { - const [nodeFlows, setNodeFlows] = useState< - Array<{ flowId: number; flowName: string; flowDescription?: string }> - >([]); +const ExcelNumberingRuleConfig: React.FC<{ + config: { numberingRuleId?: string; numberingTargetColumn?: string }; + updateConfig: (updates: { numberingRuleId?: string; numberingTargetColumn?: string }) => void; + tableName?: string; // ๋‹จ์ผ ํ…Œ์ด๋ธ”์ธ ๊ฒฝ์šฐ ํ…Œ์ด๋ธ”๋ช… + hasSplitPanel?: boolean; // ๋ถ„ํ•  ํŒจ๋„ ์—ฌ๋ถ€ (๋งˆ์Šคํ„ฐ-๋””ํ…Œ์ผ) +}> = ({ config, updateConfig, tableName, hasSplitPanel }) => { + const [numberingRules, setNumberingRules] = useState([]); + const [ruleSelectOpen, setRuleSelectOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [tableColumns, setTableColumns] = useState>([]); + const [columnsLoading, setColumnsLoading] = useState(false); + + // ์ฑ„๋ฒˆ ๊ทœ์น™ ๋ชฉ๋ก ๋กœ๋“œ + useEffect(() => { + const loadNumberingRules = async () => { + setIsLoading(true); + try { + const { apiClient } = await import("@/lib/api/client"); + const response = await apiClient.get("/numbering-rules"); + if (response.data?.success && response.data?.data) { + setNumberingRules(response.data.data); + } + } catch (error) { + console.error("์ฑ„๋ฒˆ ๊ทœ์น™ ๋ชฉ๋ก ๋กœ๋“œ ์‹คํŒจ:", error); + } finally { + setIsLoading(false); + } + }; + + loadNumberingRules(); + }, []); + + // ๋‹จ์ผ ํ…Œ์ด๋ธ”์ธ ๊ฒฝ์šฐ ์ปฌ๋Ÿผ ๋ชฉ๋ก ๋กœ๋“œ + useEffect(() => { + if (!tableName || hasSplitPanel) { + setTableColumns([]); + return; + } + + const loadColumns = async () => { + setColumnsLoading(true); + try { + const { apiClient } = await import("@/lib/api/client"); + const response = await apiClient.get(`/table-management/tables/${tableName}/columns`); + if (response.data?.success && response.data?.data?.columns) { + const cols = response.data.data.columns.map((col: any) => ({ + columnName: col.columnName || col.column_name, + columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name, + })); + setTableColumns(cols); + } + } catch (error) { + console.error("์ปฌ๋Ÿผ ๋ชฉ๋ก ๋กœ๋“œ ์‹คํŒจ:", error); + } finally { + setColumnsLoading(false); + } + }; + + loadColumns(); + }, [tableName, hasSplitPanel]); + + const selectedRule = numberingRules.find((r) => String(r.rule_id || r.ruleId) === String(config.numberingRuleId)); + + return ( +
+ +

+ ์—…๋กœ๋“œ ์‹œ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•  ์ฝ”๋“œ/๋ฒˆํ˜ธ์˜ ์ฑ„๋ฒˆ ๊ทœ์น™์„ ์„ ํƒํ•˜์„ธ์š”. +

+ + + + + + + + + + ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์—†์Œ + + { + updateConfig({ numberingRuleId: undefined, numberingTargetColumn: undefined }); + setRuleSelectOpen(false); + }} + className="text-xs" + > + + ์ฑ„๋ฒˆ ์—†์Œ + + {numberingRules.map((rule, idx) => { + const ruleId = String(rule.rule_id || rule.ruleId || `rule-${idx}`); + const ruleName = rule.rule_name || rule.ruleName || "(์ด๋ฆ„ ์—†์Œ)"; + return ( + { + updateConfig({ numberingRuleId: ruleId }); + setRuleSelectOpen(false); + }} + className="text-xs" + > + + {ruleName} + + ); + })} + + + + + + + {/* ๋‹จ์ผ ํ…Œ์ด๋ธ”์ด๊ณ  ์ฑ„๋ฒˆ ๊ทœ์น™์ด ์„ ํƒ๋œ ๊ฒฝ์šฐ, ์ ์šฉํ•  ์ปฌ๋Ÿผ ์„ ํƒ */} + {config.numberingRuleId && !hasSplitPanel && tableName && ( +
+ + +

์ฑ„๋ฒˆ ๊ฐ’์ด ์ž…๋ ฅ๋  ์ปฌ๋Ÿผ์„ ์„ ํƒํ•˜์„ธ์š”.

+
+ )} + + {/* ๋ถ„ํ•  ํŒจ๋„์ธ ๊ฒฝ์šฐ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€ */} + {config.numberingRuleId && hasSplitPanel && ( +

๋งˆ์Šคํ„ฐ-๋””ํ…Œ์ผ ๊ตฌ์กฐ์—์„œ๋Š” ๋งˆ์Šคํ„ฐ ํ‚ค ์ปฌ๋Ÿผ์— ์ž๋™ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

+ )} +
+ ); +}; + +/** + * ์—‘์…€ ์—…๋กœ๋“œ ํ›„ ์ œ์–ด ์‹คํ–‰ ์„ค์ • (๋‹จ์ผ ํ…Œ์ด๋ธ”/๋งˆ์Šคํ„ฐ-๋””ํ…Œ์ผ ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅ) + */ +const ExcelAfterUploadControlConfig: React.FC<{ + config: { afterUploadFlows?: Array<{ flowId: string; order: number }> }; + updateConfig: (updates: { afterUploadFlows?: Array<{ flowId: string; order: number }> }) => void; +}> = ({ config, updateConfig }) => { + const [nodeFlows, setNodeFlows] = useState>([]); const [flowSelectOpen, setFlowSelectOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); - // ์„ ํƒ๋œ ์ œ์–ด ๋ชฉ๋ก (๋ฐฐ์—ด๋กœ ๊ด€๋ฆฌ) - const selectedFlows: Array<{ flowId: string; order: number }> = masterDetailConfig.afterUploadFlows || []; + const selectedFlows = config.afterUploadFlows || []; // ๋…ธ๋“œ ํ”Œ๋กœ์šฐ ๋ชฉ๋ก ๋กœ๋“œ useEffect(() => { @@ -3779,53 +3841,39 @@ const AfterUploadControlConfig: React.FC<{ loadNodeFlows(); }, []); - // ์ œ์–ด ์ถ”๊ฐ€ const addFlow = (flowId: string) => { if (selectedFlows.some((f) => f.flowId === flowId)) return; const newFlows = [...selectedFlows, { flowId, order: selectedFlows.length + 1 }]; - updateMasterDetailConfig({ afterUploadFlows: newFlows }); + updateConfig({ afterUploadFlows: newFlows }); setFlowSelectOpen(false); }; - // ์ œ์–ด ์ œ๊ฑฐ const removeFlow = (flowId: string) => { - const newFlows = selectedFlows - .filter((f) => f.flowId !== flowId) - .map((f, idx) => ({ ...f, order: idx + 1 })); - updateMasterDetailConfig({ afterUploadFlows: newFlows }); + const newFlows = selectedFlows.filter((f) => f.flowId !== flowId).map((f, idx) => ({ ...f, order: idx + 1 })); + updateConfig({ afterUploadFlows: newFlows }); }; - // ์ˆœ์„œ ๋ณ€๊ฒฝ (์œ„๋กœ) const moveUp = (index: number) => { if (index === 0) return; const newFlows = [...selectedFlows]; [newFlows[index - 1], newFlows[index]] = [newFlows[index], newFlows[index - 1]]; - updateMasterDetailConfig({ - afterUploadFlows: newFlows.map((f, idx) => ({ ...f, order: idx + 1 })), - }); + updateConfig({ afterUploadFlows: newFlows.map((f, idx) => ({ ...f, order: idx + 1 })) }); }; - // ์ˆœ์„œ ๋ณ€๊ฒฝ (์•„๋ž˜๋กœ) const moveDown = (index: number) => { if (index === selectedFlows.length - 1) return; const newFlows = [...selectedFlows]; [newFlows[index], newFlows[index + 1]] = [newFlows[index + 1], newFlows[index]]; - updateMasterDetailConfig({ - afterUploadFlows: newFlows.map((f, idx) => ({ ...f, order: idx + 1 })), - }); + updateConfig({ afterUploadFlows: newFlows.map((f, idx) => ({ ...f, order: idx + 1 })) }); }; - // ์„ ํƒ๋˜์ง€ ์•Š์€ ํ”Œ๋กœ์šฐ๋งŒ ํ•„ํ„ฐ๋ง const availableFlows = nodeFlows.filter((f) => !selectedFlows.some((s) => s.flowId === String(f.flowId))); return (
-

- ์—‘์…€ ์—…๋กœ๋“œ ์™„๋ฃŒ ํ›„ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•  ์ œ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”. -

+

์—‘์…€ ์—…๋กœ๋“œ ์™„๋ฃŒ ํ›„ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•  ์ œ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

- {/* ์„ ํƒ๋œ ์ œ์–ด ๋ชฉ๋ก */} {selectedFlows.length > 0 && (
{selectedFlows.map((selected, index) => { @@ -3852,7 +3900,12 @@ const AfterUploadControlConfig: React.FC<{ > -
@@ -3861,7 +3914,6 @@ const AfterUploadControlConfig: React.FC<{
)} - {/* ์ œ์–ด ์ถ”๊ฐ€ ๋ฒ„ํŠผ */}