e44ba2953a
T3 (본체) + T4 (ConfigPanel) 흡수 완료에 따라 옛 별도 컴포넌트 폐기.
v2-split-panel-layout 은 별도 컨테이너로 유지 (Codex 권고).
폴더 5개 삭제
- v2-table-grouped/ (537 + ConfigPanel)
- v2-pivot-grid/ (1963 + utils + components + hooks + ConfigPanel)
- v2-card-display/ (1314 + ConfigPanel)
- pivot-grid/ (legacy)
- card-display/ (legacy)
ConfigPanel 3개 삭제
- V2TableGroupedConfigPanel.tsx
- V2PivotGridConfigPanel.tsx
- V2CardDisplayConfigPanel.tsx
레지스트리 / alias / hidden 정리
- lib/registry/components/index.ts: 5개 import 라인 제거 (renderer 자동 등록 폐기)
- ComponentsPanel.tsx: hidden 목록의 v2-card-display ("→ stats" 잘못된 매핑) /
v2-table-grouped / v2-pivot-grid / pivot-grid / card-display 모두 제거
- DynamicComponentRenderer.tsx LEGACY_TO_UNIFIED: v2-card-display "→stats"
(잘못) / v2-table-grouped / v2-pivot-grid / card-display alias 제거
- getComponentConfigPanel.tsx: 4개 dynamic import + alias 제거
- templateMigrate.ts: 3 매핑 제거
- componentConfig.ts: v2PivotGridOverridesSchema, v2CardDisplayOverridesSchema
+ 등록 + defaults 제거
이벤트 dead code
- types/component-events.ts: RefreshCardDisplayDetail / REFRESH_CARD_DISPLAY
이벤트 (사용처 0건 — v2-card-display 전용) 제거
ScreenDesigner
- 4058 의 isCardDisplay 분기 (66.67% 그리드 특수 처리) 제거
- 4098 의 gridColumnsRatioMap 의 "card-display" 항목 제거
검증
- npx tsc --noEmit 우리 작업 파일 새 에러 0
- v2-table-grouped/v2-pivot-grid/v2-card-display/RefreshCardDisplay 잔존
grep — 의도적 주석 5곳만 (폐기 흔적 설명)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
231 lines
6.2 KiB
TypeScript
231 lines
6.2 KiB
TypeScript
/**
|
|
* V2 컴포넌트 간 통신 이벤트 타입 정의
|
|
*
|
|
* 모든 V2 컴포넌트는 이 파일에 정의된 이벤트 타입을 사용해야 합니다.
|
|
* 이벤트 발행/구독 시 타입 안전성을 보장합니다.
|
|
*/
|
|
|
|
// ============================================================
|
|
// 이벤트 상세 데이터 타입 (event.detail)
|
|
// ============================================================
|
|
|
|
/**
|
|
* 테이블 리스트 데이터 변경 이벤트
|
|
* 발행: v2-table-list
|
|
* 구독: v2-aggregation-widget, v2-repeat-container
|
|
*/
|
|
export interface TableListDataChangeDetail {
|
|
component_id: string;
|
|
table_name: string;
|
|
data: any[];
|
|
selected_rows: string[] | number[];
|
|
}
|
|
|
|
/**
|
|
* 리피터 데이터 변경 이벤트
|
|
* 발행: v2-unified-repeater
|
|
* 구독: v2-aggregation-widget, v2-repeat-container
|
|
*/
|
|
export interface RepeaterDataChangeDetail {
|
|
component_id: string;
|
|
table_name: string;
|
|
data: any[];
|
|
selected_data?: any[];
|
|
}
|
|
|
|
/**
|
|
* 폼 저장 전 이벤트
|
|
* 발행: buttonActions, UnifiedFormContext
|
|
* 구독: v2-unified-repeater, simple-repeater-table, modal-repeater-table 등
|
|
*/
|
|
export interface BeforeFormSaveDetail {
|
|
form_data: Record<string, any>;
|
|
skip_default_save?: boolean;
|
|
}
|
|
|
|
/**
|
|
* 폼 저장 후 이벤트
|
|
* 발행: UnifiedFormContext
|
|
* 구독: 저장 결과 처리 컴포넌트들
|
|
*/
|
|
export interface AfterFormSaveDetail {
|
|
success: boolean;
|
|
data?: any;
|
|
error?: string;
|
|
}
|
|
|
|
/**
|
|
* 리피터 저장 이벤트 (마스터-디테일 FK 연결용)
|
|
* 발행: InteractiveScreenViewerDynamic
|
|
* 구독: v2-unified-repeater
|
|
*/
|
|
export interface RepeaterSaveDetail {
|
|
parent_id?: string | number;
|
|
master_record_id: string | number;
|
|
main_form_data: Record<string, any>;
|
|
table_name: string;
|
|
}
|
|
|
|
/**
|
|
* 테이블 새로고침 이벤트
|
|
* 발행: v2-button-primary, buttonActions
|
|
* 구독: v2-table-list, v2-split-panel-layout
|
|
*/
|
|
export interface RefreshTableDetail {
|
|
table_name?: string;
|
|
component_id?: string;
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 간 데이터 전달 이벤트
|
|
* 발행: buttonActions
|
|
* 구독: v2-unified-repeater
|
|
*/
|
|
export interface ComponentDataTransferDetail {
|
|
source_component_id: string;
|
|
target_component_id: string;
|
|
data: any[];
|
|
mode: "append" | "replace" | "merge";
|
|
mapping_rules?: Array<{
|
|
source_field: string;
|
|
target_field: string;
|
|
default_value?: any;
|
|
}>;
|
|
}
|
|
|
|
/**
|
|
* 분할 패널 간 데이터 전달 이벤트
|
|
* 발행: buttonActions
|
|
* 구독: v2-unified-repeater, repeater-field-group
|
|
*/
|
|
export interface SplitPanelDataTransferDetail {
|
|
source_position: "left" | "right";
|
|
target_position: "left" | "right";
|
|
data: any[];
|
|
mode: "append" | "replace" | "merge";
|
|
mapping_rules?: Array<{
|
|
source_field: string;
|
|
target_field: string;
|
|
default_value?: any;
|
|
}>;
|
|
}
|
|
|
|
/**
|
|
* 연관 데이터 버튼 선택 이벤트
|
|
* 발행: related-data-buttons
|
|
* 구독: v2-table-list
|
|
*/
|
|
export interface RelatedButtonSelectDetail {
|
|
target_table: string;
|
|
filter_column: string;
|
|
filter_value: any;
|
|
selected_data?: any;
|
|
}
|
|
|
|
/**
|
|
* 모달 제어 이벤트
|
|
*/
|
|
export interface EditModalDetail {
|
|
screen_id?: number;
|
|
record_id?: string | number;
|
|
data?: any;
|
|
}
|
|
|
|
// ============================================================
|
|
// 이벤트 이름 상수
|
|
// ============================================================
|
|
|
|
export const V2_EVENTS = {
|
|
// 데이터 변경 이벤트
|
|
TABLE_LIST_DATA_CHANGE: "tableListDataChange",
|
|
REPEATER_DATA_CHANGE: "repeaterDataChange",
|
|
|
|
// 폼 저장 이벤트
|
|
BEFORE_FORM_SAVE: "beforeFormSave",
|
|
AFTER_FORM_SAVE: "afterFormSave",
|
|
REPEATER_SAVE: "repeaterSave",
|
|
|
|
// UI 갱신 이벤트
|
|
REFRESH_TABLE: "refreshTable",
|
|
|
|
// 데이터 전달 이벤트
|
|
COMPONENT_DATA_TRANSFER: "componentDataTransfer",
|
|
SPLIT_PANEL_DATA_TRANSFER: "splitPanelDataTransfer",
|
|
|
|
// 모달 제어 이벤트
|
|
OPEN_EDIT_MODAL: "openEditModal",
|
|
CLOSE_EDIT_MODAL: "closeEditModal",
|
|
SAVE_SUCCESS_IN_MODAL: "saveSuccessInModal",
|
|
|
|
// 연관 데이터 버튼 이벤트
|
|
RELATED_BUTTON_SELECT: "related-button-select",
|
|
RELATED_BUTTON_REGISTER: "related-button-register",
|
|
RELATED_BUTTON_UNREGISTER: "related-button-unregister",
|
|
} as const;
|
|
|
|
// ============================================================
|
|
// Window EventMap 확장 (타입 안전한 이벤트 리스너)
|
|
// ============================================================
|
|
|
|
declare global {
|
|
interface WindowEventMap {
|
|
// 데이터 변경 이벤트
|
|
[V2_EVENTS.TABLE_LIST_DATA_CHANGE]: CustomEvent<TableListDataChangeDetail>;
|
|
[V2_EVENTS.REPEATER_DATA_CHANGE]: CustomEvent<RepeaterDataChangeDetail>;
|
|
|
|
// 폼 저장 이벤트
|
|
[V2_EVENTS.BEFORE_FORM_SAVE]: CustomEvent<BeforeFormSaveDetail>;
|
|
[V2_EVENTS.AFTER_FORM_SAVE]: CustomEvent<AfterFormSaveDetail>;
|
|
[V2_EVENTS.REPEATER_SAVE]: CustomEvent<RepeaterSaveDetail>;
|
|
|
|
// UI 갱신 이벤트
|
|
[V2_EVENTS.REFRESH_TABLE]: CustomEvent<RefreshTableDetail>;
|
|
|
|
// 데이터 전달 이벤트
|
|
[V2_EVENTS.COMPONENT_DATA_TRANSFER]: CustomEvent<ComponentDataTransferDetail>;
|
|
[V2_EVENTS.SPLIT_PANEL_DATA_TRANSFER]: CustomEvent<SplitPanelDataTransferDetail>;
|
|
|
|
// 연관 데이터 버튼 이벤트
|
|
[V2_EVENTS.RELATED_BUTTON_SELECT]: CustomEvent<RelatedButtonSelectDetail>;
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// 유틸리티 함수
|
|
// ============================================================
|
|
|
|
/**
|
|
* 타입 안전한 이벤트 발행 함수
|
|
*/
|
|
export function dispatchV2Event<K extends keyof WindowEventMap>(
|
|
eventName: K,
|
|
detail: WindowEventMap[K] extends CustomEvent<infer D> ? D : never
|
|
): void {
|
|
if (typeof window !== "undefined") {
|
|
window.dispatchEvent(new CustomEvent(eventName, { detail }));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 타입 안전한 이벤트 구독 함수
|
|
*/
|
|
export function subscribeV2Event<K extends keyof WindowEventMap>(
|
|
eventName: K,
|
|
handler: (event: WindowEventMap[K]) => void
|
|
): () => void {
|
|
if (typeof window === "undefined") {
|
|
return () => {};
|
|
}
|
|
|
|
window.addEventListener(eventName, handler as EventListener);
|
|
return () => {
|
|
window.removeEventListener(eventName, handler as EventListener);
|
|
};
|
|
}
|
|
|
|
// ============================================================
|
|
// 내보내기
|
|
// ============================================================
|
|
|
|
export type V2EventName = typeof V2_EVENTS[keyof typeof V2_EVENTS];
|