ERP-node/frontend/components/dataflow/connection/DataSaveSettings.tsx

233 lines
9.7 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Plus, Save, Trash2 } from "lucide-react";
import { TableInfo, ColumnInfo } from "@/lib/api/dataflow";
import { DataSaveSettings as DataSaveSettingsType } from "@/types/connectionTypes";
import { ActionConditionsSection } from "./ActionConditionsSection";
import { ActionFieldMappings } from "./ActionFieldMappings";
import { ActionSplitConfig } from "./ActionSplitConfig";
interface DataSaveSettingsProps {
settings: DataSaveSettingsType;
onSettingsChange: (settings: DataSaveSettingsType) => void;
availableTables: TableInfo[];
fromTableColumns: ColumnInfo[];
toTableColumns: ColumnInfo[];
fromTableName?: string;
toTableName?: string;
tableColumnsCache: { [tableName: string]: ColumnInfo[] };
}
export const DataSaveSettings: React.FC<DataSaveSettingsProps> = ({
settings,
onSettingsChange,
availableTables,
fromTableColumns,
toTableColumns,
fromTableName,
toTableName,
tableColumnsCache,
}) => {
const addAction = () => {
const newAction = {
id: `action_${settings.actions.length + 1}`,
name: `액션 ${settings.actions.length + 1}`,
actionType: "insert" as const,
// 첫 번째 액션이 아니면 기본적으로 AND 연산자 추가
...(settings.actions.length > 0 && { logicalOperator: "AND" as const }),
fieldMappings: [],
conditions: [],
splitConfig: {
sourceField: "",
delimiter: "",
targetField: "",
},
};
onSettingsChange({
...settings,
actions: [...settings.actions, newAction],
});
};
const updateAction = (actionIndex: number, field: string, value: any) => {
const newActions = [...settings.actions];
(newActions[actionIndex] as any)[field] = value;
onSettingsChange({ ...settings, actions: newActions });
};
const removeAction = (actionIndex: number) => {
const newActions = settings.actions.filter((_, i) => i !== actionIndex);
// 첫 번째 액션을 삭제했다면, 새로운 첫 번째 액션의 logicalOperator 제거
if (actionIndex === 0 && newActions.length > 0) {
delete newActions[0].logicalOperator;
}
onSettingsChange({ ...settings, actions: newActions });
};
return (
<div className="rounded-lg border border-l-4 border-l-green-500 bg-green-50/30 p-4">
<div className="mb-3 flex items-center gap-2">
<Save className="h-4 w-4 text-green-500" />
<span className="text-sm font-medium"> </span>
</div>
<div className="space-y-4">
{/* 액션 목록 */}
<div>
<div className="mb-2 flex items-center justify-between">
<Label className="text-sm font-medium"> </Label>
<Button size="sm" variant="outline" onClick={addAction} className="h-7 text-xs">
<Plus className="mr-1 h-3 w-3" />
</Button>
</div>
{settings.actions.length === 0 ? (
<div className="rounded-lg border border-dashed p-3 text-center text-xs text-gray-500">
.
</div>
) : (
<div className="space-y-3">
{settings.actions.map((action, actionIndex) => (
<div key={action.id}>
{/* 첫 번째 액션이 아닌 경우 논리 연산자 표시 */}
{actionIndex > 0 && (
<div className="mb-2 flex items-center justify-center">
<div className="flex items-center gap-2 rounded-lg bg-gray-100 px-3 py-1">
<span className="text-xs text-gray-600"> :</span>
<Select
value={action.logicalOperator || "AND"}
onValueChange={(value: "AND" | "OR") => updateAction(actionIndex, "logicalOperator", value)}
>
<SelectTrigger className="h-8 w-20 text-sm">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="AND">AND</SelectItem>
<SelectItem value="OR">OR</SelectItem>
</SelectContent>
</Select>
</div>
</div>
)}
<div className="rounded border bg-white p-3">
<div className="mb-3 flex items-center justify-between">
<Input
value={action.name}
onChange={(e) => updateAction(actionIndex, "name", e.target.value)}
className="h-7 flex-1 text-xs font-medium"
placeholder="액션 이름"
/>
<Button
size="sm"
variant="ghost"
onClick={() => removeAction(actionIndex)}
className="h-7 w-7 p-0"
>
<Trash2 className="h-3 w-3" />
</Button>
</div>
<div className="grid grid-cols-1 gap-3">
{/* 액션 타입 */}
<div>
<Label className="text-xs"> </Label>
<Select
value={action.actionType}
onValueChange={(value: "insert" | "update" | "delete" | "upsert") =>
updateAction(actionIndex, "actionType", value)
}
>
<SelectTrigger className="h-7 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="insert">INSERT</SelectItem>
<SelectItem value="update">UPDATE</SelectItem>
<SelectItem value="delete">DELETE</SelectItem>
<SelectItem value="upsert">UPSERT</SelectItem>
</SelectContent>
</Select>
</div>
</div>
{/* 액션별 개별 실행 조건 */}
<ActionConditionsSection
action={action}
actionIndex={actionIndex}
settings={settings}
onSettingsChange={onSettingsChange}
fromTableColumns={fromTableColumns}
toTableColumns={toTableColumns}
fromTableName={fromTableName}
toTableName={toTableName}
/>
{/* 데이터 분할 설정 - DELETE 액션은 제외 */}
{action.actionType !== "delete" && (
<ActionSplitConfig
action={action}
actionIndex={actionIndex}
settings={settings}
onSettingsChange={onSettingsChange}
fromTableColumns={fromTableColumns}
toTableColumns={toTableColumns}
/>
)}
{/* 필드 매핑 - DELETE 액션은 제외 */}
{action.actionType !== "delete" && (
<ActionFieldMappings
action={action}
actionIndex={actionIndex}
settings={settings}
onSettingsChange={onSettingsChange}
availableTables={availableTables}
tableColumnsCache={tableColumnsCache}
fromTableColumns={fromTableColumns}
toTableColumns={toTableColumns}
fromTableName={fromTableName}
toTableName={toTableName}
/>
)}
{/* DELETE 액션일 때 안내 메시지 */}
{action.actionType === "delete" && (
<div className="mt-3">
<div className="rounded border border-blue-200 bg-blue-50 p-3 text-xs text-blue-700">
<div className="flex items-start gap-2">
<span></span>
<div>
<div className="font-medium">DELETE </div>
<div className="mt-1">
DELETE <strong></strong> .
<br />
설정: 불필요 ( )
<br />
매핑: 불필요 ( )
<br />
.
</div>
</div>
</div>
</div>
</div>
)}
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
);
};