@eintrek/erp-shell 0.1.71 → 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 +22 -0
- package/dist/chunks/{guide-runtime-BTatpm-V.esm.js → guide-runtime-C7Z00QwM.esm.js} +103 -9
- package/dist/chunks/guide-runtime-C7Z00QwM.esm.js.map +1 -0
- package/dist/chunks/{guide-runtime-B_fYkQv7.cjs → guide-runtime-CLVSNkTN.cjs} +103 -8
- 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 +26 -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-BTatpm-V.esm.js.map +0 -1
- package/dist/chunks/guide-runtime-B_fYkQv7.cjs.map +0 -1
|
@@ -357,6 +357,16 @@ function publishGuideEntry(next, openPanel) {
|
|
|
357
357
|
emit();
|
|
358
358
|
}
|
|
359
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* Whether the "?" menu offers "ไกด์เริ่มต้น": a tour whose missions are all
|
|
362
|
+
* hidden for this user (`visible`, e.g. Plannex without an employee record)
|
|
363
|
+
* has nothing to open, and "0/0" led to an empty panel. The entry itself
|
|
364
|
+
* stays published: apps wait on it before they load the facts that make
|
|
365
|
+
* missions visible.
|
|
366
|
+
*/
|
|
367
|
+
function guideMenuShown(e) {
|
|
368
|
+
return !!e && e.total > 0;
|
|
369
|
+
}
|
|
360
370
|
/** Opens the tour's quest panel, when this user has a tour here. */
|
|
361
371
|
function openGuidePanel() {
|
|
362
372
|
openPanelImpl?.();
|
|
@@ -747,11 +757,34 @@ function announceStep(d, suite, env) {
|
|
|
747
757
|
const ctx = guideContext(env, d.state.progress.context, routeParamsFor(step, env));
|
|
748
758
|
const title = s.bridge ? COPY.bridgeTitle : plainTitle(resolveText(step.title, ctx));
|
|
749
759
|
const why = s.bridge ? COPY.bridgeWhy(suite.appName) : plainTitle(resolveText(step.why, ctx));
|
|
760
|
+
const pos = stepPosition(mission, s.index, env, d.state.progress.context);
|
|
750
761
|
d.effects.push({
|
|
751
762
|
type: "announce",
|
|
752
|
-
text: `ขั้นที่ ${
|
|
763
|
+
text: `ขั้นที่ ${pos.no} จาก ${pos.total}. ${title}${why ? `. ${why}` : ""}`,
|
|
753
764
|
});
|
|
754
765
|
}
|
|
766
|
+
/**
|
|
767
|
+
* "ขั้นที่ no จาก total" counting only the steps this person will see: a step
|
|
768
|
+
* whose `requires` they lack or whose `skipIf` holds is left out (the step on
|
|
769
|
+
* screen always counts).
|
|
770
|
+
*/
|
|
771
|
+
function stepPosition(mission, index, env, context) {
|
|
772
|
+
let no = 0;
|
|
773
|
+
let total = 0;
|
|
774
|
+
mission.steps.forEach((step, i) => {
|
|
775
|
+
if (i !== index) {
|
|
776
|
+
if (step.requires && !safe(() => env.can(step.requires), true))
|
|
777
|
+
return;
|
|
778
|
+
const ctx = guideContext(env, context, routeParamsFor(step, env));
|
|
779
|
+
if (step.skipIf && safe(() => step.skipIf(ctx), false))
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
total++;
|
|
783
|
+
if (i <= index)
|
|
784
|
+
no = total;
|
|
785
|
+
});
|
|
786
|
+
return { no: Math.max(no, 1), total: Math.max(total, 1) };
|
|
787
|
+
}
|
|
755
788
|
/** "กด [บันทึก]" → "กด บันทึก" (for screen readers). */
|
|
756
789
|
function plainTitle(t) {
|
|
757
790
|
return t.replace(/\[([^\]]+)\]/g, "$1");
|
|
@@ -800,6 +833,7 @@ function enterStep(d, suite, env, mission, index, opts) {
|
|
|
800
833
|
const where = placeRoute(steps, i);
|
|
801
834
|
const away = !!where && !matchRoute(where, env.pathname, env.search, env.code);
|
|
802
835
|
const bridge = !away && needsBridge(step, env, ctx);
|
|
836
|
+
const nts = !away && !bridge && nothingToSaveHolds(step, env, ctx);
|
|
803
837
|
setScreen(d, {
|
|
804
838
|
name: "step",
|
|
805
839
|
mission: mission.key,
|
|
@@ -811,7 +845,9 @@ function enterStep(d, suite, env, mission, index, opts) {
|
|
|
811
845
|
confirmExit: false,
|
|
812
846
|
misses: 0,
|
|
813
847
|
armed: hiddenAnchorShown(step, env),
|
|
814
|
-
nothingToSave:
|
|
848
|
+
nothingToSave: nts,
|
|
849
|
+
status: away || bridge ? null : stepStatus(shownStep(step, nts), ctx),
|
|
850
|
+
replayNext: !away && !bridge && opts.replay && replayCanGoOn(mission, i, env, d.state.progress.context, nts),
|
|
815
851
|
});
|
|
816
852
|
if (!opts.replay) {
|
|
817
853
|
const cp = checkpointAtOrBefore(steps, i);
|
|
@@ -854,6 +890,54 @@ function setNothingToSave(d, suite, env, on) {
|
|
|
854
890
|
if (stepTargetVisible(step, env, ctx, s.bridge))
|
|
855
891
|
announceStep(d, suite, env);
|
|
856
892
|
}
|
|
893
|
+
/** The step's status line (GuideStep.status): trimmed text, or null. */
|
|
894
|
+
function stepStatus(step, ctx) {
|
|
895
|
+
if (!step.status)
|
|
896
|
+
return null;
|
|
897
|
+
const text = safe(() => step.status(ctx), undefined);
|
|
898
|
+
return typeof text === "string" && text.trim() ? text.trim() : null;
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* In a replay, whether a "select" step may go on with ถัดไป: the next step
|
|
902
|
+
* this person sees has its target on the page already (or there is none).
|
|
903
|
+
* A pick that makes the next step's target (a save shown only once the
|
|
904
|
+
* right value is chosen) is still needed.
|
|
905
|
+
*/
|
|
906
|
+
function replayCanGoOn(mission, index, env, context, nothingToSave = false) {
|
|
907
|
+
if (stepKind(shownStep(mission.steps[index], nothingToSave)) !== "select")
|
|
908
|
+
return false;
|
|
909
|
+
for (let i = index + 1; i < mission.steps.length; i++) {
|
|
910
|
+
const next = mission.steps[i];
|
|
911
|
+
const ctx = guideContext(env, context, routeParamsFor(next, env));
|
|
912
|
+
if (next.requires && !safe(() => env.can(next.requires), true))
|
|
913
|
+
continue;
|
|
914
|
+
if (next.skipIf && safe(() => next.skipIf(ctx), false))
|
|
915
|
+
continue;
|
|
916
|
+
if (!next.target)
|
|
917
|
+
return true;
|
|
918
|
+
if (stepTargetVisible(next, env, ctx, false))
|
|
919
|
+
return true;
|
|
920
|
+
// A commit step with nothing to save is read on its saved state.
|
|
921
|
+
return nothingToSaveHolds(next, env, ctx);
|
|
922
|
+
}
|
|
923
|
+
return true;
|
|
924
|
+
}
|
|
925
|
+
/** Keep the status line and a replay's ถัดไป current (the page changed). */
|
|
926
|
+
function syncStatus(d, suite, env) {
|
|
927
|
+
const s = d.state.screen;
|
|
928
|
+
if (s.name !== "step")
|
|
929
|
+
return;
|
|
930
|
+
const mission = findMission(suite, s.mission);
|
|
931
|
+
if (!mission)
|
|
932
|
+
return;
|
|
933
|
+
const step = shownStep(mission.steps[s.index], s.nothingToSave);
|
|
934
|
+
const ctx = guideContext(env, d.state.progress.context, routeParamsFor(step, env));
|
|
935
|
+
const off = s.phase === "away" || s.bridge;
|
|
936
|
+
const status = off ? null : stepStatus(step, ctx);
|
|
937
|
+
const replayNext = !off && s.replay && replayCanGoOn(mission, s.index, env, d.state.progress.context, s.nothingToSave);
|
|
938
|
+
if (status !== s.status || replayNext !== s.replayNext)
|
|
939
|
+
setScreen(d, { ...s, status, replayNext });
|
|
940
|
+
}
|
|
857
941
|
function markReadyIfVisible(d, suite, env) {
|
|
858
942
|
const s = d.state.screen;
|
|
859
943
|
if (s.name !== "step" || s.phase !== "waiting")
|
|
@@ -1239,6 +1323,7 @@ function reduceGuide(state, action, suite, env) {
|
|
|
1239
1323
|
else if (!cur.bridge && needsBridge(step, env, ctx)) {
|
|
1240
1324
|
setScreen(d, { ...cur, bridge: true, phase: "waiting" });
|
|
1241
1325
|
}
|
|
1326
|
+
syncStatus(d, suite, env);
|
|
1242
1327
|
markReadyIfVisible(d, suite, env);
|
|
1243
1328
|
break;
|
|
1244
1329
|
}
|
|
@@ -1301,6 +1386,12 @@ function reduceGuide(state, action, suite, env) {
|
|
|
1301
1386
|
advance(d, suite, env);
|
|
1302
1387
|
break;
|
|
1303
1388
|
}
|
|
1389
|
+
if (kind === "select") {
|
|
1390
|
+
// A replay goes on without a pick when the next step is on the page.
|
|
1391
|
+
if (s.replay && replayCanGoOn(mission, s.index, env, d.state.progress.context, s.nothingToSave))
|
|
1392
|
+
advance(d, suite, env);
|
|
1393
|
+
break;
|
|
1394
|
+
}
|
|
1304
1395
|
if (kind !== "input")
|
|
1305
1396
|
break;
|
|
1306
1397
|
const ctx = guideContext(env, d.state.progress.context, routeParamsFor(step, env));
|
|
@@ -2307,6 +2398,7 @@ const GUIDE_CSS = `
|
|
|
2307
2398
|
.eg-b-t{margin:0;font-size:16px;font-weight:600;line-height:1.45}
|
|
2308
2399
|
.eg-b-w{margin:2px 0 0;font-size:13.5px;color:var(--eg-muted)}
|
|
2309
2400
|
.eg-bubble.eg-err .eg-b-t{color:var(--eg-danger)}
|
|
2401
|
+
.eg-b-s{margin:6px 0 0;font-size:13px;font-weight:600;color:var(--eg-danger)}
|
|
2310
2402
|
.eg-k{display:inline-block;background:var(--eg-tint);color:var(--eg-strong);border-radius:7px;padding:0 7px;font-weight:600}
|
|
2311
2403
|
.eg-b-f{display:flex;align-items:center;justify-content:space-between;margin-top:12px;gap:8px}
|
|
2312
2404
|
.eg-b-f .eg-btn{height:34px;padding:0 14px;font-size:13.5px}
|
|
@@ -2540,7 +2632,7 @@ function StepLayer(p) {
|
|
|
2540
2632
|
const showBubble = p.phase === "ready" && (!!spot || !p.hasTarget);
|
|
2541
2633
|
const gap = p.showHand ? 34 : 14;
|
|
2542
2634
|
const spotKey = spot ? `${spot.x}|${spot.y}|${spot.width}|${spot.height}` : "";
|
|
2543
|
-
const contentKey = `${p.bubble.title}|${p.bubble.why}|${p.bubble.error?.title ?? ""}|${p.bubble.showNext}`;
|
|
2635
|
+
const contentKey = `${p.bubble.title}|${p.bubble.why}|${p.bubble.error?.title ?? ""}|${p.bubble.status ?? ""}|${p.bubble.showNext}`;
|
|
2544
2636
|
// What the bubble sits beside: the target, with an open list over it (the
|
|
2545
2637
|
// list is what the person is choosing from now). What it must not cover:
|
|
2546
2638
|
// open lists, and the other anchors the step allows (a map step's
|
|
@@ -2663,7 +2755,7 @@ function BubbleBody(p) {
|
|
|
2663
2755
|
const b = p.bubble;
|
|
2664
2756
|
const title = b.error ? b.error.title : b.title;
|
|
2665
2757
|
const why = b.error ? (b.error.detail ?? "") : b.why;
|
|
2666
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "eg-b-top", children: [jsxRuntime.jsxs("span", { className: "eg-mis", children: ["\u0E20\u0E32\u0E23\u0E01\u0E34\u0E08 ", b.missionNo, " \u00B7 ", b.missionTitle, b.replay ? " (ทบทวน)" : ""] }), jsxRuntime.jsxs("span", { className: "eg-cnt", children: ["\u0E02\u0E31\u0E49\u0E19\u0E17\u0E35\u0E48 ", b.index + 1, "/", b.total] })] }), jsxRuntime.jsx("div", { className: "eg-pips", "aria-hidden": "true", children: Array.from({ length: b.total }, (_, i) => (jsxRuntime.jsx("i", { className: i < b.index ? "eg-d" : i === b.index ? "eg-c" : undefined }, i))) }), jsxRuntime.jsx("p", { className: "eg-b-t", id: BUBBLE_TITLE_ID, children: jsxRuntime.jsx(GuideTitle, { text: title }) }), jsxRuntime.jsx("p", { className: "eg-b-w", id: BUBBLE_WHY_ID, hidden: !why, children: jsxRuntime.jsx(GuideTitle, { text: why }) }), jsxRuntime.jsxs("div", { className: "eg-b-f", children: [jsxRuntime.jsx("button", { type: "button", className: "eg-exit", onClick: p.onExit, children: b.replay ? "จบการทบทวน" : "ออกจากไกด์" }), jsxRuntime.jsxs("span", { style: { display: "flex", gap: 6 }, children: [b.showEndWithoutSave ? (jsxRuntime.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 ? (jsxRuntime.jsx("button", { type: "button", className: "eg-btn eg-primary", onClick: p.onNext, children: "\u0E16\u0E31\u0E14\u0E44\u0E1B" })) : null] })] })] }));
|
|
2758
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "eg-b-top", children: [jsxRuntime.jsxs("span", { className: "eg-mis", children: ["\u0E20\u0E32\u0E23\u0E01\u0E34\u0E08 ", b.missionNo, " \u00B7 ", b.missionTitle, b.replay ? " (ทบทวน)" : ""] }), jsxRuntime.jsxs("span", { className: "eg-cnt", children: ["\u0E02\u0E31\u0E49\u0E19\u0E17\u0E35\u0E48 ", b.index + 1, "/", b.total] })] }), jsxRuntime.jsx("div", { className: "eg-pips", "aria-hidden": "true", children: Array.from({ length: b.total }, (_, i) => (jsxRuntime.jsx("i", { className: i < b.index ? "eg-d" : i === b.index ? "eg-c" : undefined }, i))) }), jsxRuntime.jsx("p", { className: "eg-b-t", id: BUBBLE_TITLE_ID, children: jsxRuntime.jsx(GuideTitle, { text: title }) }), jsxRuntime.jsx("p", { className: "eg-b-w", id: BUBBLE_WHY_ID, hidden: !why, children: jsxRuntime.jsx(GuideTitle, { text: why }) }), b.status && !b.error ? (jsxRuntime.jsx("p", { className: "eg-b-s", role: "status", "data-eg-status": "", children: b.status })) : null, jsxRuntime.jsxs("div", { className: "eg-b-f", children: [jsxRuntime.jsx("button", { type: "button", className: "eg-exit", onClick: p.onExit, children: b.replay ? "จบการทบทวน" : "ออกจากไกด์" }), jsxRuntime.jsxs("span", { style: { display: "flex", gap: 6 }, children: [b.showEndWithoutSave ? (jsxRuntime.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 ? (jsxRuntime.jsx("button", { type: "button", className: "eg-btn eg-primary", onClick: p.onNext, children: "\u0E16\u0E31\u0E14\u0E44\u0E1B" })) : null] })] })] }));
|
|
2667
2759
|
}
|
|
2668
2760
|
/** The fingertip at ≈62% across and down the target; upside down near the bottom. */
|
|
2669
2761
|
function handPosition(spot, viewportHeight) {
|
|
@@ -3809,12 +3901,14 @@ function GuideRuntimeInner({ config, organizationId, code, routing, progress: pr
|
|
|
3809
3901
|
missionNo,
|
|
3810
3902
|
missionTitle: mission.title,
|
|
3811
3903
|
replay: screen.replay,
|
|
3812
|
-
|
|
3813
|
-
|
|
3904
|
+
// Steps this person skips (requires / skipIf) are not counted.
|
|
3905
|
+
index: stepPosition(mission, screen.index, env(), state.progress.context).no - 1,
|
|
3906
|
+
total: stepPosition(mission, screen.index, env(), state.progress.context).total,
|
|
3814
3907
|
title: bridge ? "กดปุ่มเมนู" : resolveText(step.title, stepCtx),
|
|
3815
3908
|
why: bridge ? `เมนูทั้งหมดของ ${suite.appName} อยู่ในนี้` : resolveText(step.why, stepCtx),
|
|
3816
3909
|
error: screen.error,
|
|
3817
|
-
|
|
3910
|
+
status: bridge ? null : screen.status,
|
|
3911
|
+
showNext: !bridge && (kind === "input" || kind === "view" || (kind === "select" && screen.replay && screen.replayNext)),
|
|
3818
3912
|
showEndWithoutSave: !bridge && screen.replay && kind === "commit",
|
|
3819
3913
|
}, 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" }) }));
|
|
3820
3914
|
}
|
|
@@ -3876,6 +3970,7 @@ exports.apiCallDetail = apiCallDetail;
|
|
|
3876
3970
|
exports.emitGuideEvent = emitGuideEvent;
|
|
3877
3971
|
exports.fillRoute = fillRoute;
|
|
3878
3972
|
exports.guideAnchor = guideAnchor;
|
|
3973
|
+
exports.guideMenuShown = guideMenuShown;
|
|
3879
3974
|
exports.loadGuides = loadGuides;
|
|
3880
3975
|
exports.matchApiPath = matchApiPath;
|
|
3881
3976
|
exports.matchRoute = matchRoute;
|
|
@@ -3884,4 +3979,4 @@ exports.reportApiCall = reportApiCall;
|
|
|
3884
3979
|
exports.reportApiEvent = reportApiEvent;
|
|
3885
3980
|
exports.storeGuides = storeGuides;
|
|
3886
3981
|
exports.useGuideEntry = useGuideEntry;
|
|
3887
|
-
//# sourceMappingURL=guide-runtime-
|
|
3982
|
+
//# sourceMappingURL=guide-runtime-CLVSNkTN.cjs.map
|