feat(M02): 일위대가 사전조합 — 층 단추 따로 · 명시 owner · 구분 › 상세구분 2단 나무(134-3)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SE9MxeXTu2uaDZ55BJowAY
This commit is contained in:
2026-10-09 15:01:16 +09:00
co-authored by Claude Opus 5.5
parent 15f2e7c4f5
commit 66efaf2834
16 changed files with 466 additions and 94 deletions
@@ -46,6 +46,10 @@ export interface Selection {
name: string;
/** 화면 제목에 쓸 글 — 없으면 name 그대로(구조물 도면은 열 머리글) */
label?: string;
/** 사전조합 층(134-3 · 페이지 층과 따로) — 서버 길에 붙일 주인(null = 자기 층) · 고칠 권한 ·
* 없으면 페이지 층 것 */
owner?: string | null;
canWrite?: boolean;
}
interface EditorHandle {
@@ -243,9 +247,11 @@ export function createMain(
const empty = (text: string): void => {
host.replaceChildren(el("p", { className: "m02-main__empty", text }));
};
/** 고를 것마다 고칠 권한 — 사전조합 층은 고름에 실림(134-3) · 그 밖 페이지 층 */
const writable = (at: Selection): boolean => at.canWrite ?? canEdit(at.layer, isAdmin);
const bar = (): void => {
reload.hidden = !sel;
save.hidden = !sel || !canEdit(sel.layer, isAdmin);
save.hidden = !sel || !writable(sel);
back.hidden = !sel || !(sel.kind in NUMBER_FIELD);
nav.update(back.hidden ? null : sel); // 보임 조건 = 뒤로 단추와 같음
const kind = sel && sel.kind in HELP_TITLE ? (sel.kind as keyof typeof HELP_TITLE) : null;
@@ -345,7 +351,7 @@ export function createMain(
}
async function mount(doc: unknown, at: Selection): Promise<void> {
const readOnly = !canEdit(at.layer, isAdmin);
const readOnly = !writable(at);
host.replaceChildren();
if (at.kind === "table") {
const create = await findExport<(h: HTMLElement, d: unknown, o: object) => EditorHandle>(
@@ -424,7 +430,7 @@ export function createMain(
void open({ ...at, kind: "area" });
return true;
},
...(mode ? { mode } : {}),
...(mode ? { mode, owner: at.owner ?? null } : {}),
});
// [저장] = 엑셀에서 고른 칸 연결(면적 문서) 먼저 · 그다음 일위대가(서버가 새 칸 값으로 계산값)
editor = {
@@ -508,14 +514,16 @@ export function createMain(
editor = mountLibraryList(host, slot, {
layer: next.layer,
kind: next.kind,
canEdit: canEdit(next.layer, isAdmin),
owner: next.owner ?? null,
canEdit: writable(next),
open: (name, label) => void open({ ...next, name, label }),
changed: () => onSaved?.(),
});
return;
}
const stop = showLoading(host); // 0.3초 넘으면 상세 칸 안에 「불러오는 중」(PLAN 30-6)
try {
const got = await readTemplate(next.layer, next.kind, next.name, next.projectId);
const got = await readTemplate(next.layer, next.kind, next.name, next.projectId, next.owner);
if (mine !== seq) return;
version = got.판 ?? "";
loaded = got.문서;
@@ -563,7 +571,15 @@ export function createMain(
...(edited as Record<string, unknown>),
}) // + 저장 전 [보내기 취소] 연결(112-2)
: edited;
const info = await saveTemplate(at.layer, at.kind, at.name, at.projectId, version, doc);
const info = await saveTemplate(
at.layer,
at.kind,
at.name,
at.projectId,
version,
doc,
at.owner,
);
version = info.판;
loaded = doc;
dirty = false;