/** * 테이블 화면 표시 데이터 전역 저장소 * 엑셀 다운로드 등에서 현재 화면에 표시된 데이터에 접근하기 위함 * * Key 컨벤션 (Phase B.4 2026-05-20, F.5 docstring 갱신): * - canonical `lib/registry/components/table/TableComponent` : `table-${component.id}` prefix * (`setTableDataForComponent` / `getTableDataForComponent` helper 사용) * - 외부 데이터가 옛 prefix (`table-list-${component.id}`) 로 들어오는 fallback 경로도 유지. * (옛 본체는 Phase F.2/F.8 에서 삭제됐지만 historical key 가 store 에 들어올 수 있는 * 경로를 위해 read 측만 fallback 으로 살려둔다.) * - 외부 consumer (Excel/Copy/Toolbar) 가 component.id 만 알 때는 * `getTableDataForComponent(componentId)` 가 canonical 우선 + historical fallback 으로 안전 조회. */ interface TableDisplayState { data: any[]; column_order: string[]; sort_by: string | null; sort_order: "asc" | "desc"; table_name: string; // 🆕 엑셀 다운로드 개선을 위한 추가 필드 filter_conditions?: Record; // 필터 조건 search_term?: string; // 검색어 visible_columns?: string[]; // 화면 표시 컬럼 column_labels?: Record; // 컬럼 라벨 current_page?: number; // 현재 페이지 page_size?: number; // 페이지 크기 total_items?: number; // 전체 항목 수 } class TableDisplayStore { private state: Map = new Map(); private listeners: Set<() => void> = new Set(); /** canonical TableComponent 가 쓰는 키 (`table-${componentId}`) */ private static canonicalKeyForComponent(componentId: string): string { return `table-${componentId}`; } /** historical fallback 키 — 옛 본체가 직접 set 하던 prefix. 본체는 Phase F.2/F.8 에서 삭제됨. */ private static legacyKeyForComponent(componentId: string): string { return `table-list-${componentId}`; } /** * 테이블 표시 데이터 저장 * @param tableName 테이블명 * @param data 화면에 표시된 데이터 * @param columnOrder 컬럼 순서 * @param sortBy 정렬 컬럼 * @param sortOrder 정렬 방향 * @param options 추가 옵션 (필터, 페이징 등) */ setTableData( tableName: string, data: any[], columnOrder: string[], sortBy: string | null, sortOrder: "asc" | "desc", options?: { filter_conditions?: Record; search_term?: string; visible_columns?: string[]; column_labels?: Record; current_page?: number; page_size?: number; total_items?: number; } ) { this.state.set(tableName, { data, column_order: columnOrder, sort_by: sortBy, sort_order: sortOrder, table_name: tableName, ...options, }); this.notifyListeners(); } /** * 테이블 표시 데이터 조회 * @param tableName 테이블명 */ getTableData(tableName: string): TableDisplayState | undefined { return this.state.get(tableName); } /** * 모든 테이블 데이터 조회 */ getAllTableData(): Map { return new Map(this.state); } /** * 테이블 데이터 삭제 * @param tableName 테이블명 */ clearTableData(tableName: string) { this.state.delete(tableName); this.notifyListeners(); } /** * canonical TableComponent 용 set — component.id 기반 자동 key (Phase B.4) */ setTableDataForComponent( componentId: string, data: any[], columnOrder: string[], sortBy: string | null, sortOrder: "asc" | "desc", options?: { filter_conditions?: Record; search_term?: string; visible_columns?: string[]; column_labels?: Record; current_page?: number; page_size?: number; total_items?: number; }, ) { this.setTableData( TableDisplayStore.canonicalKeyForComponent(componentId), data, columnOrder, sortBy, sortOrder, options, ); } /** * component.id 기반 조회 — canonical 우선 + historical fallback (Phase B.4) * 외부 consumer (Excel export, copy, toolbar) 는 prefix 를 몰라도 component.id 만으로 안전 조회. */ getTableDataForComponent(componentId: string): TableDisplayState | undefined { return ( this.state.get(TableDisplayStore.canonicalKeyForComponent(componentId)) ?? this.state.get(TableDisplayStore.legacyKeyForComponent(componentId)) ); } /** * component.id 기반 삭제 — canonical + historical fallback 둘 다 제거 (Phase B.4) */ clearTableDataForComponent(componentId: string) { const canonical = TableDisplayStore.canonicalKeyForComponent(componentId); const legacy = TableDisplayStore.legacyKeyForComponent(componentId); const hadCanonical = this.state.delete(canonical); const hadLegacy = this.state.delete(legacy); if (hadCanonical || hadLegacy) { this.notifyListeners(); } } /** * 모든 데이터 삭제 */ clearAll() { this.state.clear(); this.notifyListeners(); } /** * 변경 리스너 등록 */ subscribe(listener: () => void) { this.listeners.add(listener); return () => { this.listeners.delete(listener); }; } private notifyListeners() { this.listeners.forEach((listener) => listener()); } } // 싱글톤 인스턴스 export const tableDisplayStore = new TableDisplayStore();