fix: 피벗 ConfigPanel — FeatureChipGrid 로 교체 + PivotView 빈 그리드 회피
이전 commit (3ed53a670,57ffbcbbc) 의 두 잘못 수정. 1. ConfigPanel — CPSwitch 8개 → FeatureChipGrid 1개 CP 시스템에 다중 boolean 토글 묶음용 FeatureChipGrid 가 이미 있는데 (CPExtras.tsx:208, InvLegacyDivider/Button/Text/InvRepeater 가 사용), CPRow + CPSwitch 8개로 따로 만든 게 잘못. cp 시스템 본래 패턴 따름. - 8 토글 (chartEnabled / fieldChooserEnabled / rowGrandTotals / columnGrandTotals / mergeCells / alternateRowColors / exportExcel / exportPdf) 을 평면 key 로 정의 - source = nested config 에서 평면 boolean 객체 변환 - onToggle = 평면 key 받아 nested patch (switch 분기) - 각 chip 에 desc 추가 (hover tooltip, FeatureChipGrid 가 portal 로 표시) 2. PivotView — data 영역 0개면 안내 (빈 0 그리드 회피) hasActiveFields 분기를 강화. 기존: row/column/data 중 하나만 있어도 true → row 영역에만 컬럼이 들어간 옛 잘못된 매핑이 빈 0 그리드를 표시 하는 회귀 (Image #6). 변경: data 영역 컬럼 ≥1 이어야 의미있는 피벗. data 0개면 "필드를 배치하세요" 안내 + FieldChooser 버튼 fallback. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -282,121 +282,82 @@ export const InvTableConfigPanel: React.FC<InvTableConfigPanelProps> = ({
|
||||
|
||||
{displayMode === "pivot" && (
|
||||
<CPSection title="④ 피벗 설정" desc="본체 분석 UI에서 사용할 표시 옵션">
|
||||
{/* 피벗 필드 배치는 PivotView 본체의 FieldPanel/FieldChooser가 담당한다. ConfigPanel은 메타 옵션만 관리한다. */}
|
||||
<CPRow label="차트 표시">
|
||||
<CPSwitch
|
||||
value={current.pivotChart?.enabled ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotChart: {
|
||||
type: current.pivotChart?.type ?? "bar",
|
||||
position: current.pivotChart?.position ?? "bottom",
|
||||
...current.pivotChart,
|
||||
enabled: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="필드 선택기">
|
||||
<CPSwitch
|
||||
value={current.pivotFieldChooser?.enabled ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotFieldChooser: {
|
||||
...current.pivotFieldChooser,
|
||||
enabled: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="행 총계">
|
||||
<CPSwitch
|
||||
value={current.pivotTotals?.showRowGrandTotals ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotTotals: {
|
||||
...current.pivotTotals,
|
||||
showRowGrandTotals: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="열 총계">
|
||||
<CPSwitch
|
||||
value={current.pivotTotals?.showColumnGrandTotals ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotTotals: {
|
||||
...current.pivotTotals,
|
||||
showColumnGrandTotals: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="셀 병합">
|
||||
<CPSwitch
|
||||
value={current.pivotStyle?.mergeCells ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotStyle: {
|
||||
theme: current.pivotStyle?.theme ?? "default",
|
||||
headerStyle: current.pivotStyle?.headerStyle ?? "default",
|
||||
cellPadding: current.pivotStyle?.cellPadding ?? "normal",
|
||||
borderStyle: current.pivotStyle?.borderStyle ?? "light",
|
||||
{/* 피벗 필드 배치는 PivotView 본체의 FieldPanel/FieldChooser가 담당한다. ConfigPanel은 메타 토글만 관리한다. */}
|
||||
<FeatureChipGrid
|
||||
items={[
|
||||
{ key: "chartEnabled", label: "차트 표시", desc: "본체 안에 피벗 차트(bar/line/pie 등) 패널을 함께 표시합니다." },
|
||||
{ key: "fieldChooserEnabled", label: "필드 선택기", desc: "본체에서 row/column/data/filter 영역에 컬럼을 드래그-앤-드롭 배치하는 모달을 활성화." },
|
||||
{ key: "rowGrandTotals", label: "행 총계", desc: "각 행의 합계 행을 자동 표시합니다. row 영역 컬럼이 있을 때 의미가 있습니다." },
|
||||
{ key: "columnGrandTotals", label: "열 총계", desc: "각 열의 합계 열을 자동 표시합니다. column 영역 컬럼이 있을 때 의미가 있습니다." },
|
||||
{ key: "mergeCells", label: "셀 병합", desc: "같은 값의 인접 셀을 병합해 가독성을 높입니다." },
|
||||
{ key: "alternateRowColors", label: "행 교대 색", desc: "홀수/짝수 행을 다른 톤으로 교대 표시 (Zebra)." },
|
||||
{ key: "exportExcel", label: "엑셀 내보내기", desc: "본체 툴바에 .xlsx 다운로드 버튼을 활성화." },
|
||||
{ key: "exportPdf", label: "PDF 내보내기", desc: "본체 툴바에 PDF 다운로드 버튼을 활성화." },
|
||||
]}
|
||||
source={{
|
||||
chartEnabled: current.pivotChart?.enabled ?? false,
|
||||
fieldChooserEnabled: current.pivotFieldChooser?.enabled ?? false,
|
||||
rowGrandTotals: current.pivotTotals?.showRowGrandTotals ?? false,
|
||||
columnGrandTotals: current.pivotTotals?.showColumnGrandTotals ?? false,
|
||||
mergeCells: current.pivotStyle?.mergeCells ?? false,
|
||||
alternateRowColors: current.pivotStyle?.alternateRowColors ?? false,
|
||||
exportExcel: current.pivotExportConfig?.excel ?? false,
|
||||
exportPdf: current.pivotExportConfig?.pdf ?? false,
|
||||
}}
|
||||
onToggle={(key, value) => {
|
||||
switch (key) {
|
||||
case "chartEnabled":
|
||||
patch({
|
||||
pivotChart: {
|
||||
type: current.pivotChart?.type ?? "bar",
|
||||
position: current.pivotChart?.position ?? "bottom",
|
||||
...current.pivotChart,
|
||||
enabled: value,
|
||||
},
|
||||
});
|
||||
return;
|
||||
case "fieldChooserEnabled":
|
||||
patch({
|
||||
pivotFieldChooser: { ...current.pivotFieldChooser, enabled: value },
|
||||
});
|
||||
return;
|
||||
case "rowGrandTotals":
|
||||
patch({
|
||||
pivotTotals: { ...current.pivotTotals, showRowGrandTotals: value },
|
||||
});
|
||||
return;
|
||||
case "columnGrandTotals":
|
||||
patch({
|
||||
pivotTotals: { ...current.pivotTotals, showColumnGrandTotals: value },
|
||||
});
|
||||
return;
|
||||
case "mergeCells":
|
||||
case "alternateRowColors": {
|
||||
const baseStyle = {
|
||||
theme: current.pivotStyle?.theme ?? "default" as const,
|
||||
headerStyle: current.pivotStyle?.headerStyle ?? "default" as const,
|
||||
cellPadding: current.pivotStyle?.cellPadding ?? "normal" as const,
|
||||
borderStyle: current.pivotStyle?.borderStyle ?? "light" as const,
|
||||
...current.pivotStyle,
|
||||
mergeCells: v,
|
||||
},
|
||||
})
|
||||
};
|
||||
patch({
|
||||
pivotStyle: { ...baseStyle, [key]: value },
|
||||
});
|
||||
return;
|
||||
}
|
||||
case "exportExcel":
|
||||
patch({
|
||||
pivotExportConfig: { ...current.pivotExportConfig, excel: value },
|
||||
});
|
||||
return;
|
||||
case "exportPdf":
|
||||
patch({
|
||||
pivotExportConfig: { ...current.pivotExportConfig, pdf: value },
|
||||
});
|
||||
return;
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="행 교대 색">
|
||||
<CPSwitch
|
||||
value={current.pivotStyle?.alternateRowColors ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotStyle: {
|
||||
theme: current.pivotStyle?.theme ?? "default",
|
||||
headerStyle: current.pivotStyle?.headerStyle ?? "default",
|
||||
cellPadding: current.pivotStyle?.cellPadding ?? "normal",
|
||||
borderStyle: current.pivotStyle?.borderStyle ?? "light",
|
||||
...current.pivotStyle,
|
||||
alternateRowColors: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="엑셀 내보내기">
|
||||
<CPSwitch
|
||||
value={current.pivotExportConfig?.excel ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotExportConfig: {
|
||||
...current.pivotExportConfig,
|
||||
excel: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
<CPRow label="PDF 내보내기">
|
||||
<CPSwitch
|
||||
value={current.pivotExportConfig?.pdf ?? false}
|
||||
onChange={(v) =>
|
||||
patch({
|
||||
pivotExportConfig: {
|
||||
...current.pivotExportConfig,
|
||||
pdf: v,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</CPRow>
|
||||
}}
|
||||
/>
|
||||
</CPSection>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1045,10 +1045,10 @@ export const PivotView: React.FC<PivotGridProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
// 필드 미설정 (행, 열, 데이터 영역에 필드가 있는지 확인)
|
||||
const hasActiveFields = fields.some(
|
||||
(f) => f.visible !== false && ["row", "column", "data"].includes(f.area)
|
||||
);
|
||||
// 필드 미설정 — data 영역 (집계 대상) 이 1개 이상 있어야 의미있는 피벗.
|
||||
// row/column 만 있고 data 가 비어있으면 빈 0 그리드가 생성되므로 안내로 fallback.
|
||||
const hasDataField = fields.some((f) => f.visible !== false && f.area === "data");
|
||||
const hasActiveFields = hasDataField;
|
||||
if (!hasActiveFields) {
|
||||
return (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user