- ④ 노선 저장 뒤 횡단 저장 = 고침 없어도 한 번(뒤에 나간 계획고 초안이 횡단 설계 높이에 실림) - ⑤ 상단측 다시 셈 = 깎기 경사 · 소단을 기하 입력으로 · 사용자 조작값 목록째 승계 · 측구 끔(None) 저장분 셈 - ⑨ 추가 측점 = 묶음 입력 plusStations(stations 부터) · 가게 초안 · 되돌리기 → 묶음 - ⑨ [저장] 차례 실패 = 그 차례에서 멈춤 · 차례 이름째 알림(뒤 차례 안 보냄) - 시험 test_429_save_path · test_design_store_save 멈춤 규칙으로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
74 lines
3.3 KiB
TypeScript
74 lines
3.3 KiB
TypeScript
/* =============================================================================
|
|
* A00_Common/design/design_pipeline_facilities.ts
|
|
* 계산 묶음 관 · 구조물 · 추가 측점 먹이기(PLAN 415 · 429 ⑨) — 가게 초안이 바뀌면 묶음에 넣음(비면 저장분).
|
|
* · [저장] 도중 = 안 넣음(H2) — 초안이 비는 사이 열 때 읽은 옛 저장분으로 돌지 않게 · 끝나면 `resync`
|
|
* (저장 목록 다시 읽기 · 입력 맞춤) 한 번.
|
|
* · 되돌리기 · 다시하기 = 세션만 되쓰고 가게 알림이 없음 → 묶음 입력과 견줘 다르면 넣음(415-2 · 노선 초안은
|
|
* 노선 길이 맡음).
|
|
* 저장 창구는 늦게 불러옴(묶음 시험이 화면 모듈을 안 끌게).
|
|
* ========================================================================== */
|
|
|
|
import { onPageHistory } from "../../B05_Profile/B05_Profile_UI_Profile_History";
|
|
import type { useDesignStore } from "./design_store";
|
|
import type { ChangeSource } from "./logic/design_pipeline_types";
|
|
|
|
type Key = "pipes" | "structures" | "plusStations";
|
|
const FACILITIES: ReadonlyArray<{ source: ChangeSource; key: Key }> = [
|
|
{ source: "pipe", key: "pipes" },
|
|
{ source: "structure", key: "structures" },
|
|
{ source: "plus", key: "plusStations" },
|
|
];
|
|
|
|
export interface FacilityFeed {
|
|
saving(): boolean;
|
|
/** 저장이 끝나면 `resync` 한 번 — 기다리는 동안 다시 불러도 한 번. */
|
|
afterSave(): void;
|
|
stop(): void;
|
|
}
|
|
|
|
export function feedFacilities(o: {
|
|
projectId: string;
|
|
store: ReturnType<typeof useDesignStore>;
|
|
/** 묶음이 받을 때인가(열었음 · 묶음이 가게에 쓰는 메아리 아님). */
|
|
ready: () => boolean;
|
|
gone: () => boolean;
|
|
saved: (key: Key) => unknown;
|
|
input: (key: Key) => unknown;
|
|
/** 노선 초안이 걸렸나 — 되돌리기는 노선 길이 맡음. */
|
|
routed: () => boolean;
|
|
feed: (source: ChangeSource, value: unknown) => void;
|
|
resync: () => Promise<unknown>;
|
|
}): FacilityFeed {
|
|
let savingOf: ((id: string) => boolean) | null = null;
|
|
// 한 번 불러 봄 — 덜 선 모듈(시험 싣개의 고리)은 안 받음
|
|
void import("./design_save")
|
|
.then((m) => (m.savingDesign(o.projectId), (savingOf = m.savingDesign)))
|
|
.catch(() => undefined);
|
|
const saving = (): boolean => savingOf?.(o.projectId) ?? false;
|
|
let waiting: Promise<void> | null = null;
|
|
const afterSave = (): void => {
|
|
waiting ??= (async () => {
|
|
// ponytail: 100 ms 마다 물음 — 저장 끝 알림이 생기면 그것으로
|
|
while (saving() && !o.gone()) await new Promise((done) => setTimeout(done, 100));
|
|
if (!o.gone()) await o.resync();
|
|
})().finally(() => (waiting = null));
|
|
};
|
|
const put = (source: ChangeSource, value: unknown): void =>
|
|
saving() ? afterSave() : o.feed(source, value);
|
|
const stops = [
|
|
...FACILITIES.map(({ source, key }) =>
|
|
o.store.subscribe(key, (value) => o.ready() && put(source, value ?? o.saved(key))),
|
|
),
|
|
onPageHistory({
|
|
restore: () => {
|
|
if (!o.ready() || o.routed()) return;
|
|
for (const { source, key } of FACILITIES) {
|
|
const now = o.store.get(key) ?? o.saved(key);
|
|
if (JSON.stringify(now) !== JSON.stringify(o.input(key))) put(source, now);
|
|
}
|
|
},
|
|
}),
|
|
];
|
|
return { saving, afterSave, stop: () => stops.forEach((stop) => stop()) };
|
|
}
|