@mafianacho/nacholens 0.0.0-stage → 0.3.0
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/LICENSE +202 -0
- package/NOTICE +13 -0
- package/README.de.md +46 -0
- package/README.fr.md +46 -0
- package/README.ja.md +46 -0
- package/README.ko.md +46 -0
- package/README.md +45 -2
- package/README.zh.md +46 -0
- package/demo/shop/v1/README.md +7 -0
- package/demo/shop/v1/api.js +78 -0
- package/demo/shop/v1/db.js +38 -0
- package/demo/shop/v1/gateway.js +50 -0
- package/demo/shop/v1/mock-external.js +17 -0
- package/demo/shop/v1/public/app.js +32 -0
- package/demo/shop/v1/public/format.js +2 -0
- package/demo/shop/v1/public/index.html +13 -0
- package/demo/shop/v1/public/styles.css +4 -0
- package/demo/shop/v2/README.md +7 -0
- package/demo/shop/v2/api.js +88 -0
- package/demo/shop/v2/db.js +38 -0
- package/demo/shop/v2/gateway.js +50 -0
- package/demo/shop/v2/mock-external.js +17 -0
- package/demo/shop/v2/public/app.js +33 -0
- package/demo/shop/v2/public/format.js +3 -0
- package/demo/shop/v2/public/index.html +13 -0
- package/demo/shop/v2/public/styles.css +5 -0
- package/docs/guide.ko.md +97 -0
- package/docs/guide.md +142 -0
- package/docs/model-schema.md +137 -0
- package/docs/review.md +78 -0
- package/examples/demo-shop.artifact.html +1535 -0
- package/examples/demo-shop.artifact.json +7 -0
- package/examples/demo-shop.html +1535 -0
- package/examples/external/README.md +12 -0
- package/examples/external/full-stack-fastapi-template/LICENSE +21 -0
- package/examples/external/full-stack-fastapi-template/changes.json +56 -0
- package/examples/external/full-stack-fastapi-template/full-stack-fastapi-template-backend.html +1535 -0
- package/models/demo-shop/changes.auto.json +121 -0
- package/models/demo-shop/changes.example.json +16 -0
- package/models/demo-shop/intent.example.json +75 -0
- package/models/demo-shop/model.json +3151 -0
- package/package.json +60 -4
- package/skills/nacholens/SKILL.md +235 -0
- package/src/cli.js +377 -0
- package/src/demo.js +42 -0
- package/src/diff.js +254 -0
- package/src/gitio.js +67 -0
- package/src/install.js +94 -0
- package/src/model.js +434 -0
- package/src/page.js +87 -0
- package/src/player/fonts/FONTLOG.md +30 -0
- package/src/player/fonts/OFL-Anton.txt +93 -0
- package/src/player/fonts/OFL-IBMPlex.txt +94 -0
- package/src/player/fonts/anton-400.woff2 +0 -0
- package/src/player/fonts/nacho-mono-500.woff2 +0 -0
- package/src/player/fonts/nacho-mono-600.woff2 +0 -0
- package/src/player/fonts/nacho-sans-400.woff2 +0 -0
- package/src/player/fonts/nacho-sans-500.woff2 +0 -0
- package/src/player/fonts/nacho-sans-600.woff2 +0 -0
- package/src/player/fonts/nacho-sans-700.woff2 +0 -0
- package/src/player/player.css +318 -0
- package/src/player/player.js +872 -0
- package/src/player/review.css +49 -0
- package/src/player/review.js +230 -0
- package/src/player/template.html +58 -0
- package/src/review.js +321 -0
- package/src/scan.js +255 -0
- package/src/template.js +36 -0
- package/src/verify.js +90 -0
|
@@ -0,0 +1,1535 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-target="artifact">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<meta name="generator" content="nacholens">
|
|
7
|
+
<meta name="nacholens-target" content="artifact">
|
|
8
|
+
<title>Demo shop · Nacholens</title>
|
|
9
|
+
<style>
|
|
10
|
+
/* Nacho Sans and Nacho Mono: IBM Plex Sans / Mono, Copyright 2017 IBM Corp., subset and renamed (Reserved Font Name "Plex").
|
|
11
|
+
Anton: Copyright 2020 The Anton Project Authors. Both: SIL Open Font License 1.1, https://openfontlicense.org */
|
|
12
|
+
@font-face { font-family: "Nacho Sans"; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format("woff2"); }
|
|
13
|
+
@font-face { font-family: "Nacho Sans"; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format("woff2"); }
|
|
14
|
+
@font-face { font-family: "Nacho Sans"; font-style: normal; font-weight: 600; font-display: swap; src: url(data:font/woff2;base64,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) format("woff2"); }
|
|
15
|
+
@font-face { font-family: "Nacho Sans"; font-style: normal; font-weight: 700; font-display: swap; src: url(data:font/woff2;base64,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) format("woff2"); }
|
|
16
|
+
@font-face { font-family: "Nacho Mono"; font-style: normal; font-weight: 500; font-display: swap; src: url(data:font/woff2;base64,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) format("woff2"); }
|
|
17
|
+
@font-face { font-family: "Nacho Mono"; font-style: normal; font-weight: 600; font-display: swap; src: url(data:font/woff2;base64,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) format("woff2"); }
|
|
18
|
+
@font-face { font-family: "Anton"; font-style: normal; font-weight: 400; font-display: swap; src: url(data:font/woff2;base64,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) format("woff2"); }
|
|
19
|
+
</style>
|
|
20
|
+
<style>
|
|
21
|
+
/* nacholens player — design tokens, components, layout.
|
|
22
|
+
Rule: every colour, size and duration comes from a token below; components use tokens only.
|
|
23
|
+
The palette and type roles are the Nacho Combo design system (github.com/mafianacho/nachocombo, Brand.swift):
|
|
24
|
+
section 1a holds its raw tokens for light and dark, section 1b maps the player's roles onto them. */
|
|
25
|
+
|
|
26
|
+
/* ═════════════════ 1a. Nacho Combo tokens (light, then dark) ═════════════════ */
|
|
27
|
+
:root {
|
|
28
|
+
color-scheme: light dark;
|
|
29
|
+
--paper: #FFFFFF; /* the ground: window and page background */
|
|
30
|
+
--paper2: #FFF7E1; /* tinted surfaces on paper: cards, table heads */
|
|
31
|
+
--line: #EBDDBF; /* hairlines, card borders, dashed rules */
|
|
32
|
+
--ink: #24180D; /* primary text, strong borders */
|
|
33
|
+
--ink2: #66553F; /* secondary text and metadata */
|
|
34
|
+
--nacho: #FFC43D; /* the box yellow: fills only, never text on paper */
|
|
35
|
+
--nacho-deep: #E48A0C; /* "you have to do something" as a fill */
|
|
36
|
+
--nacho-ink: #9A5A00; /* "you have to do something" as text or an outline; the focus ring */
|
|
37
|
+
--on-nacho: #2A1A0B; /* text and icons on nacho and nacho-deep fills */
|
|
38
|
+
--guac: #377F33; /* success and running */
|
|
39
|
+
--salsa: #BE3B24; /* danger, errors, "not doing" */
|
|
40
|
+
--board: #1E1610; --board2: #2B2017; --board-line: #45352A; --board-ink: #FFF1D2; --board-mute: #BFA889; --board-pick: #3A2A14;
|
|
41
|
+
--board-salsa: #F38069; --board-guac: #7FCB72;
|
|
42
|
+
--status-off: #8E8E93; /* status dot of something that is off */
|
|
43
|
+
}
|
|
44
|
+
@media (prefers-color-scheme: dark) {
|
|
45
|
+
:root {
|
|
46
|
+
--paper: #15100B; --paper2: #211810; --line: #3A2C1F; --ink: #F8EFDF; --ink2: #C7B59C;
|
|
47
|
+
--nacho-deep: #F5A53A; --nacho-ink: #F5A53A; --guac: #7FCB72; --salsa: #F38069;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* ═════════════════ 1b. Player tokens (roles mapped onto 1a) ═════════════════ */
|
|
52
|
+
:root {
|
|
53
|
+
/* neutral surfaces and text. Cards are paper2 with a line hairline and no shadow. */
|
|
54
|
+
--bg: var(--paper); --surface: var(--paper); --card: var(--paper2);
|
|
55
|
+
--hover: color-mix(in srgb, var(--paper2) 60%, var(--paper)); --sunken: var(--paper2); --canvas-dot: var(--line);
|
|
56
|
+
--border: var(--line); --border-strong: color-mix(in srgb, var(--line) 45%, var(--ink2));
|
|
57
|
+
--trail-grey: color-mix(in srgb, var(--ink2) 70%, var(--paper));
|
|
58
|
+
--text: var(--ink); --text-2: var(--ink2); --text-3: var(--ink2); --text-4: color-mix(in srgb, var(--ink2) 90%, var(--paper));
|
|
59
|
+
--on-ink: var(--paper);
|
|
60
|
+
/* accent: the nacho fill marks the current thing and the one main action; outlines and links use ink;
|
|
61
|
+
the focus ring is nacho-ink */
|
|
62
|
+
--accent: var(--nacho); --on-accent: var(--on-nacho); --accent-hover: color-mix(in srgb, var(--nacho) 85%, var(--on-nacho));
|
|
63
|
+
--accent-line: var(--ink); --accent-soft: var(--paper2); --accent-text: var(--ink);
|
|
64
|
+
--accent-done: color-mix(in srgb, var(--nacho) 45%, var(--paper2)); --focus-ring: var(--nacho-ink);
|
|
65
|
+
/* status tones: every status in the product maps to one of these. Tinted fills are paper2 (no pastel). */
|
|
66
|
+
--success: var(--guac); --success-bg: var(--paper2); --success-border: var(--guac);
|
|
67
|
+
--warning: var(--nacho-ink); --warning-bg: var(--paper2); --warning-border: var(--nacho-ink);
|
|
68
|
+
--danger: var(--salsa); --danger-bg: var(--paper2); --danger-border: var(--salsa);
|
|
69
|
+
--info: var(--ink2); --info-bg: var(--paper2); --info-border: var(--border-strong);
|
|
70
|
+
--neutral: var(--ink2); --neutral-bg: var(--paper2); --neutral-border: var(--line);
|
|
71
|
+
/* data in motion (stage only): request = nacho-deep, response = ink, inside a component = guac (running) */
|
|
72
|
+
--req: var(--nacho-deep); --res: var(--ink); --int: var(--guac);
|
|
73
|
+
--req-text: var(--nacho-ink); /* nacho-deep is a fill; as text the request colour is nacho-ink */
|
|
74
|
+
--req-soft: color-mix(in srgb, var(--req) 16%, var(--paper2)); --res-soft: color-mix(in srgb, var(--res) 10%, var(--paper2));
|
|
75
|
+
--int-soft: color-mix(in srgb, var(--int) 16%, var(--paper2));
|
|
76
|
+
/* type: Nacho Sans (IBM Plex Sans) for text and headings, Nacho Mono (IBM Plex Mono) for code and paths, Anton
|
|
77
|
+
(capitals) for the one loud line. They are embedded (fonts/, SIL OFL 1.1) as a Latin subset; Hangul and any
|
|
78
|
+
other script fall back, glyph by glyph, to the system stack. Headings never use the mono face or wide
|
|
79
|
+
tracking: Hangul set that way reads as loose letters. */
|
|
80
|
+
--font: "Nacho Sans", "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Segoe UI", "Noto Sans KR", "Malgun Gothic", system-ui, sans-serif;
|
|
81
|
+
--mono: "Nacho Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
|
|
82
|
+
--sign: Anton, var(--font);
|
|
83
|
+
--fs-xs: 11.5px; --fs-sm: 12.5px; --fs-md: 14px; --fs-lg: 16px; --fs-xl: 18px;
|
|
84
|
+
/* space (4px grid) */
|
|
85
|
+
--s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 20px; --s6: 24px;
|
|
86
|
+
/* shape: no shadows, no pill shapes (r-full is for round dots and switches only) */
|
|
87
|
+
--r-sm: 4px; --r-md: 6px; --r-lg: 10px; --r-full: 999px;
|
|
88
|
+
--focus: 0 0 0 2px var(--surface), 0 0 0 4px var(--focus-ring);
|
|
89
|
+
/* motion: UI transitions (the stage's travel timing lives in player.js) */
|
|
90
|
+
--t-fast: 120ms; --t-base: 200ms; --t-slow: 320ms; --ease-out: cubic-bezier(.2, .8, .2, 1);
|
|
91
|
+
/* layout */
|
|
92
|
+
--topbar-h: 52px; --foot-h: 24px; --side-w: 280px; --insp-w: 344px; --dock-h: clamp(170px, 32vh, 300px);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* ═════════════════ 2. Base ═════════════════ */
|
|
96
|
+
* { box-sizing: border-box; }
|
|
97
|
+
html, body { height: 100%; margin: 0; }
|
|
98
|
+
body { background: var(--bg); color: var(--text); font: var(--fs-md)/1.5 var(--font); -webkit-font-smoothing: antialiased; }
|
|
99
|
+
button, input { font: inherit; color: inherit; }
|
|
100
|
+
button { cursor: pointer; }
|
|
101
|
+
:focus-visible { outline: none; box-shadow: var(--focus); border-radius: var(--r-sm); }
|
|
102
|
+
[hidden] { display: none !important; }
|
|
103
|
+
.mono { font-family: var(--mono); }
|
|
104
|
+
.kr { word-break: keep-all; overflow-wrap: anywhere; }
|
|
105
|
+
.ell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
106
|
+
svg.i { width: 16px; height: 16px; flex: none; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
|
107
|
+
|
|
108
|
+
/* ═════════════════ 3. Components ═════════════════ */
|
|
109
|
+
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 32px; padding: 0 var(--s3); border-radius: var(--r-md); border: 1px solid var(--border-strong); background: var(--surface); font-size: var(--fs-sm); font-weight: 500; transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast); }
|
|
110
|
+
.btn:hover { background: var(--hover); }
|
|
111
|
+
.btn:disabled { opacity: .4; cursor: default; background: var(--surface); }
|
|
112
|
+
.btn.icon { width: 32px; padding: 0; }
|
|
113
|
+
.btn.primary { background: var(--accent); border-color: var(--on-accent); color: var(--on-accent); font-weight: 600; min-width: 96px; }
|
|
114
|
+
.btn.primary:hover { background: var(--accent-hover); }
|
|
115
|
+
.btn.ghost { border-color: transparent; background: transparent; color: var(--text-2); }
|
|
116
|
+
.btn.ghost:hover { background: var(--hover); color: var(--text); }
|
|
117
|
+
[data-tone="success"] { --t: var(--success); --t-bg: var(--success-bg); --t-bd: var(--success-border); }
|
|
118
|
+
[data-tone="warning"] { --t: var(--warning); --t-bg: var(--warning-bg); --t-bd: var(--warning-border); }
|
|
119
|
+
[data-tone="danger"] { --t: var(--danger); --t-bg: var(--danger-bg); --t-bd: var(--danger-border); }
|
|
120
|
+
[data-tone="info"] { --t: var(--info); --t-bg: var(--info-bg); --t-bd: var(--info-border); }
|
|
121
|
+
[data-tone="neutral"] { --t: var(--neutral); --t-bg: var(--neutral-bg); --t-bd: var(--neutral-border); }
|
|
122
|
+
.badge { display: inline-flex; align-items: center; height: 20px; padding: 0 6px; border-radius: var(--r-sm); font-size: var(--fs-xs); font-weight: 600; line-height: 1; white-space: nowrap; border: 1px solid var(--t-bd, var(--neutral-border)); background: var(--t-bg, var(--neutral-bg)); color: var(--t, var(--neutral)); }
|
|
123
|
+
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--t, var(--status-off)); flex: none; }
|
|
124
|
+
.dot[data-tone="neutral"] { background: var(--status-off); }
|
|
125
|
+
.seg { display: inline-flex; padding: 2px; gap: 2px; background: var(--sunken); border-radius: var(--r-md); }
|
|
126
|
+
.seg button { height: 24px; padding: 0 10px; border: 1px solid transparent; border-radius: var(--r-sm); background: transparent; font-size: var(--fs-xs); font-weight: 600; color: var(--text-3); }
|
|
127
|
+
.seg button[aria-pressed="true"] { background: var(--surface); color: var(--text); border-color: var(--border); }
|
|
128
|
+
.switch { display: inline-flex; align-items: center; gap: var(--s2); background: none; border: 0; padding: 0; font-size: var(--fs-sm); color: var(--text-2); }
|
|
129
|
+
.switch .track { width: 30px; height: 18px; border-radius: var(--r-full); background: var(--border-strong); position: relative; transition: background var(--t-base) var(--ease-out); }
|
|
130
|
+
.switch .track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--surface); border: 1px solid var(--border-strong); transition: transform var(--t-base) var(--ease-out); }
|
|
131
|
+
.switch[aria-checked="true"] .track { background: var(--accent); }
|
|
132
|
+
.switch[aria-checked="true"] .track::after { transform: translateX(12px); }
|
|
133
|
+
.check { width: 18px; height: 18px; flex: none; border: 1.5px solid var(--border-strong); border-radius: var(--r-sm); background: var(--surface); display: inline-grid; place-items: center; padding: 0; transition: background var(--t-fast), border-color var(--t-fast); }
|
|
134
|
+
.check svg.i { width: 12px; height: 12px; stroke-width: 2.8; color: var(--on-accent); opacity: 0; transition: opacity var(--t-fast); }
|
|
135
|
+
.check[aria-checked="true"] { background: var(--accent); border-color: var(--on-accent); }
|
|
136
|
+
.check[aria-checked="true"] svg.i { opacity: 1; }
|
|
137
|
+
.code { font-family: var(--mono); font-size: 12px; line-height: 1.6; background: var(--sunken); border-radius: var(--r-md); padding: var(--s2) var(--s3); margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text); }
|
|
138
|
+
.link { border: 0; background: none; padding: 0; color: var(--accent-text); font-size: inherit; font-weight: 500; text-decoration: underline; text-decoration-color: var(--border-strong); text-underline-offset: 2px; }
|
|
139
|
+
.link:hover { text-decoration-color: var(--accent-line); }
|
|
140
|
+
.steplink { border: 0; background: var(--sunken); color: var(--text-2); font-size: 11px; font-weight: 600; height: 18px; padding: 0 6px; border-radius: var(--r-sm); transition: background var(--t-fast), color var(--t-fast); }
|
|
141
|
+
.steplink:hover { background: var(--accent); color: var(--on-accent); }
|
|
142
|
+
.empty { padding: var(--s6) var(--s4); text-align: center; color: var(--text-3); font-size: var(--fs-sm); }
|
|
143
|
+
.search { display: flex; align-items: center; gap: var(--s2); height: 34px; padding: 0 var(--s3); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--hover); color: var(--text-3); transition: border-color var(--t-fast), background var(--t-fast); }
|
|
144
|
+
.search:focus-within { background: var(--surface); border-color: var(--border-strong); box-shadow: var(--focus); }
|
|
145
|
+
.search input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; font-size: var(--fs-sm); color: var(--text); }
|
|
146
|
+
.note { display: flex; gap: var(--s2); padding: var(--s3); border-radius: var(--r-md); background: var(--card); border: 1px solid var(--border); font-size: var(--fs-sm); }
|
|
147
|
+
.note svg.i { color: var(--t); margin-top: 2px; }
|
|
148
|
+
|
|
149
|
+
/* ═════════════════ 4. Shell ═════════════════
|
|
150
|
+
top bar / [ flows | stage + transport + review dock | current step ]. Each piece of information has one home. */
|
|
151
|
+
.app { height: 100vh; display: grid; grid-template-rows: var(--topbar-h) minmax(0, 1fr) var(--foot-h); }
|
|
152
|
+
.topbar { display: flex; align-items: center; gap: var(--s3); padding: 0 var(--s4); border-bottom: 1px solid var(--border); min-width: 0; }
|
|
153
|
+
.brand { display: flex; align-items: center; gap: var(--s2); font-family: var(--sign); font-weight: 800; font-synthesis: none; text-transform: uppercase; letter-spacing: .02em; font-size: 15px; flex: none; }
|
|
154
|
+
.brand .logo { width: 22px; height: 22px; border-radius: var(--r-md); background: var(--accent); color: var(--on-accent); border: 1.5px solid var(--on-accent); display: grid; place-items: center; font-size: 12px; font-weight: 800; }
|
|
155
|
+
.topbar .sep { width: 1px; height: 18px; background: var(--border); flex: none; }
|
|
156
|
+
.topbar .product { margin: 0; font-size: var(--fs-md); font-weight: 600; flex: none; }
|
|
157
|
+
.topbar .ref { font-family: var(--mono); font-size: var(--fs-xs); color: var(--text-2); padding: 2px 6px; border-radius: var(--r-sm); background: var(--sunken); flex: none; }
|
|
158
|
+
.topbar .commit { color: var(--text-2); font-size: var(--fs-sm); min-width: 0; }
|
|
159
|
+
.topbar .grow { flex: 1; }
|
|
160
|
+
.foot { display: flex; align-items: center; justify-content: flex-end; gap: var(--s2); padding: 0 var(--s4); border-top: 1px solid var(--border); background: var(--surface); font-size: 11px; line-height: 1; color: var(--text-3); min-width: 0; }
|
|
161
|
+
.foot a { color: inherit; text-decoration: none; }
|
|
162
|
+
.foot a:hover { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
|
|
163
|
+
.body { display: grid; min-height: 0; grid-template-columns: var(--side-w) minmax(0, 1fr) var(--insp-w); grid-template-rows: minmax(240px, 1fr) auto auto;
|
|
164
|
+
grid-template-areas: "side stage insp" "side transport insp" "side dock insp"; }
|
|
165
|
+
.side { grid-area: side; border-right: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; }
|
|
166
|
+
.stage { grid-area: stage; }
|
|
167
|
+
.transport { grid-area: transport; }
|
|
168
|
+
.dock { grid-area: dock; height: var(--dock-h); }
|
|
169
|
+
.insp { grid-area: insp; border-left: 1px solid var(--border); min-height: 0; overflow-y: auto; overflow-x: hidden; }
|
|
170
|
+
|
|
171
|
+
/* ═════════════════ 5. Sidebar: flows and their steps ═════════════════ */
|
|
172
|
+
.side-tools { padding: var(--s3); }
|
|
173
|
+
.side-list { flex: 1; min-height: 0; overflow: auto; padding: 0 var(--s2) var(--s3); }
|
|
174
|
+
.gh { display: flex; align-items: center; gap: 6px; width: 100%; padding: var(--s2) var(--s2) var(--s1); border: 0; background: none; color: var(--text-3); font-size: var(--fs-xs); font-weight: 600; text-align: left; }
|
|
175
|
+
.gh svg.i { width: 14px; height: 14px; transition: transform var(--t-base) var(--ease-out); }
|
|
176
|
+
.gh[aria-expanded="false"] svg.i { transform: rotate(-90deg); }
|
|
177
|
+
.gh .n { color: var(--text-4); }
|
|
178
|
+
.uc { display: flex; align-items: flex-start; gap: var(--s2); width: 100%; padding: var(--s2); border: 0; border-radius: var(--r-md); background: none; text-align: left; transition: background var(--t-fast); }
|
|
179
|
+
.uc:hover { background: var(--hover); }
|
|
180
|
+
.uc[aria-current="true"] { background: var(--sunken); }
|
|
181
|
+
.uc .main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
182
|
+
.uc .t { font-weight: 600; }
|
|
183
|
+
.uc .m { font-family: var(--mono); font-size: 11px; color: var(--text-3); }
|
|
184
|
+
.steps { list-style: none; margin: 2px 0 6px; padding: 0 0 0 10px; position: relative; }
|
|
185
|
+
.steps::before { content: ""; position: absolute; left: 21px; top: 10px; bottom: 10px; width: 1px; background: var(--border); }
|
|
186
|
+
.st { display: flex; align-items: center; gap: var(--s2); min-height: 30px; padding: 3px 6px; border-radius: var(--r-md); font-size: var(--fs-sm); color: var(--text-2); cursor: pointer; position: relative; transition: background var(--t-fast), color var(--t-fast); }
|
|
187
|
+
.st:hover { background: var(--hover); color: var(--text); }
|
|
188
|
+
.st[aria-current="step"] { color: var(--text); font-weight: 600; background: var(--accent-soft); }
|
|
189
|
+
.st .n { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font-size: 11px; font-weight: 600; color: var(--text-3); background: var(--surface); border: 1px solid var(--border-strong); flex: none; position: relative; z-index: 1; font-variant-numeric: tabular-nums; transition: background var(--t-base), color var(--t-base), border-color var(--t-base); }
|
|
190
|
+
.st.done .n { background: var(--sunken); }
|
|
191
|
+
.st[aria-current="step"] .n { background: var(--accent); border-color: var(--on-accent); color: var(--on-accent); }
|
|
192
|
+
.st .lbl { flex: 1; min-width: 0; }
|
|
193
|
+
.st .chg { font-size: 11px; font-weight: 600; color: var(--t); flex: none; }
|
|
194
|
+
.st .check { width: 16px; height: 16px; }
|
|
195
|
+
|
|
196
|
+
/* ═════════════════ 6. Stage ═════════════════ */
|
|
197
|
+
.stage { position: relative; min-height: 0; overflow: hidden; background-color: var(--bg); background-image: radial-gradient(var(--canvas-dot) 1px, transparent 1px); background-size: 20px 20px; }
|
|
198
|
+
.stage svg.canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
|
|
199
|
+
.caption { position: absolute; top: var(--s4); left: 50%; transform: translateX(-50%); max-width: calc(100% - 32px); display: flex; align-items: center; gap: var(--s2); padding: 6px 12px 6px 6px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); font-size: var(--fs-sm); z-index: 2; transition: opacity var(--t-base) var(--ease-out); }
|
|
200
|
+
.caption .leg { display: inline-flex; align-items: center; height: 22px; padding: 0 7px; border-radius: var(--r-sm); font-size: var(--fs-xs); font-weight: 700; color: var(--lc); background: var(--surface); border: 1px solid var(--lc); flex: none; white-space: nowrap; }
|
|
201
|
+
.caption .leg.req { --lc: var(--req-text); --lc-soft: var(--req-soft); }
|
|
202
|
+
.caption .leg.res { --lc: var(--res); --lc-soft: var(--res-soft); }
|
|
203
|
+
.caption .leg.int { --lc: var(--int); --lc-soft: var(--int-soft); }
|
|
204
|
+
.caption .leg.idle { --lc: var(--text-3); --lc-soft: var(--sunken); }
|
|
205
|
+
.caption .txt { min-width: 0; }
|
|
206
|
+
.caption .txt.mono { font-size: 12px; }
|
|
207
|
+
.caption.swap { opacity: 0; }
|
|
208
|
+
.stage.in-detail .caption { left: auto; right: var(--s4); transform: none; max-width: calc(100% - 330px); }
|
|
209
|
+
.crumbs { position: absolute; top: var(--s4); left: var(--s4); z-index: 3; display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 14px 0 4px; background: var(--card); border: 1px solid var(--border); border-radius: var(--r-md); font-size: var(--fs-sm); }
|
|
210
|
+
.crumbs .back { display: inline-flex; align-items: center; gap: 4px; height: 28px; padding: 0 10px 0 6px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface); font-size: var(--fs-xs); font-weight: 600; color: var(--text-2); transition: background var(--t-fast), color var(--t-fast); }
|
|
211
|
+
.crumbs .back:hover { background: var(--accent); border-color: var(--on-accent); color: var(--on-accent); }
|
|
212
|
+
.crumbs .back svg.i { width: 14px; height: 14px; }
|
|
213
|
+
.crumbs .here { font-weight: 700; }
|
|
214
|
+
.crumbs .sub { color: var(--text-3); }
|
|
215
|
+
.hidden-note { position: absolute; left: var(--s4); bottom: var(--s3); font-size: var(--fs-xs); color: var(--text-3); background: var(--card); padding: 2px 8px; border-radius: var(--r-sm); border: 1px solid var(--border); }
|
|
216
|
+
/* architecture nodes */
|
|
217
|
+
.nd .box { fill: var(--card); stroke: var(--border-strong); stroke-width: 1.25; transition: stroke var(--t-base), stroke-width var(--t-base); }
|
|
218
|
+
.nd .ibox { fill: var(--surface); stroke: var(--border); stroke-width: 1; transition: fill var(--t-base); }
|
|
219
|
+
.nd .ico { fill: none; stroke: var(--text-2); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; transition: stroke var(--t-base); }
|
|
220
|
+
.nd .nm { font-size: 14px; font-weight: 600; fill: var(--text); }
|
|
221
|
+
.nd .kd { font-size: 11px; fill: var(--text-3); }
|
|
222
|
+
.nd.has-detail { cursor: pointer; }
|
|
223
|
+
.nd.has-detail:hover .box { stroke: var(--accent-line); }
|
|
224
|
+
.nd .open { fill: none; stroke: var(--text-4); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: stroke var(--t-fast); }
|
|
225
|
+
.nd.has-detail:hover .open { stroke: var(--accent-line); }
|
|
226
|
+
/* not on this flow: dimmed by colour (text stays >= 4.5:1), not by opacity */
|
|
227
|
+
.nd.off .box, .it.off .box { fill: var(--surface); stroke: var(--border); }
|
|
228
|
+
.nd.off .ibox { fill: var(--surface); } .nd.off .ico, .nd.off .open { stroke: var(--text-4); }
|
|
229
|
+
.nd.off .nm, .it.off .t1 { fill: var(--text-3); font-weight: 500; } .nd.off .kd, .it.off .t2 { fill: var(--text-4); }
|
|
230
|
+
.nd.visited .box, .it.visited .box { stroke: var(--trail-grey); }
|
|
231
|
+
.nd.active .box, .it.active .box, .it.hitcard .box { stroke: var(--text); stroke-width: 2; }
|
|
232
|
+
.nd.active .ibox { fill: var(--accent); stroke: var(--on-accent); } .nd.active .ico { stroke: var(--on-accent); }
|
|
233
|
+
.nd.working .box, .it.working .box { stroke: var(--int); stroke-width: 2; }
|
|
234
|
+
.nd.working .ibox { fill: var(--int-soft); } .nd.working .ico { stroke: var(--int); }
|
|
235
|
+
.nd:focus-visible, .it:focus-visible { box-shadow: none; }
|
|
236
|
+
.nd:focus-visible .box, .it:focus-visible .box { stroke: var(--focus-ring); stroke-width: 2.25; }
|
|
237
|
+
/* change tags (opaque, one style everywhere) */
|
|
238
|
+
.tagbg { fill-opacity: 1; stroke-width: 1; }
|
|
239
|
+
.tagtx { font-size: 11px; font-weight: 700; text-anchor: middle; }
|
|
240
|
+
.chg-added .tagbg { fill: var(--success-bg); stroke: var(--success-border); } .chg-added .tagtx { fill: var(--success); }
|
|
241
|
+
.chg-modified .tagbg { fill: var(--warning-bg); stroke: var(--warning-border); } .chg-modified .tagtx { fill: var(--warning); }
|
|
242
|
+
.chg-removed .tagbg { fill: var(--danger-bg); stroke: var(--danger-border); } .chg-removed .tagtx { fill: var(--danger); }
|
|
243
|
+
/* links and wires */
|
|
244
|
+
.lk, .wr { fill: none; stroke: var(--border-strong); stroke-width: 1.5; transition: stroke var(--t-slow), stroke-width var(--t-slow), opacity var(--t-slow); }
|
|
245
|
+
.lk.off, .wr.off { opacity: .32; }
|
|
246
|
+
.lk.visited, .wr.visited { stroke: var(--trail-grey); stroke-width: 2; }
|
|
247
|
+
.wr.stubwire { stroke-dasharray: 3 4; }
|
|
248
|
+
.wr.chg-added:not(.visited) { stroke: var(--success-border); stroke-width: 2; }
|
|
249
|
+
.wr.chg-modified:not(.visited) { stroke: var(--warning-border); stroke-width: 2; }
|
|
250
|
+
/* inside a component */
|
|
251
|
+
.it .box { fill: var(--card); stroke: var(--border-strong); stroke-width: 1.25; transition: stroke var(--t-base), stroke-width var(--t-base); }
|
|
252
|
+
.it.part, .it.table, .it.endpoint, .it.stub.nav { cursor: pointer; }
|
|
253
|
+
.it.part:hover .box, .it.table:hover .box, .it.endpoint:hover .box, .it.stub.nav:hover .box { stroke: var(--accent-line); }
|
|
254
|
+
.it.stub .box { fill: var(--surface); stroke-dasharray: 4 3; }
|
|
255
|
+
.it.sel .box { stroke: var(--focus-ring); stroke-width: 2.25; }
|
|
256
|
+
.it .t1 { font-size: 14px; font-weight: 600; fill: var(--text); }
|
|
257
|
+
.it .t2 { font-size: 11px; fill: var(--text-3); }
|
|
258
|
+
.it.stub .t1 { font-size: 14px; text-anchor: middle; } .it.stub .t2 { text-anchor: middle; }
|
|
259
|
+
.it .t1.mono { font-family: var(--mono); }
|
|
260
|
+
.it .hr { stroke: var(--border); }
|
|
261
|
+
.it .colname { font-size: 11.5px; fill: var(--text-2); font-family: var(--mono); }
|
|
262
|
+
.it .coltype { font-size: 11px; fill: var(--text-4); font-family: var(--mono); text-anchor: end; }
|
|
263
|
+
.it .collab { font-size: 11px; fill: var(--text-4); font-family: var(--mono); }
|
|
264
|
+
.it .colname.col-hit { fill: var(--accent-text); font-weight: 700; }
|
|
265
|
+
.it .mth rect { fill: var(--surface); stroke: var(--border); } .it .mth text { font-size: 11px; font-weight: 700; fill: var(--text-2); text-anchor: middle; font-family: var(--mono); }
|
|
266
|
+
.it .opb rect { fill: var(--board); } .it .opb text { fill: var(--board-ink); font-size: 11px; font-weight: 700; text-anchor: middle; }
|
|
267
|
+
.colh { font-size: 11px; font-weight: 700; fill: var(--text-4); text-anchor: middle; }
|
|
268
|
+
.xchip rect { fill: var(--card); stroke: var(--int); stroke-width: 1; } .xchip text { font-size: 11px; fill: var(--int); font-family: var(--mono); text-anchor: middle; }
|
|
269
|
+
/* data in motion */
|
|
270
|
+
.flowline { fill: none; stroke-width: 2.5; stroke-linecap: round; stroke-dasharray: 1 9; animation: march .5s linear infinite; }
|
|
271
|
+
.trail { fill: none; stroke-width: 2.5; stroke-linecap: round; }
|
|
272
|
+
.flowline.req, .trail.req { stroke: var(--req); } .flowline.res, .trail.res { stroke: var(--res); } .flowline.int, .trail.int { stroke: var(--int); }
|
|
273
|
+
.trail.past { opacity: .28; }
|
|
274
|
+
@keyframes march { from { stroke-dashoffset: 10; } to { stroke-dashoffset: 0; } }
|
|
275
|
+
.pk .core { stroke: var(--surface); stroke-width: 2.5; }
|
|
276
|
+
.pk .halo { opacity: .25; animation: halo 1.1s var(--ease-out) infinite; }
|
|
277
|
+
.pk.req .core, .pk.req .halo { fill: var(--req); } .pk.res .core, .pk.res .halo { fill: var(--res); } .pk.int .core, .pk.int .halo { fill: var(--int); }
|
|
278
|
+
@keyframes halo { from { r: 7px; opacity: .35; } to { r: 18px; opacity: 0; } }
|
|
279
|
+
.ring { fill: none; stroke-width: 2; transform-box: fill-box; transform-origin: center; animation: ring .55s var(--ease-out) forwards; }
|
|
280
|
+
.ring.req { stroke: var(--req); } .ring.res { stroke: var(--res); } .ring.int { stroke: var(--int); }
|
|
281
|
+
@keyframes ring { from { opacity: .9; transform: scale(1); } to { opacity: 0; transform: scale(1.14); } }
|
|
282
|
+
.wbar-bg { fill: var(--int-soft); } .wbar { fill: var(--int); }
|
|
283
|
+
.zoom { fill: var(--surface); stroke: var(--accent-line); stroke-width: 1.5; }
|
|
284
|
+
.canvas.fade-in { animation: stagein var(--t-slow) var(--ease-out); }
|
|
285
|
+
@keyframes stagein { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
|
|
286
|
+
|
|
287
|
+
/* ═════════════════ 7. Transport ═════════════════ */
|
|
288
|
+
.transport { display: flex; align-items: center; gap: var(--s2); padding: var(--s2) var(--s4); border-top: 1px solid var(--border); background: var(--surface); min-width: 0; }
|
|
289
|
+
.scrub { flex: 1; display: flex; gap: 3px; min-width: 120px; height: 28px; align-items: center; }
|
|
290
|
+
.seg-step { flex: 1; height: 6px; border-radius: 1px; background: var(--sunken); border: 0; padding: 0; position: relative; overflow: hidden; transition: height var(--t-fast); }
|
|
291
|
+
.seg-step:hover { height: 10px; }
|
|
292
|
+
.seg-step i { position: absolute; top: 0; bottom: 0; left: 0; width: 0; background: var(--accent); border-radius: 1px; }
|
|
293
|
+
.seg-step.done i { width: 100%; background: var(--accent-done); }
|
|
294
|
+
.counter { font-size: var(--fs-sm); color: var(--text-2); font-variant-numeric: tabular-nums; min-width: 44px; text-align: right; }
|
|
295
|
+
|
|
296
|
+
/* ═════════════════ 8. Inspector: the current step (or the item picked inside a component) ═════════════════ */
|
|
297
|
+
.ih { padding: var(--s5) var(--s5) var(--s3); }
|
|
298
|
+
.eyebrow { font-size: var(--fs-xs); font-weight: 600; color: var(--text-3); margin: 0 0 6px; }
|
|
299
|
+
.lead { font-size: 15px; line-height: 1.65; color: var(--text); margin: 0; }
|
|
300
|
+
.isec { padding: var(--s3) var(--s5); }
|
|
301
|
+
.isec h2 { margin: 0 0 var(--s2); font-size: var(--fs-xs); font-weight: 600; color: var(--text-3); }
|
|
302
|
+
.isec p { margin: 0; }
|
|
303
|
+
.ev { list-style: none; margin: 0; padding: 0; font-family: var(--mono); font-size: 12px; }
|
|
304
|
+
.ev li { display: flex; align-items: flex-start; gap: var(--s2); padding: 4px 0; border-bottom: 1px dashed var(--border); color: var(--text-2); }
|
|
305
|
+
.ev li:last-child { border-bottom: 0; }
|
|
306
|
+
.ev li span:first-child { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
307
|
+
.ev li.hit { color: var(--text); }
|
|
308
|
+
.kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 6px var(--s3); font-size: var(--fs-sm); margin: 8px 0 0; }
|
|
309
|
+
.kv dt { color: var(--text-3); font-family: var(--mono); }
|
|
310
|
+
.kv dd { margin: 0; min-width: 0; font-family: var(--mono); overflow-wrap: anywhere; }
|
|
311
|
+
.rel { list-style: none; margin: 0; padding: 0; }
|
|
312
|
+
.rel li { display: flex; flex-direction: column; padding: 6px 0; border-bottom: 1px dashed var(--border); }
|
|
313
|
+
.rel li:last-child { border-bottom: 0; }
|
|
314
|
+
.rel .who { font-size: var(--fs-sm); color: var(--text); }
|
|
315
|
+
.rel .how { font-size: 12px; color: var(--text-3); overflow-wrap: anywhere; }
|
|
316
|
+
.xf { margin: 0 0 var(--s2); }
|
|
317
|
+
.xf .at { font-size: var(--fs-sm); font-weight: 600; }
|
|
318
|
+
.xf .io { font-family: var(--mono); font-size: 12px; color: var(--int); }
|
|
319
|
+
.xf .map { font-family: var(--mono); font-size: 12px; color: var(--text-2); margin: 2px 0 0; padding: 0; list-style: none; }
|
|
320
|
+
.before { font-size: var(--fs-sm); }
|
|
321
|
+
.before dt { font-family: var(--font); }
|
|
322
|
+
.legend { display: grid; grid-template-columns: 28px 1fr; gap: 10px var(--s3); align-items: center; font-size: var(--fs-sm); color: var(--text-2); }
|
|
323
|
+
.legend svg { display: block; }
|
|
324
|
+
.gone { list-style: none; margin: 0; padding: 0; font-size: var(--fs-sm); }
|
|
325
|
+
.gone li { padding: 4px 0; color: var(--text-2); }
|
|
326
|
+
|
|
327
|
+
/* ═════════════════ 9. Responsive and reduced motion ═════════════════ */
|
|
328
|
+
@media (max-width: 1280px) { :root { --side-w: 248px; --insp-w: 304px; } }
|
|
329
|
+
@media (max-width: 1100px) {
|
|
330
|
+
.app { height: auto; min-height: 100vh; }
|
|
331
|
+
.body { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 460px auto auto auto; grid-template-areas: "side" "stage" "transport" "insp" "dock"; }
|
|
332
|
+
.side { border-right: 0; border-bottom: 1px solid var(--border); }
|
|
333
|
+
.side-list { max-height: 260px; }
|
|
334
|
+
.insp { border-left: 0; border-top: 1px solid var(--border); overflow: visible; }
|
|
335
|
+
.stage.in-detail .caption { max-width: calc(100% - 32px); top: 64px; }
|
|
336
|
+
.topbar .commit { display: none; }
|
|
337
|
+
}
|
|
338
|
+
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }
|
|
339
|
+
|
|
340
|
+
</style>
|
|
341
|
+
<style>
|
|
342
|
+
/* Review dock (below the stage). Tokens and shared components (badge, check, seg, link, steplink, empty) come from player.css. */
|
|
343
|
+
.dock { display: flex; flex-direction: column; min-height: 0; min-width: 0; border-top: 1px solid var(--border); background: var(--surface); position: relative; }
|
|
344
|
+
.dock.collapsed { height: auto; }
|
|
345
|
+
.dock.collapsed .grip { display: none; }
|
|
346
|
+
.grip { height: 7px; margin-top: -4px; cursor: row-resize; position: relative; z-index: 3; flex: none; }
|
|
347
|
+
.grip::after { content: ""; position: absolute; left: 50%; top: 2px; width: 36px; height: 3px; margin-left: -18px; border-radius: 2px; background: var(--border-strong); opacity: 0; transition: opacity var(--t-fast); }
|
|
348
|
+
.grip:hover::after { opacity: 1; }
|
|
349
|
+
.dtabs { display: flex; align-items: stretch; gap: 2px; padding: 0 var(--s2) 0 var(--s3); border-bottom: 1px solid var(--border); flex: none; overflow-x: auto; }
|
|
350
|
+
.dock.collapsed .dtabs { border-bottom: 0; }
|
|
351
|
+
.dtabs .grow { flex: 1; }
|
|
352
|
+
.dtabs .fold { align-self: center; }
|
|
353
|
+
.dtabs .fold svg.i { transition: transform var(--t-base) var(--ease-out); }
|
|
354
|
+
.dock.collapsed .dtabs .fold svg.i { transform: rotate(180deg); }
|
|
355
|
+
.dtab { display: inline-flex; align-items: center; gap: var(--s2); height: 44px; padding: 0 var(--s3); border: 0; background: none; color: var(--text-2); font-weight: 500; position: relative; white-space: nowrap; transition: color var(--t-fast); }
|
|
356
|
+
.dtab:hover { color: var(--text); }
|
|
357
|
+
.dtab[aria-selected="true"] { color: var(--text); font-weight: 600; }
|
|
358
|
+
.dtab[aria-selected="true"]::after { content: ""; position: absolute; left: var(--s3); right: var(--s3); bottom: -1px; height: 2px; border-radius: 2px; background: var(--accent-line); }
|
|
359
|
+
.dtab .role { font-size: 11px; font-weight: 600; color: var(--text-3); padding: 0 5px; border: 1px solid var(--border); height: 18px; display: inline-flex; align-items: center; border-radius: var(--r-sm); background: var(--sunken); }
|
|
360
|
+
.dtab .left { font-size: var(--fs-xs); font-weight: 700; color: var(--t); font-variant-numeric: tabular-nums; }
|
|
361
|
+
.dtab .left.none { color: var(--text-4); font-weight: 600; }
|
|
362
|
+
.dtab .ok { color: var(--success); display: inline-flex; }
|
|
363
|
+
.dbody { flex: 1; min-height: 0; overflow: auto; }
|
|
364
|
+
.dhead { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s1) var(--s3); padding: var(--s3) var(--s4) var(--s2); }
|
|
365
|
+
.dhead .q { font-weight: 600; }
|
|
366
|
+
.dhead .sub { font-size: var(--fs-sm); color: var(--text-3); }
|
|
367
|
+
.dhead .grow { flex: 1; }
|
|
368
|
+
.rowlist { list-style: none; margin: 0; padding: 0 var(--s2) var(--s3); }
|
|
369
|
+
.ri { display: flex; align-items: flex-start; gap: var(--s3); padding: var(--s2); border-radius: var(--r-md); transition: background var(--t-fast); }
|
|
370
|
+
.ri:hover { background: var(--hover); }
|
|
371
|
+
.ri .check { margin-top: 1px; }
|
|
372
|
+
.ri .gap { width: 18px; flex: none; }
|
|
373
|
+
.ri .main { flex: 1; min-width: 0; }
|
|
374
|
+
.ri .main.small { font-size: var(--fs-sm); }
|
|
375
|
+
.ri .t { font-weight: 500; }
|
|
376
|
+
.ri .t.mono { font-size: 13px; }
|
|
377
|
+
.ri .m { font-size: var(--fs-xs); color: var(--text-3); margin-top: 1px; display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }
|
|
378
|
+
.ri .end { display: flex; gap: 6px; align-items: center; flex: none; }
|
|
379
|
+
.ri.done .t { color: var(--text-3); text-decoration: line-through; text-decoration-color: var(--text-4); }
|
|
380
|
+
.ri .link.plain { color: inherit; font-weight: 500; text-align: left; }
|
|
381
|
+
.chev { border: 0; background: none; padding: 2px; color: var(--text-3); border-radius: var(--r-sm); display: inline-flex; }
|
|
382
|
+
.chev svg.i { transition: transform var(--t-base) var(--ease-out); }
|
|
383
|
+
.chev[aria-expanded="true"] svg.i { transform: rotate(180deg); }
|
|
384
|
+
.files { list-style: none; margin: 6px 0 0; padding: 0; font-family: var(--mono); font-size: 12px; color: var(--text-2); }
|
|
385
|
+
.files li { display: flex; gap: var(--s2); padding: 2px 0; }
|
|
386
|
+
.files li span:first-child { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
387
|
+
.files .ln, .files .st { color: var(--text-4); flex: none; }
|
|
388
|
+
.subhead { display: flex; align-items: center; gap: var(--s2); padding: var(--s3) var(--s4) var(--s1); font-size: var(--fs-xs); font-weight: 600; color: var(--text-3); }
|
|
389
|
+
.subhead .link { font-size: var(--fs-xs); }
|
|
390
|
+
@media (max-width: 1100px) { .dock { height: auto; max-height: 70vh; } }
|
|
391
|
+
|
|
392
|
+
</style>
|
|
393
|
+
</head>
|
|
394
|
+
<body>
|
|
395
|
+
<div class="app" id="app">
|
|
396
|
+
<header class="topbar">
|
|
397
|
+
<div class="brand"><span class="logo" aria-hidden="true">N</span>nacholens</div>
|
|
398
|
+
<span class="sep" aria-hidden="true"></span>
|
|
399
|
+
<h1 class="product" id="sv-product"></h1>
|
|
400
|
+
<span class="ref" id="sv-ref" hidden></span>
|
|
401
|
+
<span class="commit ell" id="sv-commit"></span>
|
|
402
|
+
<span class="grow"></span>
|
|
403
|
+
<button class="switch" id="sv-overlay" type="button" role="switch" aria-checked="true" hidden><span class="track" aria-hidden="true"></span>Highlight changes</button>
|
|
404
|
+
</header>
|
|
405
|
+
<div class="body" id="sv-body">
|
|
406
|
+
<nav class="side" aria-label="Flows and steps">
|
|
407
|
+
<div class="side-tools">
|
|
408
|
+
<label class="search"><svg class="i" viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg><input id="sv-q" type="search" placeholder="Search flows" aria-label="Search flows"></label>
|
|
409
|
+
</div>
|
|
410
|
+
<div class="side-list" id="sv-list"></div>
|
|
411
|
+
</nav>
|
|
412
|
+
<section class="stage" id="sv-stage" aria-label="Data flow animation">
|
|
413
|
+
<div class="crumbs" id="sv-crumbs" hidden></div>
|
|
414
|
+
<div class="caption" id="sv-caption" aria-live="polite"></div>
|
|
415
|
+
<svg class="canvas" id="sv-canvas" role="img" aria-label="Architecture and request flow"></svg>
|
|
416
|
+
</section>
|
|
417
|
+
<div class="transport" id="sv-transport" role="group" aria-label="Playback"></div>
|
|
418
|
+
<section id="sv-review" class="dock" hidden aria-label="Review"></section>
|
|
419
|
+
<aside class="insp" id="sv-insp" aria-label="About the current step"></aside>
|
|
420
|
+
</div>
|
|
421
|
+
<footer class="foot" id="sv-foot"><a href="https://mafianacho.com" target="_blank" rel="noopener noreferrer">Made by Mafianacho Inc.</a></footer>
|
|
422
|
+
</div>
|
|
423
|
+
<script type="application/json" id="sv-model">{"schemaVersion":1,"product":{"id":"demo-shop","name":"Demo shop","description":"Browser → gateway → order API → SQLite, with three third-party services. A tiny app that ships with nacholens, so every feature can be tried without a private repository."},"source":{"repo":"demo/shop (built by nacholens demo)","commit":"e9f308776fd0d64ac269e02a5581415c2dfabf43"},"components":[{"id":"browser","kind":"client","label":"Browser\nvanilla JS","detail":"Static page from public/. Calls the API with same-origin fetch under /api and redirects the user to the login provider.","evidence":[{"file":"public/app.js","lines":[6,6],"contains":"fetch(\"/api\" + path"}]},{"id":"gateway","kind":"gateway","label":"Gateway\nNode http","detail":"Serves public/ and forwards /api/* to the order API after a per-IP rate limit (120 requests per minute). Adds an x-request-id header.","evidence":[{"file":"gateway.js","lines":[10,10],"contains":"const LIMIT_PER_MINUTE"},{"file":"gateway.js","lines":[26,26],"contains":"if (req.url.startsWith(\"/api/\"))"}]},{"id":"api","kind":"service","label":"Order API\nNode http","detail":"Handles sign-in, orders and the sales report. Every route except the two auth routes needs a valid session cookie; writes check the Origin header.","evidence":[{"file":"api.js","lines":[36,36],"contains":"async function route(req, res)"}],"parts":[{"id":"auth-start","label":"GET /api/auth/start","role":"route","detail":"Starts sign-in: stores a one-time state and sends the user to the sign-in provider.","evidence":[{"file":"api.js","lines":[40,40],"contains":"if (key === \"GET /api/auth/start\")"}]},{"id":"auth-callback","label":"GET /api/auth/callback","role":"route","detail":"Where the sign-in provider sends the user back: checks the state, exchanges the code, issues a session.","evidence":[{"file":"api.js","lines":[49,49],"contains":"if (key === \"GET /api/auth/callback\")"}]},{"id":"session","label":"sessionOf (cookie → session)","role":"middleware","detail":"Finds the session from the sid cookie. Without one it ends with 401.","evidence":[{"file":"api.js","lines":[31,34],"contains":"function sessionOf(req)"},{"file":"api.js","lines":[59,60],"contains":"const me = sessionOf(req);"}]},{"id":"orders-get","label":"GET /api/orders","role":"route","detail":"My orders, returned with their delivery status.","evidence":[{"file":"api.js","lines":[62,62],"contains":"if (key === \"GET /api/orders\")"}]},{"id":"orders-post","label":"POST /api/orders","role":"route","detail":"Creates an order: checks the Origin and the input, then saves it.","evidence":[{"file":"api.js","lines":[68,68],"contains":"if (key === \"POST /api/orders\")"}]},{"id":"sales-get","label":"GET /api/reports/sales","role":"route","detail":"Sales report, admins only. Passes on what the analytics service returns.","evidence":[{"file":"api.js","lines":[77,77],"contains":"if (key === \"GET /api/reports/sales\")"}]},{"id":"track","label":"trackShipping","role":"service","detail":"Asks the carrier for the status of each order. On failure: unknown.","evidence":[{"file":"api.js","lines":[12,18],"contains":"async function trackShipping(rows)"}]},{"id":"db-module","label":"db.js","role":"adapter","detail":"Functions that read and write SQLite through node:sqlite.","evidence":[{"file":"db.js","lines":[2,5],"contains":"import { DatabaseSync } from \"node:sqlite\";"}],"connects":"db"},{"id":"fetch-ext","label":"fetch(EXTERNAL)","role":"adapter","detail":"Calls the external services (sign-in, carrier, analytics) over HTTP. The address is EXTERNAL_URL.","evidence":[{"file":"api.js","lines":[6,6],"contains":"const EXTERNAL = process.env.EXTERNAL_URL"}]}],"wires":[{"from":"auth-start","to":"db-module","label":"saveState(state)","evidence":[{"file":"api.js","lines":[42,42],"contains":"saveState(state);"}]},{"from":"auth-callback","to":"db-module","label":"consumeState · saveSession","evidence":[{"file":"api.js","lines":[50,50],"contains":"if (!consumeState(url.searchParams.get(\"state\")"},{"file":"api.js","lines":[55,55],"contains":"saveSession(sid, email, SESSION_TTL_MS);"}]},{"from":"auth-callback","to":"fetch-ext","label":"POST /token(code)","evidence":[{"file":"api.js","lines":[51,51],"contains":"const token = await fetch(EXTERNAL + \"/token\""}]},{"from":"session","to":"db-module","label":"findSession(sid)","evidence":[{"file":"api.js","lines":[33,33],"contains":"return m ? findSession(m[1]) : null;"}]},{"from":"session","to":"orders-get","label":"me(email)","evidence":[{"file":"api.js","lines":[63,63],"contains":"const rows = listOrders(me.email);"}]},{"from":"session","to":"orders-post","label":"me(email)","evidence":[{"file":"api.js","lines":[73,73],"contains":"const id = insertOrder(me.email"}]},{"from":"session","to":"sales-get","label":"me(email)","evidence":[{"file":"api.js","lines":[78,78],"contains":"if (!ADMINS.has(me.email))"}]},{"from":"orders-get","to":"db-module","label":"listOrders(email)","evidence":[{"file":"api.js","lines":[63,63],"contains":"const rows = listOrders(me.email);"}]},{"from":"orders-get","to":"track","label":"trackShipping(rows)","evidence":[{"file":"api.js","lines":[64,64],"contains":"const shipping = await trackShipping(rows);"}]},{"from":"track","to":"fetch-ext","label":"GET /track?code=","evidence":[{"file":"api.js","lines":[15,15],"contains":"const r = await fetch(`${EXTERNAL}/track?code="}]},{"from":"orders-post","to":"db-module","label":"insertOrder(...)","evidence":[{"file":"api.js","lines":[73,73],"contains":"const id = insertOrder(me.email"}]},{"from":"sales-get","to":"fetch-ext","label":"GET /sales","evidence":[{"file":"api.js","lines":[79,79],"contains":"const r = await fetch(EXTERNAL + \"/sales\");"}]}]},{"id":"db","kind":"datastore","label":"SQLite\nnode:sqlite","detail":"Tables oauth_state, sessions and orders. In memory unless SHOP_DB names a file.","evidence":[{"file":"db.js","lines":[8,8],"contains":"CREATE TABLE IF NOT EXISTS orders"}],"row":1,"tables":[{"name":"oauth_state","detail":"One-time sign-in state. Deleted as soon as it is checked.","columns":[{"name":"state","type":"TEXT","note":"Primary key"},{"name":"created_at","type":"INTEGER"}],"evidence":[{"file":"db.js","lines":[6,6],"contains":"CREATE TABLE IF NOT EXISTS oauth_state"}]},{"name":"sessions","detail":"Sign-in sessions, found by the sid cookie.","columns":[{"name":"id","type":"TEXT","note":"sid"},{"name":"email","type":"TEXT"},{"name":"expires_at","type":"INTEGER"}],"evidence":[{"file":"db.js","lines":[7,7],"contains":"CREATE TABLE IF NOT EXISTS sessions"}]},{"name":"orders","detail":"Orders, with the delivery tracking code (tracking).","columns":[{"name":"id","type":"INTEGER"},{"name":"email","type":"TEXT"},{"name":"item","type":"TEXT"},{"name":"qty","type":"INTEGER"},{"name":"tracking","type":"TEXT","note":"Delivery tracking code"},{"name":"created_at","type":"INTEGER"}],"evidence":[{"file":"db.js","lines":[8,11],"contains":"CREATE TABLE IF NOT EXISTS orders"}]}]},{"id":"idp","kind":"external","label":"Login provider\nOAuth-style","detail":"Third-party sign-in. The demo ships a stand-in in mock-external.js with /authorize and /token.","evidence":[{"file":"mock-external.js","lines":[7,7],"contains":"url.pathname === \"/authorize\""}],"row":0,"endpoints":[{"id":"authorize","method":"GET","path":"/authorize","auth":"None (browser redirect)","detail":"Sign-in consent screen. When done it redirects to redirect_uri with code and state.","request":[{"name":"state"},{"name":"redirect_uri"}],"response":[{"name":"code","note":"Redirect query"},{"name":"state","note":"Redirect query"}],"evidence":[{"file":"api.js","lines":[44,45],"contains":"to.searchParams.set(\"state\", state);"},{"file":"mock-external.js","lines":[7,9],"contains":"if (url.pathname === \"/authorize\")"}]},{"id":"token","method":"POST","path":"/token","auth":"None (demo stand-in)","detail":"Exchanges the code for the user's details.","request":[{"name":"code"}],"response":[{"name":"email"}],"evidence":[{"file":"api.js","lines":[51,51],"contains":"const token = await fetch(EXTERNAL + \"/token\""},{"file":"mock-external.js","lines":[11,11],"contains":"if (url.pathname === \"/token\")"}]}]},{"id":"shipping","kind":"external","label":"Shipping tracker\nHTTP JSON","detail":"Third-party tracking lookup. Called once per order that has a tracking code (v2 and later).","evidence":[{"file":"api.js","lines":[12,12],"contains":"async function trackShipping"}],"row":2,"endpoints":[{"id":"track","method":"GET","path":"/track?code=","auth":"None (demo stand-in)","detail":"Delivery status of a tracking code.","request":[{"name":"code","note":"Query"}],"response":[{"name":"status","note":"e.g. in_transit"}],"evidence":[{"file":"api.js","lines":[15,16],"contains":"const r = await fetch(`${EXTERNAL}/track?code="},{"file":"mock-external.js","lines":[12,12],"contains":"if (url.pathname === \"/track\")"}]}]},{"id":"analytics","kind":"external","label":"Analytics\nHTTP JSON","detail":"Third-party sales totals used by the report.","evidence":[{"file":"mock-external.js","lines":[13,13],"contains":"url.pathname === \"/sales\""}],"row":3,"endpoints":[{"id":"sales","method":"GET","path":"/sales","auth":"None (demo stand-in)","detail":"Total sales and order count.","response":[{"name":"total"},{"name":"orders"}],"evidence":[{"file":"api.js","lines":[79,79],"contains":"const r = await fetch(EXTERNAL + \"/sales\");"},{"file":"mock-external.js","lines":[13,13],"contains":"if (url.pathname === \"/sales\")"}]}]}],"links":[{"a":"browser","b":"gateway","label":"HTTP, same origin /api/*","evidence":[{"file":"public/app.js","lines":[6,6],"contains":"fetch(\"/api\" + path"}]},{"a":"gateway","b":"api","label":"HTTP forward with x-request-id","evidence":[{"file":"gateway.js","lines":[27,33],"contains":"const upstream = await fetch(API + req.url"}]},{"a":"api","b":"db","label":"SQL (node:sqlite)","evidence":[{"file":"api.js","lines":[4,4],"contains":"from \"./db.js\""}]},{"a":"api","b":"idp","label":"HTTPS: POST /token","evidence":[{"file":"api.js","lines":[51,51],"contains":"fetch(EXTERNAL + \"/token\""}]},{"a":"api","b":"shipping","label":"HTTPS: GET /track","evidence":[{"file":"api.js","lines":[15,15],"contains":"fetch(`${EXTERNAL}/track"}]},{"a":"api","b":"analytics","label":"HTTPS: GET /sales","evidence":[{"file":"api.js","lines":[79,79],"contains":"fetch(EXTERNAL + \"/sales\")"}]},{"a":"browser","b":"idp","label":"Browser redirect to /authorize","evidence":[{"file":"api.js","lines":[46,46],"contains":"location: to.toString()"}]}],"useCases":[{"id":"sign-in","title":"Sign in with the login provider","summary":"The user is sent to a third-party provider and comes back with a one-time code that the API turns into a session cookie.","trigger":"GET /api/auth/start → provider → GET /api/auth/callback","steps":[{"id":"start","kind":"request","from":"browser","via":["gateway"],"to":"api","label":"Start sign-in","narration":"The user clicks \"Sign in\". The browser asks /api/auth/start; the gateway rate-limits the request and forwards it to the order API.","request":"GET /api/auth/start","evidence":[{"file":"public/index.html","lines":[5,5],"contains":"href=\"/api/auth/start\""},{"file":"api.js","lines":[40,40],"contains":"key === \"GET /api/auth/start\""},{"file":"gateway.js","lines":[24,24],"contains":"if (!allowed("}],"trace":["api/auth-start"]},{"id":"make-state","kind":"internal","from":"api","to":"api","label":"Create a one-time state value","narration":"The API creates a random state value and builds the provider URL with that state and its own callback address.","evidence":[{"file":"api.js","lines":[41,46],"contains":"const state = randomUUID();"}],"trace":["api/auth-start"]},{"id":"save-state","kind":"call","from":"api","to":"db","label":"Remember the state","narration":"The state is written to oauth_state so the callback can prove it started here.","request":"INSERT INTO oauth_state (state, created_at)","response":"ok","evidence":[{"file":"api.js","lines":[42,42],"contains":"saveState(state);"},{"file":"db.js","lines":[14,16],"contains":"export function saveState"}],"trace":["api/auth-start","api/db-module"],"data":[{"store":"db","table":"oauth_state","op":"insert","columns":["state","created_at"],"evidence":[{"file":"db.js","lines":[15,15],"contains":"INSERT INTO oauth_state"}]}],"payload":[{"leg":"request","format":"sql","title":"store the state","body":"INSERT INTO oauth_state (state, created_at) VALUES (?, ?)","bind":[{"name":"?1 state","value":"\u003cuuid\u003e randomUUID"},{"name":"?2 created_at","value":"\u003cint\u003e Date.now(), ms"}],"evidence":[{"file":"db.js","lines":[15,15],"contains":"db.prepare(\"INSERT INTO oauth_state (state, created_at) VALUES (?, ?)\")"}]}],"transforms":[{"at":"api/auth-start","in":{"type":"(nothing)"},"out":{"type":"state: \u003cuuid\u003e"},"map":[{"from":"randomUUID()","to":"state"}],"evidence":[{"file":"api.js","lines":[41,42],"contains":"const state = randomUUID();"}]},{"at":"api/db-module","in":{"type":"state"},"out":{"type":"oauth_state row","fields":["state","created_at"]},"map":[{"from":"state","to":"?1"},{"from":"Date.now()","to":"created_at"}],"evidence":[{"file":"db.js","lines":[14,16],"contains":"export function saveState(state) {"}]}]},{"id":"redirect","kind":"response","from":"api","via":["gateway"],"to":"browser","label":"Redirect to the provider","narration":"The API answers 302 with the provider URL. The gateway passes status and headers through unchanged.","response":"302 Location: provider /authorize?state=…","evidence":[{"file":"api.js","lines":[46,46],"contains":"return send(res, 302, { redirect: to.toString() }"},{"file":"gateway.js","lines":[37,37],"contains":"res.writeHead(upstream.status"}],"trace":["api/auth-start"],"payload":[{"leg":"response","format":"http","title":"302 to the login provider","body":"HTTP 302\nlocation: \u003cEXTERNAL\u003e/authorize?state=\u003cuuid\u003e\u0026redirect_uri=\u003cPUBLIC_ORIGIN\u003e/api/auth/callback\n\n{ \"redirect\": \"\u003csame URL\u003e\" }","evidence":[{"file":"api.js","lines":[43,46],"contains":"const to = new URL(EXTERNAL + \"/authorize\");"}]}]},{"id":"consent","kind":"request","from":"browser","to":"idp","label":"Pick an account at the provider","narration":"The browser talks to the provider directly, outside the gateway. The demo provider approves at once.","request":"GET /authorize?state=…\u0026redirect_uri=…","response":"302 back to /api/auth/callback?code=…\u0026state=…","evidence":[{"file":"mock-external.js","lines":[7,10],"contains":"url.pathname === \"/authorize\""}],"endpoints":["idp/authorize"]},{"id":"callback","kind":"request","from":"browser","via":["gateway"],"to":"api","label":"Come back with the code","narration":"The provider sends the browser back to the callback address with the code and the state.","request":"GET /api/auth/callback?code=…\u0026state=…","evidence":[{"file":"mock-external.js","lines":[8,8],"contains":"location: `${url.searchParams.get(\"redirect_uri\")}"},{"file":"api.js","lines":[49,49],"contains":"key === \"GET /api/auth/callback\""}],"trace":["api/auth-callback"]},{"id":"consume-state","kind":"call","from":"api","to":"db","label":"Use the state once","narration":"The state row is deleted in the same statement that reads it, so a replayed callback finds nothing and gets 400.","request":"DELETE FROM oauth_state … RETURNING state","response":"row or none","evidence":[{"file":"api.js","lines":[50,50],"contains":"if (!consumeState("},{"file":"db.js","lines":[20,20],"contains":"DELETE FROM oauth_state WHERE state = ? RETURNING state"}],"trace":["api/auth-callback","api/db-module"],"data":[{"store":"db","table":"oauth_state","op":"delete","columns":["state"],"evidence":[{"file":"db.js","lines":[20,20],"contains":"DELETE FROM oauth_state WHERE state = ? RETURNING state"}]}],"payload":[{"leg":"request","format":"sql","title":"use the state once (delete while reading)","body":"DELETE FROM oauth_state WHERE state = ? RETURNING state","bind":[{"name":"?1 state","value":"\u003cuuid\u003e query state"}],"evidence":[{"file":"db.js","lines":[20,20],"contains":"db.prepare(\"DELETE FROM oauth_state WHERE state = ? RETURNING state\")"}]},{"leg":"response","format":"row","title":"deleted row (null → 400)","columns":[{"name":"state","value":"\u003cuuid\u003e"}],"evidence":[{"file":"db.js","lines":[20,20],"contains":"db.prepare(\"DELETE FROM oauth_state WHERE state = ? RETURNING state\")"},{"file":"api.js","lines":[50,50],"contains":"if (!consumeState(url.searchParams.get(\"state\") ?? \"\")) return send(res, 400"}]}]},{"id":"exchange","kind":"call","from":"api","to":"idp","label":"Exchange the code","narration":"The API posts the code to the provider token endpoint and reads the verified email from the answer.","request":"POST /token {code}","response":"{ email }","evidence":[{"file":"api.js","lines":[51,55],"contains":"fetch(EXTERNAL + \"/token\""},{"file":"mock-external.js","lines":[11,11],"contains":"url.pathname === \"/token\""}],"trace":["api/auth-callback","api/fetch-ext"],"endpoints":["idp/token"],"payload":[{"leg":"request","format":"http","title":"POST /token","body":"POST \u003cEXTERNAL\u003e/token\n\n{ \"code\": \"\u003ctext\u003e query code\" }","evidence":[{"file":"api.js","lines":[51,51],"contains":"const token = await fetch(EXTERNAL + \"/token\""}]},{"leg":"response","format":"json","title":"token reply (demo stand-in)","body":"{ \"email\": \"\u003cemail\u003e\" }","evidence":[{"file":"mock-external.js","lines":[11,11],"contains":"if (url.pathname === \"/token\")"},{"file":"api.js","lines":[53,53],"contains":"const { email } = await token.json();"}]}],"transforms":[{"at":"api/auth-callback","in":{"type":"query code"},"out":{"type":"email"},"map":[{"from":"code","to":"body.code"},{"from":"reply email","to":"email","how":"502 on failure"}],"evidence":[{"file":"api.js","lines":[51,53],"contains":"const token = await fetch(EXTERNAL + \"/token\""}]}]},{"id":"save-session","kind":"call","from":"api","to":"db","label":"Create the session","narration":"A random session id is stored with the email and an 8 hour expiry.","request":"INSERT INTO sessions (id, email, expires_at)","response":"ok","evidence":[{"file":"api.js","lines":[55,55],"contains":"saveSession(sid, email, SESSION_TTL_MS)"},{"file":"db.js","lines":[23,25],"contains":"export function saveSession"}],"trace":["api/auth-callback","api/db-module"],"data":[{"store":"db","table":"sessions","op":"insert","columns":["id","email","expires_at"],"evidence":[{"file":"db.js","lines":[24,24],"contains":"INSERT INTO sessions (id, email, expires_at)"}]}],"payload":[{"leg":"request","format":"sql","title":"create the session","body":"INSERT INTO sessions (id, email, expires_at) VALUES (?, ?, ?)","bind":[{"name":"?1 id","value":"\u003cuuid\u003e randomUUID"},{"name":"?2 email","value":"\u003cemail\u003e"},{"name":"?3 expires_at","value":"\u003cint\u003e now + 8 h, ms"}],"evidence":[{"file":"db.js","lines":[24,24],"contains":"db.prepare(\"INSERT INTO sessions (id, email, expires_at) VALUES (?, ?, ?)\")"},{"file":"api.js","lines":[8,8],"contains":"const SESSION_TTL_MS = 8 * 60 * 60 * 1000;"}]}],"transforms":[{"at":"api/db-module","in":{"type":"sid, email, ttlMs"},"out":{"type":"sessions row","fields":["id","email","expires_at"]},"map":[{"from":"ttlMs","to":"expires_at","how":"Date.now() + ttlMs"}],"evidence":[{"file":"db.js","lines":[23,25],"contains":"export function saveSession(id, email, ttlMs) {"}]}]},{"id":"done","kind":"response","from":"api","via":["gateway"],"to":"browser","label":"Back to the shop with a cookie","narration":"302 to / with an HttpOnly, SameSite=Lax cookie that carries the session id.","response":"302 Location: / Set-Cookie: sid=…","evidence":[{"file":"api.js","lines":[56,56],"contains":"return send(res, 302, { ok: true }"}],"trace":["api/auth-callback"],"payload":[{"leg":"response","format":"http","title":"302 to the shop with a session cookie","body":"HTTP 302\nlocation: /\nset-cookie: sid=\u003cuuid\u003e; HttpOnly; SameSite=Lax; Path=/; Max-Age=\u003cseconds\u003e\n\n{ \"ok\": true }","evidence":[{"file":"api.js","lines":[56,56],"contains":"return send(res, 302, { ok: true }, { location: \"/\", \"set-cookie\":"}]}],"transforms":[{"at":"api/auth-callback","in":{"type":"sid"},"out":{"type":"set-cookie header"},"map":[{"from":"sid","to":"sid=\u003cuuid\u003e","how":"HttpOnly · SameSite=Lax"},{"from":"SESSION_TTL_MS","to":"Max-Age","how":"÷ 1000 (seconds)"}],"evidence":[{"file":"api.js","lines":[56,56],"contains":"return send(res, 302, { ok: true }, { location: \"/\", \"set-cookie\":"}]}]}]},{"id":"list-orders","title":"List my orders","summary":"The page loads the signed-in user's orders. For each order with a tracking code the API asks the shipping tracker for its status.","trigger":"GET /api/orders","steps":[{"id":"request","kind":"request","from":"browser","via":["gateway"],"to":"api","label":"Load the order list","narration":"When the page opens, the browser asks /api/orders. The gateway checks the rate limit and forwards the request.","request":"GET /api/orders","evidence":[{"file":"public/app.js","lines":[12,12],"contains":"api(\"/orders\")"},{"file":"api.js","lines":[62,62],"contains":"key === \"GET /api/orders\""},{"file":"gateway.js","lines":[24,24],"contains":"if (!allowed("}],"trace":["api/session"],"payload":[{"leg":"request","format":"http","title":"GET /api/orders","body":"GET /api/orders\ncookie: sid=\u003cuuid\u003e","evidence":[{"file":"public/app.js","lines":[12,12],"contains":"const { orders } = await api(\"/orders\");"},{"file":"public/app.js","lines":[6,6],"contains":"const res = await fetch(\"/api\" + path, { credentials: \"same-origin\""}]}]},{"id":"session","kind":"call","from":"api","to":"db","label":"Check the session","narration":"The sid cookie is looked up in sessions. Missing or expired means 401 and nothing else runs.","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none","evidence":[{"file":"api.js","lines":[31,34],"contains":"function sessionOf(req)"},{"file":"api.js","lines":[60,60],"contains":"if (!me) return send(res, 401"},{"file":"db.js","lines":[27,29],"contains":"export function findSession"}],"trace":["api/session","api/db-module"],"data":[{"store":"db","table":"sessions","op":"read","columns":["id","email","expires_at"],"evidence":[{"file":"db.js","lines":[28,28],"contains":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?"}]}],"payload":[{"leg":"request","format":"sql","title":"find the session","body":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?","bind":[{"name":"?1 id","value":"\u003cuuid\u003e cookie sid"},{"name":"?2 now","value":"\u003cint\u003e now, ms"}],"evidence":[{"file":"db.js","lines":[28,28],"contains":"db.prepare(\"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?\")"}]},{"leg":"response","format":"row","title":"session row (null if none)","columns":[{"name":"email","value":"\u003cemail\u003e"}],"evidence":[{"file":"db.js","lines":[28,28],"contains":"db.prepare(\"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?\")"}]}],"transforms":[{"at":"api/session","in":{"type":"Cookie header","fields":["sid=\u003cuuid\u003e"]},"out":{"type":"me | null","fields":["email"]},"map":[{"from":"cookie","to":"sid","how":"regex sid=([\\w-]+)"},{"from":"sid","to":"findSession(sid)","how":"unexpired rows only"},{"from":"none","to":"401 unauthenticated"}],"evidence":[{"file":"api.js","lines":[31,33],"contains":"function sessionOf(req) {"},{"file":"api.js","lines":[59,60],"contains":"const me = sessionOf(req);"}]}]},{"id":"query","kind":"call","from":"api","to":"db","label":"Read the user's orders","narration":"The latest 50 orders of the signed-in email are read, newest first.","request":"SELECT … FROM orders WHERE email = ? ORDER BY id DESC LIMIT 50","response":"order rows","evidence":[{"file":"api.js","lines":[63,63],"contains":"const rows = listOrders(me.email);"},{"file":"db.js","lines":[31,33],"contains":"export function listOrders"}],"trace":["api/session","api/orders-get","api/db-module"],"data":[{"store":"db","table":"orders","op":"read","columns":["id","item","qty","tracking","created_at","email"],"evidence":[{"file":"db.js","lines":[32,32],"contains":"SELECT id, item, qty, tracking, created_at FROM orders WHERE"}]}],"payload":[{"leg":"request","format":"sql","title":"read my orders","body":"SELECT id, item, qty, tracking, created_at FROM orders\nWHERE email = ? ORDER BY id DESC LIMIT 50","bind":[{"name":"?1 email","value":"\u003cemail\u003e from the session"}],"evidence":[{"file":"db.js","lines":[32,32],"contains":"db.prepare(\"SELECT id, item, qty, tracking, created_at FROM orders WHERE email = ?"}]},{"leg":"response","format":"row","title":"orders rows (up to 50)","columns":[{"name":"id","value":"INTEGER"},{"name":"item","value":"TEXT"},{"name":"qty","value":"INTEGER"},{"name":"tracking","value":"TEXT | null"},{"name":"created_at","value":"INTEGER ms"}],"evidence":[{"file":"db.js","lines":[8,11],"contains":"CREATE TABLE IF NOT EXISTS orders ("}]}]},{"id":"shipping","kind":"call","from":"api","to":"shipping","label":"Ask the tracker for each status","narration":"Orders that have a tracking code are looked up in parallel. A failed lookup becomes \"unknown\" instead of failing the list.","request":"GET /track?code=TRK-… (one per order)","response":"{ status } per order","evidence":[{"file":"api.js","lines":[12,18],"contains":"async function trackShipping"}],"trace":["api/orders-get","api/track","api/fetch-ext"],"endpoints":["shipping/track"],"payload":[{"leg":"request","format":"http","title":"GET /track (per order)","body":"GET \u003cEXTERNAL\u003e/track?code=\u003ctracking, URL-encoded\u003e","evidence":[{"file":"api.js","lines":[15,15],"contains":"const r = await fetch(`${EXTERNAL}/track?code=${encodeURIComponent(o.tracking)}`)"}]},{"leg":"response","format":"json","title":"shipping status (demo stand-in)","body":"{ \"status\": \"\u003ctext\u003e e.g. in_transit\" }","evidence":[{"file":"api.js","lines":[16,16],"contains":"return r \u0026\u0026 r.ok ? (await r.json()).status"}]}],"transforms":[{"at":"api/track","in":{"type":"orders rows","fields":["tracking"]},"out":{"type":"status strings"},"map":[{"from":"no tracking","to":"\"none\""},{"from":"reply status","to":"status"},{"from":"call failed","to":"\"unknown\""}],"evidence":[{"file":"api.js","lines":[12,17],"contains":"async function trackShipping(rows) {"}]}]},{"id":"shape","kind":"internal","from":"api","to":"api","label":"Build the response","narration":"Each row becomes { id, item, qty, shipping, createdAt }. The database column names do not leave the server.","evidence":[{"file":"api.js","lines":[65,65],"contains":"orders: rows.map((o, i) =\u003e"}],"trace":["api/orders-get"],"transforms":[{"at":"api/orders-get","in":{"type":"orders rows + statuses","fields":["id","item","qty","tracking","created_at","shipping[i]"]},"out":{"type":"reply orders[]","fields":["id","item","qty","shipping","createdAt"]},"map":[{"from":"shipping[i]","to":"shipping"},{"from":"created_at","to":"createdAt","how":"renamed only"},{"from":"tracking","to":"(dropped)","how":"not in the reply"}],"evidence":[{"file":"api.js","lines":[65,65],"contains":"return send(res, 200, { orders: rows.map((o, i) =\u003e"}]}]},{"id":"response","kind":"response","from":"api","via":["gateway"],"to":"browser","label":"Show the list with status","narration":"The page renders one line per order, including a readable shipping status.","response":"200 { orders: [{ id, item, qty, shipping, createdAt }] }","evidence":[{"file":"api.js","lines":[65,65],"contains":"return send(res, 200, { orders: rows.map"},{"file":"public/app.js","lines":[16,16],"contains":"li.textContent ="},{"file":"gateway.js","lines":[38,38],"contains":"return res.end(Buffer.from(await upstream.arrayBuffer()))"}],"trace":["api/orders-get"],"payload":[{"leg":"response","format":"http","title":"200 order list","body":"HTTP 200\ncontent-type: application/json\n\n{ \"orders\": [\n { \"id\": \u003cint\u003e, \"item\": \"\u003ctext\u003e\", \"qty\": \u003cint\u003e,\n \"shipping\": \"\u003ctext\u003e\", \"createdAt\": \u003cint ms\u003e }\n] }","evidence":[{"file":"api.js","lines":[65,65],"contains":"return send(res, 200, { orders: rows.map((o, i) =\u003e"},{"file":"api.js","lines":[20,23],"contains":"const send = (res, code, body, headers = {}) =\u003e {"}]}],"transforms":[{"at":"api/orders-get","in":{"type":"reply object"},"out":{"type":"JSON body"},"map":[{"from":"object","to":"JSON.stringify"}],"evidence":[{"file":"api.js","lines":[20,23],"contains":"const send = (res, code, body, headers = {}) =\u003e {"}]}]}]},{"id":"place-order","title":"Place an order","summary":"A signed-in user submits an item and a quantity. The API checks origin and input, stores the order and returns its id.","trigger":"POST /api/orders","steps":[{"id":"request","kind":"request","from":"browser","via":["gateway"],"to":"api","label":"Submit the form","narration":"The browser posts JSON. The gateway forwards the body untouched.","request":"POST /api/orders {item, qty}","evidence":[{"file":"public/app.js","lines":[25,25],"contains":"method: \"POST\""},{"file":"api.js","lines":[68,68],"contains":"key === \"POST /api/orders\""},{"file":"gateway.js","lines":[24,24],"contains":"if (!allowed("}],"trace":["api/session"],"payload":[{"leg":"request","format":"http","title":"POST /api/orders","body":"POST /api/orders\ncontent-type: application/json\norigin: \u003cPUBLIC_ORIGIN\u003e\ncookie: sid=\u003cuuid\u003e\n\n{ \"item\": \"\u003ctext\u003e\", \"qty\": \u003cint\u003e }","evidence":[{"file":"public/app.js","lines":[24,27],"contains":"await api(\"/orders\", {"}]}]},{"id":"session","kind":"call","from":"api","to":"db","label":"Check the session","narration":"The sid cookie is looked up in sessions. Missing or expired means 401 and nothing else runs.","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none","evidence":[{"file":"api.js","lines":[31,34],"contains":"function sessionOf(req)"},{"file":"api.js","lines":[60,60],"contains":"if (!me) return send(res, 401"},{"file":"db.js","lines":[27,29],"contains":"export function findSession"}],"trace":["api/session","api/db-module"],"data":[{"store":"db","table":"sessions","op":"read","columns":["id","email","expires_at"],"evidence":[{"file":"db.js","lines":[28,28],"contains":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?"}]}],"payload":[{"leg":"request","format":"sql","title":"find the session","body":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?","bind":[{"name":"?1 id","value":"\u003cuuid\u003e cookie sid"},{"name":"?2 now","value":"\u003cint\u003e now, ms"}],"evidence":[{"file":"db.js","lines":[28,28],"contains":"db.prepare(\"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?\")"}]},{"leg":"response","format":"row","title":"session row (null if none)","columns":[{"name":"email","value":"\u003cemail\u003e"}],"evidence":[{"file":"db.js","lines":[28,28],"contains":"db.prepare(\"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?\")"}]}],"transforms":[{"at":"api/session","in":{"type":"Cookie header","fields":["sid=\u003cuuid\u003e"]},"out":{"type":"me | null","fields":["email"]},"map":[{"from":"cookie","to":"sid","how":"regex sid=([\\w-]+)"},{"from":"sid","to":"findSession(sid)","how":"unexpired rows only"},{"from":"none","to":"401 unauthenticated"}],"evidence":[{"file":"api.js","lines":[31,33],"contains":"function sessionOf(req) {"},{"file":"api.js","lines":[59,60],"contains":"const me = sessionOf(req);"}]}]},{"id":"origin","kind":"internal","from":"api","to":"api","label":"Check the Origin header","narration":"A write is accepted only when the Origin header equals the shop's public origin; otherwise 403.","evidence":[{"file":"api.js","lines":[69,69],"contains":"req.headers.origin !== PUBLIC_ORIGIN"}],"trace":["api/session","api/orders-post"]},{"id":"validate","kind":"internal","from":"api","to":"api","label":"Validate the input","narration":"item must be text (cut to 80 characters), qty a whole number from 1 to 99; anything else is 400.","evidence":[{"file":"api.js","lines":[70,72],"contains":"const body = await readBody(req);"}],"trace":["api/orders-post"],"transforms":[{"at":"api/orders-post","in":{"type":"request body (JSON)","fields":["item","qty"]},"out":{"type":"validated order","fields":["item: string","qty: integer 1-99"]},"map":[{"from":"body","to":"body","how":"JSON.parse, null on failure"},{"from":"item not a string · qty out of range","to":"400 invalid_order"}],"evidence":[{"file":"api.js","lines":[70,72],"contains":"const body = await readBody(req);"},{"file":"api.js","lines":[25,28],"contains":"const readBody = (req) =\u003e new Promise((resolve) =\u003e {"}]}]},{"id":"insert","kind":"call","from":"api","to":"db","label":"Store the order","narration":"The order is inserted with the user's email and, from v2 on, a generated tracking code.","request":"INSERT INTO orders (email, item, qty, tracking, created_at)","response":"new id","evidence":[{"file":"api.js","lines":[73,73],"contains":"const id = insertOrder("},{"file":"db.js","lines":[35,38],"contains":"export function insertOrder"}],"trace":["api/orders-post","api/db-module"],"data":[{"store":"db","table":"orders","op":"insert","columns":["email","item","qty","tracking","created_at"],"evidence":[{"file":"db.js","lines":[36,36],"contains":"INSERT INTO orders (email, item, qty, tracking, created_at)"}]}],"payload":[{"leg":"request","format":"sql","title":"store the order","body":"INSERT INTO orders (email, item, qty, tracking, created_at)\nVALUES (?, ?, ?, ?, ?)","bind":[{"name":"?1 email","value":"\u003cemail\u003e from the session"},{"name":"?2 item","value":"\u003ctext\u003e up to 80 chars"},{"name":"?3 qty","value":"\u003cint 1-99\u003e"},{"name":"?4 tracking","value":"TRK-\u003c8 chars\u003e"},{"name":"?5 created_at","value":"\u003cint\u003e Date.now(), ms"}],"evidence":[{"file":"db.js","lines":[36,36],"contains":"db.prepare(\"INSERT INTO orders (email, item, qty, tracking, created_at) VALUES (?, ?, ?, ?, ?)\")"}]},{"leg":"response","format":"row","title":"insert result","columns":[{"name":"lastInsertRowid","value":"\u003cint\u003e new order id"}],"evidence":[{"file":"db.js","lines":[37,37],"contains":"return Number(r.lastInsertRowid);"}]}],"transforms":[{"at":"api/orders-post","in":{"type":"validated order","fields":["item","qty","me.email"]},"out":{"type":"insertOrder arguments","fields":["email","item (cut to 80)","qty","tracking"]},"map":[{"from":"item","to":"item.slice(0, 80)"},{"from":"(nothing)","to":"tracking","how":"\"TRK-\" + first 8 of randomUUID"}],"evidence":[{"file":"api.js","lines":[73,73],"contains":"const id = insertOrder(me.email, body.item.slice(0, 80), body.qty, \"TRK-\" + randomUUID().slice(0, 8));"}]},{"at":"api/db-module","in":{"type":"email, item, qty, tracking"},"out":{"type":"orders row → id"},"map":[{"from":"Date.now()","to":"created_at"},{"from":"lastInsertRowid","to":"id","how":"Number"}],"evidence":[{"file":"db.js","lines":[35,38],"contains":"export function insertOrder(email, item, qty, tracking) {"}]}]},{"id":"response","kind":"response","from":"api","via":["gateway"],"to":"browser","label":"Return the new id","narration":"201 with { id }; the page reloads the list.","response":"201 { id }","evidence":[{"file":"api.js","lines":[74,74],"contains":"return send(res, 201, { id })"},{"file":"public/app.js","lines":[29,29],"contains":"await loadOrders();"}],"trace":["api/orders-post"],"payload":[{"leg":"response","format":"http","title":"201 new order id","body":"HTTP 201\ncontent-type: application/json\n\n{ \"id\": \u003cint\u003e }","evidence":[{"file":"api.js","lines":[74,74],"contains":"return send(res, 201, { id });"}]}]}]},{"id":"sales-report","title":"Sales report (admin only)","summary":"Only emails on the admin list may read totals, which come from a third-party analytics service.","trigger":"GET /api/reports/sales","steps":[{"id":"request","kind":"request","from":"browser","via":["gateway"],"to":"api","label":"Ask for the totals","narration":"The page requests the report after loading.","request":"GET /api/reports/sales","evidence":[{"file":"public/app.js","lines":[33,33],"contains":"api(\"/reports/sales\")"},{"file":"api.js","lines":[77,77],"contains":"key === \"GET /api/reports/sales\""},{"file":"gateway.js","lines":[24,24],"contains":"if (!allowed("}],"trace":["api/session"]},{"id":"session","kind":"call","from":"api","to":"db","label":"Check the session","narration":"The sid cookie is looked up in sessions. Missing or expired means 401 and nothing else runs.","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none","evidence":[{"file":"api.js","lines":[31,34],"contains":"function sessionOf(req)"},{"file":"api.js","lines":[60,60],"contains":"if (!me) return send(res, 401"},{"file":"db.js","lines":[27,29],"contains":"export function findSession"}],"trace":["api/session","api/db-module"],"data":[{"store":"db","table":"sessions","op":"read","columns":["id","email","expires_at"],"evidence":[{"file":"db.js","lines":[28,28],"contains":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?"}]}],"payload":[{"leg":"request","format":"sql","title":"find the session","body":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?","bind":[{"name":"?1 id","value":"\u003cuuid\u003e cookie sid"},{"name":"?2 now","value":"\u003cint\u003e now, ms"}],"evidence":[{"file":"db.js","lines":[28,28],"contains":"db.prepare(\"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?\")"}]},{"leg":"response","format":"row","title":"session row (null if none)","columns":[{"name":"email","value":"\u003cemail\u003e"}],"evidence":[{"file":"db.js","lines":[28,28],"contains":"db.prepare(\"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e ?\")"}]}],"transforms":[{"at":"api/session","in":{"type":"Cookie header","fields":["sid=\u003cuuid\u003e"]},"out":{"type":"me | null","fields":["email"]},"map":[{"from":"cookie","to":"sid","how":"regex sid=([\\w-]+)"},{"from":"sid","to":"findSession(sid)","how":"unexpired rows only"},{"from":"none","to":"401 unauthenticated"}],"evidence":[{"file":"api.js","lines":[31,33],"contains":"function sessionOf(req) {"},{"file":"api.js","lines":[59,60],"contains":"const me = sessionOf(req);"}]}]},{"id":"admin-check","kind":"internal","from":"api","to":"api","label":"Check the admin list","narration":"The session email must be in ADMIN_EMAILS (default: the demo buyer); otherwise 403.","evidence":[{"file":"api.js","lines":[9,9],"contains":"const ADMINS = new Set("},{"file":"api.js","lines":[78,78],"contains":"if (!ADMINS.has(me.email))"}],"trace":["api/session","api/sales-get"]},{"id":"analytics","kind":"call","from":"api","to":"analytics","label":"Fetch the totals","narration":"The API calls the analytics service. If it fails the API answers 502 instead of guessing numbers.","request":"GET /sales","response":"{ total, orders }","evidence":[{"file":"api.js","lines":[79,80],"contains":"const r = await fetch(EXTERNAL + \"/sales\");"},{"file":"mock-external.js","lines":[13,13],"contains":"url.pathname === \"/sales\""}],"trace":["api/sales-get","api/fetch-ext"],"endpoints":["analytics/sales"],"payload":[{"leg":"request","format":"http","title":"GET /sales","body":"GET \u003cEXTERNAL\u003e/sales","evidence":[{"file":"api.js","lines":[79,79],"contains":"const r = await fetch(EXTERNAL + \"/sales\");"}]},{"leg":"response","format":"json","title":"sales totals (demo stand-in)","body":"{ \"total\": \u003cint\u003e, \"orders\": \u003cint\u003e }","evidence":[{"file":"mock-external.js","lines":[13,13],"contains":"if (url.pathname === \"/sales\")"}]}]},{"id":"response","kind":"response","from":"api","via":["gateway"],"to":"browser","label":"Show the totals","narration":"The totals are passed through and shown under the order list.","response":"200 { total, orders }","evidence":[{"file":"api.js","lines":[81,81],"contains":"return send(res, 200, await r.json());"},{"file":"public/app.js","lines":[33,33],"contains":"$(\"sales\").textContent"}],"trace":["api/sales-get"],"payload":[{"leg":"response","format":"http","title":"200 totals as received","body":"HTTP 200\ncontent-type: application/json\n\n{ \"total\": \u003cint\u003e, \"orders\": \u003cint\u003e }","evidence":[{"file":"api.js","lines":[81,81],"contains":"return send(res, 200, await r.json());"}]}],"transforms":[{"at":"api/sales-get","in":{"type":"analytics JSON"},"out":{"type":"reply JSON"},"map":[{"from":"body","to":"passed through","how":"502 on failure"}],"evidence":[{"file":"api.js","lines":[80,81],"contains":"if (!r.ok) return send(res, 502, { error: \"analytics_unavailable\" });"}]}]}]}]}</script>
|
|
424
|
+
<script type="application/json" id="sv-changes">{"title":"show shipping status on the order list","summary":"Generated from git diff: 4 changed steps, 3 changed components (browser, api, shipping), 2 changed files outside the model, 1 ignored files.","ref":"demo/shop (built by nacholens demo) 030bf9c..e9f3087","components":[{"id":"browser","change":"modified","note":"End of a changed step: list-orders/response"},{"id":"api","change":"modified","note":"End of a changed step: list-orders/shipping"},{"id":"shipping","change":"added","note":"Component evidence code changed: api.js:12"}],"steps":[{"useCase":"list-orders","step":"shipping","change":"added","note":"Evidence code added: api.js:12-18"},{"useCase":"list-orders","step":"shape","change":"modified","note":"Evidence code changed: api.js:65"},{"useCase":"list-orders","step":"response","change":"modified","note":"Evidence code changed: api.js:65, public/app.js:16"},{"useCase":"place-order","step":"insert","change":"modified","note":"Evidence code changed: api.js:73"}],"details":[{"component":"api","kind":"part","id":"track","change":"added","note":"Evidence code added: api.js:12-18"},{"component":"api","kind":"wire","id":"session\u003eorders-post","change":"modified","note":"Evidence code changed: api.js:73"},{"component":"api","kind":"wire","id":"orders-get\u003etrack","change":"modified","note":"Evidence code changed: api.js:64"},{"component":"api","kind":"wire","id":"track\u003efetch-ext","change":"added","note":"Evidence code added: api.js:15"},{"component":"api","kind":"wire","id":"orders-post\u003edb-module","change":"modified","note":"Evidence code changed: api.js:73"},{"component":"shipping","kind":"endpoint","id":"track","change":"modified","note":"Evidence code changed: api.js:15-16"}],"unmapped":[{"file":"public/format.js","category":"code","status":"modified","lines":"3 (1 hunk)","hint":"Not in the evidence of any use-case step: add the path to the model, or confirm the change is unrelated"},{"file":"public/styles.css","category":"style","status":"modified","lines":"5 (1 hunk)","hint":"Not in the evidence of any use-case step: add the path to the model, or confirm the change is unrelated"}],"ignored":[{"file":"README.md","reason":"docs"}],"generated":{"by":"nacholens diff","base":"030bf9c56ec32a5a14c831cc73c8915a1b0a1eba","head":"e9f308776fd0d64ac269e02a5581415c2dfabf43","modelCommit":"e9f308776fd0d64ac269e02a5581415c2dfabf43","lineTranslation":false}}</script>
|
|
425
|
+
<script type="application/json" id="sv-review-data">{"compare":{"mode":"overlay","useCases":[{"id":"sign-in","title":"Sign in with the login provider","trigger":"GET /api/auth/start → provider → GET /api/auth/callback","state":"same","pathBefore":["browser","gateway","api","db","api","gateway","browser","idp","browser","gateway","api","db","api","idp","api","db","api","gateway","browser"],"pathAfter":["browser","gateway","api","db","api","gateway","browser","idp","browser","gateway","api","db","api","idp","api","db","api","gateway","browser"],"pathLabels":{"browser":"Browser","gateway":"Gateway","api":"Order API","db":"SQLite","idp":"Login provider","shipping":"Shipping tracker","analytics":"Analytics"},"rows":[{"id":"start","status":"same","before":{"label":"Start sign-in","kind":"request","route":"Browser → Gateway → Order API","request":"GET /api/auth/start"},"after":{"label":"Start sign-in","kind":"request","route":"Browser → Gateway → Order API","request":"GET /api/auth/start"}},{"id":"make-state","status":"same","before":{"label":"Create a one-time state value","kind":"internal","route":"Order API → Order API"},"after":{"label":"Create a one-time state value","kind":"internal","route":"Order API → Order API"}},{"id":"save-state","status":"same","before":{"label":"Remember the state","kind":"call","route":"Order API → SQLite","request":"INSERT INTO oauth_state (state, created_at)","response":"ok"},"after":{"label":"Remember the state","kind":"call","route":"Order API → SQLite","request":"INSERT INTO oauth_state (state, created_at)","response":"ok"}},{"id":"redirect","status":"same","before":{"label":"Redirect to the provider","kind":"response","route":"Order API → Gateway → Browser","response":"302 Location: provider /authorize?state=…"},"after":{"label":"Redirect to the provider","kind":"response","route":"Order API → Gateway → Browser","response":"302 Location: provider /authorize?state=…"}},{"id":"consent","status":"same","before":{"label":"Pick an account at the provider","kind":"request","route":"Browser → Login provider","request":"GET /authorize?state=…\u0026redirect_uri=…","response":"302 back to /api/auth/callback?code=…\u0026state=…"},"after":{"label":"Pick an account at the provider","kind":"request","route":"Browser → Login provider","request":"GET /authorize?state=…\u0026redirect_uri=…","response":"302 back to /api/auth/callback?code=…\u0026state=…"}},{"id":"callback","status":"same","before":{"label":"Come back with the code","kind":"request","route":"Browser → Gateway → Order API","request":"GET /api/auth/callback?code=…\u0026state=…"},"after":{"label":"Come back with the code","kind":"request","route":"Browser → Gateway → Order API","request":"GET /api/auth/callback?code=…\u0026state=…"}},{"id":"consume-state","status":"same","before":{"label":"Use the state once","kind":"call","route":"Order API → SQLite","request":"DELETE FROM oauth_state … RETURNING state","response":"row or none"},"after":{"label":"Use the state once","kind":"call","route":"Order API → SQLite","request":"DELETE FROM oauth_state … RETURNING state","response":"row or none"}},{"id":"exchange","status":"same","before":{"label":"Exchange the code","kind":"call","route":"Order API → Login provider","request":"POST /token {code}","response":"{ email }"},"after":{"label":"Exchange the code","kind":"call","route":"Order API → Login provider","request":"POST /token {code}","response":"{ email }"}},{"id":"save-session","status":"same","before":{"label":"Create the session","kind":"call","route":"Order API → SQLite","request":"INSERT INTO sessions (id, email, expires_at)","response":"ok"},"after":{"label":"Create the session","kind":"call","route":"Order API → SQLite","request":"INSERT INTO sessions (id, email, expires_at)","response":"ok"}},{"id":"done","status":"same","before":{"label":"Back to the shop with a cookie","kind":"response","route":"Order API → Gateway → Browser","response":"302 Location: / Set-Cookie: sid=…"},"after":{"label":"Back to the shop with a cookie","kind":"response","route":"Order API → Gateway → Browser","response":"302 Location: / Set-Cookie: sid=…"}}],"changedRows":0},{"id":"list-orders","title":"List my orders","trigger":"GET /api/orders","state":"changed","pathBefore":["browser","gateway","api","db","api","db","api","gateway","browser"],"pathAfter":["browser","gateway","api","db","api","db","api","shipping","api","gateway","browser"],"pathLabels":{"browser":"Browser","gateway":"Gateway","api":"Order API","db":"SQLite","idp":"Login provider","shipping":"Shipping tracker","analytics":"Analytics"},"rows":[{"id":"request","status":"same","before":{"label":"Load the order list","kind":"request","route":"Browser → Gateway → Order API","request":"GET /api/orders"},"after":{"label":"Load the order list","kind":"request","route":"Browser → Gateway → Order API","request":"GET /api/orders"}},{"id":"session","status":"same","before":{"label":"Check the session","kind":"call","route":"Order API → SQLite","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none"},"after":{"label":"Check the session","kind":"call","route":"Order API → SQLite","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none"}},{"id":"query","status":"same","before":{"label":"Read the user's orders","kind":"call","route":"Order API → SQLite","request":"SELECT … FROM orders WHERE email = ? ORDER BY id DESC LIMIT 50","response":"order rows"},"after":{"label":"Read the user's orders","kind":"call","route":"Order API → SQLite","request":"SELECT … FROM orders WHERE email = ? ORDER BY id DESC LIMIT 50","response":"order rows"}},{"id":"shipping","status":"added","before":null,"after":{"label":"Ask the tracker for each status","kind":"call","route":"Order API → Shipping tracker","request":"GET /track?code=TRK-… (one per order)","response":"{ status } per order"},"note":"Evidence code added: api.js:12-18"},{"id":"shape","status":"modified","before":{"label":"Build the response","kind":"internal","route":"Order API → Order API"},"after":{"label":"Build the response","kind":"internal","route":"Order API → Order API"},"note":"Evidence code changed: api.js:65 (the model has no earlier version, so the flow is shown unchanged)","codeOnly":true},{"id":"response","status":"modified","before":{"label":"Show the list with status","kind":"response","route":"Order API → Gateway → Browser","response":"200 { orders: [{ id, item, qty, shipping, createdAt }] }"},"after":{"label":"Show the list with status","kind":"response","route":"Order API → Gateway → Browser","response":"200 { orders: [{ id, item, qty, shipping, createdAt }] }"},"note":"Evidence code changed: api.js:65, public/app.js:16 (the model has no earlier version, so the flow is shown unchanged)","codeOnly":true}],"changedRows":3},{"id":"place-order","title":"Place an order","trigger":"POST /api/orders","state":"changed","pathBefore":["browser","gateway","api","db","api","db","api","gateway","browser"],"pathAfter":["browser","gateway","api","db","api","db","api","gateway","browser"],"pathLabels":{"browser":"Browser","gateway":"Gateway","api":"Order API","db":"SQLite","idp":"Login provider","shipping":"Shipping tracker","analytics":"Analytics"},"rows":[{"id":"request","status":"same","before":{"label":"Submit the form","kind":"request","route":"Browser → Gateway → Order API","request":"POST /api/orders {item, qty}"},"after":{"label":"Submit the form","kind":"request","route":"Browser → Gateway → Order API","request":"POST /api/orders {item, qty}"}},{"id":"session","status":"same","before":{"label":"Check the session","kind":"call","route":"Order API → SQLite","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none"},"after":{"label":"Check the session","kind":"call","route":"Order API → SQLite","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none"}},{"id":"origin","status":"same","before":{"label":"Check the Origin header","kind":"internal","route":"Order API → Order API"},"after":{"label":"Check the Origin header","kind":"internal","route":"Order API → Order API"}},{"id":"validate","status":"same","before":{"label":"Validate the input","kind":"internal","route":"Order API → Order API"},"after":{"label":"Validate the input","kind":"internal","route":"Order API → Order API"}},{"id":"insert","status":"modified","before":{"label":"Store the order","kind":"call","route":"Order API → SQLite","request":"INSERT INTO orders (email, item, qty, tracking, created_at)","response":"new id"},"after":{"label":"Store the order","kind":"call","route":"Order API → SQLite","request":"INSERT INTO orders (email, item, qty, tracking, created_at)","response":"new id"},"note":"Evidence code changed: api.js:73 (the model has no earlier version, so the flow is shown unchanged)","codeOnly":true},{"id":"response","status":"same","before":{"label":"Return the new id","kind":"response","route":"Order API → Gateway → Browser","response":"201 { id }"},"after":{"label":"Return the new id","kind":"response","route":"Order API → Gateway → Browser","response":"201 { id }"}}],"changedRows":1},{"id":"sales-report","title":"Sales report (admin only)","trigger":"GET /api/reports/sales","state":"same","pathBefore":["browser","gateway","api","db","api","analytics","api","gateway","browser"],"pathAfter":["browser","gateway","api","db","api","analytics","api","gateway","browser"],"pathLabels":{"browser":"Browser","gateway":"Gateway","api":"Order API","db":"SQLite","idp":"Login provider","shipping":"Shipping tracker","analytics":"Analytics"},"rows":[{"id":"request","status":"same","before":{"label":"Ask for the totals","kind":"request","route":"Browser → Gateway → Order API","request":"GET /api/reports/sales"},"after":{"label":"Ask for the totals","kind":"request","route":"Browser → Gateway → Order API","request":"GET /api/reports/sales"}},{"id":"session","status":"same","before":{"label":"Check the session","kind":"call","route":"Order API → SQLite","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none"},"after":{"label":"Check the session","kind":"call","route":"Order API → SQLite","request":"SELECT email FROM sessions WHERE id = ? AND expires_at \u003e now","response":"email or none"}},{"id":"admin-check","status":"same","before":{"label":"Check the admin list","kind":"internal","route":"Order API → Order API"},"after":{"label":"Check the admin list","kind":"internal","route":"Order API → Order API"}},{"id":"analytics","status":"same","before":{"label":"Fetch the totals","kind":"call","route":"Order API → Analytics","request":"GET /sales","response":"{ total, orders }"},"after":{"label":"Fetch the totals","kind":"call","route":"Order API → Analytics","request":"GET /sales","response":"{ total, orders }"}},{"id":"response","status":"same","before":{"label":"Show the totals","kind":"response","route":"Order API → Gateway → Browser","response":"200 { total, orders }"},"after":{"label":"Show the totals","kind":"response","route":"Order API → Gateway → Browser","response":"200 { total, orders }"}}],"changedRows":0}],"summary":{"useCases":2,"added":1,"removed":0,"modified":3,"moved":0}},"intent":{"title":"Show the delivery status in the order list","source":"Example planning note (demo shop)","results":[{"id":"ship-lookup","text":"The order list asks the carrier for the status and shows it","useCase":"list-orders","status":"met","reason":"1 matching step.","proof":[{"useCase":"list-orders","step":"shipping","label":"Ask the tracker for each status","evidence":"api.js:12-18","change":"added"}],"touched":true},{"id":"ship-fail-soft","text":"The order list still shows when the carrier lookup fails","useCase":"list-orders","status":"met","reason":"1 matching step.","proof":[{"useCase":"list-orders","step":"shipping","label":"Ask the tracker for each status","evidence":"api.js:12-18","change":"added"}],"touched":true},{"id":"login-first","text":"The order list reads orders only after checking the sign-in (session)","useCase":"list-orders","status":"met","reason":"The step that should come first comes before the later one.","proof":[{"useCase":"list-orders","step":"session","label":"Check the session","evidence":"api.js:31-34, api.js:60","change":null},{"useCase":"list-orders","step":"query","label":"Read the user's orders","evidence":"api.js:63, db.js:31-33","change":null}],"touched":false},{"id":"admin-only","text":"Only admins can see the sales report","useCase":"sales-report","status":"met","reason":"The step that should come first comes before the later one.","proof":[{"useCase":"sales-report","step":"admin-check","label":"Check the admin list","evidence":"api.js:9, api.js:78","change":null},{"useCase":"sales-report","step":"analytics","label":"Fetch the totals","evidence":"api.js:79-80, mock-external.js:13","change":null}],"touched":false},{"id":"address-check","text":"Creating an order validates the delivery address","useCase":"place-order","status":"unmet","reason":"No step of this use case matches.","proof":[],"touched":false},{"id":"ship-wording","text":"Delivery status words are easy for customers to understand","status":"unknown","reason":"No automatic check. Add a check that names the model step that proves it, or have a person confirm it.","proof":[]}],"uncovered":[{"useCase":"list-orders","step":"shape","label":"Build the response","useCaseTitle":"List my orders","change":"modified","evidence":"api.js:65"},{"useCase":"list-orders","step":"response","label":"Show the list with status","useCaseTitle":"List my orders","change":"modified","evidence":"api.js:65, public/app.js:16"},{"useCase":"place-order","step":"insert","label":"Store the order","useCaseTitle":"Place an order","change":"modified","evidence":"api.js:73, db.js:35-38"}],"summary":{"total":6,"met":4,"unmet":1,"unknown":1,"touched":2,"uncovered":3,"changedSteps":4}},"impact":{"useCases":[{"id":"list-orders","title":"List my orders","trigger":"GET /api/orders","relation":"direct","direct":[{"step":"shipping","change":"added","label":"Ask the tracker for each status"},{"step":"shape","change":"modified","label":"Build the response"},{"step":"response","change":"modified","label":"Show the list with status"}],"reasons":[{"kind":"table","ref":"db.orders","useCase":"list-orders","step":"query","label":"Read the user's orders","text":"Does read on table db.orders, the same table as the changed place-order/insert (insert)."}],"tests":{"state":"unknown","files":[],"note":"The repository was not read, so tests were not looked for."},"recheck":[{"step":"shipping","label":"Ask the tracker for each status"},{"step":"shape","label":"Build the response"},{"step":"response","label":"Show the list with status"},{"step":"query","label":"Read the user's orders"}]},{"id":"place-order","title":"Place an order","trigger":"POST /api/orders","relation":"direct","direct":[{"step":"insert","change":"modified","label":"Store the order"}],"reasons":[{"kind":"wire","ref":"api/session\u003eapi/orders-post","useCase":"place-order","step":"origin","label":"Check the Origin header","text":"Passes the wire api/session → api/orders-post, whose evidence code changed in this work."}],"tests":{"state":"unknown","files":[],"note":"The repository was not read, so tests were not looked for."},"recheck":[{"step":"insert","label":"Store the order"},{"step":"origin","label":"Check the Origin header"}]}],"summary":{"direct":2,"indirect":0,"withoutTests":0,"changedSteps":4,"testsKnown":false}}}</script>
|
|
426
|
+
<script>
|
|
427
|
+
/* nacholens player.
|
|
428
|
+
One stage with two scenes (the architecture, or the inside of one component) driven by one motion engine,
|
|
429
|
+
the list of flows with their steps, and the current step. Every piece of information has exactly one home:
|
|
430
|
+
flow/step names + change words + review ticks -> sidebar · what is moving now -> stage caption ·
|
|
431
|
+
narration, change reason, data, evidence -> inspector · planner/test/unmapped review -> review dock (review.js).
|
|
432
|
+
Model text is rendered with textContent only. Public API for review.js and tests: window.__nacholens. */
|
|
433
|
+
(function () {
|
|
434
|
+
"use strict";
|
|
435
|
+
var doc = document;
|
|
436
|
+
function $(id) { return doc.getElementById(id); }
|
|
437
|
+
var model = JSON.parse($("sv-model").textContent);
|
|
438
|
+
var changes = JSON.parse($("sv-changes").textContent);
|
|
439
|
+
var review = null;
|
|
440
|
+
try { review = $("sv-review-data") ? JSON.parse($("sv-review-data").textContent) : null; } catch (e) { review = null; }
|
|
441
|
+
var TARGET = (doc.documentElement && doc.documentElement.getAttribute && doc.documentElement.getAttribute("data-target")) || "html";
|
|
442
|
+
var reduce = !!(window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches);
|
|
443
|
+
function now() { return typeof performance !== "undefined" && performance.now ? performance.now() : Date.now(); }
|
|
444
|
+
function nextFrame(cb) { return typeof requestAnimationFrame === "function" ? requestAnimationFrame(cb) : setTimeout(function () { cb(now()); }, 16); }
|
|
445
|
+
function cancelFrame(id) { if (typeof cancelAnimationFrame === "function") cancelAnimationFrame(id); else clearTimeout(id); }
|
|
446
|
+
|
|
447
|
+
/* ═════════════════ DOM helpers (text nodes only) ═════════════════ */
|
|
448
|
+
var NS = "http://www.w3.org/2000/svg";
|
|
449
|
+
function h(tag, a) {
|
|
450
|
+
var e = doc.createElement(tag);
|
|
451
|
+
if (a) Object.keys(a).forEach(function (k) {
|
|
452
|
+
var v = a[k];
|
|
453
|
+
if (v == null || v === false) return;
|
|
454
|
+
if (k === "on") Object.keys(v).forEach(function (x) { e.addEventListener(x, v[x]); });
|
|
455
|
+
else if (k === "text") e.textContent = v;
|
|
456
|
+
else e.setAttribute(k, v === true ? "" : v);
|
|
457
|
+
});
|
|
458
|
+
for (var i = 2; i < arguments.length; i++) put(e, arguments[i]);
|
|
459
|
+
return e;
|
|
460
|
+
}
|
|
461
|
+
function put(e, c) {
|
|
462
|
+
if (c == null || c === false) return;
|
|
463
|
+
if (Array.isArray(c)) { c.forEach(function (x) { put(e, x); }); return; }
|
|
464
|
+
e.appendChild(typeof c === "object" ? c : doc.createTextNode(String(c)));
|
|
465
|
+
}
|
|
466
|
+
function s(tag, a, text) { var e = doc.createElementNS(NS, tag); Object.keys(a || {}).forEach(function (k) { e.setAttribute(k, a[k]); }); if (text != null) e.textContent = text; return e; }
|
|
467
|
+
function clear(e) { while (e.firstChild) e.removeChild(e.firstChild); }
|
|
468
|
+
function cls(e, name, on) { if (e && e.classList) e.classList[on ? "add" : "remove"](name); }
|
|
469
|
+
var P = {
|
|
470
|
+
check: "M5 12.5l4.5 4.5L19 7.5", play: "M7 4.5v15l12-7.5z", pause: "M8 5v14M16 5v14", prev: "M15 6l-6 6 6 6", next: "M9 6l6 6-6 6",
|
|
471
|
+
first: "M6 5v14M17 6l-7 6 7 6", replay: "M4 12a8 8 0 1 0 2.3-5.7M4 4v4h4", chevron: "m6 9 6 6 6-6", expand: "M14 4h6v6M10 20H4v-6M20 4l-6 6M4 20l6-6",
|
|
472
|
+
git: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM18 9a9 9 0 0 1-9 9",
|
|
473
|
+
client: "M8 3h8a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1ZM11 18h2",
|
|
474
|
+
gateway: "M12 3 4 7v5c0 4.4 3.4 8.3 8 9 4.6-.7 8-4.6 8-9V7l-8-4Z",
|
|
475
|
+
service: "M4 5h16v6H4zM4 13h16v6H4zM8 8h.01M8 16h.01",
|
|
476
|
+
datastore: "M12 3c4.4 0 8 1.3 8 3s-3.6 3-8 3-8-1.3-8-3 3.6-3 8-3ZM4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3",
|
|
477
|
+
external: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18ZM3 12h18M12 3c2.5 2.5 3.8 5.5 3.8 9s-1.3 6.5-3.8 9c-2.5-2.5-3.8-5.5-3.8-9S9.5 5.5 12 3Z"
|
|
478
|
+
};
|
|
479
|
+
function icon(n) { var e = s("svg", { "class": "i", viewBox: "0 0 24 24", "aria-hidden": "true" }); e.appendChild(s("path", { d: P[n] })); return e; }
|
|
480
|
+
|
|
481
|
+
/* ═════════════════ words (English by default; build --lang ko gives Korean) ═════════════════ */
|
|
482
|
+
var LANG = (function () { var l = doc.documentElement && doc.documentElement.getAttribute ? doc.documentElement.getAttribute("lang") : null; return String(l || "en").toLowerCase().indexOf("ko") === 0 ? "ko" : "en"; })();
|
|
483
|
+
var W = LANG === "ko" ? {
|
|
484
|
+
chg: { added: "신규", modified: "변경", removed: "삭제" },
|
|
485
|
+
kind: { client: "클라이언트", gateway: "게이트웨이", service: "서비스", datastore: "데이터 저장소", external: "외부 서비스" },
|
|
486
|
+
step: { request: "요청", response: "응답", call: "왕복 호출", internal: "내부 처리" },
|
|
487
|
+
role: { route: "라우트", handler: "핸들러", middleware: "미들웨어", service: "서비스", port: "포트", adapter: "어댑터", job: "작업", module: "모듈" },
|
|
488
|
+
op: { read: "읽기", insert: "추가", update: "수정", upsert: "추가·수정", delete: "삭제" },
|
|
489
|
+
leg: { req: "요청", res: "응답", int: "내부 호출" },
|
|
490
|
+
callers: "부르는 쪽", callees: "불리는 쪽", colEntry: "진입", colWork: "처리", colAdapter: "어댑터", tables: "테이블", endpoints: "엔드포인트",
|
|
491
|
+
whole: "전체 구조", inside: "내부",
|
|
492
|
+
hidden: function (n, arch) { return (arch ? "이 흐름과 무관한 컴포넌트 " : "이 흐름이 지나지 않는 항목 ") + n + "개는 숨김"; },
|
|
493
|
+
lookInside: function (x) { return x + " 내부 보기"; }, goInside: function (x) { return x + " 내부로 이동"; },
|
|
494
|
+
moreCols: function (n) { return "+" + n + "개 컬럼"; }, sends: "보냄", gets: "받음", details: function (x) { return x + " 자세히"; }, call: "호출",
|
|
495
|
+
idle: "대기", idleText: function (focus, canOpen) { return focus ? "재생하면 " + focus + " 안에서 데이터가 움직입니다" : "재생하면 요청이 컴포넌트 사이를 움직입니다" + (canOpen ? " · 상자를 누르면 내부로" : ""); },
|
|
496
|
+
out: "밖", outText: function (inPath, focus) { return inPath ? "이 단계의 " + focus + " 내부 경로는 모델에 없습니다" : "이 단계는 " + focus + " 밖에서 일어납니다"; },
|
|
497
|
+
work: "내부 처리", workText: function (x) { return x + " 안에서 처리"; },
|
|
498
|
+
first: "처음으로", prev: "이전 단계", next: "다음 단계", play: "재생", pause: "일시정지", replay: "다시 재생", toStep: function (n) { return n + "단계로"; }, speed: "재생 속도",
|
|
499
|
+
reviewed: "이 단계 리뷰함", gChanged: "이번에 바뀐 흐름", gSame: "바뀌지 않은 흐름", gAll: "흐름", reviewedTitle: "바뀐 단계 중 리뷰한 수", reviewBadge: function (a, b) { return "리뷰 " + a + "/" + b; },
|
|
500
|
+
noMatch: "맞는 흐름이 없습니다", overview: "흐름 개요", gone: "이번에 없어진 단계", howTo: "애니메이션 읽는 법", inStep: function (n) { return n + "단계에서 일어나는 일"; },
|
|
501
|
+
field: { label: "단계 이름", kind: "종류", route: "경로", request: "요청", response: "응답" }, before: "변경 전", moved: "내용은 같고 단계 순서만 바뀌었습니다.",
|
|
502
|
+
transforms: "데이터 모양이 바뀌는 곳", sent: "보내는 데이터", received: "받는 데이터", evidence: "근거 코드", changed: "바뀜", table: "테이블", endpoint: "엔드포인트",
|
|
503
|
+
backStep: function (n) { return "← " + n + "단계 설명으로"; }, backOverview: "← 흐름 개요로", insideOf: function (k, x) { return k + " · " + x + " 내부"; }, noDetail: "설명이 모델에 없습니다.",
|
|
504
|
+
newHere: "이번 작업에서 새로 생겼습니다", changedHere: "이번 작업에서 근거 코드가 바뀌었습니다", calledBy: "이 부품을 부르는 곳", calls: "이 부품이 부르는 곳", auth: "인증",
|
|
505
|
+
stepsHere: "이 흐름에서 지나는 단계", stepN: function (n) { return n + "단계"; },
|
|
506
|
+
lgReq: "요청이 이동 (주황 점)", lgRes: "응답이 돌아옴 (먹색 점)", lgWork: "컴포넌트 안에서 처리 중", lgPast: "이미 지나간 길", lgChanged: "이번 작업으로 생기거나 바뀐 것",
|
|
507
|
+
lgOpen: "상자를 누르면 내부로 들어가 같은 흐름을 봅니다", lgInt: "내부: 부품 사이 호출 (초록 점)",
|
|
508
|
+
ui: { overlay: "변경 강조", nav: "흐름과 단계", search: "흐름 검색", stage: "데이터 흐름 애니메이션", canvas: "아키텍처와 요청 흐름", transport: "재생 제어", review: "검토", insp: "현재 단계 설명" }
|
|
509
|
+
} : {
|
|
510
|
+
chg: { added: "New", modified: "Changed", removed: "Removed" },
|
|
511
|
+
kind: { client: "Client", gateway: "Gateway", service: "Service", datastore: "Data store", external: "External service" },
|
|
512
|
+
step: { request: "Request", response: "Response", call: "Round trip", internal: "Internal" },
|
|
513
|
+
role: { route: "Route", handler: "Handler", middleware: "Middleware", service: "Service", port: "Port", adapter: "Adapter", job: "Job", module: "Module" },
|
|
514
|
+
op: { read: "Read", insert: "Insert", update: "Update", upsert: "Upsert", delete: "Delete" },
|
|
515
|
+
leg: { req: "Request", res: "Response", int: "Internal call" },
|
|
516
|
+
callers: "Callers", callees: "Called", colEntry: "Entry", colWork: "Logic", colAdapter: "Adapters", tables: "Tables", endpoints: "Endpoints",
|
|
517
|
+
whole: "Architecture", inside: "inside",
|
|
518
|
+
hidden: function (n, arch) { return n + (arch ? (n === 1 ? " component" : " components") + " not on this flow hidden" : (n === 1 ? " item" : " items") + " this flow does not pass hidden"); },
|
|
519
|
+
lookInside: function (x) { return "Look inside " + x; }, goInside: function (x) { return "Go inside " + x; },
|
|
520
|
+
moreCols: function (n) { return "+" + n + (n === 1 ? " column" : " columns"); }, sends: "Req", gets: "Res", details: function (x) { return x + ": details"; }, call: "Call",
|
|
521
|
+
idle: "Idle", idleText: function (focus, canOpen) { return focus ? "Press play to watch the data move inside " + focus : "Press play to watch the request move between components" + (canOpen ? " · click a box to look inside" : ""); },
|
|
522
|
+
out: "Outside", outText: function (inPath, focus) { return inPath ? "The model has no path inside " + focus + " for this step" : "This step happens outside " + focus; },
|
|
523
|
+
work: "Working", workText: function (x) { return "Working inside " + x; },
|
|
524
|
+
first: "Back to the start", prev: "Previous step", next: "Next step", play: "Play", pause: "Pause", replay: "Replay", toStep: function (n) { return "Go to step " + n; }, speed: "Playback speed",
|
|
525
|
+
reviewed: "I reviewed this step", gChanged: "Changed in this work", gSame: "Not changed", gAll: "Flows", reviewedTitle: "Changed steps reviewed", reviewBadge: function (a, b) { return "Reviewed " + a + "/" + b; },
|
|
526
|
+
noMatch: "No matching flow", overview: "Flow overview", gone: "Steps removed in this work", howTo: "How to read the animation", inStep: function (n) { return "What happens in step " + n; },
|
|
527
|
+
field: { label: "Step name", kind: "Kind", route: "Route", request: "Request", response: "Response" }, before: "Before", moved: "Same content; only the step order changed.",
|
|
528
|
+
transforms: "Where the data changes shape", sent: "Data sent", received: "Data received", evidence: "Evidence", changed: "Changed", table: "Table", endpoint: "Endpoint",
|
|
529
|
+
backStep: function (n) { return "← Back to step " + n; }, backOverview: "← Back to the flow overview", insideOf: function (k, x) { return k + " · inside " + x; }, noDetail: "The model has no description.",
|
|
530
|
+
newHere: "New in this work", changedHere: "Its evidence code changed in this work", calledBy: "Called by", calls: "Calls", auth: "Authentication",
|
|
531
|
+
stepsHere: "Steps of this flow that pass here", stepN: function (n) { return "Step " + n; },
|
|
532
|
+
lgReq: "A request moves (orange dot)", lgRes: "The response comes back (ink dot)", lgWork: "Working inside a component", lgPast: "Path already taken", lgChanged: "Added or changed in this work",
|
|
533
|
+
lgOpen: "Click a box to see the same flow inside it", lgInt: "Inside: a call between parts (green dot)",
|
|
534
|
+
ui: null
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
/* ═════════════════ vocabulary (one table for every status) ═════════════════ */
|
|
538
|
+
var ST = { added: ["success", W.chg.added], modified: ["warning", W.chg.modified], removed: ["danger", W.chg.removed] };
|
|
539
|
+
var KIND = W.kind, STEP_KO = W.step, ROLE_KO = W.role, OP_KO = W.op, LEG_KO = W.leg;
|
|
540
|
+
var LANE = { client: 0, gateway: 1, service: 2, datastore: 3, external: 3 };
|
|
541
|
+
|
|
542
|
+
/* ═════════════════ derived data ═════════════════ */
|
|
543
|
+
var comp = {}; model.components.forEach(function (c) { comp[c.id] = c; });
|
|
544
|
+
var ucById = {}; model.useCases.forEach(function (u) { ucById[u.id] = u; });
|
|
545
|
+
var stepChg = {}, compChg = {}, dchg = {};
|
|
546
|
+
if (changes) {
|
|
547
|
+
(changes.steps || []).forEach(function (c) { stepChg[c.useCase + "/" + c.step] = c; });
|
|
548
|
+
(changes.components || []).forEach(function (c) { compChg[c.id] = c; });
|
|
549
|
+
(changes.details || []).forEach(function (d) { dchg[d.component + "|" + d.kind + "|" + d.id] = d.change; });
|
|
550
|
+
}
|
|
551
|
+
var cmp = {}; if (review && review.compare) review.compare.useCases.forEach(function (u) { cmp[u.id] = u; });
|
|
552
|
+
function uc() { return ucById[S.uc]; }
|
|
553
|
+
function first(l) { return String(l).split("\n")[0]; }
|
|
554
|
+
function pathOf(st) { return [st.from].concat(st.via || [], [st.to]); }
|
|
555
|
+
function chgOf(u, st) { return (S.overlay && stepChg[u.id + "/" + st.id]) || null; }
|
|
556
|
+
function changedSteps(u) { return u.steps.filter(function (st) { return stepChg[u.id + "/" + st.id]; }); }
|
|
557
|
+
function hasDetail(c) { return !!(c && ((c.parts && c.parts.length) || (c.tables && c.tables.length) || (c.endpoints && c.endpoints.length))); }
|
|
558
|
+
function compTag(id) { // marked only when changed AND on a changed step of the selected flow
|
|
559
|
+
var c = compChg[id]; if (!c || !S.overlay) return null;
|
|
560
|
+
return changedSteps(uc()).some(function (st) { return pathOf(st).indexOf(id) >= 0; }) ? c.change : null;
|
|
561
|
+
}
|
|
562
|
+
function evRef(e) { return e.file + ":" + e.lines[0] + (e.lines[1] !== e.lines[0] ? "-" + e.lines[1] : ""); }
|
|
563
|
+
|
|
564
|
+
/* ═════════════════ state ═════════════════ */
|
|
565
|
+
function parseHash(raw) { var o = {}; String(raw || "").replace(/^#/, "").split("&").forEach(function (kv) { var i = kv.indexOf("="); if (i > 0) o[kv.slice(0, i)] = decodeURIComponent(kv.slice(i + 1)); }); return o; }
|
|
566
|
+
var H0 = parseHash(typeof location !== "undefined" ? location.hash : "");
|
|
567
|
+
var start = model.useCases.filter(function (u) { return changedSteps(u).length; })[0] || model.useCases[0];
|
|
568
|
+
var S = { uc: H0.uc && ucById[H0.uc] ? H0.uc : start.id, overlay: !!changes, filter: "", collapsed: { same: true }, item: null, zooming: false };
|
|
569
|
+
var KEY = "sv-player:" + ((changes && changes.ref) || model.product.id), ticks = {};
|
|
570
|
+
try { ticks = JSON.parse(localStorage.getItem(KEY) || "{}") || {}; } catch (e) { ticks = {}; }
|
|
571
|
+
function setTick(id, on) { if (on) ticks[id] = 1; else delete ticks[id]; try { localStorage.setItem(KEY, JSON.stringify(ticks)); } catch (e) { /* storage blocked: ticks last for this visit */ } }
|
|
572
|
+
|
|
573
|
+
/* ═════════════════ Stage: scenes ═════════════════
|
|
574
|
+
A scene is a table of boxes { id: {x, y, w, h, kind, ref} }: the architecture, or the inside of one component
|
|
575
|
+
(parts + wires / tables / endpoints) with its neighbours as dashed stubs. Paths inside come only from the model
|
|
576
|
+
(step.trace, step.data, step.endpoints); nothing is inferred. */
|
|
577
|
+
var G = { W: 800, H: 400, NW: 168, NH: 56 };
|
|
578
|
+
var SC = { mode: "arch", focus: null, pos: {}, hidden: 0, heads: [] };
|
|
579
|
+
function measure() { var st = $("sv-stage"); G.W = Math.max(480, st.clientWidth || 0); G.H = Math.max(260, st.clientHeight || 0); }
|
|
580
|
+
function ucComps(u) { var out = []; u.steps.forEach(function (st) { pathOf(st).forEach(function (id) { if (out.indexOf(id) < 0) out.push(id); }); }); return out; }
|
|
581
|
+
function archLayout() {
|
|
582
|
+
var used = ucComps(uc()); SC.pos = {}; SC.heads = [];
|
|
583
|
+
// scale rule: with many components only the ones this flow touches are drawn
|
|
584
|
+
var shown = model.components.length > 8 ? model.components.filter(function (c) { return used.indexOf(c.id) >= 0; }) : model.components.slice();
|
|
585
|
+
SC.hidden = model.components.length - shown.length;
|
|
586
|
+
var lanes = {}; shown.forEach(function (c) { var l = c.lane != null ? c.lane : LANE[c.kind]; (lanes[l] = lanes[l] || []).push(c); });
|
|
587
|
+
var keys = Object.keys(lanes).map(Number).sort(function (a, b) { return a - b; });
|
|
588
|
+
G.NW = Math.round(Math.max(140, Math.min(200, (G.W - 60) / keys.length - 28)));
|
|
589
|
+
var mx = G.NW / 2 + 32, span = keys.length > 1 ? (G.W - 2 * mx) / (keys.length - 1) : 0, top = 76, bottom = 28;
|
|
590
|
+
keys.forEach(function (k, li) {
|
|
591
|
+
var list = lanes[k], rows = {}, used2 = {}, next = 0;
|
|
592
|
+
list.forEach(function (c) { if (c.row != null) { rows[c.id] = c.row; used2[c.row] = 1; } });
|
|
593
|
+
list.forEach(function (c) { if (rows[c.id] == null) { while (used2[next]) next++; rows[c.id] = next; used2[next] = 1; } });
|
|
594
|
+
var order = Object.keys(used2).map(Number).sort(function (a, b) { return a - b; }), n = order.length;
|
|
595
|
+
var gap = n > 1 ? Math.min(108, Math.max(G.NH + 18, (G.H - top - bottom - G.NH) / (n - 1))) : 0;
|
|
596
|
+
list.forEach(function (c) {
|
|
597
|
+
var i = order.indexOf(rows[c.id]);
|
|
598
|
+
SC.pos[c.id] = { x: keys.length > 1 ? mx + li * span : G.W / 2, y: top + (G.H - top - bottom) / 2 + (i - (n - 1) / 2) * gap, w: G.NW, h: G.NH, lane: li, kind: "node", ref: c };
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
function traceIn(st, cid) { return (st.trace || []).filter(function (r) { return r.split("/")[0] === cid; }).map(function (r) { return "p:" + r.split("/")[1]; }); }
|
|
603
|
+
function targetsIn(st, c) { // the cards a step reaches inside a datastore / third party
|
|
604
|
+
if (c.tables) return (st.data || []).filter(function (d) { return d.store === c.id; }).map(function (d) { return "t:" + d.table; });
|
|
605
|
+
if (c.endpoints) return (st.endpoints || []).filter(function (e) { return e.split("/")[0] === c.id; }).map(function (e) { return "e:" + e.split("/")[1]; });
|
|
606
|
+
return [];
|
|
607
|
+
}
|
|
608
|
+
function detailLayout() {
|
|
609
|
+
var c = comp[SC.focus], u = uc(), top = 98, bottom = 26, pad = 18, stubW = 104, stubH = 44;
|
|
610
|
+
SC.pos = {}; SC.heads = []; SC.hidden = 0;
|
|
611
|
+
// neighbours this flow connects to the focus: earlier lanes on the left (callers), later lanes on the right (callees)
|
|
612
|
+
var nb = [];
|
|
613
|
+
u.steps.forEach(function (st) { var p = pathOf(st); p.forEach(function (id, i) { if (id !== c.id) return; [p[i - 1], p[i + 1]].forEach(function (n) { if (n && n !== c.id && nb.indexOf(n) < 0) nb.push(n); }); }); });
|
|
614
|
+
var me = LANE[c.kind], left = nb.filter(function (id) { return LANE[comp[id].kind] < me; }), right = nb.filter(function (id) { return LANE[comp[id].kind] >= me; });
|
|
615
|
+
function stubs(list, x, head) {
|
|
616
|
+
if (!list.length) return;
|
|
617
|
+
SC.heads.push({ x: x, text: head });
|
|
618
|
+
var gap = Math.min(92, (G.H - top - bottom) / list.length);
|
|
619
|
+
list.forEach(function (id, i) { SC.pos["stub:" + id] = { x: x, y: top + (G.H - top - bottom) / 2 + (i - (list.length - 1) / 2) * gap, w: stubW, h: stubH, kind: "stub", ref: comp[id] }; });
|
|
620
|
+
}
|
|
621
|
+
stubs(left, pad + stubW / 2, W.callers);
|
|
622
|
+
stubs(right, G.W - pad - stubW / 2, W.callees);
|
|
623
|
+
var inL = left.length ? pad + stubW + 28 : pad, inR = right.length ? G.W - pad - stubW - 28 : G.W - pad;
|
|
624
|
+
if (c.parts && c.parts.length) {
|
|
625
|
+
var byId = {}; c.parts.forEach(function (p) { byId[p.id] = p; });
|
|
626
|
+
var order = []; u.steps.forEach(function (st) { traceIn(st, c.id).forEach(function (id) { if (order.indexOf(id) < 0 && byId[id.slice(2)]) order.push(id); }); });
|
|
627
|
+
var list = (order.length ? order.map(function (id) { return byId[id.slice(2)]; }) : c.parts.slice()).slice(0, 14);
|
|
628
|
+
SC.hidden = c.parts.length - list.length; // scale rule: only the parts this flow passes
|
|
629
|
+
var cols = [[W.colEntry, ["route", "handler", "middleware"]], [W.colWork, ["service", "module", "job", "port"]], [W.colAdapter, ["adapter"]]]
|
|
630
|
+
.map(function (g) { return { name: g[0], items: list.filter(function (p) { return g[1].indexOf(p.role) >= 0; }) }; })
|
|
631
|
+
.filter(function (g) { return g.items.length; });
|
|
632
|
+
var colW = (inR - inL) / cols.length, cw = Math.max(124, Math.min(200, colW - 30)), ch = 58;
|
|
633
|
+
cols.forEach(function (col, ci) {
|
|
634
|
+
var x = inL + colW * (ci + 0.5), n = col.items.length, gap = n > 1 ? Math.min(86, Math.max(ch + 12, (G.H - top - bottom - ch) / (n - 1))) : 0; // room for a transform chip when there is space
|
|
635
|
+
SC.heads.push({ x: x, text: col.name });
|
|
636
|
+
col.items.forEach(function (p, i) { SC.pos["p:" + p.id] = { x: x, y: top + (G.H - top - bottom) / 2 + (i - (n - 1) / 2) * gap, w: cw, h: ch, kind: "part", ref: p, col: ci }; });
|
|
637
|
+
});
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
var used = {}; u.steps.forEach(function (st) { targetsIn(st, c).forEach(function (id) { used[id] = 1; }); });
|
|
641
|
+
var cards = c.tables ? c.tables.map(function (t) { return { id: "t:" + t.name, kind: "table", ref: t, lines: t.columns.length }; })
|
|
642
|
+
: c.endpoints.map(function (e) { return { id: "e:" + e.id, kind: "endpoint", ref: e, lines: 2 }; });
|
|
643
|
+
cards.sort(function (a, b) { return (used[b.id] ? 1 : 0) - (used[a.id] ? 1 : 0); }); // the ones this flow reaches first
|
|
644
|
+
var avail = inR - inL, ncol = Math.max(1, Math.min(3, Math.floor(avail / 240))), cw2 = avail / ncol - 18, all = (c.tables || c.endpoints).length;
|
|
645
|
+
cards = cards.slice(0, ncol * 3); SC.hidden = all - cards.length;
|
|
646
|
+
var maxLines = 6, rowsH = [], total = 0;
|
|
647
|
+
for (var pass = 0; pass < 3; pass++) {
|
|
648
|
+
cards.forEach(function (cd) { cd.show = Math.min(cd.lines, maxLines); cd.h = 46 + cd.show * 17 + (cd.lines > cd.show ? 18 : 0); });
|
|
649
|
+
rowsH = []; cards.forEach(function (cd, i) { var r = Math.floor(i / ncol); rowsH[r] = Math.max(rowsH[r] || 0, cd.h); });
|
|
650
|
+
total = rowsH.reduce(function (a, b) { return a + b; }, 0) + 14 * Math.max(0, rowsH.length - 1);
|
|
651
|
+
if (total <= G.H - top - bottom) break;
|
|
652
|
+
maxLines = maxLines > 3 ? 3 : 1;
|
|
653
|
+
}
|
|
654
|
+
var y = top + Math.max(0, (G.H - top - bottom - total) / 2);
|
|
655
|
+
rowsH.forEach(function (rh, r) {
|
|
656
|
+
cards.slice(r * ncol, r * ncol + ncol).forEach(function (cd, k) { SC.pos[cd.id] = { x: inL + (k + 0.5) * (avail / ncol), y: y + cd.h / 2, w: cw2, h: cd.h, kind: cd.kind, ref: cd.ref, show: cd.show }; });
|
|
657
|
+
y += rh + 14;
|
|
658
|
+
});
|
|
659
|
+
SC.heads.push({ x: (inL + inR) / 2, text: c.tables ? W.tables : W.endpoints });
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/* ═════════════════ Stage: geometry (computed here, so the engine needs no SVG measuring) ═════════════════ */
|
|
663
|
+
function edge(id, tx, ty) {
|
|
664
|
+
var p = SC.pos[id], dx = tx - p.x, dy = ty - p.y, hw = p.w / 2 + 3, hh = p.h / 2 + 3;
|
|
665
|
+
if (!dx && !dy) return { x: p.x, y: p.y };
|
|
666
|
+
var t = Math.min(dx ? hw / Math.abs(dx) : 1e9, dy ? hh / Math.abs(dy) : 1e9);
|
|
667
|
+
return { x: p.x + dx * t, y: p.y + dy * t };
|
|
668
|
+
}
|
|
669
|
+
function bend(a, b) {
|
|
670
|
+
var A0 = SC.pos[a], B0 = SC.pos[b];
|
|
671
|
+
if (SC.mode === "arch" && Math.abs(A0.lane - B0.lane) > 1) return { x: (A0.x + B0.x) / 2, y: (A0.y + B0.y) / 2 > G.H / 2 ? Math.max(A0.y, B0.y) + 110 : Math.min(A0.y, B0.y) - 110 };
|
|
672
|
+
if (SC.mode === "detail" && Math.abs(A0.x - B0.x) < 1 && Math.abs(A0.y - B0.y) > 1.7 * A0.h) return { x: A0.x + A0.w / 2 + 48, y: (A0.y + B0.y) / 2 }; // same column, not adjacent: go around
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
function hopPts(a, b) {
|
|
676
|
+
var A0 = SC.pos[a], B0 = SC.pos[b], c = bend(a, b);
|
|
677
|
+
if (!c) return [edge(a, B0.x, B0.y), edge(b, A0.x, A0.y)];
|
|
678
|
+
var q0 = edge(a, c.x, c.y), q1 = edge(b, c.x, c.y), out = [];
|
|
679
|
+
for (var i = 0; i <= 20; i++) { var t = i / 20, v = 1 - t; out.push({ x: v * v * q0.x + 2 * v * t * c.x + t * t * q1.x, y: v * v * q0.y + 2 * v * t * c.y + t * t * q1.y }); }
|
|
680
|
+
return out;
|
|
681
|
+
}
|
|
682
|
+
function routePts(ids) { var pts = []; ids.slice(1).forEach(function (b, i) { pts = pts.concat(hopPts(ids[i], b)); }); return pts; }
|
|
683
|
+
function r1(v) { return Math.round(v * 10) / 10; }
|
|
684
|
+
function dOf(pts) { return pts.map(function (p, i) { return (i ? "L" : "M") + r1(p.x) + " " + r1(p.y); }).join(" "); }
|
|
685
|
+
function lengths(pts) { var acc = [0]; for (var i = 1; i < pts.length; i++) acc.push(acc[i - 1] + Math.hypot(pts[i].x - pts[i - 1].x, pts[i].y - pts[i - 1].y)); return acc; }
|
|
686
|
+
function pointAt(pts, acc, d) {
|
|
687
|
+
if (d <= 0) return pts[0];
|
|
688
|
+
for (var i = 1; i < pts.length; i++) if (acc[i] >= d) { var k = acc[i] === acc[i - 1] ? 0 : (d - acc[i - 1]) / (acc[i] - acc[i - 1]); return { x: pts[i - 1].x + (pts[i].x - pts[i - 1].x) * k, y: pts[i - 1].y + (pts[i].y - pts[i - 1].y) * k }; }
|
|
689
|
+
return pts[pts.length - 1];
|
|
690
|
+
}
|
|
691
|
+
// a tag box around centred text: the rendered width when the browser can measure it (the embedded fonts are wider
|
|
692
|
+
// or narrower than the estimate), the estimate otherwise; `pad` on each side so the text never touches the edge
|
|
693
|
+
// (and, given `max`, shortened with … until the measured text fits)
|
|
694
|
+
function measure(text) { try { return text.getComputedTextLength ? text.getComputedTextLength() || 0 : 0; } catch (e) { return 0; } }
|
|
695
|
+
function fitPad(rect, text, cx, est, pad, max) {
|
|
696
|
+
var tw = measure(text);
|
|
697
|
+
if (max && tw && tw + 2 * pad > max) {
|
|
698
|
+
var str = String(text.textContent).replace(/…$/, "");
|
|
699
|
+
while (str.length > 1 && tw + 2 * pad > max) { str = str.slice(0, -1); text.textContent = str.replace(/\s+$/, "") + "…"; tw = measure(text); }
|
|
700
|
+
est = Math.min(est, tw);
|
|
701
|
+
}
|
|
702
|
+
var w = Math.max(est, tw) + 2 * pad;
|
|
703
|
+
rect.setAttribute("x", cx - w / 2); rect.setAttribute("width", w);
|
|
704
|
+
}
|
|
705
|
+
function textW(str, px) { var w = 0; for (var i = 0; i < str.length; i++) w += str.charCodeAt(i) > 0x2e80 ? px : px * 0.6; return w; }
|
|
706
|
+
function clip(str, maxW, px) { str = String(str); if (textW(str, px) <= maxW) return str; var o = ""; for (var i = 0; i < str.length && textW(o + str[i] + "…", px) <= maxW; i++) o += str[i]; return o + "…"; }
|
|
707
|
+
function wrap2(str, maxW, px) { // one line if it fits, else break at a space, a slash or a camelCase hump, then clip
|
|
708
|
+
str = String(str); if (textW(str, px) <= maxW) return [str];
|
|
709
|
+
var cut = 0;
|
|
710
|
+
for (var i = 1; i < str.length; i++) {
|
|
711
|
+
var brk = str[i] === " " || str[i] === "(" || str[i - 1] === "/" || (/[a-z]/.test(str[i - 1]) && /[A-Z]/.test(str[i]));
|
|
712
|
+
if (brk && textW(str.slice(0, i), px) <= maxW) cut = i;
|
|
713
|
+
}
|
|
714
|
+
if (!cut) while (cut < str.length && textW(str.slice(0, cut + 1), px) <= maxW) cut++;
|
|
715
|
+
return [str.slice(0, cut).trim(), clip(str.slice(cut).trim(), maxW, px)];
|
|
716
|
+
}
|
|
717
|
+
function itemName(id) {
|
|
718
|
+
var p = SC.pos[id]; if (!p) return "";
|
|
719
|
+
if (p.kind === "node" || p.kind === "stub") return first(p.ref.label);
|
|
720
|
+
if (p.kind === "part") return p.ref.label;
|
|
721
|
+
if (p.kind === "table") return p.ref.name;
|
|
722
|
+
return p.ref.method + " " + p.ref.path;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/* ═════════════════ Stage: legs (what moves, per scene) ═════════════════ */
|
|
726
|
+
function mv(ids, tone, text) { return { type: "move", ids: ids, tone: tone, text: text || "" }; }
|
|
727
|
+
function legsOf(st) { return SC.mode === "arch" ? archLegs(st) : detailLegs(st); }
|
|
728
|
+
function archLegs(st) {
|
|
729
|
+
var p = pathOf(st).filter(function (id) { return SC.pos[id]; });
|
|
730
|
+
if (st.kind === "internal") return SC.pos[st.from] ? [{ type: "work", at: st.from }] : [];
|
|
731
|
+
if (p.length < 2) return [];
|
|
732
|
+
if (st.kind === "call") return [mv(p, "req", st.request), mv(p.slice().reverse(), "res", st.response)];
|
|
733
|
+
return [mv(p, st.kind === "response" ? "res" : "req", st.kind === "response" ? st.response : st.request)];
|
|
734
|
+
}
|
|
735
|
+
function wireBetween(a, b) { return (comp[SC.focus].wires || []).filter(function (w) { var f = "p:" + w.from, t = "p:" + w.to; return (f === a && t === b) || (f === b && t === a); })[0]; }
|
|
736
|
+
function detailLegs(st) {
|
|
737
|
+
var c = comp[SC.focus]; if (pathOf(st).indexOf(c.id) < 0) return [];
|
|
738
|
+
var stub = function (id) { return SC.pos["stub:" + id] ? "stub:" + id : null; };
|
|
739
|
+
if (c.parts && c.parts.length) {
|
|
740
|
+
var T = traceIn(st, c.id).filter(function (id) { return SC.pos[id]; });
|
|
741
|
+
if (st.kind === "internal") {
|
|
742
|
+
if (T.length > 1) return [mv(T, "int", T.slice(1).map(function (b, i) { var w = wireBetween(T[i], b); return w ? w.label : itemName(b); }).join(" → "))];
|
|
743
|
+
return T.length ? [{ type: "work", at: T[0] }] : [];
|
|
744
|
+
}
|
|
745
|
+
if (!T.length) return [];
|
|
746
|
+
// the neighbour on each side of the focus in this step's path (a gateway in `via` counts)
|
|
747
|
+
var p = pathOf(st), i = p.indexOf(c.id), inS = i > 0 ? stub(p[i - 1]) : null, outS = i < p.length - 1 ? stub(p[i + 1]) : null;
|
|
748
|
+
var ids = (inS ? [inS] : []).concat(T, outS ? [outS] : []);
|
|
749
|
+
if (ids.length < 2) return [];
|
|
750
|
+
if (st.kind === "call") return [mv(ids, "req", st.request), mv(ids.slice().reverse(), "res", st.response)];
|
|
751
|
+
return [mv(ids, st.kind === "response" ? "res" : "req", st.kind === "response" ? st.response : st.request)];
|
|
752
|
+
}
|
|
753
|
+
var p2 = pathOf(st), j = p2.indexOf(c.id), other = j > 0 ? p2[j - 1] : p2[j + 1];
|
|
754
|
+
var tg = targetsIn(st, c).filter(function (id) { return SC.pos[id]; })[0], s0 = other ? stub(other) : null;
|
|
755
|
+
if (!tg || !s0) return [];
|
|
756
|
+
if (st.kind === "call") return [mv([s0, tg], "req", st.request), mv([tg, s0], "res", st.response)];
|
|
757
|
+
return [mv(st.to === c.id ? [s0, tg] : [tg, s0], st.kind === "response" ? "res" : "req", st.kind === "response" ? st.response : st.request)];
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/* ═════════════════ Stage: drawing ═════════════════ */
|
|
761
|
+
var L = {}, NODE = {}, LINK = {};
|
|
762
|
+
function drawStage() {
|
|
763
|
+
measure();
|
|
764
|
+
var svg = $("sv-canvas"); clear(svg);
|
|
765
|
+
svg.setAttribute("viewBox", "0 0 " + G.W + " " + G.H);
|
|
766
|
+
["links", "trail", "flow", "packet", "nodes", "notes", "fx", "rings"].forEach(function (k) { L[k] = s("g", { "class": "layer-" + k }); svg.appendChild(L[k]); });
|
|
767
|
+
NODE = {}; LINK = {};
|
|
768
|
+
if (SC.mode === "arch") { archLayout(); drawArch(); } else { detailLayout(); drawDetail(); }
|
|
769
|
+
cls($("sv-stage"), "in-detail", SC.mode === "detail");
|
|
770
|
+
var cr = $("sv-crumbs"); clear(cr); cr.hidden = SC.mode !== "detail";
|
|
771
|
+
if (SC.mode === "detail") put(cr, [h("button", { type: "button", "class": "back", on: { click: closeDetail } }, icon("prev"), W.whole), h("span", { "class": "here", text: first(comp[SC.focus].label) }), h("span", { "class": "sub", text: W.inside })]);
|
|
772
|
+
var stage = $("sv-stage"), old = stage.lastHiddenNote; if (old && old.parentNode) old.parentNode.removeChild(old);
|
|
773
|
+
stage.lastHiddenNote = null;
|
|
774
|
+
if (SC.hidden > 0) stage.lastHiddenNote = stage.appendChild(h("div", { "class": "hidden-note", text: W.hidden(SC.hidden, SC.mode === "arch") }));
|
|
775
|
+
}
|
|
776
|
+
function addLink(key, el) { (LINK[key] = LINK[key] || []).push(el); L.links.appendChild(el); }
|
|
777
|
+
function keyOf(a, b) { return [a, b].sort().join("|"); }
|
|
778
|
+
function changeTag(g, x, y, w, change) {
|
|
779
|
+
if (!change) return;
|
|
780
|
+
cls(g, "chg-" + change, true);
|
|
781
|
+
var tw = Math.max(32, textW(ST[change][1], 11) + 12), rc = g.appendChild(s("rect", { "class": "tagbg", y: y - 9, height: 18, rx: 4 }));
|
|
782
|
+
var tx = g.appendChild(s("text", { "class": "tagtx", x: x + w - 8 - tw / 2, y: y + 4 }, ST[change][1]));
|
|
783
|
+
fitPad(rc, tx, x + w - 8 - tw / 2, tw - 12, 6);
|
|
784
|
+
}
|
|
785
|
+
function clickable(g, label, fn) {
|
|
786
|
+
g.setAttribute("tabindex", "0"); g.setAttribute("role", "button"); g.setAttribute("aria-label", label);
|
|
787
|
+
g.addEventListener("click", fn);
|
|
788
|
+
g.addEventListener("keydown", function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); e.stopPropagation(); fn(); } });
|
|
789
|
+
}
|
|
790
|
+
function drawArch() {
|
|
791
|
+
model.links.forEach(function (l) { if (SC.pos[l.a] && SC.pos[l.b]) addLink(keyOf(l.a, l.b), s("path", { "class": "lk", d: dOf(hopPts(l.a, l.b)) })); });
|
|
792
|
+
Object.keys(SC.pos).forEach(function (id) {
|
|
793
|
+
var p = SC.pos[id], c = p.ref, x = p.x - p.w / 2, y = p.y - p.h / 2, g = s("g", { "class": "nd", "data-id": id, "data-kind": c.kind }), open = hasDetail(c);
|
|
794
|
+
g.appendChild(s("rect", { "class": "box", x: x, y: y, width: p.w, height: p.h, rx: 10 }));
|
|
795
|
+
g.appendChild(s("rect", { "class": "ibox", x: x + 10, y: p.y - 15, width: 30, height: 30, rx: 8 }));
|
|
796
|
+
g.appendChild(s("path", { "class": "ico", d: P[c.kind], transform: "translate(" + (x + 16) + "," + (p.y - 9) + ") scale(.75)" }));
|
|
797
|
+
var ln = wrap2(first(c.label), p.w - (open ? 72 : 56), 14), y1 = ln.length > 1 ? p.y - 11 : p.y - 2;
|
|
798
|
+
ln.forEach(function (t, i) { g.appendChild(s("text", { "class": "nm", x: x + 48, y: y1 + i * 16 }, t)); });
|
|
799
|
+
g.appendChild(s("text", { "class": "kd", x: x + 48, y: ln.length > 1 ? p.y + 20 : p.y + 14 }, KIND[c.kind]));
|
|
800
|
+
if (open) {
|
|
801
|
+
cls(g, "has-detail", true);
|
|
802
|
+
g.appendChild(s("path", { "class": "open", d: P.expand, transform: "translate(" + (x + p.w - 24) + "," + (p.y - 7) + ") scale(.58)" }));
|
|
803
|
+
g.appendChild(s("title", {}, W.lookInside(first(c.label))));
|
|
804
|
+
clickable(g, W.lookInside(first(c.label)), function () { openDetail(id); });
|
|
805
|
+
}
|
|
806
|
+
changeTag(g, x, y, p.w, compTag(id));
|
|
807
|
+
NODE[id] = g; L.nodes.appendChild(g);
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
function drawDetail() {
|
|
811
|
+
var c = comp[SC.focus];
|
|
812
|
+
SC.heads.forEach(function (hd) { L.links.appendChild(s("text", { "class": "colh", x: hd.x, y: 82 }, hd.text)); });
|
|
813
|
+
(c.wires || []).forEach(function (w) {
|
|
814
|
+
var a = "p:" + w.from, b = "p:" + w.to; if (!SC.pos[a] || !SC.pos[b]) return;
|
|
815
|
+
var ch = S.overlay ? dchg[c.id + "|wire|" + w.from + ">" + w.to] : null;
|
|
816
|
+
addLink(keyOf(a, b), s("path", { "class": "wr" + (ch ? " chg-" + ch : ""), d: dOf(hopPts(a, b)) }));
|
|
817
|
+
});
|
|
818
|
+
var seen = {}; // the edges to the neighbours: only those a step of this flow actually crosses
|
|
819
|
+
uc().steps.forEach(function (st) {
|
|
820
|
+
detailLegs(st).forEach(function (lg) {
|
|
821
|
+
if (lg.type !== "move") return;
|
|
822
|
+
lg.ids.slice(1).forEach(function (b, i) {
|
|
823
|
+
var a = lg.ids[i], k = keyOf(a, b);
|
|
824
|
+
if (seen[k] || LINK[k]) return;
|
|
825
|
+
seen[k] = 1; addLink(k, s("path", { "class": "wr stubwire", d: dOf(hopPts(a, b)) }));
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
Object.keys(SC.pos).forEach(function (id) { drawItem(id, SC.pos[id], c); });
|
|
830
|
+
}
|
|
831
|
+
function drawItem(id, p, c) {
|
|
832
|
+
var g = s("g", { "class": "it " + p.kind, "data-id": id }), x = p.x - p.w / 2, y = p.y - p.h / 2, r = p.ref;
|
|
833
|
+
g.appendChild(s("rect", { "class": "box", x: x, y: y, width: p.w, height: p.h, rx: 8 }));
|
|
834
|
+
if (p.kind === "stub") {
|
|
835
|
+
g.appendChild(s("text", { "class": "t1", x: p.x, y: p.y - 2 }, clip(first(r.label), p.w - 16, 14)));
|
|
836
|
+
g.appendChild(s("text", { "class": "t2", x: p.x, y: p.y + 14 }, KIND[r.kind]));
|
|
837
|
+
if (hasDetail(r)) { cls(g, "nav", true); g.appendChild(s("title", {}, W.goInside(first(r.label)))); clickable(g, W.goInside(first(r.label)), function () { switchFocus(r.id); }); }
|
|
838
|
+
} else if (p.kind === "part") {
|
|
839
|
+
var ln = wrap2(r.label, p.w - 22, 14), y1 = ln.length > 1 ? p.y - 11 : p.y - 3;
|
|
840
|
+
ln.forEach(function (t, i) { g.appendChild(s("text", { "class": "t1", x: x + 11, y: y1 + i * 16 }, t)); });
|
|
841
|
+
g.appendChild(s("text", { "class": "t2", x: x + 11, y: ln.length > 1 ? p.y + 20 : p.y + 14 }, clip((ROLE_KO[r.role] || r.role) + (r.connects && comp[r.connects] ? " → " + first(comp[r.connects].label) : ""), p.w - 22, 11)));
|
|
842
|
+
changeTag(g, x, y, p.w, S.overlay ? dchg[c.id + "|part|" + r.id] : null);
|
|
843
|
+
} else if (p.kind === "table") {
|
|
844
|
+
g.appendChild(s("text", { "class": "t1 mono", x: x + 12, y: y + 21 }, clip(r.name, p.w - 70, 14)));
|
|
845
|
+
g.appendChild(s("line", { "class": "hr", x1: x + 1, x2: x + p.w - 1, y1: y + 31, y2: y + 31 }));
|
|
846
|
+
g.colEls = {};
|
|
847
|
+
r.columns.slice(0, p.show).forEach(function (col, i) {
|
|
848
|
+
var cy = y + 31 + 17 * (i + 1);
|
|
849
|
+
g.colEls[col.name] = g.appendChild(s("text", { "class": "colname", "data-col": col.name, x: x + 12, y: cy }, clip(col.name, p.w * 0.6, 11.5)));
|
|
850
|
+
if (col.type) g.appendChild(s("text", { "class": "coltype", x: x + p.w - 12, y: cy }, col.type));
|
|
851
|
+
});
|
|
852
|
+
if (r.columns.length > p.show) g.appendChild(s("text", { "class": "collab", x: x + 12, y: y + 33 + 17 * (p.show + 1) }, W.moreCols(r.columns.length - p.show)));
|
|
853
|
+
changeTag(g, x, y, p.w, S.overlay ? dchg[c.id + "|table|" + r.name] : null);
|
|
854
|
+
} else {
|
|
855
|
+
var mth = s("g", { "class": "mth" });
|
|
856
|
+
mth.appendChild(s("rect", { x: x + 10, y: y + 10, width: 46, height: 18, rx: 4 }));
|
|
857
|
+
mth.appendChild(s("text", { x: x + 33, y: y + 23 }, r.method));
|
|
858
|
+
g.appendChild(mth);
|
|
859
|
+
g.appendChild(s("text", { "class": "t1 mono", x: x + 64, y: y + 23 }, clip(r.path, p.w - 122, 14)));
|
|
860
|
+
g.appendChild(s("line", { "class": "hr", x1: x + 1, x2: x + p.w - 1, y1: y + 36, y2: y + 36 }));
|
|
861
|
+
[[W.sends, r.request], [W.gets, r.response]].forEach(function (row, i) {
|
|
862
|
+
var cy = y + 36 + 17 * (i + 1);
|
|
863
|
+
g.appendChild(s("text", { "class": "collab", x: x + 12, y: cy }, row[0]));
|
|
864
|
+
g.appendChild(s("text", { "class": "colname", x: x + 44, y: cy }, clip(row[1] && row[1].length ? row[1].map(function (f) { return f.name; }).join(", ") : "—", p.w - 56, 11.5)));
|
|
865
|
+
});
|
|
866
|
+
changeTag(g, x, y, p.w, S.overlay ? dchg[c.id + "|endpoint|" + r.id] : null);
|
|
867
|
+
}
|
|
868
|
+
if (p.kind !== "stub") clickable(g, W.details(itemName(id)), function () { selectItem(id); });
|
|
869
|
+
g.opb = g.appendChild(s("g", { "class": "opb" }));
|
|
870
|
+
NODE[id] = g; L.nodes.appendChild(g);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/* ═════════════════ Stage: state of the current step (classes only; no re-draw) ═════════════════ */
|
|
874
|
+
function idsOf(lg) { return lg.type === "move" ? lg.ids : [lg.at]; }
|
|
875
|
+
function paintStepState() {
|
|
876
|
+
var u = uc(), cur = A.step >= 0 ? u.steps[A.step] : null, used = {}, usedK = {}, vis = {}, visK = {}, act = {}, work = {};
|
|
877
|
+
u.steps.forEach(function (st, i) {
|
|
878
|
+
var past = i < A.step || (i === A.step && A.finished);
|
|
879
|
+
legsOf(st).forEach(function (lg) {
|
|
880
|
+
var ids = idsOf(lg);
|
|
881
|
+
ids.forEach(function (id) { used[id] = 1; if (past) vis[id] = 1; });
|
|
882
|
+
ids.slice(1).forEach(function (b, j) { var k = keyOf(ids[j], b); usedK[k] = 1; if (past) visK[k] = 1; });
|
|
883
|
+
if (i !== A.step) return;
|
|
884
|
+
if (lg.type === "work") work[lg.at] = 1;
|
|
885
|
+
else ids.forEach(function (id, j) { if (SC.mode === "detail" || j === 0 || j === ids.length - 1) act[id] = 1; });
|
|
886
|
+
});
|
|
887
|
+
});
|
|
888
|
+
Object.keys(NODE).forEach(function (id) {
|
|
889
|
+
var g = NODE[id];
|
|
890
|
+
cls(g, "off", !used[id] && id.indexOf("stub:") !== 0);
|
|
891
|
+
cls(g, "visited", !!vis[id]); cls(g, "active", !!act[id]); cls(g, "working", !!work[id]); cls(g, "sel", S.item === id); cls(g, "hitcard", false);
|
|
892
|
+
if (g.colEls) Object.keys(g.colEls).forEach(function (k) { cls(g.colEls[k], "col-hit", false); });
|
|
893
|
+
if (g.opb) clear(g.opb);
|
|
894
|
+
});
|
|
895
|
+
Object.keys(LINK).forEach(function (k) { LINK[k].forEach(function (el) { cls(el, "off", !usedK[k]); cls(el, "visited", !!visK[k]); }); });
|
|
896
|
+
clear(L.notes);
|
|
897
|
+
if (SC.mode !== "detail" || !cur) return;
|
|
898
|
+
var c = comp[SC.focus];
|
|
899
|
+
(cur.data || []).filter(function (d) { return d.store === c.id; }).forEach(function (d) { markCard("t:" + d.table, OP_KO[d.op] || d.op, d.columns); });
|
|
900
|
+
(cur.endpoints || []).filter(function (e) { return e.split("/")[0] === c.id; }).forEach(function (e) { markCard("e:" + e.split("/")[1], W.call); });
|
|
901
|
+
// where the data changes shape on this step (step.transforms), under the part that converts it
|
|
902
|
+
(cur.transforms || []).forEach(function (tf) {
|
|
903
|
+
var at = tf.at.split("/"), p = at[0] === c.id ? SC.pos["p:" + at[1]] : null; if (!p) return;
|
|
904
|
+
// "in → out" when it fits beside the neighbours, else "→ out" (the full pair is in the panel), clipped only as a last resort
|
|
905
|
+
var room = chipRoom(p, p.y + p.h / 2 + 6, 20), full = tf["in"].type + " → " + tf.out.type;
|
|
906
|
+
var text = clip(textW(full, 11) <= room - 18 ? full : "→ " + tf.out.type, room - 18, 11), g = s("g", { "class": "xchip" });
|
|
907
|
+
var rc = g.appendChild(s("rect", { y: p.y + p.h / 2 + 6, height: 20, rx: 4 }));
|
|
908
|
+
var tx = g.appendChild(s("text", { x: p.x, y: p.y + p.h / 2 + 20 }, text));
|
|
909
|
+
L.notes.appendChild(g);
|
|
910
|
+
if (text === full && measure(tx) + 18 > room) { tx.textContent = text = clip("→ " + tf.out.type, room - 18, 11); }
|
|
911
|
+
fitPad(rc, tx, p.x, textW(text, 11), 9, room);
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
// widest centred tag under box p that stays clear of every other box beside it and of the stage edge
|
|
915
|
+
function chipRoom(p, top, hgt) {
|
|
916
|
+
var half = Math.min(p.x, G.W - p.x) - 4;
|
|
917
|
+
Object.keys(SC.pos).forEach(function (id) {
|
|
918
|
+
var q = SC.pos[id]; if (q === p || q.y + q.h / 2 < top - 4 || q.y - q.h / 2 > top + hgt + 4) return;
|
|
919
|
+
var gap = q.x > p.x ? q.x - q.w / 2 - p.x : p.x - (q.x + q.w / 2);
|
|
920
|
+
if (gap > 0) half = Math.min(half, gap - 6);
|
|
921
|
+
});
|
|
922
|
+
return Math.max(p.w, 2 * half);
|
|
923
|
+
}
|
|
924
|
+
function markCard(id, label, cols) {
|
|
925
|
+
var g = NODE[id], p = SC.pos[id]; if (!g || !p) return;
|
|
926
|
+
cls(g, "hitcard", true);
|
|
927
|
+
var w = textW(label, 11) + 16;
|
|
928
|
+
var rc = g.opb.appendChild(s("rect", { y: p.y - p.h / 2 + 9, height: 18, rx: 4 }));
|
|
929
|
+
var tx = g.opb.appendChild(s("text", { x: p.x + p.w / 2 - w / 2 - 10, y: p.y - p.h / 2 + 22 }, label));
|
|
930
|
+
fitPad(rc, tx, p.x + p.w / 2 - w / 2 - 10, textW(label, 11), 8);
|
|
931
|
+
(cols || []).forEach(function (n) { if (g.colEls && g.colEls[n]) cls(g.colEls[n], "col-hit", true); });
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/* ═════════════════ Stage: motion engine ═════════════════
|
|
935
|
+
A step is a list of legs. move = the packet travels a route; work = one box processes (progress bar).
|
|
936
|
+
Duration follows route length and speed; each leg eases in and out; a continuous run keeps a faint trail. */
|
|
937
|
+
var SPEED = 300, DWELL = 240, GAP = 260, WORK = 950, EMPTY = 700, HOLD = 900;
|
|
938
|
+
var A = { step: -1, legs: [], leg: 0, t: 0, dur: 1, playing: false, running: false, raf: 0, timer: 0, last: 0, rate: 1, finished: true };
|
|
939
|
+
var MOVE = null; // current move leg geometry: { pts, acc, len, trail, packet }
|
|
940
|
+
function ease(t) { return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; }
|
|
941
|
+
function stopClock() { cancelFrame(A.raf); clearTimeout(A.timer); A.running = false; }
|
|
942
|
+
function clearMotion() { [L.flow, L.packet, L.fx].forEach(function (g) { if (g) clear(g); }); MOVE = null; }
|
|
943
|
+
function startLeg(i, t0) {
|
|
944
|
+
var lg = A.legs[i]; A.leg = i; A.t = t0 || 0; clearMotion();
|
|
945
|
+
if (lg.type === "move") {
|
|
946
|
+
var pts = routePts(lg.ids), acc = lengths(pts), d = dOf(pts);
|
|
947
|
+
L.flow.appendChild(s("path", { "class": "flowline " + lg.tone, d: d }));
|
|
948
|
+
var trail = L.trail.appendChild(s("path", { "class": "trail " + lg.tone, d: d, "stroke-dasharray": "0 99999" }));
|
|
949
|
+
var pk = s("g", { "class": "pk " + lg.tone }); pk.appendChild(s("circle", { "class": "halo", r: 7 })); pk.appendChild(s("circle", { "class": "core", r: 6 }));
|
|
950
|
+
L.packet.appendChild(pk);
|
|
951
|
+
MOVE = { pts: pts, acc: acc, len: acc[acc.length - 1], trail: trail, packet: pk, tone: lg.tone, x: pts[0].x, y: pts[0].y };
|
|
952
|
+
A.dur = Math.max(520, Math.min(1700, MOVE.len / SPEED * 1000)) / A.rate;
|
|
953
|
+
} else {
|
|
954
|
+
var p = SC.pos[lg.at], w = p.w - 24;
|
|
955
|
+
L.fx.appendChild(s("rect", { "class": "wbar-bg", x: p.x - w / 2, y: p.y + p.h / 2 + 8, width: w, height: 4, rx: 2 }));
|
|
956
|
+
MOVE = { bar: L.fx.appendChild(s("rect", { "class": "wbar", x: p.x - w / 2, y: p.y + p.h / 2 + 8, width: 0, height: 4, rx: 2 })), w: w };
|
|
957
|
+
A.dur = WORK / A.rate;
|
|
958
|
+
}
|
|
959
|
+
frameDraw(); // place the packet before the first frame
|
|
960
|
+
caption();
|
|
961
|
+
if (reduce) { A.t = 1; frameDraw(); legEnd(); return; }
|
|
962
|
+
A.running = true; A.last = now(); A.raf = nextFrame(frame);
|
|
963
|
+
}
|
|
964
|
+
function frame(ts) {
|
|
965
|
+
if (!A.running) return;
|
|
966
|
+
A.t = Math.min(1, A.t + Math.max(0, ts - A.last) / A.dur); A.last = ts;
|
|
967
|
+
frameDraw();
|
|
968
|
+
if (A.t >= 1) { A.running = false; legEnd(); } else A.raf = nextFrame(frame);
|
|
969
|
+
}
|
|
970
|
+
function frameDraw() {
|
|
971
|
+
if (!MOVE) return;
|
|
972
|
+
var e = ease(A.t);
|
|
973
|
+
if (MOVE.pts) {
|
|
974
|
+
var pt = pointAt(MOVE.pts, MOVE.acc, e * MOVE.len); MOVE.x = pt.x; MOVE.y = pt.y;
|
|
975
|
+
MOVE.packet.setAttribute("transform", "translate(" + r1(pt.x) + "," + r1(pt.y) + ")");
|
|
976
|
+
MOVE.trail.setAttribute("stroke-dasharray", r1(e * MOVE.len) + " 99999");
|
|
977
|
+
} else MOVE.bar.setAttribute("width", r1(MOVE.w * e));
|
|
978
|
+
progress();
|
|
979
|
+
}
|
|
980
|
+
function legEnd() {
|
|
981
|
+
var lg = A.legs[A.leg];
|
|
982
|
+
if (lg.type === "move") {
|
|
983
|
+
var p = SC.pos[lg.ids[lg.ids.length - 1]];
|
|
984
|
+
if (!reduce) {
|
|
985
|
+
var rg = L.rings.appendChild(s("rect", { "class": "ring " + lg.tone, x: p.x - p.w / 2 - 3, y: p.y - p.h / 2 - 3, width: p.w + 6, height: p.h + 6, rx: 11 }));
|
|
986
|
+
rg.addEventListener("animationend", function () { if (rg.parentNode) rg.parentNode.removeChild(rg); });
|
|
987
|
+
}
|
|
988
|
+
if (MOVE && MOVE.trail) cls(MOVE.trail, "past", true);
|
|
989
|
+
}
|
|
990
|
+
if (A.leg < A.legs.length - 1) {
|
|
991
|
+
if (reduce) { startLeg(A.leg + 1); return; }
|
|
992
|
+
A.timer = setTimeout(function () { startLeg(A.leg + 1); }, DWELL / A.rate);
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
stepFinished();
|
|
996
|
+
}
|
|
997
|
+
function stepFinished() {
|
|
998
|
+
A.finished = true; paintStepState(); progress(); transport(); renderSide();
|
|
999
|
+
if (A.playing && A.step < uc().steps.length - 1) A.timer = setTimeout(function () { go(A.step + 1, true); }, (reduce ? HOLD : GAP) / A.rate);
|
|
1000
|
+
else if (A.playing) { A.playing = false; transport(); }
|
|
1001
|
+
}
|
|
1002
|
+
function go(i, animate) { // the only way the current step changes
|
|
1003
|
+
stopClock(); clearMotion();
|
|
1004
|
+
var u = uc(), target = Math.max(-1, Math.min(i, u.steps.length - 1)), cont = target === A.step + 1 && A.finished && animate;
|
|
1005
|
+
A.step = target; A.finished = !animate || target < 0; A.legs = A.step >= 0 ? legsOf(u.steps[A.step]) : []; A.leg = 0; A.t = 0; S.item = null;
|
|
1006
|
+
if (!cont) { clear(L.trail); clear(L.rings); } // a continuous run keeps the faint trail of earlier legs; any jump starts clean
|
|
1007
|
+
paintStepState(); caption(); renderSide(); renderInsp(); transport(); syncHash();
|
|
1008
|
+
if (A.step >= 0 && animate) {
|
|
1009
|
+
if (A.legs.length) startLeg(0);
|
|
1010
|
+
else if (reduce) stepFinished();
|
|
1011
|
+
else A.timer = setTimeout(stepFinished, EMPTY / A.rate); // nothing moves in this scene: hold briefly, then go on
|
|
1012
|
+
} else progress();
|
|
1013
|
+
}
|
|
1014
|
+
function play() {
|
|
1015
|
+
var n = uc().steps.length;
|
|
1016
|
+
if (A.playing) { pause(); return; }
|
|
1017
|
+
A.playing = true;
|
|
1018
|
+
if ((A.step >= n - 1 && A.finished) || A.step < 0) { go(0, true); return; }
|
|
1019
|
+
if (!A.finished && A.legs.length) { transport(); if (MOVE && A.t < 1) { A.running = true; A.last = now(); A.raf = nextFrame(frame); } else legEnd(); return; } // resume mid-leg
|
|
1020
|
+
go(A.step + 1, true);
|
|
1021
|
+
}
|
|
1022
|
+
function pause() { A.playing = false; stopClock(); transport(); }
|
|
1023
|
+
function next() { A.playing = false; go(A.step + 1, true); }
|
|
1024
|
+
function prev() { A.playing = false; go(A.step - 1, false); }
|
|
1025
|
+
function caption() {
|
|
1026
|
+
var c = $("sv-caption"), u = uc(), lg = A.legs[A.leg], focus = SC.mode === "detail" ? first(comp[SC.focus].label) : null, kids;
|
|
1027
|
+
if (A.step < 0) kids = [h("span", { "class": "leg idle" }, W.idle), h("span", { "class": "txt kr", text: W.idleText(focus, model.components.some(hasDetail)) })];
|
|
1028
|
+
else if (!lg) kids = [h("span", { "class": "leg idle" }, W.out), h("span", { "class": "txt kr", text: W.outText(pathOf(u.steps[A.step]).indexOf(SC.focus) >= 0, focus) })];
|
|
1029
|
+
else if (lg.type === "work") kids = [h("span", { "class": "leg int" }, W.work), h("span", { "class": "txt kr", text: W.workText(itemName(lg.at)) })];
|
|
1030
|
+
else kids = [h("span", { "class": "leg " + lg.tone }, LEG_KO[lg.tone] + " → " + itemName(lg.ids[lg.ids.length - 1])), h("span", { "class": "txt mono ell", text: lg.text })];
|
|
1031
|
+
if (reduce) { clear(c); put(c, kids); return; }
|
|
1032
|
+
cls(c, "swap", true);
|
|
1033
|
+
clearTimeout(c.swapTimer);
|
|
1034
|
+
c.swapTimer = setTimeout(function () { clear(c); put(c, kids); cls(c, "swap", false); }, 110);
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/* ═════════════════ Stage: entering and leaving a component ═════════════════ */
|
|
1038
|
+
function tween(ms, fn, done) {
|
|
1039
|
+
if (reduce) { fn(1); if (done) done(); return; }
|
|
1040
|
+
var t0 = now();
|
|
1041
|
+
(function f(ts) { var k = Math.min(1, Math.max(0, (ts - t0) / ms)); fn(ease(k)); if (k < 1) nextFrame(f); else if (done) done(); })(t0);
|
|
1042
|
+
}
|
|
1043
|
+
function lerpRect(a, b, k) { return { x: a.x + (b.x - a.x) * k, y: a.y + (b.y - a.y) * k, w: a.w + (b.w - a.w) * k, h: a.h + (b.h - a.h) * k }; }
|
|
1044
|
+
function setRect(el, r) { el.setAttribute("x", r1(r.x)); el.setAttribute("y", r1(r.y)); el.setAttribute("width", r1(r.w)); el.setAttribute("height", r1(r.h)); }
|
|
1045
|
+
function fadeLayers(v) { [L.links, L.trail, L.nodes, L.notes, L.rings].forEach(function (g) { g.style.opacity = String(v); }); }
|
|
1046
|
+
function fadeIn() { var cv = $("sv-canvas"); cls(cv, "fade-in", false); if (cv.getBoundingClientRect) cv.getBoundingClientRect(); cls(cv, "fade-in", true); }
|
|
1047
|
+
function boxOf(p) { return { x: p.x - p.w / 2, y: p.y - p.h / 2, w: p.w, h: p.h }; }
|
|
1048
|
+
function openDetail(id) {
|
|
1049
|
+
if (SC.mode !== "arch" || S.zooming || !hasDetail(comp[id]) || !SC.pos[id]) return;
|
|
1050
|
+
var resume = A.playing, from = boxOf(SC.pos[id]), to = { x: 8, y: 8, w: G.W - 16, h: G.H - 16 };
|
|
1051
|
+
A.playing = false; stopClock(); clearMotion(); S.zooming = true;
|
|
1052
|
+
var z = $("sv-canvas").appendChild(s("rect", { "class": "zoom", rx: 10 }));
|
|
1053
|
+
tween(360, function (k) { setRect(z, lerpRect(from, to, k)); fadeLayers(1 - k); }, function () {
|
|
1054
|
+
SC.mode = "detail"; SC.focus = id; S.zooming = false; drawStage(); fadeIn();
|
|
1055
|
+
A.playing = resume; go(A.step, A.step >= 0); // replay the current step inside
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
function closeDetail() {
|
|
1059
|
+
if (SC.mode !== "detail" || S.zooming) return;
|
|
1060
|
+
var resume = A.playing, id = SC.focus; A.playing = false; stopClock(); clearMotion(); S.zooming = true;
|
|
1061
|
+
tween(160, function (k) { fadeLayers(1 - k); }, function () {
|
|
1062
|
+
SC.mode = "arch"; SC.focus = null; drawStage(); fadeLayers(0);
|
|
1063
|
+
var full = { x: 8, y: 8, w: G.W - 16, h: G.H - 16 }, to = SC.pos[id] ? boxOf(SC.pos[id]) : full;
|
|
1064
|
+
var z = $("sv-canvas").appendChild(s("rect", { "class": "zoom", rx: 10 }));
|
|
1065
|
+
tween(340, function (k) { setRect(z, lerpRect(full, to, k)); z.style.opacity = String(1 - k * 0.9); fadeLayers(k); }, function () {
|
|
1066
|
+
if (z.parentNode) z.parentNode.removeChild(z);
|
|
1067
|
+
S.zooming = false; A.playing = resume; go(A.step, resume && A.step >= 0);
|
|
1068
|
+
});
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
function switchFocus(id) { // from a stub straight into the neighbour's inside
|
|
1072
|
+
if (!hasDetail(comp[id])) return;
|
|
1073
|
+
var resume = A.playing; A.playing = false; stopClock(); clearMotion();
|
|
1074
|
+
SC.mode = "detail"; SC.focus = id; drawStage(); fadeIn(); A.playing = resume; go(A.step, A.step >= 0);
|
|
1075
|
+
}
|
|
1076
|
+
function selectItem(id) { S.item = S.item === id ? null : id; paintStepState(); renderInsp(); }
|
|
1077
|
+
function setOverlay(on) { S.overlay = !!on && !!changes; renderTop(); drawStage(); paintStepState(); renderSide(); renderInsp(); }
|
|
1078
|
+
|
|
1079
|
+
/* ═════════════════ Transport ═════════════════ */
|
|
1080
|
+
function transport() {
|
|
1081
|
+
var t = $("sv-transport"), u = uc(), n = u.steps.length, atEnd = A.step >= n - 1 && A.finished; clear(t);
|
|
1082
|
+
put(t, [
|
|
1083
|
+
h("button", { type: "button", "class": "btn icon ghost", title: W.first, "aria-label": W.first, disabled: A.step < 0 ? true : null, on: { click: function () { A.playing = false; go(-1, false); } } }, icon("first")),
|
|
1084
|
+
h("button", { type: "button", "class": "btn icon", title: W.prev, "aria-label": W.prev, disabled: A.step < 0 ? true : null, on: { click: prev } }, icon("prev")),
|
|
1085
|
+
h("button", { type: "button", "class": "btn primary", id: "sv-play", on: { click: play } }, icon(A.playing ? "pause" : atEnd ? "replay" : "play"), A.playing ? W.pause : atEnd ? W.replay : W.play),
|
|
1086
|
+
h("button", { type: "button", "class": "btn icon", title: W.next, "aria-label": W.next, disabled: atEnd ? true : null, on: { click: next } }, icon("next"))
|
|
1087
|
+
]);
|
|
1088
|
+
var sc = h("div", { "class": "scrub", id: "sv-scrub" });
|
|
1089
|
+
u.steps.forEach(function (st, i) {
|
|
1090
|
+
put(sc, h("button", { type: "button", "class": "seg-step" + (i < A.step || (i === A.step && A.finished) ? " done" : ""), title: (i + 1) + ". " + st.label, "aria-label": W.toStep(i + 1), on: { click: function () { A.playing = false; go(i, true); } } }, h("i")));
|
|
1091
|
+
});
|
|
1092
|
+
put(t, [sc, h("span", { "class": "counter", id: "sv-counter" }, (A.step + 1) + " / " + n)]);
|
|
1093
|
+
var sp = h("div", { "class": "seg", role: "group", "aria-label": W.speed });
|
|
1094
|
+
[[0.5, "0.5×"], [1, "1×"], [2, "2×"]].forEach(function (x) { put(sp, h("button", { type: "button", "aria-pressed": A.rate === x[0] ? "true" : "false", on: { click: function () { A.rate = x[0]; transport(); } } }, x[1])); });
|
|
1095
|
+
put(t, sp);
|
|
1096
|
+
}
|
|
1097
|
+
function progress() {
|
|
1098
|
+
var sc = $("sv-scrub"); if (!sc) return;
|
|
1099
|
+
var seg = sc.children[A.step]; if (!seg || !seg.firstChild) return;
|
|
1100
|
+
var frac = A.finished ? 1 : (A.leg + A.t) / Math.max(1, A.legs.length);
|
|
1101
|
+
seg.firstChild.style.width = Math.round(frac * 1000) / 10 + "%";
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/* ═════════════════ Sidebar: flows, their steps, the change word and the review tick ═════════════════ */
|
|
1105
|
+
function tickBox(id) {
|
|
1106
|
+
var on = !!ticks[id];
|
|
1107
|
+
return h("button", { type: "button", "class": "check", role: "checkbox", "aria-checked": on ? "true" : "false", "aria-label": W.reviewed, title: W.reviewed,
|
|
1108
|
+
on: { click: function (e) { e.stopPropagation(); setTick(id, !on); renderSide(); } } }, icon("check"));
|
|
1109
|
+
}
|
|
1110
|
+
function renderSide() {
|
|
1111
|
+
var side = $("sv-list"); clear(side);
|
|
1112
|
+
var f = S.filter.trim().toLowerCase();
|
|
1113
|
+
var groups = changes ? [["changed", W.gChanged], ["same", W.gSame]] : [["all", W.gAll]];
|
|
1114
|
+
groups.forEach(function (g) {
|
|
1115
|
+
var list = model.useCases.filter(function (u) {
|
|
1116
|
+
var grp = !changes ? "all" : changedSteps(u).length ? "changed" : "same";
|
|
1117
|
+
return grp === g[0] && (!f || (u.title + " " + u.trigger).toLowerCase().indexOf(f) >= 0);
|
|
1118
|
+
});
|
|
1119
|
+
if (!list.length) return;
|
|
1120
|
+
var open = f || g[0] === "all" ? true : !S.collapsed[g[0]];
|
|
1121
|
+
put(side, h("button", { type: "button", "class": "gh", "aria-expanded": open ? "true" : "false", on: { click: function () { S.collapsed[g[0]] = open; renderSide(); } } }, icon("chevron"), g[1], h("span", { "class": "n", text: String(list.length) })));
|
|
1122
|
+
if (!open) return;
|
|
1123
|
+
list.forEach(function (u) {
|
|
1124
|
+
var cur = u.id === S.uc, ch = S.overlay ? changedSteps(u) : [], rv = ch.filter(function (st) { return ticks["rv:" + u.id + "/" + st.id]; }).length;
|
|
1125
|
+
put(side, h("button", { type: "button", "class": "uc", "data-uc": u.id, "aria-current": cur ? "true" : null, on: { click: function () { if (!cur) selectUc(u.id); } } },
|
|
1126
|
+
h("span", { "class": "main" }, h("span", { "class": "t kr", text: u.title }), h("span", { "class": "m ell", text: u.trigger })),
|
|
1127
|
+
ch.length ? h("span", { "class": "badge", "data-tone": rv === ch.length ? "success" : "warning", title: W.reviewedTitle }, W.reviewBadge(rv, ch.length)) : null));
|
|
1128
|
+
if (!cur) return;
|
|
1129
|
+
var ol = h("ol", { "class": "steps", id: "sv-steps" });
|
|
1130
|
+
u.steps.forEach(function (st, i) {
|
|
1131
|
+
var c = chgOf(u, st), pick = function () { A.playing = false; go(i, true); };
|
|
1132
|
+
put(ol, h("li", { "class": "st" + (i < A.step ? " done" : ""), "data-step": st.id, "aria-current": i === A.step ? "step" : null, tabindex: 0,
|
|
1133
|
+
on: { click: pick, keydown: function (e) { if (e.key === "Enter") pick(); } } },
|
|
1134
|
+
h("span", { "class": "n" }, String(i + 1)), h("span", { "class": "lbl ell kr", text: st.label }),
|
|
1135
|
+
c ? h("span", { "class": "chg", "data-tone": ST[c.change][0] }, ST[c.change][1]) : null,
|
|
1136
|
+
c ? tickBox("rv:" + u.id + "/" + st.id) : null));
|
|
1137
|
+
});
|
|
1138
|
+
put(side, ol);
|
|
1139
|
+
});
|
|
1140
|
+
});
|
|
1141
|
+
if (!side.firstChild) put(side, h("div", { "class": "empty", text: W.noMatch }));
|
|
1142
|
+
}
|
|
1143
|
+
function selectUc(id, step) {
|
|
1144
|
+
if (!ucById[id]) return;
|
|
1145
|
+
S.uc = id; A.playing = false; stopClock(); A.step = -1; A.finished = true; S.item = null;
|
|
1146
|
+
drawStage(); fadeIn();
|
|
1147
|
+
go(step != null && step >= 0 ? step : -1, step != null && step >= 0);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
/* ═════════════════ Inspector: the current step, or the item picked inside a component ═════════════════ */
|
|
1151
|
+
function sec(title) { var e = h("div", { "class": "isec" }, title ? h("h2", { text: title }) : null); for (var i = 1; i < arguments.length; i++) put(e, arguments[i]); return e; }
|
|
1152
|
+
function noteRefs(note) { // "Evidence code changed: a.js:1-3, b.js:9" -> {lead, refs}
|
|
1153
|
+
var cut = note.indexOf(": "), lead = (cut > 0 ? note.slice(0, cut) : note).replace(/\s*\(.*\)\s*$/, "");
|
|
1154
|
+
var refs = cut > 0 ? note.slice(cut + 2).replace(/\s*\(.*\)\s*$/, "").split(/,\s*(?=[^\s,]+:\d)/) : [];
|
|
1155
|
+
return { lead: lead, refs: refs };
|
|
1156
|
+
}
|
|
1157
|
+
function renderInsp() {
|
|
1158
|
+
var el = $("sv-insp"); clear(el);
|
|
1159
|
+
if (S.item && SC.mode === "detail" && SC.pos[S.item]) { itemInsp(el); return; }
|
|
1160
|
+
var u = uc();
|
|
1161
|
+
if (A.step < 0) {
|
|
1162
|
+
put(el, h("div", { "class": "ih" }, h("p", { "class": "eyebrow", text: W.overview }), h("p", { "class": "lead kr", text: u.summary })));
|
|
1163
|
+
var row = cmp[u.id], gone = row && review.compare.mode === "two-models" && S.overlay ? row.rows.filter(function (r) { return r.status === "removed" && r.before; }) : [];
|
|
1164
|
+
if (gone.length) put(el, sec(W.gone, h("ul", { "class": "gone" }, gone.map(function (r) { return h("li", { "class": "kr", text: r.before.label }); }))));
|
|
1165
|
+
put(el, sec(W.howTo, legend()));
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
var st = u.steps[A.step], c = chgOf(u, st), hit = {};
|
|
1169
|
+
put(el, h("div", { "class": "ih" }, h("p", { "class": "eyebrow", text: W.inStep(A.step + 1) }), h("p", { "class": "lead kr", text: st.narration })));
|
|
1170
|
+
if (c) {
|
|
1171
|
+
var nr = noteRefs(c.note || ""); nr.refs.forEach(function (r) { hit[r.trim()] = 1; });
|
|
1172
|
+
put(el, sec(null, h("div", { "class": "note", "data-tone": ST[c.change][0] }, icon("git"), h("span", { "class": "kr", text: nr.lead }))));
|
|
1173
|
+
}
|
|
1174
|
+
var row2 = cmp[u.id] && review.compare.mode === "two-models" && S.overlay ? cmp[u.id].rows.filter(function (r) { return r.id === st.id; })[0] : null;
|
|
1175
|
+
if (row2 && row2.before && row2.after) {
|
|
1176
|
+
var diff = ["label", "kind", "route", "request", "response"].filter(function (k) { return (row2.before[k] || "") !== (row2.after[k] || ""); });
|
|
1177
|
+
var NAME = W.field;
|
|
1178
|
+
if (diff.length) put(el, sec(W.before, h("dl", { "class": "kv before" }, diff.map(function (k) { return [h("dt", { text: NAME[k] }), h("dd", { "class": "kr", text: k === "kind" ? STEP_KO[row2.before[k]] || row2.before[k] : row2.before[k] || "—" })]; }))));
|
|
1179
|
+
else if (row2.status === "moved") put(el, sec(W.before, h("p", { "class": "kr", text: W.moved })));
|
|
1180
|
+
}
|
|
1181
|
+
if (SC.mode === "arch" && st.transforms && st.transforms.length) { // inside a component the stage shows these as chips
|
|
1182
|
+
put(el, sec(W.transforms, st.transforms.map(function (tf) {
|
|
1183
|
+
var at = tf.at.split("/"), part = (comp[at[0]] && comp[at[0]].parts || []).filter(function (p) { return p.id === at[1]; })[0];
|
|
1184
|
+
return h("div", { "class": "xf" }, h("div", { "class": "at kr", text: (part ? part.label : at[1]) + " · " + first(comp[at[0]].label) }), h("div", { "class": "io", text: tf["in"].type + " → " + tf.out.type }),
|
|
1185
|
+
tf.map && tf.map.length ? h("ul", { "class": "map" }, tf.map.map(function (m) { return h("li", { text: m.from + " → " + m.to + (m.how ? " (" + m.how + ")" : "") }); })) : null);
|
|
1186
|
+
})));
|
|
1187
|
+
}
|
|
1188
|
+
(st.payload || []).forEach(function (p) {
|
|
1189
|
+
put(el, sec((p.leg === "request" ? W.sent : W.received) + (p.title ? " · " + p.title : ""),
|
|
1190
|
+
p.body ? h("pre", { "class": "code", text: p.body }) : null,
|
|
1191
|
+
p.bind ? h("dl", { "class": "kv" }, p.bind.map(function (b) { return [h("dt", { text: b.name }), h("dd", { text: b.value })]; })) : null,
|
|
1192
|
+
p.columns ? h("dl", { "class": "kv" }, p.columns.map(function (b) { return [h("dt", { text: b.name }), h("dd", { text: b.value })]; })) : null));
|
|
1193
|
+
});
|
|
1194
|
+
put(el, sec(W.evidence, h("ul", { "class": "ev" }, st.evidence.map(function (e) {
|
|
1195
|
+
var ref = evRef(e), on = !!(c && hit[ref]);
|
|
1196
|
+
return h("li", { "class": on ? "hit" : null }, h("span", { text: ref }), on ? h("span", { "class": "badge", "data-tone": ST[c.change][0] }, W.changed) : null);
|
|
1197
|
+
}))));
|
|
1198
|
+
}
|
|
1199
|
+
function itemInsp(el) { // a part / table / endpoint picked inside a component: only what its card does not show
|
|
1200
|
+
var p = SC.pos[S.item], r = p.ref, c = comp[SC.focus], u = uc(), id = S.item;
|
|
1201
|
+
var kindKo = p.kind === "part" ? ROLE_KO[r.role] || r.role : p.kind === "table" ? W.table : W.endpoint;
|
|
1202
|
+
put(el, h("div", { "class": "ih" },
|
|
1203
|
+
h("button", { type: "button", "class": "link", style: "font-size:12px;margin-bottom:12px", on: { click: function () { S.item = null; paintStepState(); renderInsp(); } } }, A.step >= 0 ? W.backStep(A.step + 1) : W.backOverview),
|
|
1204
|
+
h("p", { "class": "eyebrow", text: W.insideOf(kindKo, first(c.label)) }),
|
|
1205
|
+
h("p", { "class": "lead kr", text: r.detail || W.noDetail })));
|
|
1206
|
+
var ch = S.overlay ? dchg[c.id + "|" + p.kind + "|" + (p.kind === "table" ? r.name : r.id)] : null;
|
|
1207
|
+
if (ch) put(el, sec(null, h("div", { "class": "note", "data-tone": ST[ch][0] }, icon("git"), h("span", { "class": "kr", text: ch === "added" ? W.newHere : W.changedHere }))));
|
|
1208
|
+
if (p.kind === "part") {
|
|
1209
|
+
var byId = {}; c.parts.forEach(function (x) { byId[x.id] = x; });
|
|
1210
|
+
var rel = function (w, dir) { var o = dir === "in" ? byId[w.from] : byId[w.to]; return h("li", null, h("span", { "class": "who kr", text: (dir === "in" ? "← " : "→ ") + (o ? o.label : dir === "in" ? w.from : w.to) }), h("span", { "class": "how mono", text: w.label })); };
|
|
1211
|
+
var ins = (c.wires || []).filter(function (w) { return w.to === r.id; }), outs = (c.wires || []).filter(function (w) { return w.from === r.id; });
|
|
1212
|
+
if (ins.length) put(el, sec(W.calledBy, h("ul", { "class": "rel" }, ins.map(function (w) { return rel(w, "in"); }))));
|
|
1213
|
+
if (outs.length) put(el, sec(W.calls, h("ul", { "class": "rel" }, outs.map(function (w) { return rel(w, "out"); }))));
|
|
1214
|
+
}
|
|
1215
|
+
if (p.kind === "endpoint" && r.auth) put(el, sec(W.auth, h("p", { "class": "kr", text: r.auth })));
|
|
1216
|
+
var hits = u.steps.map(function (st, i) { return { st: st, i: i }; }).filter(function (x) { return p.kind === "part" ? traceIn(x.st, c.id).indexOf(id) >= 0 : targetsIn(x.st, c).indexOf(id) >= 0; });
|
|
1217
|
+
if (hits.length) put(el, sec(W.stepsHere, h("div", { style: "display:flex;flex-wrap:wrap;gap:6px" }, hits.map(function (x) {
|
|
1218
|
+
return h("button", { type: "button", "class": "steplink", title: x.st.label, on: { click: function () { A.playing = false; go(x.i, true); } } }, W.stepN(x.i + 1));
|
|
1219
|
+
}))));
|
|
1220
|
+
put(el, sec(W.evidence, h("ul", { "class": "ev" }, (r.evidence || []).map(function (e) { return h("li", null, h("span", { text: evRef(e) })); }))));
|
|
1221
|
+
}
|
|
1222
|
+
function legend() {
|
|
1223
|
+
function sw(draw) { var g = s("svg", { width: 28, height: 16, viewBox: "0 0 28 16", "aria-hidden": "true" }); draw(g); return g; }
|
|
1224
|
+
function dotLine(color, cx) { return function (g) { g.appendChild(s("line", { x1: 2, y1: 8, x2: 26, y2: 8, style: "stroke:" + color, "stroke-width": 2.5, "stroke-dasharray": "1 5", "stroke-linecap": "round" })); g.appendChild(s("circle", { cx: cx, cy: 8, r: 5, style: "fill:" + color + ";stroke:var(--surface)", "stroke-width": 2 })); }; }
|
|
1225
|
+
var rows = [
|
|
1226
|
+
[dotLine("var(--req)", 18), W.lgReq],
|
|
1227
|
+
[dotLine("var(--res)", 10), W.lgRes],
|
|
1228
|
+
[function (g) { g.appendChild(s("rect", { x: 3, y: 6, width: 22, height: 4, rx: 2, style: "fill:var(--int-soft)" })); g.appendChild(s("rect", { x: 3, y: 6, width: 13, height: 4, rx: 2, style: "fill:var(--int)" })); }, W.lgWork],
|
|
1229
|
+
[function (g) { g.appendChild(s("line", { x1: 2, y1: 8, x2: 26, y2: 8, style: "stroke:var(--trail-grey)", "stroke-width": 2 })); }, W.lgPast]
|
|
1230
|
+
];
|
|
1231
|
+
if (changes) rows.push([function (g) { g.appendChild(s("rect", { x: 4, y: 3, width: 20, height: 10, rx: 3, style: "fill:var(--success-bg);stroke:var(--success-border)" })); }, W.lgChanged]);
|
|
1232
|
+
if (model.components.some(hasDetail)) {
|
|
1233
|
+
rows.push([function (g) { g.appendChild(s("path", { d: P.expand, transform: "translate(6,0) scale(.66)", style: "fill:none;stroke:var(--text-3)", "stroke-width": 2.2, "stroke-linecap": "round" })); }, W.lgOpen]);
|
|
1234
|
+
rows.push([dotLine("var(--int)", 14), W.lgInt]);
|
|
1235
|
+
}
|
|
1236
|
+
return h("div", { "class": "legend" }, rows.map(function (r) { return [sw(r[0]), h("span", { text: r[1] })]; }));
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
/* ═════════════════ Top bar, URL, wiring ═════════════════ */
|
|
1240
|
+
function renderTop() {
|
|
1241
|
+
$("sv-product").textContent = model.product.name;
|
|
1242
|
+
var g = changes && changes.generated, ref = $("sv-ref");
|
|
1243
|
+
ref.hidden = !g; ref.textContent = g && g.base && g.head ? g.base.slice(0, 7) + " → " + g.head.slice(0, 7) : "";
|
|
1244
|
+
$("sv-commit").textContent = changes ? changes.title : model.product.description;
|
|
1245
|
+
var t = $("sv-overlay"); t.hidden = !changes; t.setAttribute("aria-checked", S.overlay ? "true" : "false");
|
|
1246
|
+
if (doc.title !== undefined) doc.title = model.product.name + " · Nacholens";
|
|
1247
|
+
}
|
|
1248
|
+
function syncHash() {
|
|
1249
|
+
if (TARGET !== "html" || typeof history === "undefined" || !history.replaceState) return;
|
|
1250
|
+
var extra = H0.dock ? "&dock=" + encodeURIComponent(H0.dock) : "";
|
|
1251
|
+
try { history.replaceState(null, "", "#uc=" + S.uc + "&step=" + (A.step + 1) + (SC.mode === "detail" ? "&focus=" + SC.focus : "") + extra); } catch (e) { /* sandboxed */ }
|
|
1252
|
+
}
|
|
1253
|
+
function relayout() {
|
|
1254
|
+
var keep = { leg: A.leg, t: A.t, running: A.running };
|
|
1255
|
+
stopClock(); clearMotion(); drawStage(); paintStepState();
|
|
1256
|
+
if (A.step >= 0 && !A.finished) {
|
|
1257
|
+
A.legs = legsOf(uc().steps[A.step]);
|
|
1258
|
+
if (A.legs.length) { startLeg(Math.min(keep.leg, A.legs.length - 1), keep.t); if (!keep.running) stopClock(); }
|
|
1259
|
+
} else progress();
|
|
1260
|
+
}
|
|
1261
|
+
$("sv-q").addEventListener("input", function (e) { S.filter = e.target.value || ""; renderSide(); });
|
|
1262
|
+
$("sv-overlay").addEventListener("click", function () { setOverlay(!S.overlay); });
|
|
1263
|
+
doc.addEventListener("keydown", function (e) {
|
|
1264
|
+
if (e.key === "Escape") { closeDetail(); return; }
|
|
1265
|
+
var a = doc.activeElement; if (a && a !== doc.body && a.tagName !== "svg") return; // keys belong to the focused control
|
|
1266
|
+
if (e.key === " ") { e.preventDefault(); play(); } else if (e.key === "ArrowRight") next(); else if (e.key === "ArrowLeft") prev();
|
|
1267
|
+
});
|
|
1268
|
+
// tag boxes are sized from the rendered text: draw again once the embedded fonts are ready
|
|
1269
|
+
if (typeof document !== "undefined" && document.fonts && document.fonts.ready && document.fonts.status !== "loaded") document.fonts.ready.then(function () { relayout(); });
|
|
1270
|
+
if (typeof ResizeObserver === "function") {
|
|
1271
|
+
var rz = 0, lastW = 0, lastH = 0;
|
|
1272
|
+
new ResizeObserver(function () {
|
|
1273
|
+
var st = $("sv-stage"); if (st.clientWidth === lastW && st.clientHeight === lastH) return;
|
|
1274
|
+
lastW = st.clientWidth; lastH = st.clientHeight; clearTimeout(rz); rz = setTimeout(relayout, 60);
|
|
1275
|
+
}).observe($("sv-stage"));
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/* ═════════════════ start ═════════════════ */
|
|
1279
|
+
if (H0.focus && hasDetail(comp[H0.focus])) { SC.mode = "detail"; SC.focus = H0.focus; }
|
|
1280
|
+
renderTop(); drawStage();
|
|
1281
|
+
go(H0.step ? Number(H0.step) - 1 : -1, false);
|
|
1282
|
+
if (H0.at != null && A.step >= 0) { // capture aid: #…&at=0.4 freezes the step at that point of its motion
|
|
1283
|
+
A.finished = false; A.legs = legsOf(uc().steps[A.step]);
|
|
1284
|
+
if (A.legs.length) { var f = Math.max(0, Math.min(0.999, Number(H0.at))) * A.legs.length, li = Math.floor(f); startLeg(li, f - li); stopClock(); A.t = f - li; frameDraw(); paintStepState(); caption(); transport(); progress(); }
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
window.__nacholens = {
|
|
1288
|
+
model: model, changes: changes, target: TARGET, hash: H0,
|
|
1289
|
+
get state() { return { uc: S.uc, step: A.step, finished: A.finished, playing: A.playing, running: A.running, leg: A.leg, t: A.t, mode: SC.mode, focus: SC.focus, item: S.item, overlay: S.overlay, rate: A.rate }; },
|
|
1290
|
+
scene: function () { var b = {}; Object.keys(SC.pos).forEach(function (id) { var p = SC.pos[id]; b[id] = { x: p.x, y: p.y, w: p.w, h: p.h, kind: p.kind }; }); return { mode: SC.mode, focus: SC.focus, w: G.W, h: G.H, boxes: b, hidden: SC.hidden }; },
|
|
1291
|
+
legs: function (i) { return legsOf(uc().steps[i]).map(function (l) { return l.type === "move" ? { type: l.type, ids: l.ids.slice(), tone: l.tone, text: l.text } : { type: l.type, at: l.at }; }); },
|
|
1292
|
+
packet: function () { return MOVE && MOVE.pts ? { x: MOVE.x, y: MOVE.y, tone: MOVE.tone } : null; },
|
|
1293
|
+
tagged: function () { return Object.keys(NODE).filter(function (id) { return NODE[id].getAttribute("class").indexOf("chg-") >= 0; }).sort(); },
|
|
1294
|
+
selectUseCase: selectUc, go: go, play: play, pause: pause, next: next, prev: prev,
|
|
1295
|
+
openDetail: openDetail, closeDetail: closeDetail, switchFocus: switchFocus, selectItem: selectItem,
|
|
1296
|
+
setOverlay: setOverlay, relayout: relayout
|
|
1297
|
+
};
|
|
1298
|
+
})();
|
|
1299
|
+
|
|
1300
|
+
</script>
|
|
1301
|
+
<script>
|
|
1302
|
+
/* Review dock: the three review tracks under the stage — planner intent (planner), regression tests (QA) and changes the
|
|
1303
|
+
model does not cover (dev). Each tab carries its own status (a dot and the count still to check), so the tab bar is
|
|
1304
|
+
the to-do summary of the page. Rows link to steps through the player API and never repeat a step's details.
|
|
1305
|
+
Ticks are a per-viewer convenience (browser storage, may be unavailable). Text nodes only. */
|
|
1306
|
+
(function () {
|
|
1307
|
+
"use strict";
|
|
1308
|
+
var doc = document, root = doc.getElementById("sv-review");
|
|
1309
|
+
if (!root) return;
|
|
1310
|
+
var api = window.__nacholens || null;
|
|
1311
|
+
function json(id) { var e = doc.getElementById(id); try { return e ? JSON.parse(e.textContent) : null; } catch (x) { return null; } }
|
|
1312
|
+
var model = api ? api.model : json("sv-model"), changes = api ? api.changes : json("sv-changes"), data = json("sv-review-data") || {};
|
|
1313
|
+
if (!changes && !data.intent && !data.impact) return; // nothing to review: the dock stays hidden
|
|
1314
|
+
|
|
1315
|
+
/* ── helpers ── */
|
|
1316
|
+
function h(tag, a) {
|
|
1317
|
+
var e = doc.createElement(tag);
|
|
1318
|
+
if (a) Object.keys(a).forEach(function (k) {
|
|
1319
|
+
var v = a[k]; if (v == null || v === false) return;
|
|
1320
|
+
if (k === "on") Object.keys(v).forEach(function (x) { e.addEventListener(x, v[x]); });
|
|
1321
|
+
else if (k === "text") e.textContent = v;
|
|
1322
|
+
else e.setAttribute(k, v === true ? "" : v);
|
|
1323
|
+
});
|
|
1324
|
+
for (var i = 2; i < arguments.length; i++) put(e, arguments[i]);
|
|
1325
|
+
return e;
|
|
1326
|
+
}
|
|
1327
|
+
function put(e, c) { if (c == null || c === false) return; if (Array.isArray(c)) { c.forEach(function (x) { put(e, x); }); return; } e.appendChild(typeof c === "object" ? c : doc.createTextNode(String(c))); }
|
|
1328
|
+
function clear(e) { while (e.firstChild) e.removeChild(e.firstChild); }
|
|
1329
|
+
var NS = "http://www.w3.org/2000/svg";
|
|
1330
|
+
function icon(d) { var e = doc.createElementNS(NS, "svg"); e.setAttribute("class", "i"); e.setAttribute("viewBox", "0 0 24 24"); e.setAttribute("aria-hidden", "true"); var p = doc.createElementNS(NS, "path"); p.setAttribute("d", d); e.appendChild(p); return e; }
|
|
1331
|
+
var CHECK = "M5 12.5l4.5 4.5L19 7.5", CHEV = "m6 9 6 6 6-6";
|
|
1332
|
+
/* words: English by default, Korean when the page is built with --lang ko (html lang=ko) */
|
|
1333
|
+
var KO = String((doc.documentElement && doc.documentElement.getAttribute && doc.documentElement.getAttribute("lang")) || "en").toLowerCase().indexOf("ko") === 0;
|
|
1334
|
+
var L = KO ? {
|
|
1335
|
+
tone: { met: "충족", unmet: "미충족", unknown: "확인 불가", direct: "직접 영향", indirect: "간접 영향", "covered-changed": "테스트 있음 · 함께 바뀜", covered: "테스트 있음", "none-found": "테스트 못 찾음", tests: "테스트 미확인", added: "신규", modified: "변경", deleted: "삭제", removed: "삭제" },
|
|
1336
|
+
ignore: { test: "테스트", docs: "문서", lockfile: "잠금 파일", asset: "정적 자산" },
|
|
1337
|
+
step: function (n) { return n + "단계"; },
|
|
1338
|
+
tIntent: "기획 의도", rIntent: "기획", tImpact: "회귀 테스트", rImpact: "QA", tUnmapped: "모델 밖 변경", rUnmapped: "개발",
|
|
1339
|
+
noIntent: "intent.json 을 주면 기획 기대사항을 이 모델과 대조합니다 (build --intent).", qIntent: "기획대로 동작하나요?",
|
|
1340
|
+
sumIntent: function (m) { return "충족 " + m.met + " · 미충족 " + m.unmet + " · 확인 불가 " + m.unknown; },
|
|
1341
|
+
showMet: function (n, open) { return "충족 " + n + "건 " + (open ? "접기" : "보기"); },
|
|
1342
|
+
uncovered: function (n) { return "기획에 연결되지 않은 변경 " + n + "건 — 범위 이탈인지 판단"; }, scopeOk: "범위 확인함", checked: "확인함",
|
|
1343
|
+
unprovable: "모델로 증명할 수 없음 — 사람이 직접 확인", touched: "이번 변경이 건드림",
|
|
1344
|
+
noImpact: "저장소와 기준 커밋을 주면 다시 테스트할 흐름을 계산합니다 (build --repo --base).", qImpact: "무엇을 다시 테스트하나요?",
|
|
1345
|
+
sumImpact: function (m) { return "직접 " + m.direct + " · 간접 " + m.indirect + " · 테스트 못 찾음 " + m.withoutTests + (m.testsKnown ? " — 테스트 파일이 경로를 언급하는지로만 찾습니다" : " — 테스트는 저장소를 읽지 않아 확인하지 않았습니다"); },
|
|
1346
|
+
tested: "테스트함", why: { table: "테이블 ", endpoint: "외부 호출 ", part: "부품 ", wire: "배선 " },
|
|
1347
|
+
changedSteps: function (n) { return "바뀐 단계 " + n; }, testFiles: function (n) { return "테스트 " + n + "개"; }, testFilesLabel: "테스트 파일", kindLabel: "종류",
|
|
1348
|
+
cats: function (code, other, ign) { return [["code", "코드 " + code], ["other", "설정·스타일 " + other], ["ignored", "무시 " + ign]]; },
|
|
1349
|
+
qUnmapped: "흐름에 안 잡힌 변경이 있나요?", subUnmapped: "어떤 단계의 근거에도 없는 변경 — 단계를 추가하거나 무관한 변경인지 확인",
|
|
1350
|
+
noIgnored: "무시한 파일이 없습니다", allMapped: "모든 코드 변경이 흐름의 단계에 잡혔습니다", noOther: "바뀐 설정·스타일 파일이 없습니다",
|
|
1351
|
+
nFiles: function (n) { return n + "개"; }, fileList: "파일 목록", grip: "검토 패널 높이", dock: "검토", none: "없음", left: function (n) { return n + "건 남음"; }, allDone: "모두 확인함",
|
|
1352
|
+
expand: "검토 패널 펼치기", fold: "검토 패널 접기"
|
|
1353
|
+
} : {
|
|
1354
|
+
tone: { met: "Met", unmet: "Not met", unknown: "Can't tell", direct: "Direct", indirect: "Indirect", "covered-changed": "Tested · changed too", covered: "Tested", "none-found": "No test found", tests: "Tests not checked", added: "New", modified: "Changed", deleted: "Deleted", removed: "Removed" },
|
|
1355
|
+
ignore: { test: "Test", docs: "Docs", lockfile: "Lockfile", asset: "Asset" },
|
|
1356
|
+
step: function (n) { return "step " + n; },
|
|
1357
|
+
tIntent: "Plan", rIntent: "Planner", tImpact: "Retest", rImpact: "QA", tUnmapped: "Outside the model", rUnmapped: "Dev",
|
|
1358
|
+
noIntent: "Pass intent.json to check the planner's expectations against this model (build --intent).", qIntent: "Does it work as planned?",
|
|
1359
|
+
sumIntent: function (m) { return "Met " + m.met + " · Not met " + m.unmet + " · Can't tell " + m.unknown; },
|
|
1360
|
+
showMet: function (n, open) { return (open ? "Hide " : "Show ") + n + " met"; },
|
|
1361
|
+
uncovered: function (n) { return n + (n === 1 ? " change is" : " changes are") + " not linked to the plan: is it out of scope?"; }, scopeOk: "Scope checked", checked: "Checked",
|
|
1362
|
+
unprovable: "The model cannot prove this: a person has to check", touched: "Touched by this change",
|
|
1363
|
+
noImpact: "Pass the repository and a base commit to find the flows to retest (build --repo --base).", qImpact: "What should be retested?",
|
|
1364
|
+
sumImpact: function (m) { return "Direct " + m.direct + " · Indirect " + m.indirect + " · No test found " + m.withoutTests + (m.testsKnown ? ": tests are found only by the paths they mention" : ": tests were not checked because the repository was not read"); },
|
|
1365
|
+
tested: "Tested", why: { table: "table ", endpoint: "call ", part: "part ", wire: "wire " },
|
|
1366
|
+
changedSteps: function (n) { return n + (n === 1 ? " changed step" : " changed steps"); }, testFiles: function (n) { return n + (n === 1 ? " test" : " tests"); }, testFilesLabel: "Test files", kindLabel: "Kind",
|
|
1367
|
+
cats: function (code, other, ign) { return [["code", "Code " + code], ["other", "Config & style " + other], ["ignored", "Ignored " + ign]]; },
|
|
1368
|
+
qUnmapped: "Did any change miss the flows?", subUnmapped: "Changes that are not in any step's evidence: add a step, or confirm they are unrelated",
|
|
1369
|
+
noIgnored: "No ignored files", allMapped: "Every code change is in a step of a flow", noOther: "No config or style files changed",
|
|
1370
|
+
nFiles: function (n) { return n + (n === 1 ? " file" : " files"); }, fileList: "File list", grip: "Review panel height", dock: "Review", none: "None", left: function (n) { return n + " to check"; }, allDone: "All checked",
|
|
1371
|
+
expand: "Expand the review panel", fold: "Collapse the review panel"
|
|
1372
|
+
};
|
|
1373
|
+
var TONE = { met: "success", unmet: "danger", unknown: "neutral", direct: "warning", indirect: "info", "covered-changed": "success", covered: "success", "none-found": "danger", tests: "neutral", added: "success", modified: "warning", deleted: "danger", removed: "danger" };
|
|
1374
|
+
function badge(k) { return h("span", { "class": "badge", "data-tone": TONE[k] || "neutral" }, L.tone[k] || k); }
|
|
1375
|
+
var ucs = {}; model.useCases.forEach(function (u) { ucs[u.id] = u; });
|
|
1376
|
+
function ucTitle(id) { return ucs[id] ? ucs[id].title : id; }
|
|
1377
|
+
function jump(ucId, stepId) {
|
|
1378
|
+
if (!api) return;
|
|
1379
|
+
var u = ucs[ucId], i = -1; if (u && stepId) u.steps.forEach(function (st, k) { if (st.id === stepId) i = k; });
|
|
1380
|
+
api.selectUseCase(ucId, i >= 0 ? i : null);
|
|
1381
|
+
}
|
|
1382
|
+
function stepLinks(list) {
|
|
1383
|
+
return list.map(function (p) {
|
|
1384
|
+
var u = ucs[p.useCase], i = -1; if (u) u.steps.forEach(function (st, k) { if (st.id === p.step) i = k; });
|
|
1385
|
+
var t = ucTitle(p.useCase);
|
|
1386
|
+
return h("button", { type: "button", "class": "steplink", title: p.label || "", on: { click: function () { jump(p.useCase, p.step); } } }, (t.length > 12 ? t.slice(0, 12) + "…" : t) + " " + L.step(i + 1));
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/* ── ticks (per viewer) ── */
|
|
1391
|
+
var KEY = "sv-review:" + ((changes && changes.ref) || model.product.id), done = {};
|
|
1392
|
+
try { done = JSON.parse(localStorage.getItem(KEY) || "{}") || {}; } catch (e) { done = {}; }
|
|
1393
|
+
function tick(id, on) { if (on) done[id] = 1; else delete done[id]; try { localStorage.setItem(KEY, JSON.stringify(done)); } catch (e) { /* storage blocked: ticks last for this visit */ } paint(); }
|
|
1394
|
+
function checkbox(id, label) {
|
|
1395
|
+
var on = !!done[id];
|
|
1396
|
+
return h("button", { type: "button", "class": "check", role: "checkbox", "aria-checked": on ? "true" : "false", "aria-label": label, on: { click: function (e) { e.stopPropagation(); tick(id, !on); } } }, icon(CHECK));
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/* ── tracks: what each tab still asks a person to check ── */
|
|
1400
|
+
var unmapped = (changes && changes.unmapped) || [];
|
|
1401
|
+
function folders(code) {
|
|
1402
|
+
var m = {}, order = [];
|
|
1403
|
+
unmapped.filter(function (f) { return code ? f.category === "code" : f.category !== "code"; }).forEach(function (f) {
|
|
1404
|
+
var p = f.file.split("/"), dir = p.slice(0, Math.min(p.length - 1, 3)).join("/") || ".";
|
|
1405
|
+
if (!m[dir]) { m[dir] = []; order.push(dir); } m[dir].push(f);
|
|
1406
|
+
});
|
|
1407
|
+
return order.map(function (d) { return { dir: d, files: m[d] }; }).sort(function (a, b) { return b.files.length - a.files.length || (a.dir < b.dir ? -1 : 1); });
|
|
1408
|
+
}
|
|
1409
|
+
function uncoveredByUc() { var m = {}, order = []; ((data.intent && data.intent.uncovered) || []).forEach(function (x) { if (!m[x.useCase]) { m[x.useCase] = []; order.push(x.useCase); } m[x.useCase].push(x); }); return order.map(function (id) { return { id: id, items: m[id] }; }); }
|
|
1410
|
+
function tracks() {
|
|
1411
|
+
return [
|
|
1412
|
+
{ id: "intent", label: L.tIntent, role: L.rIntent, avail: !!data.intent,
|
|
1413
|
+
items: data.intent ? data.intent.results.filter(function (r) { return r.status !== "met"; }).map(function (r) { return "it:" + r.id; }).concat(uncoveredByUc().map(function (g) { return "sc:" + g.id; })) : [],
|
|
1414
|
+
danger: !!(data.intent && data.intent.summary.unmet) },
|
|
1415
|
+
{ id: "impact", label: L.tImpact, role: L.rImpact, avail: !!data.impact,
|
|
1416
|
+
items: data.impact ? data.impact.useCases.map(function (u) { return "rt:" + u.id; }) : [],
|
|
1417
|
+
danger: !!(data.impact && data.impact.summary.withoutTests) },
|
|
1418
|
+
{ id: "unmapped", label: L.tUnmapped, role: L.rUnmapped, avail: !!changes,
|
|
1419
|
+
items: folders(true).map(function (g) { return "dir:" + g.dir; }), danger: false }
|
|
1420
|
+
];
|
|
1421
|
+
}
|
|
1422
|
+
function left(t) { return t.items.filter(function (id) { return !done[id]; }).length; }
|
|
1423
|
+
|
|
1424
|
+
/* ── state ── */
|
|
1425
|
+
var hashTab = api && api.hash ? api.hash.dock : null, T0 = tracks();
|
|
1426
|
+
var avail = T0.filter(function (t) { return t.avail; });
|
|
1427
|
+
var S = { tab: (T0.filter(function (t) { return t.id === hashTab && t.avail; })[0] || avail.filter(function (t) { return left(t); })[0] || avail[0]).id, collapsed: false, showMet: false, open: {}, ucat: "code" };
|
|
1428
|
+
|
|
1429
|
+
/* ── tab bodies ── */
|
|
1430
|
+
function head(q, sub, extra) { return h("div", { "class": "dhead" }, h("span", { "class": "q kr", text: q }), sub ? h("span", { "class": "sub kr", text: sub }) : null, h("span", { "class": "grow" }), extra || null); }
|
|
1431
|
+
function bodyIntent(b) {
|
|
1432
|
+
var I = data.intent;
|
|
1433
|
+
if (!I) { put(b, h("div", { "class": "empty kr", text: L.noIntent })); return; }
|
|
1434
|
+
var sm = I.summary;
|
|
1435
|
+
put(b, head(L.qIntent, L.sumIntent(sm) + (I.title ? " — " + I.title : "")));
|
|
1436
|
+
var todo = I.results.filter(function (r) { return r.status !== "met"; }), met = I.results.filter(function (r) { return r.status === "met"; });
|
|
1437
|
+
if (todo.length) put(b, h("ul", { "class": "rowlist" }, todo.map(function (r) { return intentRow(r, true); })));
|
|
1438
|
+
if (met.length) {
|
|
1439
|
+
put(b, h("div", { "class": "subhead" }, h("button", { type: "button", "class": "link", on: { click: function () { S.showMet = !S.showMet; paint(); } } }, L.showMet(met.length, S.showMet))));
|
|
1440
|
+
if (S.showMet) put(b, h("ul", { "class": "rowlist" }, met.map(function (r) { return intentRow(r, false); })));
|
|
1441
|
+
}
|
|
1442
|
+
var groups = uncoveredByUc();
|
|
1443
|
+
if (groups.length) {
|
|
1444
|
+
put(b, h("div", { "class": "subhead kr", text: L.uncovered(I.uncovered.length) }));
|
|
1445
|
+
put(b, h("ul", { "class": "rowlist" }, groups.map(function (g) {
|
|
1446
|
+
var key = "sc:" + g.id;
|
|
1447
|
+
return h("li", { "class": "ri" + (done[key] ? " done" : "") }, checkbox(key, L.scopeOk), h("div", { "class": "main" }, h("div", { "class": "t kr", text: ucTitle(g.id) }), h("div", { "class": "m" }, stepLinks(g.items))));
|
|
1448
|
+
})));
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
function intentRow(r, todo) {
|
|
1452
|
+
var key = "it:" + r.id;
|
|
1453
|
+
return h("li", { "class": "ri" + (todo && done[key] ? " done" : "") },
|
|
1454
|
+
todo ? checkbox(key, L.checked) : h("span", { "class": "gap" }),
|
|
1455
|
+
h("div", { "class": "main" }, h("div", { "class": "t kr", text: r.text }),
|
|
1456
|
+
h("div", { "class": "m" }, r.status === "unknown" ? h("span", { "class": "kr", text: L.unprovable }) : r.status === "unmet" ? h("span", { "class": "kr", text: r.reason }) : null,
|
|
1457
|
+
r.useCase && !(r.proof || []).length ? h("span", { "class": "kr", text: ucTitle(r.useCase) }) : null, stepLinks(r.proof || []))),
|
|
1458
|
+
h("span", { "class": "end" }, r.touched ? h("span", { "class": "badge", "data-tone": "info" }, L.touched) : null, badge(r.status)));
|
|
1459
|
+
}
|
|
1460
|
+
function bodyImpact(b) {
|
|
1461
|
+
var M = data.impact;
|
|
1462
|
+
if (!M) { put(b, h("div", { "class": "empty kr", text: L.noImpact })); return; }
|
|
1463
|
+
var sm = M.summary;
|
|
1464
|
+
put(b, head(L.qImpact, L.sumImpact(sm)));
|
|
1465
|
+
put(b, h("ul", { "class": "rowlist" }, M.useCases.map(function (u) {
|
|
1466
|
+
var key = "rt:" + u.id, open = !!S.open[key], files = (u.tests && u.tests.files) || [];
|
|
1467
|
+
return h("li", { "class": "ri" + (done[key] ? " done" : "") }, checkbox(key, L.tested),
|
|
1468
|
+
h("div", { "class": "main" },
|
|
1469
|
+
h("div", { "class": "t kr" }, h("button", { type: "button", "class": "link plain", on: { click: function () { jump(u.id); } } }, u.title)),
|
|
1470
|
+
h("div", { "class": "m" }, (u.reasons || []).map(function (r) { return h("span", { "class": "mono", text: (L.why[r.kind] || "") + r.ref }); }),
|
|
1471
|
+
(u.direct || []).length ? h("span", { text: L.changedSteps(u.direct.length) }) : null, files.length ? h("span", { text: L.testFiles(files.length) }) : null),
|
|
1472
|
+
open ? h("ul", { "class": "files" }, files.map(function (f) { return h("li", null, h("span", { text: f.file })); })) : null),
|
|
1473
|
+
h("span", { "class": "end" }, badge(u.relation), badge(u.tests && u.tests.state !== "unknown" ? u.tests.state : "tests"),
|
|
1474
|
+
files.length ? h("button", { type: "button", "class": "chev", "aria-expanded": open ? "true" : "false", "aria-label": L.testFilesLabel, on: { click: function () { S.open[key] = !open; paint(); } } }, icon(CHEV)) : null));
|
|
1475
|
+
})));
|
|
1476
|
+
}
|
|
1477
|
+
function bodyUnmapped(b) {
|
|
1478
|
+
var code = unmapped.filter(function (f) { return f.category === "code"; }).length, ign = (changes && changes.ignored) || [];
|
|
1479
|
+
var seg = h("div", { "class": "seg", role: "group", "aria-label": L.kindLabel });
|
|
1480
|
+
L.cats(code, unmapped.length - code, ign.length).forEach(function (x) {
|
|
1481
|
+
put(seg, h("button", { type: "button", "aria-pressed": S.ucat === x[0] ? "true" : "false", on: { click: function () { S.ucat = x[0]; paint(); } } }, x[1]));
|
|
1482
|
+
});
|
|
1483
|
+
put(b, head(L.qUnmapped, L.subUnmapped, seg));
|
|
1484
|
+
if (S.ucat === "ignored") {
|
|
1485
|
+
put(b, ign.length ? h("ul", { "class": "rowlist" }, ign.map(function (f) { return h("li", { "class": "ri" }, h("span", { "class": "gap" }), h("div", { "class": "main mono small", text: f.file }), h("span", { "class": "end" }, h("span", { "class": "badge", text: L.ignore[f.reason] || f.reason }))); }))
|
|
1486
|
+
: h("div", { "class": "empty", text: L.noIgnored }));
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
var gs = folders(S.ucat === "code");
|
|
1490
|
+
if (!gs.length) { put(b, h("div", { "class": "empty kr", text: S.ucat === "code" ? L.allMapped : L.noOther })); return; }
|
|
1491
|
+
put(b, h("ul", { "class": "rowlist" }, gs.map(function (g) {
|
|
1492
|
+
var key = "dir:" + g.dir, open = !!S.open[key];
|
|
1493
|
+
return h("li", { "class": "ri" + (done[key] ? " done" : "") }, checkbox(key, L.checked),
|
|
1494
|
+
h("div", { "class": "main" }, h("div", { "class": "t mono", text: g.dir + "/" }),
|
|
1495
|
+
open ? h("ul", { "class": "files" }, g.files.map(function (f) { return h("li", null, h("span", { text: f.file.slice(g.dir.length + 1) }), h("span", { "class": "ln", text: f.lines }), h("span", { "class": "st", text: (WORD[f.status] || ["", f.status])[1] })); }))
|
|
1496
|
+
: h("div", { "class": "m mono ell", text: g.files.map(function (f) { return f.file.slice(g.dir.length + 1); }).join(" · ") })),
|
|
1497
|
+
h("span", { "class": "end" }, h("span", { "class": "badge", text: L.nFiles(g.files.length) }), h("button", { type: "button", "class": "chev", "aria-expanded": open ? "true" : "false", "aria-label": L.fileList, on: { click: function () { S.open[key] = !open; paint(); } } }, icon(CHEV))));
|
|
1498
|
+
})));
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
/* ── frame ── */
|
|
1502
|
+
var grip = h("div", { "class": "grip", role: "separator", "aria-orientation": "horizontal", "aria-label": L.grip });
|
|
1503
|
+
var bar = h("div", { "class": "dtabs", role: "tablist", "aria-label": L.dock }), body = h("div", { "class": "dbody", role: "tabpanel", id: "sv-review-body" });
|
|
1504
|
+
function paint() {
|
|
1505
|
+
clear(bar); clear(body);
|
|
1506
|
+
tracks().forEach(function (t) {
|
|
1507
|
+
var n = left(t), tone = !t.avail ? "neutral" : n === 0 ? "success" : t.danger ? "danger" : "warning";
|
|
1508
|
+
put(bar, h("button", { type: "button", "class": "dtab", role: "tab", "data-tab": t.id, "aria-selected": S.tab === t.id && !S.collapsed ? "true" : "false", "aria-controls": "sv-review-body",
|
|
1509
|
+
on: { click: function () { if (S.tab === t.id) S.collapsed = !S.collapsed; else { S.tab = t.id; S.collapsed = false; } paint(); } } },
|
|
1510
|
+
h("span", { "class": "dot", "data-tone": tone }), t.label, h("span", { "class": "role", text: t.role }),
|
|
1511
|
+
!t.avail ? h("span", { "class": "left none", text: L.none }) : n ? h("span", { "class": "left", "data-tone": tone, text: L.left(n) }) : h("span", { "class": "ok", title: L.allDone }, icon(CHECK))));
|
|
1512
|
+
});
|
|
1513
|
+
put(bar, [h("span", { "class": "grow" }), h("button", { type: "button", "class": "btn icon ghost fold", "aria-label": S.collapsed ? L.expand : L.fold, "aria-expanded": S.collapsed ? "false" : "true", on: { click: function () { S.collapsed = !S.collapsed; paint(); } } }, icon(CHEV))]);
|
|
1514
|
+
if (root.classList) root.classList[S.collapsed ? "add" : "remove"]("collapsed");
|
|
1515
|
+
if (!S.collapsed) ({ intent: bodyIntent, impact: bodyImpact, unmapped: bodyUnmapped })[S.tab](body);
|
|
1516
|
+
}
|
|
1517
|
+
(function resizable() {
|
|
1518
|
+
var y0 = 0, h0 = 0, dragging = false;
|
|
1519
|
+
grip.addEventListener("pointerdown", function (e) { dragging = true; y0 = e.clientY; h0 = root.getBoundingClientRect().height; if (grip.setPointerCapture) grip.setPointerCapture(e.pointerId); });
|
|
1520
|
+
grip.addEventListener("pointermove", function (e) { if (!dragging) return; var v = Math.max(120, Math.min(window.innerHeight * 0.6, h0 - (e.clientY - y0))); doc.documentElement.style.setProperty("--dock-h", Math.round(v) + "px"); });
|
|
1521
|
+
grip.addEventListener("pointerup", function () { dragging = false; });
|
|
1522
|
+
})();
|
|
1523
|
+
put(root, [grip, bar, body]);
|
|
1524
|
+
root.removeAttribute("hidden");
|
|
1525
|
+
paint();
|
|
1526
|
+
window.__nacholensReview = {
|
|
1527
|
+
get state() { return { tab: S.tab, collapsed: S.collapsed, ucat: S.ucat }; },
|
|
1528
|
+
tracks: function () { return tracks().map(function (t) { return { id: t.id, avail: t.avail, left: left(t), total: t.items.length }; }); },
|
|
1529
|
+
open: function (tab) { S.tab = tab; S.collapsed = false; paint(); }
|
|
1530
|
+
};
|
|
1531
|
+
})();
|
|
1532
|
+
|
|
1533
|
+
</script>
|
|
1534
|
+
</body>
|
|
1535
|
+
</html>
|