@flamingo-stack/openframe-frontend-core 0.0.838 → 0.0.839
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-MMPMQUQM.cjs → chunk-2XZZHRRU.cjs} +4 -4
- package/dist/{chunk-JFR3OFE6.cjs → chunk-37XKZ4JM.cjs} +2 -2
- package/dist/{chunk-U4MJ2Z4V.cjs → chunk-3MBKEF7Z.cjs} +10 -10
- package/dist/{chunk-V322TUBY.cjs → chunk-C4RYIDPU.cjs} +3 -3
- package/dist/{chunk-TMD55O5U.cjs → chunk-DFTXZE7B.cjs} +24 -24
- package/dist/{chunk-JI34QKPJ.cjs → chunk-GN6LEJWY.cjs} +20 -20
- package/dist/{chunk-B4THEQOW.cjs → chunk-N2TCVIPR.cjs} +208 -25
- package/dist/{chunk-NV5AHL4G.cjs → chunk-SZVPRP5E.cjs} +3 -3
- package/dist/{chunk-7QNGILIY.cjs → chunk-TKS25VKE.cjs} +7 -7
- package/dist/{chunk-4TUHHKLR.cjs → chunk-UDRVVCOC.cjs} +31 -31
- package/dist/{chunk-2X5LYDNA.cjs → chunk-XJ4AB24Y.cjs} +3 -3
- package/dist/{cloud-tenants-GLPDB2F5.cjs → cloud-tenants-WE3H3VAW.cjs} +2 -2
- package/dist/components/case-studies/index.cjs +11 -11
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/docs/index.cjs +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/features/command-box.d.ts.map +1 -1
- package/dist/components/features/command-box.js +4 -23
- package/dist/components/features/index.cjs +12 -2
- package/dist/components/features/software/index.d.ts +1 -0
- package/dist/components/features/software/index.d.ts.map +1 -1
- package/dist/components/features/software/index.js +12 -0
- package/dist/components/features/software/software-action-form.d.ts +9 -1
- package/dist/components/features/software/software-action-form.d.ts.map +1 -1
- package/dist/components/features/software/software-action-form.js +18 -1
- package/dist/components/features/software/update-settings-fields.d.ts +43 -0
- package/dist/components/features/software/update-settings-fields.d.ts.map +1 -0
- package/dist/components/features/software/update-settings-fields.js +202 -0
- package/dist/components/help-center-pages/download-apps-page.d.ts +1 -1
- package/dist/components/help-center-pages/download-apps-page.d.ts.map +1 -1
- package/dist/components/help-center-pages/download-apps-page.js +2 -3
- package/dist/components/help-center-pages/index.cjs +48 -49
- package/dist/components/index.cjs +27 -17
- package/dist/components/meeting-scheduler/index.cjs +20 -20
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/onboarding-guides/index.cjs +3 -3
- package/dist/components/product-demo/fixtures/software-update.d.ts +2 -0
- package/dist/components/product-demo/fixtures/software-update.d.ts.map +1 -1
- package/dist/components/product-demo/fixtures/software-update.js +3 -2
- package/dist/components/product-demo/index.cjs +11 -11
- package/dist/components/tickets/index.cjs +5 -5
- package/dist/components/ui/index.cjs +2 -2
- package/dist/{devices-GHPW5WCO.cjs → devices-ZBZN2RRG.cjs} +3 -3
- package/dist/index.cjs +13 -3
- package/dist/{knowledge-4TOSY2S5.cjs → knowledge-2QNZGDFO.cjs} +2 -2
- package/dist/{logs-MUODFY6N.cjs → logs-YPWTJVIH.cjs} +9 -9
- package/dist/{policies-TJHO3VLE.cjs → policies-BK7TUKAF.cjs} +6 -6
- package/dist/{scripts-X5CMYE2V.cjs → scripts-K7AOYWZE.cjs} +7 -7
- package/dist/{software-update-2UZKHTYM.cjs → software-update-UFN4SBMY.cjs} +7 -7
- package/dist/utils/notifications.cjs +2 -0
- package/dist/utils/notifications.d.ts +1 -1
- package/dist/utils/notifications.d.ts.map +1 -1
- package/dist/utils/notifications.js +2 -0
- package/package.json +1 -1
- package/src/components/features/command-box.tsx +17 -19
- package/src/components/features/notifications/notification-category-icon.tsx +1 -1
- package/src/components/features/software/index.ts +11 -0
- package/src/components/features/software/software-action-form.tsx +28 -1
- package/src/components/features/software/update-settings-fields.tsx +265 -0
- package/src/components/help-center-pages/download-apps-page.tsx +4 -5
- package/src/components/product-demo/fixtures/software-update.ts +2 -2
- package/src/utils/notifications.ts +2 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { InfoCircleIcon } from '../../icons-v2-generated';
|
|
4
|
+
import {
|
|
5
|
+
Alert,
|
|
6
|
+
CheckboxBlock,
|
|
7
|
+
Label,
|
|
8
|
+
RadioGroupBlock,
|
|
9
|
+
type RadioGroupBlockOption,
|
|
10
|
+
Select,
|
|
11
|
+
SelectContent,
|
|
12
|
+
SelectItem,
|
|
13
|
+
SelectTrigger,
|
|
14
|
+
SelectValue,
|
|
15
|
+
} from '../../ui';
|
|
16
|
+
|
|
17
|
+
/** What an update does on a device where the app is running. */
|
|
18
|
+
export type SoftwareUpdateMode = 'WAIT' | 'FORCE';
|
|
19
|
+
|
|
20
|
+
/** "If the app is running": one update's behaviour on a device where the app is open. */
|
|
21
|
+
export interface SoftwareUpdatePolicy {
|
|
22
|
+
mode: SoftwareUpdateMode;
|
|
23
|
+
/** WAIT only: "Countdown after the deadline". Off, the update waits for the user however long it takes. */
|
|
24
|
+
deadlineEnabled: boolean;
|
|
25
|
+
/** WAIT only: seconds after the first try before the countdown starts. */
|
|
26
|
+
deadlineSeconds: number;
|
|
27
|
+
/** Seconds of countdown before the app is closed: after the deadline (WAIT) or right away (FORCE). */
|
|
28
|
+
countdownSeconds: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The Update Software form's "Update Settings": this update, and whether later releases follow it. */
|
|
32
|
+
export interface SoftwareUpdateSettingsValues {
|
|
33
|
+
policy: SoftwareUpdatePolicy;
|
|
34
|
+
/** "Keep it auto-updated": every new version is installed on the same devices after this update. */
|
|
35
|
+
autoUpdate: boolean;
|
|
36
|
+
/** "Same settings for auto-update": auto-updates run with `policy`; off, with `autoUpdatePolicy`. */
|
|
37
|
+
sameForAutoUpdate: boolean;
|
|
38
|
+
autoUpdatePolicy: SoftwareUpdatePolicy;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const DAY = 24 * 60 * 60;
|
|
42
|
+
const MINUTE = 60;
|
|
43
|
+
|
|
44
|
+
export const SOFTWARE_UPDATE_DEADLINE_OPTIONS: ReadonlyArray<{ seconds: number; label: string }> = [
|
|
45
|
+
{ seconds: DAY, label: '1 day after the first try' },
|
|
46
|
+
{ seconds: 3 * DAY, label: '3 days after the first try' },
|
|
47
|
+
{ seconds: 7 * DAY, label: '7 days after the first try' },
|
|
48
|
+
{ seconds: 14 * DAY, label: '14 days after the first try' },
|
|
49
|
+
{ seconds: 30 * DAY, label: '30 days after the first try' },
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
export const SOFTWARE_UPDATE_COUNTDOWN_OPTIONS: ReadonlyArray<{ seconds: number; label: string }> = [
|
|
53
|
+
{ seconds: MINUTE, label: '1 minute' },
|
|
54
|
+
{ seconds: 5 * MINUTE, label: '5 minutes' },
|
|
55
|
+
{ seconds: 15 * MINUTE, label: '15 minutes' },
|
|
56
|
+
{ seconds: 30 * MINUTE, label: '30 minutes' },
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
/** Wait & notify, a countdown 7 days after the first try, 5 minutes long: what the server applies when sent none. */
|
|
60
|
+
export const DEFAULT_SOFTWARE_UPDATE_POLICY: SoftwareUpdatePolicy = {
|
|
61
|
+
mode: 'WAIT',
|
|
62
|
+
deadlineEnabled: true,
|
|
63
|
+
deadlineSeconds: 7 * DAY,
|
|
64
|
+
countdownSeconds: 5 * MINUTE,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const DEFAULT_SOFTWARE_UPDATE_SETTINGS: SoftwareUpdateSettingsValues = {
|
|
68
|
+
policy: DEFAULT_SOFTWARE_UPDATE_POLICY,
|
|
69
|
+
autoUpdate: true,
|
|
70
|
+
sameForAutoUpdate: true,
|
|
71
|
+
autoUpdatePolicy: DEFAULT_SOFTWARE_UPDATE_POLICY,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const MODE_OPTIONS: RadioGroupBlockOption[] = [
|
|
75
|
+
{
|
|
76
|
+
value: 'WAIT',
|
|
77
|
+
label: 'Wait & notify',
|
|
78
|
+
description: 'The user gets Update now or Ask Later. If they close the app, it updates then.',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
value: 'FORCE',
|
|
82
|
+
label: 'Force Update',
|
|
83
|
+
description: 'The user gets a short countdown, then the app closes and updates.',
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
const SAME_SETTINGS_DESCRIPTION: Record<SoftwareUpdateMode, string> = {
|
|
88
|
+
WAIT: 'Auto-updates follow "If the app is running" above. Uncheck to set them separately.',
|
|
89
|
+
FORCE: 'Later releases will also be force-updated.',
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const groupLabelClass = 'text-h5 text-ods-text-secondary';
|
|
93
|
+
|
|
94
|
+
function SecondsSelect({
|
|
95
|
+
label,
|
|
96
|
+
value,
|
|
97
|
+
options,
|
|
98
|
+
onChange,
|
|
99
|
+
}: {
|
|
100
|
+
label: string;
|
|
101
|
+
value: number;
|
|
102
|
+
options: ReadonlyArray<{ seconds: number; label: string }>;
|
|
103
|
+
onChange: (seconds: number) => void;
|
|
104
|
+
}) {
|
|
105
|
+
return (
|
|
106
|
+
<div className="flex min-w-0 flex-col gap-[var(--spacing-system-xxs)]">
|
|
107
|
+
<Label className="text-h4">{label}</Label>
|
|
108
|
+
<Select value={String(value)} onValueChange={next => onChange(Number(next))}>
|
|
109
|
+
<SelectTrigger aria-label={label}>
|
|
110
|
+
<SelectValue />
|
|
111
|
+
</SelectTrigger>
|
|
112
|
+
<SelectContent>
|
|
113
|
+
{options.map(option => (
|
|
114
|
+
<SelectItem key={option.seconds} value={String(option.seconds)}>
|
|
115
|
+
{option.label}
|
|
116
|
+
</SelectItem>
|
|
117
|
+
))}
|
|
118
|
+
</SelectContent>
|
|
119
|
+
</Select>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** "If the app is running" with its deadline and countdown. */
|
|
125
|
+
function UpdatePolicyFields({
|
|
126
|
+
name,
|
|
127
|
+
label,
|
|
128
|
+
policy,
|
|
129
|
+
onChange,
|
|
130
|
+
}: {
|
|
131
|
+
/** The radio group's name: two policies on one page must not share it. */
|
|
132
|
+
name: string;
|
|
133
|
+
label: string;
|
|
134
|
+
policy: SoftwareUpdatePolicy;
|
|
135
|
+
onChange: (policy: SoftwareUpdatePolicy) => void;
|
|
136
|
+
}) {
|
|
137
|
+
const waits = policy.mode === 'WAIT';
|
|
138
|
+
const deadline = waits && policy.deadlineEnabled;
|
|
139
|
+
const countdown = (
|
|
140
|
+
<SecondsSelect
|
|
141
|
+
label="Countdown"
|
|
142
|
+
value={policy.countdownSeconds}
|
|
143
|
+
options={SOFTWARE_UPDATE_COUNTDOWN_OPTIONS}
|
|
144
|
+
onChange={countdownSeconds => onChange({ ...policy, countdownSeconds })}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
return (
|
|
148
|
+
<div className="flex flex-col gap-[var(--spacing-system-m)]">
|
|
149
|
+
<div className="flex flex-col gap-[var(--spacing-system-xxs)]">
|
|
150
|
+
<span className={groupLabelClass}>{label}</span>
|
|
151
|
+
<RadioGroupBlock
|
|
152
|
+
name={name}
|
|
153
|
+
aria-label={label}
|
|
154
|
+
variant="grouped"
|
|
155
|
+
value={policy.mode}
|
|
156
|
+
onValueChange={mode => onChange({ ...policy, mode: mode as SoftwareUpdateMode })}
|
|
157
|
+
options={MODE_OPTIONS}
|
|
158
|
+
itemClassName="py-[var(--spacing-system-sf)]"
|
|
159
|
+
/>
|
|
160
|
+
</div>
|
|
161
|
+
{waits ? (
|
|
162
|
+
<div className="flex flex-col gap-[var(--spacing-system-xsf)]">
|
|
163
|
+
<CheckboxBlock
|
|
164
|
+
id={`${name}-deadline`}
|
|
165
|
+
checked={policy.deadlineEnabled}
|
|
166
|
+
onCheckedChange={deadlineEnabled => onChange({ ...policy, deadlineEnabled })}
|
|
167
|
+
label="Countdown after the deadline"
|
|
168
|
+
description="If the update still isn’t installed by the deadline, the user gets a countdown and then it installs."
|
|
169
|
+
/>
|
|
170
|
+
{deadline && (
|
|
171
|
+
<div className="grid grid-cols-1 gap-[var(--spacing-system-lf)] content-md:grid-cols-3 content-md:items-start">
|
|
172
|
+
<SecondsSelect
|
|
173
|
+
label="Deadline"
|
|
174
|
+
value={policy.deadlineSeconds}
|
|
175
|
+
options={SOFTWARE_UPDATE_DEADLINE_OPTIONS}
|
|
176
|
+
onChange={deadlineSeconds => onChange({ ...policy, deadlineSeconds })}
|
|
177
|
+
/>
|
|
178
|
+
{countdown}
|
|
179
|
+
</div>
|
|
180
|
+
)}
|
|
181
|
+
</div>
|
|
182
|
+
) : (
|
|
183
|
+
<div className="grid grid-cols-1 gap-[var(--spacing-system-lf)] content-md:grid-cols-3">{countdown}</div>
|
|
184
|
+
)}
|
|
185
|
+
</div>
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface SoftwareUpdateSettingsFieldsProps {
|
|
190
|
+
value: SoftwareUpdateSettingsValues;
|
|
191
|
+
onChange: (value: SoftwareUpdateSettingsValues) => void;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Update Software's "Update Settings" (design 988:21462, the separate auto-update
|
|
196
|
+
* rules 1034:8173): what happens on a device where the app is running, and
|
|
197
|
+
* whether later releases are installed the same way.
|
|
198
|
+
*/
|
|
199
|
+
export function SoftwareUpdateSettingsFields({ value, onChange }: SoftwareUpdateSettingsFieldsProps) {
|
|
200
|
+
return (
|
|
201
|
+
<section aria-labelledby="software-update-settings" className="flex flex-col gap-[var(--spacing-system-l)]">
|
|
202
|
+
<h2 id="software-update-settings" className="pt-[var(--spacing-system-l)] text-ods-text-primary text-h2">
|
|
203
|
+
Update Settings
|
|
204
|
+
</h2>
|
|
205
|
+
|
|
206
|
+
<UpdatePolicyFields
|
|
207
|
+
name="updatePolicy"
|
|
208
|
+
label="If the app is running"
|
|
209
|
+
policy={value.policy}
|
|
210
|
+
onChange={policy => onChange({ ...value, policy })}
|
|
211
|
+
/>
|
|
212
|
+
|
|
213
|
+
<div className="flex flex-col gap-[var(--spacing-system-xxs)]">
|
|
214
|
+
<span className={groupLabelClass}>Auto-update</span>
|
|
215
|
+
<div className="flex flex-col gap-[var(--spacing-system-sf)]">
|
|
216
|
+
<CheckboxBlock
|
|
217
|
+
id="software-auto-update"
|
|
218
|
+
checked={value.autoUpdate}
|
|
219
|
+
onCheckedChange={autoUpdate => onChange({ ...value, autoUpdate })}
|
|
220
|
+
label="Keep it auto-updated"
|
|
221
|
+
description="After this update, OpenFrame installs each new version from Winget or Brew on the selected devices. When off, only this update runs."
|
|
222
|
+
/>
|
|
223
|
+
{value.autoUpdate && (
|
|
224
|
+
<>
|
|
225
|
+
<CheckboxBlock
|
|
226
|
+
id="software-auto-update-same"
|
|
227
|
+
checked={value.sameForAutoUpdate}
|
|
228
|
+
onCheckedChange={sameForAutoUpdate => onChange({ ...value, sameForAutoUpdate })}
|
|
229
|
+
label="Same settings for auto-update"
|
|
230
|
+
description={SAME_SETTINGS_DESCRIPTION[value.policy.mode]}
|
|
231
|
+
/>
|
|
232
|
+
{!value.sameForAutoUpdate && (
|
|
233
|
+
<div className="rounded-[6px] border border-ods-border p-[var(--spacing-system-m)]">
|
|
234
|
+
<UpdatePolicyFields
|
|
235
|
+
name="autoUpdatePolicy"
|
|
236
|
+
label="For auto-updates"
|
|
237
|
+
policy={value.autoUpdatePolicy}
|
|
238
|
+
onChange={autoUpdatePolicy => onChange({ ...value, autoUpdatePolicy })}
|
|
239
|
+
/>
|
|
240
|
+
</div>
|
|
241
|
+
)}
|
|
242
|
+
</>
|
|
243
|
+
)}
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
|
|
247
|
+
{/* Core Alert on the card surface, as a note: it is there from the start, nothing to announce. The icon sits in
|
|
248
|
+
a span so Alert's `[&>svg]` positioning does not apply. */}
|
|
249
|
+
<Alert
|
|
250
|
+
role="note"
|
|
251
|
+
className="flex items-center gap-[var(--spacing-system-m)] rounded-[6px] border-ods-border bg-ods-card p-[var(--spacing-system-m)]"
|
|
252
|
+
>
|
|
253
|
+
<span className="shrink-0 text-ods-text-secondary">
|
|
254
|
+
<InfoCircleIcon size={24} color="currentColor" />
|
|
255
|
+
</span>
|
|
256
|
+
<div className="flex min-w-0 flex-1 flex-col gap-[var(--spacing-system-xxs)]">
|
|
257
|
+
<p className="text-ods-text-primary text-h3">Apps installed by hand get reinstalled</p>
|
|
258
|
+
<p className="text-ods-text-secondary text-h6">
|
|
259
|
+
On the first update, OpenFrame reinstalls them with Winget or Brew so it can keep them updated.
|
|
260
|
+
</p>
|
|
261
|
+
</div>
|
|
262
|
+
</Alert>
|
|
263
|
+
</section>
|
|
264
|
+
);
|
|
265
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* lists its platforms; it does not hide them behind tabs, so nothing moves
|
|
8
8
|
* when a visitor looks for another system). In a card the installer is THE
|
|
9
9
|
* action (the other architecture is a quieter button) and each package
|
|
10
|
-
* manager is one
|
|
10
|
+
* manager is one row under it, with its copy button.
|
|
11
11
|
* - The mobile app: the store badges, and the install QR code beside them. The
|
|
12
12
|
* code and the address it encodes are the server's (`mobile.install`): the
|
|
13
13
|
* website's install link, which the server answers with a redirect to the
|
|
@@ -111,7 +111,7 @@ export interface DownloadAppsWebOption {
|
|
|
111
111
|
|
|
112
112
|
const SECTIONS_CLASS = 'flex flex-col gap-[var(--spacing-system-xlf)]';
|
|
113
113
|
const SECTION_CLASS = 'flex flex-col gap-[var(--spacing-system-lf)]';
|
|
114
|
-
const CARDS_GRID_CLASS = 'grid grid-cols-1 gap-[var(--spacing-system-lf)] content-
|
|
114
|
+
const CARDS_GRID_CLASS = 'grid grid-cols-1 gap-[var(--spacing-system-lf)] content-lg:grid-cols-2';
|
|
115
115
|
/** One card takes the row; two or more share it. */
|
|
116
116
|
const cardsGridClass = (cards: number) => (cards > 1 ? CARDS_GRID_CLASS : 'grid grid-cols-1');
|
|
117
117
|
const CARD_CLASS =
|
|
@@ -183,7 +183,7 @@ function installerLabel(download: AppDownload, siblings: number): string {
|
|
|
183
183
|
return siblings > 1 && architecture ? `${label} (${architecture})` : label;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
/** One system's card: its logo and name, its installers side by side, then each package manager as one
|
|
186
|
+
/** One system's card: its logo and name, its installers side by side, then each package manager as one row. */
|
|
187
187
|
function SystemCard({
|
|
188
188
|
system,
|
|
189
189
|
onDownloadAction,
|
|
@@ -243,8 +243,7 @@ function SystemCard({
|
|
|
243
243
|
key={row.id}
|
|
244
244
|
title={row.label ?? undefined}
|
|
245
245
|
command={row.command}
|
|
246
|
-
|
|
247
|
-
commandClassName="text-ods-accent"
|
|
246
|
+
commandClassName="break-words text-ods-accent"
|
|
248
247
|
copyAriaLabel={`Copy the ${row.label ?? 'install'} command`}
|
|
249
248
|
onCopy={() => {
|
|
250
249
|
void copy(row.command as string);
|
|
@@ -16,7 +16,7 @@ const chrome: SelectedPackage = {
|
|
|
16
16
|
const TONIGHT_11_PM = { value: '23:00', label: '11:00 PM' };
|
|
17
17
|
|
|
18
18
|
/** A fixed reading of the schedule fields: tonight's late slots, nothing in the past. */
|
|
19
|
-
const
|
|
19
|
+
export const SOFTWARE_DEMO_TIMING: SoftwareScheduleTiming = {
|
|
20
20
|
timeReferenceOptions: [
|
|
21
21
|
{ value: 'SERVER', label: 'Your account timezone' },
|
|
22
22
|
{ value: 'DEVICE_LOCAL', label: 'Device local timezone' },
|
|
@@ -49,7 +49,7 @@ export function buildSoftwareUpdateFixture(cast: DemoCast) {
|
|
|
49
49
|
return {
|
|
50
50
|
action: 'UPDATE',
|
|
51
51
|
package: chrome,
|
|
52
|
-
timing,
|
|
52
|
+
timing: SOFTWARE_DEMO_TIMING,
|
|
53
53
|
initialValues,
|
|
54
54
|
devices,
|
|
55
55
|
selectedIds: new Set<string>([DEMO_DEVICES.reception.id, DEMO_DEVICES.samT14.id, DEMO_DEVICES.frontDesk.id]),
|
|
@@ -39,6 +39,7 @@ export const NOTIFICATION_CATEGORIES = [
|
|
|
39
39
|
'INSIGHTS',
|
|
40
40
|
'MINGO',
|
|
41
41
|
'INTEGRATIONS',
|
|
42
|
+
'BILLING',
|
|
42
43
|
'GENERIC',
|
|
43
44
|
] as const;
|
|
44
45
|
export type NotificationCategory = (typeof NOTIFICATION_CATEGORIES)[number];
|
|
@@ -56,6 +57,7 @@ export const NOTIFICATION_CATEGORY_LABELS: Readonly<Record<NotificationCategory,
|
|
|
56
57
|
INSIGHTS: 'Insights',
|
|
57
58
|
MINGO: 'Mingo',
|
|
58
59
|
INTEGRATIONS: 'Integrations',
|
|
60
|
+
BILLING: 'Billing',
|
|
59
61
|
GENERIC: 'General',
|
|
60
62
|
};
|
|
61
63
|
|