207 lines
7.7 KiB
TypeScript
207 lines
7.7 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Select, SelectContent, SelectItem, 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";
|
|
|
|
interface ActionConditionRendererProps {
|
|
condition: ConditionNode;
|
|
condIndex: number;
|
|
actionIndex: number;
|
|
settings: DataSaveSettings;
|
|
onSettingsChange: (settings: DataSaveSettings) => void;
|
|
fromTableColumns: ColumnInfo[];
|
|
getActionCurrentGroupLevel: (conditions: ConditionNode[], conditionIndex: number) => number;
|
|
}
|
|
|
|
export const ActionConditionRenderer: React.FC<ActionConditionRendererProps> = ({
|
|
condition,
|
|
condIndex,
|
|
actionIndex,
|
|
settings,
|
|
onSettingsChange,
|
|
fromTableColumns,
|
|
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 selectedColumn = fromTableColumns.find((col) => col.columnName === condition.field);
|
|
const dataType = selectedColumn?.dataType?.toLowerCase() || "string";
|
|
const inputType = getInputTypeForDataType(dataType);
|
|
|
|
if (dataType.includes("bool")) {
|
|
return (
|
|
<Select value={String(condition.value || "")} onValueChange={(value) => updateCondition("value", value)}>
|
|
<SelectTrigger className="h-6 flex-1 text-xs">
|
|
<SelectValue placeholder="선택" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="true">TRUE</SelectItem>
|
|
<SelectItem value="false">FALSE</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
);
|
|
} else {
|
|
return (
|
|
<Input
|
|
type={inputType}
|
|
placeholder={inputType === "number" ? "숫자" : "값"}
|
|
value={String(condition.value || "")}
|
|
onChange={(e) => updateCondition("value", e.target.value)}
|
|
className="h-6 flex-1 text-xs"
|
|
/>
|
|
);
|
|
}
|
|
};
|
|
|
|
// 그룹 시작 렌더링
|
|
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`,
|
|
}}
|
|
>
|
|
<Select value={condition.field || ""} onValueChange={(value) => updateCondition("field", value)}>
|
|
<SelectTrigger className="h-6 flex-1 text-xs">
|
|
<SelectValue placeholder="필드" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{fromTableColumns.map((column) => (
|
|
<SelectItem key={column.columnName} value={column.columnName}>
|
|
{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>
|
|
);
|
|
};
|