[agent-pipeline] pipe-20260329112709-ncml round-1

This commit is contained in:
DDD1542
2026-03-29 22:56:00 +09:00
parent b3f2383ef0
commit a5f4cd5ba9
397 changed files with 4011 additions and 4161 deletions
@@ -40,7 +40,7 @@ interface ColumnFilterConfig {
}
export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFiltersApplied, screenId }) => {
const { getTable, selectedTableId } = useTableOptions();
const { getTable, selected_table_id: selectedTableId } = useTableOptions();
const table = selectedTableId ? getTable(selectedTableId) : undefined;
const [activeTab, setActiveTab] = useState("columns");
@@ -65,34 +65,34 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
if (table) {
setLocalColumns(
table.columns.map((col) => ({
columnName: col.columnName,
column_name: col.column_name,
visible: col.visible,
width: col.width,
order: 0,
}))
);
setFrozenColumnCount(table.frozenColumnCount ?? 0);
setFrozenColumnCount(table.frozen_column_count ?? 0);
}
}, [table]);
// 테이블 정보 로드 - 필터
useEffect(() => {
if (table?.columns && table?.tableName) {
if (table?.columns && table?.table_name) {
const storageKey = screenId
? `table_filters_${table.tableName}_screen_${screenId}`
: `table_filters_${table.tableName}`;
? `table_filters_${table.table_name}_screen_${screenId}`
: `table_filters_${table.table_name}`;
const savedFilters = localStorage.getItem(storageKey);
const groupSumKey = screenId
? `table_groupsum_${table.tableName}_screen_${screenId}`
: `table_groupsum_${table.tableName}`;
? `table_groupsum_${table.table_name}_screen_${screenId}`
: `table_groupsum_${table.table_name}`;
const savedGroupSum = localStorage.getItem(groupSumKey);
if (savedGroupSum) {
try {
const parsed = JSON.parse(savedGroupSum) as GroupSumConfig;
setGroupSumEnabled(parsed.enabled);
setGroupByColumn(parsed.groupByColumn || "");
setGroupByColumn(parsed.group_by_column || "");
} catch {
setGroupSumEnabled(false);
setGroupByColumn("");
@@ -111,16 +111,16 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
initializeFilters();
}
}
}, [table?.columns, table?.tableName, screenId]);
}, [table?.columns, table?.table_name, screenId]);
const initializeFilters = () => {
if (!table?.columns) return;
const filters: ColumnFilterConfig[] = table.columns
.filter((col) => col.columnName !== "__checkbox__")
.filter((col) => col.column_name !== "__checkbox__")
.map((col) => {
let filterType: "text" | "number" | "date" | "select" = "text";
const inputType = col.inputType || "";
const inputType = col.input_type || "";
if (["number", "decimal", "currency", "integer"].includes(inputType)) {
filterType = "number";
@@ -131,8 +131,8 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
}
return {
columnName: col.columnName,
columnLabel: col.columnLabel,
columnName: col.column_name,
columnLabel: col.column_label,
inputType,
enabled: false,
filterType,
@@ -147,13 +147,13 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
// 컬럼 가시성 핸들러
const handleVisibilityChange = (columnName: string, visible: boolean) => {
setLocalColumns((prev) =>
prev.map((col) => (col.columnName === columnName ? { ...col, visible } : col))
prev.map((col) => (col.column_name === columnName ? { ...col, visible } : col))
);
};
const handleWidthChange = (columnName: string, width: number) => {
setLocalColumns((prev) =>
prev.map((col) => (col.columnName === columnName ? { ...col, width } : col))
prev.map((col) => (col.column_name === columnName ? { ...col, width } : col))
);
};
@@ -230,18 +230,10 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
// 1. 컬럼 가시성 저장
table.onColumnVisibilityChange(localColumns);
// 2. 컬럼 순서 변경 콜백 호출
if (table.onColumnOrderChange) {
const newOrder = localColumns
.map((col) => col.columnName)
.filter((name) => name !== "__checkbox__");
table.onColumnOrderChange(newOrder);
}
// 3. 틀고정 컬럼 수 변경 콜백 호출 (현재 컬럼 상태도 함께 전달)
if (table.onFrozenColumnCountChange) {
const updatedColumns = localColumns.map((col) => ({
columnName: col.columnName,
column_name: col.column_name,
visible: col.visible,
}));
table.onFrozenColumnCountChange(frozenColumnCount, updatedColumns);
@@ -249,17 +241,17 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
// 2. 필터 설정 저장
const storageKey = screenId
? `table_filters_${table.tableName}_screen_${screenId}`
: `table_filters_${table.tableName}`;
? `table_filters_${table.table_name}_screen_${screenId}`
: `table_filters_${table.table_name}`;
localStorage.setItem(storageKey, JSON.stringify(columnFilters));
// 그룹별 합산 설정 저장
const groupSumKey = screenId
? `table_groupsum_${table.tableName}_screen_${screenId}`
: `table_groupsum_${table.tableName}`;
? `table_groupsum_${table.table_name}_screen_${screenId}`
: `table_groupsum_${table.table_name}`;
const groupSumConfig: GroupSumConfig = {
enabled: groupSumEnabled,
groupByColumn: groupByColumn || undefined,
group_by_column: groupByColumn,
};
localStorage.setItem(groupSumKey, JSON.stringify(groupSumConfig));
@@ -267,10 +259,10 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
const activeFilters: TableFilter[] = columnFilters
.filter((f) => f.enabled)
.map((f) => ({
columnName: f.columnName,
column_name: f.columnName,
operator: "contains",
value: "",
filterType: f.filterType,
filter_type: f.filterType,
width: f.width && f.width >= 10 && f.width <= 100 ? f.width : 25,
}));
onFiltersApplied?.(activeFilters);
@@ -345,7 +337,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
if (table) {
setLocalColumns(
table.columns.map((col) => ({
columnName: col.columnName,
column_name: col.column_name,
visible: true,
width: 150,
order: 0,
@@ -364,7 +356,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
<ScrollArea className="h-[300px]">
<div className="space-y-2 pr-4">
{localColumns.map((col, index) => {
const originalCol = table?.columns.find((c) => c.columnName === col.columnName);
const originalCol = table?.columns.find((c) => c.column_name === col.column_name);
if (!originalCol) return null;
// 표시 가능한 컬럼 중 몇 번째인지 계산 (틀고정 표시용)
@@ -375,7 +367,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
return (
<div
key={col.columnName}
key={col.column_name}
draggable
onDragStart={() => setDraggedColumnIndex(index)}
onDragOver={(e) => {
@@ -399,7 +391,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
<Checkbox
checked={col.visible}
onCheckedChange={(checked) =>
handleVisibilityChange(col.columnName, checked as boolean)
handleVisibilityChange(col.column_name, checked as boolean)
}
/>
@@ -416,7 +408,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
<span className="truncate text-xs font-medium sm:text-sm">
{originalCol.columnLabel}
{originalCol.column_label}
</span>
{isFrozen && (
<span className="text-[10px] font-medium text-primary dark:text-primary/80">
@@ -425,7 +417,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
)}
</div>
<div className="text-muted-foreground truncate text-[10px] sm:text-xs">
{col.columnName}
{col.column_name}
</div>
</div>
@@ -435,7 +427,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
<Input
type="number"
value={col.width || 150}
onChange={(e) => handleWidthChange(col.columnName, parseInt(e.target.value) || 150)}
onChange={(e) => handleWidthChange(col.column_name, parseInt(e.target.value) || 150)}
className="h-7 w-16 text-xs sm:h-8 sm:w-20 sm:text-sm"
min={50}
max={500}
@@ -559,7 +551,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
</div>
<div className="max-h-[40vh] space-y-2 overflow-y-auto pr-1">
{selectedGroupColumns.map((colName, index) => {
const col = table?.columns.find((c) => c.columnName === colName);
const col = table?.columns.find((c) => c.column_name === colName);
if (!col) return null;
return (
@@ -582,7 +574,7 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
{index + 1}
</div>
<div className="min-w-0 flex-1">
<div className="truncate text-xs font-medium sm:text-sm">{col.columnLabel}</div>
<div className="truncate text-xs font-medium sm:text-sm">{col.column_label}</div>
</div>
<Button
variant="ghost"
@@ -601,10 +593,10 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
<div className="bg-muted/30 mt-2 rounded-lg border p-2">
<div className="flex flex-wrap items-center gap-2 text-xs">
{selectedGroupColumns.map((colName, index) => {
const col = table?.columns.find((c) => c.columnName === colName);
const col = table?.columns.find((c) => c.column_name === colName);
return (
<React.Fragment key={colName}>
<span className="font-medium">{col?.columnLabel}</span>
<span className="font-medium">{col?.column_label}</span>
{index < selectedGroupColumns.length - 1 && (
<ArrowRight className="text-muted-foreground h-3 w-3" />
)}
@@ -622,22 +614,22 @@ export const TableSettingsModal: React.FC<Props> = ({ isOpen, onClose, onFilters
<ScrollArea className={selectedGroupColumns.length > 0 ? "h-[200px]" : "h-[320px]"}>
<div className="space-y-2 pr-4">
{table?.columns
.filter((col) => !selectedGroupColumns.includes(col.columnName))
.filter((col) => !selectedGroupColumns.includes(col.column_name))
.map((col) => (
<div
key={col.columnName}
key={col.column_name}
className="hover:bg-muted/50 flex cursor-pointer items-center gap-3 rounded-lg border bg-background p-2 transition-colors"
onClick={() => toggleGroupColumn(col.columnName)}
onClick={() => toggleGroupColumn(col.column_name)}
>
<Checkbox
checked={false}
onCheckedChange={() => toggleGroupColumn(col.columnName)}
onCheckedChange={() => toggleGroupColumn(col.column_name)}
className="flex-shrink-0"
/>
<div className="min-w-0 flex-1">
<div className="truncate text-xs font-medium sm:text-sm">{col.columnLabel}</div>
<div className="truncate text-xs font-medium sm:text-sm">{col.column_label}</div>
<div className="text-muted-foreground truncate text-[10px] sm:text-xs">
{col.columnName}
{col.column_name}
</div>
</div>
</div>