- 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
76 lines
3.6 KiB
TypeScript
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);
|
|
}
|