Merge remote-tracking branch 'origin/sub_laptop_2' into main_laptop_1
This commit is contained in:
@@ -3,12 +3,12 @@
|
||||
* 계산 묶음 관 · 구조물 · 추가 측점 먹이기(PLAN 415 · 429 ⑨) — 가게 초안이 바뀌면 묶음에 넣음(비면 저장분).
|
||||
* · [저장] 도중 = 안 넣음(H2) — 초안이 비는 사이 열 때 읽은 옛 저장분으로 돌지 않게 · 끝나면 `resync`
|
||||
* (저장 목록 다시 읽기 · 입력 맞춤) 한 번.
|
||||
* · 되돌리기 · 다시하기 = 세션만 되쓰고 가게 알림이 없음 → 묶음 입력과 견줘 다르면 넣음(415-2 · 노선 초안은
|
||||
* 노선 길이 맡음).
|
||||
* · 되돌리기 · 다시하기 = 아래 되살림 훅 한 길 — 묶음 입력과 견줘 다르면 넣음(415-2 · 노선 초안은 노선 길이
|
||||
* 맡음) · 그 사이 가게 알림(`announceDesignStore` · 472-5)은 구독이 받지 않음(두 번 안 넣음).
|
||||
* 저장 창구는 늦게 불러옴(묶음 시험이 화면 모듈을 안 끌게).
|
||||
* ========================================================================== */
|
||||
|
||||
import { onPageHistory } from "../../B05_Profile/B05_Profile_UI_Profile_History";
|
||||
import { onPageHistory, pageReplaying } from "../../B05_Profile/B05_Profile_UI_Profile_History";
|
||||
import type { useDesignStore } from "./design_store";
|
||||
import type { ChangeSource } from "./logic/design_pipeline_types";
|
||||
|
||||
@@ -57,7 +57,13 @@ export function feedFacilities(o: {
|
||||
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))),
|
||||
o.store.subscribe(key, (value) => {
|
||||
const now = value ?? o.saved(key);
|
||||
// 묶음 입력과 같은 값 = 이미 받음(되살림 뒤 추가 측점 다시 알림 등) — 한 번만 넣음(472-5)
|
||||
if (!o.ready() || pageReplaying() || JSON.stringify(now) === JSON.stringify(o.input(key)))
|
||||
return;
|
||||
put(source, now);
|
||||
}),
|
||||
),
|
||||
onPageHistory({
|
||||
restore: () => {
|
||||
|
||||
@@ -241,11 +241,12 @@ const listeners = new Map<string, Set<(value: unknown) => void>>();
|
||||
* 노선을 모르면 `routeId = null` — 노선 칸(`alignmentDraft` · `sectionDetail`)은 비어 보이고
|
||||
* 쓰기는 버려진다. 프로젝트를 모르면 프로젝트 칸이 그렇다.
|
||||
*/
|
||||
/** 가게를 안 거친 세션 되씀(되돌리기 · 다시하기) 뒤 — 프로젝트 목록 칸을 듣는 쪽을 지금 값으로 부름
|
||||
* (472-5 · 관 · 구조물 사본이 옛 값으로 남아 다음 조작이 되돌림을 덮던 흠). */
|
||||
/** 가게를 안 거친 세션 되씀(되돌리기 · 다시하기) 뒤 — 관 · 구조물 칸 듣는 쪽을 지금 값으로 한 번 부름
|
||||
* (472-5 · 사본이 옛 값으로 남아 다음 조작이 되돌림을 덮던 흠). 추가 측점 · 페이지 설정은 자기 되살림 훅이
|
||||
* 알림(`_Api_PlusStations` · `_Api_PageSettings`) · 계산 묶음은 되살림 훅 한 길(구독은 되돌리는 동안 안 받음). */
|
||||
export function announceDesignStore(projectId: string): void {
|
||||
const store = useDesignStore(projectId, null);
|
||||
(["structures", "pipes", "plusStations"] as const).forEach((key) => {
|
||||
(["structures", "pipes"] as const).forEach((key) => {
|
||||
const id = slotOf(key, projectId, null).id;
|
||||
const value = store.get(key);
|
||||
if (id) listeners.get(`${key}|${id}`)?.forEach((fn) => fn(value));
|
||||
|
||||
@@ -573,8 +573,16 @@ export function createStructuresSection(
|
||||
},
|
||||
getStructures: () => [...structures],
|
||||
setPipeFacilities(pipes) {
|
||||
const before = pipeFacilities;
|
||||
pipeFacilities = pipes.map((pipe) => ({ ...pipe }));
|
||||
followPipeList(panelContext, pipeFacilities);
|
||||
// 열린 관 폼 — 값이 밖에서 바뀌면(되돌리기 · 다른 보기) 새 값으로 다시 엶 · 고치던 실시간 반영 · 임시 배치는
|
||||
// 둠(472-5 · 옛 칸 값이 다음 조작에 되쓰이던 흠)
|
||||
const at = selectedPipeChainage;
|
||||
if (at === null || applyingLive || tempPipeChainage !== null) return;
|
||||
const near = (pipe: PipeFacilityItem) => Math.abs(pipe.chainage_m - at) < PIPE_MATCH_M;
|
||||
const now = pipeFacilities.find(near);
|
||||
if (now && JSON.stringify(now) !== JSON.stringify(before.find(near))) loadPipeForm(now);
|
||||
},
|
||||
selectPipeByChainage(chainageM) {
|
||||
if (chainageM !== null) callbacks.onReveal?.();
|
||||
|
||||
@@ -105,6 +105,7 @@ async function run() {
|
||||
const feeder = loader({
|
||||
"../../B05_Profile/B05_Profile_UI_Profile_History": {
|
||||
onPageHistory: (hooks) => ((restore = hooks.restore), () => undefined),
|
||||
pageReplaying: () => false, // 묶음 먹이기가 되돌리는 동안 구독을 거름(472-5)
|
||||
},
|
||||
"./design_save": { savingDesign: () => false },
|
||||
})(path.join(DESIGN, "design_pipeline_facilities.ts"));
|
||||
@@ -116,7 +117,11 @@ async function run() {
|
||||
saved: (key) => (key === "plusStations" ? [12] : []),
|
||||
input: (key) => inputNow[key] ?? null,
|
||||
routed: () => false,
|
||||
feed: (source, value) => fed.push([source, value]),
|
||||
// 묶음처럼 받은 값이 입력이 됨 — 같은 값 다시 알림은 안 넣음(472-5)
|
||||
feed: (source, value) => {
|
||||
fed.push([source, value]);
|
||||
if (source === "plus") inputNow.plusStations = value;
|
||||
},
|
||||
resync: async () => undefined,
|
||||
});
|
||||
fakeStore.set("plusStations", [12, 30]);
|
||||
|
||||
@@ -43,19 +43,49 @@ const pipes2 = [
|
||||
];
|
||||
store.set("structures", A);
|
||||
store.set("pipes", pipes1);
|
||||
m.writePlusDraft(P, [60]);
|
||||
const history = m.createProfileHistory(() => undefined, 100);
|
||||
store.set("structures", AB);
|
||||
store.set("pipes", pipes2);
|
||||
m.writePlusDraft(P, [60, 80]);
|
||||
history.record();
|
||||
const heard = { structures: [], pipes: [] };
|
||||
const heard = { structures: [], pipes: [], plusStations: [] };
|
||||
store.subscribe("structures", (v) => heard.structures.push(v));
|
||||
store.subscribe("pipes", (v) => heard.pipes.push(v));
|
||||
store.subscribe("plusStations", (v) => heard.plusStations.push(v));
|
||||
// 계산 묶음 먹이기 — 되돌리기 한 번에 출처마다 한 번만(되살림 훅 한 길 · 472-5 겹침 정리)
|
||||
const fed = [];
|
||||
const input = { pipes: pipes2, structures: AB, plusStations: [60, 80] };
|
||||
const keyOf = { pipe: "pipes", structure: "structures", plus: "plusStations" };
|
||||
m.feedFacilities({
|
||||
projectId: P,
|
||||
store,
|
||||
ready: () => true,
|
||||
gone: () => false,
|
||||
saved: () => null,
|
||||
input: (key) => input[key],
|
||||
routed: () => false,
|
||||
feed: (source, value) => {
|
||||
fed.push(source);
|
||||
input[keyOf[source]] = value;
|
||||
},
|
||||
resync: async () => undefined,
|
||||
});
|
||||
const tick = () => new Promise((done) => setTimeout(done, 5));
|
||||
history.undo();
|
||||
await tick();
|
||||
const afterUndo = {
|
||||
structures: heard.structures.at(-1) ?? null,
|
||||
pipes: heard.pipes.at(-1) ?? null,
|
||||
};
|
||||
const counts = {
|
||||
structures: heard.structures.length,
|
||||
pipes: heard.pipes.length,
|
||||
plusStations: heard.plusStations.length,
|
||||
fed: [...fed].sort(),
|
||||
};
|
||||
history.redo();
|
||||
await tick();
|
||||
const afterRedo = {
|
||||
structures: heard.structures.at(-1) ?? null,
|
||||
pipes: heard.pipes.at(-1) ?? null,
|
||||
@@ -85,6 +115,7 @@ console.log(
|
||||
JSON.stringify({
|
||||
afterUndo,
|
||||
afterRedo,
|
||||
counts,
|
||||
echo,
|
||||
adopted,
|
||||
picked,
|
||||
|
||||
@@ -4,3 +4,5 @@ export { pinDraftProject, useDesignStore } from "../../A00_Common/design/design_
|
||||
export { adoptEditorPipes } from "../../B05_Profile/B05_Profile_UI_Drainage_Parts";
|
||||
export { createPipeEditor } from "../../B05_Profile/B05_Profile_UI_Drainage_Pipes";
|
||||
export { createFacilityStore } from "../../B05_Profile/B05_Profile_UI_Drainage_Facility";
|
||||
export { feedFacilities } from "../../A00_Common/design/design_pipeline_facilities";
|
||||
export { writePlusDraft } from "../../B05_Profile/B05_Profile_Api_PlusStations";
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"""PLAN 472-5 5-A (요구 273) — 관 · 구조물 값 주인 하나(설계 가게) · 사본 갈림 막음.
|
||||
|
||||
못박는 것
|
||||
- 되돌리기 · 다시하기(세션 직접 되씀)가 가게 듣는 쪽을 되돌린 값으로 부름 — 옛 코드는 안 불러
|
||||
종단 목록 · 횡단 판 · 배수 편집기가 옛 값을 쥐고 다음 조작이 되돌림을 덮었음(옛 코드 실패).
|
||||
- 되돌리기 · 다시하기(세션 직접 되씀)가 가게 듣는 쪽을 되돌린 값으로 한 번씩 부름(5-C 훅 · 묶음과
|
||||
안 겹침) — 옛 코드는 안 불러 종단 목록 · 횡단 판 · 배수 편집기가 옛 값을 쥐고 다음 조작이
|
||||
되돌림을 덮었음(옛 코드 실패).
|
||||
- 배수 편집기 받기 — 제 쓰기 메아리는 안 받음 · 남이 고친 옵션 · 차례도 받음 · 고른 관(id) 유지.
|
||||
- 배선 — 종단 보기 = 관(숨어도) · 구조물(보일 때) 구독 · 횡단 보기 = 남 고침(옵션만도) 다시 실음 ·
|
||||
횡단 판은 쓰기 전에 제 값을 적음(메아리 가름).
|
||||
@@ -75,6 +76,16 @@ def test_되돌리기가_가게_듣는_쪽을_부름(out) -> None:
|
||||
assert out["afterRedo"]["pipes"][0]["options"] == {"diameter_mm": 1000}
|
||||
|
||||
|
||||
def test_되돌리기_알림은_한_번씩(out) -> None:
|
||||
"""겹침 정리 — 관 · 구조물 = 가게 알림 한 번 · 추가 측점 = 자기 훅 · 묶음 = 출처마다 한 번."""
|
||||
assert out["counts"] == {
|
||||
"structures": 1,
|
||||
"pipes": 1,
|
||||
"plusStations": 1,
|
||||
"fed": ["pipe", "plus", "structure"],
|
||||
}
|
||||
|
||||
|
||||
def test_배수_편집기_남_고침만_받음(out) -> None:
|
||||
assert out["echo"] is False
|
||||
assert out["adopted"] is True
|
||||
@@ -105,5 +116,9 @@ def test_배선() -> None:
|
||||
assert panel.index("seen.structures = JSON.stringify(structures);") < panel.index(
|
||||
"writePendingStructures(deps.projectId, structures);"
|
||||
)
|
||||
# 열린 관 폼 — 밖에서 바뀐 값(되돌리기 · 다른 보기)으로 다시 엶(옛 칸 값 되쓰던 흠)
|
||||
form = _read("B05_Profile", "B05_Profile_UI_Structures_Panel.ts")
|
||||
assert "if (at === null || applyingLive || tempPipeChainage !== null) return;" in form
|
||||
assert "JSON.stringify(now) !== JSON.stringify(before.find(near))) loadPipeForm(now);" in form
|
||||
history = _read("B05_Profile", "B05_Profile_UI_Profile_History.ts")
|
||||
assert "announceDesignStore(projectId);" in history
|
||||
|
||||
Reference in New Issue
Block a user