제어관리 수정

This commit is contained in:
kjs
2025-10-02 11:12:45 +09:00
parent 3f76d16afe
commit db25b0435f
6 changed files with 539 additions and 160 deletions

View File

@@ -5,7 +5,8 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import { ArrowLeft, Settings, CheckCircle } from "lucide-react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ArrowLeft, Settings, CheckCircle, Eye } from "lucide-react";
// 타입 import
import { DataConnectionState, DataConnectionActions } from "../types/redesigned";
@@ -14,6 +15,7 @@ import { getColumnsFromConnection } from "@/lib/api/multiConnection";
// 컴포넌트 import
import ActionConditionBuilder from "./ActionConfig/ActionConditionBuilder";
import { DataflowVisualization } from "./DataflowVisualization";
interface ActionConfigStepProps {
state: DataConnectionState;
@@ -78,7 +80,8 @@ const ActionConfigStep: React.FC<ActionConfigStepProps> = ({
const canComplete =
actionType &&
(actionType === "insert" || (actionConditions.length > 0 && (actionType === "delete" || fieldMappings.length > 0)));
(actionType === "insert" ||
((actionConditions || []).length > 0 && (actionType === "delete" || fieldMappings.length > 0)));
return (
<>
@@ -89,106 +92,137 @@ const ActionConfigStep: React.FC<ActionConfigStepProps> = ({
</CardTitle>
</CardHeader>
<CardContent className="max-h-[calc(100vh-400px)] min-h-[400px] space-y-6 overflow-y-auto">
{/* 액션 타입 선택 */}
<div className="space-y-3">
<h3 className="text-lg font-semibold"> </h3>
<Select value={actionType} onValueChange={actions.setActionType}>
<SelectTrigger>
<SelectValue placeholder="액션 타입을 선택하세요" />
</SelectTrigger>
<SelectContent>
{actionTypes.map((type) => (
<SelectItem key={type.value} value={type.value}>
<div className="flex w-full items-center justify-between">
<div>
<span className="font-medium">{type.label}</span>
<p className="text-muted-foreground text-xs">{type.description}</p>
<CardContent className="flex h-full flex-col overflow-hidden p-0">
<Tabs defaultValue="config" className="flex h-full flex-col">
<div className="flex-shrink-0 border-b px-4 pt-4">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="config" className="flex items-center gap-2">
<Settings className="h-4 w-4" />
</TabsTrigger>
<TabsTrigger value="visualization" className="flex items-center gap-2">
<Eye className="h-4 w-4" />
</TabsTrigger>
</TabsList>
</div>
{/* 액션 설정 탭 */}
<TabsContent value="config" className="mt-0 flex-1 overflow-y-auto p-4">
<div className="space-y-6">
{/* 액션 타입 선택 */}
<div className="space-y-3">
<h3 className="text-lg font-semibold"> </h3>
<Select value={actionType} onValueChange={actions.setActionType}>
<SelectTrigger>
<SelectValue placeholder="액션 타입을 선택하세요" />
</SelectTrigger>
<SelectContent>
{actionTypes.map((type) => (
<SelectItem key={type.value} value={type.value}>
<div className="flex w-full items-center justify-between">
<div>
<span className="font-medium">{type.label}</span>
<p className="text-muted-foreground text-xs">{type.description}</p>
</div>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
{actionType && (
<div className="bg-primary/5 border-primary/20 rounded-lg border p-3">
<div className="flex items-center gap-2">
<Badge variant="outline" className="text-primary">
{actionTypes.find((t) => t.value === actionType)?.label}
</Badge>
<span className="text-sm">{actionTypes.find((t) => t.value === actionType)?.description}</span>
</div>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
{actionType && (
<div className="bg-primary/5 border-primary/20 rounded-lg border p-3">
<div className="flex items-center gap-2">
<Badge variant="outline" className="text-primary">
{actionTypes.find((t) => t.value === actionType)?.label}
</Badge>
<span className="text-sm">{actionTypes.find((t) => t.value === actionType)?.description}</span>
)}
</div>
</div>
)}
</div>
{/* 상세 조건 설정 */}
{actionType && !isLoading && fromColumns.length > 0 && toColumns.length > 0 && (
<ActionConditionBuilder
actionType={actionType}
fromColumns={fromColumns}
toColumns={toColumns}
conditions={actionConditions}
fieldMappings={fieldMappings}
onConditionsChange={(conditions) => {
// 액션 조건 배열 전체 업데이트
actions.setActionConditions(conditions);
}}
onFieldMappingsChange={setFieldMappings}
/>
)}
{/* 상세 조건 설정 */}
{actionType && !isLoading && fromColumns.length > 0 && toColumns.length > 0 && (
<ActionConditionBuilder
actionType={actionType}
fromColumns={fromColumns}
toColumns={toColumns}
conditions={actionConditions || []}
fieldMappings={fieldMappings}
onConditionsChange={(conditions) => {
// 액션 조건 배열 전체 업데이트
actions.setActionConditions(conditions);
}}
onFieldMappingsChange={setFieldMappings}
/>
)}
{/* 로딩 상태 */}
{isLoading && (
<div className="flex items-center justify-center py-8">
<div className="text-muted-foreground"> ...</div>
</div>
)}
{/* 로딩 상태 */}
{isLoading && (
<div className="flex items-center justify-center py-8">
<div className="text-muted-foreground"> ...</div>
</div>
)}
{/* INSERT 액션 안내 */}
{actionType === "insert" && (
<div className="rounded-lg border border-green-200 bg-green-50 p-4">
<h4 className="mb-2 text-sm font-medium text-green-800">INSERT </h4>
<p className="text-sm text-green-700">
INSERT . .
</p>
</div>
)}
{/* INSERT 액션 안내 */}
{actionType === "insert" && (
<div className="rounded-lg border border-green-200 bg-green-50 p-4">
<h4 className="mb-2 text-sm font-medium text-green-800">INSERT </h4>
<p className="text-sm text-green-700">
INSERT . .
</p>
</div>
)}
{/* 액션 요약 */}
{actionType && (
<div className="bg-muted/50 rounded-lg p-4">
<h4 className="mb-3 text-sm font-medium"> </h4>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span> :</span>
<Badge variant="outline">{actionType.toUpperCase()}</Badge>
</div>
{actionType !== "insert" && (
<>
<div className="flex justify-between text-sm">
<span> :</span>
<span className="text-muted-foreground">
{actionConditions.length > 0 ? `${actionConditions.length}개 조건` : "조건 없음"}
</span>
</div>
{actionType !== "delete" && (
{/* 액션 요약 */}
{actionType && (
<div className="bg-muted/50 rounded-lg p-4">
<h4 className="mb-3 text-sm font-medium"> </h4>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span> :</span>
<span className="text-muted-foreground">
{fieldMappings.length > 0 ? `${fieldMappings.length}개 필드` : "필드 없음"}
</span>
<span> :</span>
<Badge variant="outline">{actionType.toUpperCase()}</Badge>
</div>
)}
</>
{actionType !== "insert" && (
<>
<div className="flex justify-between text-sm">
<span> :</span>
<span className="text-muted-foreground">
{actionConditions.length > 0 ? `${actionConditions.length}개 조건` : "조건 없음"}
</span>
</div>
{actionType !== "delete" && (
<div className="flex justify-between text-sm">
<span> :</span>
<span className="text-muted-foreground">
{fieldMappings.length > 0 ? `${fieldMappings.length}개 필드` : "필드 없음"}
</span>
</div>
)}
</>
)}
</div>
</div>
)}
</div>
</div>
)}
</TabsContent>
{/* 흐름 미리보기 탭 */}
<TabsContent value="visualization" className="mt-0 flex-1 overflow-y-auto">
<DataflowVisualization
state={state}
onEdit={(step) => {
// 편집 버튼 클릭 시 해당 단계로 이동하는 로직 추가 가능
console.log(`편집 요청: ${step}`);
}}
/>
</TabsContent>
</Tabs>
{/* 하단 네비게이션 */}
<div className="border-t pt-4">
<div className="flex-shrink-0 border-t bg-white p-4">
<div className="flex items-center justify-between">
<Button variant="outline" onClick={onBack} className="flex items-center gap-2">
<ArrowLeft className="h-4 w-4" />