/** * ๐ŸŽฎ ์ œ์–ด๊ด€๋ฆฌ ์‹œ์Šคํ…œ ์ „์šฉ ํƒ€์ž… ์ •์˜ * * ๋ฒ„ํŠผ ์•ก์…˜, ๋ฐ์ดํ„ฐํ”Œ๋กœ์šฐ, ์กฐ๊ฑด๋ถ€ ์‹คํ–‰, ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ๋“ฑ ์ œ์–ด๊ด€๋ฆฌ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ํƒ€์ž…๋“ค */ import { ButtonActionType, ConditionOperator, CompanyCode, ActiveStatus, TimestampFields, BaseApiResponse, } from "./unified-core"; // ===== ๋ฒ„ํŠผ ์ œ์–ด ๊ด€๋ จ ===== /** * ํ™•์žฅ๋œ ๋ฒ„ํŠผ ์„ค์ • (ํ™”๋ฉด๊ด€๋ฆฌ์˜ ButtonTypeConfig ํ™•์žฅ) */ export interface ExtendedButtonTypeConfig { // ๊ธฐ๋ณธ ๋ฒ„ํŠผ ์„ค์ • actionType: ButtonActionType; text?: string; variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"; size?: "sm" | "md" | "lg"; icon?: string; // ํ™•์ธ ๋ฐ ๊ฒ€์ฆ confirmMessage?: string; requiresConfirmation?: boolean; // ๋ชจ๋‹ฌ ๊ด€๋ จ ์„ค์ • popupTitle?: string; popupContent?: string; popupScreenId?: number; // ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ด€๋ จ ์„ค์ • navigateType?: "url" | "screen"; navigateUrl?: string; navigateScreenId?: number; navigateTarget?: "_self" | "_blank"; // ์ปค์Šคํ…€ ์•ก์…˜ ์„ค์ • customAction?: string; // ๐ŸŽฏ ์ œ์–ด๊ด€๋ฆฌ ๊ธฐ๋Šฅ enableDataflowControl?: boolean; dataflowConfig?: ButtonDataflowConfig; dataflowTiming?: "before" | "after" | "replace"; // ์Šคํƒ€์ผ ์„ค์ • backgroundColor?: string; textColor?: string; borderColor?: string; } /** * ๐Ÿ”ฅ ๋‹จ์ˆœํ™”๋œ ๋ฒ„ํŠผ ๋ฐ์ดํ„ฐํ”Œ๋กœ์šฐ ์„ค์ • */ export interface ButtonDataflowConfig { // ์ œ์–ด ๋ฐฉ์‹ ์„ ํƒ (๊ด€๊ณ„ ์‹คํ–‰ + ๐Ÿ†• ๋…ธ๋“œ ํ”Œ๋กœ์šฐ) controlMode: "relationship" | "flow" | "none"; // ๊ด€๊ณ„ ๊ธฐ๋ฐ˜ ์ œ์–ด relationshipConfig?: { relationshipId: string; // ๊ด€๊ณ„ ์ง์ ‘ ์„ ํƒ relationshipName: string; // ๊ด€๊ณ„๋ช… ํ‘œ์‹œ executionTiming: "before" | "after" | "replace"; contextData?: Record; // ์‹คํ–‰ ์‹œ ์ „๋‹ฌํ•  ์ปจํ…์ŠคํŠธ }; // ๐Ÿ†• ๋…ธ๋“œ ํ”Œ๋กœ์šฐ ๊ธฐ๋ฐ˜ ์ œ์–ด flowConfig?: { flowId: number; // ๋…ธ๋“œ ํ”Œ๋กœ์šฐ ID flowName: string; // ํ”Œ๋กœ์šฐ๋ช… ํ‘œ์‹œ executionTiming: "before" | "after" | "replace"; contextData?: Record; // ์‹คํ–‰ ์‹œ ์ „๋‹ฌํ•  ์ปจํ…์ŠคํŠธ }; // ์ œ์–ด ๋ฐ์ดํ„ฐ ์†Œ์Šค (๊ธฐ์กด ํ˜ธํ™˜์„ฑ ์œ ์ง€) controlDataSource?: ControlDataSource; // ์‹คํ–‰ ์˜ต์…˜ executionOptions?: ExecutionOptions; // ๐Ÿ”ง ๊ธฐ์กด ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•œ ํ•„๋“œ๋“ค (deprecated) selectedDiagramId?: number; selectedRelationshipId?: number; directControl?: DirectControlConfig; // ๐Ÿ”ง ์ œ๊ฑฐ๋œ ํ•„๋“œ๋“ค (ํ•˜์œ„ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด optional๋กœ ์œ ์ง€) externalCallConfig?: any; // deprecated customConfig?: any; // deprecated } /** * ์ œ์–ด ๋ฐ์ดํ„ฐ ์†Œ์Šค ํƒ€์ž… */ export type ControlDataSource = "form" | "table-selection" | "both"; /** * ์ง์ ‘ ์ œ์–ด ์„ค์ • */ export interface DirectControlConfig { conditions: DataflowCondition[]; actions: DataflowAction[]; logic?: "AND" | "OR" | "CUSTOM"; customLogic?: string; // "(A AND B) OR (C AND D)" } /** * ์‹คํ–‰ ์˜ต์…˜ */ export interface ExecutionOptions { timeout?: number; // ms retryCount?: number; parallelExecution?: boolean; continueOnError?: boolean; } // ===== ๋ฐ์ดํ„ฐํ”Œ๋กœ์šฐ ์กฐ๊ฑด ๋ฐ ์•ก์…˜ ===== /** * ๋ฐ์ดํ„ฐํ”Œ๋กœ์šฐ ์กฐ๊ฑด */ export interface DataflowCondition { id: string; type: "condition" | "group"; // ๋‹จ์ผ ์กฐ๊ฑด field?: string; operator?: ConditionOperator; value?: unknown; dataSource?: ControlDataSource; // ๊ทธ๋ฃน ์กฐ๊ฑด conditions?: DataflowCondition[]; logic?: "AND" | "OR"; // ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ name?: string; description?: string; } /** * ๋ฐ์ดํ„ฐํ”Œ๋กœ์šฐ ์•ก์…˜ */ export interface DataflowAction { id: string; name: string; type: ActionType; // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•ก์…˜ tableName?: string; operation?: DatabaseOperation; fields?: ActionField[]; conditions?: DataflowCondition[]; // API ์•ก์…˜ endpoint?: string; method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; headers?: Record; body?: unknown; // ์•Œ๋ฆผ ์•ก์…˜ notificationType?: NotificationType; message?: string; recipients?: string[]; // ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์•ก์…˜ redirectUrl?: string; redirectTarget?: "_self" | "_blank"; // ์‹คํ–‰ ์˜ต์…˜ timeout?: number; retryCount?: number; rollbackable?: boolean; // ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ description?: string; order?: number; } /** * ์•ก์…˜ ํƒ€์ž… */ export type ActionType = "database" | "api" | "notification" | "redirect" | "custom"; /** * ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—… ํƒ€์ž… */ export type DatabaseOperation = "INSERT" | "UPDATE" | "DELETE" | "SELECT"; /** * ์•ก์…˜ ํ•„๋“œ */ export interface ActionField { name: string; value: unknown; type?: "static" | "dynamic" | "computed"; source?: string; // ๋™์  ๊ฐ’์˜ ์†Œ์Šค (form field, selected row ๋“ฑ) } /** * ์•Œ๋ฆผ ํƒ€์ž… */ export type NotificationType = "success" | "error" | "warning" | "info" | "toast" | "modal" | "email"; // ===== ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ ===== /** * ํŠธ๋žœ์žญ์…˜ ๊ทธ๋ฃน */ export interface TransactionGroup { id: string; name: string; description?: string; actions: DataflowAction[]; rollbackStrategy: RollbackStrategy; executionMode: "sequential" | "parallel"; onFailure: FailureHandling; } /** * ๋กค๋ฐฑ ์ „๋žต */ export type RollbackStrategy = | "none" // ๋กค๋ฐฑ ์•ˆํ•จ | "partial" // ์‹คํŒจํ•œ ์•ก์…˜๋งŒ ๋กค๋ฐฑ | "complete"; // ์ „์ฒด ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ /** * ์‹คํŒจ ์ฒ˜๋ฆฌ ๋ฐฉ์‹ */ export type FailureHandling = | "stop" // ์‹คํŒจ ์‹œ ์ค‘๋‹จ | "continue" // ์‹คํŒจํ•ด๋„ ๊ณ„์† ์ง„ํ–‰ | "alternative"; // ๋Œ€์•ˆ ์•ก์…˜ ์‹คํ–‰ /** * ์กฐ๊ฑด๋ถ€ ์‹คํ–‰ ๊ณ„ํš */ export interface ConditionalExecutionPlan { id: string; name: string; conditions: ExecutionCondition[]; logic: "AND" | "OR" | "CUSTOM"; customLogic?: string; } /** * ์‹คํ–‰ ์กฐ๊ฑด */ export interface ExecutionCondition { id: string; type: "action_group" | "validation" | "data_check"; // ์•ก์…˜ ๊ทธ๋ฃน ์กฐ๊ฑด actionGroup?: TransactionGroup; // ๊ฒ€์ฆ ์กฐ๊ฑด validation?: { field: string; operator: ConditionOperator; value: unknown; }; // ์„ฑ๊ณต/์‹คํŒจ ์กฐ๊ฑด expectedResult: "success" | "failure" | "any"; } /** * ์กฐ๊ฑด๋ถ€ ์•ก์…˜ ๊ทธ๋ฃน */ export interface ConditionalActionGroup { id: string; name: string; description?: string; // ์‹คํ–‰ ์กฐ๊ฑด executionCondition: { type: "always" | "conditional" | "fallback"; conditions?: DataflowCondition[]; logic?: "AND" | "OR"; }; // ์•ก์…˜๋“ค actions: DataflowAction[]; // ์„ฑ๊ณต/์‹คํŒจ ์กฐ๊ฑด ์ •์˜ successCriteria: { type: "all_success" | "any_success" | "custom"; customLogic?: string; }; // ๋‹ค์Œ ๋‹จ๊ณ„ ์ •์˜ onSuccess?: { nextGroup?: string; completeTransaction?: boolean; }; onFailure?: { retryCount?: number; fallbackGroup?: string; rollbackStrategy?: RollbackStrategy; }; } // ===== ์‹คํ–‰ ๊ฒฐ๊ณผ ๋ฐ ์ƒํƒœ ===== /** * ์•ก์…˜ ์‹คํ–‰ ๊ฒฐ๊ณผ */ export interface ActionExecutionResult { actionId: string; transactionId?: string; status: "pending" | "running" | "success" | "failed" | "rolled_back"; startTime: Date; endTime?: Date; result?: unknown; error?: { code: string; message: string; details?: unknown; }; rollbackData?: unknown; } /** * ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰ ์ƒํƒœ */ export interface TransactionExecutionState { transactionId: string; status: "pending" | "running" | "success" | "failed" | "rolling_back" | "rolled_back"; actions: ActionExecutionResult[]; rollbackActions?: ActionExecutionResult[]; startTime: Date; endTime?: Date; } /** * ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰ ๊ฒฐ๊ณผ */ export interface TransactionExecutionResult { success: boolean; message: string; requiresRollback: boolean; results: [string, boolean][]; transactionId?: string; } /** * ๋ฐ์ดํ„ฐํ”Œ๋กœ์šฐ ์‹คํ–‰ ๊ฒฐ๊ณผ */ export interface DataflowExecutionResult { success: boolean; message: string; data?: unknown; executedActions?: ActionExecutionResult[]; failedActions?: ActionExecutionResult[]; totalActions?: number; executionTime?: number; } // ===== ์ œ์–ด ์ปจํ…์ŠคํŠธ ===== /** * ํ™•์žฅ๋œ ์ œ์–ด ์ปจํ…์ŠคํŠธ */ export interface ExtendedControlContext { // ๊ธฐ์กด ํผ ๋ฐ์ดํ„ฐ formData: Record; // ํ…Œ์ด๋ธ” ์„ ํƒ ๋ฐ์ดํ„ฐ selectedRows?: unknown[]; selectedRowsData?: Record[]; // ์ œ์–ด ๋ฐ์ดํ„ฐ ์†Œ์Šค ํƒ€์ž… controlDataSource: ControlDataSource; // ๊ธฐํƒ€ ์ปจํ…์ŠคํŠธ buttonId: string; componentData?: unknown; timestamp: string; clickCount?: number; // ์‚ฌ์šฉ์ž ์ •๋ณด userId?: string; companyCode?: CompanyCode; // ํ™”๋ฉด ์ •๋ณด screenId?: number; screenCode?: string; } /** * ๋น ๋ฅธ ๊ฒ€์ฆ ๊ฒฐ๊ณผ */ export interface QuickValidationResult { success: boolean; message?: string; canExecuteImmediately: boolean; actions?: DataflowAction[]; } // ===== ๋ฒ„ํŠผ ์•ก์…˜ ํ‘œ์ค€ (DB ๊ธฐ๋ฐ˜) ===== /** * ๋ฒ„ํŠผ ์•ก์…˜ ํ‘œ์ค€ ์ •์˜ (DB์˜ button_action_standards ํ…Œ์ด๋ธ”) */ export interface ButtonActionStandard extends TimestampFields { action_type: string; action_name: string; action_name_eng?: string; description?: string; category: string; default_text?: string; default_text_eng?: string; default_icon?: string; default_color?: string; default_variant?: string; confirmation_required: boolean; confirmation_message?: string; validation_rules?: unknown; action_config?: unknown; sort_order?: number; is_active: ActiveStatus; } /** * ๋ฒ„ํŠผ ์•ก์…˜ ์ƒ์„ฑ/์ˆ˜์ • ์š”์ฒญ */ export interface ButtonActionFormData { action_type: string; action_name: string; action_name_eng?: string; description?: string; category: string; default_text?: string; default_text_eng?: string; default_icon?: string; default_color?: string; default_variant?: string; confirmation_required: boolean; confirmation_message?: string; validation_rules?: unknown; action_config?: unknown; sort_order?: number; is_active: ActiveStatus; } // ===== API ์‘๋‹ต ํƒ€์ž…๋“ค ===== /** * ๋ฒ„ํŠผ ์•ก์…˜ ๋ชฉ๋ก ์‘๋‹ต */ export interface ButtonActionListResponse extends BaseApiResponse {} /** * ๋ฐ์ดํ„ฐํ”Œ๋กœ์šฐ ์‹คํ–‰ ์‘๋‹ต */ export interface DataflowExecutionResponse extends BaseApiResponse {} /** * ํŠธ๋žœ์žญ์…˜ ์‹คํ–‰ ์‘๋‹ต */ export interface TransactionExecutionResponse extends BaseApiResponse {} // ===== ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…๋“ค ===== /** * ๋กค๋ฐฑ ํ•ธ๋“ค๋Ÿฌ */ export interface RollbackHandler { actionId: string; rollbackFn: () => Promise; } /** * ์ตœ์ ํ™”๋œ ์‹คํ–‰ ๊ฒฐ๊ณผ */ export interface OptimizedExecutionResult { jobId: string; immediateResult?: unknown; isBackground?: boolean; timing?: "before" | "after" | "replace"; } // ===== ํƒ€์ž… ๊ฐ€๋“œ ๋ฐ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋“ค ===== /** * DataflowCondition์ด ๋‹จ์ผ ์กฐ๊ฑด์ธ์ง€ ํ™•์ธ */ export const isSingleCondition = (condition: DataflowCondition): boolean => { return condition.type === "condition" && !!condition.field; }; /** * DataflowCondition์ด ๊ทธ๋ฃน ์กฐ๊ฑด์ธ์ง€ ํ™•์ธ */ export const isGroupCondition = (condition: DataflowCondition): boolean => { return condition.type === "group" && !!condition.conditions?.length; }; /** * DataflowAction์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•ก์…˜์ธ์ง€ ํ™•์ธ */ export const isDatabaseAction = (action: DataflowAction): boolean => { return action.type === "database" && !!action.tableName; }; /** * DataflowAction์ด API ์•ก์…˜์ธ์ง€ ํ™•์ธ */ export const isApiAction = (action: DataflowAction): boolean => { return action.type === "api" && !!action.endpoint; }; /** * ์•ก์…˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ ์„ฑ๊ณต์ธ์ง€ ํ™•์ธ */ export const isActionSuccess = (result: ActionExecutionResult): boolean => { return result.status === "success"; }; /** * ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ (์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจ) */ export const isTransactionCompleted = (state: TransactionExecutionState): boolean => { return ["success", "failed", "rolled_back"].includes(state.status); };