fix(M01): 시험 입력 한 벌 — 왼쪽 시험 계산 입력 ↔ 흐름 변수 예시값

- 로직을 열 때 왼쪽 시험 계산 입력(자동값 포함)을 이름이 같은 흐름 변수 예시값으로
- 왼쪽 입력을 바꾸면 흐름 예시값도 · 흐름 검증 칸 예시값을 바꾸면 왼쪽 입력도 바꾸고 다시 셈
- 예시값만 바뀐 것은 고친 것(drafts)으로 안 셈(sameShape)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
This commit is contained in:
2026-10-02 01:38:24 +09:00
co-authored by Claude Opus 5.5
parent 2b3ba84fe5
commit f30bc9e82f
2 changed files with 88 additions and 4 deletions
+44 -4
View File
@@ -41,7 +41,10 @@ import { tl } from "./M01_MasterData_UI_LogicLab_Text";
import {
buildSplit,
emptyFlow,
examplesOf,
fetchFlow,
sameShape,
withExamples,
mountLogicFlow,
tf,
type LogicFlow,
@@ -244,12 +247,16 @@ export async function mountM01LogicLab(
split.right.replaceChildren(el("p", { className: "m01lab-flow__wait", text: tf("Waiting") }));
const own = flowOf(row);
const got = own || o.origKey === null ? null : await fetchFlow(o.origKey, o.file);
const flow = own ?? got?.flow ?? (await emptyFlow(row.이름, row.결과단위));
// 시험 입력 한 벌 — 열 때 왼쪽 시험 계산 입력을 흐름 변수 예시값으로
let base = withExamples(
own ?? got?.flow ?? (await emptyFlow(row.이름, row.결과단위)),
o.values,
);
if (opened !== o) return;
try {
const made = await mountLogicFlow({
split,
flow: clone(flow),
flow: clone(base),
title: row.이름 || row.키,
readOnly: !admin,
notes: got?.notes ?? [],
@@ -258,6 +265,12 @@ export async function mountM01LogicLab(
onChange: (lg) => {
if (!o.row || opened !== o) return;
const was = flowOf(o.row);
if (sameShape(lg, was ?? base)) {
// 예시값만 바뀜 — 고친 것 아님 · 왼쪽 시험 계산 입력에 같은 이름으로 넣고 다시 셈
base = lg;
syncLeft(o, examplesOf(lg));
return;
}
o.row.흐름 = lg;
touch();
if (!was) drawEditor(); // 이제 흐름 로직 — 왼쪽을 흐름 보기로
@@ -265,6 +278,7 @@ export async function mountM01LogicLab(
});
if (opened !== o) return made.destroy();
flowNow = made;
made.setExamples(o.values); // 띄우는 사이에 온 자동값까지
} catch (e) {
split.right.replaceChildren(
el("p", { className: "m01-logic__muted", text: tf("Failed", String(e)) }),
@@ -272,6 +286,32 @@ export async function mountM01LogicLab(
}
};
/** 흐름 예시값 → 왼쪽 시험 계산 입력(이름이 있는 칸만) · 바뀌면 왼쪽을 다시 그리고 셈 */
const syncLeft = (o: Opened, ex: Record<string, string>): void => {
const names = new Set((o.row?.입력 ?? []).map((x) => x.이름));
const changed = Object.entries(ex).filter(([k, v]) => names.has(k) && o.values[k] !== v);
if (!changed.length) return;
quiet = true;
for (const [k, v] of changed) o.values[k] = v;
quiet = false;
drawCalc();
calc.querySelector<HTMLButtonElement>("[data-calc-run]")?.click();
};
/** 왼쪽 시험 계산 입력 — 칸이 바뀌면 흐름 예시값으로(이 로직이 열려 있을 때만) */
let quiet = false;
const watchValues = (): Record<string, string> => {
const self: Record<string, string> = new Proxy({} as Record<string, string>, {
set(t, k, v) {
const was = t[k as string];
t[k as string] = v as string;
if (!quiet && was !== v && opened?.values === self)
flowNow?.setExamples({ [k as string]: v as string });
return true;
},
});
return self;
};
const show = (next: Opened | null): void => {
flowNow?.destroy();
flowNow = null;
@@ -294,7 +334,7 @@ export async function mountM01LogicLab(
lines: null,
text: null,
ownHost: ownHost(),
values: {},
values: watchValues(),
flowHost: el("div"),
});
return;
@@ -314,7 +354,7 @@ export async function mountM01LogicLab(
lines: null,
text: null,
ownHost: ownHost(),
values: {},
values: watchValues(),
flowHost: el("div"),
});
} catch (error) {