185 lines
5.4 KiB
TypeScript
185 lines
5.4 KiB
TypeScript
/**
|
|
* 테이블 화면 표시 데이터 전역 저장소
|
|
* 엑셀 다운로드 등에서 현재 화면에 표시된 데이터에 접근하기 위함
|
|
*
|
|
* 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<string, any>; // 필터 조건
|
|
search_term?: string; // 검색어
|
|
visible_columns?: string[]; // 화면 표시 컬럼
|
|
column_labels?: Record<string, string>; // 컬럼 라벨
|
|
current_page?: number; // 현재 페이지
|
|
page_size?: number; // 페이지 크기
|
|
total_items?: number; // 전체 항목 수
|
|
}
|
|
|
|
class TableDisplayStore {
|
|
private state: Map<string, TableDisplayState> = 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<string, any>;
|
|
search_term?: string;
|
|
visible_columns?: string[];
|
|
column_labels?: Record<string, string>;
|
|
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<string, TableDisplayState> {
|
|
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<string, any>;
|
|
search_term?: string;
|
|
visible_columns?: string[];
|
|
column_labels?: Record<string, string>;
|
|
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();
|