152 lines
5.1 KiB
TypeScript
152 lines
5.1 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import React, { useState, useEffect } from "react";
|
||
|
|
import { Button } from "@/components/ui/button";
|
||
|
|
import { Settings, Filter, Layers } from "lucide-react";
|
||
|
|
import { useTableOptions } from "@/contexts/TableOptionsContext";
|
||
|
|
import { ColumnVisibilityPanel } from "@/components/screen/table-options/ColumnVisibilityPanel";
|
||
|
|
import { FilterPanel } from "@/components/screen/table-options/FilterPanel";
|
||
|
|
import { GroupingPanel } from "@/components/screen/table-options/GroupingPanel";
|
||
|
|
import {
|
||
|
|
Select,
|
||
|
|
SelectContent,
|
||
|
|
SelectItem,
|
||
|
|
SelectTrigger,
|
||
|
|
SelectValue,
|
||
|
|
} from "@/components/ui/select";
|
||
|
|
|
||
|
|
interface TableSearchWidgetProps {
|
||
|
|
component: {
|
||
|
|
id: string;
|
||
|
|
title?: string;
|
||
|
|
style?: {
|
||
|
|
width?: string;
|
||
|
|
height?: string;
|
||
|
|
padding?: string;
|
||
|
|
backgroundColor?: string;
|
||
|
|
};
|
||
|
|
componentConfig?: {
|
||
|
|
autoSelectFirstTable?: boolean; // 첫 번째 테이블 자동 선택 여부
|
||
|
|
showTableSelector?: boolean; // 테이블 선택 드롭다운 표시 여부
|
||
|
|
};
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export function TableSearchWidget({ component }: TableSearchWidgetProps) {
|
||
|
|
const { registeredTables, selectedTableId, setSelectedTableId } = useTableOptions();
|
||
|
|
const [columnVisibilityOpen, setColumnVisibilityOpen] = useState(false);
|
||
|
|
const [filterOpen, setFilterOpen] = useState(false);
|
||
|
|
const [groupingOpen, setGroupingOpen] = useState(false);
|
||
|
|
|
||
|
|
const autoSelectFirstTable = component.componentConfig?.autoSelectFirstTable ?? true;
|
||
|
|
const showTableSelector = component.componentConfig?.showTableSelector ?? true;
|
||
|
|
|
||
|
|
// Map을 배열로 변환
|
||
|
|
const tableList = Array.from(registeredTables.values());
|
||
|
|
|
||
|
|
// 첫 번째 테이블 자동 선택
|
||
|
|
useEffect(() => {
|
||
|
|
const tables = Array.from(registeredTables.values());
|
||
|
|
if (autoSelectFirstTable && tables.length > 0 && !selectedTableId) {
|
||
|
|
setSelectedTableId(tables[0].tableId);
|
||
|
|
}
|
||
|
|
}, [registeredTables, selectedTableId, autoSelectFirstTable, setSelectedTableId]);
|
||
|
|
|
||
|
|
const hasMultipleTables = tableList.length > 1;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
className="flex h-full w-full items-center justify-between gap-2 border-b bg-card"
|
||
|
|
style={{
|
||
|
|
padding: component.style?.padding || "0.75rem",
|
||
|
|
backgroundColor: component.style?.backgroundColor,
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{/* 왼쪽: 제목 + 테이블 정보 */}
|
||
|
|
<div className="flex items-center gap-3">
|
||
|
|
{/* 제목 */}
|
||
|
|
{component.title && (
|
||
|
|
<div className="text-sm font-medium text-foreground">
|
||
|
|
{component.title}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 테이블 선택 드롭다운 (여러 테이블이 있고, showTableSelector가 true일 때만) */}
|
||
|
|
{showTableSelector && hasMultipleTables && (
|
||
|
|
<Select value={selectedTableId || ""} onValueChange={setSelectedTableId}>
|
||
|
|
<SelectTrigger className="h-8 w-[200px] text-xs sm:h-9 sm:text-sm">
|
||
|
|
<SelectValue placeholder="테이블 선택" />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
{tableList.map((table) => (
|
||
|
|
<SelectItem key={table.tableId} value={table.tableId} className="text-xs sm:text-sm">
|
||
|
|
{table.label}
|
||
|
|
</SelectItem>
|
||
|
|
))}
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 테이블이 하나만 있을 때는 라벨만 표시 */}
|
||
|
|
{!hasMultipleTables && tableList.length === 1 && (
|
||
|
|
<div className="text-xs text-muted-foreground sm:text-sm">
|
||
|
|
{tableList[0].label}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 테이블이 없을 때 */}
|
||
|
|
{tableList.length === 0 && (
|
||
|
|
<div className="text-xs text-muted-foreground sm:text-sm">
|
||
|
|
화면에 테이블 컴포넌트를 추가하면 자동으로 감지됩니다
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 오른쪽: 버튼들 */}
|
||
|
|
<div className="flex items-center gap-2 flex-shrink-0">
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="sm"
|
||
|
|
onClick={() => setColumnVisibilityOpen(true)}
|
||
|
|
disabled={!selectedTableId}
|
||
|
|
className="h-8 text-xs sm:h-9 sm:text-sm"
|
||
|
|
>
|
||
|
|
<Settings className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
|
||
|
|
테이블 옵션
|
||
|
|
</Button>
|
||
|
|
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="sm"
|
||
|
|
onClick={() => setFilterOpen(true)}
|
||
|
|
disabled={!selectedTableId}
|
||
|
|
className="h-8 text-xs sm:h-9 sm:text-sm"
|
||
|
|
>
|
||
|
|
<Filter className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
|
||
|
|
필터 설정
|
||
|
|
</Button>
|
||
|
|
|
||
|
|
<Button
|
||
|
|
variant="outline"
|
||
|
|
size="sm"
|
||
|
|
onClick={() => setGroupingOpen(true)}
|
||
|
|
disabled={!selectedTableId}
|
||
|
|
className="h-8 text-xs sm:h-9 sm:text-sm"
|
||
|
|
>
|
||
|
|
<Layers className="mr-1 h-3 w-3 sm:h-4 sm:w-4" />
|
||
|
|
그룹 설정
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 패널들 */}
|
||
|
|
<ColumnVisibilityPanel
|
||
|
|
isOpen={columnVisibilityOpen}
|
||
|
|
onClose={() => setColumnVisibilityOpen(false)}
|
||
|
|
/>
|
||
|
|
<FilterPanel isOpen={filterOpen} onClose={() => setFilterOpen(false)} />
|
||
|
|
<GroupingPanel isOpen={groupingOpen} onClose={() => setGroupingOpen(false)} />
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|