291 lines
11 KiB
TypeScript
291 lines
11 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import React from "react";
|
||
|
|
import { Input } from "@/components/ui/input";
|
||
|
|
import { Label } from "@/components/ui/label";
|
||
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
||
|
|
import { DataFilterConfigPanel } from "@/components/screen/config-panels/DataFilterConfigPanel";
|
||
|
|
|
||
|
|
export interface OptionsConfigPanelProps {
|
||
|
|
config: any;
|
||
|
|
onChange: (key: string, value: any) => void;
|
||
|
|
onNestedChange: (parentKey: string, childKey: string, value: any) => void;
|
||
|
|
availableColumns: Array<{ columnName: string; dataType: string; label?: string; input_type?: string }>;
|
||
|
|
screenTableName?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 옵션 설정 패널: 툴바, 체크박스, 기본 정렬, 가로 스크롤, 데이터 필터링
|
||
|
|
*/
|
||
|
|
export const OptionsConfigPanel: React.FC<OptionsConfigPanelProps> = ({
|
||
|
|
config,
|
||
|
|
onChange,
|
||
|
|
onNestedChange,
|
||
|
|
availableColumns,
|
||
|
|
screenTableName,
|
||
|
|
}) => {
|
||
|
|
return (
|
||
|
|
<div className="space-y-6">
|
||
|
|
{/* 툴바 버튼 설정 */}
|
||
|
|
<div className="space-y-3">
|
||
|
|
<div>
|
||
|
|
<h3 className="text-sm font-semibold">툴바 버튼 설정</h3>
|
||
|
|
<p className="text-muted-foreground text-[10px]">테이블 상단에 표시할 버튼을 선택합니다</p>
|
||
|
|
</div>
|
||
|
|
<hr className="border-border" />
|
||
|
|
<div className="grid grid-cols-2 gap-2">
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showEditMode"
|
||
|
|
checked={config.toolbar?.showEditMode ?? false}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("toolbar", "showEditMode", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="showEditMode" className="text-xs">
|
||
|
|
즉시 저장
|
||
|
|
</Label>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showExcel"
|
||
|
|
checked={config.toolbar?.showExcel ?? false}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("toolbar", "showExcel", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="showExcel" className="text-xs">
|
||
|
|
Excel
|
||
|
|
</Label>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showPdf"
|
||
|
|
checked={config.toolbar?.showPdf ?? false}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("toolbar", "showPdf", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="showPdf" className="text-xs">
|
||
|
|
PDF
|
||
|
|
</Label>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showCopy"
|
||
|
|
checked={config.toolbar?.showCopy ?? false}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("toolbar", "showCopy", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="showCopy" className="text-xs">
|
||
|
|
복사
|
||
|
|
</Label>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showSearch"
|
||
|
|
checked={config.toolbar?.showSearch ?? false}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("toolbar", "showSearch", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="showSearch" className="text-xs">
|
||
|
|
검색
|
||
|
|
</Label>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showFilter"
|
||
|
|
checked={config.toolbar?.showFilter ?? false}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("toolbar", "showFilter", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="showFilter" className="text-xs">
|
||
|
|
필터
|
||
|
|
</Label>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showRefresh"
|
||
|
|
checked={config.toolbar?.showRefresh ?? false}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("toolbar", "showRefresh", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="showRefresh" className="text-xs">
|
||
|
|
새로고침 (상단)
|
||
|
|
</Label>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showPaginationRefresh"
|
||
|
|
checked={config.toolbar?.showPaginationRefresh ?? true}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("toolbar", "showPaginationRefresh", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="showPaginationRefresh" className="text-xs">
|
||
|
|
새로고침 (하단)
|
||
|
|
</Label>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 체크박스 설정 */}
|
||
|
|
<div className="space-y-3">
|
||
|
|
<div>
|
||
|
|
<h3 className="text-sm font-semibold">체크박스 설정</h3>
|
||
|
|
</div>
|
||
|
|
<hr className="border-border" />
|
||
|
|
<div className="space-y-2">
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="checkboxEnabled"
|
||
|
|
checked={config.checkbox?.enabled ?? true}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("checkbox", "enabled", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="checkboxEnabled">체크박스 표시</Label>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{config.checkbox?.enabled && (
|
||
|
|
<>
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="checkboxSelectAll"
|
||
|
|
checked={config.checkbox?.selectAll ?? true}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("checkbox", "selectAll", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="checkboxSelectAll">전체 선택 체크박스 표시</Label>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="space-y-1">
|
||
|
|
<Label htmlFor="checkboxPosition" className="text-xs">
|
||
|
|
체크박스 위치
|
||
|
|
</Label>
|
||
|
|
<select
|
||
|
|
id="checkboxPosition"
|
||
|
|
value={config.checkbox?.position || "left"}
|
||
|
|
onChange={(e) => onNestedChange("checkbox", "position", e.target.value)}
|
||
|
|
className="h-8 w-full rounded-md border px-2 text-xs"
|
||
|
|
>
|
||
|
|
<option value="left">왼쪽</option>
|
||
|
|
<option value="right">오른쪽</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 기본 정렬 설정 */}
|
||
|
|
<div className="space-y-3">
|
||
|
|
<div>
|
||
|
|
<h3 className="text-sm font-semibold">기본 정렬 설정</h3>
|
||
|
|
<p className="text-muted-foreground text-[10px]">테이블 로드 시 기본 정렬 순서를 지정합니다</p>
|
||
|
|
</div>
|
||
|
|
<hr className="border-border" />
|
||
|
|
<div className="space-y-2">
|
||
|
|
<div className="space-y-1">
|
||
|
|
<Label htmlFor="defaultSortColumn" className="text-xs">
|
||
|
|
정렬 컬럼
|
||
|
|
</Label>
|
||
|
|
<select
|
||
|
|
id="defaultSortColumn"
|
||
|
|
value={config.defaultSort?.columnName || ""}
|
||
|
|
onChange={(e) => {
|
||
|
|
if (e.target.value) {
|
||
|
|
onChange("defaultSort", {
|
||
|
|
columnName: e.target.value,
|
||
|
|
direction: config.defaultSort?.direction || "asc",
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
onChange("defaultSort", undefined);
|
||
|
|
}
|
||
|
|
}}
|
||
|
|
className="h-8 w-full rounded-md border px-2 text-xs"
|
||
|
|
>
|
||
|
|
<option value="">정렬 없음</option>
|
||
|
|
{availableColumns.map((col) => (
|
||
|
|
<option key={col.columnName} value={col.columnName}>
|
||
|
|
{col.label || col.columnName}
|
||
|
|
</option>
|
||
|
|
))}
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{config.defaultSort?.columnName && (
|
||
|
|
<div className="space-y-1">
|
||
|
|
<Label htmlFor="defaultSortDirection" className="text-xs">
|
||
|
|
정렬 방향
|
||
|
|
</Label>
|
||
|
|
<select
|
||
|
|
id="defaultSortDirection"
|
||
|
|
value={config.defaultSort?.direction || "asc"}
|
||
|
|
onChange={(e) =>
|
||
|
|
onChange("defaultSort", {
|
||
|
|
...config.defaultSort,
|
||
|
|
columnName: config.defaultSort?.columnName || "",
|
||
|
|
direction: e.target.value as "asc" | "desc",
|
||
|
|
})
|
||
|
|
}
|
||
|
|
className="h-8 w-full rounded-md border px-2 text-xs"
|
||
|
|
>
|
||
|
|
<option value="asc">오름차순 (A→Z, 1→9)</option>
|
||
|
|
<option value="desc">내림차순 (Z→A, 9→1)</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 가로 스크롤 및 컬럼 고정 */}
|
||
|
|
<div className="space-y-3">
|
||
|
|
<div>
|
||
|
|
<h3 className="text-sm font-semibold">가로 스크롤 및 컬럼 고정</h3>
|
||
|
|
</div>
|
||
|
|
<hr className="border-border" />
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="horizontalScrollEnabled"
|
||
|
|
checked={config.horizontalScroll?.enabled}
|
||
|
|
onCheckedChange={(checked) => onNestedChange("horizontalScroll", "enabled", checked)}
|
||
|
|
/>
|
||
|
|
<Label htmlFor="horizontalScrollEnabled">가로 스크롤 사용</Label>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{config.horizontalScroll?.enabled && (
|
||
|
|
<div className="space-y-3">
|
||
|
|
<div className="space-y-1">
|
||
|
|
<Label htmlFor="maxVisibleColumns" className="text-sm">
|
||
|
|
최대 표시 컬럼 수
|
||
|
|
</Label>
|
||
|
|
<Input
|
||
|
|
id="maxVisibleColumns"
|
||
|
|
type="number"
|
||
|
|
value={config.horizontalScroll?.maxVisibleColumns || 8}
|
||
|
|
onChange={(e) =>
|
||
|
|
onNestedChange("horizontalScroll", "maxVisibleColumns", parseInt(e.target.value) || 8)
|
||
|
|
}
|
||
|
|
min={3}
|
||
|
|
max={20}
|
||
|
|
placeholder="8"
|
||
|
|
className="h-8"
|
||
|
|
/>
|
||
|
|
<div className="text-xs text-gray-500">이 수를 넘는 컬럼이 있으면 가로 스크롤이 생성됩니다</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 데이터 필터링 설정 */}
|
||
|
|
<div className="space-y-3">
|
||
|
|
<div>
|
||
|
|
<h3 className="text-sm font-semibold">데이터 필터링</h3>
|
||
|
|
<p className="text-muted-foreground mt-1 text-xs">특정 컬럼 값으로 데이터를 필터링합니다</p>
|
||
|
|
</div>
|
||
|
|
<hr className="border-border" />
|
||
|
|
<DataFilterConfigPanel
|
||
|
|
tableName={config.selectedTable || screenTableName}
|
||
|
|
columns={availableColumns.map(
|
||
|
|
(col) =>
|
||
|
|
({
|
||
|
|
columnName: col.columnName,
|
||
|
|
columnLabel: col.label || col.columnName,
|
||
|
|
dataType: col.dataType,
|
||
|
|
input_type: col.input_type,
|
||
|
|
}) as any,
|
||
|
|
)}
|
||
|
|
config={config.dataFilter}
|
||
|
|
onConfigChange={(dataFilter) => onChange("dataFilter", dataFilter)}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|