diff --git a/A00_Common/design/design_view_profile.ts b/A00_Common/design/design_view_profile.ts
index bd9795fb5..21e23ccd5 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,
onCorridorStale: () => sections.setCorridorPending(true),
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_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/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";
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