@unofficialbox/box-open-elements 0.5.0 → 0.7.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.
Files changed (227) hide show
  1. package/README.md +27 -73
  2. package/dist/components/collections/table.d.ts +113 -3
  3. package/dist/components/collections/table.js +540 -37
  4. package/dist/components/feedback/due-badge.d.ts +38 -0
  5. package/dist/components/feedback/due-badge.js +168 -0
  6. package/dist/components/feedback/due-types.d.ts +32 -0
  7. package/dist/components/feedback/due-types.js +91 -0
  8. package/dist/components/feedback/progress-steps.d.ts +51 -5
  9. package/dist/components/feedback/progress-steps.js +200 -22
  10. package/dist/components/feedback/stage-path.d.ts +44 -0
  11. package/dist/components/feedback/stage-path.js +235 -0
  12. package/dist/components/forms/select.d.ts +21 -0
  13. package/dist/components/forms/select.js +100 -3
  14. package/dist/components/forms/text-field.d.ts +21 -0
  15. package/dist/components/forms/text-field.js +100 -1
  16. package/dist/components/layout/nav-sidebar.d.ts +14 -0
  17. package/dist/components/layout/nav-sidebar.js +49 -0
  18. package/dist/components/layout/split-view.d.ts +14 -0
  19. package/dist/components/layout/split-view.js +80 -1
  20. package/dist/components/overlays/command-palette.d.ts +62 -0
  21. package/dist/components/overlays/command-palette.js +537 -0
  22. package/dist/components/overlays/command-types.d.ts +90 -0
  23. package/dist/components/overlays/command-types.js +259 -0
  24. package/dist/components/overlays/drawer.d.ts +18 -0
  25. package/dist/components/overlays/drawer.js +135 -9
  26. package/dist/components/overlays/shortcuts-overlay.d.ts +48 -0
  27. package/dist/components/overlays/shortcuts-overlay.js +385 -0
  28. package/dist/components/overlays/tooltip.js +1 -1
  29. package/dist/core/index.d.ts +4 -0
  30. package/dist/core/index.js +2 -0
  31. package/dist/core/offset-window.d.ts +70 -0
  32. package/dist/core/offset-window.js +134 -0
  33. package/dist/core/virtualize.d.ts +71 -0
  34. package/dist/core/virtualize.js +67 -0
  35. package/dist/element-maps.d.ts +292 -0
  36. package/dist/element-maps.js +1 -0
  37. package/dist/entries/activity-density.d.ts +1 -0
  38. package/dist/entries/activity-density.js +1 -0
  39. package/dist/entries/agent-chat.d.ts +1 -0
  40. package/dist/entries/agent-chat.js +1 -0
  41. package/dist/entries/audit-log.d.ts +1 -0
  42. package/dist/entries/audit-log.js +1 -0
  43. package/dist/entries/command-palette.d.ts +1 -0
  44. package/dist/entries/command-palette.js +1 -0
  45. package/dist/entries/compare-view.d.ts +1 -0
  46. package/dist/entries/compare-view.js +1 -0
  47. package/dist/entries/diff-viewer.d.ts +1 -0
  48. package/dist/entries/diff-viewer.js +1 -0
  49. package/dist/entries/due-badge.d.ts +1 -0
  50. package/dist/entries/due-badge.js +1 -0
  51. package/dist/entries/form-wizard.d.ts +1 -0
  52. package/dist/entries/form-wizard.js +1 -0
  53. package/dist/entries/lineage-graph.d.ts +1 -0
  54. package/dist/entries/lineage-graph.js +1 -0
  55. package/dist/entries/notification-bell.d.ts +1 -0
  56. package/dist/entries/notification-bell.js +1 -0
  57. package/dist/entries/notification-inbox.d.ts +1 -0
  58. package/dist/entries/notification-inbox.js +1 -0
  59. package/dist/entries/provenance-strip.d.ts +1 -0
  60. package/dist/entries/provenance-strip.js +1 -0
  61. package/dist/entries/run-trace.d.ts +1 -0
  62. package/dist/entries/run-trace.js +1 -0
  63. package/dist/entries/shortcuts-overlay.d.ts +1 -0
  64. package/dist/entries/shortcuts-overlay.js +1 -0
  65. package/dist/entries/signature-ceremony.d.ts +1 -0
  66. package/dist/entries/signature-ceremony.js +1 -0
  67. package/dist/entries/stage-path.d.ts +1 -0
  68. package/dist/entries/stage-path.js +1 -0
  69. package/dist/entries/timeline.d.ts +1 -0
  70. package/dist/entries/timeline.js +1 -0
  71. package/dist/entries/version-graph.d.ts +1 -0
  72. package/dist/entries/version-graph.js +1 -0
  73. package/dist/entries/version-list.d.ts +1 -0
  74. package/dist/entries/version-list.js +1 -0
  75. package/dist/entries/wizard-summary.d.ts +1 -0
  76. package/dist/entries/wizard-summary.js +1 -0
  77. package/dist/entries/work-queue.d.ts +1 -0
  78. package/dist/entries/work-queue.js +1 -0
  79. package/dist/entries/workload-board.d.ts +1 -0
  80. package/dist/entries/workload-board.js +1 -0
  81. package/dist/index.d.ts +21 -0
  82. package/dist/index.js +21 -0
  83. package/dist/patterns/agent-chat/agent-chat.d.ts +75 -0
  84. package/dist/patterns/agent-chat/agent-chat.js +820 -0
  85. package/dist/patterns/agent-chat/controller.d.ts +27 -0
  86. package/dist/patterns/agent-chat/controller.js +182 -0
  87. package/dist/patterns/agent-chat/index.d.ts +3 -0
  88. package/dist/patterns/agent-chat/index.js +6 -0
  89. package/dist/patterns/agent-chat/types.d.ts +109 -0
  90. package/dist/patterns/agent-chat/types.js +1 -0
  91. package/dist/patterns/audit/activity-density.d.ts +68 -0
  92. package/dist/patterns/audit/activity-density.js +428 -0
  93. package/dist/patterns/audit/audit-log.d.ts +182 -0
  94. package/dist/patterns/audit/audit-log.js +1082 -0
  95. package/dist/patterns/audit/index.d.ts +3 -0
  96. package/dist/patterns/audit/index.js +7 -0
  97. package/dist/patterns/audit/shared.d.ts +10 -0
  98. package/dist/patterns/audit/shared.js +50 -0
  99. package/dist/patterns/audit/types.d.ts +143 -0
  100. package/dist/patterns/audit/types.js +327 -0
  101. package/dist/patterns/audit/window.d.ts +116 -0
  102. package/dist/patterns/audit/window.js +132 -0
  103. package/dist/patterns/content-explorer/actions/controller.js +12 -2
  104. package/dist/patterns/content-explorer/box-transport.js +117 -25
  105. package/dist/patterns/content-explorer/content-explorer.d.ts +13 -1
  106. package/dist/patterns/content-explorer/content-explorer.js +36 -3
  107. package/dist/patterns/content-explorer/contracts.d.ts +24 -1
  108. package/dist/patterns/content-explorer/contracts.js +68 -11
  109. package/dist/patterns/content-explorer/controller.d.ts +16 -1
  110. package/dist/patterns/content-explorer/controller.js +130 -4
  111. package/dist/patterns/content-explorer/navigation/controller.js +11 -9
  112. package/dist/patterns/content-explorer/types.d.ts +58 -1
  113. package/dist/patterns/content-picker/content-picker.d.ts +71 -0
  114. package/dist/patterns/content-picker/content-picker.js +747 -0
  115. package/dist/patterns/content-picker/controller.d.ts +38 -0
  116. package/dist/patterns/content-picker/controller.js +141 -0
  117. package/dist/patterns/content-picker/index.d.ts +3 -0
  118. package/dist/patterns/content-picker/index.js +6 -0
  119. package/dist/patterns/content-picker/types.d.ts +52 -0
  120. package/dist/patterns/content-picker/types.js +26 -0
  121. package/dist/patterns/content-sidebar/content-sidebar.d.ts +43 -0
  122. package/dist/patterns/content-sidebar/content-sidebar.js +293 -0
  123. package/dist/patterns/content-sidebar/index.d.ts +2 -0
  124. package/dist/patterns/content-sidebar/index.js +4 -0
  125. package/dist/patterns/content-sidebar/types.d.ts +18 -0
  126. package/dist/patterns/content-sidebar/types.js +20 -0
  127. package/dist/patterns/content-uploader/box-transport.d.ts +14 -0
  128. package/dist/patterns/content-uploader/box-transport.js +54 -0
  129. package/dist/patterns/content-uploader/content-uploader.d.ts +62 -0
  130. package/dist/patterns/content-uploader/content-uploader.js +559 -0
  131. package/dist/patterns/content-uploader/controller.d.ts +39 -0
  132. package/dist/patterns/content-uploader/controller.js +227 -0
  133. package/dist/patterns/content-uploader/index.d.ts +4 -0
  134. package/dist/patterns/content-uploader/index.js +8 -0
  135. package/dist/patterns/content-uploader/types.d.ts +120 -0
  136. package/dist/patterns/content-uploader/types.js +38 -0
  137. package/dist/patterns/diff/compare-view.d.ts +47 -0
  138. package/dist/patterns/diff/compare-view.js +276 -0
  139. package/dist/patterns/diff/diff-viewer.d.ts +42 -0
  140. package/dist/patterns/diff/diff-viewer.js +434 -0
  141. package/dist/patterns/diff/engine.d.ts +22 -0
  142. package/dist/patterns/diff/engine.js +276 -0
  143. package/dist/patterns/diff/index.d.ts +4 -0
  144. package/dist/patterns/diff/index.js +8 -0
  145. package/dist/patterns/diff/types.d.ts +69 -0
  146. package/dist/patterns/diff/types.js +24 -0
  147. package/dist/patterns/form-wizard/controller.d.ts +39 -0
  148. package/dist/patterns/form-wizard/controller.js +157 -0
  149. package/dist/patterns/form-wizard/form-wizard.d.ts +63 -0
  150. package/dist/patterns/form-wizard/form-wizard.js +468 -0
  151. package/dist/patterns/form-wizard/index.d.ts +4 -0
  152. package/dist/patterns/form-wizard/index.js +8 -0
  153. package/dist/patterns/form-wizard/types.d.ts +109 -0
  154. package/dist/patterns/form-wizard/types.js +83 -0
  155. package/dist/patterns/form-wizard/wizard-summary.d.ts +62 -0
  156. package/dist/patterns/form-wizard/wizard-summary.js +324 -0
  157. package/dist/patterns/internal/safe-href.d.ts +17 -0
  158. package/dist/patterns/internal/safe-href.js +17 -0
  159. package/dist/patterns/lineage/index.d.ts +3 -0
  160. package/dist/patterns/lineage/index.js +6 -0
  161. package/dist/patterns/lineage/lineage-graph.d.ts +30 -0
  162. package/dist/patterns/lineage/lineage-graph.js +434 -0
  163. package/dist/patterns/lineage/provenance-strip.d.ts +22 -0
  164. package/dist/patterns/lineage/provenance-strip.js +194 -0
  165. package/dist/patterns/lineage/types.d.ts +53 -0
  166. package/dist/patterns/lineage/types.js +49 -0
  167. package/dist/patterns/notifications/index.d.ts +3 -0
  168. package/dist/patterns/notifications/index.js +6 -0
  169. package/dist/patterns/notifications/notification-bell.d.ts +38 -0
  170. package/dist/patterns/notifications/notification-bell.js +198 -0
  171. package/dist/patterns/notifications/notification-inbox.d.ts +46 -0
  172. package/dist/patterns/notifications/notification-inbox.js +537 -0
  173. package/dist/patterns/notifications/types.d.ts +61 -0
  174. package/dist/patterns/notifications/types.js +108 -0
  175. package/dist/patterns/preview/annotation-inspector.d.ts +25 -6
  176. package/dist/patterns/preview/annotation-inspector.js +239 -94
  177. package/dist/patterns/preview/annotation-thread.d.ts +25 -5
  178. package/dist/patterns/preview/annotation-thread.js +233 -82
  179. package/dist/patterns/preview/annotation-toolbar.d.ts +20 -6
  180. package/dist/patterns/preview/annotation-toolbar.js +162 -96
  181. package/dist/patterns/preview/content-preview-adapter.d.ts +10 -1
  182. package/dist/patterns/preview/content-preview-adapter.js +26 -1
  183. package/dist/patterns/preview/preview-element.d.ts +15 -2
  184. package/dist/patterns/preview/preview-element.js +223 -52
  185. package/dist/patterns/preview/provider-adapter.d.ts +47 -0
  186. package/dist/patterns/preview/provider-adapter.js +17 -0
  187. package/dist/patterns/run/index.d.ts +2 -0
  188. package/dist/patterns/run/index.js +4 -0
  189. package/dist/patterns/run/run-trace.d.ts +40 -0
  190. package/dist/patterns/run/run-trace.js +441 -0
  191. package/dist/patterns/run/types.d.ts +66 -0
  192. package/dist/patterns/run/types.js +152 -0
  193. package/dist/patterns/signature/index.d.ts +2 -0
  194. package/dist/patterns/signature/index.js +4 -0
  195. package/dist/patterns/signature/signature-ceremony.d.ts +33 -0
  196. package/dist/patterns/signature/signature-ceremony.js +317 -0
  197. package/dist/patterns/signature/types.d.ts +68 -0
  198. package/dist/patterns/signature/types.js +89 -0
  199. package/dist/patterns/timeline/index.d.ts +2 -0
  200. package/dist/patterns/timeline/index.js +4 -0
  201. package/dist/patterns/timeline/timeline.d.ts +27 -0
  202. package/dist/patterns/timeline/timeline.js +430 -0
  203. package/dist/patterns/timeline/types.d.ts +36 -0
  204. package/dist/patterns/timeline/types.js +27 -0
  205. package/dist/patterns/versions/graph-layout.d.ts +43 -0
  206. package/dist/patterns/versions/graph-layout.js +159 -0
  207. package/dist/patterns/versions/index.d.ts +4 -0
  208. package/dist/patterns/versions/index.js +8 -0
  209. package/dist/patterns/versions/shared.d.ts +4 -0
  210. package/dist/patterns/versions/shared.js +13 -0
  211. package/dist/patterns/versions/types.d.ts +37 -0
  212. package/dist/patterns/versions/types.js +39 -0
  213. package/dist/patterns/versions/version-graph.d.ts +36 -0
  214. package/dist/patterns/versions/version-graph.js +438 -0
  215. package/dist/patterns/versions/version-list.d.ts +39 -0
  216. package/dist/patterns/versions/version-list.js +407 -0
  217. package/dist/patterns/work-queue/controller.d.ts +26 -0
  218. package/dist/patterns/work-queue/controller.js +150 -0
  219. package/dist/patterns/work-queue/index.d.ts +4 -0
  220. package/dist/patterns/work-queue/index.js +7 -0
  221. package/dist/patterns/work-queue/types.d.ts +128 -0
  222. package/dist/patterns/work-queue/types.js +45 -0
  223. package/dist/patterns/work-queue/work-queue.d.ts +48 -0
  224. package/dist/patterns/work-queue/work-queue.js +534 -0
  225. package/dist/patterns/work-queue/workload-board.d.ts +53 -0
  226. package/dist/patterns/work-queue/workload-board.js +608 -0
  227. package/package.json +89 -5
@@ -0,0 +1,441 @@
1
+ import { formatRunDuration, formatRunSummary, isRunStepRecord, resolveRunSteps, } from "./types.js";
2
+ import { ProgressBar } from "../../components/feedback/progress-bar.js";
3
+ import { BaseElement } from "../../core/index.js";
4
+ import { boePanel } from "../../foundations/geometry/index.js";
5
+ const DEFAULT_TAG_NAME = "box-run-trace";
6
+ /** Escape a value for use inside a double-quoted attribute selector. */
7
+ const cssAttrValue = (value) => value.replaceAll("\\", "\\\\").replaceAll('"', '\\"');
8
+ const escapeHtml = (value) => value
9
+ .replaceAll("&", "&")
10
+ .replaceAll("<", "&lt;")
11
+ .replaceAll(">", "&gt;")
12
+ .replaceAll('"', "&quot;")
13
+ .replaceAll("'", "&#39;");
14
+ /** Every status in words — colour never carries the meaning alone. */
15
+ export const RUN_STEP_STATUS_LABEL = {
16
+ pending: "Queued",
17
+ running: "Running",
18
+ succeeded: "Succeeded",
19
+ warning: "Completed with warnings",
20
+ failed: "Failed",
21
+ skipped: "Skipped",
22
+ };
23
+ const STATUS_TONE = {
24
+ pending: "var(--boe-token-text-text-secondary, #6f6f6f)",
25
+ running: "var(--boe-token-surface-surface-brand, #0061d5)",
26
+ succeeded: "var(--boe-token-surface-status-surface-success, #26a27b)",
27
+ warning: "var(--boe-token-surface-status-surface-warning, #f5b31b)",
28
+ failed: "var(--boe-token-surface-status-surface-error, #ed3757)",
29
+ skipped: "var(--boe-token-text-text-secondary, #6f6f6f)",
30
+ };
31
+ const elementStyles = `
32
+ :host {
33
+ display: block;
34
+ }
35
+
36
+ [part="panel"] {
37
+ border: ${boePanel.border};
38
+ border-radius: ${boePanel.radius};
39
+ background: ${boePanel.background};
40
+ padding: 0.8rem 1rem;
41
+ }
42
+
43
+ [part="header"] {
44
+ display: flex;
45
+ align-items: baseline;
46
+ gap: 0.6rem;
47
+ margin-block-end: 0.4rem;
48
+ }
49
+
50
+ [part="heading"] {
51
+ margin: 0;
52
+ font: inherit;
53
+ font-size: 0.95rem;
54
+ font-weight: 700;
55
+ color: var(--boe-token-text-text, #1f1e1b);
56
+ }
57
+
58
+ [part="summary"] {
59
+ margin-inline-start: auto;
60
+ font-size: 0.78rem;
61
+ font-weight: 600;
62
+ padding: 0.14rem 0.5rem;
63
+ border-radius: 999px;
64
+ border: 1px solid transparent;
65
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
66
+ background: color-mix(in srgb, var(--boe-token-surface-surface-hover, #f4f4f4) 80%, transparent);
67
+ }
68
+
69
+ [part="summary"][data-status="completed"] {
70
+ background: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 14%, transparent);
71
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 74%, black 26%);
72
+ border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-success, #26a27b) 32%, transparent);
73
+ }
74
+
75
+ [part="summary"][data-status="failed"] {
76
+ background: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 14%, transparent);
77
+ color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 76%, black 24%);
78
+ border-color: color-mix(in srgb, var(--boe-token-surface-status-surface-error, #ed3757) 32%, transparent);
79
+ }
80
+
81
+ [part="summary"][data-status="running"] {
82
+ background: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 12%, transparent);
83
+ color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 80%, black 20%);
84
+ border-color: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 30%, transparent);
85
+ }
86
+
87
+ [part="steps"] {
88
+ margin: 0;
89
+ padding: 0;
90
+ list-style: none;
91
+ }
92
+
93
+ /* Marker column + body; the spine hangs off the marker column so the
94
+ nodes stay aligned at every width — long titles wrap in the body. */
95
+ [part="step"] {
96
+ position: relative;
97
+ display: grid;
98
+ grid-template-columns: auto 1fr;
99
+ gap: 0.65rem;
100
+ padding: 0.55rem 0 0.55rem 0.15rem;
101
+ }
102
+
103
+ [part="step"]:not(:last-child)::after {
104
+ content: "";
105
+ position: absolute;
106
+ left: calc(0.15rem + 0.55rem - 1px);
107
+ top: 1.9rem;
108
+ bottom: -0.35rem;
109
+ width: 2px;
110
+ background: color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 72%, transparent);
111
+ }
112
+
113
+ [part="marker"] {
114
+ inline-size: 1.1rem;
115
+ block-size: 1.1rem;
116
+ margin-top: 0.2rem;
117
+ border-radius: 999px;
118
+ border: 2px solid var(--run-tone, var(--boe-token-text-text-secondary, #6f6f6f));
119
+ background: color-mix(in srgb, var(--run-tone, var(--boe-token-text-text-secondary, #6f6f6f)) 14%, var(--boe-token-surface-surface, #ffffff) 86%);
120
+ }
121
+
122
+ [part="step"][data-status="running"] [part="marker"] {
123
+ background: var(--run-tone, var(--boe-token-surface-surface-brand, #0061d5));
124
+ }
125
+
126
+ [part="step"][data-status="pending"] [part="marker"],
127
+ [part="step"][data-status="skipped"] [part="marker"] {
128
+ border-style: dashed;
129
+ background: transparent;
130
+ }
131
+
132
+ [part="step-body"] {
133
+ display: grid;
134
+ gap: 0.25rem;
135
+ min-inline-size: 0;
136
+ }
137
+
138
+ [part="topline"] {
139
+ display: flex;
140
+ flex-wrap: wrap;
141
+ align-items: center;
142
+ gap: 0.4rem;
143
+ }
144
+
145
+ [part="step-title"] {
146
+ font-weight: 700;
147
+ font-size: 0.88rem;
148
+ color: var(--boe-token-text-text, #1f1e1b);
149
+ }
150
+
151
+ [part="step"][data-status="pending"] [part="step-title"],
152
+ [part="step"][data-status="skipped"] [part="step-title"] {
153
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
154
+ font-weight: 600;
155
+ }
156
+
157
+ [part="status"] {
158
+ font-size: 0.76rem;
159
+ font-weight: 700;
160
+ color: color-mix(in srgb, var(--run-tone, var(--boe-token-text-text-secondary, #6f6f6f)) 78%, black 22%);
161
+ }
162
+
163
+ [part="timestamp"],
164
+ [part="duration"] {
165
+ font-size: 0.76rem;
166
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
167
+ }
168
+
169
+ [part="duration"] {
170
+ font-variant-numeric: tabular-nums;
171
+ }
172
+
173
+ [part="toggle"] {
174
+ appearance: none;
175
+ border: 0;
176
+ background: transparent;
177
+ padding: 0.1rem 0.35rem;
178
+ border-radius: 4px;
179
+ font: inherit;
180
+ font-size: 0.76rem;
181
+ font-weight: 700;
182
+ color: var(--boe-token-surface-surface-brand, #0061d5);
183
+ cursor: pointer;
184
+ }
185
+
186
+ [part="toggle"]:hover {
187
+ background: color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 8%, transparent);
188
+ }
189
+
190
+ [part="toggle"]:focus-visible {
191
+ outline: 2px solid color-mix(in srgb, var(--boe-token-surface-surface-brand, #0061d5) 34%, transparent);
192
+ outline-offset: 1px;
193
+ }
194
+
195
+ [part="detail"] {
196
+ display: grid;
197
+ gap: 0.45rem;
198
+ font-size: 0.82rem;
199
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
200
+ padding: 0.2rem 0 0.1rem;
201
+ }
202
+
203
+ [part="detail"][hidden] {
204
+ display: none;
205
+ }
206
+
207
+ [part="children"] {
208
+ margin: 0;
209
+ padding: 0;
210
+ list-style: none;
211
+ display: grid;
212
+ gap: 0.4rem;
213
+ }
214
+
215
+ [part="child"] {
216
+ display: grid;
217
+ grid-template-columns: minmax(7rem, auto) 1fr auto;
218
+ align-items: center;
219
+ gap: 0.55rem;
220
+ }
221
+
222
+ [part="child-label"] {
223
+ font-size: 0.8rem;
224
+ color: var(--boe-token-text-text, #1f1e1b);
225
+ }
226
+
227
+ /* The row already carries the label and status in words; the bar's
228
+ own meta line would say it twice in half the space. */
229
+ [part="child"] box-progress-bar::part(meta) {
230
+ display: none;
231
+ }
232
+
233
+ [part="child-status"] {
234
+ font-size: 0.74rem;
235
+ font-weight: 700;
236
+ color: color-mix(in srgb, var(--run-tone, var(--boe-token-text-text-secondary, #6f6f6f)) 78%, black 22%);
237
+ }
238
+
239
+ [part="empty"] {
240
+ padding: 0.8rem 0;
241
+ text-align: center;
242
+ color: var(--boe-token-text-text-secondary, #6f6f6f);
243
+ }
244
+
245
+ .boe-sr-only {
246
+ position: absolute;
247
+ width: 1px;
248
+ height: 1px;
249
+ margin: -1px;
250
+ padding: 0;
251
+ border: 0;
252
+ clip: rect(0, 0, 0, 0);
253
+ overflow: hidden;
254
+ white-space: nowrap;
255
+ }
256
+ `;
257
+ /**
258
+ * Machine execution trace: a job, pipeline, or agent run, top-down. The
259
+ * rules live in `resolveRunSteps` (pure), the same way `resolveCeremony`
260
+ * backs the signature card: an explicit status wins, a failure shadows the
261
+ * queue behind it as skipped, timestamps derive running/succeeded, and the
262
+ * host can drive its notifications from the identical function.
263
+ *
264
+ * Deliberately not `box-timeline` (the human activity feed): a run reads
265
+ * forward, has one step in flight, and takes no comments.
266
+ *
267
+ * The summary chip doubles as a polite status region, so a run driven by
268
+ * attribute updates announces "Running Deploy — step 3 of 5" → "Completed"
269
+ * without extra wiring. Per-step detail expands in place: `description`
270
+ * plus a `detail-<id>` slot for rich host content, plus child tasks with
271
+ * live `box-progress-bar` rows.
272
+ */
273
+ export class RunTrace extends BaseElement {
274
+ static tagName = DEFAULT_TAG_NAME;
275
+ static get observedAttributes() {
276
+ return ["heading", "steps"];
277
+ }
278
+ hostEl;
279
+ stepsRaw = null;
280
+ stepsCache = [];
281
+ expandedIds = new Set();
282
+ get heading() {
283
+ return this.getAttribute("heading") ?? "Run";
284
+ }
285
+ set heading(value) {
286
+ this.setAttribute("heading", value);
287
+ }
288
+ get steps() {
289
+ const raw = this.getAttribute("steps");
290
+ if (!raw) {
291
+ return [...this.stepsCache];
292
+ }
293
+ if (raw !== this.stepsRaw) {
294
+ this.stepsRaw = raw;
295
+ try {
296
+ const parsed = JSON.parse(raw);
297
+ this.stepsCache =
298
+ Array.isArray(parsed) && parsed.every(isRunStepRecord) ? parsed : [];
299
+ }
300
+ catch {
301
+ this.stepsCache = [];
302
+ }
303
+ }
304
+ return [...this.stepsCache];
305
+ }
306
+ set steps(value) {
307
+ if (value.length) {
308
+ this.setAttribute("steps", JSON.stringify(value));
309
+ return;
310
+ }
311
+ // Clear the cache too: the no-attribute branch of the getter serves from
312
+ // it, and a stale cache would make an emptied run un-clearable.
313
+ this.stepsCache = [];
314
+ this.stepsRaw = null;
315
+ this.removeAttribute("steps");
316
+ }
317
+ /** The resolved run — same object the render uses. */
318
+ get resolution() {
319
+ return resolveRunSteps(this.steps);
320
+ }
321
+ /** Ids of the steps whose detail is expanded (host-readable). */
322
+ get expandedSteps() {
323
+ return [...this.expandedIds];
324
+ }
325
+ renderTemplate() {
326
+ if (!this.shadowRoot) {
327
+ return;
328
+ }
329
+ this.shadowRoot.innerHTML = `<style>${elementStyles}</style><div part="host"></div>`;
330
+ this.hostEl = this.shadowRoot.querySelector('[part="host"]');
331
+ }
332
+ setupListeners() {
333
+ // Slot-only detail can be appended after render; watch the light DOM so
334
+ // the step's toggle appears without the host having to touch `steps`.
335
+ // Shallow, and update() never mutates the light DOM, so this cannot loop.
336
+ new MutationObserver(() => {
337
+ this.update();
338
+ }).observe(this, { childList: true });
339
+ this.hostEl.addEventListener("click", event => {
340
+ const toggle = event.target.closest('[part="toggle"]');
341
+ if (!toggle || !this.hostEl.contains(toggle)) {
342
+ return;
343
+ }
344
+ const stepId = toggle.getAttribute("data-step-id") ?? "";
345
+ if (!stepId) {
346
+ return;
347
+ }
348
+ const expanded = !this.expandedIds.has(stepId);
349
+ if (expanded) {
350
+ this.expandedIds.add(stepId);
351
+ }
352
+ else {
353
+ this.expandedIds.delete(stepId);
354
+ }
355
+ this.dispatchEvent(new CustomEvent("step-toggled", {
356
+ bubbles: true,
357
+ composed: true,
358
+ detail: { stepId, expanded },
359
+ }));
360
+ this.update();
361
+ });
362
+ }
363
+ childrenMarkup(step) {
364
+ if (!step.children?.length) {
365
+ return "";
366
+ }
367
+ const rows = step.children
368
+ .map(child => {
369
+ const status = child.status ?? "pending";
370
+ const clamped = child.progress === undefined ? null : Math.max(0, Math.min(100, child.progress));
371
+ return `
372
+ <li part="child" style="--run-tone:${STATUS_TONE[status]};">
373
+ <span part="child-label">${escapeHtml(child.label)}</span>
374
+ ${clamped === null
375
+ ? "<span></span>"
376
+ : `<box-progress-bar label="${escapeHtml(child.label)} progress" value="${String(clamped)}"></box-progress-bar>`}
377
+ <span part="child-status">${RUN_STEP_STATUS_LABEL[status]}</span>
378
+ </li>
379
+ `;
380
+ })
381
+ .join("");
382
+ return `<ul part="children">${rows}</ul>`;
383
+ }
384
+ update() {
385
+ if (!this.hostEl) {
386
+ return;
387
+ }
388
+ const resolution = this.resolution;
389
+ const rows = resolution.steps
390
+ .map(entry => {
391
+ const { step, status, position } = entry;
392
+ const duration = formatRunDuration(step.startedAt, step.finishedAt);
393
+ // Slot-only detail counts: a host projecting logs for a step with no
394
+ // JSON description still needs the toggle that reveals them.
395
+ const hasSlotted = this.querySelector(`[slot="detail-${cssAttrValue(step.id)}"]`) !== null;
396
+ const hasDetail = Boolean(step.description) || Boolean(step.children?.length) || hasSlotted;
397
+ const expanded = this.expandedIds.has(step.id);
398
+ // The detail slot renders even without JSON detail so a host can
399
+ // project rich content (logs, links) for any step by id.
400
+ const detail = `
401
+ <div part="detail" data-step-id="${escapeHtml(step.id)}" ${expanded ? "" : "hidden"}>
402
+ ${step.description ? `<p part="description">${escapeHtml(step.description)}</p>` : ""}
403
+ ${this.childrenMarkup(step)}
404
+ <slot name="detail-${escapeHtml(step.id)}"></slot>
405
+ </div>
406
+ `;
407
+ return `
408
+ <li part="step" data-status="${status}" data-step-id="${escapeHtml(step.id)}" style="--run-tone:${STATUS_TONE[status]};">
409
+ <span part="marker" aria-hidden="true"></span>
410
+ <div part="step-body">
411
+ <div part="topline">
412
+ <span part="step-title">${escapeHtml(step.title)}</span>
413
+ <span part="status">${RUN_STEP_STATUS_LABEL[status]}</span>
414
+ <span class="boe-sr-only">, step ${String(position)} of ${String(resolution.total)}</span>
415
+ ${duration ? `<span part="duration">${duration}</span>` : ""}
416
+ ${hasDetail
417
+ ? `<button type="button" part="toggle" data-step-id="${escapeHtml(step.id)}" aria-expanded="${String(expanded)}">${expanded ? "Hide details" : "Details"}</button>`
418
+ : ""}
419
+ </div>
420
+ ${detail}
421
+ </div>
422
+ </li>
423
+ `;
424
+ })
425
+ .join("");
426
+ const summary = formatRunSummary(resolution);
427
+ this.hostEl.innerHTML = `
428
+ <section part="panel" aria-label="${escapeHtml(this.heading)}">
429
+ <div part="header">
430
+ <h3 part="heading">${escapeHtml(this.heading)}</h3>
431
+ <span part="summary" role="status" data-status="${resolution.status}">${escapeHtml(summary)}</span>
432
+ </div>
433
+ ${resolution.total
434
+ ? `<ol part="steps">${rows}</ol>`
435
+ : `<div part="empty">No steps yet.</div>`}
436
+ </section>
437
+ `;
438
+ }
439
+ }
440
+ ProgressBar.register();
441
+ RunTrace.register();
@@ -0,0 +1,66 @@
1
+ /**
2
+ * A run is a machine execution trace — a job, pipeline, or agent run —
3
+ * rendered forward-chronologically. This is deliberately not
4
+ * `box-timeline`: that surface is an append-only *human* activity feed
5
+ * (newest first, actors, comments); a run reads top-down, has exactly one
6
+ * step in flight, and a failure shadows everything queued behind it.
7
+ */
8
+ export type RunStepStatus = "pending" | "running" | "succeeded" | "warning" | "failed" | "skipped";
9
+ export type RunStatus = "pending" | "running" | "completed" | "failed";
10
+ /** A nested unit of work under a step, with optional live progress. */
11
+ export interface RunChildTask {
12
+ id: string;
13
+ label: string;
14
+ /** 0–100; omit for indeterminate work that only has a status. */
15
+ progress?: number;
16
+ status?: RunStepStatus;
17
+ }
18
+ export interface RunStep {
19
+ id: string;
20
+ title: string;
21
+ /** Expandable detail under the title. */
22
+ description?: string;
23
+ /**
24
+ * Explicit status wins. Absent, the status derives from timestamps and
25
+ * the failure shadow — see `resolveRunSteps`.
26
+ */
27
+ status?: RunStepStatus;
28
+ /** ISO timestamps; duration renders when both are present. */
29
+ startedAt?: string;
30
+ finishedAt?: string;
31
+ children?: RunChildTask[];
32
+ }
33
+ export interface ResolvedRunStep {
34
+ step: RunStep;
35
+ status: RunStepStatus;
36
+ /** 1-based position, for "step 2 of 5" phrasing. */
37
+ position: number;
38
+ }
39
+ export interface RunResolution {
40
+ steps: ResolvedRunStep[];
41
+ status: RunStatus;
42
+ total: number;
43
+ /** Steps in a terminal state (succeeded, warning, failed, or skipped). */
44
+ settled: number;
45
+ }
46
+ /** Attribute payloads are author input — validate every record. */
47
+ export declare const isRunStepRecord: (value: unknown) => value is RunStep;
48
+ /**
49
+ * The run rules, pure and DOM-free, so a host can drive notifications or a
50
+ * "retry from here" affordance from the same function the surface renders.
51
+ *
52
+ * Per step, in priority order:
53
+ * 1. An explicit `status` wins.
54
+ * 2. A failure shadows what is queued behind it: steps after a failed step
55
+ * are `skipped` — a dead run must not show work as still coming, the
56
+ * same rule `resolveCeremony` applies after a decline.
57
+ * 3. `finishedAt` ⇒ succeeded; `startedAt` alone ⇒ running; neither ⇒ pending.
58
+ */
59
+ export declare const resolveRunSteps: (steps: readonly RunStep[]) => RunResolution;
60
+ /** One line a host can put in a toast or heading — same rules as the surface. */
61
+ export declare const formatRunSummary: (resolution: RunResolution) => string;
62
+ /**
63
+ * "4m 12s"-style duration between two ISO timestamps; empty when either is
64
+ * missing or unparseable, so callers can simply omit the segment.
65
+ */
66
+ export declare const formatRunDuration: (startedAt?: string, finishedAt?: string) => string;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * A run is a machine execution trace — a job, pipeline, or agent run —
3
+ * rendered forward-chronologically. This is deliberately not
4
+ * `box-timeline`: that surface is an append-only *human* activity feed
5
+ * (newest first, actors, comments); a run reads top-down, has exactly one
6
+ * step in flight, and a failure shadows everything queued behind it.
7
+ */
8
+ const STEP_STATUSES = new Set([
9
+ "pending",
10
+ "running",
11
+ "succeeded",
12
+ "warning",
13
+ "failed",
14
+ "skipped",
15
+ ]);
16
+ /** Attribute payloads are author input — validate every record. */
17
+ export const isRunStepRecord = (value) => {
18
+ if (typeof value !== "object" || value === null) {
19
+ return false;
20
+ }
21
+ const step = value;
22
+ if (typeof step.id !== "string" ||
23
+ step.id.length === 0 ||
24
+ typeof step.title !== "string" ||
25
+ step.title.length === 0) {
26
+ return false;
27
+ }
28
+ if (step.status !== undefined && !STEP_STATUSES.has(step.status)) {
29
+ return false;
30
+ }
31
+ // A non-string description would reach escapeHtml and throw mid-render.
32
+ if (step.description !== undefined && typeof step.description !== "string") {
33
+ return false;
34
+ }
35
+ if (step.children !== undefined) {
36
+ if (!Array.isArray(step.children)) {
37
+ return false;
38
+ }
39
+ for (const entry of step.children) {
40
+ const child = entry;
41
+ if (typeof child !== "object" ||
42
+ child === null ||
43
+ typeof child.id !== "string" ||
44
+ typeof child.label !== "string" ||
45
+ (child.progress !== undefined && typeof child.progress !== "number") ||
46
+ (child.status !== undefined && !STEP_STATUSES.has(child.status))) {
47
+ return false;
48
+ }
49
+ }
50
+ }
51
+ return true;
52
+ };
53
+ const TERMINAL = new Set(["succeeded", "warning", "failed", "skipped"]);
54
+ /**
55
+ * The run rules, pure and DOM-free, so a host can drive notifications or a
56
+ * "retry from here" affordance from the same function the surface renders.
57
+ *
58
+ * Per step, in priority order:
59
+ * 1. An explicit `status` wins.
60
+ * 2. A failure shadows what is queued behind it: steps after a failed step
61
+ * are `skipped` — a dead run must not show work as still coming, the
62
+ * same rule `resolveCeremony` applies after a decline.
63
+ * 3. `finishedAt` ⇒ succeeded; `startedAt` alone ⇒ running; neither ⇒ pending.
64
+ */
65
+ export const resolveRunSteps = (steps) => {
66
+ let failed = false;
67
+ const resolved = steps.map((step, index) => {
68
+ let status;
69
+ if (step.status) {
70
+ status = step.status;
71
+ }
72
+ else if (failed) {
73
+ status = "skipped";
74
+ }
75
+ else if (step.finishedAt) {
76
+ status = "succeeded";
77
+ }
78
+ else if (step.startedAt) {
79
+ status = "running";
80
+ }
81
+ else {
82
+ status = "pending";
83
+ }
84
+ // An explicit failed also shadows what follows; an explicit status on a
85
+ // later step still overrides the shadow (rule 1 beats rule 2).
86
+ if (status === "failed") {
87
+ failed = true;
88
+ }
89
+ return { step, status, position: index + 1 };
90
+ });
91
+ const settled = resolved.filter(entry => TERMINAL.has(entry.status)).length;
92
+ const anyRunning = resolved.some(entry => entry.status === "running");
93
+ const status = failed
94
+ ? "failed"
95
+ : anyRunning
96
+ ? "running"
97
+ : resolved.length > 0 && settled === resolved.length
98
+ ? "completed"
99
+ : settled > 0
100
+ ? "running"
101
+ : "pending";
102
+ return { steps: resolved, status, total: resolved.length, settled };
103
+ };
104
+ /** One line a host can put in a toast or heading — same rules as the surface. */
105
+ export const formatRunSummary = (resolution) => {
106
+ if (resolution.total === 0) {
107
+ return "No steps";
108
+ }
109
+ if (resolution.status === "failed") {
110
+ const failedStep = resolution.steps.find(entry => entry.status === "failed");
111
+ return failedStep ? `Failed at ${failedStep.step.title}` : "Failed";
112
+ }
113
+ if (resolution.status === "completed") {
114
+ const warnings = resolution.steps.filter(entry => entry.status === "warning").length;
115
+ return warnings > 0
116
+ ? `Completed with ${String(warnings)} warning${warnings === 1 ? "" : "s"}`
117
+ : "Completed";
118
+ }
119
+ if (resolution.status === "running") {
120
+ const runningStep = resolution.steps.find(entry => entry.status === "running");
121
+ return runningStep
122
+ ? `Running ${runningStep.step.title} — step ${String(runningStep.position)} of ${String(resolution.total)}`
123
+ : `${String(resolution.settled)} of ${String(resolution.total)} steps done`;
124
+ }
125
+ return "Not started";
126
+ };
127
+ /**
128
+ * "4m 12s"-style duration between two ISO timestamps; empty when either is
129
+ * missing or unparseable, so callers can simply omit the segment.
130
+ */
131
+ export const formatRunDuration = (startedAt, finishedAt) => {
132
+ if (!startedAt || !finishedAt) {
133
+ return "";
134
+ }
135
+ const start = Date.parse(startedAt);
136
+ const finish = Date.parse(finishedAt);
137
+ if (Number.isNaN(start) || Number.isNaN(finish) || finish < start) {
138
+ return "";
139
+ }
140
+ const totalSeconds = Math.round((finish - start) / 1000);
141
+ if (totalSeconds < 60) {
142
+ return `${String(totalSeconds)}s`;
143
+ }
144
+ const minutes = Math.floor(totalSeconds / 60);
145
+ const seconds = totalSeconds % 60;
146
+ if (minutes < 60) {
147
+ return seconds ? `${String(minutes)}m ${String(seconds)}s` : `${String(minutes)}m`;
148
+ }
149
+ const hours = Math.floor(minutes / 60);
150
+ const rest = minutes % 60;
151
+ return rest ? `${String(hours)}h ${String(rest)}m` : `${String(hours)}h`;
152
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./types.js";
2
+ export * from "./signature-ceremony.js";
@@ -0,0 +1,4 @@
1
+ // Signature ceremony model and the pure ordering engine
2
+ export * from "./types.js";
3
+ // Party-oriented signing progress surface
4
+ export * from "./signature-ceremony.js";