diff --git a/frontend/app/(main)/screens/[screenId]/page.tsx b/frontend/app/(main)/screens/[screenId]/page.tsx index 95305aaf..160883ad 100644 --- a/frontend/app/(main)/screens/[screenId]/page.tsx +++ b/frontend/app/(main)/screens/[screenId]/page.tsx @@ -87,10 +87,12 @@ function ScreenViewPage() { // ๐Ÿ†• ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๋†’์ด ์ถ”์  (์ปดํฌ๋„ŒํŠธ ID โ†’ ๋†’์ด) const [conditionalContainerHeights, setConditionalContainerHeights] = useState>({}); - // ๐Ÿ†• ๋ ˆ์ด์–ด ์‹œ์Šคํ…œ ์ง€์› + // ๋ ˆ์ด์–ด ์‹œ์Šคํ…œ ์ง€์› const [conditionalLayers, setConditionalLayers] = useState([]); - // ๐Ÿ†• ์กฐ๊ฑด๋ถ€ ์˜์—ญ(Zone) ๋ชฉ๋ก + // ์กฐ๊ฑด๋ถ€ ์˜์—ญ(Zone) ๋ชฉ๋ก const [zones, setZones] = useState([]); + // ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์— ์˜ํ•ด ๊ฐ•์ œ ํ™œ์„ฑํ™”๋œ ๋ ˆ์ด์–ด ID ๋ชฉ๋ก + const [forceActivatedLayerIds, setForceActivatedLayerIds] = useState([]); // ํŽธ์ง‘ ๋ชจ๋‹ฌ ์ƒํƒœ const [editModalOpen, setEditModalOpen] = useState(false); @@ -378,11 +380,51 @@ function ScreenViewPage() { } }); - return newActiveIds; - }, [formData, conditionalLayers, layout]); + // ๊ฐ•์ œ ํ™œ์„ฑํ™”๋œ ๋ ˆ์ด์–ด ID ๋ณ‘ํ•ฉ + for (const forcedId of forceActivatedLayerIds) { + if (!newActiveIds.includes(forcedId)) { + newActiveIds.push(forcedId); + } + } - // ๐Ÿ†• ๋ฉ”์ธ ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ ์ž๋™ ๋กœ๋“œ (๋‹จ์ผ ๋ ˆ์ฝ”๋“œ ํผ) - // ํ™”๋ฉด์˜ ๋ฉ”์ธ ํ…Œ์ด๋ธ”์—์„œ ์‚ฌ์šฉ์ž ํšŒ์‚ฌ ์ฝ”๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜์—ฌ ํผ์— ์ž๋™ ์ฑ„์›€ + return newActiveIds; + }, [formData, conditionalLayers, layout, forceActivatedLayerIds]); + + // ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์— ์˜ํ•œ ๋ ˆ์ด์–ด ๊ฐ•์ œ ํ™œ์„ฑํ™” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ + useEffect(() => { + const handleActivateLayer = (e: Event) => { + const { componentId, targetLayerId } = (e as CustomEvent).detail || {}; + if (!componentId && !targetLayerId) return; + + // targetLayerId๊ฐ€ ์ง์ ‘ ์ง€์ •๋œ ๊ฒฝ์šฐ + if (targetLayerId) { + setForceActivatedLayerIds((prev) => + prev.includes(targetLayerId) ? prev : [...prev, targetLayerId], + ); + console.log(`๐Ÿ”“ [๋ ˆ์ด์–ด ๊ฐ•์ œ ํ™œ์„ฑํ™”] layerId: ${targetLayerId}`); + return; + } + + // componentId๋กœ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์†ํ•œ ๋ ˆ์ด์–ด๋ฅผ ์ฐพ์•„ ํ™œ์„ฑํ™” + for (const layer of conditionalLayers) { + const found = layer.components.some((comp) => comp.id === componentId); + if (found) { + setForceActivatedLayerIds((prev) => + prev.includes(layer.id) ? prev : [...prev, layer.id], + ); + console.log(`๐Ÿ”“ [๋ ˆ์ด์–ด ๊ฐ•์ œ ํ™œ์„ฑํ™”] componentId: ${componentId} โ†’ layerId: ${layer.id}`); + return; + } + } + }; + + window.addEventListener("activateLayerForComponent", handleActivateLayer); + return () => { + window.removeEventListener("activateLayerForComponent", handleActivateLayer); + }; + }, [conditionalLayers]); + + // ๋ฉ”์ธ ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ ์ž๋™ ๋กœ๋“œ (๋‹จ์ผ ๋ ˆ์ฝ”๋“œ ํผ) useEffect(() => { const loadMainTableData = async () => { if (!screen || !layout || !layout.components || !companyCode) { diff --git a/frontend/components/common/ScreenModal.tsx b/frontend/components/common/ScreenModal.tsx index 16dd5afc..a79f26e3 100644 --- a/frontend/components/common/ScreenModal.tsx +++ b/frontend/components/common/ScreenModal.tsx @@ -25,6 +25,7 @@ import { useSplitPanelContext } from "@/contexts/SplitPanelContext"; import { ActiveTabProvider } from "@/contexts/ActiveTabContext"; import { convertV2ToLegacy, isValidV2Layout } from "@/lib/utils/layoutV2Converter"; import { ConditionalZone, LayerDefinition } from "@/types/screen-management"; +import { ScreenContextProvider } from "@/contexts/ScreenContext"; interface ScreenModalState { isOpen: boolean; @@ -1025,6 +1026,10 @@ export const ScreenModal: React.FC = ({ className }) => { ) : screenData ? ( +
= ({ className }) => {
+
) : (

ํ™”๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

diff --git a/frontend/components/screen/EditModal.tsx b/frontend/components/screen/EditModal.tsx index 8dad77db..5f13cb78 100644 --- a/frontend/components/screen/EditModal.tsx +++ b/frontend/components/screen/EditModal.tsx @@ -17,6 +17,7 @@ import { dynamicFormApi } from "@/lib/api/dynamicForm"; import { useAuth } from "@/hooks/useAuth"; import { ConditionalZone, LayerDefinition } from "@/types/screen-management"; import { convertV2ToLegacy, isValidV2Layout } from "@/lib/utils/layoutV2Converter"; +import { ScreenContextProvider } from "@/contexts/ScreenContext"; interface EditModalState { isOpen: boolean; @@ -1385,12 +1386,16 @@ export const EditModal: React.FC = ({ className }) => {
) : screenData ? ( +
{ const baseHeight = (screenDimensions?.height || 600) + 30; if (activeConditionalComponents.length > 0) { @@ -1546,6 +1551,7 @@ export const EditModal: React.FC = ({ className }) => { ); })}
+
) : (

ํ™”๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

diff --git a/frontend/components/screen/ScreenDesigner.tsx b/frontend/components/screen/ScreenDesigner.tsx index fcb5b100..7f94bca0 100644 --- a/frontend/components/screen/ScreenDesigner.tsx +++ b/frontend/components/screen/ScreenDesigner.tsx @@ -551,9 +551,12 @@ export default function ScreenDesigner({ originalRegion: null, }); - // ๐Ÿ†• ํ˜„์žฌ ํ™œ์„ฑ ๋ ˆ์ด์–ด์˜ Zone ์ •๋ณด (์บ”๋ฒ„์Šค ํฌ๊ธฐ ๊ฒฐ์ •์šฉ) + // ํ˜„์žฌ ํ™œ์„ฑ ๋ ˆ์ด์–ด์˜ Zone ์ •๋ณด (์บ”๋ฒ„์Šค ํฌ๊ธฐ ๊ฒฐ์ •์šฉ) const [activeLayerZone, setActiveLayerZone] = useState(null); + // ๋‹ค๋ฅธ ๋ ˆ์ด์–ด์˜ ์ปดํฌ๋„ŒํŠธ ๋ฉ”ํƒ€ ์ •๋ณด ์บ์‹œ (๋ฐ์ดํ„ฐ ์ „๋‹ฌ ํƒ€๊ฒŸ ์„ ํƒ์šฉ) + const [otherLayerComponents, setOtherLayerComponents] = useState([]); + // ๐Ÿ†• activeLayerId ๋ณ€๊ฒฝ ์‹œ ํ•ด๋‹น ๋ ˆ์ด์–ด์˜ Zone ์ฐพ๊ธฐ useEffect(() => { if (activeLayerId <= 1 || !selectedScreen?.screenId) { @@ -578,6 +581,41 @@ export default function ScreenDesigner({ findZone(); }, [activeLayerId, selectedScreen?.screenId, zones]); + // ๋‹ค๋ฅธ ๋ ˆ์ด์–ด์˜ ์ปดํฌ๋„ŒํŠธ ๋ฉ”ํƒ€ ์ •๋ณด ๋กœ๋“œ (๋ฐ์ดํ„ฐ ์ „๋‹ฌ ํƒ€๊ฒŸ ์„ ํƒ์šฉ) + useEffect(() => { + if (!selectedScreen?.screenId) return; + const loadOtherLayerComponents = async () => { + try { + const allLayers = await screenApi.getScreenLayers(selectedScreen.screenId); + const currentLayerId = activeLayerIdRef.current || 1; + const otherLayers = allLayers.filter((l: any) => l.layer_id !== currentLayerId && l.layer_id > 0); + + const components: ComponentData[] = []; + for (const layerInfo of otherLayers) { + try { + const layerData = await screenApi.getLayerLayout(selectedScreen.screenId, layerInfo.layer_id); + const rawComps = layerData?.components; + if (rawComps && Array.isArray(rawComps)) { + for (const comp of rawComps) { + components.push({ + ...comp, + _layerName: layerInfo.layer_name || `๋ ˆ์ด์–ด ${layerInfo.layer_id}`, + _layerId: String(layerInfo.layer_id), + } as any); + } + } + } catch { + // ๊ฐœ๋ณ„ ๋ ˆ์ด์–ด ๋กœ๋“œ ์‹คํŒจ ๋ฌด์‹œ + } + } + setOtherLayerComponents(components); + } catch { + setOtherLayerComponents([]); + } + }; + loadOtherLayerComponents(); + }, [selectedScreen?.screenId, activeLayerId]); + // ์บ”๋ฒ„์Šค์— ๋ Œ๋”๋งํ•  ์ปดํฌ๋„ŒํŠธ (DB ๊ธฐ๋ฐ˜ ๋ ˆ์ด์–ด: ๊ฐ ๋ ˆ์ด์–ด๋ณ„๋กœ ๋ณ„๋„ ๋กœ๋“œ๋˜๋ฏ€๋กœ ์ „์ฒด ํ‘œ์‹œ) const visibleComponents = useMemo(() => { return layout.components; @@ -6516,8 +6554,8 @@ export default function ScreenDesigner({ updateComponentProperty(selectedComponent.id, "style", style); } }} - allComponents={layout.components} // ๐Ÿ†• ํ”Œ๋กœ์šฐ ์œ„์ ฏ ๊ฐ์ง€์šฉ - menuObjid={menuObjid} // ๐Ÿ†• ๋ฉ”๋‰ด OBJID ์ „๋‹ฌ + allComponents={[...layout.components, ...otherLayerComponents]} + menuObjid={menuObjid} /> )} diff --git a/frontend/components/screen/config-panels/ButtonConfigPanel.tsx b/frontend/components/screen/config-panels/ButtonConfigPanel.tsx index ea2febb1..ba9acbf1 100644 --- a/frontend/components/screen/config-panels/ButtonConfigPanel.tsx +++ b/frontend/components/screen/config-panels/ButtonConfigPanel.tsx @@ -2966,11 +2966,17 @@ export const ButtonConfigPanel: React.FC = ({ - {/* ๋ฐ์ดํ„ฐ ์ œ๊ณต ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ ํ•„ํ„ฐ๋ง */} + {/* ์ž๋™ ํƒ์ƒ‰ ์˜ต์…˜ (๋ ˆ์ด์–ด๋ณ„ ํ…Œ์ด๋ธ”์ด ๋‹ค๋ฅผ ๋•Œ ์œ ์šฉ) */} + +
+ ์ž๋™ ํƒ์ƒ‰ (ํ˜„์žฌ ํ™œ์„ฑ ํ…Œ์ด๋ธ”) + (auto) +
+
+ {/* ๋ฐ์ดํ„ฐ ์ œ๊ณต ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ ํ•„ํ„ฐ๋ง (๋ชจ๋“  ๋ ˆ์ด์–ด ํฌํ•จ) */} {allComponents .filter((comp: any) => { const type = comp.componentType || comp.type || ""; - // ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…๋“ค return ["table-list", "repeater-field-group", "form-group", "data-table"].some((t) => type.includes(t), ); @@ -2978,11 +2984,17 @@ export const ButtonConfigPanel: React.FC = ({ .map((comp: any) => { const compType = comp.componentType || comp.type || "unknown"; const compLabel = comp.label || comp.componentConfig?.title || comp.id; + const layerName = comp._layerName; return (
{compLabel} ({compType}) + {layerName && ( + + {layerName} + + )}
); @@ -2999,7 +3011,9 @@ export const ButtonConfigPanel: React.FC = ({ )}
-

ํ…Œ์ด๋ธ”, ๋ฐ˜๋ณต ํ•„๋“œ ๊ทธ๋ฃน ๋“ฑ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ

+

+ ๋ ˆ์ด์–ด๋ณ„๋กœ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์ด ์žˆ์„ ๊ฒฝ์šฐ "์ž๋™ ํƒ์ƒ‰"์„ ์„ ํƒํ•˜๋ฉด ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ๋ ˆ์ด์–ด์˜ ํ…Œ์ด๋ธ”์„ ์ž๋™์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค +

@@ -3037,33 +3051,47 @@ export const ButtonConfigPanel: React.FC = ({ { - const currentSources = config.action?.dataTransfer?.additionalSources || []; - const newSources = [...currentSources]; - if (newSources.length === 0) { - newSources.push({ componentId: "", fieldName: e.target.value }); - } else { - newSources[0] = { ...newSources[0], fieldName: e.target.value }; - } - onUpdateProperty("componentConfig.action.dataTransfer.additionalSources", newSources); - }} - className="h-8 text-xs" - /> -

ํƒ€๊ฒŸ ํ…Œ์ด๋ธ”์— ์ €์žฅ๋  ํ•„๋“œ๋ช…

+ + + + + + + + + ์ปฌ๋Ÿผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. + + { + const currentSources = config.action?.dataTransfer?.additionalSources || []; + const newSources = [...currentSources]; + if (newSources.length === 0) { + newSources.push({ componentId: "", fieldName: "" }); + } else { + newSources[0] = { ...newSources[0], fieldName: "" }; + } + onUpdateProperty("componentConfig.action.dataTransfer.additionalSources", newSources); + }} + className="text-xs" + > + + ์„ ํƒ ์•ˆ ํ•จ (์ „์ฒด ๋ฐ์ดํ„ฐ ๋ณ‘ํ•ฉ) + + {(mappingTargetColumns.length > 0 ? mappingTargetColumns : currentTableColumns).map((col) => ( + { + const currentSources = config.action?.dataTransfer?.additionalSources || []; + const newSources = [...currentSources]; + if (newSources.length === 0) { + newSources.push({ componentId: "", fieldName: col.name }); + } else { + newSources[0] = { ...newSources[0], fieldName: col.name }; + } + onUpdateProperty("componentConfig.action.dataTransfer.additionalSources", newSources); + }} + className="text-xs" + > + + {col.label || col.name} + {col.label && col.label !== col.name && ( + ({col.name}) + )} + + ))} + + + + + +

์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋  ํƒ€๊ฒŸ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ

diff --git a/frontend/components/v2/V2Repeater.tsx b/frontend/components/v2/V2Repeater.tsx index d2b288ff..bd50ffdb 100644 --- a/frontend/components/v2/V2Repeater.tsx +++ b/frontend/components/v2/V2Repeater.tsx @@ -23,6 +23,9 @@ import { import { apiClient } from "@/lib/api/client"; import { allocateNumberingCode } from "@/lib/api/numberingRule"; import { v2EventBus, V2_EVENTS, V2ErrorBoundary } from "@/lib/v2-core"; +import { useScreenContextOptional } from "@/contexts/ScreenContext"; +import { DataReceivable } from "@/types/data-transfer"; +import { toast } from "sonner"; // modal-repeater-table ์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ import { RepeaterTable } from "@/lib/registry/components/modal-repeater-table/RepeaterTable"; @@ -38,6 +41,7 @@ declare global { export const V2Repeater: React.FC = ({ config: propConfig, + componentId, parentId, data: initialData, onDataChange, @@ -48,6 +52,12 @@ export const V2Repeater: React.FC = ({ }) => { // ScreenModal์—์„œ ์ „๋‹ฌ๋œ groupedData (๋ชจ๋‹ฌ ๊ฐ„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์šฉ) const groupedData = (restProps as any).groupedData || (restProps as any)._groupedData; + + // componentId ๊ฒฐ์ •: ์ง์ ‘ ์ „๋‹ฌ ๋˜๋Š” component ๊ฐ์ฒด์—์„œ ์ถ”์ถœ + const effectiveComponentId = componentId || (restProps as any).component?.id; + + // ScreenContext ์—ฐ๋™ (DataReceiver ๋“ฑ๋ก, Provider ์—†์œผ๋ฉด null) + const screenContext = useScreenContextOptional(); // ์„ค์ • ๋ณ‘ํ•ฉ const config: V2RepeaterConfig = useMemo( () => ({ @@ -68,6 +78,57 @@ export const V2Repeater: React.FC = ({ // ๐Ÿ†• ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‹œ ์ž๋™์œผ๋กœ ์ปฌ๋Ÿผ ๋„ˆ๋น„ ์กฐ์ • ํŠธ๋ฆฌ๊ฑฐ const [autoWidthTrigger, setAutoWidthTrigger] = useState(0); + // ScreenContext DataReceiver ๋“ฑ๋ก (๋ฐ์ดํ„ฐ ์ „๋‹ฌ ์•ก์…˜ ์ˆ˜์‹ ) + const onDataChangeRef = useRef(onDataChange); + onDataChangeRef.current = onDataChange; + + const handleReceiveData = useCallback( + async (incomingData: any[], configOrMode?: any) => { + console.log("๐Ÿ“ฅ [V2Repeater] ๋ฐ์ดํ„ฐ ์ˆ˜์‹ :", { count: incomingData?.length, configOrMode }); + + if (!incomingData || incomingData.length === 0) { + toast.warning("์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค"); + return; + } + + // ๋ฐ์ดํ„ฐ ์ •๊ทœํ™”: {0: {...}} ํ˜•ํƒœ ์ฒ˜๋ฆฌ + const normalizedData = incomingData.map((item: any) => { + if (item && typeof item === "object" && item[0] && typeof item[0] === "object") { + const { 0: originalData, ...additionalFields } = item; + return { ...originalData, ...additionalFields }; + } + return item; + }); + + const mode = configOrMode?.mode || configOrMode || "append"; + + setData((prev) => { + const next = mode === "replace" ? normalizedData : [...prev, ...normalizedData]; + onDataChangeRef.current?.(next); + return next; + }); + + toast.success(`${normalizedData.length}๊ฐœ ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`); + }, + [], + ); + + useEffect(() => { + if (screenContext && effectiveComponentId) { + const receiver: DataReceivable = { + componentId: effectiveComponentId, + componentType: "v2-repeater", + receiveData: handleReceiveData, + }; + console.log("๐Ÿ“‹ [V2Repeater] ScreenContext์— ๋ฐ์ดํ„ฐ ์ˆ˜์‹ ์ž ๋“ฑ๋ก:", effectiveComponentId); + screenContext.registerDataReceiver(effectiveComponentId, receiver); + + return () => { + screenContext.unregisterDataReceiver(effectiveComponentId); + }; + } + }, [screenContext, effectiveComponentId, handleReceiveData]); + // ์†Œ์Šค ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ๋ผ๋ฒจ ๋งคํ•‘ const [sourceColumnLabels, setSourceColumnLabels] = useState>({}); @@ -512,17 +573,26 @@ export const V2Repeater: React.FC = ({ }); }, [config.columns, sourceColumnLabels, currentTableColumnInfo, resolvedSourceTable, config.dataSource?.tableName]); - // ๐Ÿ†• ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‹œ ์นดํ…Œ๊ณ ๋ฆฌ ๋ผ๋ฒจ ๋กœ๋“œ (RepeaterTable ํ‘œ์‹œ์šฉ) + // ๋ฆฌํ”ผํ„ฐ ์ปฌ๋Ÿผ ์„ค์ •์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ ํƒ€์ž… ์ปฌ๋Ÿผ ์ž๋™ ๊ฐ์ง€ + const allCategoryColumns = useMemo(() => { + const fromConfig = config.columns + .filter((col) => col.inputType === "category") + .map((col) => col.key); + const merged = new Set([...sourceCategoryColumns, ...fromConfig]); + return Array.from(merged); + }, [sourceCategoryColumns, config.columns]); + + // ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‹œ ์นดํ…Œ๊ณ ๋ฆฌ ๋ผ๋ฒจ ๋กœ๋“œ (RepeaterTable ํ‘œ์‹œ์šฉ) useEffect(() => { const loadCategoryLabels = async () => { - if (sourceCategoryColumns.length === 0 || data.length === 0) { + if (allCategoryColumns.length === 0 || data.length === 0) { return; } // ๋ฐ์ดํ„ฐ์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ ์ปฌ๋Ÿผ์˜ ๋ชจ๋“  ๊ณ ์œ  ์ฝ”๋“œ ์ˆ˜์ง‘ const allCodes = new Set(); for (const row of data) { - for (const col of sourceCategoryColumns) { + for (const col of allCategoryColumns) { // _display_ ์ ‘๋‘์‚ฌ๊ฐ€ ์žˆ๋Š” ์ปฌ๋Ÿผ๊ณผ ์›๋ณธ ์ปฌ๋Ÿผ ๋ชจ๋‘ ํ™•์ธ const val = row[`_display_${col}`] || row[col]; if (val && typeof val === "string") { @@ -531,7 +601,7 @@ export const V2Repeater: React.FC = ({ .map((c: string) => c.trim()) .filter(Boolean); for (const code of codes) { - if (!categoryLabelMap[code] && code.startsWith("CATEGORY_")) { + if (!categoryLabelMap[code] && code.length > 0) { allCodes.add(code); } } @@ -560,7 +630,7 @@ export const V2Repeater: React.FC = ({ }; loadCategoryLabels(); - }, [data, sourceCategoryColumns]); + }, [data, allCategoryColumns]); // ๊ณ„์‚ฐ ๊ทœ์น™ ์ ์šฉ (์†Œ์Šค ํ…Œ์ด๋ธ”์˜ _display_* ํ•„๋“œ๋„ ์ฐธ์กฐ ๊ฐ€๋Šฅ) const applyCalculationRules = useCallback( @@ -1112,7 +1182,7 @@ export const V2Repeater: React.FC = ({ selectedRows={selectedRows} onSelectionChange={setSelectedRows} equalizeWidthsTrigger={autoWidthTrigger} - categoryColumns={sourceCategoryColumns} + categoryColumns={allCategoryColumns} categoryLabelMap={categoryLabelMap} /> diff --git a/frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx b/frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx index 5b5b5fc2..1f89ae12 100644 --- a/frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx +++ b/frontend/components/v2/config-panels/V2RepeaterConfigPanel.tsx @@ -1214,13 +1214,21 @@ export const V2RepeaterConfigPanel: React.FC = ({ )} - {/* ํŽธ์ง‘ ๊ฐ€๋Šฅ ์ฒดํฌ๋ฐ•์Šค */} + {/* ํŽธ์ง‘ ๊ฐ€๋Šฅ ํ† ๊ธ€ */} {!col.isSourceDisplay && ( - updateColumnProp(col.key, "editable", !!checked)} - title="ํŽธ์ง‘ ๊ฐ€๋Šฅ" - /> + )}