@eintrek/erp-shell 0.1.72 → 0.1.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/chunks/{guide-runtime-B-3myqxe.esm.js → guide-runtime-C7Z00QwM.esm.js} +76 -6
- package/dist/chunks/guide-runtime-C7Z00QwM.esm.js.map +1 -0
- package/dist/chunks/{guide-runtime-DfnNdrjZ.cjs → guide-runtime-CLVSNkTN.cjs} +76 -5
- package/dist/chunks/guide-runtime-CLVSNkTN.cjs.map +1 -0
- package/dist/guide/core.d.ts +1 -1
- package/dist/guide/guide-store.d.ts +8 -0
- package/dist/guide/guide-styles.d.ts +1 -1
- package/dist/guide/guide-ui.d.ts +2 -0
- package/dist/guide/machine.d.ts +17 -0
- package/dist/guide/types.d.ts +8 -0
- package/dist/guide-core.cjs +2 -1
- package/dist/guide-core.cjs.map +1 -1
- package/dist/guide-core.esm.js +1 -1
- package/dist/index.cjs +4 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +5 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunks/guide-runtime-B-3myqxe.esm.js.map +0 -1
- package/dist/chunks/guide-runtime-DfnNdrjZ.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -176,6 +176,22 @@ progress API: `API.md` next to it.
|
|
|
176
176
|
shell's adapters), `guide-ui.tsx`, `guide-styles.ts`. Tests:
|
|
177
177
|
`src/guide/*.test.ts`.
|
|
178
178
|
|
|
179
|
+
### 0.1.73
|
|
180
|
+
|
|
181
|
+
- `GuideStep.status`: a short status line in the bubble while it returns
|
|
182
|
+
text, read again on every page change. A select step names a wrong pick
|
|
183
|
+
("ยังไม่ใช่ชื่อคุณ") instead of waiting in silence (owner, 3 Nov 2026:
|
|
184
|
+
Plannex's managers step, someone else picked, nothing moved).
|
|
185
|
+
- In a replay (ทบทวน), a select step offers ถัดไป when the next step's target
|
|
186
|
+
is already on the page (a form's save button), so a review never has to
|
|
187
|
+
change a real record to go on. Not while the next target needs the pick
|
|
188
|
+
(Plannex's save shows only once the user is a manager). First runs are
|
|
189
|
+
unchanged.
|
|
190
|
+
- The "?" button opens the help dialog straight away, without the
|
|
191
|
+
"ไกด์เริ่มต้น 0/0" row, when every mission is hidden for this user
|
|
192
|
+
(`guideMenuShown`). `useGuideEntry()` still answers `{ done, total }`;
|
|
193
|
+
an app's own entry row should hide at `total === 0` too.
|
|
194
|
+
|
|
179
195
|
### 0.1.72
|
|
180
196
|
|
|
181
197
|
- "ขั้นที่ x/y" counts only the steps this person will see: a step whose
|
|
@@ -337,6 +337,16 @@ function publishGuideEntry(next, openPanel) {
|
|
|
337
337
|
emit();
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
|
+
/**
|
|
341
|
+
* Whether the "?" menu offers "ไกด์เริ่มต้น": a tour whose missions are all
|
|
342
|
+
* hidden for this user (`visible`, e.g. Plannex without an employee record)
|
|
343
|
+
* has nothing to open, and "0/0" led to an empty panel. The entry itself
|
|
344
|
+
* stays published: apps wait on it before they load the facts that make
|
|
345
|
+
* missions visible.
|
|
346
|
+
*/
|
|
347
|
+
function guideMenuShown(e) {
|
|
348
|
+
return !!e && e.total > 0;
|
|
349
|
+
}
|
|
340
350
|
/** Opens the tour's quest panel, when this user has a tour here. */
|
|
341
351
|
function openGuidePanel() {
|
|
342
352
|
openPanelImpl?.();
|
|
@@ -803,6 +813,7 @@ function enterStep(d, suite, env, mission, index, opts) {
|
|
|
803
813
|
const where = placeRoute(steps, i);
|
|
804
814
|
const away = !!where && !matchRoute(where, env.pathname, env.search, env.code);
|
|
805
815
|
const bridge = !away && needsBridge(step, env, ctx);
|
|
816
|
+
const nts = !away && !bridge && nothingToSaveHolds(step, env, ctx);
|
|
806
817
|
setScreen(d, {
|
|
807
818
|
name: "step",
|
|
808
819
|
mission: mission.key,
|
|
@@ -814,7 +825,9 @@ function enterStep(d, suite, env, mission, index, opts) {
|
|
|
814
825
|
confirmExit: false,
|
|
815
826
|
misses: 0,
|
|
816
827
|
armed: hiddenAnchorShown(step, env),
|
|
817
|
-
nothingToSave:
|
|
828
|
+
nothingToSave: nts,
|
|
829
|
+
status: away || bridge ? null : stepStatus(shownStep(step, nts), ctx),
|
|
830
|
+
replayNext: !away && !bridge && opts.replay && replayCanGoOn(mission, i, env, d.state.progress.context, nts),
|
|
818
831
|
});
|
|
819
832
|
if (!opts.replay) {
|
|
820
833
|
const cp = checkpointAtOrBefore(steps, i);
|
|
@@ -857,6 +870,54 @@ function setNothingToSave(d, suite, env, on) {
|
|
|
857
870
|
if (stepTargetVisible(step, env, ctx, s.bridge))
|
|
858
871
|
announceStep(d, suite, env);
|
|
859
872
|
}
|
|
873
|
+
/** The step's status line (GuideStep.status): trimmed text, or null. */
|
|
874
|
+
function stepStatus(step, ctx) {
|
|
875
|
+
if (!step.status)
|
|
876
|
+
return null;
|
|
877
|
+
const text = safe(() => step.status(ctx), undefined);
|
|
878
|
+
return typeof text === "string" && text.trim() ? text.trim() : null;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* In a replay, whether a "select" step may go on with ถัดไป: the next step
|
|
882
|
+
* this person sees has its target on the page already (or there is none).
|
|
883
|
+
* A pick that makes the next step's target (a save shown only once the
|
|
884
|
+
* right value is chosen) is still needed.
|
|
885
|
+
*/
|
|
886
|
+
function replayCanGoOn(mission, index, env, context, nothingToSave = false) {
|
|
887
|
+
if (stepKind(shownStep(mission.steps[index], nothingToSave)) !== "select")
|
|
888
|
+
return false;
|
|
889
|
+
for (let i = index + 1; i < mission.steps.length; i++) {
|
|
890
|
+
const next = mission.steps[i];
|
|
891
|
+
const ctx = guideContext(env, context, routeParamsFor(next, env));
|
|
892
|
+
if (next.requires && !safe(() => env.can(next.requires), true))
|
|
893
|
+
continue;
|
|
894
|
+
if (next.skipIf && safe(() => next.skipIf(ctx), false))
|
|
895
|
+
continue;
|
|
896
|
+
if (!next.target)
|
|
897
|
+
return true;
|
|
898
|
+
if (stepTargetVisible(next, env, ctx, false))
|
|
899
|
+
return true;
|
|
900
|
+
// A commit step with nothing to save is read on its saved state.
|
|
901
|
+
return nothingToSaveHolds(next, env, ctx);
|
|
902
|
+
}
|
|
903
|
+
return true;
|
|
904
|
+
}
|
|
905
|
+
/** Keep the status line and a replay's ถัดไป current (the page changed). */
|
|
906
|
+
function syncStatus(d, suite, env) {
|
|
907
|
+
const s = d.state.screen;
|
|
908
|
+
if (s.name !== "step")
|
|
909
|
+
return;
|
|
910
|
+
const mission = findMission(suite, s.mission);
|
|
911
|
+
if (!mission)
|
|
912
|
+
return;
|
|
913
|
+
const step = shownStep(mission.steps[s.index], s.nothingToSave);
|
|
914
|
+
const ctx = guideContext(env, d.state.progress.context, routeParamsFor(step, env));
|
|
915
|
+
const off = s.phase === "away" || s.bridge;
|
|
916
|
+
const status = off ? null : stepStatus(step, ctx);
|
|
917
|
+
const replayNext = !off && s.replay && replayCanGoOn(mission, s.index, env, d.state.progress.context, s.nothingToSave);
|
|
918
|
+
if (status !== s.status || replayNext !== s.replayNext)
|
|
919
|
+
setScreen(d, { ...s, status, replayNext });
|
|
920
|
+
}
|
|
860
921
|
function markReadyIfVisible(d, suite, env) {
|
|
861
922
|
const s = d.state.screen;
|
|
862
923
|
if (s.name !== "step" || s.phase !== "waiting")
|
|
@@ -1242,6 +1303,7 @@ function reduceGuide(state, action, suite, env) {
|
|
|
1242
1303
|
else if (!cur.bridge && needsBridge(step, env, ctx)) {
|
|
1243
1304
|
setScreen(d, { ...cur, bridge: true, phase: "waiting" });
|
|
1244
1305
|
}
|
|
1306
|
+
syncStatus(d, suite, env);
|
|
1245
1307
|
markReadyIfVisible(d, suite, env);
|
|
1246
1308
|
break;
|
|
1247
1309
|
}
|
|
@@ -1304,6 +1366,12 @@ function reduceGuide(state, action, suite, env) {
|
|
|
1304
1366
|
advance(d, suite, env);
|
|
1305
1367
|
break;
|
|
1306
1368
|
}
|
|
1369
|
+
if (kind === "select") {
|
|
1370
|
+
// A replay goes on without a pick when the next step is on the page.
|
|
1371
|
+
if (s.replay && replayCanGoOn(mission, s.index, env, d.state.progress.context, s.nothingToSave))
|
|
1372
|
+
advance(d, suite, env);
|
|
1373
|
+
break;
|
|
1374
|
+
}
|
|
1307
1375
|
if (kind !== "input")
|
|
1308
1376
|
break;
|
|
1309
1377
|
const ctx = guideContext(env, d.state.progress.context, routeParamsFor(step, env));
|
|
@@ -2310,6 +2378,7 @@ const GUIDE_CSS = `
|
|
|
2310
2378
|
.eg-b-t{margin:0;font-size:16px;font-weight:600;line-height:1.45}
|
|
2311
2379
|
.eg-b-w{margin:2px 0 0;font-size:13.5px;color:var(--eg-muted)}
|
|
2312
2380
|
.eg-bubble.eg-err .eg-b-t{color:var(--eg-danger)}
|
|
2381
|
+
.eg-b-s{margin:6px 0 0;font-size:13px;font-weight:600;color:var(--eg-danger)}
|
|
2313
2382
|
.eg-k{display:inline-block;background:var(--eg-tint);color:var(--eg-strong);border-radius:7px;padding:0 7px;font-weight:600}
|
|
2314
2383
|
.eg-b-f{display:flex;align-items:center;justify-content:space-between;margin-top:12px;gap:8px}
|
|
2315
2384
|
.eg-b-f .eg-btn{height:34px;padding:0 14px;font-size:13.5px}
|
|
@@ -2543,7 +2612,7 @@ function StepLayer(p) {
|
|
|
2543
2612
|
const showBubble = p.phase === "ready" && (!!spot || !p.hasTarget);
|
|
2544
2613
|
const gap = p.showHand ? 34 : 14;
|
|
2545
2614
|
const spotKey = spot ? `${spot.x}|${spot.y}|${spot.width}|${spot.height}` : "";
|
|
2546
|
-
const contentKey = `${p.bubble.title}|${p.bubble.why}|${p.bubble.error?.title ?? ""}|${p.bubble.showNext}`;
|
|
2615
|
+
const contentKey = `${p.bubble.title}|${p.bubble.why}|${p.bubble.error?.title ?? ""}|${p.bubble.status ?? ""}|${p.bubble.showNext}`;
|
|
2547
2616
|
// What the bubble sits beside: the target, with an open list over it (the
|
|
2548
2617
|
// list is what the person is choosing from now). What it must not cover:
|
|
2549
2618
|
// open lists, and the other anchors the step allows (a map step's
|
|
@@ -2666,7 +2735,7 @@ function BubbleBody(p) {
|
|
|
2666
2735
|
const b = p.bubble;
|
|
2667
2736
|
const title = b.error ? b.error.title : b.title;
|
|
2668
2737
|
const why = b.error ? (b.error.detail ?? "") : b.why;
|
|
2669
|
-
return (jsxs(Fragment, { children: [jsxs("div", { className: "eg-b-top", children: [jsxs("span", { className: "eg-mis", children: ["\u0E20\u0E32\u0E23\u0E01\u0E34\u0E08 ", b.missionNo, " \u00B7 ", b.missionTitle, b.replay ? " (ทบทวน)" : ""] }), jsxs("span", { className: "eg-cnt", children: ["\u0E02\u0E31\u0E49\u0E19\u0E17\u0E35\u0E48 ", b.index + 1, "/", b.total] })] }), jsx("div", { className: "eg-pips", "aria-hidden": "true", children: Array.from({ length: b.total }, (_, i) => (jsx("i", { className: i < b.index ? "eg-d" : i === b.index ? "eg-c" : undefined }, i))) }), jsx("p", { className: "eg-b-t", id: BUBBLE_TITLE_ID, children: jsx(GuideTitle, { text: title }) }), jsx("p", { className: "eg-b-w", id: BUBBLE_WHY_ID, hidden: !why, children: jsx(GuideTitle, { text: why }) }), jsxs("div", { className: "eg-b-f", children: [jsx("button", { type: "button", className: "eg-exit", onClick: p.onExit, children: b.replay ? "จบการทบทวน" : "ออกจากไกด์" }), jsxs("span", { style: { display: "flex", gap: 6 }, children: [b.showEndWithoutSave ? (jsx("button", { type: "button", className: "eg-btn eg-ghost", onClick: p.onEndWithoutSave, children: "\u0E08\u0E1A\u0E42\u0E14\u0E22\u0E44\u0E21\u0E48\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01" })) : null, b.showNext ? (jsx("button", { type: "button", className: "eg-btn eg-primary", onClick: p.onNext, children: "\u0E16\u0E31\u0E14\u0E44\u0E1B" })) : null] })] })] }));
|
|
2738
|
+
return (jsxs(Fragment, { children: [jsxs("div", { className: "eg-b-top", children: [jsxs("span", { className: "eg-mis", children: ["\u0E20\u0E32\u0E23\u0E01\u0E34\u0E08 ", b.missionNo, " \u00B7 ", b.missionTitle, b.replay ? " (ทบทวน)" : ""] }), jsxs("span", { className: "eg-cnt", children: ["\u0E02\u0E31\u0E49\u0E19\u0E17\u0E35\u0E48 ", b.index + 1, "/", b.total] })] }), jsx("div", { className: "eg-pips", "aria-hidden": "true", children: Array.from({ length: b.total }, (_, i) => (jsx("i", { className: i < b.index ? "eg-d" : i === b.index ? "eg-c" : undefined }, i))) }), jsx("p", { className: "eg-b-t", id: BUBBLE_TITLE_ID, children: jsx(GuideTitle, { text: title }) }), jsx("p", { className: "eg-b-w", id: BUBBLE_WHY_ID, hidden: !why, children: jsx(GuideTitle, { text: why }) }), b.status && !b.error ? (jsx("p", { className: "eg-b-s", role: "status", "data-eg-status": "", children: b.status })) : null, jsxs("div", { className: "eg-b-f", children: [jsx("button", { type: "button", className: "eg-exit", onClick: p.onExit, children: b.replay ? "จบการทบทวน" : "ออกจากไกด์" }), jsxs("span", { style: { display: "flex", gap: 6 }, children: [b.showEndWithoutSave ? (jsx("button", { type: "button", className: "eg-btn eg-ghost", onClick: p.onEndWithoutSave, children: "\u0E08\u0E1A\u0E42\u0E14\u0E22\u0E44\u0E21\u0E48\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01" })) : null, b.showNext ? (jsx("button", { type: "button", className: "eg-btn eg-primary", onClick: p.onNext, children: "\u0E16\u0E31\u0E14\u0E44\u0E1B" })) : null] })] })] }));
|
|
2670
2739
|
}
|
|
2671
2740
|
/** The fingertip at ≈62% across and down the target; upside down near the bottom. */
|
|
2672
2741
|
function handPosition(spot, viewportHeight) {
|
|
@@ -3818,7 +3887,8 @@ function GuideRuntimeInner({ config, organizationId, code, routing, progress: pr
|
|
|
3818
3887
|
title: bridge ? "กดปุ่มเมนู" : resolveText(step.title, stepCtx),
|
|
3819
3888
|
why: bridge ? `เมนูทั้งหมดของ ${suite.appName} อยู่ในนี้` : resolveText(step.why, stepCtx),
|
|
3820
3889
|
error: screen.error,
|
|
3821
|
-
|
|
3890
|
+
status: bridge ? null : screen.status,
|
|
3891
|
+
showNext: !bridge && (kind === "input" || kind === "view" || (kind === "select" && screen.replay && screen.replayNext)),
|
|
3822
3892
|
showEndWithoutSave: !bridge && screen.replay && kind === "commit",
|
|
3823
3893
|
}, hasTarget: bridge || !!step.target, targetPressable: targetPressable(step, bridge), phase: screen.phase, confirmExit: screen.confirmExit, reopenHint: suite.reopenHint, nudge: state.nudge, moving: moving, onExit: () => dispatch({ type: "exit" }), onNext: () => dispatch({ type: "next" }), onEndWithoutSave: () => dispatch({ type: "endWithoutSave" }), onRetry: () => dispatch({ type: "retry" }), onGoResume: () => dispatch({ type: "goResume" }), onExitConfirm: () => dispatch({ type: "exitConfirm" }), onExitCancel: () => dispatch({ type: "exitCancel" }) }));
|
|
3824
3894
|
}
|
|
@@ -3870,5 +3940,5 @@ function useFactsKey(facts) {
|
|
|
3870
3940
|
}, [facts]);
|
|
3871
3941
|
}
|
|
3872
3942
|
|
|
3873
|
-
export { API_EVENT as A, GUIDE_EVENT_PREFIX as G, GUIDE_LAYER_ATTRIBUTE as a, GuideErrorBoundary as b, GuideProgressConflict as c, GuideRuntime as d, apiCallDetail as e, emitGuideEvent as f, fillRoute as g, guideAnchor as h,
|
|
3874
|
-
//# sourceMappingURL=guide-runtime-
|
|
3943
|
+
export { API_EVENT as A, GUIDE_EVENT_PREFIX as G, GUIDE_LAYER_ATTRIBUTE as a, GuideErrorBoundary as b, GuideProgressConflict as c, GuideRuntime as d, apiCallDetail as e, emitGuideEvent as f, fillRoute as g, guideAnchor as h, guideMenuShown as i, matchRoute as j, reportApiEvent as k, loadGuides as l, matchApiPath as m, openGuidePanel as o, reportApiCall as r, storeGuides as s, useGuideEntry as u };
|
|
3944
|
+
//# sourceMappingURL=guide-runtime-C7Z00QwM.esm.js.map
|