diff --git a/frontend/lib/api/file.ts b/frontend/lib/api/file.ts index 318f26fb..4908b381 100644 --- a/frontend/lib/api/file.ts +++ b/frontend/lib/api/file.ts @@ -32,7 +32,7 @@ export const uploadFiles = async (params: { files: FileList | File[]; tableName?: string; fieldName?: string; - recordId?: string; + recordId?: string | number; docType?: string; docTypeName?: string; targetObjid?: string; @@ -43,6 +43,7 @@ export const uploadFiles = async (params: { columnName?: string; isVirtualFileColumn?: boolean; companyCode?: string; // ๐Ÿ”’ ๋ฉ€ํ‹ฐํ…Œ๋„Œ์‹œ: ํšŒ์‚ฌ ์ฝ”๋“œ + isRecordMode?: boolean; // ๐Ÿ†• ๋ ˆ์ฝ”๋“œ ๋ชจ๋“œ ํ”Œ๋ž˜๊ทธ }): Promise => { const formData = new FormData(); @@ -55,7 +56,7 @@ export const uploadFiles = async (params: { // ์ถ”๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค ์ถ”๊ฐ€ if (params.tableName) formData.append("tableName", params.tableName); if (params.fieldName) formData.append("fieldName", params.fieldName); - if (params.recordId) formData.append("recordId", params.recordId); + if (params.recordId) formData.append("recordId", String(params.recordId)); if (params.docType) formData.append("docType", params.docType); if (params.docTypeName) formData.append("docTypeName", params.docTypeName); if (params.targetObjid) formData.append("targetObjid", params.targetObjid); @@ -66,6 +67,8 @@ export const uploadFiles = async (params: { if (params.columnName) formData.append("columnName", params.columnName); if (params.isVirtualFileColumn !== undefined) formData.append("isVirtualFileColumn", params.isVirtualFileColumn.toString()); if (params.companyCode) formData.append("companyCode", params.companyCode); // ๐Ÿ”’ ๋ฉ€ํ‹ฐํ…Œ๋„Œ์‹œ + // ๐Ÿ†• ๋ ˆ์ฝ”๋“œ ๋ชจ๋“œ ํ”Œ๋ž˜๊ทธ ์ถ”๊ฐ€ (๋ฐฑ์—”๋“œ์—์„œ attachments ์ปฌ๋Ÿผ ์ž๋™ ์—…๋ฐ์ดํŠธ์šฉ) + if (params.isRecordMode !== undefined) formData.append("isRecordMode", params.isRecordMode.toString()); const response = await apiClient.post("/files/upload", formData, { headers: { diff --git a/frontend/lib/registry/components/accordion-basic/AccordionBasicComponent.tsx b/frontend/lib/registry/components/accordion-basic/AccordionBasicComponent.tsx index c25cb7bd..78951f7e 100644 --- a/frontend/lib/registry/components/accordion-basic/AccordionBasicComponent.tsx +++ b/frontend/lib/registry/components/accordion-basic/AccordionBasicComponent.tsx @@ -602,6 +602,9 @@ export const AccordionBasicComponent: React.FC = ( isInModal: _isInModal, isPreview: _isPreview, originalData: _originalData, + _originalData: __originalData, + _initialData: __initialData, + _groupedData: __groupedData, allComponents: _allComponents, selectedRows: _selectedRows, selectedRowsData: _selectedRowsData, diff --git a/frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx b/frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx index 1942d268..ae6a01d8 100644 --- a/frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx +++ b/frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx @@ -984,6 +984,9 @@ export const ButtonPrimaryComponent: React.FC = ({ flowSelectedStepId: _flowSelectedStepId, // ํ”Œ๋กœ์šฐ ์„ ํƒ ์Šคํ… ID ํ•„ํ„ฐ๋ง onFlowRefresh: _onFlowRefresh, // ํ”Œ๋กœ์šฐ ์ƒˆ๋กœ๊ณ ์นจ ์ฝœ๋ฐฑ ํ•„ํ„ฐ๋ง originalData: _originalData, // ๋ถ€๋ถ„ ์—…๋ฐ์ดํŠธ์šฉ ์›๋ณธ ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ๋ง + _originalData: __originalData, // DOM ํ•„ํ„ฐ๋ง + _initialData: __initialData, // DOM ํ•„ํ„ฐ๋ง + _groupedData: __groupedData, // DOM ํ•„ํ„ฐ๋ง refreshKey: _refreshKey, // ํ•„ํ„ฐ๋ง ์ถ”๊ฐ€ isInModal: _isInModal, // ํ•„ํ„ฐ๋ง ์ถ”๊ฐ€ mode: _mode, // ํ•„ํ„ฐ๋ง ์ถ”๊ฐ€ diff --git a/frontend/lib/registry/components/divider-line/DividerLineComponent.tsx b/frontend/lib/registry/components/divider-line/DividerLineComponent.tsx index d2b61c90..ea4428ca 100644 --- a/frontend/lib/registry/components/divider-line/DividerLineComponent.tsx +++ b/frontend/lib/registry/components/divider-line/DividerLineComponent.tsx @@ -86,6 +86,9 @@ export const DividerLineComponent: React.FC = ({ isInModal: _isInModal, readonly: _readonly, originalData: _originalData, + _originalData: __originalData, + _initialData: __initialData, + _groupedData: __groupedData, allComponents: _allComponents, onUpdateLayout: _onUpdateLayout, selectedRows: _selectedRows, diff --git a/frontend/lib/registry/components/file-upload/FileUploadComponent.tsx b/frontend/lib/registry/components/file-upload/FileUploadComponent.tsx index 805fe755..dd4f4c6b 100644 --- a/frontend/lib/registry/components/file-upload/FileUploadComponent.tsx +++ b/frontend/lib/registry/components/file-upload/FileUploadComponent.tsx @@ -603,10 +603,16 @@ const FileUploadComponent: React.FC = ({ targetObjid, }); + // ๐Ÿ”‘ ๋ ˆ์ฝ”๋“œ ๋ชจ๋“œ์ผ ๋•Œ๋Š” effectiveTableName์„ ์šฐ์„  ์‚ฌ์šฉ + // formData.linkedTable์ด 'screen_files' ๊ฐ™์€ ๊ธฐ๋ณธ๊ฐ’์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ ˆ์ฝ”๋“œ ๋ชจ๋“œ์—์„œ๋Š” ๋ฌด์‹œ + const finalLinkedTable = effectiveIsRecordMode + ? effectiveTableName + : (formData?.linkedTable || effectiveTableName); + const uploadData = { // ๐ŸŽฏ formData์—์„œ ๋ฐฑ์—”๋“œ API ์„ค์ • ๊ฐ€์ ธ์˜ค๊ธฐ autoLink: formData?.autoLink || true, - linkedTable: formData?.linkedTable || effectiveTableName, + linkedTable: finalLinkedTable, recordId: effectiveRecordId || `temp_${component.id}`, columnName: effectiveColumnName, isVirtualFileColumn: formData?.isVirtualFileColumn || true, @@ -620,13 +626,27 @@ const FileUploadComponent: React.FC = ({ // ๐Ÿ†• ๋ ˆ์ฝ”๋“œ ๋ชจ๋“œ ํ”Œ๋ž˜๊ทธ isRecordMode: effectiveIsRecordMode, }; + + console.log("๐Ÿ“ค [FileUploadComponent] uploadData ์ตœ์ข…:", { + isRecordMode: effectiveIsRecordMode, + linkedTable: finalLinkedTable, + recordId: effectiveRecordId, + columnName: effectiveColumnName, + targetObjid, + }); + console.log("๐Ÿš€ [FileUploadComponent] uploadFiles API ํ˜ธ์ถœ ์ง์ „:", { + filesCount: filesToUpload.length, + uploadData, + }); + const response = await uploadFiles({ files: filesToUpload, ...uploadData, }); + console.log("๐Ÿ“ฅ [FileUploadComponent] uploadFiles API ์‘๋‹ต:", response); if (response.success) { // FileUploadResponse ํƒ€์ž…์— ๋งž๊ฒŒ files ๋ฐฐ์—ด ์‚ฌ์šฉ diff --git a/frontend/lib/registry/components/repeat-screen-modal/RepeatScreenModalComponent.tsx b/frontend/lib/registry/components/repeat-screen-modal/RepeatScreenModalComponent.tsx index 980bbfe9..4b4809a1 100644 --- a/frontend/lib/registry/components/repeat-screen-modal/RepeatScreenModalComponent.tsx +++ b/frontend/lib/registry/components/repeat-screen-modal/RepeatScreenModalComponent.tsx @@ -52,11 +52,15 @@ export function RepeatScreenModalComponent({ config, className, groupedData: propsGroupedData, // EditModal์—์„œ ์ „๋‹ฌ๋ฐ›๋Š” ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ + // DynamicComponentRenderer์—์„œ ์ „๋‹ฌ๋˜๋Š” props (DOM ์ „๋‹ฌ ๋ฐฉ์ง€) + _initialData, + _originalData: _propsOriginalData, + _groupedData, ...props -}: RepeatScreenModalComponentProps) { +}: RepeatScreenModalComponentProps & { _initialData?: any; _originalData?: any; _groupedData?: any }) { // props์—์„œ๋„ groupedData๋ฅผ ์ถ”์ถœ (DynamicWebTypeRenderer์—์„œ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์Œ) // DynamicComponentRenderer์—์„œ๋Š” _groupedData๋กœ ์ „๋‹ฌ๋จ - const groupedData = propsGroupedData || (props as any).groupedData || (props as any)._groupedData; + const groupedData = propsGroupedData || (props as any).groupedData || _groupedData; const componentConfig = { ...config, ...component?.config, diff --git a/frontend/lib/registry/components/table-list/TableListComponent.tsx b/frontend/lib/registry/components/table-list/TableListComponent.tsx index 7bb56779..b722e31c 100644 --- a/frontend/lib/registry/components/table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/table-list/TableListComponent.tsx @@ -4065,30 +4065,54 @@ export const TableListComponent: React.FC = ({ } // ๐Ÿ“Ž ์ฒจ๋ถ€ํŒŒ์ผ ํƒ€์ž…: ํŒŒ์ผ ์•„์ด์ฝ˜๊ณผ ๊ฐœ์ˆ˜ ํ‘œ์‹œ - if (inputType === "file" || inputType === "attachment" || column.columnName === "attachments") { + // ์ปฌ๋Ÿผ๋ช…์ด 'attachments'๋ฅผ ํฌํ•จํ•˜๊ฑฐ๋‚˜, inputType์ด file/attachment์ธ ๊ฒฝ์šฐ + const isAttachmentColumn = + inputType === "file" || + inputType === "attachment" || + column.columnName === "attachments" || + column.columnName?.toLowerCase().includes("attachment") || + column.columnName?.toLowerCase().includes("file"); + + if (isAttachmentColumn) { // JSONB ๋ฐฐ์—ด ๋˜๋Š” JSON ๋ฌธ์ž์—ด ํŒŒ์‹ฑ let files: any[] = []; try { - if (typeof value === "string") { - files = JSON.parse(value); + if (typeof value === "string" && value.trim()) { + const parsed = JSON.parse(value); + files = Array.isArray(parsed) ? parsed : []; } else if (Array.isArray(value)) { files = value; + } else if (value && typeof value === "object") { + // ๋‹จ์ผ ๊ฐ์ฒด์ธ ๊ฒฝ์šฐ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ + files = [value]; } - } catch { + } catch (e) { // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๋นˆ ๋ฐฐ์—ด + console.warn("๐Ÿ“Ž [TableList] ์ฒจ๋ถ€ํŒŒ์ผ ํŒŒ์‹ฑ ์‹คํŒจ:", { columnName: column.columnName, value, error: e }); } if (!files || files.length === 0) { return -; } - // ํŒŒ์ผ ๊ฐœ์ˆ˜์™€ ์•„์ด์ฝ˜ ํ‘œ์‹œ + // ํŒŒ์ผ ์ด๋ฆ„ ํ‘œ์‹œ (์—ฌ๋Ÿฌ ๊ฐœ๋ฉด ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„) const { Paperclip } = require("lucide-react"); + const fileNames = files.map((f: any) => f.realFileName || f.real_file_name || f.name || "ํŒŒ์ผ").join(", "); + return ( -
- - {files.length} - ๊ฐœ +
+ + + {fileNames} + + {files.length > 1 && ( + + ({files.length}) + + )}
); } diff --git a/frontend/lib/registry/components/text-input/TextInputComponent.tsx b/frontend/lib/registry/components/text-input/TextInputComponent.tsx index 72dabb61..ad37f19f 100644 --- a/frontend/lib/registry/components/text-input/TextInputComponent.tsx +++ b/frontend/lib/registry/components/text-input/TextInputComponent.tsx @@ -224,6 +224,9 @@ export const TextInputComponent: React.FC = ({ isInModal: _isInModal, isPreview: _isPreview, originalData: _originalData, + _originalData: __originalData, + _initialData: __initialData, + _groupedData: __groupedData, allComponents: _allComponents, selectedRows: _selectedRows, selectedRowsData: _selectedRowsData, diff --git a/frontend/lib/registry/components/universal-form-modal/UniversalFormModalComponent.tsx b/frontend/lib/registry/components/universal-form-modal/UniversalFormModalComponent.tsx index a78d2e95..c503ded6 100644 --- a/frontend/lib/registry/components/universal-form-modal/UniversalFormModalComponent.tsx +++ b/frontend/lib/registry/components/universal-form-modal/UniversalFormModalComponent.tsx @@ -126,11 +126,13 @@ export function UniversalFormModalComponent({ initialData: propInitialData, // DynamicComponentRenderer์—์„œ ์ „๋‹ฌ๋˜๋Š” props (DOM ์ „๋‹ฌ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด _ prefix ์‚ฌ์šฉ) _initialData, + _originalData, + _groupedData, onSave, onCancel, onChange, ...restProps // ๋‚˜๋จธ์ง€ props๋Š” DOM์— ์ „๋‹ฌํ•˜์ง€ ์•Š์Œ -}: UniversalFormModalComponentProps & { _initialData?: any }) { +}: UniversalFormModalComponentProps & { _initialData?: any; _originalData?: any; _groupedData?: any }) { // initialData ์šฐ์„ ์ˆœ์œ„: ์ง์ ‘ ์ „๋‹ฌ๋œ prop > DynamicComponentRenderer์—์„œ ์ „๋‹ฌ๋œ prop const initialData = propInitialData || _initialData; // ์„ค์ • ๋ณ‘ํ•ฉ