feat(804-6): 옛 수식 탭 걷음 · 줄 쌓기 = 첫 「수식」 탭(요구 686-1)
- M01 단가산출 기초 · M02 단가산출 상세 보기 = 수식(줄 쌓기 · 기본) · 단가산출 상세 둘 - 줄 쌓기에 M02 사본 [단가 갱신] · [재생성](미리 셈 → 알림 → 저장 · 고침 있으면 막음) · 판 바뀜(409) 문서 그대로면 새 판으로 다시 저장 옮김 - 옛 수식 문서 화면 걷음(formula_doc_screen · defs · edit · lines · math · math_model · rows · sub · formula_doc.css) · 이미 안 부르던 796-2 수식 나무 화면(LogicLab_Equation · Defs · Var · css · M01_Logic_Equation_Model · sheet_formula_cell · ui_template_equation_defs · edit) 걷음 — 18 파일 4,860 줄 - formula_doc_render = 줄 쌓기가 쓰는 reach 만 · 옵션 가로 CSS 는 line_stack.css 로 - 남김 = 계산기 common_util_formula_doc* · 서버 길 · 옵션 · 사본 표지 · 합계 상자 · KaTeX · 시험 페이지 tools/line-stack-test - 시험: test_796_2 지움(걷은 화면 원본 검사뿐) · 799_1 · 800_2 걷은 화면 줄만 뺌 · 799_2 · 802_4b2 · 804_2 보기 · 화면 파일 대상 바꿈 · test_804_6 새로(걷은 파일 · 부르는 곳 없음 · 첫 탭 · 사본 할일) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,139 +0,0 @@
|
||||
"""796-2 수식 탭 화면 지킴(정적 · 서버 · 브라우저 없이) — 부품 상자만 · 수식 탭 첫 탭 · 아이콘 숨김 · 변수 고침 창 · 옵션 가로.
|
||||
|
||||
화면 동작(분수 · 변수 풀이 · 고침 → 금액 · 변수 더함 · 지움 · 저장)은 ORCA 사용자 길로 확인 — 서버 모델은 `test_796_1_formula_model.py`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
M01 = ROOT / "M01_MasterData"
|
||||
UI = ROOT / "ui_template"
|
||||
PARTS = [UI / "ui_template_equation.ts", UI / "ui_template_equation_line.ts"]
|
||||
PAGE = [
|
||||
M01 / "M01_MasterData_UI_LogicLab_Equation.ts",
|
||||
M01 / "M01_MasterData_UI_LogicLab_EquationVar.ts",
|
||||
]
|
||||
MODEL = M01 / "logic" / "M01_Logic_Equation_Model.ts"
|
||||
CSS = [UI / "ui_template_equation.css", M01 / "M01_MasterData_UI_LogicLab_Equation.css"]
|
||||
RAW = re.compile(r"<button|<input|(el|createElement)\(\"(button|input)\"")
|
||||
|
||||
|
||||
def _text(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8").replace("\r\n", "\n")
|
||||
|
||||
|
||||
def test_부품_상자만_날_단추_입력_없음():
|
||||
for path in [*PARTS, *PAGE, MODEL]:
|
||||
src = _text(path)
|
||||
assert not RAW.search(src), f"{path.name} — 날 button · input"
|
||||
# 수식 칩 = 글 속 부품(span role) · 단추 · 입력 · 고르기는 부품 상자 것
|
||||
page = _text(PAGE[0]) + _text(PAGE[1])
|
||||
for part in (
|
||||
"createButton",
|
||||
"createToolbar",
|
||||
"createFormulaCell",
|
||||
"openModal",
|
||||
):
|
||||
assert part in page, part
|
||||
assert "createValueControl" in page # 옵션 값 칸 = 기존 값 칸 한 벌(M02_Labor_Values)
|
||||
|
||||
|
||||
def test_색은_공통_값만_700줄_안():
|
||||
for path in CSS:
|
||||
css = _text(path)
|
||||
assert not re.search(r"#[0-9a-fA-F]{3,8}\b|rgba?\(", css), path.name
|
||||
assert "var(--color-" in css
|
||||
for path in [*PARTS, *PAGE, MODEL, *CSS, M01 / "M01_MasterData_UI_LogicLab.ts"]:
|
||||
assert len(_text(path).splitlines()) <= 700, path.name
|
||||
assert len(_text(M01 / "M01_MasterData_UI_LogicLab_Ho.ts").splitlines()) <= 700
|
||||
|
||||
|
||||
def test_계산_자리_화면은_모양만():
|
||||
model = _text(MODEL)
|
||||
assert "fetch(" not in model and "document." not in model # logic/ = 화면 · fetch 없음
|
||||
for path in PARTS:
|
||||
assert "fetch(" not in _text(path) # 부품은 그리기만
|
||||
page = _text(PAGE[0])
|
||||
assert page.count("fetch(") == 1 # 서버 길 한 곳 — 계산은 서버 한 벌(③)
|
||||
for route in ("`/logic/equation${suffix}`", '"/preview"', '"/logic/equation/save"'):
|
||||
assert route in page, route # 796-2b 길 앞머리 = M01 · 페이지 갈래(page.ask)
|
||||
assert "page ? page.ask<T>(suffix, body, signal)" in page
|
||||
assert "saveRevised(" in page and "개정확인" in page # [저장] = 개정 확인 길
|
||||
assert "edits" in page and "sessionStorage" in page # 고침 목록 = 캐시 → [저장] 한 번
|
||||
assert "ctl?.abort()" in page # 옛 요청 끊음
|
||||
assert "setInterval" not in page and "autosave" not in page.lower() # 자동저장 없음
|
||||
|
||||
|
||||
def test_수식_탭이_첫_탭_단가산출_상세는_그대로():
|
||||
"""799-2 — 보기 둘(수식 · 단가산출 상세)만 남김(시트 · 인력·재료·경비 · 시험 계산 · 텍스트 수식 걷음)."""
|
||||
view = _text(M01 / "M01_MasterData_UI_LogicLab_View.ts")
|
||||
labels = re.findall(r'\{ value: "(\w+)", label: tl\("(\w+)"\) \}', view)
|
||||
assert [v for v, _ in labels] == ["equation", "ho"]
|
||||
assert 'host.dataset.view = "equation";' in view and 'value: "equation",\n size: 32' in view
|
||||
detail = _text(M01 / "M01_MasterData_UI_LogicLab_Detail.ts")
|
||||
assert 'block(ctx.equation, "equation")' in detail
|
||||
assert '"formula"' not in detail and "buildFormula" not in detail # 799-2 텍스트 수식 걷음
|
||||
css = _text(M01 / "M01_MasterData_UI_LogicLab_Style.css")
|
||||
assert '[data-view="equation"] [data-block]:not([data-block="equation"])' in css
|
||||
lab = _text(M01 / "M01_MasterData_UI_LogicLab.ts")
|
||||
assert "createLabEquation({" in lab and "equation: equation.root," in lab
|
||||
assert "equation.canLeave()" in lab # 저장 전 떠나면 버림 물음
|
||||
|
||||
|
||||
def test_식_바로_고침은_관리자만():
|
||||
# 800-3 — 줄을 눌러 여는 아래 편집 · 아이콘 줄을 걷고 식 칸을 그 자리에서 고침
|
||||
line = _text(PARTS[1])
|
||||
assert "o.selected" not in line and "o.slot" not in line and "onSelect" not in line
|
||||
assert "o.editing === id && o.editor" in line # 이름 식 칸 자리에 식 칸
|
||||
page = _text(PAGE[0])
|
||||
for icon in ('"frac"', '"paren"', '"sub"', '"sup"'):
|
||||
assert icon not in page, icon # 아이콘 줄 걷음
|
||||
assert 'label: t("Add")' in page # 변수 더함
|
||||
assert "opt.admin && !opt.blocked()" in page # 관리자 + 시트 쪽 저장 안 한 고침 없을 때만
|
||||
assert "onEdit: edit" in page and "editor: edit" in page
|
||||
assert "createFormulaCell" in page and "../A00_Common/sheet_formula_cell" in page
|
||||
|
||||
|
||||
def test_변수_고침_창_칸과_지움_막힘():
|
||||
var = _text(PAGE[1])
|
||||
for label in (
|
||||
'Name: ["이름"',
|
||||
'Sign: ["기호"',
|
||||
'Up: ["위첨자"',
|
||||
'Down: ["아래첨자"',
|
||||
'Unit: ["단위"',
|
||||
'Digits: ["보이는 자리',
|
||||
"Value:",
|
||||
):
|
||||
assert label in var, label
|
||||
assert '할일: "지움"' in var and "why.set(bad)" in var # 쓰는 곳 목록 = 서버 까닭 그대로 띠에
|
||||
assert "commit(" in var or "o.commit(" in var
|
||||
assert "openAddDialog" in var and 'value: "중간"' in var # 입력 · 중간 더함
|
||||
model = _text(MODEL)
|
||||
for job in ('"식"', '"더함"', '"지움"', '"변수"'):
|
||||
assert job in model, job
|
||||
|
||||
|
||||
def test_옵션_가로_찾기형_말줄임():
|
||||
page = _text(PAGE[0])
|
||||
assert "createToolbar({" in page and "optionNode(" in page
|
||||
assert "BIG = 12" in page and "datalist" in page # 고르기 많으면 찾기형
|
||||
assert "title" in page # 마우스 올림 전체 글
|
||||
css = _text(CSS[1])
|
||||
assert "text-overflow: ellipsis" in css and "max-width: 14rem" in css
|
||||
assert "askAgain" in page # 옵션 바꾸면 다시 셈
|
||||
|
||||
|
||||
def test_부품_모음_견본_한_줄():
|
||||
src = _text(UI / "ui_template_ui_kit_parts.ts")
|
||||
rows = re.findall(
|
||||
r'\{ key: "([^"]+)", name: "[^"]+", group: "(\w+)",[^\n]*file: "([^"]+)"', src
|
||||
)
|
||||
assert ("equation", "compound", "ui_template_equation.ts") in rows
|
||||
assert len(src.splitlines()) <= 700
|
||||
head = _text(PARTS[0])
|
||||
for word in ("분수", "첨자", "조건 칩", "크기", "상태", "쓰는 법"):
|
||||
assert word in head, word
|
||||
@@ -98,5 +98,3 @@ def test_화면_부품이_서버_칸을_읽음():
|
||||
ts = Path("ui_template/ui_template_equation_sum.ts").read_text(encoding="utf-8")
|
||||
for name in ("노무비", "재료비", "경비", "끝수", "합계"):
|
||||
assert name in ts
|
||||
line = Path("M01_MasterData/M01_MasterData_UI_LogicLab_Equation.ts").read_text(encoding="utf-8")
|
||||
assert "createEqSum(eq, open" in line # 796-2e 덧단추 자리 인자가 뒤에 붙음
|
||||
|
||||
@@ -60,8 +60,8 @@ def test_보기는_수식_단가산출상세_둘():
|
||||
m01 = _text(M01 / "M01_MasterData_UI_LogicLab_View.ts")
|
||||
m02 = _text(M02 / "M02_MasterTemplete_Sangeun_Tabs.ts")
|
||||
for src in (m01, m02):
|
||||
assert re.findall(r'\{ value: "(\w+)", label: ', src) == ["equation", "ho"]
|
||||
assert 'export type LabView = "equation" | "ho";' in m01
|
||||
assert re.findall(r'\{ value: "(\w+)", label: ', src) == ["stack", "ho"] # 804-6
|
||||
assert 'export type LabView = "stack" | "ho";' in m01
|
||||
css = _text(M01 / "M01_MasterData_UI_LogicLab_Style.css")
|
||||
assert '[data-view="ho"] [data-block]:not([data-block="ho"])' in css
|
||||
assert 'data-view="sheet"' not in css and 'data-view="calc"' not in css
|
||||
|
||||
@@ -121,10 +121,7 @@ def test_screen_source_groups_and_inline_edit():
|
||||
ui = ROOT / "ui_template"
|
||||
sum_ts = (ui / "ui_template_equation_sum.ts").read_text(encoding="utf-8")
|
||||
line_ts = (ui / "ui_template_equation_line.ts").read_text(encoding="utf-8")
|
||||
page = (ROOT / "M01_MasterData/M01_MasterData_UI_LogicLab_Equation.ts").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert "ORDER" in sum_ts and "ui-eq__grp" in sum_ts # 가 · 나 · 다 묶음
|
||||
assert "o.after?.(line)" in line_ts and "after:" in page # 블록 식 줄 바로 아래
|
||||
assert "o.after?.(line)" in line_ts # 블록 식 줄 바로 아래
|
||||
assert "block-key" not in line_ts # 줄 곁 DB 열쇠 글 없음
|
||||
assert "ui-eq__solve" not in line_ts and "ui-eq__step" not in line_ts # 풀이 · 줄 번호 걷음
|
||||
|
||||
@@ -48,10 +48,10 @@ def _src(rel: str) -> str:
|
||||
|
||||
def test_길_앞머리_M02_공용화면():
|
||||
tabs = _src("M02_MasterTemplete/M02_MasterTemplete_Sangeun_Tabs.ts")
|
||||
assert "createDocScreen({" in tabs and "copy: { route: (k, p) => skDocPath(" in tabs
|
||||
assert "createStackScreen({" in tabs and "copy: { route: (k, p) => skDocPath(" in tabs
|
||||
assert "/m02/layers/${scope.layer}/sangeun/${encodeURIComponent(key)}/doc${tail}" in tabs
|
||||
assert "admin: opt.edit" in tabs # 층 쓰기 권한 = 고침
|
||||
scr = _src("A00_Common/formula_doc_screen.ts")
|
||||
scr = _src("A00_Common/line_stack_screen.ts") # 804-6 수식 탭 = 줄 쌓기
|
||||
assert "cp ? cp.route(key, path) : opt.base + path" in scr
|
||||
assert "{ 문서: doc, 끊음: cut, 판: version }" in scr # 저장 몸
|
||||
detail = _src("M02_MasterTemplete/M02_MasterTemplete_Sangeun_Detail.ts")
|
||||
@@ -59,7 +59,7 @@ def test_길_앞머리_M02_공용화면():
|
||||
assert not (ROOT / "M02_MasterTemplete/M02_MasterTemplete_Sangeun_Equation.ts").exists()
|
||||
main = _src("main.py")
|
||||
assert '__import__("M02_MasterTemplete.M02_Doc_Screen", fromlist=["router"]).router' in main
|
||||
for name in ("formula_doc_screen", "formula_doc_sub", "formula_doc_copy", "formula_doc_edit"):
|
||||
for name in ("line_stack_screen", "formula_doc_copy"):
|
||||
assert len(_src(f"A00_Common/{name}.ts").splitlines()) <= 700, name
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ def test_권한_회사층_일반계정_읽기만(world):
|
||||
)
|
||||
assert any(c["키"] == "GC000267" for c in found["후보"])
|
||||
assert "줄" in screen.doc_table("company", key, "QC000431", None, _session())
|
||||
scr = _src("A00_Common/formula_doc_screen.ts")
|
||||
scr = _src("A00_Common/line_stack_screen.ts")
|
||||
assert "buildOptions(doc, given, !!cp && !opt.admin," in scr # 사본 읽기만 = 옵션 잠금
|
||||
copy_src = _src("A00_Common/formula_doc_copy.ts")
|
||||
assert "if (!edit) return [];" in copy_src and 'createBadge(ft("Read_Only")' in copy_src
|
||||
|
||||
@@ -209,16 +209,13 @@ def _src(rel: str) -> str:
|
||||
def test_화면_이음():
|
||||
lab = _src("M01_MasterData/M01_MasterData_UI_LogicLab.ts")
|
||||
assert 'createStackScreen({ base: "/m01/logic/doc", admin, cache: "m01_doc_drafts" })' in lab
|
||||
assert (
|
||||
"stack: stack.root" in lab
|
||||
and "equation.canLeave().then((ok) => ok && stack.canLeave())" in lab
|
||||
)
|
||||
assert '{ value: "stack", label: lt("Tab") }' in _src(
|
||||
assert "stack: stack.root" in lab and "=> stack.canLeave();" in lab # 804-6 수식 탭 = 줄 쌓기
|
||||
assert '{ value: "stack", label: tl("View_Equation") }' in _src(
|
||||
"M01_MasterData/M01_MasterData_UI_LogicLab_View.ts"
|
||||
)
|
||||
assert '[data-view="stack"]' in _src("M01_MasterData/M01_MasterData_UI_LogicLab_Style.css")
|
||||
tabs = _src("M02_MasterTemplete/M02_MasterTemplete_Sangeun_Tabs.ts")
|
||||
assert 'cache: "m02_sk_doc_drafts"' in tabs and tabs.count("skDocPath(opt.scope, k, p)") == 2
|
||||
assert 'cache: "m02_sk_doc_drafts"' in tabs and tabs.count("skDocPath(opt.scope, k, p)") == 1
|
||||
vite = _src("vite.config.ts")
|
||||
assert 'exclude: ["0_old", "katex"]' in vite and "katex/dist/katex.mjs" in vite
|
||||
pkg = json.loads(_src("config/package.json"))
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
"""804-6(요구 686-1) — 옛 수식 문서 탭 걷음 · 줄 쌓기 = 첫 「수식」 탭 지킴.
|
||||
|
||||
① 걷은 파일 없고 부르는 곳 없음 ② M01 · M02 보기 = 수식(줄 쌓기) · 단가산출 상세
|
||||
③ 줄 쌓기가 사본 [단가 갱신] · [재생성] · 판 바뀜 다시 저장을 이어 받음.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
GONE = [
|
||||
"A00_Common/formula_doc_screen.ts",
|
||||
"A00_Common/formula_doc_defs.ts",
|
||||
"A00_Common/formula_doc_edit.ts",
|
||||
"A00_Common/formula_doc_lines.ts",
|
||||
"A00_Common/formula_doc_math.ts",
|
||||
"A00_Common/formula_doc_math_model.ts",
|
||||
"A00_Common/formula_doc_rows.ts",
|
||||
"A00_Common/formula_doc_sub.ts",
|
||||
"A00_Common/formula_doc.css",
|
||||
"A00_Common/sheet_formula_cell.ts",
|
||||
"M01_MasterData/M01_MasterData_UI_LogicLab_Equation.ts",
|
||||
"M01_MasterData/M01_MasterData_UI_LogicLab_Equation.css",
|
||||
"M01_MasterData/M01_MasterData_UI_LogicLab_EquationDefs.ts",
|
||||
"M01_MasterData/M01_MasterData_UI_LogicLab_EquationVar.ts",
|
||||
"M01_MasterData/logic/M01_Logic_Equation_Model.ts",
|
||||
"ui_template/ui_template_equation_defs.ts",
|
||||
"ui_template/ui_template_equation_edit.ts",
|
||||
]
|
||||
|
||||
|
||||
def _text(rel: str) -> str:
|
||||
return (ROOT / rel).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_걷은_파일_없고_부르는_곳_없음():
|
||||
assert not [g for g in GONE if (ROOT / g).exists()]
|
||||
names = [Path(g).name.rsplit(".", 1)[0] for g in GONE]
|
||||
out = subprocess.run(
|
||||
["git", "-c", "core.quotepath=off", "ls-files", "*.ts", "*.css", "*.html"],
|
||||
cwd=ROOT, capture_output=True, text=True, encoding="utf-8", check=True,
|
||||
).stdout # fmt: skip
|
||||
for rel in out.splitlines():
|
||||
if rel.startswith(("docs/", "tmp/")) or not (ROOT / rel).exists():
|
||||
continue
|
||||
text = (ROOT / rel).read_text(encoding="utf-8", errors="ignore")
|
||||
for n in names:
|
||||
assert f'/{n}"' not in text and f"{n}.css" not in text, (rel, n)
|
||||
|
||||
|
||||
def test_보기_수식은_줄쌓기_첫탭():
|
||||
for rel in (
|
||||
"M01_MasterData/M01_MasterData_UI_LogicLab_View.ts",
|
||||
"M02_MasterTemplete/M02_MasterTemplete_Sangeun_Tabs.ts",
|
||||
):
|
||||
src = _text(rel)
|
||||
assert '{ value: "stack", label: tl("View_Equation") },' in src, rel
|
||||
assert 'value: "stack",\n' in src and '"equation"' not in src, rel
|
||||
lab = _text("M01_MasterData/M01_MasterData_UI_LogicLab.ts")
|
||||
assert "createStackScreen({" in lab and "createDocScreen" not in lab
|
||||
|
||||
|
||||
def test_줄쌓기가_사본_할일_이어받음():
|
||||
src = _text("A00_Common/line_stack_screen.ts")
|
||||
assert "copyTools(true, (job) => void runJob(job))" in src
|
||||
assert 'call<JobReply>("/preview", { 할일: job })' in src
|
||||
assert "e.status !== 409" in src and "#끊음" not in src
|
||||
assert len(src.splitlines()) <= 700
|
||||
Reference in New Issue
Block a user