From 9ca31ef7e85ec1cd6755cd258c3954009e71c6df Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 25 Sep 2026 10:06:12 +0900 Subject: [PATCH] =?UTF-8?q?fix(M02):=20=EC=96=91=EC=8B=9D=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EA=B8=B0=20=EB=AA=A9=EB=A1=9D=EC=9D=B4=20?= =?UTF-8?q?=EC=84=9C=EB=B2=84=20=EB=AC=B6=EC=9D=8C(=EC=B8=B5=20=C2=B7=20?= =?UTF-8?q?=EC=82=AC=EB=9E=8C=20=C2=B7=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8)=EC=9D=84=20=EA=B7=B8=EB=8C=80=EB=A1=9C=20=ED=8E=B4?= =?UTF-8?q?=EC=84=9C=20=EB=B3=B4=EC=9E=84=20(PLAN=2010-1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0148XFUpPfpiuTjxF1EK9c95 --- .../M02_MasterTemplete_Api_Fetch.ts | 10 ---- .../M02_MasterTemplete_UI_Side.ts | 52 +++++++++++++------ 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts b/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts index 9656e6b5..df250b19 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts @@ -101,16 +101,6 @@ export const saveProjectAs = ( 이름: string, ): Promise => post(project(id, "save-as"), { to, 종류, 이름 }); -export interface SourceItem { - from: Layer; - label?: string; - user_id?: string; - project_id?: string; - 종류?: Kind; - 이름?: string; - [key: string]: unknown; -} - export const fetchSources = (id: string): Promise => call(`/projects/${enc(id)}/sources`); /** 설계값을 채운 표 문서 — 서버가 그때그때 채움 · 저장 안 함 */ diff --git a/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts b/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts index 4834a141..f2a5256b 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts @@ -91,17 +91,35 @@ const why = (error: unknown): string => (error instanceof Error ? error.message const failed = (error: unknown): void => showToast(L("M02_ActionFailed").replace("{value}", why(error)), "error"); -/** 가져올 곳 목록 — 모양이 배열이든 묶음 객체든 한 줄씩 펴서 받음(길이 채워지면 맞춤) */ -function flatten(raw: unknown): Record[] { - if (Array.isArray(raw)) { - return raw.filter((x): x is Record => !!x && typeof x === "object"); +type ApplyFrom = Parameters[1]; +interface Source { + label: string; + body: ApplyFrom; +} + +/** 가져올 곳 — 서버 `sources` 는 층마다 묶음 · 개인·프로젝트는 사람·프로젝트 아래 양식 목록 */ +function sourceItems(raw: unknown): Source[] { + const group = (raw ?? {}) as Record[] | undefined>; + const layerName: Record = { + system: L("M02_LayerSystem"), + company: L("M02_LayerCompany"), + personal: L("M02_LayerPersonal"), + project: L("M02_LayerProject"), + }; + const out: Source[] = []; + for (const from of ["system", "company", "personal", "project"] as const) { + for (const entry of group[from] ?? []) { + const templates = (Array.isArray(entry.양식) ? entry.양식 : [entry]) as TemplateInfo[]; + const owner = entry.name ? ` · ${String(entry.name)}` : ""; + for (const t of templates) { + const body: ApplyFrom = { from, 종류: t.종류, 이름: t.이름 }; + if (entry.user_id != null) body.user_id = String(entry.user_id); + if (entry.project_id != null) body.project_id = String(entry.project_id); + out.push({ label: `${layerName[from]}${owner} · ${t.이름}`, body }); + } + } } - if (raw && typeof raw === "object") { - return Object.entries(raw).flatMap(([from, v]) => - flatten(v).map((item) => ({ from: item.from ?? from, ...item })), - ); - } - return []; + return out; } export function buildSide(opt: SideOptions): SideHandle { @@ -337,9 +355,9 @@ export function buildSide(opt: SideOptions): SideHandle { } }); projectButton(L("M02_ProjectImport"), async () => { - let sources: Record[] = []; + let sources: Source[] = []; try { - sources = flatten(await fetchSources(projectId)); + sources = sourceItems(await fetchSources(projectId)); } catch (error) { return failed(error); } @@ -352,12 +370,14 @@ export function buildSide(opt: SideOptions): SideHandle { body.append(el("p", { className: "m02-side__empty", text: L("M02_ImportNone") })); } for (const src of sources) { - const text = String(src.label ?? src.이름 ?? src.from ?? JSON.stringify(src)); - const b = el("button", { className: "m02-side__item", text, attrs: { type: "button" } }); + const b = el("button", { + className: "m02-side__item", + text: src.label, + attrs: { type: "button" }, + }); b.addEventListener("click", () => { close(); - const { label: _label, ...rest } = src; - void act(() => applyToProject(projectId, rest as never)); + void act(() => applyToProject(projectId, src.body)); }); body.append(b); }