From d5360194c9374996887841234e2b74e7c0056883 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 16 Oct 2026 12:34:13 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(=EB=85=B8=EC=84=A0=EC=B6=94=EC=B2=9C):?= =?UTF-8?q?=20346-3=20=EB=8D=A7=20=EB=82=A8=EC=9D=80=20=E3=80=8C[=EB=85=B8?= =?UTF-8?q?=EC=84=A0=20=EB=B0=98=EC=98=81]=E3=80=8D=20=EA=B8=80=EC=9E=90?= =?UTF-8?q?=20=E2=80=94=20[=EC=B4=88=EA=B8=B0=ED=99=94]=20=ED=92=8D?= =?UTF-8?q?=EC=84=A0=20=3D=20=EB=8B=A4=EC=8B=9C=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=EC=9D=80=20[=EC=A0=80=EC=9E=A5]=EC=97=90=EC=84=9C=20=C2=B7=20[?= =?UTF-8?q?=EB=85=B8=EC=84=A0=20=EC=B6=94=EC=B2=9C]=20=ED=92=8D=EC=84=A0?= =?UTF-8?q?=20=3D=20[=EC=A0=81=EC=9A=A9]=EC=9D=80=20=EB=B0=94=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=C2=B7=20=EC=83=88=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=EA=B0=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주석 글자도 지금 흐름으로([저장] · [저장 전으로]) — RouteEdit · _History · _Draft · design_view_profile - 남김: design_profile · design_pipeline_page 주석(sub7 일하는 중) · 「없앰」을 적은 주석 · 서버 옛 칸 설명 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn --- A00_Common/design/design_view_profile.ts | 6 +++--- B05_Profile/B05_Profile_UI_Panel_Recommend.ts | 4 ++-- B05_Profile/B05_Profile_UI_RouteEdit.ts | 6 +++--- B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts | 4 ++-- B05_Profile/B05_Profile_UI_RouteEdit_History.ts | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/A00_Common/design/design_view_profile.ts b/A00_Common/design/design_view_profile.ts index 61525c4bf..8c0328ca4 100644 --- a/A00_Common/design/design_view_profile.ts +++ b/A00_Common/design/design_view_profile.ts @@ -410,9 +410,9 @@ export async function mountProfileView( }, }); - /** [노선 반영] 끝 — 서버가 배수유역부터 다시 셌고 그 결과가 새 초기값이다. 새로고침 대신 페이지를 + /** 노선 저장([저장] · 추천 [적용]) 끝 — 서버가 배수유역부터 다시 셌고 그 결과가 새 초기값이다. 새로고침 대신 페이지를 * 통째로 다시 세운다(345-3) — 제자리 고침은 옛 노선 관 목록 등 메모리 · 진행 중 요청이 살아남아 - * [저장]에 실렸다(PLAN 77). 초안 · 결과 칸은 [노선 반영]이 비웠고 옛 노선 캐시는 여기서 비운다 · + * [저장]에 실렸다(PLAN 77). 초안 · 결과 칸은 노선 저장이 비웠고 옛 노선 캐시는 여기서 비운다 · * 떠나는 페이지의 늦은 응답은 `host.disposed()` 로 버려진다. */ const rebuildAfterReplan = (): void => { clearRouteLatestCache(activeProjectId); @@ -488,7 +488,7 @@ export async function mountProfileView( smooth: latestResponse.surface_params.smooth, tools: [view3d.modal.button], recommend: panel.recommend, - // 계산 묶음(346-1) — 노선을 고칠 때마다 종단이 따라옴(미리보기 · [노선 반영]이 정본). + // 계산 묶음(346-1) — 노선을 고칠 때마다 종단이 따라옴(미리보기 · [저장]이 정본). draft: routeDraftBridge(activeProjectId, profilePanel, { stationIntervalM: panel.values().stationInterval ?? undefined, }), diff --git a/B05_Profile/B05_Profile_UI_Panel_Recommend.ts b/B05_Profile/B05_Profile_UI_Panel_Recommend.ts index 3fa0ed2ae..7c9590928 100644 --- a/B05_Profile/B05_Profile_UI_Panel_Recommend.ts +++ b/B05_Profile/B05_Profile_UI_Panel_Recommend.ts @@ -20,9 +20,9 @@ export function createRecommendPart(): RecommendPart { actions.className = "b05-route__rec-actions"; actions.innerHTML = ` + title="예상노선 추적 · 영선 · 토공 최소 · 기울기 최소 · 비중 계산 중 하나로 노선을 추천받아 미리 봅니다 — [적용]은 바로 저장 · 새 초기값">노선 추천 `; + title="초기값 노선(전처리 · 추천 [적용] 때 정한 것)으로 되돌립니다 — 다시 계산은 [저장]에서">초기화`; const recommendButton = actions.querySelector('[data-act="recommend"]')!; const resetButton = actions.querySelector('[data-act="reset"]')!; return { recommendButton, resetButton, nowLine, nodes: [nowLine, actions] }; diff --git a/B05_Profile/B05_Profile_UI_RouteEdit.ts b/B05_Profile/B05_Profile_UI_RouteEdit.ts index 6d916379f..186c5eff1 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit.ts @@ -3,7 +3,7 @@ * 계획노선 편집(평면) — 예상노선(점선) 위에 계획노선(실선)을 고쳐 그린다. * * 자리(345-3) — 모달이 아니라 종단 보기 가운데 위 본문(옛 3D 자리)이고 **페이지 수명**이다. - * 이력 · 키 듣기는 보기의 보임 · 숨김 · 떠남(`host`)을 따른다. [노선 반영]을 누르면 배수유역부터 + * 이력 · 키 듣기는 보기의 보임 · 숨김 · 떠남(`host`)을 따른다. [저장]이 노선을 보내면 배수유역부터 * 종·횡단·유토곡선까지 다시 돌고(무거움), 끝나면 부른 쪽이 새로고침 없이 페이지를 다시 세운다. * **편집 중에는 아무 계산도 나가지 않는다**(띠 · 기울기 · 횡단 미리보기 묻기만). * @@ -94,7 +94,7 @@ const CONTOUR_LEVEL_BUDGET = 1200; type Vertex = [number, number]; -/** 편집기 곁값. [노선 반영]이 끝나면 `onApplied`를 부른다(화면 다시 세우기). */ +/** 편집기 곁값. 노선 저장이 끝나면 `onApplied`를 부른다(화면 다시 세우기). */ export interface RouteEditOptions { /** 규칙 측점 간격(m) — 좌측 패널이 쥔 값을 그대로 받는다(코드에 굳히지 않는다). */ stationIntervalM?: number; @@ -279,7 +279,7 @@ export async function mountRouteEditor( planMinRadiusM: () => minRadiusM, apply: (snapshot, message) => restoreSnapshot(snapshot, message, true), }); - // [반영 전으로] — 마지막 반영(페이지를 세운 때) 노선 · 그 걸음의 「현재 추천」으로. 되돌리기로 다시 살림. + // [저장 전으로] — 마지막 저장(페이지를 세운 때) 노선 · 그 걸음의 「현재 추천」으로. 되돌리기로 다시 살림. overlay.querySelector('[data-act="cancel"]')!.addEventListener("click", () => { const snapshot = history?.reset(); if (!snapshot) return showToast("반영 뒤 고친 노선이 없습니다.", "info"); diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts index 5c54fa6e1..8775940d4 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts @@ -1,14 +1,14 @@ /* ============================================================================= * B05_Profile_UI_RouteEdit_Draft.ts * 노선 편집기 ↔ 계산 묶음 다리(PLAN 346-1) — 노선을 한 번 고칠 때마다(놓기 · 더함 · 지움 · 곡선 · - * 되돌리기 · 다시하기 · [반영 전으로] · 추천 [적용]) 노선 초안을 넘김. 끄는 동안은 넘기지 않음 + * 되돌리기 · 다시하기 · [저장 전으로] · 추천 [적용]) 노선 초안을 넘김. 끄는 동안은 넘기지 않음 * (사진첩에 쌓이는 때 = 손을 놓은 때). * * 편집기는 사진첩(`_History`)을 `watch` 로 감싸기만 함 — 고친 줄 하나. 저장 안 한 초안은 * 다리가 캐시 칸(`route-draft`)에 두고, 편집기가 자료를 읽은 뒤 `restore` 로 한 번 되살림 * (새로고침 · 보기 전환에도 남음). 계산 · 가게는 `A00_Common/design/design_pipeline_page.ts` 몫. * - * 되돌리기 줄(346-4) — 페이지 사진첩(`_Profile_History`)이 있으면 쌓기 · [반영 전으로] 뒤 사진첩에 한 걸음 · + * 되돌리기 줄(346-4) — 페이지 사진첩(`_Profile_History`)이 있으면 쌓기 · [저장 전으로] 뒤 사진첩에 한 걸음 · * [되돌리기] · [다시하기]는 사진첩이 함(평면 · 종단 · 횡단 · 관 · 구조물 한 줄) · 사진첩이 되쓴 노선 * 초안은 `fromPage` 로 편집기 새 걸음이 됨. 사진첩이 없으면 편집기 사진 그대로. * ========================================================================== */ diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_History.ts b/B05_Profile/B05_Profile_UI_RouteEdit_History.ts index a9109d3c7..1a2added5 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit_History.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit_History.ts @@ -11,7 +11,7 @@ * * 되돌리기 줄은 페이지 사진첩 하나(`_Profile_History` · 346-4) — 계산 묶음 다리가 있으면(`_Draft.watch`) * [되돌리기] · [다시하기] · Ctrl+Z · Y 는 사진첩이 받고, 여기 사진은 고정 · 추천 꼬리표 · 고른 점을 - * 되살리는 기록(`match`)과 [반영 전으로](`reset`) · 고친 것 있음(`isDirty`)에만 씀. + * 되살리는 기록(`match`)과 [저장 전으로](`reset`) · 고친 것 있음(`isDirty`)에만 씀. * ========================================================================== */ import { onPageHistory } from "./B05_Profile_UI_Profile_History"; From 276411712045a37384a48949dd700108fae9c6bc Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 16 Oct 2026 12:34:14 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix(=EC=A2=85=EB=8B=A8=EB=B3=B4=EA=B8=B0):?= =?UTF-8?q?=20346-3=20=EB=8D=A7=20[=EC=A0=80=EC=9E=A5]=20=EB=92=A4=20?= =?UTF-8?q?=E3=80=8C=EB=85=B8=EC=84=A0=20=EB=B0=96=20=EA=B3=A0=EC=B9=A8?= =?UTF-8?q?=E3=80=8D=20=EC=95=8C=EB=A6=BC=20=EB=91=90=20=EC=A4=84=20?= =?UTF-8?q?=E2=86=92=20=ED=95=9C=20=EC=A4=84=20=E2=80=94=20carryStationDra?= =?UTF-8?q?fts=20=EC=A1=B0=EC=9A=A9=ED=9E=88=20=EA=BC=B4(quiet=20=C2=B7=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=EC=9D=80=20=EC=95=8C=EB=A6=BC=20=EA=B7=B8?= =?UTF-8?q?=EB=8C=80=EB=A1=9C)=20=C2=B7=20=EC=88=98=EB=8A=94=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=ED=95=9C=20=EC=A4=84=EC=97=90=20=ED=95=A9=EC=B9=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 시험: test_346_3_route_save_screen 9 · 관련 97 통과 · typecheck 통과 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn --- B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts | 2 +- B06_Section/B06_Section_Station_Keys.ts | 4 ++- resources/tester/helper_346_3_route_save.cjs | 5 +++- .../tester/test_346_3_route_save_screen.py | 30 ++++++++++++++++++- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts index 38a350737..bd43901b7 100644 --- a/B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts +++ b/B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts @@ -150,7 +150,7 @@ export async function carryAfterRouteSave( invalidateSectionDetail(projectId, toRouteId); const detail = await loadSectionDetail(projectId, toRouteId); useStationKeys(projectId, toRouteId, detail); - const outside = carryStationDrafts(projectId, fromRouteId, toRouteId); + const outside = carryStationDrafts(projectId, fromRouteId, toRouteId, { quiet: true }); await saveCachedCrossPatches(projectId, toRouteId); return outside; } diff --git a/B06_Section/B06_Section_Station_Keys.ts b/B06_Section/B06_Section_Station_Keys.ts index 6710c8db1..f6c1cb6ae 100644 --- a/B06_Section/B06_Section_Station_Keys.ts +++ b/B06_Section/B06_Section_Station_Keys.ts @@ -273,11 +273,13 @@ export function writeKeyed( * 노선이 바뀜(새 측점 목록을 `useStationKeys` 로 세운 뒤) — 옛 노선 고침을 측점 열쇠로 새 노선에 넘김. * 넘김 = 카드 선택 넷(지반 유형 · 측구 종류 · 측구 선택 · 2단 경사) · 암 경계 · 암 경사 · 단면 유형 · 측구 * 방향은 새 지형이 정함 · 노견 확장 · 소단 깊이는 안 넘김. 돌려주는 값 = 노선 밖으로 나간 고침 수(측점 단위). + * `quiet` = 알림 없이 수만 돌려줌(부르는 쪽이 결과 한 줄에 합칠 때). */ export function carryStationDrafts( projectId: string, fromRouteId: number, toRouteId: number, + { quiet = false }: { quiet?: boolean } = {}, ): number { const outside = new Set(); for (const name of KEYED_STATES) { @@ -301,7 +303,7 @@ export function carryStationDrafts( } writeState(name, next, projectId, toRouteId); } - if (outside.size) + if (outside.size && !quiet) showToast(`노선 밖 고침 ${outside.size} 건 — 사라진 측점이라 버렸습니다.`, "info"); return outside.size; } diff --git a/resources/tester/helper_346_3_route_save.cjs b/resources/tester/helper_346_3_route_save.cjs index 9cd166030..149d689b1 100644 --- a/resources/tester/helper_346_3_route_save.cjs +++ b/resources/tester/helper_346_3_route_save.cjs @@ -43,7 +43,10 @@ const STUBS = { }, "../B06_Section/B06_Section_Station_Keys": { useStationKeys: (_p, routeId, detail) => calls.push(`keys:${routeId}:${detail.tag}`), - carryStationDrafts: (_p, from, to) => (calls.push(`carry:${from}->${to}`), 2), + carryStationDrafts: (_p, from, to, opts) => ( + calls.push(`carry:${from}->${to}${opts?.quiet ? ":quiet" : ""}`), + 2 + ), }, "./B05_Profile_Api_Fetch": { clearRouteLatestCache: () => calls.push("latest:clear") }, "./B05_Profile_Api_Replan": { diff --git a/resources/tester/test_346_3_route_save_screen.py b/resources/tester/test_346_3_route_save_screen.py index 154d25cb4..850545e9c 100644 --- a/resources/tester/test_346_3_route_save_screen.py +++ b/resources/tester/test_346_3_route_save_screen.py @@ -72,7 +72,13 @@ def test_저장_뒤_가게_초안_비움_결과_한_줄(out): def test_초안_넘김_차례(out): - assert out["carryCalls"] == ["invalidate:9", "load:9", "keys:9:9", "carry:7->9", "crossSave:9"] + assert out["carryCalls"] == [ + "invalidate:9", + "load:9", + "keys:9:9", + "carry:7->9:quiet", + "crossSave:9", + ] assert out["outside"] == 2 @@ -107,3 +113,25 @@ def test_노선_반영_단추_없앰_배선(): assert "saveRecommendedRoute(" in initial[at : at + 900] replan = _read("B05_Profile/B05_Profile_Api_Replan.ts") assert "body: JSON.stringify(body)" in replan and "as_initial?: boolean;" in replan + + +def test_넘김_알림은_결과_한_줄에_합침(): + """346-3 덧 — [저장] 뒤 「노선 밖 고침」 두 줄 → 한 줄 · 넘김은 조용히 수만 · 기본은 알림 그대로.""" + keys = _read("B06_Section/B06_Section_Station_Keys.ts") + assert "{ quiet = false }: { quiet?: boolean } = {}," in keys + assert "if (outside.size && !quiet)" in keys + apply = _read("B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts") + assert "carryStationDrafts(projectId, fromRouteId, toRouteId, { quiet: true })" in apply + + +def test_노선_반영_글자_없음(): + recommend = _read("B05_Profile/B05_Profile_UI_Panel_Recommend.ts") + assert "노선 반영" not in recommend and "다시 계산은 [저장]에서" in recommend + for rel in ( + "B05_Profile/B05_Profile_UI_RouteEdit.ts", + "B05_Profile/B05_Profile_UI_RouteEdit_History.ts", + "B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts", + "A00_Common/design/design_view_profile.ts", + ): + text = _read(rel) + assert "[노선 반영]" not in text and "[반영 전으로]" not in text, rel