diff --git a/frontend/components/dashboard/DashboardViewer.tsx b/frontend/components/dashboard/DashboardViewer.tsx index fe17b97b..94e6aa8a 100644 --- a/frontend/components/dashboard/DashboardViewer.tsx +++ b/frontend/components/dashboard/DashboardViewer.tsx @@ -274,7 +274,6 @@ export function DashboardViewer({ console.log("๐Ÿ“ธ html-to-image ๋กœ๋”ฉ ์ค‘..."); // html-to-image ๋™์  import - // @ts-expect-error - html-to-image ํƒ€์ž… ์„ ์–ธ ๋ˆ„๋ฝ const { toPng } = await import("html-to-image"); console.log("๐Ÿ“ธ ์บ”๋ฒ„์Šค ์บก์ฒ˜ ์ค‘..."); diff --git a/frontend/components/dataflow/connection/redesigned/DataConnectionDesigner.tsx b/frontend/components/dataflow/connection/redesigned/DataConnectionDesigner.tsx index 718c9953..f13eb287 100644 --- a/frontend/components/dataflow/connection/redesigned/DataConnectionDesigner.tsx +++ b/frontend/components/dataflow/connection/redesigned/DataConnectionDesigner.tsx @@ -8,8 +8,6 @@ import { ConnectionStep } from "./RightPanel/ConnectionStep"; import { TableStep } from "./RightPanel/TableStep"; import { FieldMappingStep } from "./RightPanel/FieldMappingStep"; import { DataConnectionState } from "./types/redesigned"; -import { ResponsiveContainer, ResponsiveGrid } from "@/components/layout/ResponsiveContainer"; -import { useResponsive } from "@/lib/hooks/useResponsive"; const initialState: DataConnectionState = { connectionType: "data_save", diff --git a/frontend/components/dataflow/connection/redesigned/RightPanel/DataflowVisualization.tsx b/frontend/components/dataflow/connection/redesigned/RightPanel/DataflowVisualization.tsx index 770839ac..7b39944d 100644 --- a/frontend/components/dataflow/connection/redesigned/RightPanel/DataflowVisualization.tsx +++ b/frontend/components/dataflow/connection/redesigned/RightPanel/DataflowVisualization.tsx @@ -5,16 +5,45 @@ import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Database, Filter, Zap, CheckCircle, XCircle, Edit } from "lucide-react"; -import { DataConnectionState } from "../types/redesigned"; +interface TableRef { + tableName?: string; + tableLabel?: string; + displayName?: string; + [key: string]: any; +} + +interface ColumnRef { + columnName?: string; + displayName?: string; + labelKo?: string; + [key: string]: any; +} + +interface ControlCondition { + field: string; + operator: string; + value: string; + logicalOperator?: string; + [key: string]: any; +} + +interface DataflowAction { + actionType: string; + targetTable?: string; + name?: string; + fieldMappings?: any[]; + [key: string]: any; +} interface DataflowVisualizationProps { - state: Partial & { - dataflowActions?: Array<{ - actionType: string; - targetTable?: string; - name?: string; - fieldMappings?: any[]; - }>; + state: { + fromTable?: TableRef; + toTable?: TableRef; + controlConditions?: ControlCondition[]; + dataflowActions?: DataflowAction[]; + fromColumns?: ColumnRef[]; + toColumns?: ColumnRef[]; + [key: string]: any; }; onEdit: (step: "source" | "conditions" | "actions") => void; } diff --git a/frontend/components/pop/designer/PopCanvas.tsx b/frontend/components/pop/designer/PopCanvas.tsx index 0a9e70c1..41fa2955 100644 --- a/frontend/components/pop/designer/PopCanvas.tsx +++ b/frontend/components/pop/designer/PopCanvas.tsx @@ -832,14 +832,14 @@ function ReviewPanel({ }: ReviewPanelProps) { return (
{/* ํ—ค๋” */} -
+
๊ฒ€ํ†  ํ•„์š” ({components.length}๊ฐœ) @@ -859,7 +859,7 @@ function ReviewPanel({
{/* ์•ˆ๋‚ด ๋ฌธ๊ตฌ */} -
+

์ž๋™ ๋ฐฐ์น˜๋จ. ํด๋ฆญํ•˜์—ฌ ํ™•์ธ ํ›„ ํŽธ์ง‘ ๊ฐ€๋Šฅ

@@ -953,7 +953,7 @@ function HiddenPanel({ className={cn( "flex flex-col rounded-lg border-2 border-dashed bg-muted/50 transition-colors", isOver && canDrop - ? "border-input bg-muted/80/70" + ? "border-input bg-muted/70" : "border-input" )} style={{ @@ -962,7 +962,7 @@ function HiddenPanel({ }} > {/* ํ—ค๋” */} -
+
์ˆจ๊น€ ({components.length}๊ฐœ) diff --git a/frontend/components/screen/InteractiveDataTable.tsx b/frontend/components/screen/InteractiveDataTable.tsx index 22ab5158..8cd4fc32 100644 --- a/frontend/components/screen/InteractiveDataTable.tsx +++ b/frontend/components/screen/InteractiveDataTable.tsx @@ -261,11 +261,11 @@ export const InteractiveDataTable: React.FC = ({ label: component.title || "๋ฐ์ดํ„ฐ ํ…Œ์ด๋ธ”", tableName: component.tableName, columns: component.columns.map((col) => ({ - columnName: col.field, + columnName: col.columnName, columnLabel: col.label, - inputType: col.inputType || "text", + inputType: col.widgetType || "text", visible: col.visible !== false, - width: col.width || 150, + width: (col as any).width || 150, sortable: col.sortable, filterable: col.filterable !== false, })), @@ -583,6 +583,15 @@ export const InteractiveDataTable: React.FC = ({ const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [isDeleting, setIsDeleting] = useState(false); + // ์ถ”๊ฐ€/์ˆ˜์ • ๋ชจ๋‹ฌ ์ƒํƒœ + const [showAddModal, setShowAddModal] = useState(false); + const [showEditModal, setShowEditModal] = useState(false); + const [addFormData, setAddFormData] = useState>({}); + const [editFormData, setEditFormData] = useState>({}); + const [editingRowData, setEditingRowData] = useState | null>(null); + const [isAdding, setIsAdding] = useState(false); + const [isEditing, setIsEditing] = useState(false); + // ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด const [currentUser, setCurrentUser] = useState(null); @@ -696,12 +705,12 @@ export const InteractiveDataTable: React.FC = ({ const sampleData = Array.from({ length: 3 }, (_, i) => { const sample: Record = { id: i + 1 }; component.columns.forEach((col) => { - if (col.type === "number") { - sample[col.key] = Math.floor(Math.random() * 1000); - } else if (col.type === "boolean") { - sample[col.key] = i % 2 === 0 ? "Y" : "N"; + if (col.widgetType === "number") { + sample[col.columnName] = Math.floor(Math.random() * 1000); + } else if (col.widgetType === "boolean") { + sample[col.columnName] = i % 2 === 0 ? "Y" : "N"; } else { - sample[col.key] = `์ƒ˜ํ”Œ ${col.label} ${i + 1}`; + sample[col.columnName] = `์ƒ˜ํ”Œ ${col.label} ${i + 1}`; } }); return sample; @@ -1240,6 +1249,13 @@ export const InteractiveDataTable: React.FC = ({ })); }, []); + const handleAddFormChange = useCallback((columnName: string, value: any) => { + setAddFormData((prev) => ({ + ...prev, + [columnName]: value, + })); + }, []); + // ํŒŒ์ผ ์—…๋กœ๋“œ ํ•ธ๋“ค๋Ÿฌ const handleFileUpload = useCallback( async (columnName: string, files: FileList | null, isEdit: boolean = false) => { diff --git a/frontend/components/screen/toolbar/SlimToolbar.tsx b/frontend/components/screen/toolbar/SlimToolbar.tsx index 8f2e893a..dd4b60b5 100644 --- a/frontend/components/screen/toolbar/SlimToolbar.tsx +++ b/frontend/components/screen/toolbar/SlimToolbar.tsx @@ -35,7 +35,8 @@ import { Keyboard, Equal, } from "lucide-react"; -import { ScreenResolution, SCREEN_RESOLUTIONS } from "@/types/screen"; +import { ScreenResolution } from "@/types/screen"; +import { SCREEN_RESOLUTIONS } from "@/types/screen-management"; import { DropdownMenu, DropdownMenuContent, diff --git a/frontend/components/screen/widgets/FileUpload.tsx b/frontend/components/screen/widgets/FileUpload.tsx index 6ee77a96..fcb0a639 100644 --- a/frontend/components/screen/widgets/FileUpload.tsx +++ b/frontend/components/screen/widgets/FileUpload.tsx @@ -1,14 +1,65 @@ import React, { useState, useCallback, useRef, useEffect } from "react"; import { Upload, X, File, Image, Eye, Download, AlertCircle, CheckCircle, Loader2 } from "lucide-react"; -import { FileComponent, AttachedFileInfo } from "@/types/screen"; +import { FileComponent } from "@/types/screen-management"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { apiClient } from "@/lib/api/client"; import { useAuth } from "@/hooks/useAuth"; +// ์ฒจ๋ถ€ํŒŒ์ผ ์ •๋ณด (attach_file_info ํ…Œ์ด๋ธ” ๊ธฐ๋ฐ˜, UI ํ™•์žฅ ์†์„ฑ ํฌํ•จ) +export interface AttachedFileInfo { + objid: string; + savedFileName: string; + realFileName: string; + fileSize: number; + fileExt: string; + filePath: string; + docType: string; + docTypeName: string; + targetObjid: string; + parentTargetObjid?: string; + companyCode: string; + writer: string; + regdate: string; + status: string; + uploadProgress?: number; + isUploading?: boolean; + hasError?: boolean; + errorMessage?: string; +} + +// FileTypeConfig ํ™•์žฅ (FileComponent์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ถ”๊ฐ€ ์†์„ฑ ํฌํ•จ) +interface ExtendedFileTypeConfig { + accept?: string[]; + multiple?: boolean; + maxSize?: number; + maxFiles?: number; + showPreview?: boolean; + showProgress?: boolean; + docType?: string; + docTypeName?: string; + dragDropText?: string; + uploadButtonText?: string; + autoUpload?: boolean; + chunkedUpload?: boolean; + linkedTable?: string; + linkedField?: string; + autoLink?: boolean; + companyCode?: string; + recordId?: string; + isVirtualFileColumn?: boolean; + columnName?: string; +} + +// FileComponent๋ฅผ AttachedFileInfo ๊ธฐ๋ฐ˜์œผ๋กœ ํ™•์žฅํ•œ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž… +interface FileComponentWithAttached extends Omit { + uploadedFiles?: AttachedFileInfo[]; + fileConfig: ExtendedFileTypeConfig; +} + interface FileUploadProps { - component: FileComponent; - onUpdateComponent?: (updates: Partial) => void; + component: FileComponentWithAttached; + onUpdateComponent?: (updates: Partial) => void; onFileUpload?: (files: AttachedFileInfo[]) => void; // ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ ์ฝœ๋ฐฑ userInfo?: any; // ์‚ฌ์šฉ์ž ์ •๋ณด (์„ ํƒ์ ) }