@nightkatana/kronosys-app 1.0.0-beta.21 → 1.0.0-beta.22
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/README.md +1 -1
- package/app/changelog/page.tsx +87 -19
- package/app/globals.css +10 -8
- package/app/guide/page.tsx +71 -34
- package/app/implementation/page.tsx +70 -60
- package/app/licenses/page.tsx +79 -47
- package/app/logs/page.tsx +103 -47
- package/app/page.tsx +104 -169
- package/app/reporting/page.tsx +1918 -1436
- package/app/settings/page.tsx +66 -44
- package/components/KronosysPayloadProvider.tsx +19 -5
- package/components/dashboard/AppShellHeaderKronoFocus.tsx +78 -0
- package/components/dashboard/AppShellHeaderToolbarLayout.tsx +36 -0
- package/components/dashboard/AppShellHeaderUtilityRibbon.tsx +19 -0
- package/components/dashboard/AppShellHeaderWallClock.tsx +23 -17
- package/components/dashboard/AppShellRouteNav.tsx +336 -209
- package/components/dashboard/AppShellToolbarCommandCenter.tsx +225 -0
- package/components/dashboard/AppShellToolbarRouteNav.tsx +204 -0
- package/components/dashboard/DashboardCommandCenter.tsx +119 -30
- package/components/dashboard/KronoFocusPanel.tsx +287 -260
- package/components/dashboard/LanguageMenu.tsx +23 -7
- package/components/dashboard/PageRefreshButton.tsx +42 -16
- package/components/dashboard/ReportingTour.tsx +20 -2
- package/components/dashboard/SessionListPanel.tsx +4 -4
- package/components/dashboard/ThemeToggle.tsx +4 -3
- package/components/dashboard/useAnchoredFloatingPortalStyle.ts +9 -2
- package/components/dashboard/useKronoFocusLiveSeconds.ts +4 -2
- package/lib/appShellHeaderClasses.ts +22 -3
- package/lib/appShellToolbarChrome.ts +112 -0
- package/lib/appShellToolbarDeferredIntents.ts +112 -0
- package/lib/appShellToolbarSessionSlices.ts +67 -0
- package/lib/dashboardCopy.ts +78 -29
- package/lib/dashboardQuickSearch.ts +37 -6
- package/lib/dashboardUrlSession.ts +36 -0
- package/lib/generatedUserChangelog.ts +14 -0
- package/lib/implementationNotes.ts +18 -14
- package/lib/reportingAggregate.ts +68 -9
- package/lib/reportingMetricHelp.ts +8 -8
- package/lib/reportingStrings.ts +118 -9
- package/lib/reportingTagWeekBreakdown.ts +55 -13
- package/lib/settingsCopy.ts +6 -7
- package/lib/userGuideCopy.ts +29 -26
- package/package.json +7 -5
- package/server/db.ts +6 -4
- package/server/dbSchema.ts +2 -2
- package/components/dashboard/AppShellCommandCenterPlaceholder.tsx +0 -17
|
@@ -12,23 +12,27 @@ import {
|
|
|
12
12
|
Logs,
|
|
13
13
|
Pause,
|
|
14
14
|
Play,
|
|
15
|
+
ScrollText,
|
|
15
16
|
Settings,
|
|
16
17
|
} from "lucide-react";
|
|
17
18
|
import { withDashboardSessionParam } from "@/lib/dashboardSessionNav";
|
|
18
19
|
import { PLANNED_BOUNDARY_ATTENTION_EVENT } from "@/lib/plannedBoundaryAttention";
|
|
20
|
+
import type { AppShellRouteNavLabelBundle } from "@/lib/reportingStrings";
|
|
21
|
+
import {
|
|
22
|
+
appShellToolbarDashboardPulseChromeClass,
|
|
23
|
+
appShellToolbarGlobalPauseResumeHighlightClass,
|
|
24
|
+
appShellToolbarIconActiveClass,
|
|
25
|
+
appShellToolbarIconLinkClass,
|
|
26
|
+
appShellToolbarRibbonGroupClass,
|
|
27
|
+
} from "@/lib/appShellToolbarChrome";
|
|
19
28
|
|
|
20
|
-
const iconLinkClass =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
"inline-flex size-10 items-center justify-center rounded-lg border border-violet-400/70 bg-violet-100/90 text-violet-950 dark:border-violet-600/60 dark:bg-violet-950/40 dark:text-violet-100";
|
|
25
|
-
|
|
26
|
-
const dashboardPulseChromeClass =
|
|
27
|
-
"ring-2 ring-amber-400/85 motion-safe:animate-pulse shadow-[0_0_14px_rgba(251,191,36,0.35)] dark:ring-amber-300/80";
|
|
28
|
-
|
|
29
|
-
/** Anneau autour du bouton pause globale lorsque la reprise est disponible (pause active). */
|
|
29
|
+
const iconLinkClass = appShellToolbarIconLinkClass;
|
|
30
|
+
const iconActiveClass = appShellToolbarIconActiveClass;
|
|
31
|
+
const dashboardPulseChromeClass = appShellToolbarDashboardPulseChromeClass;
|
|
32
|
+
const ribbonGroupClass = appShellToolbarRibbonGroupClass;
|
|
30
33
|
const globalPauseResumeHighlightClass =
|
|
31
|
-
|
|
34
|
+
appShellToolbarGlobalPauseResumeHighlightClass;
|
|
35
|
+
const iconButtonDisabledNativeClass = `${iconLinkClass} disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-45`;
|
|
32
36
|
|
|
33
37
|
type GlobalPauseControlProps = Readonly<{
|
|
34
38
|
active: boolean;
|
|
@@ -85,19 +89,9 @@ function AppShellGlobalPauseButton({
|
|
|
85
89
|
);
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
export type AppShellRouteNavLabels = {
|
|
89
|
-
dashboard: string;
|
|
90
|
-
reporting: string;
|
|
91
|
-
settings: string;
|
|
92
|
-
logs?: string;
|
|
93
|
-
/** Guide d’utilisation in-app. */
|
|
94
|
-
guide: string;
|
|
95
|
-
/** Détails d’implémentation (documentation technique maintenue). */
|
|
96
|
-
implementation?: string;
|
|
92
|
+
export type AppShellRouteNavLabels = AppShellRouteNavLabelBundle & {
|
|
97
93
|
/** Libellé infobulle / `aria-label` pour l’icône « licences » (page licences uniquement). */
|
|
98
94
|
licenses?: string;
|
|
99
|
-
/** Infobulle lorsque l’icône tableau de bord pulse (rappel conflit minuteurs). */
|
|
100
|
-
dashboardAttentionHint?: string;
|
|
101
95
|
};
|
|
102
96
|
|
|
103
97
|
export type AppShellRouteNavCurrent =
|
|
@@ -107,7 +101,8 @@ export type AppShellRouteNavCurrent =
|
|
|
107
101
|
| "logs"
|
|
108
102
|
| "licenses"
|
|
109
103
|
| "guide"
|
|
110
|
-
| "implementation"
|
|
104
|
+
| "implementation"
|
|
105
|
+
| "changelog";
|
|
111
106
|
|
|
112
107
|
type Props = Readonly<{
|
|
113
108
|
current: AppShellRouteNavCurrent;
|
|
@@ -119,8 +114,6 @@ type Props = Readonly<{
|
|
|
119
114
|
dashboardSessionId?: string | null;
|
|
120
115
|
globalPauseControl?: GlobalPauseControlProps;
|
|
121
116
|
ganttControl?: { label: string; onPress: () => void };
|
|
122
|
-
/** Réserve l’emplacement du bouton pause globale (tableau de bord) pour éviter les sauts. */
|
|
123
|
-
reserveGlobalPauseSlot?: boolean;
|
|
124
117
|
}>;
|
|
125
118
|
|
|
126
119
|
export function AppShellRouteNav({
|
|
@@ -131,9 +124,9 @@ export function AppShellRouteNav({
|
|
|
131
124
|
dashboardSessionId,
|
|
132
125
|
globalPauseControl,
|
|
133
126
|
ganttControl,
|
|
134
|
-
reserveGlobalPauseSlot,
|
|
135
127
|
}: Props) {
|
|
136
|
-
const wrapClass =
|
|
128
|
+
const wrapClass =
|
|
129
|
+
className ?? "flex shrink-0 flex-nowrap items-center gap-2.5";
|
|
137
130
|
const dash = (path: string) =>
|
|
138
131
|
withDashboardSessionParam(path, dashboardSessionId);
|
|
139
132
|
|
|
@@ -192,156 +185,138 @@ export function AppShellRouteNav({
|
|
|
192
185
|
? `${dashboardBaseNavClass} ${dashboardPulseChromeClass}`
|
|
193
186
|
: dashboardBaseNavClass;
|
|
194
187
|
|
|
188
|
+
const implLabel = labels.implementation?.trim() ?? "";
|
|
189
|
+
|
|
195
190
|
return (
|
|
196
191
|
<nav className={wrapClass} aria-label={navAriaLabel}>
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
aria-label={labels.reporting}
|
|
232
|
-
aria-current="page"
|
|
233
|
-
>
|
|
234
|
-
<BarChart3
|
|
235
|
-
size={20}
|
|
236
|
-
strokeWidth={2}
|
|
237
|
-
className="shrink-0"
|
|
238
|
-
aria-hidden
|
|
239
|
-
/>
|
|
240
|
-
</span>
|
|
241
|
-
) : (
|
|
242
|
-
<Link
|
|
243
|
-
href={dash("/reporting")}
|
|
244
|
-
className={iconLinkClass}
|
|
245
|
-
title={labels.reporting}
|
|
246
|
-
aria-label={labels.reporting}
|
|
247
|
-
>
|
|
248
|
-
<BarChart3
|
|
249
|
-
size={20}
|
|
250
|
-
strokeWidth={2}
|
|
251
|
-
className="shrink-0"
|
|
252
|
-
aria-hidden
|
|
253
|
-
/>
|
|
254
|
-
</Link>
|
|
255
|
-
)}
|
|
192
|
+
<div
|
|
193
|
+
role="group"
|
|
194
|
+
aria-label={labels.navGroupAppAria}
|
|
195
|
+
className={ribbonGroupClass}
|
|
196
|
+
>
|
|
197
|
+
{current === "dashboard" ? (
|
|
198
|
+
<span
|
|
199
|
+
className={dashboardNavClass}
|
|
200
|
+
title={dashboardPulseTitle}
|
|
201
|
+
aria-label={dashboardPulseTitle}
|
|
202
|
+
aria-current="page"
|
|
203
|
+
>
|
|
204
|
+
<LayoutDashboard
|
|
205
|
+
size={20}
|
|
206
|
+
strokeWidth={2}
|
|
207
|
+
className="shrink-0"
|
|
208
|
+
aria-hidden
|
|
209
|
+
/>
|
|
210
|
+
</span>
|
|
211
|
+
) : (
|
|
212
|
+
<Link
|
|
213
|
+
href={dash("/")}
|
|
214
|
+
className={dashboardNavClass}
|
|
215
|
+
title={dashboardPulseTitle}
|
|
216
|
+
aria-label={dashboardPulseTitle}
|
|
217
|
+
>
|
|
218
|
+
<LayoutDashboard
|
|
219
|
+
size={20}
|
|
220
|
+
strokeWidth={2}
|
|
221
|
+
className="shrink-0"
|
|
222
|
+
aria-hidden
|
|
223
|
+
/>
|
|
224
|
+
</Link>
|
|
225
|
+
)}
|
|
256
226
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
{current === "logs" ? (
|
|
287
|
-
<span
|
|
288
|
-
className={iconActiveClass}
|
|
289
|
-
title={logsTitle}
|
|
290
|
-
aria-label={logsTitle}
|
|
291
|
-
aria-current="page"
|
|
292
|
-
>
|
|
293
|
-
<Logs size={20} strokeWidth={2} className="shrink-0" aria-hidden />
|
|
294
|
-
</span>
|
|
295
|
-
) : (
|
|
296
|
-
<Link
|
|
297
|
-
href={dash("/logs")}
|
|
298
|
-
className={iconLinkClass}
|
|
299
|
-
title={logsTitle}
|
|
300
|
-
aria-label={logsTitle}
|
|
301
|
-
>
|
|
302
|
-
<Logs size={20} strokeWidth={2} className="shrink-0" aria-hidden />
|
|
303
|
-
</Link>
|
|
304
|
-
)}
|
|
227
|
+
{current === "reporting" ? (
|
|
228
|
+
<span
|
|
229
|
+
className={iconActiveClass}
|
|
230
|
+
title={labels.reporting}
|
|
231
|
+
aria-label={labels.reporting}
|
|
232
|
+
aria-current="page"
|
|
233
|
+
>
|
|
234
|
+
<BarChart3
|
|
235
|
+
size={20}
|
|
236
|
+
strokeWidth={2}
|
|
237
|
+
className="shrink-0"
|
|
238
|
+
aria-hidden
|
|
239
|
+
/>
|
|
240
|
+
</span>
|
|
241
|
+
) : (
|
|
242
|
+
<Link
|
|
243
|
+
href={dash("/reporting")}
|
|
244
|
+
className={iconLinkClass}
|
|
245
|
+
title={labels.reporting}
|
|
246
|
+
aria-label={labels.reporting}
|
|
247
|
+
>
|
|
248
|
+
<BarChart3
|
|
249
|
+
size={20}
|
|
250
|
+
strokeWidth={2}
|
|
251
|
+
className="shrink-0"
|
|
252
|
+
aria-hidden
|
|
253
|
+
/>
|
|
254
|
+
</Link>
|
|
255
|
+
)}
|
|
305
256
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
257
|
+
{current === "settings" ? (
|
|
258
|
+
<span
|
|
259
|
+
className={iconActiveClass}
|
|
260
|
+
title={labels.settings}
|
|
261
|
+
aria-label={labels.settings}
|
|
262
|
+
aria-current="page"
|
|
263
|
+
>
|
|
264
|
+
<Settings
|
|
265
|
+
size={20}
|
|
266
|
+
strokeWidth={2}
|
|
267
|
+
className="shrink-0"
|
|
268
|
+
aria-hidden
|
|
269
|
+
/>
|
|
270
|
+
</span>
|
|
271
|
+
) : (
|
|
272
|
+
<Link
|
|
273
|
+
href={dash("/settings")}
|
|
274
|
+
className={iconLinkClass}
|
|
275
|
+
title={labels.settings}
|
|
276
|
+
aria-label={labels.settings}
|
|
277
|
+
>
|
|
278
|
+
<Settings
|
|
279
|
+
size={20}
|
|
280
|
+
strokeWidth={2}
|
|
281
|
+
className="shrink-0"
|
|
282
|
+
aria-hidden
|
|
283
|
+
/>
|
|
284
|
+
</Link>
|
|
285
|
+
)}
|
|
286
|
+
{current === "logs" ? (
|
|
287
|
+
<span
|
|
288
|
+
className={iconActiveClass}
|
|
289
|
+
title={logsTitle}
|
|
290
|
+
aria-label={logsTitle}
|
|
291
|
+
aria-current="page"
|
|
292
|
+
>
|
|
293
|
+
<Logs size={20} strokeWidth={2} className="shrink-0" aria-hidden />
|
|
294
|
+
</span>
|
|
295
|
+
) : (
|
|
296
|
+
<Link
|
|
297
|
+
href={dash("/logs")}
|
|
298
|
+
className={iconLinkClass}
|
|
299
|
+
title={logsTitle}
|
|
300
|
+
aria-label={logsTitle}
|
|
301
|
+
>
|
|
302
|
+
<Logs size={20} strokeWidth={2} className="shrink-0" aria-hidden />
|
|
303
|
+
</Link>
|
|
304
|
+
)}
|
|
305
|
+
</div>
|
|
335
306
|
|
|
336
|
-
|
|
337
|
-
|
|
307
|
+
<div
|
|
308
|
+
role="group"
|
|
309
|
+
aria-label={labels.navGroupDocsAria}
|
|
310
|
+
className={ribbonGroupClass}
|
|
311
|
+
>
|
|
312
|
+
{current === "guide" ? (
|
|
338
313
|
<span
|
|
339
314
|
className={iconActiveClass}
|
|
340
|
-
title={labels.
|
|
341
|
-
aria-label={labels.
|
|
315
|
+
title={labels.guide}
|
|
316
|
+
aria-label={labels.guide}
|
|
342
317
|
aria-current="page"
|
|
343
318
|
>
|
|
344
|
-
<
|
|
319
|
+
<BookOpen
|
|
345
320
|
size={20}
|
|
346
321
|
strokeWidth={2}
|
|
347
322
|
className="shrink-0"
|
|
@@ -350,57 +325,209 @@ export function AppShellRouteNav({
|
|
|
350
325
|
</span>
|
|
351
326
|
) : (
|
|
352
327
|
<Link
|
|
353
|
-
href={dash("/
|
|
328
|
+
href={dash("/guide")}
|
|
354
329
|
className={iconLinkClass}
|
|
355
|
-
title={labels.
|
|
356
|
-
aria-label={labels.
|
|
330
|
+
title={labels.guide}
|
|
331
|
+
aria-label={labels.guide}
|
|
357
332
|
>
|
|
358
|
-
<
|
|
333
|
+
<BookOpen
|
|
359
334
|
size={20}
|
|
360
335
|
strokeWidth={2}
|
|
361
336
|
className="shrink-0"
|
|
362
337
|
aria-hidden
|
|
363
338
|
/>
|
|
364
339
|
</Link>
|
|
365
|
-
)
|
|
366
|
-
) : null}
|
|
340
|
+
)}
|
|
367
341
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
342
|
+
{(() => {
|
|
343
|
+
const changelogLabel = labels.changelog?.trim() ?? "";
|
|
344
|
+
const changelogDisabled = changelogLabel.length === 0;
|
|
345
|
+
if (changelogDisabled) {
|
|
346
|
+
return (
|
|
347
|
+
<button
|
|
348
|
+
type="button"
|
|
349
|
+
disabled
|
|
350
|
+
className={iconButtonDisabledNativeClass}
|
|
351
|
+
title={labels.navChangelogUnavailableTooltip}
|
|
352
|
+
aria-label={labels.navChangelogUnavailableTooltip}
|
|
353
|
+
>
|
|
354
|
+
<ScrollText
|
|
355
|
+
size={20}
|
|
356
|
+
strokeWidth={2}
|
|
357
|
+
className="shrink-0"
|
|
358
|
+
aria-hidden
|
|
359
|
+
/>
|
|
360
|
+
</button>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
return current === "changelog" ? (
|
|
364
|
+
<span
|
|
365
|
+
className={iconActiveClass}
|
|
366
|
+
title={changelogLabel}
|
|
367
|
+
aria-label={changelogLabel}
|
|
368
|
+
aria-current="page"
|
|
369
|
+
>
|
|
370
|
+
<ScrollText
|
|
371
|
+
size={20}
|
|
372
|
+
strokeWidth={2}
|
|
373
|
+
className="shrink-0"
|
|
374
|
+
aria-hidden
|
|
375
|
+
/>
|
|
376
|
+
</span>
|
|
377
|
+
) : (
|
|
378
|
+
<Link
|
|
379
|
+
href={dash("/changelog")}
|
|
380
|
+
className={iconLinkClass}
|
|
381
|
+
title={changelogLabel}
|
|
382
|
+
aria-label={changelogLabel}
|
|
383
|
+
>
|
|
384
|
+
<ScrollText
|
|
385
|
+
size={20}
|
|
386
|
+
strokeWidth={2}
|
|
387
|
+
className="shrink-0"
|
|
388
|
+
aria-hidden
|
|
389
|
+
/>
|
|
390
|
+
</Link>
|
|
391
|
+
);
|
|
392
|
+
})()}
|
|
393
|
+
|
|
394
|
+
{implLabel ? (
|
|
395
|
+
current === "implementation" ? (
|
|
396
|
+
<span
|
|
397
|
+
className={iconActiveClass}
|
|
398
|
+
title={implLabel}
|
|
399
|
+
aria-label={implLabel}
|
|
400
|
+
aria-current="page"
|
|
401
|
+
>
|
|
402
|
+
<FileCode2
|
|
403
|
+
size={20}
|
|
404
|
+
strokeWidth={2}
|
|
405
|
+
className="shrink-0"
|
|
406
|
+
aria-hidden
|
|
407
|
+
/>
|
|
408
|
+
</span>
|
|
409
|
+
) : (
|
|
410
|
+
<Link
|
|
411
|
+
href={dash("/implementation")}
|
|
412
|
+
className={iconLinkClass}
|
|
413
|
+
title={implLabel}
|
|
414
|
+
aria-label={implLabel}
|
|
415
|
+
>
|
|
416
|
+
<FileCode2
|
|
417
|
+
size={20}
|
|
418
|
+
strokeWidth={2}
|
|
419
|
+
className="shrink-0"
|
|
420
|
+
aria-hidden
|
|
421
|
+
/>
|
|
422
|
+
</Link>
|
|
423
|
+
)
|
|
424
|
+
) : (
|
|
425
|
+
<button
|
|
426
|
+
type="button"
|
|
427
|
+
disabled
|
|
428
|
+
className={iconButtonDisabledNativeClass}
|
|
429
|
+
title={labels.navImplementationUnavailableTooltip}
|
|
430
|
+
aria-label={labels.navImplementationUnavailableTooltip}
|
|
431
|
+
>
|
|
432
|
+
<FileCode2
|
|
433
|
+
size={20}
|
|
434
|
+
strokeWidth={2}
|
|
435
|
+
className="shrink-0"
|
|
436
|
+
aria-hidden
|
|
437
|
+
/>
|
|
438
|
+
</button>
|
|
439
|
+
)}
|
|
440
|
+
</div>
|
|
441
|
+
|
|
442
|
+
<div
|
|
443
|
+
role="group"
|
|
444
|
+
aria-label={labels.navGroupToolsAria}
|
|
445
|
+
className={ribbonGroupClass}
|
|
446
|
+
>
|
|
447
|
+
{ganttControl ? (
|
|
448
|
+
<button
|
|
449
|
+
type="button"
|
|
450
|
+
onClick={ganttControl.onPress}
|
|
451
|
+
className={iconLinkClass}
|
|
452
|
+
title={ganttControl.label}
|
|
453
|
+
aria-label={ganttControl.label}
|
|
454
|
+
>
|
|
455
|
+
<LayoutGrid
|
|
456
|
+
size={20}
|
|
457
|
+
strokeWidth={2}
|
|
458
|
+
className="shrink-0"
|
|
459
|
+
aria-hidden
|
|
460
|
+
/>
|
|
461
|
+
</button>
|
|
462
|
+
) : (
|
|
463
|
+
<button
|
|
464
|
+
type="button"
|
|
465
|
+
disabled
|
|
466
|
+
className={iconButtonDisabledNativeClass}
|
|
467
|
+
title={labels.navGanttDashboardOnlyTooltip}
|
|
468
|
+
aria-label={`${labels.navGanttButtonLabel}. ${labels.navGanttDashboardOnlyTooltip}`}
|
|
469
|
+
>
|
|
470
|
+
<LayoutGrid
|
|
471
|
+
size={20}
|
|
472
|
+
strokeWidth={2}
|
|
473
|
+
className="shrink-0"
|
|
474
|
+
aria-hidden
|
|
475
|
+
/>
|
|
476
|
+
</button>
|
|
477
|
+
)}
|
|
478
|
+
{globalPauseControl ? (
|
|
479
|
+
<AppShellGlobalPauseButton control={globalPauseControl} />
|
|
480
|
+
) : (
|
|
481
|
+
<AppShellGlobalPauseButton
|
|
482
|
+
control={{
|
|
483
|
+
active: false,
|
|
484
|
+
label: labels.navGlobalPauseButtonLabel,
|
|
485
|
+
disabled: true,
|
|
486
|
+
disabledTooltip:
|
|
487
|
+
current === "dashboard"
|
|
488
|
+
? labels.navGlobalPauseNoSessionContextTooltip
|
|
489
|
+
: labels.navGlobalPauseDashboardOnlyTooltip,
|
|
490
|
+
onPress: () => {},
|
|
491
|
+
}}
|
|
396
492
|
/>
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
493
|
+
)}
|
|
494
|
+
</div>
|
|
495
|
+
|
|
496
|
+
<div
|
|
497
|
+
role="group"
|
|
498
|
+
aria-label={labels.navGroupLegalAria}
|
|
499
|
+
className={ribbonGroupClass}
|
|
500
|
+
>
|
|
501
|
+
{current === "licenses" ? (
|
|
502
|
+
<span
|
|
503
|
+
className={iconActiveClass}
|
|
504
|
+
title={licensesTitle}
|
|
505
|
+
aria-label={licensesTitle}
|
|
506
|
+
aria-current="page"
|
|
507
|
+
>
|
|
508
|
+
<FileText
|
|
509
|
+
size={20}
|
|
510
|
+
strokeWidth={2}
|
|
511
|
+
className="shrink-0"
|
|
512
|
+
aria-hidden
|
|
513
|
+
/>
|
|
514
|
+
</span>
|
|
515
|
+
) : (
|
|
516
|
+
<Link
|
|
517
|
+
href={dash("/licenses")}
|
|
518
|
+
className={iconLinkClass}
|
|
519
|
+
title={licensesTitle}
|
|
520
|
+
aria-label={licensesTitle}
|
|
521
|
+
>
|
|
522
|
+
<FileText
|
|
523
|
+
size={20}
|
|
524
|
+
strokeWidth={2}
|
|
525
|
+
className="shrink-0"
|
|
526
|
+
aria-hidden
|
|
527
|
+
/>
|
|
528
|
+
</Link>
|
|
529
|
+
)}
|
|
530
|
+
</div>
|
|
404
531
|
</nav>
|
|
405
532
|
);
|
|
406
533
|
}
|