feat(구조물표): 323-6 바꿈 한 길 — 바뀜 신호 하나(구조물 초안도 설계 가게 · watchDrafts) · 종류 바꿈 표 규칙(swapsInPlace · E · F 점형 ↔ 구간형 = 지우고 같은 기준 측점에 새로) · 조용한 되돌림 없앰(알림) · 그리기가 조정값 안 만듦 · replayDraftPipeOptions 걷음
- 구조물 초안 쓰기 = useDesignStore().set("structures")(칸 그대로) → 관 초안과 같은 구독 · 횡단 보기 watchDrafts(구조물 = 늘 · 관 = 자리 · 종류 · 구간 · 잇기가 바뀔 때만 · 옵션만은 폼 길이 그 카드만 · 카드 줌 · 팬 지킴) · 옛 되부름 onStructuresChanged 걷음
- 종류 바꿈 = 표(catalog) swapsInPlace — 정본 다름 · 구조물 자리꼴 다름(E · F) = 지우고 같은 기준 측점에 새로(구간 = 기본 길이) · 같으면 종류 키만 · 막히면 옛 기록 · 옛 종류 폼 + 알림(전엔 [수정] 조기 반환 → 조용히 되돌림 · 드롭다운만 새 종류)
- syncApplied = 사용자가 조작한 세션이 있을 때만 깎음(카드 그리기가 자동 배치를 조정값으로 굳혀 [저장]으로 내보내던 것)
- replayDraftPipeOptions 걷음 — 그림 자료는 형상 얹기(초안 현황) · 다단 조정값은 조정 세션이 정본
- 시험: test_323_6_change(신호 · 거르기 · 표 규칙 · 그리기 · 걷음) · test_319 점형 ↔ 구간형 · 막힘 알림 · 되얹기 시험 = 형상 얹기로 · 옛 기대 글 고침
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
This commit is contained in:
@@ -95,10 +95,14 @@ const out = {};
|
||||
],
|
||||
{
|
||||
"./B05_Profile_UI_Structures_Define": { asRoad: (record) => record },
|
||||
"@ui/ui_template_elements": { showConfirmDialog: async () => true, showToast: () => {} },
|
||||
"@ui/ui_template_elements": {
|
||||
showConfirmDialog: async () => true,
|
||||
showToast: (text, kind) => toasts.push([text, kind ?? null]),
|
||||
},
|
||||
"./B06_Section_Section_Drafts": { forgetPreviewAdjusts: () => {} },
|
||||
},
|
||||
);
|
||||
const toasts = [];
|
||||
const { bindStructuresEvents } = load(B05("B05_Profile_UI_Structures_Panel_Events"));
|
||||
const typeMap = new Map(TYPES.map((type) => [type.type_id, type]));
|
||||
const el = () => ({
|
||||
@@ -109,8 +113,18 @@ const out = {};
|
||||
},
|
||||
});
|
||||
const fields = () => ({ station: el(), remainder: el(), wrap: { hidden: false } });
|
||||
const run = ({ structures = [], pipes = [], editing = null, pipeAt = null, next }) => {
|
||||
// commitOk = [수정] 반영이 받아 줌(패널은 기록을 새 것으로 갈아 끼움) · false = 막힘(필수 칸 등 · 323-6 알림)
|
||||
const run = ({
|
||||
structures = [],
|
||||
pipes = [],
|
||||
editing = null,
|
||||
pipeAt = null,
|
||||
next,
|
||||
commitOk = true,
|
||||
}) => {
|
||||
toasts.length = 0;
|
||||
const calls = {
|
||||
loaded: [],
|
||||
removed: [],
|
||||
addAt: [],
|
||||
emit: 0,
|
||||
@@ -164,14 +178,19 @@ const out = {};
|
||||
syncPlacementFields: () => {},
|
||||
renderOptionFields: () => {},
|
||||
syncFacilityForm: () => {},
|
||||
liveCommit: () => (calls.live += 1),
|
||||
liveCommit: () => {
|
||||
calls.live += 1;
|
||||
const at = structures.findIndex((s) => s.structure_id === editingId);
|
||||
if (commitOk && at >= 0) structures[at] = { ...structures[at] };
|
||||
},
|
||||
loadForm: (target) => calls.loaded.push(target?.type_id ?? null),
|
||||
emit: () => (calls.emit += 1),
|
||||
addAt: (at, typeId) => calls.addAt.push([at, typeId]),
|
||||
interval: () => 20,
|
||||
};
|
||||
bindStructuresEvents(ctx);
|
||||
ctx.typeSelect.listeners.change();
|
||||
return { ...calls, left: structures.map((s) => s.type_id) };
|
||||
return { ...calls, left: structures.map((s) => s.type_id), toasts: [...toasts] };
|
||||
};
|
||||
const store = window.sessionStorage;
|
||||
const kindreset = () => JSON.parse(store.getItem("aislo:draft:kindreset:P") ?? "null");
|
||||
@@ -219,6 +238,47 @@ const out = {};
|
||||
next: "open_ditch",
|
||||
});
|
||||
out.to_blank = run({ pipes: [{ chainage_m: 200, facility: "pipe" }], pipeAt: 200, next: null });
|
||||
// 323-6 — E · F 점형 ↔ 구간형 = 지우고 같은 기준 측점에 새로(구간 = 기본 길이는 `addAt`) · 같은 자리꼴 = 제자리
|
||||
out.point_to_interval = run({
|
||||
structures: [{ structure_id: "m1", type_id: "mirror", placement: "point", chainage_m: 140 }],
|
||||
editing: "m1",
|
||||
next: "guardrail",
|
||||
});
|
||||
out.interval_to_point = run({
|
||||
structures: [
|
||||
{
|
||||
structure_id: "g1",
|
||||
type_id: "guardrail",
|
||||
placement: "interval",
|
||||
start_m: 100,
|
||||
chainage_m: 105,
|
||||
end_m: 120,
|
||||
},
|
||||
],
|
||||
editing: "g1",
|
||||
next: "mirror",
|
||||
});
|
||||
out.interval_same = run({
|
||||
structures: [
|
||||
{
|
||||
structure_id: "r1",
|
||||
type_id: "refuge",
|
||||
placement: "interval",
|
||||
start_m: 100,
|
||||
chainage_m: 105,
|
||||
end_m: 120,
|
||||
},
|
||||
],
|
||||
editing: "r1",
|
||||
next: "work_yard",
|
||||
});
|
||||
// 막힘 = 옛 기록 · 옛 종류 폼으로 되돌리고 알림(조용한 되돌림 없앰)
|
||||
out.blocked = run({
|
||||
structures: [{ structure_id: "b1", type_id: "mirror", placement: "point", chainage_m: 30 }],
|
||||
editing: "b1",
|
||||
next: "curb",
|
||||
commitOk: false,
|
||||
});
|
||||
}
|
||||
|
||||
// ── 2. 일반 측점 자리(grid) — 종류 바꿈 = 새로 뜬 횡단 · 다 빠짐 = 시설 뺀 사본(319-2) ──────
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/* PLAN 323-6 바꿈 한 길 헬퍼 — 진짜 `B05_Profile_Api_Structures.ts`(구조물 초안) · `design_store.ts`(바뀜 신호)를
|
||||
* 그 자리에서 트랜스파일해 Node 로 돌림(세션만 흉내) · 결과 = 표준출력 JSON. 짝 = `test_323_6_change.py`.
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
const ts = require(path.join(ROOT, "config", "node_modules", "typescript"));
|
||||
const CATALOG = require("./helper_322_catalog_module.cjs");
|
||||
|
||||
const memory = new Map();
|
||||
const store = {
|
||||
getItem: (k) => (memory.has(k) ? memory.get(k) : null),
|
||||
setItem: (k, v) => memory.set(k, String(v)),
|
||||
removeItem: (k) => memory.delete(k),
|
||||
key: (i) => [...memory.keys()][i] ?? null,
|
||||
get length() {
|
||||
return memory.size;
|
||||
},
|
||||
};
|
||||
globalThis.window = { sessionStorage: store, localStorage: store, addEventListener: () => {} };
|
||||
globalThis.sessionStorage = store;
|
||||
globalThis.localStorage = store;
|
||||
|
||||
const cache = new Map();
|
||||
function load(file) {
|
||||
const full = path.resolve(file);
|
||||
if (cache.has(full)) return cache.get(full);
|
||||
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
||||
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
||||
}).outputText;
|
||||
const box = { exports: {} };
|
||||
cache.set(full, box.exports);
|
||||
const need = (spec) => {
|
||||
if (CATALOG.isCatalogRequest(spec)) return CATALOG;
|
||||
if (spec.startsWith("@ui/")) return new Proxy({}, { get: () => () => {} });
|
||||
if (spec.startsWith("@config/")) return load(path.join(ROOT, "config", `${spec.slice(8)}.ts`));
|
||||
if (spec.startsWith(".")) return load(path.join(path.dirname(full), `${spec}.ts`));
|
||||
return require(spec);
|
||||
};
|
||||
new Function("exports", "module", "require", js)(box.exports, box, need);
|
||||
return box.exports;
|
||||
}
|
||||
|
||||
const api = load(path.join(ROOT, "B05_Profile", "B05_Profile_Api_Structures.ts"));
|
||||
const { useDesignStore } = load(path.join(ROOT, "A00_Common", "design", "design_store.ts"));
|
||||
const heard = { structures: [], pipes: [] };
|
||||
const shop = useDesignStore("P", null);
|
||||
for (const key of ["structures", "pipes"]) shop.subscribe(key, (value) => heard[key].push(value));
|
||||
const wall = { structure_id: "w1", type_id: "retaining_wall", chainage_m: 10 };
|
||||
api.writePendingStructures("P", [wall]);
|
||||
api.writePendingStructures("P", null);
|
||||
api.writePendingStructures("P", [wall]);
|
||||
// 바뀜 신호 거르기 — 구조물 = 늘 · 관 = 자리 · 종류 · 구간 · 잇기가 바뀔 때만(옵션만 = 폼 길이 그 카드)
|
||||
const status = load(path.join(ROOT, "A00_Common", "design", "design_structure_status.ts"));
|
||||
let fired = 0;
|
||||
const off = status.watchDrafts("Q", () => (fired += 1));
|
||||
const shopQ = useDesignStore("Q", null);
|
||||
shopQ.set("pipes", [{ chainage_m: 10, source: "user", options: { a: 1 } }]);
|
||||
shopQ.set("pipes", [{ chainage_m: 10, source: "user", options: { a: 2 } }]);
|
||||
shopQ.set("pipes", [{ chainage_m: 12, source: "user", options: { a: 2 } }]);
|
||||
shopQ.set("pipes", [{ chainage_m: 12, source: "user", facility: "box_culvert" }]);
|
||||
shopQ.set("structures", []);
|
||||
off();
|
||||
shopQ.set("structures", null);
|
||||
|
||||
process.stdout.write(
|
||||
JSON.stringify({
|
||||
watch: fired,
|
||||
heard: heard.structures.map((v) => (v ? v.length : null)),
|
||||
pipesHeard: heard.pipes.length,
|
||||
read: api.readPendingStructures("P"),
|
||||
key: memory.has("aislo:draft:structures:P"),
|
||||
swaps: [
|
||||
"mirror>curb",
|
||||
"mirror>guardrail",
|
||||
"refuge>work_yard",
|
||||
"pipe>box_culvert",
|
||||
"pipe>revetment",
|
||||
"cross_underdrain>pipe",
|
||||
].map((pair) => [pair, CATALOG.swapsInPlace(...pair.split(">"))]),
|
||||
}),
|
||||
);
|
||||
@@ -1,5 +1,6 @@
|
||||
/* 관 초안 옵션 되얹기 단위검증 헬퍼(PLAN 24-7a) — TS 를 그 자리에서 트랜스파일해 Node 로 돌린다.
|
||||
* 새로고침 뒤 캐시 상세(저장분)에 저장 전에 고친 관 옵션(월류 폭 · 관경)이 다시 얹히는지 본다.
|
||||
/* 관 초안 옵션 되얹기 단위검증 헬퍼(PLAN 24-7a → 323-6) — TS 를 그 자리에서 트랜스파일해 Node 로 돌린다.
|
||||
* 새로고침 뒤 캐시 상세(저장분)에 저장 전에 고친 관 옵션(월류 폭 · 관경)이 다시 얹히는지 본다 — 옛 되얹기
|
||||
* (`replayDraftPipeOptions`)는 걷고 형상 얹기 한 벌(`attachShapes` · 초안 현황)이 맡음(323-6).
|
||||
* 결과는 표준출력에 JSON 한 벌. 화면 그릇은 쓰지 않는다.
|
||||
*
|
||||
* ⚠ 확장자가 `.cjs` 인 까닭은 `helper_b05_structures_form_summary.cjs` 머리와 같다.
|
||||
@@ -47,50 +48,45 @@ function loadTs(file) {
|
||||
return box.exports;
|
||||
}
|
||||
|
||||
const options = loadTs(path.join(ROOT, "B06_Section", "B06_Section_UI_Page_Pipe_Options.ts"));
|
||||
const DEF = JSON.parse(
|
||||
fs.readFileSync(path.join(ROOT, "resources", "master_template", "구조물정의.json"), "utf8"),
|
||||
);
|
||||
const TYPES = DEF.types.map((t) => ({ managed_by: null, enabled: true, ...t }));
|
||||
const attach = loadTs(path.join(ROOT, "common_util", "common_util_structure_attach.ts"));
|
||||
|
||||
// 캐시 상세(저장분) — 세월교(월류 폭 10) · 배수관(관경 1000) · 옹벽 없음
|
||||
// 캐시 상세(저장분) — 세월교(월류 폭 10) · 배수관(관경 1000) · 조정창 정본(기슭막이 조정값)
|
||||
const adjust = { outlet: { x: 0.4, d: null, h: 2.0, m: null } };
|
||||
const detail = {
|
||||
cross_sections: [
|
||||
{
|
||||
chainage_m: 85.05,
|
||||
culvert: { pipe_kind: "파형강관", diameter_m: 1.0, inlet: {}, outlet: {} },
|
||||
design: { revet_adjust: adjust },
|
||||
},
|
||||
{
|
||||
chainage_m: 173.09,
|
||||
ford: { span_m: 10, diameter_m: 1.0, pipe_count: 1, wing_in: {}, wing_out: {} },
|
||||
},
|
||||
{ chainage_m: 258.12 },
|
||||
],
|
||||
};
|
||||
const sent = [];
|
||||
const ctx = {
|
||||
detail: () => detail,
|
||||
ford: {
|
||||
setPipe: (chainageM, patch) => {
|
||||
sent.push({ chainageM, patch });
|
||||
if (patch.ford_width_m) detail.cross_sections[1].ford.span_m = patch.ford_width_m;
|
||||
},
|
||||
setWing: () => {},
|
||||
},
|
||||
box: {},
|
||||
revetOffset: { update: () => sent.push({ revet: true }) },
|
||||
overrideOptions: () => {},
|
||||
refreshCard: () => {},
|
||||
};
|
||||
|
||||
// 초안: 세월교 월류 폭 3.5 · 배수관 관경 1200 · 기슭막이 높이(조정창 정본이라 되살리지 않음)
|
||||
options.replayDraftPipeOptions(ctx, [
|
||||
{ chainage_m: 85.05, options: { pipe_diameter_mm: 1200, outlet_revet_height_m: 2.5 } },
|
||||
{ chainage_m: 173.09, facility: "ford_bridge", options: { ford_width_m: 3.5 } },
|
||||
{ chainage_m: 258.12, options: {} },
|
||||
]);
|
||||
options.replayDraftPipeOptions(ctx, null);
|
||||
// 초안: 세월교 월류 폭 3.5 · 배수관 관경 1200 · 기슭막이 높이(조정창 정본이라 조정값은 안 건드림)
|
||||
attach.attachShapes(
|
||||
detail.cross_sections,
|
||||
[
|
||||
{ chainage_m: 85.05, options: { pipe_diameter_mm: 1200, outlet_revet_height_m: 2.5 } },
|
||||
{ chainage_m: 173.09, facility: "ford_bridge", options: { ford_width_m: 3.5 } },
|
||||
],
|
||||
[],
|
||||
TYPES,
|
||||
);
|
||||
|
||||
process.stdout.write(
|
||||
JSON.stringify({
|
||||
fordSpan: detail.cross_sections[1].ford.span_m,
|
||||
culvertDiameter: detail.cross_sections[0].culvert.diameter_m,
|
||||
fordCalls: sent.filter((s) => s.chainageM === 173.09).length,
|
||||
revetTouched: sent.some((s) => s.revet === true),
|
||||
fordAt: detail.cross_sections.filter((s) => s.ford).map((s) => s.chainage_m),
|
||||
revetTouched: detail.cross_sections[0].design.revet_adjust !== adjust,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -65,8 +65,7 @@ def test_B06_추가_순간_기다림_적고_초안_씀():
|
||||
body.index("pipeFacilities.push({"),
|
||||
body.index("if (waitsFordHeight(attributes.facility, attributes.options))"),
|
||||
body.index("fordWaitsOf(deps.projectId).add(at);"),
|
||||
body.index("persistPipes();"),
|
||||
body.index("deps.onStructuresChanged?.();"),
|
||||
body.index("persistPipes();"), # 초안 씀 = 카드 다시(바뀜 신호 하나 · 323-6)
|
||||
]
|
||||
assert order == sorted(order)
|
||||
|
||||
@@ -145,8 +144,11 @@ def test_실패하면_토스트_한_줄(out):
|
||||
|
||||
def test_추가_뒤_새_측점_횡단_미리_뜸():
|
||||
body = _body(B06, " onPipeAdd: (chainageM, attributes) => {", " onPipeUpdate:")
|
||||
assert "deps.onStructuresChanged?.();" in body
|
||||
assert "onStructuresChanged: () => void refreshDetailForStructures()," in CROSS
|
||||
assert "persistPipes();" in body # 초안 씀 → 구독(`watchDrafts`)이 카드 다시(323-6)
|
||||
# 카드 다시 = 바뀜 신호 하나(323-6 · 관 · 구조물 초안 구독 · 옛 되부름 갈음)
|
||||
assert (
|
||||
"watchDrafts(projectId, () => host.visible() && void refreshDetailForStructures())" in CROSS
|
||||
)
|
||||
drafts = _read("B06_Section", "B06_Section_Section_Drafts.ts")
|
||||
stations = _body(
|
||||
drafts, "export async function withDraftStations(", "parked.set(detail, stale);"
|
||||
|
||||
@@ -83,7 +83,7 @@ def test_B05_B06_같은_목록_각자_관빼기():
|
||||
assert "onPipeFacilityRemove: (chainage) => profilePanel.drainage.removePipe(chainage)," in b05
|
||||
# 공용 확인창 · 저장 길(초안 → [저장])은 안 고침
|
||||
events = _read("B05_Profile", "B05_Profile_UI_Structures_Panel_Events.ts")
|
||||
assert 'import { showConfirmDialog } from "@ui/ui_template_elements";' in events
|
||||
assert 'import { showConfirmDialog, showToast } from "@ui/ui_template_elements";' in events
|
||||
assert "ctx.emit();" in events
|
||||
|
||||
|
||||
|
||||
@@ -75,6 +75,22 @@ def test_same_owner_switch_unchanged(result: dict) -> None:
|
||||
assert result["to_blank"]["reset"] == 1 and result["to_blank"]["addAt"] == []
|
||||
|
||||
|
||||
def test_point_interval_switch_replaces_at_same_anchor(result: dict) -> None:
|
||||
# 323-6 — 표 규칙(`swapsInPlace`) · 구간 = 기본 길이(`addAt`)
|
||||
up = result["point_to_interval"]
|
||||
assert up["left"] == [] and up["addAt"] == [[140, "guardrail"]] and up["live"] == 0
|
||||
down = result["interval_to_point"]
|
||||
assert down["left"] == [] and down["addAt"] == [[105, "mirror"]]
|
||||
same = result["interval_same"]
|
||||
assert same["addAt"] == [] and same["live"] == 1 and same["left"] == ["work_yard"]
|
||||
|
||||
|
||||
def test_blocked_switch_restores_with_notice(result: dict) -> None:
|
||||
blocked = result["blocked"]
|
||||
assert blocked["left"] == ["mirror"] and blocked["loaded"] == ["mirror"]
|
||||
assert len(blocked["toasts"]) == 1 and blocked["toasts"][0][1] == "error"
|
||||
|
||||
|
||||
def test_grid_station_kind_change_uses_bare_copy(result: dict) -> None:
|
||||
# 일반 측점 자리 = 측점이 남음 — 저장분에서 구조물만 뺀 사본에 새 종류(지형 쪽 고친 값 그대로)
|
||||
grid = result["grid"]
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
"""PLAN 323-6 바꿈 한 길 — 바뀜 신호 하나 · 종류 바꿈 표 규칙 · 그리기가 조정값을 안 만듦 · 옛 되얹기 걷음.
|
||||
|
||||
- 구조물 초안도 설계 가게(`useDesignStore`)로 씀 = 관 초안과 같은 신호 · 칸은 그대로(`structures`) ·
|
||||
횡단 보기가 두 초안을 구독해 카드 · 그림을 다시(옛 되부름 `onStructuresChanged` 갈음).
|
||||
- 종류 바꿈 = 정본 같고 구조물은 자리꼴도 같아야 제자리(`swapsInPlace`) · 아니면 지우고 같은 기준 측점에 새로
|
||||
(흐름 = test_319_kind_swap).
|
||||
- 카드 그리기의 적용값 되받기는 사용자가 조작한 세션이 있을 때만(자동 배치를 조정값으로 안 굳힘).
|
||||
TS 쪽 = `helper_323_6_change.cjs`(Node).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
ROOT = HERE.parent.parent
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not (ROOT / "config" / "node_modules").is_dir(), reason="프론트엔드 의존성 미설치"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def out() -> dict:
|
||||
run = subprocess.run(
|
||||
["node", str(HERE / "helper_323_6_change.cjs")],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=120,
|
||||
check=True,
|
||||
)
|
||||
return json.loads(run.stdout)
|
||||
|
||||
|
||||
def _src(*parts: str) -> str:
|
||||
return (ROOT.joinpath(*parts)).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_structure_draft_signals_through_store(out: dict) -> None:
|
||||
assert out["heard"] == [1, None, 1] and out["pipesHeard"] == 0
|
||||
assert out["read"] == [{"structure_id": "w1", "type_id": "retaining_wall", "chainage_m": 10}]
|
||||
assert out["key"] is True # 칸 그대로
|
||||
cross = _src("A00_Common", "design", "design_view_cross.ts")
|
||||
assert "watchDrafts(projectId," in cross and "onStructuresChanged" not in cross
|
||||
panel = _src("B06_Section", "B06_Section_UI_Page_Structures_Panel.ts")
|
||||
assert "onStructuresChanged" not in panel # 옛 되부름 걷음
|
||||
|
||||
|
||||
def test_change_signal_filters_option_only_pipe_edits(out: dict) -> None:
|
||||
# 관 놓기 · 옵션만 · 옮기기 · 종류 바꿈 · 구조물 · 끊은 뒤 = 1 · 0 · 1 · 1 · 1 · 0
|
||||
assert out["watch"] == 4
|
||||
|
||||
|
||||
def test_kind_swap_rule_from_table(out: dict) -> None:
|
||||
assert dict(out["swaps"]) == {
|
||||
"mirror>curb": True,
|
||||
"mirror>guardrail": False,
|
||||
"refuge>work_yard": True,
|
||||
"pipe>box_culvert": True,
|
||||
"pipe>revetment": True,
|
||||
"cross_underdrain>pipe": False,
|
||||
}
|
||||
|
||||
|
||||
def test_drawing_does_not_create_adjusts() -> None:
|
||||
controls = _src("B06_Section", "B06_Section_UI_Page_Station_Controls.ts")
|
||||
body = controls.split("syncApplied: (chainageM, role, applied) => {", 1)[1].split("},", 1)[0]
|
||||
assert "if (!stored || sameAdjust(stored, applied)) return;" in body
|
||||
|
||||
|
||||
def test_old_replay_removed() -> None:
|
||||
assert "replayDraftPipeOptions" not in _src(
|
||||
"B06_Section", "B06_Section_UI_Page_Pipe_Options.ts"
|
||||
)
|
||||
@@ -5,6 +5,7 @@
|
||||
저장값(월류 폭 10 · 관경 1000)으로 돌아가 있었다. 초안(관 목록 세션 초안)이 정본이므로
|
||||
횡단 보기가 서며 초안 관 옵션을 캐시에 다시 얹는다.
|
||||
• 되얹기 — 세월교 월류 폭 3.5 · 배수관 관경 1200 이 캐시 스펙에 실림 · 조정창 정본(기슭막이 높이 · 형태)은 안 건드림
|
||||
(323-6 — 옛 `replayDraftPipeOptions` 걷음 · 형상 얹기 한 벌이 초안 현황으로 다시 셈)
|
||||
• 횡단 보기가 먼저 선 뒤 종단 보기가 서도 종단 보기가 배수유역도의 관 목록을 먼저 쥠(빈 목록으로 시작해 관을 지우지 않음)
|
||||
화면 그릇 없이 Node 헬퍼가 TS 를 트랜스파일해 돌린다(`helper_b06_draft_pipe_replay.cjs`).
|
||||
"""
|
||||
@@ -33,12 +34,15 @@ def test_draft_pipe_options_are_replayed_onto_the_cache():
|
||||
out = json.loads(proc.stdout)
|
||||
assert out["fordSpan"] == 3.5 # 월류 폭 초안이 캐시 스펙에 실림(저장분 10 아님)
|
||||
assert out["culvertDiameter"] == 1.2 # 배수관 관경 초안 1200
|
||||
assert out["fordCalls"] == 1 # 옵션 없는 관은 건드리지 않고 세월교는 한 번만
|
||||
assert out["fordAt"] == [173.09] # 세월교는 제 측점에만
|
||||
assert out["revetTouched"] is False # 기슭막이 높이 · 형태는 조정창이 정본
|
||||
|
||||
# 배선 — 횡단 보기가 서며 초안을 읽어 되얹고, 종단 보기는 마지막 관 목록을 먼저 싣는다.
|
||||
# 배선 — 옛 되얹기는 걷음(323-6) · 초안 현황으로 상세를 읽을 때마다 형상 얹기(`withDraftShapes`) ·
|
||||
# 종단 보기는 마지막 관 목록을 먼저 싣는다.
|
||||
cross = _read("A00_Common", "design", "design_view_cross.ts")
|
||||
assert "replayDraftPipeOptions(pipeOptionsContext, readPendingPipes(projectId))" in cross
|
||||
assert "replayDraftPipeOptions" not in cross
|
||||
store = _read("B06_Section", "B06_Section_Section_Store.ts")
|
||||
assert "await withDraftShapes(detail, projectId);" in store
|
||||
shared = _read("A00_Common", "design", "design_shared.ts")
|
||||
assert "shared.lastPipes = pipes" in shared
|
||||
profile = _read("A00_Common", "design", "design_view_profile.ts")
|
||||
|
||||
Reference in New Issue
Block a user