Files
Aislo/A00_Common/design/design_page_data.ts
T
eomsangdonandClaude Opus 5.5 80cfc187c6 feat(B05·B06 한 페이지): 페이지 자료 줄 · 묶음 입력 = 가게만 (386-2 · 386-3)
- design_page_data 새로 — 저장분(구조물 · 관 · 정의 판 확인) 페이지에서 한 번 · 저장 정본 바뀜(invalidate) · 페이지 떠남에 비움 · 보기 전환 요청 0
- 묶음 · 두 보기 구조물 칸 · 초안 측점이 같은 줄 · 「계산 중」 점(도크 · 묶음 차례 동안)
- 묶음 planline 저장 기준 = 입력(관 · 구조물)이 심는 측점(design_pipeline_base · 페이지가 옵션으로) · baseMoved 지움 · 종류 한 벌
- design_pipeline_page 700줄 앞 쪼갬(design_pipeline_page_types)
- 시험 test_384_2 · test_384_3 · 엄격 흉내 helper 에 자료 줄 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
2026-10-17 18:08:17 +09:00

76 lines
3.6 KiB
TypeScript

/* =============================================================================
* A00_Common/design/design_page_data.ts
* B05 · B06 한 페이지 자료 줄(PLAN 386-2) — 저장분(구조물 · 관 · 정의 판 확인)을 페이지에서 한 번만 받음.
*
* 받는 쪽 = 묶음(`design_pipeline_page`) · 종단 보기 구조물 칸 · 횡단 보기 구조물 칸 · 초안 측점
* (`B06_Section_Section_Drafts`) · [저장] 관 얹기(`design_save`) — 보기 전환 · 다시 보임 = 요청 0.
* 다시 받기 = 저장 정본이 바뀐 뒤 한 번 — `invalidateSectionDetail` → `forgetDraftStations` → 여기 비움
* ([저장] · [확정] · [초기화] · 노선 [적용] · 파일 다시 올림) · 페이지를 떠나면 비움.
* 종류 목록은 `fetchStructureTypes` 가 탭 수명 동안 쥠 — 정의 판 확인만 페이지마다 한 번.
* 돌려줄 때마다 사본 — 받는 쪽이 고쳐도 다른 쪽 저장분이 안 바뀜.
* 「계산 중」 — 묶음 차례가 떠 있는 동안 좌측 아래 점(`onPageBusy`).
* ========================================================================== */
import { fetchDetailPipePoints } from "../../B04_PreProcess/B04_PreProcess_Api_Fetch";
import {
dropStaleStructureTypes,
fetchStructures,
} from "../../B05_Profile/B05_Profile_Api_Structures";
const memo = new Map<string, Promise<unknown>>();
function once<T>(key: string, load: () => Promise<T>): Promise<T> {
let hit = memo.get(key) as Promise<T> | undefined;
if (!hit) {
hit = load();
memo.set(key, hit);
hit.catch(() => memo.get(key) === hit && memo.delete(key)); // 실패는 다음에 다시 물음
}
return hit.then((value) => structuredClone(value));
}
/** 저장 구조물(structures.json · 판번호 · 정의 판). */
export const pageStructures = (projectId: string): ReturnType<typeof fetchStructures> =>
once(`structures:${projectId}`, () => fetchStructures(projectId));
/** 저장 관(pipe_points.json · 유역). */
export const pagePipes = (projectId: string): ReturnType<typeof fetchDetailPipePoints> =>
once(`pipes:${projectId}`, () => fetchDetailPipePoints(projectId));
/** 정의 판이 바뀌었으면 종류 캐시 버림 — 페이지마다 한 번(탭이 다시 보일 때는 `onStaleStructureTypes`). */
export const pageTypesChecked = (projectId: string): Promise<boolean> =>
once(`types:${projectId}`, () => dropStaleStructureTypes());
/** 저장 정본이 바뀜 · 페이지를 떠남 — 다음에 부르면 한 번 다시 받음. */
export function forgetPageData(projectId: string): void {
for (const key of [...memo.keys()]) if (key.endsWith(`:${projectId}`)) memo.delete(key);
}
const busy = new Map<string, number>();
const busyListeners = new Map<string, Set<(busy: boolean) => void>>();
const notify = (projectId: string): void => {
const now = (busy.get(projectId) ?? 0) > 0;
busyListeners.get(projectId)?.forEach((fn) => fn(now));
};
/** 묶음 차례 하나가 뜸 — 끝나면(밀림 · 실패 포함) 내림. */
export function trackPageBusy(projectId: string, run: Promise<unknown> | null): void {
if (!run) return;
busy.set(projectId, (busy.get(projectId) ?? 0) + 1);
notify(projectId);
const done = (): void => {
busy.set(projectId, Math.max(0, (busy.get(projectId) ?? 1) - 1));
notify(projectId);
};
run.then(done, done);
}
/** 「계산 중」 켬 · 끔 듣기 — 떼는 함수를 돌려줌. */
export function onPageBusy(projectId: string, fn: (busy: boolean) => void): () => void {
const set = busyListeners.get(projectId) ?? new Set();
busyListeners.set(projectId, set.add(fn));
fn((busy.get(projectId) ?? 0) > 0);
return () => set.delete(fn);
}