feat(M02): 구조물 옵션 정의 = 정의 그룹 꼴 종류도 이름 나무 · 옛 편집기 모든 종류에서 숨김(52-12)
- 명세 없는 종류 = 그룹 제목(그룹.이름) › 칸 이름(옵션 label) › 선택지 이름(종류.이름 `{옵션}={값}` · 값 그대로) · 그룹 밖 칸은 머리 줄 아래
- 칸 더하기 · 빼기 · 꼴 · 필수는 읽기만 · 칸 없는 종류(개거 · 노출형 횡단수로)는 「고칠 이름 없음」 · 종류 이름은 머리 칸
- 옛 편집기(옵션 · 배치 · 그룹 · 규칙 · 기준 측점)는 OLD_EDITOR 거짓으로 숨김(코드 그대로)
- 미리보기 = B05 칸 부품(field · optionControl · 그룹 상자)으로 같은 차례
- B05 · B06 고르기 칸 보기 글 = 정의 이름 표(값 그대로 · 규칙 선택지 · 시설 폼 덧보기 포함)
- 시험: test_m02_so_def_spec 정의 그룹 꼴 더함 · 헬퍼가 이웃 TS 를 읽게 고침 · ui_checks/52-11 에 맹암거 · 바닥막이 · 개거 더함
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UoSr2sqvYtBf1dtQdus88s
This commit is contained in:
@@ -6,25 +6,29 @@
|
||||
* · 이름 자리 = 정의 `종류.{종류}.이름`(키 `{컨테이너}` · `{컨테이너}.{항목}` · `{컨테이너}.{항목}={값}`)
|
||||
* · 필수 컨테이너 제목 = 이름 표에 없으면 정의 그룹(`그룹.{종류}` 의 `id = link`) 이름 — B05 그리기
|
||||
* (`containerTitle`)와 같은 차례로 읽고 그 자리에 씀
|
||||
* · 명세 없는 종류(정의 그룹 꼴 · 52-12) = 그룹 제목(`그룹.이름`) › 칸 이름(옵션 `label`) ›
|
||||
* 선택지 이름(이름 표 키 `{옵션}={값}` · 값은 그대로) — 그룹 밖 칸은 맨 앞 머리 줄 아래
|
||||
* import 는 꼴만 — 시험이 이 파일만 옮겨 돌림.
|
||||
* ========================================================================== */
|
||||
|
||||
import type { StructureSpec } from "../../A00_Common/design/design_structure_spec";
|
||||
import type { StructDef } from "./M02_SO_Def_Model";
|
||||
import type { StructDef, TypeDef } from "./M02_SO_Def_Model";
|
||||
|
||||
export interface SpecNameRow {
|
||||
/** 0 = 컨테이너 · 1 = 항목 · 2 = 값 */
|
||||
level: 0 | 1 | 2;
|
||||
/** 이름 표 키 */
|
||||
/** 이름 표 키 — 빈 글 = 고칠 이름 없는 머리 줄(그룹 밖 칸) */
|
||||
nameKey: string;
|
||||
/** 읽기만 표시 — 컨테이너 id · 항목 id · 값 */
|
||||
key: string;
|
||||
/** 지금 이름 */
|
||||
label: string;
|
||||
/** 읽기만 표시 — 필수/선택 · 꼴 */
|
||||
tag: "required" | "optional" | "select" | "number" | "auto" | null;
|
||||
tag: "required" | "optional" | "select" | "number" | "auto" | "text" | "bool" | null;
|
||||
/** 필수 컨테이너 제목이 정의 그룹 이름에서 옴 — 고치면 그 그룹 이름에 씀 */
|
||||
group: string | null;
|
||||
/** 정의 옵션 이름(`label`)에서 옴 — 고치면 그 옵션 이름에 씀 */
|
||||
option: string | null;
|
||||
}
|
||||
|
||||
/** 명세 차례대로 이름 줄 — 같은 이름 키(갈래마다 겹친 값)는 한 줄. */
|
||||
@@ -48,6 +52,7 @@ export function specNameRows(def: StructDef, spec: StructureSpec): SpecNameRow[]
|
||||
label: names[c.id] ?? group?.이름 ?? c.title,
|
||||
tag: c.required ? "required" : "optional",
|
||||
group: group ? group.id : null,
|
||||
option: null,
|
||||
});
|
||||
for (const item of c.items) {
|
||||
const itemKey = `${c.id}.${item.id}`;
|
||||
@@ -58,6 +63,7 @@ export function specNameRows(def: StructDef, spec: StructureSpec): SpecNameRow[]
|
||||
label: names[itemKey] ?? item.label,
|
||||
tag: item.kind,
|
||||
group: null,
|
||||
option: null,
|
||||
});
|
||||
const choices = [
|
||||
...(item.choices ?? []),
|
||||
@@ -72,6 +78,7 @@ export function specNameRows(def: StructDef, spec: StructureSpec): SpecNameRow[]
|
||||
label: names[choiceKey] ?? ch.label,
|
||||
tag: null,
|
||||
group: null,
|
||||
option: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -79,8 +86,67 @@ export function specNameRows(def: StructDef, spec: StructureSpec): SpecNameRow[]
|
||||
return rows;
|
||||
}
|
||||
|
||||
/** 이름 하나를 사본에 씀 — 그룹에서 온 제목은 그 그룹 이름 · 나머지는 이름 표. */
|
||||
/** 정의 그룹 꼴 종류(명세 없음) 이름 줄 — 그룹 밖 칸 · 그룹마다 제목 › 칸 › 선택지(B05 그리기 차례). */
|
||||
export function groupNameRows(def: StructDef, type: TypeDef): SpecNameRow[] {
|
||||
const names = def.종류[type.type_id]?.이름 ?? {};
|
||||
const options = type.options.filter((o) => o.enabled !== false);
|
||||
const groups = def.그룹[type.type_id] ?? [];
|
||||
const inGroup = new Set(groups.flatMap((g) => g.옵션));
|
||||
const rows: SpecNameRow[] = [];
|
||||
const optionRows = (keys: readonly string[]): void => {
|
||||
for (const o of options.filter((x) => keys.includes(x.key))) {
|
||||
rows.push({
|
||||
level: 1,
|
||||
nameKey: o.key,
|
||||
key: o.key,
|
||||
label: o.label,
|
||||
tag: o.input,
|
||||
group: null,
|
||||
option: o.key,
|
||||
});
|
||||
for (const ch of o.input === "select" ? (o.choices ?? []) : []) {
|
||||
const nameKey = `${o.key}=${ch}`;
|
||||
rows.push({
|
||||
level: 2,
|
||||
nameKey,
|
||||
key: ch,
|
||||
label: names[nameKey] ?? ch,
|
||||
tag: null,
|
||||
group: null,
|
||||
option: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const loose = options.filter((o) => !inGroup.has(o.key)).map((o) => o.key);
|
||||
if (loose.length) {
|
||||
rows.push({ level: 0, nameKey: "", key: "", label: "", tag: null, group: null, option: null });
|
||||
optionRows(loose);
|
||||
}
|
||||
for (const g of groups) {
|
||||
rows.push({
|
||||
level: 0,
|
||||
nameKey: `#${g.id}`,
|
||||
key: g.id,
|
||||
label: g.이름,
|
||||
tag: null,
|
||||
group: g.id,
|
||||
option: null,
|
||||
});
|
||||
optionRows(g.옵션);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/** 이름 하나를 사본에 씀 — 그룹에서 온 제목은 그 그룹 이름 · 옵션 칸은 옵션 이름 · 나머지는 이름 표. */
|
||||
export function setSpecName(def: StructDef, typeId: string, row: SpecNameRow, value: string): void {
|
||||
const option = row.option
|
||||
? def.types.find((t) => t.type_id === typeId)?.options.find((o) => o.key === row.option)
|
||||
: undefined;
|
||||
if (option) {
|
||||
option.label = value;
|
||||
return;
|
||||
}
|
||||
const group = row.group ? def.그룹[typeId]?.find((g) => g.id === row.group) : undefined;
|
||||
if (group) {
|
||||
group.이름 = value;
|
||||
|
||||
Reference in New Issue
Block a user