feat: Enhance EditModal and V2Repeater functionality

- Implemented zone offset adjustments for conditional components in EditModal to ensure correct rendering positions.
- Added repeaterSave event dispatching in EditModal after saving data, improving integration with V2Repeater.
- Updated V2Repeater to handle existing detail data loading based on foreign key relationships, enhancing data management.
- Improved calculation rules handling in V2RepeaterConfigPanel, allowing for dynamic updates and better user experience.
- Enhanced SplitPanelLayoutComponent to conditionally load data based on selected items and tab changes, improving performance and usability.
This commit is contained in:
DDD1542
2026-02-23 09:16:44 +09:00
parent 5af41ad90b
commit 9614ce3973
8 changed files with 410 additions and 137 deletions

View File

@@ -1526,22 +1526,30 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
[componentConfig.rightPanel?.additionalTabs, isDesignMode, toast],
);
// 탭 변경 핸들러 (좌측 미선택 시에도 전체 데이터 로드)
// 탭 변경 핸들러
const handleTabChange = useCallback(
(newTabIndex: number) => {
setActiveTabIndex(newTabIndex);
// 메인 패널이 "detail"(선택 시 표시)이면 좌측 미선택 시 데이터 로드하지 않음
const mainRelationType = componentConfig.rightPanel?.relation?.type || "detail";
const requireSelection = mainRelationType === "detail";
if (newTabIndex === 0) {
if (!rightData || (Array.isArray(rightData) && rightData.length === 0)) {
loadRightData(selectedLeftItem);
if (!requireSelection || selectedLeftItem) {
loadRightData(selectedLeftItem);
}
}
} else {
if (!tabsData[newTabIndex]) {
loadTabData(newTabIndex, selectedLeftItem);
if (!requireSelection || selectedLeftItem) {
loadTabData(newTabIndex, selectedLeftItem);
}
}
}
},
[selectedLeftItem, rightData, tabsData, loadRightData, loadTabData],
[selectedLeftItem, rightData, tabsData, loadRightData, loadTabData, componentConfig.rightPanel?.relation?.type],
);
// 좌측 항목 선택 핸들러 (동일 항목 재클릭 시 선택 해제 → 전체 데이터 표시)
@@ -1554,24 +1562,31 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
selectedLeftItem[leftPk] === item[leftPk];
if (isSameItem) {
// 선택 해제 → 전체 데이터 로드
// 선택 해제
setSelectedLeftItem(null);
setCustomLeftSelectedData({}); // 커스텀 모드 우측 폼 데이터 초기화
setCustomLeftSelectedData({});
setExpandedRightItems(new Set());
setTabsData({});
if (activeTabIndex === 0) {
loadRightData(null);
const mainRelationType = componentConfig.rightPanel?.relation?.type || "detail";
if (mainRelationType === "detail") {
// "선택 시 표시" 모드: 선택 해제 시 데이터 비움
setRightData(null);
} else {
loadTabData(activeTabIndex, null);
}
// 추가 탭들도 전체 데이터 로드
const tabs = componentConfig.rightPanel?.additionalTabs;
if (tabs && tabs.length > 0) {
tabs.forEach((_: any, idx: number) => {
if (idx + 1 !== activeTabIndex) {
loadTabData(idx + 1, null);
}
});
// "연관 목록" 모드: 선택 해제 시 전체 데이터 로드
if (activeTabIndex === 0) {
loadRightData(null);
} else {
loadTabData(activeTabIndex, null);
}
const tabs = componentConfig.rightPanel?.additionalTabs;
if (tabs && tabs.length > 0) {
tabs.forEach((_: any, idx: number) => {
if (idx + 1 !== activeTabIndex) {
loadTabData(idx + 1, null);
}
});
}
}
return;
}
@@ -2778,15 +2793,17 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
if (relationshipType === "join") {
loadRightData(null);
}
// 추가 탭: 각 탭의 relation.type에 따라 초기 로드 결정
const tabs = componentConfig.rightPanel?.additionalTabs;
if (tabs && tabs.length > 0) {
tabs.forEach((tab: any, idx: number) => {
const tabRelType = tab.relation?.type || "join";
if (tabRelType === "join") {
loadTabData(idx + 1, null);
}
});
// 추가 탭: 메인 패널이 "detail"(선택 시 표시)이면 추가 탭도 초기 로드하지 않음
if (relationshipType !== "detail") {
const tabs = componentConfig.rightPanel?.additionalTabs;
if (tabs && tabs.length > 0) {
tabs.forEach((tab: any, idx: number) => {
const tabRelType = tab.relation?.type || "join";
if (tabRelType === "join") {
loadTabData(idx + 1, null);
}
});
}
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -3734,6 +3751,17 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
const currentTabData = tabsData[activeTabIndex] || [];
const isTabLoading = tabsLoading[activeTabIndex];
// 메인 패널이 "detail"(선택 시 표시)이면 좌측 미선택 시 안내 메시지
const mainRelationType = componentConfig.rightPanel?.relation?.type || "detail";
if (mainRelationType === "detail" && !selectedLeftItem && !isDesignMode) {
return (
<div className="text-muted-foreground flex h-full flex-col items-center justify-center gap-2 py-12 text-sm">
<p> </p>
<p className="text-xs"> </p>
</div>
);
}
if (isTabLoading) {
return (
<div className="flex h-32 items-center justify-center">