Merge remote-tracking branch 'origin/sub_laptop_7' into main_laptop_1
This commit is contained in:
@@ -54,7 +54,8 @@ function reason(detail: unknown, status: number): string {
|
||||
return lines.filter(Boolean).join(" · ") || `HTTP ${status}`;
|
||||
}
|
||||
|
||||
/** 지금 화면의 층 — 시스템 = 옛 길 그대로 · 회사 · 개인 = `/layers/{층}` 아래(구조물집계표 · 조합 길 모두) ·
|
||||
/** 지금 화면의 층 — 시스템 · 회사 · 개인 모두 `/layers/{층}` 아래(구조물집계표 · 조합 길 모두 · 읽기는
|
||||
* 로그인 누구나 · 쓰기는 서버 층 권한 · 옛 `/api/m02/templates/*` 는 시스템 관리자 전용이라 안 씀) ·
|
||||
* `owner` = 남의 층을 볼 때 주인(회사 `{C}` · 개인 `{C}/{U}` · 자기 층 = null · PLAN 27-1c) —
|
||||
* 지금 층 길에 `?owner=` 로 붙음(M02 화면을 떠나면 페이지가 시스템 · null 로 되돌림) */
|
||||
let activeLayer: Layer = "system";
|
||||
@@ -73,24 +74,20 @@ const owned = (layer: Layer, path: string): string =>
|
||||
? `${path}${path.includes("?") ? "&" : "?"}owner=${enc(activeOwner)}`
|
||||
: path;
|
||||
const scoped = <T>(path: string, init: RequestInit = {}): Promise<T> =>
|
||||
call<T>(
|
||||
owned(activeLayer, `${activeLayer === "system" ? "" : `/layers/${activeLayer}`}${path}`),
|
||||
init,
|
||||
);
|
||||
call<T>(owned(activeLayer, `/layers/${activeLayer}${path}`), init);
|
||||
|
||||
const q = (projectId: string | null): string => (projectId ? `?project_id=${enc(projectId)}` : "");
|
||||
const head = (layer: Layer): string =>
|
||||
layer === "system" ? "/templates" : `/layers/${layer}/templates`;
|
||||
const head = (layer: Layer): string => `/layers/${layer}/templates`;
|
||||
const item = (layer: Layer, kind: Kind, name: string, projectId: string | null): string =>
|
||||
owned(layer, `${head(layer)}/${kind}/${enc(name)}${layer === "system" ? "" : q(projectId)}`);
|
||||
|
||||
/** 시스템 길은 배열 · 층 길은 `{층, 양식: [...]}` — 둘 다 목록으로 */
|
||||
/** 층 길은 `{층, 양식: [...]}` · 옛 시스템 길은 배열 — 둘 다 목록으로 */
|
||||
export const listTemplates = async (
|
||||
layer: Layer,
|
||||
projectId: string | null,
|
||||
): Promise<TemplateInfo[]> => {
|
||||
const got = await call<TemplateInfo[] | { 양식: TemplateInfo[] }>(
|
||||
layer === "system" ? head(layer) : owned(layer, `${head(layer)}${q(projectId)}`),
|
||||
owned(layer, `${head(layer)}${layer === "system" ? "" : q(projectId)}`),
|
||||
);
|
||||
return Array.isArray(got) ? got : got.양식;
|
||||
};
|
||||
@@ -114,7 +111,7 @@ export const saveTemplate = (
|
||||
|
||||
/** 시스템 층만 지움 */
|
||||
export const deleteTemplate = (kind: Kind, name: string, 판: string): Promise<{ ok: boolean }> =>
|
||||
call(`/templates/${kind}/${enc(name)}?판=${enc(판)}`, { method: "DELETE" });
|
||||
call(`${head("system")}/${kind}/${enc(name)}?판=${enc(판)}`, { method: "DELETE" });
|
||||
|
||||
/** 개인·회사 층에서 지움 — 판이 맞을 때만(다르면 409) */
|
||||
export const deleteLayerTemplate = (
|
||||
@@ -204,7 +201,8 @@ export interface OptionsDoc {
|
||||
종류: OptionKind[];
|
||||
}
|
||||
|
||||
export const fetchStructureOptions = (): Promise<OptionsDoc> => call("/structure-options");
|
||||
export const fetchStructureOptions = (): Promise<OptionsDoc> =>
|
||||
call("/layers/system/structure-options"); // 읽기 = 로그인 누구나 · 고쳐 씀은 옛 길(시스템 관리자)
|
||||
|
||||
/** 고쳐 씀 — 숨긴 것만 보냄 · 낡은 판이면 StaleError · 돌려받는 것은 새 문서 */
|
||||
export const saveStructureOptions = (판: string, 표시: OptionsDoc["표시"]): Promise<OptionsDoc> =>
|
||||
|
||||
@@ -288,6 +288,14 @@ def get_numbers(layer: Layer, owner: str | None = None, session: Session = Depen
|
||||
return _call(_root(session, layer, owner), store.structure_numbers)
|
||||
|
||||
|
||||
@router.get("/layers/system/structure-options")
|
||||
def get_structure_options(session: Session = Depends(verify_session)) -> dict:
|
||||
"""구조물 옵션 보이기 읽기 — 로그인 누구나(마스터 한 벌 · 고쳐 씀은 옛 길 시스템 관리자만)."""
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Options as options
|
||||
|
||||
return _call(_root(session, "system"), options.listing)
|
||||
|
||||
|
||||
@router.get("/layers/{layer}/structure-combos")
|
||||
def get_combos(layer: Layer, owner: str | None = None, session: Session = Depends(verify_session)):
|
||||
return _call(_root(session, layer, owner), store.read_combos)
|
||||
|
||||
@@ -276,6 +276,8 @@ async def list_layer(
|
||||
manifest = await asyncio.to_thread(layers.read_manifest, folder)
|
||||
for row in rows:
|
||||
row["출처"] = manifest.get(f"{row['종류']}/{row['이름']}")
|
||||
if (row["종류"], row["이름"]) in store.IN_USE: # 화면이 지우기 확인 창 전에 막음
|
||||
row["쓰는곳"] = store.IN_USE[(row["종류"], row["이름"])]
|
||||
return {"층": layer, "양식": rows}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 아직 만든 것이 없는 남의 층(404)은 맨 위만 — 첫 쓰기 때 서버가 소속을 보고 뼈대를 세움.
|
||||
* ========================================================================== */
|
||||
|
||||
import { t as L } from "@ui/ui_template_locale";
|
||||
import type { Layer, TreeView } from "./M02_MasterTemplete_Api_Fetch";
|
||||
import { askFolder } from "./M02_MasterTemplete_TreePanel_Dialogs";
|
||||
import { buildFolders, listFolders } from "./M02_MasterTemplete_TreePanel_Model";
|
||||
@@ -22,5 +23,6 @@ export async function askCopyFolder(
|
||||
): Promise<string[] | null> {
|
||||
const view = await fetchTree(to.layer, to.owner).catch(() => null);
|
||||
const folders = view ? listFolders(buildFolders(view)) : [];
|
||||
return askFolder(to.label.replace("{n}", String(n)), folders, () => false, []);
|
||||
const title = to.label.replace("{n}", String(n));
|
||||
return askFolder(title, folders, () => false, [], L("M02_TreeCopyFolder"));
|
||||
}
|
||||
|
||||
@@ -142,12 +142,14 @@ export function askNewItem(opt: {
|
||||
});
|
||||
}
|
||||
|
||||
/** 옮길 폴더 고르기 — `folders` 에서 `blocked` 인 것은 뺌 · 맨 위(폴더 밖)는 늘 있음 */
|
||||
/** 옮길 폴더 고르기 — `folders` 에서 `blocked` 인 것은 뺌 · 맨 위(폴더 밖)는 늘 있음 ·
|
||||
* `fieldLabel` = 칸 글(복사는 「복사할 폴더」) */
|
||||
export function askFolder(
|
||||
title: string,
|
||||
folders: string[][],
|
||||
blocked: (path: string[]) => boolean,
|
||||
current: string[],
|
||||
fieldLabel: string = L("M02_TreeMoveTo"),
|
||||
): Promise<string[] | null> {
|
||||
return new Promise((resolve) => {
|
||||
let done = false;
|
||||
@@ -164,7 +166,7 @@ export function askFolder(
|
||||
beforeClose: () => (finish(null), true),
|
||||
mount: (body, close) => {
|
||||
const field = createSelectField({
|
||||
label: L("M02_TreeMoveTo"),
|
||||
label: fieldLabel,
|
||||
options: choices.map((path, i) => ({
|
||||
value: String(i),
|
||||
text: path.length ? path.join(" / ") : L("M02_TreeTop"),
|
||||
|
||||
Reference in New Issue
Block a user