feat(b08): 라이브러리 가져오기 목록에 항목 종류 배지 [양식형]·[고정형] — 명세 13장대로 식이 한 줄이라도 있나로만 가름(저장된 item_kind 표시는 안 믿음)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
This commit is contained in:
@@ -44,10 +44,26 @@ def _items(folder: Path) -> list[dict[str, Any]]:
|
||||
return [json.loads(p.read_text(encoding="utf-8")) for p in sorted(folder.glob("*.json"))]
|
||||
|
||||
|
||||
def item_kind(item: dict[str, Any]) -> str:
|
||||
"""양식형(`form`) · 고정형(`fixed`) — 명세 13장: 칸은 같고 **식이 한 줄이라도 있나**로만 가름.
|
||||
저장된 `item_kind` 표시는 안 믿음 — 줄과 어긋나면 배지가 거짓이 됨."""
|
||||
return (
|
||||
"form"
|
||||
if any(str(row.get("formula") or "").strip() for row in item.get("rows") or [])
|
||||
else "fixed"
|
||||
)
|
||||
|
||||
|
||||
def list_items(dirs: dict[str, Path], type_id: str) -> list[dict[str, Any]]:
|
||||
"""가져오기 고르개 — 단마다 그 종류의 항목(단·코드·이름)."""
|
||||
"""가져오기 고르개 — 단마다 그 종류의 항목(단·코드·이름·종류)."""
|
||||
return [
|
||||
{"tier": tier, "code": item.get("code"), "name": item.get("name"), "type_id": type_id}
|
||||
{
|
||||
"tier": tier,
|
||||
"code": item.get("code"),
|
||||
"name": item.get("name"),
|
||||
"type_id": type_id,
|
||||
"kind": item_kind(item),
|
||||
}
|
||||
for tier in TIERS
|
||||
if tier in dirs
|
||||
for item in _items(dirs[tier])
|
||||
|
||||
@@ -10,11 +10,14 @@
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
|
||||
const TIER_LABELS: Record<string, string> = { personal: "개인", company: "회사", program: "기본" };
|
||||
/** 항목 종류 배지 — 양식형 = 제원을 바꾸면 수량이 다시 남 · 고정형 = 박힌 수량(명세 13장). */
|
||||
const KIND_LABELS: Record<string, string> = { form: "양식형", fixed: "고정형" };
|
||||
|
||||
interface LibraryItem {
|
||||
tier: string;
|
||||
code: string;
|
||||
name: string;
|
||||
kind: string;
|
||||
}
|
||||
|
||||
/** 장 머리의 양식 표시 — **어느 단에서 가져왔나** + **그 뒤 고쳤나**(지금 읽는 단이 아님). */
|
||||
@@ -92,7 +95,8 @@ export function buildLibraryPanel(options: LibraryPanelOptions): HTMLElement {
|
||||
const option = document.createElement("option");
|
||||
option.value = `${item.tier}|${item.code}`;
|
||||
const now = item.code === currentCode ? " (지금)" : "";
|
||||
option.textContent = `${TIER_LABELS[item.tier] ?? item.tier} · ${item.name}${now}`;
|
||||
const kind = KIND_LABELS[item.kind] ?? item.kind;
|
||||
option.textContent = `${TIER_LABELS[item.tier] ?? item.tier} · [${kind}] ${item.name}${now}`;
|
||||
return option;
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -216,6 +216,26 @@ def test_확정_때_기본_양식을_박는다(project: Path) -> None:
|
||||
assert library_module.pin_program_templates(project) == 0 # 이미 박힌 것은 그대로
|
||||
|
||||
|
||||
def test_항목마다_양식형_고정형_종류가_붙는다(tmp_path: Path) -> None:
|
||||
"""PLAN 4장 「항목마다 종류 배지」 — 명세 13장: 칸은 같고 `formula` 유무로만 갈림."""
|
||||
folder = tmp_path / "personal"
|
||||
folder.mkdir()
|
||||
fixed = {
|
||||
"type_id": "masonry_wet",
|
||||
"code": "AX-ST-0000beef",
|
||||
"name": "뽑은 항목",
|
||||
"rows": [{"name": "돌쌓기", "formula": "", "amount": 20.9}],
|
||||
}
|
||||
(folder / "AX-ST-0000beef.json").write_text(json.dumps(fixed), encoding="utf-8")
|
||||
dirs = {"personal": folder, "program": library_module.TEMPLATE_DIR}
|
||||
kinds = {item["tier"]: item["kind"] for item in library_module.list_items(dirs, "masonry_wet")}
|
||||
assert kinds == {"personal": "fixed", "program": "form"}
|
||||
ui = (ROOT / "B08_Quantity" / "B08_Quantity_UI_StructureSheet_Library.ts").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert "양식형" in ui and "고정형" in ui and "item.kind" in ui
|
||||
|
||||
|
||||
def test_코드_모양이_아니면_박지_않는다(project: Path) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
library_module.import_item(project, {"type_id": "masonry_wet", "code": "../x"}, "personal")
|
||||
|
||||
Reference in New Issue
Block a user