feat(716-1·716-2): 옵션 칸 위 구분선 부품 · 시험 정리
- M01 로직 칸 아래 구분선 = 부품 createDivider - 시험 셋 새 꼴로: 대시보드 줄 칸별(M01 3 · M02 3 · 계산 자리) · ☰ 페이지 둘(역할별) · 옛 open=옵션 돌려보냄 · M01 open 인자 - 낡은 시험 고침 까닭: 옵션 줄이 M01 로 옮겨 카드 순서 · 해시가 바뀜(test_b01_settings_cards · test_197_1 · test_309_2) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
import { createSelectField, el, showToast } from "@ui/ui_template_elements";
|
||||
import { attachCollapsible } from "@ui/ui_template_collapsible";
|
||||
import { createDivider } from "@ui/ui_template_divider";
|
||||
import { currentLanguageIndex, t as L } from "@ui/ui_template_locale";
|
||||
import {
|
||||
buildOptionsSection,
|
||||
@@ -501,7 +502,7 @@ ${first.file}`
|
||||
const optionsSec = section(options.title, options.body);
|
||||
const root = el("div", {
|
||||
className: "m01-side ui-sidebar-panel",
|
||||
children: [...groups, logic, el("hr", { className: "ui-sidebar-divider" }), optionsSec],
|
||||
children: [...groups, logic, createDivider(), optionsSec],
|
||||
});
|
||||
attachCollapsible(root);
|
||||
void Promise.all(GROUPS.filter((g) => g !== FUEL_GROUP).map(refresh)).catch((error) =>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
"""197-1 대시보드 「구조물 옵션」 카드 → M02 「구조물 옵션 정의」 화면이 바로 열림 시험 — 조작은 사용자.
|
||||
"""197-1 · 716-1 대시보드 「구조물 옵션 정의」 줄 → M01 「구조물 옵션 정의」 화면이 바로 열림 시험 — 조작은 ORCA.
|
||||
|
||||
716-1 — 화면 입구가 M02 에서 M01 로 옮겨감(화면 코드 · 서버 길은 M02 폴더 그대로) · 옛 M02 `open=옵션` 주소는
|
||||
시스템 관리자면 M01 `?open=옵션` 으로 돌려보냄.
|
||||
|
||||
원인 — 진입 해시 `open=옵션` 이 옵션 줄을 눌러 정의 화면을 띄우는 사이 첫 화면(집계표)의 `mount` 가
|
||||
모듈 · 번호를 기다리다 뒤늦게 끝나 정의 화면 위에 집계표를 덮음(`mount` 에 낡음 검사 없었음).
|
||||
|
||||
· 카드 셋 → 해시(open=구조물조합 · 옵션 · 도면) · 해시 → 진입(`entryFromHash`) Node 로 바로 돌림
|
||||
· `reveal` 가 옵션만 줄을 누르고 도면은 펼치기만 · 구조물조합은 아무것도 안 함
|
||||
· 줄 → 해시(M01 open=로직 · 옵션 / M02 open=일위대가조합 · 구조물조합 · 도면) · 해시 → 진입(`entryFromHash`) Node
|
||||
· M02 `reveal` 가 옵션만 줄을 누르고 도면은 펼치기만 · 구조물조합은 아무것도 안 함 · M01 `reveal` 도 같은 꼴
|
||||
· 옛 `open=옵션` 돌려보냄(`redirectOldOptions`)
|
||||
· `mount` 집계표 갈래(진짜 소스 조각)를 Node 로 돌림 — 기다리는 사이 다른 화면이 열리면 그리지 않음
|
||||
"""
|
||||
|
||||
@@ -41,16 +45,19 @@ def _run(script: str, *args: str) -> object:
|
||||
|
||||
|
||||
@needs_node
|
||||
def test_카드_셋_해시():
|
||||
def test_줄_해시_옵션은_M01():
|
||||
from test_b01_settings_cards import _cards
|
||||
|
||||
cards = _cards({"role": "SYSTEM_ADMIN", "is_master": False}, 3)
|
||||
assert [c[2].split("?")[1].split("&")[0] for c in cards[1:4]] == [
|
||||
"open=구조물조합",
|
||||
"open=옵션",
|
||||
"open=도면",
|
||||
heads = [c[2].split("?")[0] + "?" + c[2].split("?")[1].split("&")[0] for c in cards[1:6]]
|
||||
assert heads == [
|
||||
"m01-master-data?open=로직",
|
||||
"m01-master-data?open=옵션",
|
||||
"m02-master-template?open=일위대가조합",
|
||||
"m02-master-template?open=구조물조합",
|
||||
"m02-master-template?open=도면",
|
||||
]
|
||||
assert all("&root=master" in c[2] for c in cards[1:4])
|
||||
assert all("&root=master" in c[2] for c in cards[3:6])
|
||||
|
||||
|
||||
@needs_node
|
||||
@@ -69,7 +76,7 @@ def test_해시_진입_셋():
|
||||
+ fn.group(0).replace("export function", "function")
|
||||
+ "\nconsole.log(JSON.stringify(entryFromHash(null)));"
|
||||
)
|
||||
for want in ("구조물조합", "옵션", "도면"):
|
||||
for want in ("구조물조합", "옵션", "도면", "일위대가조합"):
|
||||
got = _run(script, f"open={want}&root=master&company=3")
|
||||
assert got["open"] == want and got["root"] == "master" and got["company"] == "3"
|
||||
|
||||
@@ -139,3 +146,38 @@ def test_집계표_갈래_기다리는_사이_다른_화면이_열리면_그리
|
||||
assert got["none"] == ["create", "panel:set"] # 안 끼어들면 그대로 그림
|
||||
assert got["mod"] == ["panel:null"] # 모듈 기다리는 사이 다른 화면 — 그리지 않음
|
||||
assert got["num"] == ["panel.destroy", "panel:null"] # 번호 기다리는 사이 — 패널도 버림
|
||||
|
||||
|
||||
@needs_node
|
||||
def test_옛_옵션_주소_M01로_돌려보냄():
|
||||
layer = _text(M02 / "M02_MasterTemplete_Layer.ts")
|
||||
fn = re.search(r"^export function redirectOldOptions\([\s\S]*?^}", layer, re.M)
|
||||
assert fn, "redirectOldOptions 를 못 찾음"
|
||||
script = (
|
||||
"const currentQuery = () => new URLSearchParams(process.argv[1]);\n"
|
||||
"const ROUTES = { M01_MASTER_DATA: 'm01' }; const sent: string[] = [];\n"
|
||||
"const navigateTo = (r: string, q: any) => sent.push(r + JSON.stringify(q));\n"
|
||||
"type SessionUser = any;\n"
|
||||
+ fn.group(0).replace("export function", "function")
|
||||
+ "\nconst a = redirectOldOptions({ role: 'SYSTEM_ADMIN' });"
|
||||
+ "\nconst b = redirectOldOptions({ role: 'USER' });"
|
||||
+ "\nconst c = redirectOldOptions(null);"
|
||||
+ "\nconsole.log(JSON.stringify([a, b, c, sent]));"
|
||||
)
|
||||
assert _run(script, "open=옵션&root=master") == [True, False, False, ['m01{"open":"옵션"}']]
|
||||
# 옵션이 아니면 안 돌려보냄
|
||||
assert _run(script, "open=도면&root=master") == [False, False, False, []]
|
||||
page = _text(M02 / "M02_MasterTemplete_UI_Page.ts")
|
||||
assert "if (redirectOldOptions(user))" in page
|
||||
assert 'mountSettingsDrawer(user ?? {}, "m02", entry.company);' in page
|
||||
|
||||
|
||||
def test_M01_open_인자_로직_옵션():
|
||||
m01 = ROOT / "M01_MasterData"
|
||||
page = _text(m01 / "M01_MasterData_UI_Page.ts")
|
||||
assert 'if (want === "로직" || want === "옵션") side.reveal(want);' in page
|
||||
assert "setLeaveGuard(leaveOptions)" in page # 저장 안 한 정의 고침 — 떠날 때 물음
|
||||
side = _text(m01 / "M01_MasterData_UI_Side.ts")
|
||||
assert "buildOptionsSection({ ...optionsOpt, isAdmin: true })" in side
|
||||
# 로직 칸 아래 구분선 부품 + 옵션 칸
|
||||
assert "logic, createDivider(), optionsSec" in side
|
||||
|
||||
@@ -263,7 +263,7 @@ def test_카드_시스템_관리자만_글_다_있음():
|
||||
links = nav.split("export function mountSettingsDrawer")[0]
|
||||
admin, rest = links.split('if (user.role === "SYSTEM_ADMIN") {')[1].split("// 회사 수정 =")
|
||||
assert 'key: "calcSites"' in admin and "calcSites" not in rest
|
||||
assert 'settingLinks(user, companyId).filter((link) => link.key !== "calcSites")' in nav
|
||||
assert "calcSites" not in nav.split("export function pageLinks")[1] # ☰ 는 페이지 둘만(716-2)
|
||||
page = _text("B01_Dashboard/B01_Dashboard_UI_View_SysDefaults.ts")
|
||||
assert 'link.key === "calcSites" ? void openCalcSitesDialog()' in page
|
||||
locale = _text("ui_template/ui_template_locale_m1.ts")
|
||||
|
||||
@@ -58,7 +58,36 @@ def _cards(user: dict, company_id: int | None = None) -> list:
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def _pages(user: dict, company_id: int | None = None) -> list:
|
||||
# ☰ 메뉴 = pageLinks(settingLinks 의 구조물 조합 줄을 바탕으로 페이지 둘만)
|
||||
script = (
|
||||
"const ROUTES = { M01_MASTER_DATA: 'm01-master-data',"
|
||||
" M02_MASTER_TEMPLATE: 'm02-master-template', B01_ACCOUNT: 'b01-account' };\n"
|
||||
"const L = (k: string) => k;\n"
|
||||
"let went = '';\n"
|
||||
"const navigateTo = (r: string, q?: Record<string, string>) =>"
|
||||
" { went = r + (q ? '?' + new URLSearchParams(q) : ''); };\n"
|
||||
+ _fn(_text(NAV), "settingLinks")
|
||||
+ "\n"
|
||||
+ _fn(_text(NAV), "pageLinks")
|
||||
+ "\nconst user = JSON.parse(process.argv[1]);"
|
||||
+ "\nconst links = pageLinks(user, JSON.parse(process.argv[2]));"
|
||||
+ "\nconsole.log(JSON.stringify(links.map((l: any) => {"
|
||||
+ " navigateTo(l.route, l.query); return [l.key, l.title, decodeURIComponent(went)]; })));"
|
||||
)
|
||||
result = subprocess.run(
|
||||
["node", "--experimental-strip-types", "--no-warnings",
|
||||
"--input-type=module-typescript", "-e", script, json.dumps(user), json.dumps(company_id)],
|
||||
capture_output=True, text=True, encoding="utf-8", timeout=60,
|
||||
) # fmt: skip
|
||||
assert result.returncode == 0, result.stderr
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
M01 = "m01-master-data"
|
||||
M02 = "m02-master-template"
|
||||
READ_SRC = "B01_Dashboard_PermSourceRead"
|
||||
WRITE_M = "B01_Dashboard_PermMasterWrite"
|
||||
# 계산 자리(504-2) — 시스템 관리자만 · 이동 대신 창
|
||||
CALC_SITES = ["B01_CalcSites_Title", "B01_CalcSites_Desc", "calc-sites-dialog"]
|
||||
READ_CO = (
|
||||
@@ -68,21 +97,40 @@ WRITE_CO = READ_CO.replace("CompanyRead", "CompanyWrite")
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
||||
def test_시스템_관리자_카드_다섯_고른_회사_해시():
|
||||
m = "B01_Dashboard_PermMasterWrite"
|
||||
def test_시스템_관리자_줄_칸별_일곱_고른_회사_해시():
|
||||
# 716-2 — 대시보드 설계 기본값 = 칸별 줄: M01 3(마스터 요소 · 단가산출 로직 · 구조물 옵션 정의) +
|
||||
# M02 3(일위대가 · 구조물 조합 · 도면 양식) + 계산 자리
|
||||
assert _cards({"role": "SYSTEM_ADMIN", "is_master": False}, 3) == [
|
||||
["B01_Dashboard_MasterElements", "B01_Dashboard_PermSourceRead", "m01-master-data"],
|
||||
["B01_Dashboard_CardStructCombo", m, f"{M02}?open=구조물조합&root=master&company=3"],
|
||||
["B01_Dashboard_CardStructOption", m, f"{M02}?open=옵션&root=master&company=3"],
|
||||
["B01_Dashboard_CardDrawing", m, f"{M02}?open=도면&root=master&company=3"],
|
||||
["M01_Title", READ_SRC, M01],
|
||||
["B01_Dashboard_CardLogic", READ_SRC, f"{M01}?open=로직"],
|
||||
["B01_Dashboard_CardStructOptionDef", WRITE_M, f"{M01}?open=옵션"],
|
||||
["B01_Dashboard_CardPrecombo", WRITE_M, f"{M02}?open=일위대가조합&root=master&company=3"],
|
||||
["B01_Dashboard_CardStructCombo", WRITE_M, f"{M02}?open=구조물조합&root=master&company=3"],
|
||||
["B01_Dashboard_CardDrawing", WRITE_M, f"{M02}?open=도면&root=master&company=3"],
|
||||
CALC_SITES,
|
||||
]
|
||||
# 회사가 없으면 해시에 안 실음
|
||||
assert _cards({"role": "SYSTEM_ADMIN", "is_master": False})[1][2] == (
|
||||
assert _cards({"role": "SYSTEM_ADMIN", "is_master": False})[4][2] == (
|
||||
f"{M02}?open=구조물조합&root=master"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
||||
def test_메뉴_페이지_둘만_역할별():
|
||||
# 716-2 — ☰ = M01 · M02 두 페이지(시스템 관리자) / M02 한 페이지(그 밖) · 열쇠 m01 · m02
|
||||
admin = _pages({"role": "SYSTEM_ADMIN", "is_master": False, "company_id": 1}, 3)
|
||||
assert admin == [
|
||||
["m01", "B01_Dashboard_MasterElements", M01],
|
||||
["m02", "M02_Title", f"{M02}?open=구조물조합&root=personal&company=3"],
|
||||
]
|
||||
assert _pages({"role": "ADMIN", "is_master": False, "company_id": None}) == [
|
||||
["m02", "M02_Title", f"{M02}?open=구조물조합&root=company"],
|
||||
]
|
||||
assert _pages({"role": "USER", "is_master": False, "company_id": 1}) == [
|
||||
["m02", "M02_Title", f"{M02}?open=구조물조합&root=personal"],
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
||||
def test_회사_관리자_개인_카드_하나():
|
||||
company = [
|
||||
@@ -191,14 +239,12 @@ def test_회사_찾기_거르기():
|
||||
def test_구조물_조합_기본_층_개인():
|
||||
"""123-1 — 회사 있는 사람은 역할 무관 구조물 조합 = 개인 · 회사 없으면 지금 규칙 · 다른 곳 그대로 ·
|
||||
134-4 — 층 없는 주소도 개인(회사 없으면 마스터) · 사전조합 기본 층도 같은 규칙."""
|
||||
m = "B01_Dashboard_PermMasterWrite"
|
||||
combo = f"{M02}?open=구조물조합&root=personal"
|
||||
assert _cards({"role": "SYSTEM_ADMIN", "is_master": False, "company_id": 1}, 3) == [
|
||||
["B01_Dashboard_MasterElements", "B01_Dashboard_PermSourceRead", "m01-master-data"],
|
||||
["B01_Dashboard_CardStructCombo", m, f"{combo}&company=3"],
|
||||
["B01_Dashboard_CardStructOption", m, f"{M02}?open=옵션&root=master&company=3"],
|
||||
["B01_Dashboard_CardDrawing", m, f"{M02}?open=도면&root=master&company=3"],
|
||||
CALC_SITES,
|
||||
rows = _cards({"role": "SYSTEM_ADMIN", "is_master": False, "company_id": 1}, 3)
|
||||
assert rows[3:6] == [
|
||||
["B01_Dashboard_CardPrecombo", WRITE_M, f"{M02}?open=일위대가조합&root=personal&company=3"],
|
||||
["B01_Dashboard_CardStructCombo", WRITE_M, f"{combo}&company=3"],
|
||||
["B01_Dashboard_CardDrawing", WRITE_M, f"{M02}?open=도면&root=master&company=3"],
|
||||
]
|
||||
assert _cards({"role": "ADMIN", "is_master": False, "company_id": 1}) == [
|
||||
["B01_Dashboard_CardStructCombo", WRITE_CO, combo],
|
||||
@@ -206,7 +252,7 @@ def test_구조물_조합_기본_층_개인():
|
||||
assert _cards({"role": "USER", "is_master": True, "company_id": 1})[0][2] == combo
|
||||
assert _cards({"role": "USER", "is_master": False, "company_id": 1})[0][2] == combo
|
||||
# 개인 층 없음(회사 없음) = 지금 규칙
|
||||
assert _cards({"role": "SYSTEM_ADMIN", "is_master": False, "company_id": None})[1][2] == (
|
||||
assert _cards({"role": "SYSTEM_ADMIN", "is_master": False, "company_id": None})[4][2] == (
|
||||
f"{M02}?open=구조물조합&root=master"
|
||||
)
|
||||
assert _cards({"role": "ADMIN", "is_master": False, "company_id": None})[0][2] == (
|
||||
|
||||
Reference in New Issue
Block a user