@flamingo-stack/openframe-frontend-core 0.0.740 → 0.0.741

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 (167) hide show
  1. package/dist/build/export-map.json +1 -1
  2. package/dist/{chunk-3ZIQOYNX.cjs → chunk-4XL4YEZM.cjs} +3 -3
  3. package/dist/{chunk-WFPCCBOM.cjs → chunk-7AM3AFM4.cjs} +10 -10
  4. package/dist/{chunk-KHXZFLIN.cjs → chunk-DKOLQPE7.cjs} +8 -2
  5. package/dist/{chunk-7UIQPMBJ.cjs → chunk-FQN6STIM.cjs} +1 -144
  6. package/dist/{chunk-ZLTCQKTD.cjs → chunk-I6UE6YVM.cjs} +2 -2
  7. package/dist/{chunk-VC4IV3AY.cjs → chunk-IK2RJUEA.cjs} +2049 -199
  8. package/dist/{chunk-D5KEWWLW.cjs → chunk-ITPEFCQ2.cjs} +10 -10
  9. package/dist/{chunk-2Y5Y4FLM.cjs → chunk-JFS6TZDX.cjs} +15 -15
  10. package/dist/{chunk-VU4CKUJW.cjs → chunk-LZ6NOVXX.cjs} +23 -23
  11. package/dist/{chunk-UW3YXDC4.cjs → chunk-QEUGYHFB.cjs} +4 -4
  12. package/dist/{chunk-II4QMH26.cjs → chunk-STEJZPIO.cjs} +3 -3
  13. package/dist/{chunk-4RLGLB45.cjs → chunk-XJ36TEGE.cjs} +11 -11
  14. package/dist/{chunk-BDA5F6RM.cjs → chunk-YQ37ZCD2.cjs} +2 -2
  15. package/dist/{chunk-LLAC2UZ3.cjs → chunk-ZJPDGVA6.cjs} +3 -3
  16. package/dist/{chunk-SWR22DOZ.cjs → chunk-ZYOS7LVQ.cjs} +22 -22
  17. package/dist/{cloud-tenants-PVXDI5MU.cjs → cloud-tenants-MVJK52I2.cjs} +12 -12
  18. package/dist/components/case-studies/index.cjs +10 -10
  19. package/dist/components/contact/index.cjs +3 -3
  20. package/dist/components/docs/index.cjs +5 -5
  21. package/dist/components/embeds/index.cjs +3 -3
  22. package/dist/components/faq/index.cjs +3 -3
  23. package/dist/components/features/capability-explorer.d.ts +9 -2
  24. package/dist/components/features/capability-explorer.d.ts.map +1 -1
  25. package/dist/components/features/capability-explorer.js +113 -6
  26. package/dist/components/features/index.cjs +140 -2
  27. package/dist/components/features/index.d.ts +1 -0
  28. package/dist/components/features/index.d.ts.map +1 -1
  29. package/dist/components/features/index.js +1 -0
  30. package/dist/components/features/scripts/execution-cells.d.ts +65 -0
  31. package/dist/components/features/scripts/execution-cells.d.ts.map +1 -0
  32. package/dist/components/features/scripts/execution-cells.js +75 -0
  33. package/dist/components/features/scripts/execution-status.d.ts +48 -0
  34. package/dist/components/features/scripts/execution-status.d.ts.map +1 -0
  35. package/dist/components/features/scripts/execution-status.js +15 -0
  36. package/dist/components/features/scripts/index.d.ts +20 -0
  37. package/dist/components/features/scripts/index.d.ts.map +1 -0
  38. package/dist/components/features/scripts/index.js +59 -0
  39. package/dist/components/features/scripts/schedule-form/index.d.ts +18 -0
  40. package/dist/components/features/scripts/schedule-form/index.d.ts.map +1 -0
  41. package/dist/components/features/scripts/schedule-form/index.js +84 -0
  42. package/dist/components/features/scripts/schedule-form/schedule-enums.d.ts +24 -0
  43. package/dist/components/features/scripts/schedule-form/schedule-enums.d.ts.map +1 -0
  44. package/dist/components/features/scripts/schedule-form/schedule-enums.js +18 -0
  45. package/dist/components/features/scripts/schedule-form/schedule-form-fields.d.ts +57 -0
  46. package/dist/components/features/scripts/schedule-form/schedule-form-fields.d.ts.map +1 -0
  47. package/dist/components/features/scripts/schedule-form/schedule-form-fields.js +169 -0
  48. package/dist/components/features/scripts/schedule-form/schedule-form-types.d.ts +138 -0
  49. package/dist/components/features/scripts/schedule-form/schedule-form-types.d.ts.map +1 -0
  50. package/dist/components/features/scripts/schedule-form/schedule-form-types.js +72 -0
  51. package/dist/components/features/scripts/schedule-form/schedule-interval-input.d.ts +54 -0
  52. package/dist/components/features/scripts/schedule-form/schedule-interval-input.d.ts.map +1 -0
  53. package/dist/components/features/scripts/schedule-form/schedule-interval-input.js +60 -0
  54. package/dist/components/features/scripts/schedule-form/schedule-offline-fields.d.ts +29 -0
  55. package/dist/components/features/scripts/schedule-form/schedule-offline-fields.d.ts.map +1 -0
  56. package/dist/components/features/scripts/schedule-form/schedule-offline-fields.js +124 -0
  57. package/dist/components/features/scripts/schedule-form/schedule-script-picker-card.d.ts +52 -0
  58. package/dist/components/features/scripts/schedule-form/schedule-script-picker-card.d.ts.map +1 -0
  59. package/dist/components/features/scripts/schedule-form/schedule-script-picker-card.js +244 -0
  60. package/dist/components/features/scripts/schedule-form/schedule-script-search-field.d.ts +35 -0
  61. package/dist/components/features/scripts/schedule-form/schedule-script-search-field.d.ts.map +1 -0
  62. package/dist/components/features/scripts/schedule-form/schedule-script-search-field.js +58 -0
  63. package/dist/components/features/scripts/schedule-form/schedule-scripts-field.d.ts +25 -0
  64. package/dist/components/features/scripts/schedule-form/schedule-scripts-field.d.ts.map +1 -0
  65. package/dist/components/features/scripts/schedule-form/schedule-scripts-field.js +66 -0
  66. package/dist/components/features/scripts/schedule-form/schedule-timing-fields.d.ts +77 -0
  67. package/dist/components/features/scripts/schedule-form/schedule-timing-fields.d.ts.map +1 -0
  68. package/dist/components/features/scripts/schedule-form/schedule-timing-fields.js +262 -0
  69. package/dist/components/features/scripts/schedule-form/schedule-timing.d.ts +288 -0
  70. package/dist/components/features/scripts/schedule-form/schedule-timing.d.ts.map +1 -0
  71. package/dist/components/features/scripts/schedule-form/schedule-timing.js +165 -0
  72. package/dist/components/features/scripts/script-cells.d.ts +11 -0
  73. package/dist/components/features/scripts/script-cells.d.ts.map +1 -0
  74. package/dist/components/features/scripts/script-cells.js +19 -0
  75. package/dist/components/features/scripts/script-executions-table.d.ts +58 -0
  76. package/dist/components/features/scripts/script-executions-table.d.ts.map +1 -0
  77. package/dist/components/features/scripts/script-executions-table.js +88 -0
  78. package/dist/components/features/scripts/script-schedules-table.d.ts +38 -0
  79. package/dist/components/features/scripts/script-schedules-table.d.ts.map +1 -0
  80. package/dist/components/features/scripts/script-schedules-table.js +71 -0
  81. package/dist/components/features/scripts/script-shell-badge.d.ts +9 -0
  82. package/dist/components/features/scripts/script-shell-badge.d.ts.map +1 -0
  83. package/dist/components/features/scripts/script-shell-badge.js +15 -0
  84. package/dist/components/features/scripts/scripts-table-columns.d.ts +162 -0
  85. package/dist/components/features/scripts/scripts-table-columns.d.ts.map +1 -0
  86. package/dist/components/features/scripts/scripts-table-columns.js +69 -0
  87. package/dist/components/features/scripts/scripts-table-shared.d.ts +19 -0
  88. package/dist/components/features/scripts/scripts-table-shared.d.ts.map +1 -0
  89. package/dist/components/features/scripts/scripts-table-shared.js +35 -0
  90. package/dist/components/features/scripts/scripts-table.d.ts +40 -0
  91. package/dist/components/features/scripts/scripts-table.d.ts.map +1 -0
  92. package/dist/components/features/scripts/scripts-table.js +84 -0
  93. package/dist/components/features/scripts/scripts-tabs.d.ts +5 -0
  94. package/dist/components/features/scripts/scripts-tabs.d.ts.map +1 -0
  95. package/dist/components/features/scripts/scripts-tabs.js +10 -0
  96. package/dist/components/features/scripts/shell-types.d.ts +13 -0
  97. package/dist/components/features/scripts/shell-types.d.ts.map +1 -0
  98. package/dist/components/features/scripts/shell-types.js +21 -0
  99. package/dist/components/help-center-pages/index.cjs +44 -44
  100. package/dist/components/index.cjs +162 -24
  101. package/dist/components/meeting-scheduler/index.cjs +11 -11
  102. package/dist/components/navigation/index.cjs +3 -3
  103. package/dist/components/onboarding-guides/index.cjs +4 -4
  104. package/dist/components/product-demo/fixtures/scripts.d.ts +34 -0
  105. package/dist/components/product-demo/fixtures/scripts.d.ts.map +1 -0
  106. package/dist/components/product-demo/fixtures/scripts.js +123 -0
  107. package/dist/components/product-demo/fixtures/shared.d.ts +8 -0
  108. package/dist/components/product-demo/fixtures/shared.d.ts.map +1 -1
  109. package/dist/components/product-demo/fixtures/shared.js +7 -1
  110. package/dist/components/product-demo/fixtures/software-update.d.ts.map +1 -1
  111. package/dist/components/product-demo/fixtures/software-update.js +1 -5
  112. package/dist/components/product-demo/index.cjs +16 -13
  113. package/dist/components/product-demo/product-screen.d.ts.map +1 -1
  114. package/dist/components/product-demo/product-screen.js +2 -1
  115. package/dist/components/product-demo/registry.d.ts.map +1 -1
  116. package/dist/components/product-demo/registry.js +2 -1
  117. package/dist/components/product-demo/screen-keys.cjs +2 -1
  118. package/dist/components/product-demo/screen-keys.d.ts +1 -0
  119. package/dist/components/product-demo/screen-keys.d.ts.map +1 -1
  120. package/dist/components/product-demo/screen-keys.js +2 -1
  121. package/dist/components/product-demo/screens/scripts.d.ts +11 -0
  122. package/dist/components/product-demo/screens/scripts.d.ts.map +1 -0
  123. package/dist/components/product-demo/screens/scripts.js +130 -0
  124. package/dist/components/tickets/index.cjs +5 -5
  125. package/dist/components/ui/index.cjs +2 -2
  126. package/dist/{devices-TWEA7XOR.cjs → devices-W3S7Q2PG.cjs} +8 -8
  127. package/dist/index.cjs +143 -5
  128. package/dist/{knowledge-4GQDBNQB.cjs → knowledge-AIYQ4FC3.cjs} +6 -6
  129. package/dist/{logs-EVU6GJHZ.cjs → logs-7SHJ2ARE.cjs} +24 -24
  130. package/dist/{policies-OZUEA5YS.cjs → policies-EIZJ5SUP.cjs} +9 -9
  131. package/dist/{remote-session-DNFZ5OLY.cjs → remote-session-BZMNE6D2.cjs} +5 -5
  132. package/dist/scripts-J2FWC7E4.cjs +2112 -0
  133. package/dist/{software-update-BLIVYOY2.cjs → software-update-QAMNASVF.cjs} +13 -17
  134. package/dist/{tickets-board-CKZRB6YV.cjs → tickets-board-CEDHD3KB.cjs} +17 -17
  135. package/package.json +1 -1
  136. package/src/components/features/capability-explorer.tsx +134 -7
  137. package/src/components/features/index.ts +1 -0
  138. package/src/components/features/scripts/execution-cells.tsx +149 -0
  139. package/src/components/features/scripts/execution-status.ts +42 -0
  140. package/src/components/features/scripts/index.ts +42 -0
  141. package/src/components/features/scripts/schedule-form/index.ts +59 -0
  142. package/src/components/features/scripts/schedule-form/schedule-enums.ts +26 -0
  143. package/src/components/features/scripts/schedule-form/schedule-form-fields.tsx +249 -0
  144. package/src/components/features/scripts/schedule-form/schedule-form-types.ts +189 -0
  145. package/src/components/features/scripts/schedule-form/schedule-interval-input.tsx +121 -0
  146. package/src/components/features/scripts/schedule-form/schedule-offline-fields.tsx +218 -0
  147. package/src/components/features/scripts/schedule-form/schedule-script-picker-card.tsx +321 -0
  148. package/src/components/features/scripts/schedule-form/schedule-script-search-field.tsx +115 -0
  149. package/src/components/features/scripts/schedule-form/schedule-scripts-field.tsx +97 -0
  150. package/src/components/features/scripts/schedule-form/schedule-timing-fields.tsx +482 -0
  151. package/src/components/features/scripts/schedule-form/schedule-timing.ts +484 -0
  152. package/src/components/features/scripts/script-cells.tsx +29 -0
  153. package/src/components/features/scripts/script-executions-table.tsx +145 -0
  154. package/src/components/features/scripts/script-schedules-table.tsx +113 -0
  155. package/src/components/features/scripts/script-shell-badge.tsx +25 -0
  156. package/src/components/features/scripts/scripts-table-columns.ts +95 -0
  157. package/src/components/features/scripts/scripts-table-shared.tsx +43 -0
  158. package/src/components/features/scripts/scripts-table.tsx +124 -0
  159. package/src/components/features/scripts/scripts-tabs.ts +11 -0
  160. package/src/components/features/scripts/shell-types.ts +26 -0
  161. package/src/components/product-demo/fixtures/scripts.ts +186 -0
  162. package/src/components/product-demo/fixtures/shared.ts +7 -0
  163. package/src/components/product-demo/fixtures/software-update.ts +1 -7
  164. package/src/components/product-demo/product-screen.tsx +3 -1
  165. package/src/components/product-demo/registry.ts +1 -0
  166. package/src/components/product-demo/screen-keys.ts +1 -0
  167. package/src/components/product-demo/screens/scripts.tsx +192 -0
@@ -0,0 +1,288 @@
1
+ import { type ScheduleOfflineBehavior, type ScheduleTimeReference, type ScriptScheduleTrigger } from './schedule-enums';
2
+ /**
3
+ * Timing model helpers for Script Schedules v2.
4
+ *
5
+ * The backend models a schedule's timing as two fields on `ScriptSchedule`:
6
+ * - `startAt: Instant` — the first scheduled run as an absolute **UTC** instant,
7
+ * pinned to a 30-minute boundary (`xx:00` / `xx:30`).
8
+ * - `repeat: Long` — the recurrence interval in **seconds**, a whole number of
9
+ * 30-minute slots (1800, 3600, …). Null / 0 means a one-shot that fires once
10
+ * at `startAt`.
11
+ *
12
+ * The UI offers repeat units that are all clean multiples of 1800s (hour, day,
13
+ * week, month=30d), so anything produced here is always a valid interval on the
14
+ * backend's 30-minute grid. (The backend also accepts a bare 30-minute repeat;
15
+ * the UI simply doesn't surface a sub-hour unit.)
16
+ *
17
+ * Two more fields say what happens when the instant arrives and the device is
18
+ * NOT there — `offlineBehavior` (`SKIP` | `RETRY_ON_RECONNECT`) and, for the
19
+ * latter, `reconnectWindowSeconds`, the deadline past which a queued run is
20
+ * abandoned. They live here because they only mean anything against a scheduled
21
+ * time: a `DEVICE_ONLINE` schedule already fires on reconnect, so it has no
22
+ * offline case to decide and is stored as `SKIP`.
23
+ *
24
+ * **Everything the user sees or picks is their LOCAL wall clock**; UTC exists
25
+ * only on the wire. See `toScheduleInstant` (the host's write side).
26
+ */
27
+ /** True when the schedule is event-driven and has no date/time/repeat. */
28
+ export declare function isEventTrigger(trigger: ScriptScheduleTrigger | string | null | undefined): boolean;
29
+ /**
30
+ * Which clock the picked date + time mean — `timeReference`, the second half of
31
+ * what `startAt` says.
32
+ *
33
+ * - `SERVER` (the default, and what every schedule authored before the field
34
+ * existed carries): `startAt` is an absolute instant. One moment, worldwide.
35
+ * - `DEVICE_LOCAL`: `startAt` carries the picked WALL CLOCK with no zone applied
36
+ * — local 09:00 is stored as `…T09:00:00Z` — and the runner re-bases it into
37
+ * each device's own timezone. One reading, many moments; a fleet across three
38
+ * zones runs at 9 AM three times.
39
+ *
40
+ * The distinction reaches almost every function below, because it decides
41
+ * whether a stored instant is converted through the viewer's offset or read
42
+ * digit for digit: `toScheduleInstant`, {@link fromScheduleInstant},
43
+ * {@link getTimeSlotOptions} (the 30-minute grid is UTC's, and only the SERVER
44
+ * reading has to be shifted onto it) and `formatScheduleStartAt`.
45
+ *
46
+ * A predicate rather than `=== ENUM.X` at the call sites, for the same reason
47
+ * {@link isEventTrigger} is one: Relay types every schema enum with a
48
+ * `%future added value` member, so asking "is it the non-default arm" is what
49
+ * lets an unknown value fall back to SERVER — which is what the write side
50
+ * documents null as meaning.
51
+ */
52
+ export declare function isDeviceLocalTime(timeReference: ScheduleTimeReference | string | null | undefined): boolean;
53
+ /**
54
+ * The units an `[interval] [unit]` pair is built from, finest first — one list,
55
+ * so the dropdowns, the form schema and the seconds table cannot drift apart.
56
+ *
57
+ * Two different settings are spelled in this vocabulary, and they are NOT the
58
+ * same quantity: the repeat cadence (`repeat`, how often the schedule fires) and
59
+ * the reconnect window (`reconnectWindowSeconds`, how long an offline device's
60
+ * queued run is still worth running). They share the units and the seconds
61
+ * table; nothing else. In particular {@link MIN_REPEAT_MINUTES} is a property of
62
+ * the RUNNER'S grid and constrains the cadence only — a reconnect window is a
63
+ * plain deadline and may sit anywhere.
64
+ */
65
+ export declare const DURATION_UNIT_VALUES: readonly ["minute", "hour", "day", "week", "month"];
66
+ export type DurationUnit = (typeof DURATION_UNIT_VALUES)[number];
67
+ export declare const DURATION_UNIT_SECONDS: Record<DurationUnit, number>;
68
+ export declare const DURATION_UNIT_LABELS: Record<DurationUnit, string>;
69
+ /**
70
+ * The smallest cadence the backend's grid allows: `repeat` must be a whole
71
+ * number of 30-minute slots, so 30 minutes is one slot and there is nothing
72
+ * below it. Every other unit clears this by construction (an hour is two slots),
73
+ * which is why the rule only ever has to be enforced on minutes.
74
+ */
75
+ export declare const MIN_REPEAT_MINUTES = 30;
76
+ export declare const DURATION_UNIT_OPTIONS: {
77
+ label: string;
78
+ value: DurationUnit;
79
+ }[];
80
+ /**
81
+ * Snaps a repeat interval onto what its unit can legally express. Only minutes
82
+ * can be illegal — see {@link MIN_REPEAT_MINUTES} — so every other unit is
83
+ * returned untouched.
84
+ *
85
+ * Used when the unit CHANGES: switching "1 Day" to minutes would otherwise leave
86
+ * "1 Minute" sitting in the form, a value the user never typed and cannot save.
87
+ */
88
+ export declare function snapRepeatInterval(interval: number | null, unit: DurationUnit): number | null;
89
+ /**
90
+ * True when a schedule QUEUES a run for a device that was offline at its
91
+ * scheduled time, instead of logging the miss and moving on.
92
+ *
93
+ * The counterpart of {@link isEventTrigger}, and the reason both are predicates
94
+ * rather than `=== ENUM.X` at the call sites: Relay types every schema enum with
95
+ * a `%future added value` member, so a stored value this client doesn't know
96
+ * reads as neither arm. Asking "is it the non-default one" answers that safely —
97
+ * an unknown behavior falls back to SKIP, which is also what the backend
98
+ * documents as the default.
99
+ */
100
+ export declare function isRetryOnReconnect(behavior: ScheduleOfflineBehavior | string | null | undefined): boolean;
101
+ /**
102
+ * The floor on the reconnect window, in minutes.
103
+ *
104
+ * NOT the runner's grid — this field sits on none, the backend accepts any
105
+ * number of seconds. It is the same 30 as {@link MIN_REPEAT_MINUTES} and a
106
+ * separate constant on purpose: that one follows the runner, this one follows
107
+ * the shortest cadence a schedule can have, and there is no reason the two must
108
+ * move together.
109
+ *
110
+ * Unlike the repeat floor it is a MINIMUM only — no multiple-of-30 rule, because
111
+ * there is no grid for a value to land on. A 45-minute window is legal.
112
+ */
113
+ export declare const MIN_RECONNECT_MINUTES = 30;
114
+ /**
115
+ * Raises a reconnect interval to its floor when the unit switches to minutes —
116
+ * the counterpart of {@link snapRepeatInterval}, minus the multiple half.
117
+ *
118
+ * `null` (the field cleared while typing) passes through untouched: snapping it
119
+ * to a number would refill a box the user is in the middle of emptying, which is
120
+ * the behaviour this whole pair of fields was reported for.
121
+ */
122
+ export declare function snapReconnectInterval(interval: number | null, unit: DurationUnit): number | null;
123
+ /**
124
+ * What the "Stop Retry after" pair starts at.
125
+ *
126
+ * The design shows 1 Week (node 460:63425); the product rule is the floor —
127
+ * minutes, at the minimum — so a new schedule starts at the smallest legal
128
+ * window and the user raises it, rather than starting at a week they may not
129
+ * want. It is only ever a SEED: the field is required whenever
130
+ * RETRY_ON_RECONNECT is picked, so every saved schedule carries a window the
131
+ * user could see, and `reconnectWindowSeconds` is never written blind.
132
+ */
133
+ export declare const DEFAULT_RECONNECT_WINDOW: {
134
+ interval: number;
135
+ unit: DurationUnit;
136
+ };
137
+ /**
138
+ * Whether an `HH:mm` the form already holds is a slot the given reading offers.
139
+ *
140
+ * Only ever false where the two grids differ — the 45-minute zones — which is
141
+ * exactly where switching the Timezone control leaves a picked time the new
142
+ * dropdown cannot show. Asked about the GRID and not about the option list, so
143
+ * a stored start that has simply gone by (which the list withholds, and which
144
+ * the form is allowed to keep) is not mistaken for one the grid rejects.
145
+ */
146
+ export declare function isSlotOnGrid(slot: string, timeReference: ScheduleTimeReference | string | null | undefined): boolean;
147
+ /**
148
+ * The Time dropdown's options — one per 30-minute slot of the **local** day,
149
+ * shifted onto the grid `startAt` must land on (see {@link slotBaseMinutes}).
150
+ * `value` is 24h `HH:mm` (what the form stores); `label` is the 12h form.
151
+ *
152
+ * A function rather than a const because the grid depends on the viewer's
153
+ * timezone, which a module evaluated during prerender does not know.
154
+ *
155
+ * `forDate` drops the slots that have already gone by: a schedule cannot start
156
+ * in the past, and offering "8:00 AM" at noon means offering a save the backend
157
+ * refuses. Only a `forDate` of TODAY narrows the list — a later day keeps the
158
+ * full 48, and so does a day not yet picked (the user may well be about to pick
159
+ * tomorrow; picking today afterwards is what clears a time that has gone by).
160
+ * A PAST day keeps them too: it can only be a stored start, and the value that
161
+ * schedule already holds has to stay readable.
162
+ *
163
+ * **None of that narrowing applies to DEVICE_LOCAL**, which keeps all 48 slots
164
+ * always. The reading is not the viewer's clock, so "already gone by" is not the
165
+ * viewer's to judge: the fleet's own clocks span 26 hours (UTC−12 … UTC+14), so
166
+ * 8:00 AM at the author's noon is still hours ahead for every device west of
167
+ * them. Withholding it would hide a perfectly good schedule behind the accident
168
+ * of where the admin sits. See {@link earliestDeviceLocalDay} for the one bound
169
+ * that IS meaningful, and note the backend agrees — it validates no start
170
+ * against the past, for either reading.
171
+ */
172
+ export declare function getTimeSlotOptions(forDate?: Date | null, timeReference?: ScheduleTimeReference | string | null): {
173
+ value: string;
174
+ label: string;
175
+ }[];
176
+ /**
177
+ * The dropdown reading for an `HH:mm` the option list no longer carries — a
178
+ * stored start whose slot has already gone by today. The form's value has to
179
+ * stay VISIBLE (it is what will be saved if nothing else changes), so the Select
180
+ * gets its option back with the same label the live slots use.
181
+ */
182
+ export declare function slotToLabel(slot: string): string;
183
+ /**
184
+ * Local midnight today — the earliest day a schedule may start, and what the
185
+ * date picker takes as its `fromDate`.
186
+ *
187
+ * Midnight rather than "now": the calendar selects whole days, so today has to
188
+ * stay pickable all day long. Which of today's SLOTS are still available is the
189
+ * time dropdown's half of the same rule ({@link getTimeSlotOptions}).
190
+ *
191
+ * Built per call — a module-level constant would freeze the boundary at import
192
+ * time and let a tab left open overnight pick yesterday.
193
+ */
194
+ export declare function startOfToday(): Date;
195
+ /**
196
+ * The earliest day a DEVICE_LOCAL schedule may start: today **as read on the
197
+ * westernmost clock on Earth** (UTC−12), returned as a local `Date` the calendar
198
+ * can take as its `fromDate`.
199
+ *
200
+ * The viewer's own midnight is the wrong bound here. A wall clock is not an
201
+ * instant, so a day is "gone" only once it has gone everywhere — and the fleet's
202
+ * clocks span 26 hours, so for a viewer in Kyiv or Auckland the calendar day
203
+ * that already ended for THEM is still running for a device in Baker Island.
204
+ * Bounding by the viewer would refuse a date that is genuinely in the future for
205
+ * part of the fleet; bounding by UTC−12 refuses only what no device anywhere can
206
+ * still reach.
207
+ *
208
+ * In practice this is today, or yesterday for viewers far enough east — which is
209
+ * the whole of the correction, and it is deliberately the only one: within a day
210
+ * that is still live somewhere, WHICH devices are still ahead of the picked time
211
+ * is the runner's business (it fires each device at its own local reading and
212
+ * marks the ones that have gone past their catch-up window MISSED), not a rule
213
+ * the form can usefully pre-empt.
214
+ */
215
+ export declare function earliestDeviceLocalDay(): Date;
216
+ /**
217
+ * The earliest day the picker may offer, for either reading — the calendar's
218
+ * `fromDate`, and the day the "start in the past" rules measure against.
219
+ */
220
+ export declare function earliestScheduleDay(timeReference?: ScheduleTimeReference | string | null): Date;
221
+ /**
222
+ * Whether a picked day + slot has already gone by. Compared as instants, so a
223
+ * slot that is still minutes away passes.
224
+ *
225
+ * Always false for DEVICE_LOCAL: the pair is a wall clock every device reads on
226
+ * its own timezone, so there is no single instant to have gone by — see
227
+ * {@link getTimeSlotOptions}.
228
+ */
229
+ export declare function isScheduleStartInPast(date: Date | null | undefined, slot: string, timeReference?: ScheduleTimeReference | string | null): boolean;
230
+ /** What both the field and the schema say about a start that has gone by. */
231
+ export declare const PAST_START_MESSAGE = "Start time must be in the future";
232
+ /**
233
+ * What a picked TODAY says once its last 30-minute slot has gone by.
234
+ *
235
+ * The dead end this names: `getTimeSlotOptions` correctly withholds every slot,
236
+ * so the Time dropdown has nothing to offer — and an empty popup states no
237
+ * reason and offers no way on. It is the DATE that has to change, which is why
238
+ * the message says so and why the field showing it is the date's.
239
+ *
240
+ * Not a schema rule: a schedule with no time already fails the save on
241
+ * `scheduledTime` being required. This is the earlier, more useful half of the
242
+ * same fact, said while the user can still act on it.
243
+ */
244
+ export declare const NO_SLOTS_TODAY_MESSAGE = "No start times left today \u2014 pick another day";
245
+ /**
246
+ * The "no start in the past" rule as the FORM applies it — stated once, and read
247
+ * by both the fields (which show it the moment it happens) and the schema (which
248
+ * refuses the save).
249
+ *
250
+ * The exemption is the whole reason it needs a name: a schedule already stored
251
+ * with a past start keeps it. Recurring schedules legitimately started long ago,
252
+ * and without this, renaming one would demand re-picking its date. So the stored
253
+ * instant stays legal for exactly as long as the form still shows it; moving
254
+ * either half makes the choice a new one, held to the same rule as any other.
255
+ *
256
+ * The rule does not exist at all for DEVICE_LOCAL — `isScheduleStartInPast`
257
+ * answers false there — which is why the day bound
258
+ * ({@link earliestDeviceLocalDay}) is the only thing left holding that reading
259
+ * to a future the fleet can still reach.
260
+ */
261
+ export declare function isStartInPastAndChanged(date: Date | null | undefined, slot: string, storedIso: string | null | undefined, timeReference?: ScheduleTimeReference | string | null): boolean;
262
+ /**
263
+ * A picked date → the local `HH:mm` slot it sits on (empty when no date yet).
264
+ *
265
+ * A stored `startAt` always lands on a slot exactly, since the backend enforces
266
+ * the same grid this builds from; the flooring is for values authored outside
267
+ * this UI, and it keeps them on a slot the dropdown can actually show.
268
+ */
269
+ export declare function dateToTimeSlot(date: Date | null | undefined, timeReference?: ScheduleTimeReference | string | null): string;
270
+ /**
271
+ * Applies an `HH:mm` slot to the picked date. Choosing a time before a date
272
+ * anchors it to today — the same fallback the core date-time picker uses.
273
+ */
274
+ export declare function applyTimeSlot(date: Date | null | undefined, slot: string): Date;
275
+ /**
276
+ * Inverse of `toScheduleInstant`: a stored UTC instant → the `Date` for
277
+ * that moment, which the picker and every formatter below then read through the
278
+ * viewer's own clock.
279
+ *
280
+ * A DEVICE_LOCAL start carries no moment to convert — its digits are a wall
281
+ * clock — so they are lifted back out of UTC and rebuilt as LOCAL components.
282
+ * The `Date` that comes back is therefore not the instant the string names; it
283
+ * is the reading, in the only form the pickers and formatters here can hold one.
284
+ * Passing the reference through is what keeps "9 AM on every device" from
285
+ * displaying as noon to the viewer who typed it.
286
+ */
287
+ export declare function fromScheduleInstant(iso: string, timeReference?: ScheduleTimeReference | string | null): Date;
288
+ //# sourceMappingURL=schedule-timing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule-timing.d.ts","sourceRoot":"","sources":["../../../../../src/components/features/scripts/schedule-form/schedule-timing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,165 @@
1
+ "use client";
2
+ import { formatTime } from "../../../../utils/format-date.js";
3
+ import {
4
+ SCHEDULE_OFFLINE_BEHAVIOR,
5
+ SCHEDULE_TIME_REFERENCE,
6
+ SCRIPT_SCHEDULE_TRIGGER
7
+ } from "./schedule-enums.js";
8
+ function isEventTrigger(trigger) {
9
+ return trigger === SCRIPT_SCHEDULE_TRIGGER.DEVICE_ONLINE;
10
+ }
11
+ function isDeviceLocalTime(timeReference) {
12
+ return timeReference === SCHEDULE_TIME_REFERENCE.DEVICE_LOCAL;
13
+ }
14
+ const DURATION_UNIT_VALUES = ["minute", "hour", "day", "week", "month"];
15
+ const DURATION_UNIT_SECONDS = {
16
+ minute: 60,
17
+ hour: 3600,
18
+ day: 86400,
19
+ week: 604800,
20
+ month: 2592e3
21
+ // 30 days — the only "calendar" unit the seconds model can approximate
22
+ };
23
+ const DURATION_UNIT_LABELS = {
24
+ minute: "Minute",
25
+ hour: "Hour",
26
+ day: "Day",
27
+ week: "Week",
28
+ month: "Month"
29
+ };
30
+ const MIN_REPEAT_MINUTES = 30;
31
+ const DURATION_UNIT_OPTIONS = DURATION_UNIT_VALUES.map((value) => ({
32
+ value,
33
+ label: DURATION_UNIT_LABELS[value]
34
+ }));
35
+ function snapRepeatInterval(interval, unit) {
36
+ if (unit !== "minute" || interval === null) return interval;
37
+ if (!Number.isFinite(interval) || interval < MIN_REPEAT_MINUTES) return MIN_REPEAT_MINUTES;
38
+ return Math.ceil(interval / MIN_REPEAT_MINUTES) * MIN_REPEAT_MINUTES;
39
+ }
40
+ function isRetryOnReconnect(behavior) {
41
+ return behavior === SCHEDULE_OFFLINE_BEHAVIOR.RETRY_ON_RECONNECT;
42
+ }
43
+ const MIN_RECONNECT_MINUTES = 30;
44
+ function snapReconnectInterval(interval, unit) {
45
+ if (unit !== "minute" || interval === null) return interval;
46
+ return Math.max(interval, MIN_RECONNECT_MINUTES);
47
+ }
48
+ const DEFAULT_RECONNECT_WINDOW = {
49
+ interval: MIN_RECONNECT_MINUTES,
50
+ unit: "minute"
51
+ };
52
+ const SLOTS_PER_DAY = 48;
53
+ const SLOT_MINUTES = 30;
54
+ function slotBaseMinutes(timeReference) {
55
+ if (isDeviceLocalTime(timeReference)) return 0;
56
+ const offset = (/* @__PURE__ */ new Date()).getTimezoneOffset();
57
+ return (-offset % SLOT_MINUTES + SLOT_MINUTES) % SLOT_MINUTES;
58
+ }
59
+ function isSlotOnGrid(slot, timeReference) {
60
+ if (!slot) return true;
61
+ const [hours, minutes] = slot.split(":").map(Number);
62
+ const offGrid = (hours * 60 + minutes - slotBaseMinutes(timeReference)) % SLOT_MINUTES;
63
+ return (offGrid % SLOT_MINUTES + SLOT_MINUTES) % SLOT_MINUTES === 0;
64
+ }
65
+ function slotValue(minutesOfDay) {
66
+ const hours = Math.floor(minutesOfDay / 60);
67
+ const minutes = minutesOfDay % 60;
68
+ return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
69
+ }
70
+ function slotLabel(minutesOfDay) {
71
+ return formatTime(new Date(1970, 0, 1, Math.floor(minutesOfDay / 60), minutesOfDay % 60));
72
+ }
73
+ function getTimeSlotOptions(forDate, timeReference) {
74
+ const base = slotBaseMinutes(timeReference);
75
+ const cutoff = !isDeviceLocalTime(timeReference) && forDate && isToday(forDate) ? nowMinutesOfDay() : -1;
76
+ return Array.from({ length: SLOTS_PER_DAY }, (_, slot) => {
77
+ const minutesOfDay = base + slot * SLOT_MINUTES;
78
+ return { value: slotValue(minutesOfDay), label: slotLabel(minutesOfDay), minutesOfDay };
79
+ }).filter((slot) => slot.minutesOfDay > cutoff).map(({ value, label }) => ({ value, label }));
80
+ }
81
+ function slotToLabel(slot) {
82
+ const [hours, minutes] = slot.split(":").map(Number);
83
+ return slotLabel(hours * 60 + minutes);
84
+ }
85
+ function nowMinutesOfDay() {
86
+ const now = /* @__PURE__ */ new Date();
87
+ return now.getHours() * 60 + now.getMinutes();
88
+ }
89
+ function isToday(date) {
90
+ const now = /* @__PURE__ */ new Date();
91
+ return date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate();
92
+ }
93
+ function startOfToday() {
94
+ const now = /* @__PURE__ */ new Date();
95
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate());
96
+ }
97
+ function earliestDeviceLocalDay() {
98
+ const westernmostNow = new Date(Date.now() - 12 * 60 * 60 * 1e3);
99
+ return new Date(westernmostNow.getUTCFullYear(), westernmostNow.getUTCMonth(), westernmostNow.getUTCDate());
100
+ }
101
+ function earliestScheduleDay(timeReference) {
102
+ return isDeviceLocalTime(timeReference) ? earliestDeviceLocalDay() : startOfToday();
103
+ }
104
+ function isScheduleStartInPast(date, slot, timeReference) {
105
+ if (!date || !slot || isDeviceLocalTime(timeReference)) return false;
106
+ return applyTimeSlot(date, slot).getTime() < Date.now();
107
+ }
108
+ const PAST_START_MESSAGE = "Start time must be in the future";
109
+ const NO_SLOTS_TODAY_MESSAGE = "No start times left today \u2014 pick another day";
110
+ function isStartInPastAndChanged(date, slot, storedIso, timeReference) {
111
+ if (!isScheduleStartInPast(date, slot, timeReference) || !date) return false;
112
+ const stored = storedIso ? fromScheduleInstant(storedIso, timeReference).getTime() : null;
113
+ return applyTimeSlot(date, slot).getTime() !== stored;
114
+ }
115
+ function dateToTimeSlot(date, timeReference) {
116
+ if (!date) return "";
117
+ const base = slotBaseMinutes(timeReference);
118
+ const minutesOfDay = date.getHours() * 60 + date.getMinutes();
119
+ const slot = Math.min(SLOTS_PER_DAY - 1, Math.max(0, Math.floor((minutesOfDay - base) / SLOT_MINUTES)));
120
+ return slotValue(base + slot * SLOT_MINUTES);
121
+ }
122
+ function applyTimeSlot(date, slot) {
123
+ const [hours, minutes] = slot.split(":").map(Number);
124
+ const next = date ? new Date(date) : /* @__PURE__ */ new Date();
125
+ next.setHours(hours, minutes, 0, 0);
126
+ return next;
127
+ }
128
+ function fromScheduleInstant(iso, timeReference) {
129
+ const instant = new Date(iso);
130
+ if (!isDeviceLocalTime(timeReference)) return instant;
131
+ return new Date(
132
+ instant.getUTCFullYear(),
133
+ instant.getUTCMonth(),
134
+ instant.getUTCDate(),
135
+ instant.getUTCHours(),
136
+ instant.getUTCMinutes()
137
+ );
138
+ }
139
+ export {
140
+ DEFAULT_RECONNECT_WINDOW,
141
+ DURATION_UNIT_LABELS,
142
+ DURATION_UNIT_OPTIONS,
143
+ DURATION_UNIT_SECONDS,
144
+ DURATION_UNIT_VALUES,
145
+ MIN_RECONNECT_MINUTES,
146
+ MIN_REPEAT_MINUTES,
147
+ NO_SLOTS_TODAY_MESSAGE,
148
+ PAST_START_MESSAGE,
149
+ applyTimeSlot,
150
+ dateToTimeSlot,
151
+ earliestDeviceLocalDay,
152
+ earliestScheduleDay,
153
+ fromScheduleInstant,
154
+ getTimeSlotOptions,
155
+ isDeviceLocalTime,
156
+ isEventTrigger,
157
+ isRetryOnReconnect,
158
+ isScheduleStartInPast,
159
+ isSlotOnGrid,
160
+ isStartInPastAndChanged,
161
+ slotToLabel,
162
+ snapReconnectInterval,
163
+ snapRepeatInterval,
164
+ startOfToday
165
+ };
@@ -0,0 +1,11 @@
1
+ /** A name over its description: the first column of both Scripts tables. */
2
+ export declare function ScriptNameCell({ name, description }: {
3
+ name: string;
4
+ description?: string | null;
5
+ }): import("react").JSX.Element;
6
+ /** When a schedule starts: the date over the time (and whose clock the time is read on). */
7
+ export declare function ScheduleDateTimeCell({ date, time }: {
8
+ date: string;
9
+ time: string;
10
+ }): import("react").JSX.Element;
11
+ //# sourceMappingURL=script-cells.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-cells.d.ts","sourceRoot":"","sources":["../../../../src/components/features/scripts/script-cells.tsx"],"names":[],"mappings":"AAIA,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,+BAWlG;AAED,4FAA4F;AAC5F,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,+BASlF"}
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { TruncateText } from "../../ui/truncate-text.js";
4
+ function ScriptNameCell({ name, description }) {
5
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col justify-center gap-1", children: [
6
+ /* @__PURE__ */ jsx(TruncateText, { children: name }),
7
+ description && /* @__PURE__ */ jsx(TruncateText, { variant: "h6", tone: "secondary", children: description })
8
+ ] });
9
+ }
10
+ function ScheduleDateTimeCell({ date, time }) {
11
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col justify-center gap-1", children: [
12
+ /* @__PURE__ */ jsx(TruncateText, { children: date }),
13
+ /* @__PURE__ */ jsx(TruncateText, { variant: "h6", tone: "secondary", children: time })
14
+ ] });
15
+ }
16
+ export {
17
+ ScheduleDateTimeCell,
18
+ ScriptNameCell
19
+ };
@@ -0,0 +1,58 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type ScriptsTableColumnLayout } from './scripts-table-columns';
3
+ /** One execution, as the Execution History shows it. */
4
+ export interface ScriptExecutionTableRow {
5
+ id: string;
6
+ executionId: string;
7
+ /** When it was dispatched, already formatted. */
8
+ timestamp: string;
9
+ /** `'QUEUED'`, `'RUNNING'`, `'SUCCESS'` or `'FAILED'`. */
10
+ status: string;
11
+ machineName: string;
12
+ /** The device's customer. */
13
+ organization?: string | null;
14
+ /** Who it ran for. */
15
+ initiator: {
16
+ name: string;
17
+ initials: string;
18
+ image?: string;
19
+ };
20
+ /** `'MANUAL'`, `'SCHEDULED'` or `'AI_ASSISTANT'`. */
21
+ source?: string | null;
22
+ /** Which script ran: only where a list runs several (a schedule's). */
23
+ scriptName?: string | null;
24
+ /** Everything the run printed. */
25
+ result?: string | null;
26
+ /** The execution's page: the row's link and the open-in-new-tab button. */
27
+ href?: string;
28
+ }
29
+ export interface ScriptExecutionsTableProps {
30
+ rows: ScriptExecutionTableRow[];
31
+ /**
32
+ * The columns and their widths. Defaults to the product's
33
+ * (`EXECUTIONS_TABLE_COLUMNS`); a host narrower than the product's page
34
+ * passes its own arrangement of `EXECUTION_COLUMNS`.
35
+ */
36
+ columns?: readonly ScriptsTableColumnLayout[];
37
+ /** Column ids to leave out (`'result'`, `'open'`). */
38
+ hideColumns?: readonly string[];
39
+ /** Content under a row, inside its card: an execution's output, for one. */
40
+ renderSubRow?: (row: ScriptExecutionTableRow) => ReactNode;
41
+ /** The table's dense rows, as tall as their two lines (the product's page uses the full row). */
42
+ compact?: boolean;
43
+ isLoading?: boolean;
44
+ emptyMessage?: string;
45
+ /** Draw the column header row; a picture short of height leaves it out. */
46
+ showHeader?: boolean;
47
+ /** Rendered at the right edge of the header (a row count). */
48
+ rightSlot?: ReactNode;
49
+ skeletonRows?: number;
50
+ }
51
+ /**
52
+ * The Execution History of a script or a schedule, presentational: every
53
+ * run with its time, status, device and who it ran for. Rows are a view-model
54
+ * the host maps its executions into. The product's own page keeps its live
55
+ * table (filters, paging, the date header) over the same cells and layout.
56
+ */
57
+ export declare function ScriptExecutionsTable({ rows, columns: layout, hideColumns, renderSubRow, compact, isLoading, emptyMessage, showHeader: withHeader, rightSlot, skeletonRows, }: ScriptExecutionsTableProps): import("react").JSX.Element;
58
+ //# sourceMappingURL=script-executions-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-executions-table.d.ts","sourceRoot":"","sources":["../../../../src/components/features/scripts/script-executions-table.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAwB,MAAM,OAAO,CAAC;AAU7D,OAAO,EAA+C,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAGrH,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sBAAsB;IACtB,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,uBAAuB,EAAE,CAAC;IAChC;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,wBAAwB,EAAE,CAAC;IAC9C,sDAAsD;IACtD,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,4EAA4E;IAC5E,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,uBAAuB,KAAK,SAAS,CAAC;IAC3D,iGAAiG;IACjG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,IAAI,EACJ,OAAO,EAAE,MAAiC,EAC1C,WAAW,EACX,YAAY,EACZ,OAAe,EACf,SAAiB,EACjB,YAAqC,EACrC,UAAU,EAAE,UAAiB,EAC7B,SAAS,EACT,YAAiB,GAClB,EAAE,0BAA0B,+BAkE5B"}
@@ -0,0 +1,88 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useMemo } from "react";
4
+ import { DataTable, useDataTable } from "../../ui/data-table/index.js";
5
+ import { SquareAvatar } from "../../ui/square-avatar.js";
6
+ import {
7
+ ExecutionDeviceCell,
8
+ ExecutionInitiatorCell,
9
+ ExecutionResultCell,
10
+ ExecutionStatusCell,
11
+ ExecutionTimestampCell
12
+ } from "./execution-cells.js";
13
+ import { EXECUTION_COLUMNS, EXECUTIONS_TABLE_COLUMNS } from "./scripts-table-columns.js";
14
+ import { OpenInNewTabCell, scriptsColumnMeta } from "./scripts-table-shared.js";
15
+ function ScriptExecutionsTable({
16
+ rows,
17
+ columns: layout = EXECUTIONS_TABLE_COLUMNS,
18
+ hideColumns,
19
+ renderSubRow,
20
+ compact = false,
21
+ isLoading = false,
22
+ emptyMessage = "No executions found.",
23
+ showHeader: withHeader = true,
24
+ rightSlot,
25
+ skeletonRows = 10
26
+ }) {
27
+ const columns = useMemo(() => {
28
+ const renderers = {
29
+ [EXECUTION_COLUMNS.executionId.id]: (row) => /* @__PURE__ */ jsx(ExecutionTimestampCell, { timestamp: row.timestamp, executionId: row.executionId }),
30
+ [EXECUTION_COLUMNS.status.id]: (row) => /* @__PURE__ */ jsx(ExecutionStatusCell, { status: row.status }),
31
+ [EXECUTION_COLUMNS.machineId.id]: (row) => /* @__PURE__ */ jsx(ExecutionDeviceCell, { name: row.machineName, organization: row.organization }),
32
+ [EXECUTION_COLUMNS.initiatorId.id]: (row) => /* @__PURE__ */ jsx(
33
+ ExecutionInitiatorCell,
34
+ {
35
+ avatar: /* @__PURE__ */ jsx(
36
+ SquareAvatar,
37
+ {
38
+ variant: "round",
39
+ size: "md",
40
+ src: row.initiator.image,
41
+ fallback: row.initiator.initials,
42
+ alt: row.initiator.name,
43
+ initialsClassName: "text-ods-text-secondary"
44
+ }
45
+ ),
46
+ name: row.initiator.name,
47
+ source: row.source,
48
+ scriptName: row.scriptName
49
+ }
50
+ ),
51
+ [EXECUTION_COLUMNS.result.id]: (row) => /* @__PURE__ */ jsx(ExecutionResultCell, { result: row.result }),
52
+ [EXECUTION_COLUMNS.open.id]: (row) => row.href ? /* @__PURE__ */ jsx(OpenInNewTabCell, { href: row.href }) : null
53
+ };
54
+ return layout.filter((column) => renderers[column.id] && !hideColumns?.includes(column.id)).map((column) => ({
55
+ id: column.id,
56
+ header: column.header ?? "",
57
+ cell: ({ row }) => renderers[column.id](row.original),
58
+ enableSorting: false,
59
+ meta: scriptsColumnMeta(column)
60
+ }));
61
+ }, [layout, hideColumns]);
62
+ const table = useDataTable({
63
+ data: rows,
64
+ columns,
65
+ getRowId: (row) => row.id,
66
+ enableSorting: false
67
+ });
68
+ const rowHref = useCallback((row) => row.href, []);
69
+ const showHeader = withHeader && (isLoading || rows.length > 0);
70
+ return /* @__PURE__ */ jsxs(DataTable, { table, children: [
71
+ showHeader && /* @__PURE__ */ jsx(DataTable.Header, { rightSlot }),
72
+ /* @__PURE__ */ jsx(
73
+ DataTable.Body,
74
+ {
75
+ loading: isLoading,
76
+ skeletonRows,
77
+ emptyMessage,
78
+ rowClassName: "mb-1",
79
+ compact,
80
+ rowHref,
81
+ renderSubRow
82
+ }
83
+ )
84
+ ] });
85
+ }
86
+ export {
87
+ ScriptExecutionsTable
88
+ };