/** * 컴포넌트 기본값 및 복원 유틸리티 * * screen_layouts_v2 테이블의 config_overrides를 기본값과 병합하여 * 전체 componentConfig를 복원합니다. */ // 컴포넌트별 기본값 맵 export const componentDefaults: Record = { "button-primary": { type: "button-primary", text: "저장", actionType: "button", variant: "primary", webType: "button", }, "v2-button-primary": { type: "v2-button-primary", text: "저장", actionType: "button", variant: "primary", webType: "button", }, "text-input": { type: "text-input", webType: "text", format: "none", multiline: false, placeholder: "텍스트를 입력하세요", }, "number-input": { type: "number-input", webType: "number", placeholder: "숫자를 입력하세요", }, "date-input": { type: "date-input", webType: "date", format: "YYYY-MM-DD", showTime: false, placeholder: "날짜를 선택하세요", }, "select-basic": { type: "select-basic", webType: "code", placeholder: "선택하세요", options: [], }, "file-upload": { type: "file-upload", webType: "file", placeholder: "입력하세요", }, "table-list": { type: "table-list", webType: "table", displayMode: "table", showHeader: true, showFooter: true, autoLoad: true, autoWidth: true, stickyHeader: false, height: "auto", columns: [], pagination: { enabled: true, pageSize: 20, showSizeSelector: true, showPageInfo: true, pageSizeOptions: [10, 20, 50, 100], }, checkbox: { enabled: true, multiple: true, position: "left", selectAll: true, }, horizontalScroll: { enabled: false, }, filter: { enabled: false, filters: [], }, actions: { showActions: false, actions: [], bulkActions: false, bulkActionList: [], }, tableStyle: { theme: "default", headerStyle: "default", rowHeight: "normal", alternateRows: false, hoverEffect: true, borderStyle: "light", }, }, "v2-table-list": { type: "v2-table-list", webType: "table", displayMode: "table", showHeader: true, showFooter: true, autoLoad: true, autoWidth: true, stickyHeader: false, height: "auto", columns: [], pagination: { enabled: true, pageSize: 20, showSizeSelector: true, showPageInfo: true, pageSizeOptions: [10, 20, 50, 100], }, checkbox: { enabled: true, multiple: true, position: "left", selectAll: true, }, horizontalScroll: { enabled: false }, filter: { enabled: false, filters: [] }, actions: { showActions: false, actions: [], bulkActions: false, bulkActionList: [] }, tableStyle: { theme: "default", headerStyle: "default", rowHeight: "normal", alternateRows: false, hoverEffect: true, borderStyle: "light" }, }, "table-search-widget": { type: "table-search-widget", webType: "custom" }, "split-panel-layout": { type: "split-panel-layout", webType: "text", autoLoad: true, resizable: true, splitRatio: 30 }, "v2-split-panel-layout": { type: "v2-split-panel-layout", webType: "custom" }, "tabs-widget": { type: "tabs-widget", webType: "text", tabs: [] }, "v2-tabs-widget": { type: "v2-tabs-widget", webType: "custom", tabs: [] }, "flow-widget": { type: "flow-widget", webType: "text", displayMode: "horizontal", allowDataMove: false, showStepCount: true }, "entity-search-input": { type: "entity-search-input", webType: "entity" }, "autocomplete-search-input": { type: "autocomplete-search-input", webType: "entity" }, "unified-list": { type: "unified-list", webType: "table" }, "modal-repeater-table": { type: "modal-repeater-table", webType: "table", columns: [], multiSelect: true }, "category-manager": { type: "category-manager", webType: "custom" }, "numbering-rule": { type: "numbering-rule", webType: "text" }, "conditional-container": { type: "conditional-container", webType: "custom" }, "selected-items-detail-input": { type: "selected-items-detail-input", webType: "custom" }, "text-display": { type: "text-display", webType: "text" }, "image-widget": { type: "image-widget", webType: "image" }, "textarea-basic": { type: "textarea-basic", webType: "textarea", placeholder: "내용을 입력하세요" }, "checkbox-basic": { type: "checkbox-basic", webType: "checkbox" }, "radio-basic": { type: "radio-basic", webType: "radio" }, "divider-line": { type: "divider-line", webType: "custom" }, "section-paper": { type: "section-paper", webType: "custom" }, "section-card": { type: "section-card", webType: "custom" }, "card-display": { type: "card-display", webType: "custom" }, "pivot-grid": { type: "pivot-grid", webType: "table" }, "rack-structure": { type: "rack-structure", webType: "custom" }, "v2-rack-structure": { type: "v2-rack-structure", webType: "custom" }, "location-swap-selector": { type: "location-swap-selector", webType: "custom" }, "screen-split-panel": { type: "screen-split-panel", webType: "custom" }, "universal-form-modal": { type: "universal-form-modal", webType: "custom" }, "repeater-field-group": { type: "repeater-field-group", webType: "custom" }, "repeat-screen-modal": { type: "repeat-screen-modal", webType: "custom" }, "related-data-buttons": { type: "related-data-buttons", webType: "custom" }, "split-panel-layout2": { type: "split-panel-layout2", webType: "custom" }, "unified-input": { type: "unified-input", webType: "text" }, "unified-select": { type: "unified-select", webType: "select" }, "unified-date": { type: "unified-date", webType: "date" }, "unified-repeater": { type: "unified-repeater", webType: "custom" }, "v2-repeat-container": { type: "v2-repeat-container", webType: "custom" }, }; /** * 컴포넌트 기본값 조회 */ export function getComponentDefaults(componentType: string): any { return componentDefaults[componentType] || {}; } /** * 설정 복원: 기본값 + overrides 병합 * * @param componentType 컴포넌트 타입 * @param overrides 저장된 차이값 (config_overrides) * @returns 복원된 전체 설정 */ export function reconstructConfig(componentType: string, overrides: any): any { const defaults = getComponentDefaults(componentType); if (!overrides || Object.keys(overrides).length === 0) { return { ...defaults }; } // _originalKeys가 있으면 해당 키만 복원 const originalKeys = overrides._originalKeys; if (originalKeys && Array.isArray(originalKeys)) { const result: any = {}; for (const key of originalKeys) { if (key === "_originalKeys") continue; if (Object.prototype.hasOwnProperty.call(overrides, key)) { result[key] = overrides[key]; } else if (Object.prototype.hasOwnProperty.call(defaults, key)) { result[key] = defaults[key]; } } return result; } // _originalKeys가 없으면 단순 병합 return { ...defaults, ...overrides }; } /** * 깊은 비교 함수 */ export function isDeepEqual(a: any, b: any): boolean { if (a === b) return true; if (a == null || b == null) return a === b; if (typeof a !== typeof b) return false; if (typeof a !== "object") return a === b; if (Array.isArray(a) !== Array.isArray(b)) return false; if (Array.isArray(a)) { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (!isDeepEqual(a[i], b[i])) return false; } return true; } const keysA = Object.keys(a); const keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; for (const key of keysA) { if (!keysB.includes(key)) return false; if (!isDeepEqual(a[key], b[key])) return false; } return true; } /** * 차이값 추출: 현재 설정에서 기본값과 다른 것만 추출 */ export function extractConfigDiff(componentType: string, currentConfig: any): any { const defaults = getComponentDefaults(componentType); if (!currentConfig) return {}; const diff: any = { _originalKeys: Object.keys(currentConfig), }; for (const key of Object.keys(currentConfig)) { const defaultVal = defaults[key]; const currentVal = currentConfig[key]; if (!isDeepEqual(defaultVal, currentVal)) { diff[key] = currentVal; } } return diff; }