diff --git a/A00_Common/design/design_shared.ts b/A00_Common/design/design_shared.ts index 773a211eb..2633f98b2 100644 --- a/A00_Common/design/design_shared.ts +++ b/A00_Common/design/design_shared.ts @@ -342,12 +342,14 @@ async function routeChanged(shared: DesignPageShared): Promise { */ export async function saveSharedDesign(shared: DesignPageShared, confirm: boolean): Promise { if (await routeChanged(shared)) return; - // [확정]은 횡단 본문(표준 횡단면 · 전 측점 면적)이 있어야 한다 — 숨긴 채라도 횡단 보기를 세운다. - if (confirm) await shared.ensureView("cross"); + // [저장] · [확정] 본문 = 횡단 보기 한 벌(표준 횡단면 · 전 측점 면적 · 카드 고침) — 들어온 화면 무관 · 숨긴 채라도 + // 세움(B05 만 연 캐시 패치 길 지움 · 386-6) + await shared.ensureView("cross"); const profileSave = shared.bindings.profile?.save; const crossSave = shared.bindings.cross?.save; - if (confirm && !crossSave?.cross) { - showToast(L("B06_Profile_Confirm_Failed"), "error"); + const crossBody = crossSave?.cross; + if (!crossBody) { + showToast(L(confirm ? "B06_Profile_Confirm_Failed" : "B06_Profile_Save_Failed"), "error"); return; } const profile = shared.profile; @@ -371,10 +373,7 @@ export async function saveSharedDesign(shared: DesignPageShared, confirm: boolea ...profileSave?.steps, ...crossSave?.steps, }, - cross: async (isConfirm) => { - if (crossSave?.cross) await crossSave.cross(isConfirm); - else await profileSave?.cross?.(isConfirm); - }, + cross: crossBody, done: async (isConfirm) => { markDesignClean(shared.projectId); // 떠남 확인 — 지금 초안이 저장분(346-4) if (isConfirm) { diff --git a/B05_Profile/B05_Profile_UI_Page_Actions.ts b/B05_Profile/B05_Profile_UI_Page_Actions.ts index d4b27c095..add7a35ff 100644 --- a/B05_Profile/B05_Profile_UI_Page_Actions.ts +++ b/B05_Profile/B05_Profile_UI_Page_Actions.ts @@ -9,10 +9,7 @@ import { confirmRoute, type RouteLatestResponse } from "./B05_Profile_Api_Fetch"; import type { DesignViewSave } from "../A00_Common/design/design_shared"; -import { - invalidateSectionDetail, - saveCachedCrossPatches, -} from "../B06_Section/B06_Section_Section_Store"; +import { invalidateSectionDetail } from "../B06_Section/B06_Section_Section_Store"; import type { createRoutePanel } from "./B05_Profile_UI_Panel"; import type { createRouteProfilePanel } from "./B05_Profile_UI_Profile_Panel"; import type { createStructuresBridge } from "./B05_Profile_UI_Page_Structures"; @@ -75,13 +72,7 @@ export function profileSaveParts(ctx: PageActionContext): DesignViewSave { ); }, }, - // 횡단 보기를 세운 적 없이 [저장]하면 — 캐시에 얹힌 횡단 수정분을 함께 남긴다. 안 보내면 - // 바로 아래 캐시 비우기에서 사라진다. 계획선 저장 **뒤에** 보내야 사용자 수정 1세트가 - // 최종본으로 얹힌다(2026-08-24 사용자 지적). 횡단 보기가 서 있으면 그쪽 본문이 나간다. - cross: async () => { - const routeId = ctx.latest()?.route?.id; - if (routeId != null) await saveCachedCrossPatches(projectId, routeId); - }, + // 횡단 본문은 늘 횡단 보기 몫 — [저장]이 숨긴 채라도 세움(386-6 · 옛 캐시 패치 길 지움) done: async () => { // 서버가 종단 정본의 계획선을 다시 썼다 — 공유 캐시를 비워 횡단 보기가 옛 계획선을 못 보게 한다. invalidateSectionDetail(projectId); diff --git a/resources/tester/test_384_6_save_one_line.py b/resources/tester/test_384_6_save_one_line.py new file mode 100644 index 000000000..f06f3140b --- /dev/null +++ b/resources/tester/test_384_6_save_one_line.py @@ -0,0 +1,46 @@ +"""PLAN 386-6 sub7 — [저장] 본문 보기 무관(B05 만 연 길 지움). + +못박는 것 + - [저장] · [확정] 둘 다 횡단 보기를 (숨긴 채라도) 세움 → 횡단 본문 = 횡단 보기 몫 한 벌(`crossSaveParts`). + - 종단 보기 몫엔 횡단 본문이 없음 — 옛 「횡단 보기를 세운 적 없이 [저장]」 캐시 패치 길(saveCachedCrossPatches) 지움. + - 횡단 보기를 못 세우면 반쪽 저장 대신 실패 알림. +화면(B05 만 연 [저장] 본문 = B06 다녀온 본문)은 PLAN 386-6 검증 줄. +""" + +from __future__ import annotations + +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] + + +def _read(rel: str) -> str: + return (ROOT / rel).read_text(encoding="utf-8") + + +def _save_body() -> str: + shared = _read("A00_Common/design/design_shared.ts") + start = shared.index("export async function saveSharedDesign") + return shared[start : shared.index("\n}\n", start)] + + +def test_저장도_횡단_보기를_세움(): + body = _save_body() + assert 'await shared.ensureView("cross");' in body + assert 'if (confirm) await shared.ensureView("cross")' not in body + assert "cross: crossBody," in body + assert "profileSave?.cross" not in body + + +def test_못_세우면_실패_알림(): + body = _save_body() + assert "if (!crossBody) {" in body + assert '"B06_Profile_Save_Failed"' in body and '"B06_Profile_Confirm_Failed"' in body + + +def test_종단_보기_몫엔_횡단_본문_없음(): + actions = _read("B05_Profile/B05_Profile_UI_Page_Actions.ts") + start = actions.index("export function profileSaveParts(") + parts = actions[start:] + assert "saveCachedCrossPatches" not in actions + assert "\n cross: " not in parts