fix(M01): 흐름도 패널 글 · 왼쪽 고침 → 오른쪽 따라감 · 시험판 길 지움
- 패널 위 글 「이 로직의 계산 방법을 흐름도로 보여 줌」(「옛 식」 · 「정본」 말 지움)
- 왼쪽 편집기로 고친 뒤 잠시 쉬면 고친 줄을 서버 변환(POST /api/m01/logic/flow {file, key, row})으로 다시 받아 오른쪽에 넣음 · 마지막 물음만 받음 · 길이 아직 없으면 아무 일 없음
- 다른 로직 받기에서 흐름도 시험판(DF-) cfGet 길 지움
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
This commit is contained in:
@@ -43,6 +43,7 @@ import {
|
||||
emptyFlow,
|
||||
examplesOf,
|
||||
fetchFlow,
|
||||
fetchFlowFor,
|
||||
sameShape,
|
||||
withExamples,
|
||||
mountLogicFlow,
|
||||
@@ -78,9 +79,11 @@ interface Opened extends Draft {
|
||||
values: Record<string, string>;
|
||||
/** 흐름 로직의 왼쪽 「지금 내용」 자리 — 흐름도 왼쪽 보기가 그림 */
|
||||
flowHost: HTMLElement;
|
||||
/** 오른쪽 흐름도의 기준(예시값만 다른지 견줄 때) */
|
||||
flowBase?: CfLogic;
|
||||
}
|
||||
|
||||
/** 줄의 흐름(있으면 흐름도가 정본) */
|
||||
/** 줄의 흐름(있으면 흐름도로 셈) */
|
||||
const flowOf = (row: LogicRow | null): CfLogic | null => (row?.흐름 as CfLogic | undefined) ?? null;
|
||||
const OWN_FILE = "로직_자체.json";
|
||||
|
||||
@@ -165,6 +168,7 @@ export async function mountM01LogicLab(
|
||||
if (opened.origKey !== null && now === opened.original) delete drafts[opened.id];
|
||||
else drafts[opened.id] = pick(opened, clone(opened.row));
|
||||
persist();
|
||||
if (!flowOf(opened.row)) scheduleFlow(opened); // 왼쪽 편집기로 고침 — 오른쪽 흐름도도 따라감
|
||||
const inputs = JSON.stringify(opened.row.입력 ?? []);
|
||||
if (inputs !== calcInputs) drawCalc();
|
||||
if (isOwnLogic(opened.row)) {
|
||||
@@ -241,6 +245,22 @@ export async function mountM01LogicLab(
|
||||
flowNow?.redrawLeft();
|
||||
};
|
||||
|
||||
/** 왼쪽 고침 뒤 잠시 쉬면 고친 줄을 서버가 흐름도로 바꿔 줌 → 오른쪽에 넣음 · 마지막 물음만 받음 */
|
||||
let flowTimer: number | undefined;
|
||||
let flowSeq = 0;
|
||||
const scheduleFlow = (o: Opened): void => {
|
||||
window.clearTimeout(flowTimer);
|
||||
flowTimer = window.setTimeout(() => {
|
||||
const seq = ++flowSeq;
|
||||
if (!o.row) return;
|
||||
void fetchFlowFor(o.row, o.origKey ?? "", o.file).then((got) => {
|
||||
if (!got || seq !== flowSeq || opened !== o || !flowNow || flowOf(o.row)) return;
|
||||
o.flowBase = withExamples(got.flow, o.values);
|
||||
flowNow.set(clone(o.flowBase));
|
||||
});
|
||||
}, 700);
|
||||
};
|
||||
|
||||
/** 오른쪽 흐름도 — 줄의 흐름 · 없으면 서버 변환(흐름 받기) · 그것도 없으면 빈 흐름 */
|
||||
const startFlow = async (o: Opened): Promise<void> => {
|
||||
const row = o.row;
|
||||
@@ -249,7 +269,7 @@ export async function mountM01LogicLab(
|
||||
const own = flowOf(row);
|
||||
const got = own || o.origKey === null ? null : await fetchFlow(o.origKey, o.file);
|
||||
// 시험 입력 한 벌 — 열 때 왼쪽 시험 계산 입력을 흐름 변수 예시값으로
|
||||
let base = withExamples(
|
||||
o.flowBase = withExamples(
|
||||
own ?? got?.flow ?? (await emptyFlow(row.이름, row.결과단위)),
|
||||
o.values,
|
||||
);
|
||||
@@ -257,7 +277,7 @@ export async function mountM01LogicLab(
|
||||
try {
|
||||
const made = await mountLogicFlow({
|
||||
split,
|
||||
flow: clone(base),
|
||||
flow: clone(o.flowBase),
|
||||
title: row.이름 || row.키,
|
||||
readOnly: !admin,
|
||||
notes: got?.notes ?? [],
|
||||
@@ -266,9 +286,9 @@ export async function mountM01LogicLab(
|
||||
onChange: (lg) => {
|
||||
if (!o.row || opened !== o) return;
|
||||
const was = flowOf(o.row);
|
||||
if (sameShape(lg, was ?? base)) {
|
||||
if (sameShape(lg, was ?? o.flowBase ?? lg)) {
|
||||
// 예시값만 바뀜 — 고친 것 아님 · 왼쪽 시험 계산 입력에 같은 이름으로 넣고 다시 셈
|
||||
base = lg;
|
||||
o.flowBase = lg;
|
||||
syncLeft(o, examplesOf(lg));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ const TEXT = {
|
||||
New: ["신규 로직", "New logic"],
|
||||
Waiting: ["흐름도 불러오는 중", "Loading the flow diagram"],
|
||||
Converted: [
|
||||
"옛 식을 흐름도로 바꿔 보임 — 저장하면 흐름도가 정본",
|
||||
"Converted from the old formula — saving makes the flow the master",
|
||||
"이 로직의 계산 방법을 흐름도로 보여 줌",
|
||||
"Shows how this logic is calculated as a flow diagram",
|
||||
],
|
||||
Failed: ["흐름도를 못 띄움 — {v}", "Couldn't open the flow diagram — {v}"],
|
||||
} as const;
|
||||
@@ -122,7 +122,7 @@ export interface FlowAnswer {
|
||||
notes: string[];
|
||||
}
|
||||
|
||||
/** 마스터 로직의 흐름 — 줄에 흐름이 있으면 그대로 · 없으면 서버가 옛 식을 바꿔 줌 · 길이 없거나 못 받으면 null */
|
||||
/** 마스터 로직의 흐름 — 줄에 흐름이 있으면 그대로 · 없으면 서버가 계산 방법을 흐름도로 바꿔 줌 · 못 받으면 null */
|
||||
export async function fetchFlow(key: string, file = ""): Promise<FlowAnswer | null> {
|
||||
try {
|
||||
const q = new URLSearchParams({ key, ...(file ? { file } : {}) });
|
||||
@@ -135,6 +135,27 @@ export async function fetchFlow(key: string, file = ""): Promise<FlowAnswer | nu
|
||||
}
|
||||
}
|
||||
|
||||
/** 고치는 중인 줄의 흐름 — 왼쪽 편집기로 고친 줄(저장 전)을 서버가 흐름도로 바꿔 줌 · 못 받으면 null */
|
||||
export async function fetchFlowFor(
|
||||
row: unknown,
|
||||
key: string,
|
||||
file: string,
|
||||
): Promise<FlowAnswer | null> {
|
||||
try {
|
||||
const r = await fetch(`${API_BASE_URL}/m01/logic/flow`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ file, key, row }),
|
||||
});
|
||||
if (!r.ok) return null;
|
||||
const got = (await r.json()) as Partial<FlowAnswer>;
|
||||
return got.flow ? { flow: got.flow, converted: !!got.converted, notes: got.notes ?? [] } : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const loadFlowMods = () =>
|
||||
Promise.all([
|
||||
import("../M02_MasterTemplete/DataFlow/M02_DF_Panel"),
|
||||
@@ -223,9 +244,9 @@ export async function mountLogicFlow(opts: LogicFlowOpts): Promise<LogicFlow> {
|
||||
let logicSig = "";
|
||||
let gone = false;
|
||||
|
||||
/** 다른 로직 — 흐름도 저장본(DF-) · 마스터 로직(흐름 받기) */
|
||||
/** 다른 로직 — 마스터 로직(흐름 받기) */
|
||||
const getLogic = async (key: string): Promise<CfLogic | null> =>
|
||||
key.startsWith("DF-") ? M.api.cfGet(key) : ((await fetchFlow(key))?.flow ?? null);
|
||||
(await fetchFlow(key))?.flow ?? null;
|
||||
|
||||
const left = (): void => {
|
||||
const at = opts.leftHost();
|
||||
|
||||
Reference in New Issue
Block a user