Files
invyone/frontend/components/control/schemas.ts
T
DDD1542 2f398ae0b3 chore: 제어모드 IDE 작업 + v2/legacy 레지스트리 컴포넌트 폐기
- 제어모드 IDE: ControlCardPanel, control/ide/* (Canvas/LeftRail/RightRail/PanZoomStage/V3RuleNode 등), schemas, lib/api/control
- 레지스트리 정리: aggregation-widget, status-count, section-card/paper, table-list(legacy/v2), tabs-widget 폐기 → table/_shared/ 로 통합
- InvLegacyButtonConfigPanel cp 마이그레이션
- canonical data view cleanup 후속 노트
2026-05-19 21:31:03 +09:00

157 lines
5.9 KiB
TypeScript

/**
* 제어 모드 — 노드 타입별 설정 schema (Inspector 자동 렌더용)
* v3 시안 shared.jsx 의 NODE_TYPE_SCHEMAS 미러
*
* 이건 코드 상수 (DB 에 들어갈 데이터 아님). 노드 16종의 "필드 정의" 자체.
* 노드 인스턴스의 실제 값은 ruleNode.config 에 들어감.
*/
export interface NodeFieldSchema {
k: string;
l: string;
v?: string;
mono?: boolean;
select?: string[];
multiline?: boolean;
hint?: string;
locked?: boolean;
}
export const NODE_TYPE_SCHEMAS: Record<string, NodeFieldSchema[]> = {
'timer': [
{ k: 'schedule', l: '스케줄 (cron)', v: '0 0 * * *', mono: true, hint: '매일 자정' },
{ k: 'timezone', l: '타임존', v: 'Asia/Seoul', select: ['Asia/Seoul', 'UTC', 'America/Los_Angeles'] },
{ k: 'max_runs', l: '1회 최대 실행 수', v: '1000', mono: true },
],
'status-change': [
{ k: 'table', l: '대상 테이블', v: '', mono: true, locked: true },
{ k: 'from', l: '이전 상태', v: '', mono: true },
{ k: 'to', l: '변경 상태', v: '', mono: true, hint: '트리거 조건' },
],
'condition': [
{ k: 'expr', l: '조건식', v: '', mono: true, hint: 'JS 표현식 — true/false 반환' },
{ k: 'yes_label', l: 'YES 분기 라벨', v: '예' },
{ k: 'no_label', l: 'NO 분기 라벨', v: '아니오' },
],
'validation': [
{ k: 'rules', l: '검증 룰', v: '', mono: true, multiline: true },
{ k: 'on_fail', l: '실패 시 동작', v: 'abort', select: ['abort', 'skip', 'log'] },
{ k: 'alert_owner', l: '실패 알림 대상', v: '' },
],
'auto-insert': [
{ k: 'target', l: '대상 테이블', v: '', mono: true },
{ k: 'mapping', l: '필드 매핑', v: '', mono: true, multiline: true },
{ k: 'fk_link', l: 'FK 연결 키', v: '', mono: true },
],
'calculation': [
{ k: 'expr', l: '수식', v: '', mono: true },
{ k: 'out_field', l: '결과 필드', v: '', mono: true },
{ k: 'round', l: '소수점', v: '2' },
],
'delete': [
{ k: 'target', l: '대상 테이블', v: '', mono: true },
{ k: 'soft_delete', l: 'Soft delete', v: 'true', select: ['true', 'false'] },
{ k: 'archive_to', l: '보관 테이블', v: '', mono: true },
],
'document': [
{ k: 'template', l: '템플릿', v: '', mono: true },
{ k: 'output', l: '출력 경로', v: '', mono: true },
{ k: 'format', l: '포맷', v: 'pdf', select: ['pdf', 'docx', 'html'] },
],
'approval': [
{ k: 'approver', l: '결재자', v: '' },
{ k: 'sla', l: 'SLA (시간)', v: '4', mono: true },
{ k: 'on_reject', l: '반려 시', v: 'rollback', select: ['rollback', 'manual', 'log'] },
],
'delay': [
{ k: 'duration', l: '대기 시간', v: '30m', mono: true, hint: '예: 30m / 2h / 1d' },
{ k: 'unit', l: '단위', v: 'minute', select: ['second', 'minute', 'hour', 'day'] },
],
'loop': [
{ k: 'source', l: '반복 대상', v: '', mono: true },
{ k: 'max', l: '최대 반복', v: '100', mono: true },
],
'parallel': [
{ k: 'branches', l: '병렬 브랜치 수', v: '2', mono: true },
{ k: 'wait', l: 'join 대기', v: 'all', select: ['all', 'any', 'first'] },
],
'merge': [
{ k: 'strategy', l: '병합 전략', v: 'overwrite', select: ['overwrite', 'keep', 'custom'] },
],
'webhook': [
{ k: 'url', l: 'URL', v: '', mono: true },
{ k: 'method', l: '메서드', v: 'POST', select: ['GET', 'POST', 'PUT', 'DELETE'] },
{ k: 'headers', l: '헤더', v: '', mono: true, multiline: true },
],
'notification': [
{ k: 'channel', l: '채널', v: 'slack', select: ['slack', 'email', 'teams', 'webhook'] },
{ k: 'target', l: '대상', v: '', mono: true },
{ k: 'template', l: '메시지', v: '', mono: true, multiline: true },
],
'log': [
{ k: 'table', l: '대상', v: 'audit_log', mono: true },
{ k: 'level', l: '레벨', v: 'info', select: ['debug', 'info', 'warn', 'error'] },
{ k: 'msg', l: '메시지', v: '', mono: true },
],
};
/** 카테고리 메타 — palette / inspector 색상 매핑 */
export const NODE_CATEGORIES: Array<{
id: 'trigger' | 'cond' | 'action' | 'flow' | 'extern' | 'log';
label: string;
cls: string;
rgb: string;
}> = [
{ id: 'trigger', label: '트리거', cls: 'c-trigger', rgb: '0,206,201' },
{ id: 'cond', label: '조건', cls: 'c-cond', rgb: '253,203,110' },
{ id: 'action', label: '액션', cls: 'c-action', rgb: '108,92,231' },
{ id: 'flow', label: '흐름', cls: 'c-flow', rgb: '253,121,168' },
{ id: 'extern', label: '연동', cls: 'c-extern', rgb: '0,184,148' },
{ id: 'log', label: '기록', cls: 'c-log', rgb: '107,107,118' },
];
/** invyone CTRL_NODE_TYPES 의 cat (한글) → v3 cat (영문) 매핑 */
export function ctrlCatToV3(catKo: string): 'trigger' | 'cond' | 'action' | 'flow' | 'extern' | 'log' {
switch (catKo) {
case '트리거': return 'trigger';
case '조건': return 'cond';
case '액션': return 'action';
case '흐름': return 'flow';
case '연동': return 'extern';
case '기록': return 'log';
default: return 'action';
}
}
import {
Clock4, Activity, GitBranch, ShieldCheck,
FilePlus2, Calculator, Archive, FileText,
Stamp, Timer, Repeat, GitMerge, Combine,
Webhook, BellRing, ScrollText, Circle,
type LucideIcon,
} from 'lucide-react';
/** 노드 타입 → Lucide 아이콘 매핑 (v3 시안 NODE_TYPES.icon 미러) */
const NODE_LUCIDE: Record<string, LucideIcon> = {
'timer': Clock4,
'status-change': Activity,
'condition': GitBranch,
'validation': ShieldCheck,
'auto-insert': FilePlus2,
'calculation': Calculator,
'delete': Archive,
'document': FileText,
'approval': Stamp,
'delay': Timer,
'loop': Repeat,
'parallel': GitMerge,
'merge': Combine,
'webhook': Webhook,
'notification': BellRing,
'log': ScrollText,
};
export function getNodeIcon(nodeType: string): LucideIcon {
return NODE_LUCIDE[nodeType] ?? Circle;
}