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:
@@ -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) {
|
||||
|
||||
@@ -150,6 +150,40 @@ export async function emptyFlow(name: string, unit: string): Promise<CfLogic> {
|
||||
return (await import("../M02_MasterTemplete/DataFlow/M02_DF_Model")).newLogic(name, unit);
|
||||
}
|
||||
|
||||
/* ── 시험 입력 한 벌 — 왼쪽 시험 계산 입력 ↔ 흐름 변수 예시값(이름이 같은 변수끼리) ── */
|
||||
|
||||
const varsOf = (lg: CfLogic) =>
|
||||
lg.boxes.flatMap((b) => [...(b.input?.variables ?? []), ...(b.func?.variables ?? [])]);
|
||||
|
||||
/** 흐름 변수 예시값 — 이름 → 글(빈 값은 뺌) */
|
||||
export function examplesOf(lg: CfLogic): Record<string, string> {
|
||||
const out: Record<string, string> = {};
|
||||
for (const v of varsOf(lg))
|
||||
if (v.example !== null && v.example !== undefined && v.example !== "")
|
||||
out[v.name] = String(v.example);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 예시값을 넣은 새 흐름 — 수처럼 생긴 글은 수로 · 빈 값은 그대로 둠 */
|
||||
export function withExamples(lg: CfLogic, vals: Record<string, string>): CfLogic {
|
||||
const next = JSON.parse(JSON.stringify(lg)) as CfLogic;
|
||||
for (const v of varsOf(next)) {
|
||||
const raw = (vals[v.name] ?? "").trim();
|
||||
if (raw) v.example = /^-?\d+(\.\d+)?$/.test(raw) ? Number(raw) : raw;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/** 예시값만 다른가 — 그 밖이 같으면 고친 것으로 안 셈 */
|
||||
export function sameShape(a: CfLogic, b: CfLogic): boolean {
|
||||
const strip = (lg: CfLogic): string => {
|
||||
const c = JSON.parse(JSON.stringify(lg)) as CfLogic;
|
||||
for (const v of varsOf(c)) v.example = null;
|
||||
return JSON.stringify(c);
|
||||
};
|
||||
return strip(a) === strip(b);
|
||||
}
|
||||
|
||||
export interface LogicFlowOpts {
|
||||
split: SplitHandle;
|
||||
flow: CfLogic;
|
||||
@@ -168,6 +202,8 @@ export interface LogicFlow {
|
||||
set(lg: CfLogic): void;
|
||||
/** 왼쪽만 다시(왼쪽 화면을 새로 그린 뒤) */
|
||||
redrawLeft(): void;
|
||||
/** 왼쪽 시험 계산 입력이 바뀜 — 같은 이름 변수의 예시값으로(고친 것 아님) */
|
||||
setExamples(vals: Record<string, string>): void;
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
@@ -253,6 +289,14 @@ export async function mountLogicFlow(opts: LogicFlowOpts): Promise<LogicFlow> {
|
||||
refresh();
|
||||
},
|
||||
redrawLeft: left,
|
||||
setExamples: (vals) => {
|
||||
const next = withExamples(lg, vals);
|
||||
if (JSON.stringify(next) === JSON.stringify(lg)) return;
|
||||
lg = next;
|
||||
panel.set(next);
|
||||
left();
|
||||
refresh();
|
||||
},
|
||||
destroy: () => {
|
||||
gone = true;
|
||||
panel.destroy();
|
||||
|
||||
Reference in New Issue
Block a user