@flamingo-stack/openframe-frontend-core 0.0.715 → 0.0.716
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/{chunk-W4CS6UJS.cjs → chunk-2V7D5GJX.cjs} +3 -3
- package/dist/{chunk-AQI74KC7.js → chunk-3AJIQPFG.js} +3 -3
- package/dist/{chunk-EORJFB2Z.cjs → chunk-5IJXM3RU.cjs} +2 -2
- package/dist/{chunk-DI5VLY3G.js → chunk-64F6OEEV.js} +1 -1
- package/dist/{chunk-JHSPIDV5.js → chunk-BVZ7W4HW.js} +1 -1
- package/dist/{chunk-2LZ3IYGT.js → chunk-C5AGSZBT.js} +2268 -2209
- package/dist/{chunk-S66W6HNZ.cjs → chunk-DHMO5GI4.cjs} +10 -10
- package/dist/{chunk-WEEZSGFD.cjs → chunk-DLEO53NX.cjs} +23 -23
- package/dist/{chunk-4GFAKUHF.js → chunk-DPX6244M.js} +1 -1
- package/dist/{chunk-GXHWSAV6.cjs → chunk-I5F2OTFE.cjs} +15 -15
- package/dist/{chunk-VBDGMXZO.js → chunk-JCA5MBVY.js} +1 -1
- package/dist/{chunk-XFFIUXVI.cjs → chunk-KNOZVVCU.cjs} +2 -2
- package/dist/{chunk-OQVGA3YE.js → chunk-KYFNFRSV.js} +1 -1
- package/dist/{chunk-BIFUUH4K.js → chunk-MXPQMQI3.js} +3 -3
- package/dist/{chunk-U4WCFIYB.cjs → chunk-NKILEG3Y.cjs} +22 -22
- package/dist/{chunk-QW7KTWLB.js → chunk-P7IL4CX3.js} +2 -2
- package/dist/{chunk-ZSJ6WWFH.cjs → chunk-S2VWQX6T.cjs} +190 -131
- package/dist/{chunk-LTLHCAZY.cjs → chunk-STCJYO2Z.cjs} +4 -4
- package/dist/{chunk-KSEOIICU.js → chunk-V36WGIYR.js} +2 -2
- package/dist/{chunk-E25A235W.cjs → chunk-X2MNNV5H.cjs} +3 -3
- package/dist/{chunk-5MMCYJAJ.cjs → chunk-YO5JB3WE.cjs} +11 -11
- package/dist/{chunk-VKIRTB7K.js → chunk-YTMV4OBY.js} +1 -1
- package/dist/{cloud-tenants-MI7APZJD.cjs → cloud-tenants-2J7CPTKT.cjs} +2 -2
- package/dist/{cloud-tenants-NSEVWC26.js → cloud-tenants-YOY2WLGC.js} +1 -1
- package/dist/components/case-studies/index.cjs +10 -10
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/approval-level.d.ts +30 -22
- package/dist/components/features/approval-level.d.ts.map +1 -1
- package/dist/components/features/index.cjs +2 -4
- package/dist/components/features/index.js +3 -5
- package/dist/components/help-center-pages/index.cjs +39 -39
- package/dist/components/help-center-pages/index.js +10 -10
- package/dist/components/index.cjs +18 -18
- package/dist/components/index.js +12 -12
- package/dist/components/meeting-scheduler/index.cjs +11 -11
- package/dist/components/meeting-scheduler/index.js +1 -1
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/onboarding-guides/index.cjs +4 -4
- package/dist/components/onboarding-guides/index.js +3 -3
- package/dist/components/product-demo/index.cjs +6 -6
- package/dist/components/product-demo/index.js +6 -6
- package/dist/components/tickets/index.cjs +5 -5
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/analyzing-state.d.ts +17 -0
- package/dist/components/ui/analyzing-state.d.ts.map +1 -0
- package/dist/components/ui/feature-list.d.ts +4 -4
- package/dist/components/ui/feature-list.d.ts.map +1 -1
- package/dist/components/ui/incident-feed.d.ts +4 -1
- package/dist/components/ui/incident-feed.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +4 -2
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +3 -1
- package/dist/components/ui/playback-toggle.d.ts +10 -4
- package/dist/components/ui/playback-toggle.d.ts.map +1 -1
- package/dist/components/ui/tab-navigation.d.ts +7 -1
- package/dist/components/ui/tab-navigation.d.ts.map +1 -1
- package/dist/{devices-6NMK4EXV.cjs → devices-5NADSKDZ.cjs} +3 -3
- package/dist/{devices-W3VKQEVZ.js → devices-EQXXILXW.js} +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.js +6 -6
- package/dist/{knowledge-GDMGHFEC.cjs → knowledge-LHQYZJE7.cjs} +2 -2
- package/dist/{knowledge-YWCB7HNC.js → knowledge-YCQITBJB.js} +1 -1
- package/dist/{logs-7QDRV3GN.cjs → logs-DUVKSQU3.cjs} +10 -10
- package/dist/{logs-E742S5A2.js → logs-LZNXGOSW.js} +1 -1
- package/dist/{policies-BEVF6AEM.cjs → policies-5H74FS4S.cjs} +6 -6
- package/dist/{policies-XTPAKRHI.js → policies-VYWOJ7IF.js} +1 -1
- package/dist/{software-update-FXWIEKSW.js → software-update-MSDY3OLX.js} +1 -1
- package/dist/{software-update-KPHX4XQ7.cjs → software-update-VRRX5U4W.cjs} +6 -6
- package/package.json +1 -1
- package/src/components/features/approval-level.tsx +62 -44
- package/src/components/ui/analyzing-state.tsx +57 -0
- package/src/components/ui/feature-list.tsx +26 -16
- package/src/components/ui/incident-feed.tsx +6 -2
- package/src/components/ui/index.ts +1 -0
- package/src/components/ui/playback-toggle.tsx +12 -6
- package/src/components/ui/tab-navigation.tsx +12 -1
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
isMegaMenu,
|
|
34
34
|
navLinkLabel,
|
|
35
35
|
siteNavHasMobileMenus
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-BVZ7W4HW.js";
|
|
37
37
|
import {
|
|
38
38
|
MobileNavigationDropdown,
|
|
39
39
|
MultiLevelNavigation,
|
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
AlertDialogTrigger,
|
|
74
74
|
AlertTitle,
|
|
75
75
|
AllowedDomainsInput,
|
|
76
|
+
AnalyzingState,
|
|
76
77
|
AnnouncementBarView,
|
|
77
78
|
AppLayoutDrawerBody,
|
|
78
79
|
AppLayoutDrawerClose,
|
|
@@ -85,8 +86,7 @@ import {
|
|
|
85
86
|
AppLayoutDrawerTrigger,
|
|
86
87
|
AppStoreBadge,
|
|
87
88
|
AppWindowFrame,
|
|
88
|
-
|
|
89
|
-
ApprovalLevelMark,
|
|
89
|
+
ApprovalLevelView,
|
|
90
90
|
ApprovalRequestNotificationTile,
|
|
91
91
|
ArrayEntryManager,
|
|
92
92
|
ArticleDetailLayout,
|
|
@@ -565,7 +565,7 @@ import {
|
|
|
565
565
|
useTrackerClock,
|
|
566
566
|
useWalkthroughVideo,
|
|
567
567
|
usersCountLabel
|
|
568
|
-
} from "./chunk-
|
|
568
|
+
} from "./chunk-C5AGSZBT.js";
|
|
569
569
|
import {
|
|
570
570
|
Board,
|
|
571
571
|
BoardColumn,
|
|
@@ -2129,6 +2129,7 @@ export {
|
|
|
2129
2129
|
AlertTitle,
|
|
2130
2130
|
AlertTriangleIcon,
|
|
2131
2131
|
AllowedDomainsInput,
|
|
2132
|
+
AnalyzingState,
|
|
2132
2133
|
AnnouncementBarView,
|
|
2133
2134
|
AppHeader,
|
|
2134
2135
|
AppLayout,
|
|
@@ -2145,8 +2146,7 @@ export {
|
|
|
2145
2146
|
AppWindowFrame,
|
|
2146
2147
|
AppleIcon,
|
|
2147
2148
|
ApprovalBatchMessage,
|
|
2148
|
-
|
|
2149
|
-
ApprovalLevelMark,
|
|
2149
|
+
ApprovalLevelView,
|
|
2150
2150
|
ApprovalRequestMessage,
|
|
2151
2151
|
ApprovalRequestNotificationTile,
|
|
2152
2152
|
ApprovalStatusTag,
|
|
@@ -8,7 +8,7 @@ var _chunkII4QMH26cjs = require('./chunk-II4QMH26.cjs');
|
|
|
8
8
|
var _chunkKHXZFLINcjs = require('./chunk-KHXZFLIN.cjs');
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
var
|
|
11
|
+
var _chunkS2VWQX6Tcjs = require('./chunk-S2VWQX6T.cjs');
|
|
12
12
|
require('./chunk-4HJRHEXD.cjs');
|
|
13
13
|
require('./chunk-HQQE74RO.cjs');
|
|
14
14
|
require('./chunk-DEY6XXGO.cjs');
|
|
@@ -96,7 +96,7 @@ function KnowledgeScreen(_props) {
|
|
|
96
96
|
const cast = _chunkII4QMH26cjs.useProductDemoCast.call(void 0, );
|
|
97
97
|
const fixture = _react.useMemo.call(void 0, () => buildKnowledgeFixture(cast), [cast]);
|
|
98
98
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full bg-ods-bg", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
99
|
-
|
|
99
|
+
_chunkS2VWQX6Tcjs.KnowledgeBaseArticleView,
|
|
100
100
|
{
|
|
101
101
|
...fixture.article,
|
|
102
102
|
content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHETQETPVcjs.SimpleMarkdownRenderer, { content: fixture.content, textSize: "compact" })
|
|
@@ -16,7 +16,7 @@ var _chunkKHXZFLINcjs = require('./chunk-KHXZFLIN.cjs');
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
var
|
|
19
|
+
var _chunkS2VWQX6Tcjs = require('./chunk-S2VWQX6T.cjs');
|
|
20
20
|
require('./chunk-4HJRHEXD.cjs');
|
|
21
21
|
require('./chunk-HQQE74RO.cjs');
|
|
22
22
|
require('./chunk-DEY6XXGO.cjs');
|
|
@@ -77,7 +77,7 @@ function entry(logId, minutesAgo, severity, toolType, device2, summary) {
|
|
|
77
77
|
id: logId,
|
|
78
78
|
logId,
|
|
79
79
|
timestamp: displayTime(_chunkKHXZFLINcjs.demoMinutesAgo.call(void 0, minutesAgo)),
|
|
80
|
-
status: { label: severity, variant:
|
|
80
|
+
status: { label: severity, variant: _chunkS2VWQX6Tcjs.logSeverityVariant.call(void 0, severity) },
|
|
81
81
|
source: { name: toolType, toolType },
|
|
82
82
|
device: device2,
|
|
83
83
|
description: { title: summary }
|
|
@@ -149,13 +149,13 @@ var NO_FILTERS = {};
|
|
|
149
149
|
var ACTION_COLUMNS = ["copy", "quickView", "open"];
|
|
150
150
|
var BESIDE_DRAWER_HIDDEN = [...ACTION_COLUMNS, "tool", "source"];
|
|
151
151
|
var logHref = () => "#";
|
|
152
|
-
var copyAction = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
152
|
+
var copyAction = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkS2VWQX6Tcjs.LogCopyIconButton, {});
|
|
153
153
|
function LogsScreen({ compact = false }) {
|
|
154
154
|
const [dock, setDock] = _react.useState.call(void 0, null);
|
|
155
155
|
const selected = LOGS_FIXTURE_SELECTED;
|
|
156
156
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full bg-ods-bg", children: [
|
|
157
157
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "min-w-0 flex-1 overflow-clip", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
158
|
-
|
|
158
|
+
_chunkS2VWQX6Tcjs.LogsPageView,
|
|
159
159
|
{
|
|
160
160
|
showHeader: false,
|
|
161
161
|
className: "p-[var(--spacing-system-l)]",
|
|
@@ -163,7 +163,7 @@ function LogsScreen({ compact = false }) {
|
|
|
163
163
|
onSearchChange: noop,
|
|
164
164
|
onOpenFilters: noop,
|
|
165
165
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
166
|
-
|
|
166
|
+
_chunkS2VWQX6Tcjs.LogsTableView,
|
|
167
167
|
{
|
|
168
168
|
logs: LOGS_FIXTURE_ENTRIES,
|
|
169
169
|
facets: LOGS_FIXTURE_FACETS,
|
|
@@ -177,8 +177,8 @@ function LogsScreen({ compact = false }) {
|
|
|
177
177
|
)
|
|
178
178
|
}
|
|
179
179
|
) }),
|
|
180
|
-
!compact && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: setDock, className: "relative w-[calc(400px+var(--spacing-system-m))] shrink-0", children: dock && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
181
|
-
|
|
180
|
+
!compact && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref: setDock, className: "relative w-[calc(400px+var(--spacing-system-m))] shrink-0", children: dock && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkS2VWQX6Tcjs.AppLayoutDrawerContainerContext.Provider, { value: dock, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
181
|
+
_chunkS2VWQX6Tcjs.LogDrawer,
|
|
182
182
|
{
|
|
183
183
|
docked: true,
|
|
184
184
|
isOpen: true,
|
|
@@ -190,12 +190,12 @@ function LogsScreen({ compact = false }) {
|
|
|
190
190
|
{ label: "Log ID", value: selected.logId },
|
|
191
191
|
{
|
|
192
192
|
label: "Source",
|
|
193
|
-
value: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
193
|
+
value: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkS2VWQX6Tcjs.ToolBadge, { toolType: _chunkHETQETPVcjs.normalizeToolTypeWithFallback.call(void 0, selected.source.toolType) })
|
|
194
194
|
},
|
|
195
|
-
{ label: "Device", value:
|
|
195
|
+
{ label: "Device", value: _chunkS2VWQX6Tcjs.logSourceLabels.call(void 0, selected.device).deviceName }
|
|
196
196
|
],
|
|
197
197
|
deviceCard: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
198
|
-
|
|
198
|
+
_chunkS2VWQX6Tcjs.DeviceCard,
|
|
199
199
|
{
|
|
200
200
|
...LOGS_FIXTURE_DEVICE,
|
|
201
201
|
actions: {
|
|
@@ -10,7 +10,7 @@ var _chunkKHXZFLINcjs = require('./chunk-KHXZFLIN.cjs');
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var _chunkS2VWQX6Tcjs = require('./chunk-S2VWQX6T.cjs');
|
|
14
14
|
require('./chunk-4HJRHEXD.cjs');
|
|
15
15
|
require('./chunk-HQQE74RO.cjs');
|
|
16
16
|
require('./chunk-DEY6XXGO.cjs');
|
|
@@ -82,14 +82,14 @@ var POLICIES = [
|
|
|
82
82
|
policy("policy-local-admins", "No local admins", "No everyday account is a local administrator.", false, 0)
|
|
83
83
|
];
|
|
84
84
|
var POLICIES_FIXTURE = {
|
|
85
|
-
summary:
|
|
85
|
+
summary: _chunkS2VWQX6Tcjs.computePolicySummary.call(void 0, POLICIES),
|
|
86
86
|
rows: POLICIES.map((item) => ({
|
|
87
87
|
id: item.id,
|
|
88
88
|
name: item.name,
|
|
89
89
|
description: item.description,
|
|
90
90
|
critical: item.critical,
|
|
91
91
|
severityLabel: item.critical ? "Critical" : "Low",
|
|
92
|
-
status:
|
|
92
|
+
status: _chunkS2VWQX6Tcjs.getPolicyTableStatus.call(void 0, item),
|
|
93
93
|
actions: [
|
|
94
94
|
{ label: "Policy Details", onClick: noop },
|
|
95
95
|
{ label: "Delete Policy", onClick: noop }
|
|
@@ -103,16 +103,16 @@ var POLICIES_FIXTURE = {
|
|
|
103
103
|
var _jsxruntime = require('react/jsx-runtime');
|
|
104
104
|
function PoliciesScreen({ compact = false }) {
|
|
105
105
|
const table = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
106
|
-
|
|
106
|
+
_chunkS2VWQX6Tcjs.PoliciesTable,
|
|
107
107
|
{
|
|
108
108
|
rows: POLICIES_FIXTURE.rows,
|
|
109
109
|
rowAsLink: true,
|
|
110
|
-
rightSlot: compact ? void 0 : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
110
|
+
rightSlot: compact ? void 0 : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkS2VWQX6Tcjs.DataTable.RowCount, {}),
|
|
111
111
|
emptyMessage: "No policies found."
|
|
112
112
|
}
|
|
113
113
|
);
|
|
114
114
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-[var(--spacing-system-l)] bg-ods-bg p-[var(--spacing-system-l)]", children: [
|
|
115
|
-
!compact && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
115
|
+
!compact && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkS2VWQX6Tcjs.PolicySummaryCards, { summary: POLICIES_FIXTURE.summary, now: POLICIES_FIXTURE.now }),
|
|
116
116
|
table
|
|
117
117
|
] });
|
|
118
118
|
}
|
|
@@ -16,7 +16,7 @@ var _chunkKHXZFLINcjs = require('./chunk-KHXZFLIN.cjs');
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
var
|
|
19
|
+
var _chunkS2VWQX6Tcjs = require('./chunk-S2VWQX6T.cjs');
|
|
20
20
|
require('./chunk-4HJRHEXD.cjs');
|
|
21
21
|
require('./chunk-HQQE74RO.cjs');
|
|
22
22
|
require('./chunk-DEY6XXGO.cjs');
|
|
@@ -114,14 +114,14 @@ var noop = () => {
|
|
|
114
114
|
var HIDDEN_WHEN_COMPACT = ["organization"];
|
|
115
115
|
function StaticPackageField({ value }) {
|
|
116
116
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
117
|
-
|
|
117
|
+
_chunkS2VWQX6Tcjs.Autocomplete,
|
|
118
118
|
{
|
|
119
|
-
label:
|
|
119
|
+
label: _chunkS2VWQX6Tcjs.PACKAGE_SEARCH_LABEL,
|
|
120
120
|
labelVariant: "large",
|
|
121
121
|
options: value ? [{ value: value.id, label: value.name, description: _nullishCoalesce(value.description, () => ( void 0)) }] : [],
|
|
122
122
|
value: _nullishCoalesce(_optionalChain([value, 'optionalAccess', _ => _.id]), () => ( null)),
|
|
123
123
|
onChange: noop,
|
|
124
|
-
placeholder:
|
|
124
|
+
placeholder: _chunkS2VWQX6Tcjs.PACKAGE_SEARCH_PLACEHOLDER
|
|
125
125
|
}
|
|
126
126
|
);
|
|
127
127
|
}
|
|
@@ -135,7 +135,7 @@ function SoftwareUpdateScreen({ compact = false }) {
|
|
|
135
135
|
[fixture.devices, fixture.selectedIds]
|
|
136
136
|
);
|
|
137
137
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full bg-ods-bg pt-[var(--spacing-system-l)]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-full", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
138
|
-
|
|
138
|
+
_chunkS2VWQX6Tcjs.SoftwareActionForm,
|
|
139
139
|
{
|
|
140
140
|
action: fixture.action,
|
|
141
141
|
showHeader: false,
|
|
@@ -147,7 +147,7 @@ function SoftwareUpdateScreen({ compact = false }) {
|
|
|
147
147
|
initialValues: fixture.initialValues,
|
|
148
148
|
renderPackageSearch,
|
|
149
149
|
renderDevicePicker: () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
150
|
-
|
|
150
|
+
_chunkS2VWQX6Tcjs.DeviceSelector,
|
|
151
151
|
{
|
|
152
152
|
devices: selected,
|
|
153
153
|
loading: false,
|
package/package.json
CHANGED
|
@@ -30,8 +30,8 @@ export interface ApprovalLevelMeta {
|
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* THE look and wording of an approval level: its name, its one-line meaning,
|
|
33
|
-
* its icon and its colour. The guardrails panel's dropdown
|
|
34
|
-
* below
|
|
33
|
+
* its icon and its colour. The guardrails panel's dropdown and `ApprovalLevelView`
|
|
34
|
+
* below read it, so a level is the same everywhere.
|
|
35
35
|
*/
|
|
36
36
|
export const APPROVAL_LEVEL_META: Record<ApprovalLevel, ApprovalLevelMeta> = {
|
|
37
37
|
ALLOW: {
|
|
@@ -57,61 +57,79 @@ export const APPROVAL_LEVEL_META: Record<ApprovalLevel, ApprovalLevelMeta> = {
|
|
|
57
57
|
|
|
58
58
|
const ICON_PX = 16;
|
|
59
59
|
|
|
60
|
-
export interface
|
|
61
|
-
level
|
|
62
|
-
/** Icon only: the name is the mark's accessible name and its tooltip. Default false (icon and name). */
|
|
63
|
-
iconOnly?: boolean;
|
|
64
|
-
className?: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** One level, read-only: its icon in its colour, with its name beside it or as its tooltip. */
|
|
68
|
-
export function ApprovalLevelMark({ level, iconOnly = false, className }: ApprovalLevelMarkProps) {
|
|
69
|
-
const { label, hint, Icon, toneClassName } = APPROVAL_LEVEL_META[level];
|
|
70
|
-
const mark = (
|
|
71
|
-
<span className={cn('inline-flex items-center gap-[var(--spacing-system-xxs)] text-h6', toneClassName, className)}>
|
|
72
|
-
<Icon size={ICON_PX} className="shrink-0" aria-hidden />
|
|
73
|
-
{iconOnly ? <span className="sr-only">{label}</span> : label}
|
|
74
|
-
</span>
|
|
75
|
-
);
|
|
76
|
-
return iconOnly ? (
|
|
77
|
-
<TouchFriendlyTooltip content={`${label}: ${hint}`} side="top">
|
|
78
|
-
{mark}
|
|
79
|
-
</TouchFriendlyTooltip>
|
|
80
|
-
) : (
|
|
81
|
-
mark
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface ApprovalLevelControlProps {
|
|
60
|
+
export interface ApprovalLevelViewProps {
|
|
61
|
+
/** The level in force. */
|
|
86
62
|
value: ApprovalLevel;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Whether the level can be changed here. `false`: the level's own icon.
|
|
65
|
+
* `true`: four icons, one per level, in a single-choice group. Default: true
|
|
66
|
+
* when `onChange` is given.
|
|
67
|
+
*/
|
|
68
|
+
editable?: boolean;
|
|
69
|
+
/** Editable: the level picked. */
|
|
70
|
+
onChange?: (level: ApprovalLevel) => void;
|
|
71
|
+
/** Editable: the group is shown and cannot be changed (a locked rule). */
|
|
92
72
|
disabled?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The level's name, written before the icons. Default true: a row reads
|
|
75
|
+
* without hovering, and on touch. False keeps the name as the accessible
|
|
76
|
+
* name (and, read-only, as the icon's tooltip).
|
|
77
|
+
*/
|
|
78
|
+
showLabel?: boolean;
|
|
79
|
+
/** Editable: the id of the element that names what is being decided (the rule's label). */
|
|
80
|
+
'aria-labelledby'?: string;
|
|
93
81
|
className?: string;
|
|
94
82
|
}
|
|
95
83
|
|
|
96
84
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
85
|
+
* THE way a level is shown, read-only or editable, by one prop: the level's
|
|
86
|
+
* name in its colour, then its icon (read-only) or the four levels' icons as a
|
|
87
|
+
* single-choice group (editable; arrow keys move, like every toggle group).
|
|
88
|
+
* Name, icon, colour and tooltip are `APPROVAL_LEVEL_META`'s in both, so a
|
|
89
|
+
* rule reads the same on a page that shows it and on one that lets it change.
|
|
90
|
+
*
|
|
91
|
+
* Editable, each icon has its level's name as its accessible name and a
|
|
92
|
+
* tooltip with what the level means (hover or keyboard focus; a tap selects).
|
|
102
93
|
*/
|
|
103
|
-
export function
|
|
94
|
+
export function ApprovalLevelView({
|
|
104
95
|
value,
|
|
96
|
+
editable,
|
|
105
97
|
onChange,
|
|
106
|
-
'aria-labelledby': labelledBy,
|
|
107
|
-
showLabel = true,
|
|
108
98
|
disabled = false,
|
|
99
|
+
showLabel = true,
|
|
100
|
+
'aria-labelledby': labelledBy,
|
|
109
101
|
className,
|
|
110
|
-
}:
|
|
102
|
+
}: ApprovalLevelViewProps) {
|
|
111
103
|
const current = APPROVAL_LEVEL_META[value];
|
|
104
|
+
const canEdit = editable ?? onChange !== undefined;
|
|
105
|
+
const name = showLabel ? (
|
|
106
|
+
<span className={cn('whitespace-nowrap text-h6', current.toneClassName)}>{current.label}</span>
|
|
107
|
+
) : null;
|
|
108
|
+
|
|
109
|
+
if (!canEdit) {
|
|
110
|
+
const icon = (
|
|
111
|
+
<span className={cn('inline-flex shrink-0', current.toneClassName)}>
|
|
112
|
+
<current.Icon size={ICON_PX} aria-hidden />
|
|
113
|
+
{!showLabel && <span className="sr-only">{current.label}</span>}
|
|
114
|
+
</span>
|
|
115
|
+
);
|
|
116
|
+
return (
|
|
117
|
+
<span className={cn('inline-flex shrink-0 items-center gap-[var(--spacing-system-xxs)]', className)}>
|
|
118
|
+
{name}
|
|
119
|
+
{showLabel ? (
|
|
120
|
+
icon
|
|
121
|
+
) : (
|
|
122
|
+
<TouchFriendlyTooltip content={`${current.label}: ${current.hint}`} side="top">
|
|
123
|
+
{icon}
|
|
124
|
+
</TouchFriendlyTooltip>
|
|
125
|
+
)}
|
|
126
|
+
</span>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
112
130
|
return (
|
|
113
131
|
<div className={cn('flex shrink-0 items-center gap-[var(--spacing-system-sf)]', className)}>
|
|
114
|
-
{
|
|
132
|
+
{name}
|
|
115
133
|
<TooltipProvider delayDuration={150}>
|
|
116
134
|
<ToggleGroup
|
|
117
135
|
type="single"
|
|
@@ -121,7 +139,7 @@ export function ApprovalLevelControl({
|
|
|
121
139
|
disabled={disabled}
|
|
122
140
|
// Clicking the level in force reports '' (deselect): a rule always has a level.
|
|
123
141
|
onValueChange={(next: string) => {
|
|
124
|
-
if (next && next !== value) onChange(next as ApprovalLevel);
|
|
142
|
+
if (next && next !== value) onChange?.(next as ApprovalLevel);
|
|
125
143
|
}}
|
|
126
144
|
aria-labelledby={labelledBy}
|
|
127
145
|
>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { cn } from '../../utils/cn';
|
|
2
|
+
import { ChatTypingIndicator } from '../chat/chat-typing-indicator';
|
|
3
|
+
import { Skeleton } from './skeleton';
|
|
4
|
+
|
|
5
|
+
export interface AnalyzingStateProps {
|
|
6
|
+
/** What is being worked on, as a sentence with no closing mark ("Mingo is analyzing your logs"). */
|
|
7
|
+
label: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** How far each row being read has faded: the list trails off instead of ending. */
|
|
12
|
+
const ROW_OPACITY = ['opacity-100', 'opacity-60', 'opacity-30'] as const;
|
|
13
|
+
/** Each row pulses a beat after the one above it, so the eye reads them as a scan. */
|
|
14
|
+
const ROW_STAGGER_MS = 200;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* THE "it is working, nothing to show yet" state of a feed or a window: three
|
|
18
|
+
* rows still being read, pulsing one after another, over the caller's words
|
|
19
|
+
* and the chat's own typing dots. It says an agent is at work, where a bare
|
|
20
|
+
* sentence in an empty box reads as idle.
|
|
21
|
+
*
|
|
22
|
+
* Built from the shared pieces only: `Skeleton` for the rows and
|
|
23
|
+
* `ChatTypingIndicator` for the dots. Still under reduced motion. It is
|
|
24
|
+
* announced as a status; the rows and dots are decoration.
|
|
25
|
+
*/
|
|
26
|
+
export function AnalyzingState({ label, className }: AnalyzingStateProps) {
|
|
27
|
+
return (
|
|
28
|
+
<div role="status" className={cn('flex w-full max-w-sm flex-col items-center gap-4', className)}>
|
|
29
|
+
<div aria-hidden className="grid w-full grid-cols-1 gap-2">
|
|
30
|
+
{ROW_OPACITY.map((opacity, row) => {
|
|
31
|
+
const delay = { animationDelay: `${row * ROW_STAGGER_MS}ms` };
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
key={opacity}
|
|
35
|
+
className={cn(
|
|
36
|
+
'flex items-center gap-3 rounded-md border border-ods-border bg-ods-bg px-3.5 py-3',
|
|
37
|
+
opacity,
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
<Skeleton
|
|
41
|
+
className="h-2 w-2 shrink-0 rounded-full bg-ods-flamingo-cyan motion-reduce:animate-none"
|
|
42
|
+
style={delay}
|
|
43
|
+
/>
|
|
44
|
+
<Skeleton className="h-2.5 min-w-0 flex-1 motion-reduce:animate-none" style={delay} />
|
|
45
|
+
<Skeleton className="h-2.5 w-12 shrink-0 motion-reduce:animate-none" style={delay} />
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
})}
|
|
49
|
+
</div>
|
|
50
|
+
{/* A div, not a paragraph: the typing dots are block elements. */}
|
|
51
|
+
<div className="flex items-center gap-1.5 text-center text-ods-text-secondary text-h4">
|
|
52
|
+
{label}
|
|
53
|
+
<ChatTypingIndicator aria-hidden size="sm" dotClassName="bg-ods-text-secondary motion-reduce:animate-none" />
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import type React from 'react';
|
|
4
|
+
import { Button } from './button';
|
|
4
5
|
|
|
5
6
|
export interface FeatureListItemData {
|
|
6
7
|
/** Shown in the boxed slot. Not used by the `numbered` variant. */
|
|
@@ -15,13 +16,13 @@ export interface FeatureListProps {
|
|
|
15
16
|
iconBoxSize?: number;
|
|
16
17
|
/**
|
|
17
18
|
* `boxed` (default): one bordered card, a boxed icon per row.
|
|
18
|
-
* `numbered`: an ordered list of open rows
|
|
19
|
-
*
|
|
19
|
+
* `numbered`: an ordered list of open rows, each led by its number in a
|
|
20
|
+
* round marker (process steps).
|
|
20
21
|
*/
|
|
21
22
|
variant?: 'boxed' | 'numbered';
|
|
22
23
|
/**
|
|
23
|
-
* `numbered` only. The step being shown now: it stays at full strength
|
|
24
|
-
* the others step back, so the list reads as "you are here" beside a timed
|
|
24
|
+
* `numbered` only. The step being shown now: it stays at full strength with
|
|
25
|
+
* its marker lit and the others step back, so the list reads as "you are here" beside a timed
|
|
25
26
|
* demo. Omit for a plain list where every step is equal.
|
|
26
27
|
*/
|
|
27
28
|
activeIndex?: number;
|
|
@@ -43,38 +44,47 @@ export function FeatureList({
|
|
|
43
44
|
if (variant === 'numbered') {
|
|
44
45
|
const dims = typeof activeIndex === 'number';
|
|
45
46
|
return (
|
|
46
|
-
<ol className={`flex flex-col ${className}`}>
|
|
47
|
+
<ol className={`flex flex-col gap-[var(--spacing-system-lf)] ${className}`}>
|
|
47
48
|
{items.map((item, index) => {
|
|
48
49
|
const current = dims && index === activeIndex;
|
|
49
50
|
const row = (
|
|
50
51
|
<>
|
|
51
|
-
<span
|
|
52
|
-
{
|
|
52
|
+
<span
|
|
53
|
+
className={`grid h-7 w-7 shrink-0 place-items-center rounded-full border transition-colors duration-200 text-h5 motion-reduce:transition-none ${
|
|
54
|
+
current
|
|
55
|
+
? 'border-ods-flamingo-pink bg-ods-flamingo-pink-secondary text-ods-text-primary'
|
|
56
|
+
: 'border-ods-border text-ods-text-secondary'
|
|
57
|
+
}`}
|
|
58
|
+
>
|
|
59
|
+
{index + 1}
|
|
53
60
|
</span>
|
|
54
61
|
<div className="flex min-w-0 flex-col gap-[var(--spacing-system-xxs)]">
|
|
55
|
-
<h3 className="text-ods-text-primary text-
|
|
56
|
-
<p className="text-ods-text-secondary text-
|
|
62
|
+
<h3 className="text-ods-text-primary text-h4">{item.title}</h3>
|
|
63
|
+
<p className="text-ods-text-secondary text-h6">{item.description}</p>
|
|
57
64
|
</div>
|
|
58
65
|
</>
|
|
59
66
|
);
|
|
60
|
-
const layout =
|
|
61
|
-
'grid grid-cols-[48px_minmax(0,1fr)] gap-[var(--spacing-system-m)] py-[var(--spacing-system-l)]';
|
|
67
|
+
const layout = 'flex items-start gap-[var(--spacing-system-sf)]';
|
|
62
68
|
return (
|
|
63
69
|
<li
|
|
64
70
|
key={index}
|
|
65
71
|
aria-current={current ? 'step' : undefined}
|
|
66
|
-
className={`
|
|
72
|
+
className={`transition-opacity duration-200 motion-reduce:transition-none ${
|
|
67
73
|
dims && !current ? 'opacity-55 focus-within:opacity-100 hover:opacity-100' : ''
|
|
68
74
|
}`}
|
|
69
75
|
>
|
|
70
76
|
{onSelect ? (
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
// The unified Button with no box of its own (`wrap`): it brings the
|
|
78
|
+
// target, the focus ring and the keyboard semantics; the row is the look.
|
|
79
|
+
<Button
|
|
80
|
+
variant="transparent"
|
|
81
|
+
size="wrap"
|
|
82
|
+
fullWidth
|
|
73
83
|
onClick={() => onSelect(index)}
|
|
74
|
-
className={`${layout}
|
|
84
|
+
className={`${layout} justify-start whitespace-normal text-left hover:bg-transparent active:bg-transparent`}
|
|
75
85
|
>
|
|
76
86
|
{row}
|
|
77
|
-
</
|
|
87
|
+
</Button>
|
|
78
88
|
) : (
|
|
79
89
|
<div className={layout}>{row}</div>
|
|
80
90
|
)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import { cn } from '../../utils/cn';
|
|
3
|
+
import { AnalyzingState } from './analyzing-state';
|
|
3
4
|
import { StatusLine, type StatusLineTone } from './status-line';
|
|
4
5
|
|
|
5
6
|
/** Where one incident stands. `waiting` is the only state that needs a person. */
|
|
@@ -46,7 +47,10 @@ export interface IncidentFeedProps {
|
|
|
46
47
|
/** Oldest first. The newest is open; earlier ones collapse to a row. */
|
|
47
48
|
items: readonly IncidentFeedItem[];
|
|
48
49
|
statusLabels: Record<IncidentStatus, string>;
|
|
49
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Shown while there is nothing in the feed, under rows that are still being
|
|
52
|
+
* read: the agent is at work, it has just not found anything yet.
|
|
53
|
+
*/
|
|
50
54
|
emptyLabel?: string;
|
|
51
55
|
/**
|
|
52
56
|
* `top`: the list grows downward (a wide window). `bottom`: the newest item
|
|
@@ -91,7 +95,7 @@ export function IncidentFeed({ items, statusLabels, emptyLabel, anchor = 'top',
|
|
|
91
95
|
className,
|
|
92
96
|
)}
|
|
93
97
|
>
|
|
94
|
-
{items.length === 0 && emptyLabel && <
|
|
98
|
+
{items.length === 0 && emptyLabel && <AnalyzingState label={emptyLabel} className="m-auto" />}
|
|
95
99
|
{items.map((item, index) => {
|
|
96
100
|
const open = index === lastIndex || item.status === 'waiting';
|
|
97
101
|
if (!open) {
|
|
@@ -236,6 +236,7 @@ export { LazyMount, type LazyMountProps } from './lazy-mount';
|
|
|
236
236
|
export * from './app-window-frame';
|
|
237
237
|
export * from './product-screen-frame';
|
|
238
238
|
export * from './phone-frame';
|
|
239
|
+
export * from './analyzing-state';
|
|
239
240
|
export * from './incident-feed';
|
|
240
241
|
export * from './status-line';
|
|
241
242
|
export * from './snap-carousel';
|
|
@@ -17,10 +17,16 @@ export interface PlaybackToggleProps {
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* THE stop/start control of anything that moves on its own (WCAG 2.2.2): one
|
|
20
|
-
* small
|
|
21
|
-
* carousel show the same one, wired to `useAutoplay`'s
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* small icon button beside what it controls. A looping demo and an
|
|
21
|
+
* auto-advancing carousel show the same one, wired to `useAutoplay`'s
|
|
22
|
+
* `paused` / `setPaused`.
|
|
23
|
+
*
|
|
24
|
+
* It has to be there and easy to reach (a 32px target, a name, a focus ring),
|
|
25
|
+
* never the thing the eye lands on: no border and no surface, only a small
|
|
26
|
+
* grey glyph that takes the accent on hover and focus. The grey is the muted
|
|
27
|
+
* text token, the quietest one that still clears the 3:1 a control's glyph
|
|
28
|
+
* needs against the page (WCAG 1.4.11); the next grey down does not. The
|
|
29
|
+
* target stays 32px; it is the glyph that is small.
|
|
24
30
|
*/
|
|
25
31
|
export function PlaybackToggle({
|
|
26
32
|
paused,
|
|
@@ -34,14 +40,14 @@ export function PlaybackToggle({
|
|
|
34
40
|
variant="transparent"
|
|
35
41
|
size="icon-sm"
|
|
36
42
|
className={cn(
|
|
37
|
-
'shrink-0 rounded-full border
|
|
43
|
+
'shrink-0 rounded-full border-0 text-ods-text-muted hover:text-ods-accent focus-visible:text-ods-accent [&_svg]:h-3 [&_svg]:w-3',
|
|
38
44
|
className,
|
|
39
45
|
)}
|
|
40
46
|
aria-label={paused ? playLabel : pauseLabel}
|
|
41
47
|
aria-pressed={paused}
|
|
42
48
|
onClick={() => onChange(!paused)}
|
|
43
49
|
>
|
|
44
|
-
{paused ? <PlayIcon size={
|
|
50
|
+
{paused ? <PlayIcon size={12} /> : <PauseIcon size={12} />}
|
|
45
51
|
</Button>
|
|
46
52
|
);
|
|
47
53
|
}
|