259 lines
9.3 KiB
TypeScript
259 lines
9.3 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectLabel,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import { Trash2 } from "lucide-react";
|
|
import { ConditionNode, ColumnInfo } from "@/lib/api/dataflow";
|
|
import { DataSaveSettings } from "@/types/connectionTypes";
|
|
import { getInputTypeForDataType } from "@/utils/connectionUtils";
|
|
import { WebTypeInput } from "../condition/WebTypeInput";
|
|
|
|
interface ActionConditionRendererProps {
|
|
condition: ConditionNode;
|
|
condIndex: number;
|
|
actionIndex: number;
|
|
settings: DataSaveSettings;
|
|
onSettingsChange: (settings: DataSaveSettings) => void;
|
|
fromTableColumns: ColumnInfo[];
|
|
toTableColumns: ColumnInfo[];
|
|
fromTableName?: string;
|
|
toTableName?: string;
|
|
getActionCurrentGroupLevel: (conditions: ConditionNode[], conditionIndex: number) => number;
|
|
}
|
|
|
|
export const ActionConditionRenderer: React.FC<ActionConditionRendererProps> = ({
|
|
condition,
|
|
condIndex,
|
|
actionIndex,
|
|
settings,
|
|
onSettingsChange,
|
|
fromTableColumns,
|
|
toTableColumns,
|
|
fromTableName,
|
|
toTableName,
|
|
getActionCurrentGroupLevel,
|
|
}) => {
|
|
const removeConditionGroup = (groupId: string) => {
|
|
const newActions = [...settings.actions];
|
|
newActions[actionIndex].conditions = newActions[actionIndex].conditions!.filter((c) => c.groupId !== groupId);
|
|
onSettingsChange({ ...settings, actions: newActions });
|
|
};
|
|
|
|
const removeCondition = () => {
|
|
const newActions = [...settings.actions];
|
|
newActions[actionIndex].conditions = newActions[actionIndex].conditions!.filter((_, i) => i !== condIndex);
|
|
onSettingsChange({ ...settings, actions: newActions });
|
|
};
|
|
|
|
const updateCondition = (field: string, value: any) => {
|
|
const newActions = [...settings.actions];
|
|
(newActions[actionIndex].conditions![condIndex] as any)[field] = value;
|
|
onSettingsChange({ ...settings, actions: newActions });
|
|
};
|
|
|
|
const updateLogicalOperator = (targetIndex: number, value: "AND" | "OR") => {
|
|
const newActions = [...settings.actions];
|
|
newActions[actionIndex].conditions![targetIndex].logicalOperator = value;
|
|
onSettingsChange({ ...settings, actions: newActions });
|
|
};
|
|
|
|
const renderConditionValue = () => {
|
|
// 선택된 테이블 타입에 따라 컬럼 찾기
|
|
const targetColumns = condition.tableType === "from" ? fromTableColumns : toTableColumns;
|
|
const selectedColumn = targetColumns.find((col) => col.columnName === condition.field);
|
|
|
|
if (!selectedColumn) {
|
|
// 컬럼이 선택되지 않은 경우 기본 input
|
|
return (
|
|
<Input
|
|
type="text"
|
|
placeholder="값"
|
|
value={String(condition.value || "")}
|
|
onChange={(e) => updateCondition("value", e.target.value)}
|
|
className="h-6 flex-1 text-xs"
|
|
/>
|
|
);
|
|
}
|
|
|
|
// 테이블명 정보를 포함한 컬럼 객체 생성
|
|
const tableName = condition.tableType === "from" ? fromTableName : toTableName;
|
|
const columnWithTableName = {
|
|
...selectedColumn,
|
|
tableName: tableName,
|
|
};
|
|
|
|
// WebType 기반 input 사용
|
|
return (
|
|
<WebTypeInput
|
|
column={columnWithTableName}
|
|
value={String(condition.value || "")}
|
|
onChange={(value) => updateCondition("value", value)}
|
|
className="h-6 flex-1 text-xs"
|
|
placeholder="값"
|
|
/>
|
|
);
|
|
};
|
|
|
|
// 그룹 시작 렌더링
|
|
if (condition.type === "group-start") {
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
{/* 그룹 시작 앞의 논리 연산자 */}
|
|
{condIndex > 0 && (
|
|
<Select
|
|
value={settings.actions[actionIndex].conditions![condIndex - 1]?.logicalOperator || "AND"}
|
|
onValueChange={(value: "AND" | "OR") => updateLogicalOperator(condIndex - 1, value)}
|
|
>
|
|
<SelectTrigger className="h-6 w-24 border-green-200 bg-green-50 text-xs">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="AND">AND</SelectItem>
|
|
<SelectItem value="OR">OR</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
)}
|
|
<div
|
|
className="flex items-center gap-2 rounded border-2 border-dashed border-green-300 bg-green-50/50 p-1"
|
|
style={{ marginLeft: `${(condition.groupLevel || 0) * 15}px` }}
|
|
>
|
|
<span className="font-mono text-xs text-green-600">(</span>
|
|
<span className="text-xs text-green-600">그룹 시작</span>
|
|
<Button
|
|
size="sm"
|
|
variant="ghost"
|
|
onClick={() => removeConditionGroup(condition.groupId!)}
|
|
className="h-4 w-4 p-0"
|
|
>
|
|
<Trash2 className="h-2 w-2" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 그룹 끝 렌더링
|
|
if (condition.type === "group-end") {
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<div
|
|
className="flex items-center gap-2 rounded border-2 border-dashed border-green-300 bg-green-50/50 p-1"
|
|
style={{ marginLeft: `${(condition.groupLevel || 0) * 15}px` }}
|
|
>
|
|
<span className="font-mono text-xs text-green-600">)</span>
|
|
<span className="text-xs text-green-600">그룹 끝</span>
|
|
<Button
|
|
size="sm"
|
|
variant="ghost"
|
|
onClick={() => removeConditionGroup(condition.groupId!)}
|
|
className="h-4 w-4 p-0"
|
|
>
|
|
<Trash2 className="h-2 w-2" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 일반 조건 렌더링
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
{/* 그룹 내 첫 번째 조건이 아닐 때만 논리 연산자 표시 */}
|
|
{condIndex > 0 && settings.actions[actionIndex].conditions![condIndex - 1]?.type !== "group-start" && (
|
|
<Select
|
|
value={settings.actions[actionIndex].conditions![condIndex - 1]?.logicalOperator || "AND"}
|
|
onValueChange={(value: "AND" | "OR") => updateLogicalOperator(condIndex - 1, value)}
|
|
>
|
|
<SelectTrigger className="h-6 w-24 border-green-200 bg-green-50 text-xs">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="AND">AND</SelectItem>
|
|
<SelectItem value="OR">OR</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
)}
|
|
<div
|
|
className="flex flex-1 items-center gap-2 rounded border bg-white p-1"
|
|
style={{
|
|
marginLeft: `${getActionCurrentGroupLevel(settings.actions[actionIndex].conditions || [], condIndex) * 15}px`,
|
|
}}
|
|
>
|
|
{/* 1단계: 테이블 선택 */}
|
|
<Select
|
|
value={condition.tableType || ""}
|
|
onValueChange={(value: "from" | "to") => {
|
|
updateCondition("tableType", value);
|
|
// 테이블이 변경되면 필드 초기화
|
|
updateCondition("field", "");
|
|
}}
|
|
>
|
|
<SelectTrigger className="h-6 w-20 text-xs">
|
|
<SelectValue placeholder="테이블" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{fromTableColumns.length > 0 && <SelectItem value="from">{fromTableName || "From 테이블"}</SelectItem>}
|
|
{toTableColumns.length > 0 && <SelectItem value="to">{toTableName || "To 테이블"}</SelectItem>}
|
|
</SelectContent>
|
|
</Select>
|
|
|
|
{/* 2단계: 선택된 테이블의 컬럼 선택 */}
|
|
<Select
|
|
value={condition.field || ""}
|
|
onValueChange={(value) => updateCondition("field", value)}
|
|
disabled={!condition.tableType}
|
|
>
|
|
<SelectTrigger className="h-6 flex-1 text-xs">
|
|
<SelectValue placeholder={condition.tableType ? "컬럼" : "테이블을 먼저 선택하세요"} />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{condition.tableType === "from" &&
|
|
fromTableColumns.map((column) => (
|
|
<SelectItem key={column.columnName} value={column.columnName}>
|
|
{column.displayName || column.columnLabel || column.columnName}
|
|
</SelectItem>
|
|
))}
|
|
{condition.tableType === "to" &&
|
|
toTableColumns.map((column) => (
|
|
<SelectItem key={column.columnName} value={column.columnName}>
|
|
{column.displayName || column.columnLabel || column.columnName}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
<Select
|
|
value={condition.operator || "="}
|
|
onValueChange={(value: "=" | "!=" | ">" | "<" | ">=" | "<=" | "LIKE") => updateCondition("operator", value)}
|
|
>
|
|
<SelectTrigger className="h-6 w-20 text-xs">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="=">=</SelectItem>
|
|
<SelectItem value="!=">!=</SelectItem>
|
|
<SelectItem value=">">></SelectItem>
|
|
<SelectItem value="<"><</SelectItem>
|
|
<SelectItem value=">=">>=</SelectItem>
|
|
<SelectItem value="<="><=</SelectItem>
|
|
<SelectItem value="LIKE">LIKE</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
{renderConditionValue()}
|
|
<Button size="sm" variant="ghost" onClick={removeCondition} className="h-6 w-6 p-0">
|
|
<Trash2 className="h-2 w-2" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|