@flamingo-stack/openframe-frontend-core 0.0.740 → 0.0.742
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/dist/build/export-map.json +1 -1
- package/dist/{chunk-BV5WZVOP.cjs → chunk-32Q7K5OP.cjs} +254 -254
- package/dist/{chunk-ZLTCQKTD.cjs → chunk-3LW43GIJ.cjs} +6 -6
- package/dist/{chunk-VA7OMDZO.cjs → chunk-4FWURR3W.cjs} +50 -50
- package/dist/{chunk-EKGL5K5K.cjs → chunk-4LDU32OB.cjs} +17 -17
- package/dist/{chunk-VC4IV3AY.cjs → chunk-4PKORVOX.cjs} +2804 -954
- package/dist/{chunk-3ZIQOYNX.cjs → chunk-54EA4RLX.cjs} +8 -8
- package/dist/{chunk-YXKB5WRE.cjs → chunk-5MH6BRPY.cjs} +36 -36
- package/dist/{chunk-PQ2M7P2U.cjs → chunk-5TCIRWHL.cjs} +9 -9
- package/dist/{chunk-WFPCCBOM.cjs → chunk-7AM3AFM4.cjs} +10 -10
- package/dist/{chunk-7ZFCR7UY.cjs → chunk-ABLUMGCI.cjs} +3 -3
- package/dist/{chunk-PX7FY655.cjs → chunk-ASMNNSUQ.cjs} +3 -3
- package/dist/{chunk-HF7Z2E4W.cjs → chunk-BI3XBCQX.cjs} +2 -2
- package/dist/{chunk-SA7LDEVJ.cjs → chunk-CSJO7ZGN.cjs} +3 -3
- package/dist/{chunk-VOX4E6AX.cjs → chunk-DGFDBPO7.cjs} +7 -5
- package/dist/{chunk-KHXZFLIN.cjs → chunk-DKOLQPE7.cjs} +8 -2
- package/dist/{chunk-BDA5F6RM.cjs → chunk-DNFSMVXJ.cjs} +16 -16
- package/dist/{chunk-B3XBJCOD.cjs → chunk-H3UA7UY5.cjs} +7 -7
- package/dist/{chunk-2Y5Y4FLM.cjs → chunk-HDBY2URA.cjs} +64 -64
- package/dist/{chunk-UW3YXDC4.cjs → chunk-HIRVNBX5.cjs} +20 -20
- package/dist/{chunk-LLAC2UZ3.cjs → chunk-ISJXKKYW.cjs} +28 -28
- package/dist/{chunk-FICJS5OA.cjs → chunk-KTPR66EE.cjs} +4 -4
- package/dist/{chunk-7UIQPMBJ.cjs → chunk-L34TKFTS.cjs} +21 -164
- package/dist/{chunk-AAFW4STC.cjs → chunk-LU7TD6QS.cjs} +5 -5
- package/dist/{chunk-3HPB4H4C.cjs → chunk-NTGIQP7O.cjs} +7 -7
- package/dist/{chunk-WBANGORJ.cjs → chunk-OBODY7F3.cjs} +3 -3
- package/dist/{chunk-GABDE3FM.cjs → chunk-OWGLRE74.cjs} +19 -19
- package/dist/{chunk-CWRVTQUO.cjs → chunk-PS6T65KA.cjs} +101 -101
- package/dist/{chunk-IFS4AH77.cjs → chunk-QYLIHZKZ.cjs} +10 -10
- package/dist/{chunk-GVTDVS5U.cjs → chunk-R34JD6NP.cjs} +3 -3
- package/dist/{chunk-VU4CKUJW.cjs → chunk-R6SCSV2I.cjs} +103 -103
- package/dist/{chunk-II4QMH26.cjs → chunk-STEJZPIO.cjs} +3 -3
- package/dist/{chunk-4RLGLB45.cjs → chunk-T433HSL6.cjs} +47 -47
- package/dist/{chunk-DSVNFRY5.cjs → chunk-U2O5YQRP.cjs} +38 -38
- package/dist/{chunk-O67V3HJR.cjs → chunk-URVIPSAJ.cjs} +24 -24
- package/dist/{chunk-HYBMADYO.cjs → chunk-UWHCRIQQ.cjs} +22 -22
- package/dist/{chunk-GSWQZX23.cjs → chunk-UY6A6TEY.cjs} +2 -2
- package/dist/{chunk-D5KEWWLW.cjs → chunk-UZLRSFGG.cjs} +32 -32
- package/dist/{chunk-DUVOQHQI.cjs → chunk-W2RM764D.cjs} +7 -7
- package/dist/{chunk-NTJE6SM6.cjs → chunk-WI2OTGKC.cjs} +2 -2
- package/dist/{chunk-SFY4UYPY.cjs → chunk-WIHHA54J.cjs} +44 -44
- package/dist/{chunk-YRE3O65E.cjs → chunk-XAA5EZ5T.cjs} +12 -12
- package/dist/{chunk-KLI4OSRA.cjs → chunk-YQGDXH3M.cjs} +2 -2
- package/dist/{chunk-SWR22DOZ.cjs → chunk-Z2DQYKZA.cjs} +89 -89
- package/dist/{chunk-5SVOGLNK.cjs → chunk-ZIFYSLIM.cjs} +6 -6
- package/dist/{cloud-tenants-PVXDI5MU.cjs → cloud-tenants-6ICAL3HO.cjs} +34 -34
- package/dist/components/case-studies/index.cjs +37 -37
- package/dist/components/chat/index.cjs +17 -17
- package/dist/components/contact/index.cjs +25 -25
- package/dist/components/docs/index.cjs +28 -28
- package/dist/components/embeds/index.cjs +25 -25
- package/dist/components/faq/index.cjs +26 -26
- package/dist/components/features/capability-explorer.d.ts +9 -2
- package/dist/components/features/capability-explorer.d.ts.map +1 -1
- package/dist/components/features/capability-explorer.js +113 -6
- package/dist/components/features/index.cjs +162 -24
- package/dist/components/features/index.d.ts +1 -0
- package/dist/components/features/index.d.ts.map +1 -1
- package/dist/components/features/index.js +1 -0
- package/dist/components/features/scripts/execution-cells.d.ts +65 -0
- package/dist/components/features/scripts/execution-cells.d.ts.map +1 -0
- package/dist/components/features/scripts/execution-cells.js +75 -0
- package/dist/components/features/scripts/execution-status.d.ts +48 -0
- package/dist/components/features/scripts/execution-status.d.ts.map +1 -0
- package/dist/components/features/scripts/execution-status.js +15 -0
- package/dist/components/features/scripts/index.d.ts +20 -0
- package/dist/components/features/scripts/index.d.ts.map +1 -0
- package/dist/components/features/scripts/index.js +59 -0
- package/dist/components/features/scripts/schedule-form/index.d.ts +18 -0
- package/dist/components/features/scripts/schedule-form/index.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/index.js +84 -0
- package/dist/components/features/scripts/schedule-form/schedule-enums.d.ts +24 -0
- package/dist/components/features/scripts/schedule-form/schedule-enums.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-enums.js +18 -0
- package/dist/components/features/scripts/schedule-form/schedule-form-fields.d.ts +57 -0
- package/dist/components/features/scripts/schedule-form/schedule-form-fields.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-form-fields.js +169 -0
- package/dist/components/features/scripts/schedule-form/schedule-form-types.d.ts +138 -0
- package/dist/components/features/scripts/schedule-form/schedule-form-types.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-form-types.js +72 -0
- package/dist/components/features/scripts/schedule-form/schedule-interval-input.d.ts +54 -0
- package/dist/components/features/scripts/schedule-form/schedule-interval-input.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-interval-input.js +60 -0
- package/dist/components/features/scripts/schedule-form/schedule-offline-fields.d.ts +29 -0
- package/dist/components/features/scripts/schedule-form/schedule-offline-fields.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-offline-fields.js +124 -0
- package/dist/components/features/scripts/schedule-form/schedule-script-picker-card.d.ts +52 -0
- package/dist/components/features/scripts/schedule-form/schedule-script-picker-card.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-script-picker-card.js +244 -0
- package/dist/components/features/scripts/schedule-form/schedule-script-search-field.d.ts +35 -0
- package/dist/components/features/scripts/schedule-form/schedule-script-search-field.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-script-search-field.js +58 -0
- package/dist/components/features/scripts/schedule-form/schedule-scripts-field.d.ts +25 -0
- package/dist/components/features/scripts/schedule-form/schedule-scripts-field.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-scripts-field.js +66 -0
- package/dist/components/features/scripts/schedule-form/schedule-timing-fields.d.ts +77 -0
- package/dist/components/features/scripts/schedule-form/schedule-timing-fields.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-timing-fields.js +262 -0
- package/dist/components/features/scripts/schedule-form/schedule-timing.d.ts +288 -0
- package/dist/components/features/scripts/schedule-form/schedule-timing.d.ts.map +1 -0
- package/dist/components/features/scripts/schedule-form/schedule-timing.js +165 -0
- package/dist/components/features/scripts/script-cells.d.ts +11 -0
- package/dist/components/features/scripts/script-cells.d.ts.map +1 -0
- package/dist/components/features/scripts/script-cells.js +19 -0
- package/dist/components/features/scripts/script-executions-table.d.ts +58 -0
- package/dist/components/features/scripts/script-executions-table.d.ts.map +1 -0
- package/dist/components/features/scripts/script-executions-table.js +88 -0
- package/dist/components/features/scripts/script-schedules-table.d.ts +38 -0
- package/dist/components/features/scripts/script-schedules-table.d.ts.map +1 -0
- package/dist/components/features/scripts/script-schedules-table.js +71 -0
- package/dist/components/features/scripts/script-shell-badge.d.ts +9 -0
- package/dist/components/features/scripts/script-shell-badge.d.ts.map +1 -0
- package/dist/components/features/scripts/script-shell-badge.js +15 -0
- package/dist/components/features/scripts/scripts-table-columns.d.ts +162 -0
- package/dist/components/features/scripts/scripts-table-columns.d.ts.map +1 -0
- package/dist/components/features/scripts/scripts-table-columns.js +69 -0
- package/dist/components/features/scripts/scripts-table-shared.d.ts +19 -0
- package/dist/components/features/scripts/scripts-table-shared.d.ts.map +1 -0
- package/dist/components/features/scripts/scripts-table-shared.js +35 -0
- package/dist/components/features/scripts/scripts-table.d.ts +40 -0
- package/dist/components/features/scripts/scripts-table.d.ts.map +1 -0
- package/dist/components/features/scripts/scripts-table.js +84 -0
- package/dist/components/features/scripts/scripts-tabs.d.ts +5 -0
- package/dist/components/features/scripts/scripts-tabs.d.ts.map +1 -0
- package/dist/components/features/scripts/scripts-tabs.js +10 -0
- package/dist/components/features/scripts/shell-types.d.ts +13 -0
- package/dist/components/features/scripts/shell-types.d.ts.map +1 -0
- package/dist/components/features/scripts/shell-types.js +21 -0
- package/dist/components/help-center-pages/index.cjs +144 -144
- package/dist/components/index.cjs +224 -86
- package/dist/components/meeting-scheduler/index.cjs +74 -74
- package/dist/components/navigation/index.cjs +27 -27
- package/dist/components/onboarding-guides/index.cjs +27 -27
- package/dist/components/product-demo/fixtures/scripts.d.ts +34 -0
- package/dist/components/product-demo/fixtures/scripts.d.ts.map +1 -0
- package/dist/components/product-demo/fixtures/scripts.js +123 -0
- package/dist/components/product-demo/fixtures/shared.d.ts +8 -0
- package/dist/components/product-demo/fixtures/shared.d.ts.map +1 -1
- package/dist/components/product-demo/fixtures/shared.js +7 -1
- package/dist/components/product-demo/fixtures/software-update.d.ts.map +1 -1
- package/dist/components/product-demo/fixtures/software-update.js +1 -5
- package/dist/components/product-demo/index.cjs +16 -13
- package/dist/components/product-demo/product-screen.d.ts.map +1 -1
- package/dist/components/product-demo/product-screen.js +2 -1
- package/dist/components/product-demo/registry.d.ts.map +1 -1
- package/dist/components/product-demo/registry.js +2 -1
- package/dist/components/product-demo/screen-keys.cjs +2 -1
- package/dist/components/product-demo/screen-keys.d.ts +1 -0
- package/dist/components/product-demo/screen-keys.d.ts.map +1 -1
- package/dist/components/product-demo/screen-keys.js +2 -1
- package/dist/components/product-demo/screens/scripts.d.ts +11 -0
- package/dist/components/product-demo/screens/scripts.d.ts.map +1 -0
- package/dist/components/product-demo/screens/scripts.js +130 -0
- package/dist/components/related-content/index.cjs +12 -12
- package/dist/components/tickets/index.cjs +30 -30
- package/dist/components/ui/index.cjs +24 -24
- package/dist/{devices-TWEA7XOR.cjs → devices-OFP2IBKN.cjs} +30 -30
- package/dist/{embeddable-chat-6JKKFQEB.cjs → embeddable-chat-4C22MGNC.cjs} +92 -92
- package/dist/hooks/index.cjs +10 -10
- package/dist/index.cjs +169 -31
- package/dist/{knowledge-4GQDBNQB.cjs → knowledge-KKBCSNUA.cjs} +29 -29
- package/dist/{logs-EVU6GJHZ.cjs → logs-X2GRNO57.cjs} +46 -46
- package/dist/{policies-OZUEA5YS.cjs → policies-35BXKB6P.cjs} +31 -31
- package/dist/{remote-session-DNFZ5OLY.cjs → remote-session-N4PJB5FW.cjs} +15 -15
- package/dist/scripts-KQYVQOLU.cjs +2112 -0
- package/dist/{software-update-BLIVYOY2.cjs → software-update-ED33WSKT.cjs} +36 -40
- package/dist/{tickets-board-CKZRB6YV.cjs → tickets-board-O753S4ZB.cjs} +31 -31
- package/dist/utils/embed-authed-fetch.d.ts +33 -0
- package/dist/utils/embed-authed-fetch.d.ts.map +1 -1
- package/dist/utils/embed-authed-fetch.js +3 -1
- package/dist/utils/index.cjs +3 -1
- package/dist/{video-file-player-ZH2ILAPO.cjs → video-file-player-QZ3YOLHO.cjs} +2 -2
- package/package.json +1 -1
- package/src/components/features/capability-explorer.tsx +134 -7
- package/src/components/features/index.ts +1 -0
- package/src/components/features/scripts/execution-cells.tsx +149 -0
- package/src/components/features/scripts/execution-status.ts +42 -0
- package/src/components/features/scripts/index.ts +42 -0
- package/src/components/features/scripts/schedule-form/index.ts +59 -0
- package/src/components/features/scripts/schedule-form/schedule-enums.ts +26 -0
- package/src/components/features/scripts/schedule-form/schedule-form-fields.tsx +249 -0
- package/src/components/features/scripts/schedule-form/schedule-form-types.ts +189 -0
- package/src/components/features/scripts/schedule-form/schedule-interval-input.tsx +121 -0
- package/src/components/features/scripts/schedule-form/schedule-offline-fields.tsx +218 -0
- package/src/components/features/scripts/schedule-form/schedule-script-picker-card.tsx +321 -0
- package/src/components/features/scripts/schedule-form/schedule-script-search-field.tsx +115 -0
- package/src/components/features/scripts/schedule-form/schedule-scripts-field.tsx +97 -0
- package/src/components/features/scripts/schedule-form/schedule-timing-fields.tsx +482 -0
- package/src/components/features/scripts/schedule-form/schedule-timing.ts +484 -0
- package/src/components/features/scripts/script-cells.tsx +29 -0
- package/src/components/features/scripts/script-executions-table.tsx +145 -0
- package/src/components/features/scripts/script-schedules-table.tsx +113 -0
- package/src/components/features/scripts/script-shell-badge.tsx +25 -0
- package/src/components/features/scripts/scripts-table-columns.ts +95 -0
- package/src/components/features/scripts/scripts-table-shared.tsx +43 -0
- package/src/components/features/scripts/scripts-table.tsx +124 -0
- package/src/components/features/scripts/scripts-tabs.ts +11 -0
- package/src/components/features/scripts/shell-types.ts +26 -0
- package/src/components/product-demo/fixtures/scripts.ts +186 -0
- package/src/components/product-demo/fixtures/shared.ts +7 -0
- package/src/components/product-demo/fixtures/software-update.ts +1 -7
- package/src/components/product-demo/product-screen.tsx +3 -1
- package/src/components/product-demo/registry.ts +1 -0
- package/src/components/product-demo/screen-keys.ts +1 -0
- package/src/components/product-demo/screens/scripts.tsx +192 -0
- package/src/utils/embed-authed-fetch.ts +42 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
import { cn } from '../../../utils/cn';
|
|
5
|
+
import { AgentMark } from '../../agent-mark';
|
|
6
|
+
import { MonitorIcon } from '../../icons-v2-generated/devices/monitor-icon';
|
|
7
|
+
import { Tag } from '../../ui/tag';
|
|
8
|
+
import { TruncateText } from '../../ui/truncate-text';
|
|
9
|
+
import { scriptExecutionStatus } from './execution-status';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The cells of the Execution History (Figma 155:38356) and the Result block
|
|
13
|
+
* of an execution's page. Each takes display values: the product maps its
|
|
14
|
+
* Relay records into them and keeps what only it has (links to an employee
|
|
15
|
+
* page, the deleted-user avatar) as slots.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** How an execution was dispatched, as the chip beside the person it ran for. */
|
|
19
|
+
export function ExecutionSourceBadge({ source, className }: { source: string | null | undefined; className?: string }) {
|
|
20
|
+
// A `span`: the chip sits inside a line of text. It never shrinks; the name beside it ellipsizes.
|
|
21
|
+
// Labels are sentence case here; the Tag's h5 type scale uppercases them.
|
|
22
|
+
const tagProps = { as: 'span', variant: 'outline', className: cn('shrink-0', className) } as const;
|
|
23
|
+
|
|
24
|
+
if (source === 'SCHEDULED') return <Tag {...tagProps} label="Scheduled" />;
|
|
25
|
+
if (source === 'AI_ASSISTANT') {
|
|
26
|
+
// Mingo's own mark, the way the product stamps it everywhere else.
|
|
27
|
+
return <Tag {...tagProps} label="Mingo" icon={<AgentMark agent="mingo" className="size-4" />} />;
|
|
28
|
+
}
|
|
29
|
+
// MANUAL draws nothing: the person is the technician who clicked Run, so a chip would restate the name.
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The Execution column: when it was dispatched over its id. The date filter
|
|
35
|
+
* sits on this column's header because its first line is that date.
|
|
36
|
+
*/
|
|
37
|
+
export function ExecutionTimestampCell({ timestamp, executionId }: { timestamp: string; executionId: string }) {
|
|
38
|
+
return (
|
|
39
|
+
<div className="flex min-w-0 flex-col justify-center gap-1">
|
|
40
|
+
<TruncateText>{timestamp}</TruncateText>
|
|
41
|
+
<TruncateText variant="h6" tone="secondary">
|
|
42
|
+
{executionId}
|
|
43
|
+
</TruncateText>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A status as its tag; the flex row keeps the tag at its own width in a stretch column. */
|
|
49
|
+
export function ExecutionStatusCell({ status }: { status: string | null | undefined }) {
|
|
50
|
+
const presentation = scriptExecutionStatus(status);
|
|
51
|
+
return (
|
|
52
|
+
<div className="flex">
|
|
53
|
+
<Tag label={presentation?.label ?? String(status ?? '')} variant={presentation?.variant ?? 'grey'} />
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The device an execution ran on, with its customer under it. The icon rides
|
|
60
|
+
* with the name only; the customer line starts under the icon, as the design
|
|
61
|
+
* has it. `name` is a node so a host can draw its own empty mark.
|
|
62
|
+
*/
|
|
63
|
+
export function ExecutionDeviceCell({ name, organization }: { name: ReactNode; organization?: string | null }) {
|
|
64
|
+
return (
|
|
65
|
+
<div className="flex min-w-0 flex-col justify-center gap-1">
|
|
66
|
+
<div className="flex min-w-0 items-center gap-1">
|
|
67
|
+
<MonitorIcon className="size-6 shrink-0 text-ods-text-secondary" />
|
|
68
|
+
{/* So the name shrinks and ellipsizes next to the icon. */}
|
|
69
|
+
<div className="min-w-0 flex-1">{typeof name === 'string' ? <TruncateText>{name}</TruncateText> : name}</div>
|
|
70
|
+
</div>
|
|
71
|
+
{organization && (
|
|
72
|
+
<TruncateText variant="h6" tone="secondary">
|
|
73
|
+
{organization}
|
|
74
|
+
</TruncateText>
|
|
75
|
+
)}
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Who an execution ran for, with the chip of what dispatched it: a schedule or
|
|
82
|
+
* Mingo runs on a technician's behalf, so the chip qualifies the name instead
|
|
83
|
+
* of standing in for it. The script's name is the second line where a list
|
|
84
|
+
* runs several scripts (a schedule's); a script's own list leaves it out.
|
|
85
|
+
* The avatar and the name are slots: the product links the name to the
|
|
86
|
+
* person's page and draws a deleted account its own way.
|
|
87
|
+
*/
|
|
88
|
+
export function ExecutionInitiatorCell({
|
|
89
|
+
avatar,
|
|
90
|
+
name,
|
|
91
|
+
source,
|
|
92
|
+
scriptName,
|
|
93
|
+
}: {
|
|
94
|
+
avatar: ReactNode;
|
|
95
|
+
name: ReactNode;
|
|
96
|
+
source?: string | null;
|
|
97
|
+
scriptName?: string | null;
|
|
98
|
+
}) {
|
|
99
|
+
return (
|
|
100
|
+
<div className="flex min-w-0 flex-1 items-center gap-[var(--spacing-system-xsf)]">
|
|
101
|
+
{avatar}
|
|
102
|
+
<div className="flex min-w-0 flex-1 flex-col justify-center">
|
|
103
|
+
<div className="flex min-w-0 items-center gap-[var(--spacing-system-xxs)]">
|
|
104
|
+
{typeof name === 'string' ? <TruncateText>{name}</TruncateText> : name}
|
|
105
|
+
<ExecutionSourceBadge source={source} />
|
|
106
|
+
</div>
|
|
107
|
+
{scriptName && (
|
|
108
|
+
<TruncateText variant="h6" tone="secondary">
|
|
109
|
+
{scriptName}
|
|
110
|
+
</TruncateText>
|
|
111
|
+
)}
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The Result column: the first two lines of what the run printed, or the host's empty mark. */
|
|
118
|
+
export function ExecutionResultCell({ result, empty = null }: { result?: string | null; empty?: ReactNode }) {
|
|
119
|
+
return result ? <TruncateText lines={2}>{result}</TruncateText> : <>{empty}</>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* What an execution printed, as its page shows it: the whole output with its
|
|
124
|
+
* line breaks, labelled "Result". A run still in flight with nothing printed
|
|
125
|
+
* yet says so (its page polls, so the output streams in) instead of a dead
|
|
126
|
+
* end; a finished run with no output shows the host's empty mark.
|
|
127
|
+
*/
|
|
128
|
+
export function ScriptExecutionResult({
|
|
129
|
+
result,
|
|
130
|
+
inFlight = false,
|
|
131
|
+
empty,
|
|
132
|
+
className,
|
|
133
|
+
}: {
|
|
134
|
+
result?: string | null;
|
|
135
|
+
inFlight?: boolean;
|
|
136
|
+
empty: ReactNode;
|
|
137
|
+
className?: string;
|
|
138
|
+
}) {
|
|
139
|
+
return (
|
|
140
|
+
<div className={cn('flex flex-col gap-[var(--spacing-system-xxs)] p-[var(--spacing-system-m)]', className)}>
|
|
141
|
+
{result ? (
|
|
142
|
+
<div className="whitespace-pre-wrap break-words text-ods-text-primary text-h4">{result}</div>
|
|
143
|
+
) : (
|
|
144
|
+
<div className="text-ods-text-secondary text-h4">{inFlight ? 'Waiting for output…' : empty}</div>
|
|
145
|
+
)}
|
|
146
|
+
<div className="text-ods-text-secondary text-h6">Result</div>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a script execution's status and source are presented: one table, read
|
|
3
|
+
* by the product's Execution History, its execution page and the pictures of
|
|
4
|
+
* them. No JSX and no imports, so a server module or a skeleton can read it.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** The statuses a script execution has (the product's `ScriptExecutionStatus`). */
|
|
8
|
+
export type ScriptExecutionStatus = 'QUEUED' | 'RUNNING' | 'SUCCESS' | 'FAILED';
|
|
9
|
+
|
|
10
|
+
/** How an execution was dispatched (the product's `ExecutionSource`). */
|
|
11
|
+
export type ScriptExecutionSource = 'MANUAL' | 'SCHEDULED' | 'AI_ASSISTANT';
|
|
12
|
+
|
|
13
|
+
/** The `Tag` colour a status is drawn in. */
|
|
14
|
+
export type ScriptExecutionStatusVariant = 'success' | 'error' | 'warning' | 'grey';
|
|
15
|
+
|
|
16
|
+
export interface ScriptExecutionStatusPresentation {
|
|
17
|
+
/** Human label (SUCCESS reads as "Completed"). */
|
|
18
|
+
label: string;
|
|
19
|
+
variant: ScriptExecutionStatusVariant;
|
|
20
|
+
/** Not a final state: a page showing it polls until it is. */
|
|
21
|
+
inFlight: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Every status, exhaustively. A host whose API grows a status checks its own
|
|
26
|
+
* enum against these keys, so a new status fails to compile there instead of
|
|
27
|
+
* landing in a grey tag with its raw value.
|
|
28
|
+
*/
|
|
29
|
+
export const SCRIPT_EXECUTION_STATUS_PRESENTATION = {
|
|
30
|
+
QUEUED: { label: 'Queued', variant: 'grey', inFlight: true },
|
|
31
|
+
RUNNING: { label: 'Running', variant: 'warning', inFlight: true },
|
|
32
|
+
SUCCESS: { label: 'Completed', variant: 'success', inFlight: false },
|
|
33
|
+
FAILED: { label: 'Failed', variant: 'error', inFlight: false },
|
|
34
|
+
} as const satisfies Record<ScriptExecutionStatus, ScriptExecutionStatusPresentation>;
|
|
35
|
+
|
|
36
|
+
/** The presentation of a status, or undefined for a value the table does not know. */
|
|
37
|
+
export function scriptExecutionStatus(
|
|
38
|
+
status: string | null | undefined,
|
|
39
|
+
): ScriptExecutionStatusPresentation | undefined {
|
|
40
|
+
if (!status || !Object.prototype.hasOwnProperty.call(SCRIPT_EXECUTION_STATUS_PRESENTATION, status)) return undefined;
|
|
41
|
+
return SCRIPT_EXECUTION_STATUS_PRESENTATION[status as ScriptExecutionStatus];
|
|
42
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
ExecutionDeviceCell,
|
|
5
|
+
ExecutionInitiatorCell,
|
|
6
|
+
ExecutionResultCell,
|
|
7
|
+
ExecutionSourceBadge,
|
|
8
|
+
ExecutionStatusCell,
|
|
9
|
+
ExecutionTimestampCell,
|
|
10
|
+
ScriptExecutionResult,
|
|
11
|
+
} from './execution-cells';
|
|
12
|
+
export { SCRIPT_EXECUTION_STATUS_PRESENTATION, scriptExecutionStatus } from './execution-status';
|
|
13
|
+
export type {
|
|
14
|
+
ScriptExecutionSource,
|
|
15
|
+
ScriptExecutionStatus,
|
|
16
|
+
ScriptExecutionStatusPresentation,
|
|
17
|
+
ScriptExecutionStatusVariant,
|
|
18
|
+
} from './execution-status';
|
|
19
|
+
export { ScheduleDateTimeCell, ScriptNameCell } from './script-cells';
|
|
20
|
+
export { ScriptExecutionsTable } from './script-executions-table';
|
|
21
|
+
export type { ScriptExecutionsTableProps, ScriptExecutionTableRow } from './script-executions-table';
|
|
22
|
+
export { ScriptSchedulesTable } from './script-schedules-table';
|
|
23
|
+
export type { ScriptScheduleTableRow, ScriptSchedulesTableProps } from './script-schedules-table';
|
|
24
|
+
export { ScriptShellBadge } from './script-shell-badge';
|
|
25
|
+
export type { ScriptShellBadgeProps } from './script-shell-badge';
|
|
26
|
+
export { ScriptsTable } from './scripts-table';
|
|
27
|
+
export type { ScriptsTableProps, ScriptTableRow } from './scripts-table';
|
|
28
|
+
export {
|
|
29
|
+
EXECUTION_COLUMNS,
|
|
30
|
+
EXECUTIONS_TABLE_COLUMNS,
|
|
31
|
+
SCHEDULE_COLUMNS,
|
|
32
|
+
SCHEDULES_TABLE_COLUMNS,
|
|
33
|
+
SCRIPT_COLUMNS,
|
|
34
|
+
SCRIPTS_TAB_WIDTHS,
|
|
35
|
+
SCRIPTS_TABLE_COLUMNS,
|
|
36
|
+
} from './scripts-table-columns';
|
|
37
|
+
export type { ScriptsTableColumnLayout } from './scripts-table-columns';
|
|
38
|
+
export { OpenInNewTabCell, RowActionsCell, scriptsColumnMeta } from './scripts-table-shared';
|
|
39
|
+
export { SCRIPTS_TABS } from './scripts-tabs';
|
|
40
|
+
export type { ScriptsTabId } from './scripts-tabs';
|
|
41
|
+
export { SCRIPT_SHELL_TYPES, scriptShellLabel, scriptShellType } from './shell-types';
|
|
42
|
+
export * from './schedule-form';
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
export { SCHEDULE_OFFLINE_BEHAVIOR, SCHEDULE_TIME_REFERENCE, SCRIPT_SCHEDULE_TRIGGER } from './schedule-enums';
|
|
4
|
+
export type { ScheduleOfflineBehavior, ScheduleTimeReference, ScriptScheduleTrigger } from './schedule-enums';
|
|
5
|
+
export { ScheduleFormFields } from './schedule-form-fields';
|
|
6
|
+
export type { ScheduleFormFieldsProps } from './schedule-form-fields';
|
|
7
|
+
export {
|
|
8
|
+
DEFAULT_SCHEDULE_FORM_VALUES,
|
|
9
|
+
EMPTY_SCHEDULE_SCRIPT_ROW,
|
|
10
|
+
SCHEDULE_OFFLINE_BEHAVIOR_OPTIONS,
|
|
11
|
+
SCHEDULE_TIME_REFERENCE_OPTIONS,
|
|
12
|
+
SCHEDULE_TRIGGER_OPTIONS,
|
|
13
|
+
} from './schedule-form-types';
|
|
14
|
+
export type {
|
|
15
|
+
RenderScheduleScriptSearch,
|
|
16
|
+
ScheduleFormData,
|
|
17
|
+
ScheduleFormEnvVar,
|
|
18
|
+
ScheduleFormGate,
|
|
19
|
+
ScheduleFormScriptRow,
|
|
20
|
+
ScheduleScriptSearchSlotProps,
|
|
21
|
+
ScheduleTimeSlot,
|
|
22
|
+
} from './schedule-form-types';
|
|
23
|
+
export { ScheduleIntervalInput } from './schedule-interval-input';
|
|
24
|
+
export { ScheduleOfflineFields } from './schedule-offline-fields';
|
|
25
|
+
export { ScheduleScriptPickerCard } from './schedule-script-picker-card';
|
|
26
|
+
export { ScheduleScriptSearchField } from './schedule-script-search-field';
|
|
27
|
+
export type { ScheduleScriptSearchFieldProps, ScheduleScriptSearchResult } from './schedule-script-search-field';
|
|
28
|
+
export { ScheduleScriptsField } from './schedule-scripts-field';
|
|
29
|
+
export type { ScheduleScriptsFieldProps } from './schedule-scripts-field';
|
|
30
|
+
export { ScheduleTimingFields } from './schedule-timing-fields';
|
|
31
|
+
export type { ScheduleTimingFieldsProps } from './schedule-timing-fields';
|
|
32
|
+
export {
|
|
33
|
+
applyTimeSlot,
|
|
34
|
+
dateToTimeSlot,
|
|
35
|
+
DEFAULT_RECONNECT_WINDOW,
|
|
36
|
+
DURATION_UNIT_LABELS,
|
|
37
|
+
DURATION_UNIT_OPTIONS,
|
|
38
|
+
DURATION_UNIT_SECONDS,
|
|
39
|
+
DURATION_UNIT_VALUES,
|
|
40
|
+
earliestDeviceLocalDay,
|
|
41
|
+
earliestScheduleDay,
|
|
42
|
+
fromScheduleInstant,
|
|
43
|
+
getTimeSlotOptions,
|
|
44
|
+
isDeviceLocalTime,
|
|
45
|
+
isEventTrigger,
|
|
46
|
+
isRetryOnReconnect,
|
|
47
|
+
isScheduleStartInPast,
|
|
48
|
+
isSlotOnGrid,
|
|
49
|
+
isStartInPastAndChanged,
|
|
50
|
+
MIN_RECONNECT_MINUTES,
|
|
51
|
+
MIN_REPEAT_MINUTES,
|
|
52
|
+
NO_SLOTS_TODAY_MESSAGE,
|
|
53
|
+
PAST_START_MESSAGE,
|
|
54
|
+
slotToLabel,
|
|
55
|
+
snapReconnectInterval,
|
|
56
|
+
snapRepeatInterval,
|
|
57
|
+
startOfToday,
|
|
58
|
+
} from './schedule-timing';
|
|
59
|
+
export type { DurationUnit } from './schedule-timing';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three schedule enums the form branches on, with the values the OpenFrame
|
|
3
|
+
* API uses. A host's generated enums carry the same strings, so its values and
|
|
4
|
+
* these are assignable both ways.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** What fires a schedule: a date and time, or a device coming online. */
|
|
8
|
+
export const SCRIPT_SCHEDULE_TRIGGER = {
|
|
9
|
+
DATE_TIME: 'DATE_TIME',
|
|
10
|
+
DEVICE_ONLINE: 'DEVICE_ONLINE',
|
|
11
|
+
} as const;
|
|
12
|
+
export type ScriptScheduleTrigger = (typeof SCRIPT_SCHEDULE_TRIGGER)[keyof typeof SCRIPT_SCHEDULE_TRIGGER];
|
|
13
|
+
|
|
14
|
+
/** Which clock a schedule's date and time mean: the account's, or each device's. */
|
|
15
|
+
export const SCHEDULE_TIME_REFERENCE = {
|
|
16
|
+
SERVER: 'SERVER',
|
|
17
|
+
DEVICE_LOCAL: 'DEVICE_LOCAL',
|
|
18
|
+
} as const;
|
|
19
|
+
export type ScheduleTimeReference = (typeof SCHEDULE_TIME_REFERENCE)[keyof typeof SCHEDULE_TIME_REFERENCE];
|
|
20
|
+
|
|
21
|
+
/** What a schedule does with a device that is offline when it fires. */
|
|
22
|
+
export const SCHEDULE_OFFLINE_BEHAVIOR = {
|
|
23
|
+
SKIP: 'SKIP',
|
|
24
|
+
RETRY_ON_RECONNECT: 'RETRY_ON_RECONNECT',
|
|
25
|
+
} as const;
|
|
26
|
+
export type ScheduleOfflineBehavior = (typeof SCHEDULE_OFFLINE_BEHAVIOR)[keyof typeof SCHEDULE_OFFLINE_BEHAVIOR];
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use no memo';
|
|
3
|
+
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
import { Controller, useFormContext, useWatch } from 'react-hook-form';
|
|
6
|
+
import { useContentMdUp } from '../../../../hooks/ui/use-content-breakpoint';
|
|
7
|
+
import { OS_PLATFORMS, type OSPlatformOption } from '../../../../utils/os-platforms';
|
|
8
|
+
import { Input } from '../../../ui/input';
|
|
9
|
+
import { Label } from '../../../ui/label';
|
|
10
|
+
import { RadioGroupBlock } from '../../../ui/radio-group';
|
|
11
|
+
import { Textarea } from '../../../ui/textarea';
|
|
12
|
+
import { TruncateText } from '../../../ui/truncate-text';
|
|
13
|
+
import { SelectButton } from '../../select-button';
|
|
14
|
+
import type { ScheduleTimeReference } from './schedule-enums';
|
|
15
|
+
import {
|
|
16
|
+
type RenderScheduleScriptSearch,
|
|
17
|
+
SCHEDULE_TRIGGER_OPTIONS,
|
|
18
|
+
type ScheduleFormData,
|
|
19
|
+
type ScheduleFormGate,
|
|
20
|
+
type ScheduleTimeSlot,
|
|
21
|
+
} from './schedule-form-types';
|
|
22
|
+
import { ScheduleOfflineFields } from './schedule-offline-fields';
|
|
23
|
+
import { ScheduleScriptsField } from './schedule-scripts-field';
|
|
24
|
+
import { ScheduleTimingFields } from './schedule-timing-fields';
|
|
25
|
+
|
|
26
|
+
export interface ScheduleFormFieldsProps {
|
|
27
|
+
showErrors: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Locks every control. This is the edit page's loading state: the real fields,
|
|
30
|
+
* in the geometry they will keep, with nothing in them yet — so there is no
|
|
31
|
+
* placeholder to swap for them when the schedule lands.
|
|
32
|
+
*/
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* The "Select Script" field of each script card. Searching the script library
|
|
36
|
+
* is the host's query, so the field is a slot: the product passes its
|
|
37
|
+
* data-bound search, a fixture a static one (both draw
|
|
38
|
+
* `ScheduleScriptSearchField`).
|
|
39
|
+
*/
|
|
40
|
+
renderScriptSearch: RenderScheduleScriptSearch;
|
|
41
|
+
/** Whether the Timezone picker is offered: the host's flag, as a gate. Default `off`. */
|
|
42
|
+
timeReferenceGate?: ScheduleFormGate;
|
|
43
|
+
/** The platforms "Supported Platform" offers. Default: every OS platform. */
|
|
44
|
+
platforms?: ReadonlyArray<OSPlatformOption>;
|
|
45
|
+
/** Platform ids shown but not selectable yet ("Coming Soon"). Default none. */
|
|
46
|
+
comingSoonPlatforms?: ReadonlyArray<string>;
|
|
47
|
+
/** The Time dropdown's options; see `ScheduleTimingFields`. Default: the viewer's own clock. */
|
|
48
|
+
getTimeSlots?: (date: Date | null, timeReference: ScheduleTimeReference) => ScheduleTimeSlot[];
|
|
49
|
+
/**
|
|
50
|
+
* `stacked` (default): the name is a row of its own, over the rest. `inline`:
|
|
51
|
+
* on a wide form it sits beside the Date / Time / Repeat row, for a host that
|
|
52
|
+
* shows only those (the sections between them hidden).
|
|
53
|
+
*/
|
|
54
|
+
nameLayout?: 'stacked' | 'inline';
|
|
55
|
+
/** The "Note" field. Default true. */
|
|
56
|
+
showNote?: boolean;
|
|
57
|
+
/** The trigger choice (on a schedule, or when a device comes online). Default true. */
|
|
58
|
+
showTrigger?: boolean;
|
|
59
|
+
/** "Supported Platform". Default true. */
|
|
60
|
+
showPlatforms?: boolean;
|
|
61
|
+
/** "If device is offline at scheduled time". Default true. */
|
|
62
|
+
showOfflineBehavior?: boolean;
|
|
63
|
+
/** The "Scheduled Scripts" heading over the script cards. Default true. */
|
|
64
|
+
showScriptsHeading?: boolean;
|
|
65
|
+
/** Each script card's arguments and environment variables. Default true. */
|
|
66
|
+
showScriptParams?: boolean;
|
|
67
|
+
/** Offer "Add Script". Default true; false is a form of the scripts it opens with. */
|
|
68
|
+
addScripts?: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Every field of the schedule form, in the order the design has them. Reads the
|
|
73
|
+
* form off context, so the page around it only owns the chrome and the Save.
|
|
74
|
+
*
|
|
75
|
+
* The defaults are the product's page. The layout props are for a host that
|
|
76
|
+
* shows the form in less room (a picture of it): fewer sections, and the name
|
|
77
|
+
* beside the timing.
|
|
78
|
+
*/
|
|
79
|
+
export function ScheduleFormFields({
|
|
80
|
+
showErrors,
|
|
81
|
+
disabled = false,
|
|
82
|
+
renderScriptSearch,
|
|
83
|
+
timeReferenceGate = 'off',
|
|
84
|
+
platforms = OS_PLATFORMS,
|
|
85
|
+
comingSoonPlatforms = [],
|
|
86
|
+
getTimeSlots,
|
|
87
|
+
nameLayout = 'stacked',
|
|
88
|
+
showNote = true,
|
|
89
|
+
showTrigger = true,
|
|
90
|
+
showPlatforms = true,
|
|
91
|
+
showOfflineBehavior = true,
|
|
92
|
+
showScriptsHeading = true,
|
|
93
|
+
showScriptParams = true,
|
|
94
|
+
addScripts = true,
|
|
95
|
+
}: ScheduleFormFieldsProps) {
|
|
96
|
+
const { control, formState, getValues, setValue } = useFormContext<ScheduleFormData>();
|
|
97
|
+
const isMdUp = useContentMdUp();
|
|
98
|
+
const supportedPlatforms = useWatch({ control, name: 'supportedPlatforms' });
|
|
99
|
+
|
|
100
|
+
const togglePlatform = useCallback(
|
|
101
|
+
(platform: string) => {
|
|
102
|
+
const current = getValues('supportedPlatforms');
|
|
103
|
+
const has = current.includes(platform);
|
|
104
|
+
// Allow deselecting any item, including the last one — the "at least one
|
|
105
|
+
// platform" rule is enforced by validation on submit (mirrors the script form).
|
|
106
|
+
setValue('supportedPlatforms', has ? current.filter(p => p !== platform) : [...current, platform], {
|
|
107
|
+
shouldValidate: true,
|
|
108
|
+
shouldDirty: true,
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
[getValues, setValue],
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const nameField = (
|
|
115
|
+
<div className="flex flex-col gap-[var(--spacing-system-xxs)]">
|
|
116
|
+
<Label className="text-h4">Schedule Name</Label>
|
|
117
|
+
<Controller
|
|
118
|
+
name="name"
|
|
119
|
+
control={control}
|
|
120
|
+
render={({ field, fieldState }) => (
|
|
121
|
+
<Input
|
|
122
|
+
placeholder="Enter schedule name"
|
|
123
|
+
value={field.value}
|
|
124
|
+
onChange={field.onChange}
|
|
125
|
+
disabled={disabled}
|
|
126
|
+
className="w-full"
|
|
127
|
+
error={showErrors ? fieldState.error?.message : undefined}
|
|
128
|
+
invalid={showErrors && !!fieldState.error}
|
|
129
|
+
/>
|
|
130
|
+
)}
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// The min-1 error overlays the section gap below the row (same absolute
|
|
136
|
+
// pattern as the script form) — no layout shift. `data-invalid`: the block
|
|
137
|
+
// has no input of its own, so it carries the marker itself, which is what
|
|
138
|
+
// `scrollToFirstInvalidField` looks for.
|
|
139
|
+
const platformField = (
|
|
140
|
+
<div
|
|
141
|
+
className="relative flex flex-col gap-[var(--spacing-system-xxs)]"
|
|
142
|
+
data-invalid={(showErrors && !!formState.errors.supportedPlatforms) || undefined}
|
|
143
|
+
>
|
|
144
|
+
<Label className="text-h4">Supported Platform</Label>
|
|
145
|
+
<div className="grid grid-cols-2 gap-[var(--spacing-system-mf)] content-md:grid-cols-4">
|
|
146
|
+
{platforms.map(platform => {
|
|
147
|
+
const comingSoon = comingSoonPlatforms.includes(platform.id);
|
|
148
|
+
return (
|
|
149
|
+
<SelectButton
|
|
150
|
+
key={platform.id}
|
|
151
|
+
title={platform.name}
|
|
152
|
+
icon={<platform.icon className="h-5 w-5" />}
|
|
153
|
+
selected={!comingSoon && supportedPlatforms.includes(platform.id)}
|
|
154
|
+
disabled={comingSoon || disabled}
|
|
155
|
+
tag={comingSoon ? (isMdUp ? 'Coming Soon' : 'Soon') : undefined}
|
|
156
|
+
onClick={comingSoon || disabled ? undefined : () => togglePlatform(platform.id)}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
})}
|
|
160
|
+
</div>
|
|
161
|
+
{showErrors && formState.errors.supportedPlatforms && (
|
|
162
|
+
<div className="absolute bottom-0 left-0 right-0 translate-y-full">
|
|
163
|
+
<TruncateText variant="h6" className="text-ods-error">
|
|
164
|
+
{formState.errors.supportedPlatforms.message ?? ''}
|
|
165
|
+
</TruncateText>
|
|
166
|
+
</div>
|
|
167
|
+
)}
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const timingFields = (
|
|
172
|
+
<ScheduleTimingFields
|
|
173
|
+
showErrors={showErrors}
|
|
174
|
+
disabled={disabled}
|
|
175
|
+
timeReferenceGate={timeReferenceGate}
|
|
176
|
+
getTimeSlots={getTimeSlots}
|
|
177
|
+
/>
|
|
178
|
+
);
|
|
179
|
+
const nameInline = nameLayout === 'inline';
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<div className="flex flex-col gap-[var(--spacing-system-lf)]">
|
|
183
|
+
{nameInline ? (
|
|
184
|
+
<div className="flex flex-col gap-[var(--spacing-system-lf)] content-md:flex-row content-md:items-start">
|
|
185
|
+
<div className="min-w-0 content-md:flex-1">{nameField}</div>
|
|
186
|
+
<div className="min-w-0 content-md:flex-[3]">{timingFields}</div>
|
|
187
|
+
</div>
|
|
188
|
+
) : (
|
|
189
|
+
nameField
|
|
190
|
+
)}
|
|
191
|
+
|
|
192
|
+
{/* "Note" in the UI, `description` on the backend. */}
|
|
193
|
+
{showNote && (
|
|
194
|
+
<div className="flex flex-col gap-[var(--spacing-system-xxs)]">
|
|
195
|
+
<Label className="text-h4">Note</Label>
|
|
196
|
+
<Controller
|
|
197
|
+
name="description"
|
|
198
|
+
control={control}
|
|
199
|
+
render={({ field }) => (
|
|
200
|
+
<Textarea
|
|
201
|
+
placeholder="Enter note here (optional)"
|
|
202
|
+
value={field.value}
|
|
203
|
+
onChange={field.onChange}
|
|
204
|
+
disabled={disabled}
|
|
205
|
+
className="min-h-[96px] w-full"
|
|
206
|
+
/>
|
|
207
|
+
)}
|
|
208
|
+
/>
|
|
209
|
+
</div>
|
|
210
|
+
)}
|
|
211
|
+
|
|
212
|
+
{/* What fires the schedule. DEVICE_ONLINE is event-driven and carries no
|
|
213
|
+
timing, so picking it collapses the Date & Time row below. */}
|
|
214
|
+
{showTrigger && (
|
|
215
|
+
<Controller
|
|
216
|
+
name="trigger"
|
|
217
|
+
control={control}
|
|
218
|
+
render={({ field }) => (
|
|
219
|
+
<RadioGroupBlock
|
|
220
|
+
variant="grouped"
|
|
221
|
+
value={field.value}
|
|
222
|
+
onValueChange={field.onChange}
|
|
223
|
+
disabled={disabled}
|
|
224
|
+
options={SCHEDULE_TRIGGER_OPTIONS}
|
|
225
|
+
/>
|
|
226
|
+
)}
|
|
227
|
+
/>
|
|
228
|
+
)}
|
|
229
|
+
|
|
230
|
+
{showPlatforms && platformField}
|
|
231
|
+
|
|
232
|
+
{!nameInline && timingFields}
|
|
233
|
+
|
|
234
|
+
{/* Hangs off the same answer as the timing above it — "if device is
|
|
235
|
+
offline at scheduled time" presupposes one — so it collapses for the
|
|
236
|
+
event trigger too, and the two blocks animate together. */}
|
|
237
|
+
{showOfflineBehavior && <ScheduleOfflineFields showErrors={showErrors} disabled={disabled} />}
|
|
238
|
+
|
|
239
|
+
<ScheduleScriptsField
|
|
240
|
+
showErrors={showErrors}
|
|
241
|
+
disabled={disabled}
|
|
242
|
+
renderScriptSearch={renderScriptSearch}
|
|
243
|
+
showHeading={showScriptsHeading}
|
|
244
|
+
showScriptParams={showScriptParams}
|
|
245
|
+
addScripts={addScripts}
|
|
246
|
+
/>
|
|
247
|
+
</div>
|
|
248
|
+
);
|
|
249
|
+
}
|