@nightkatana/kronosys-app 1.0.0-beta.20 → 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 +26 -0
- package/lib/implementationNotes.ts +22 -18
- 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/taskParsing.ts +44 -16
- package/lib/userGuideCopy.ts +33 -30
- package/package.json +7 -5
- package/server/db.ts +6 -4
- package/server/dbSchema.ts +2 -2
- package/components/dashboard/AppShellCommandCenterPlaceholder.tsx +0 -17
package/README.md
CHANGED
|
@@ -99,7 +99,7 @@ Sinon : `NODE_EXTRA_CA_CERTS` pointant vers le PEM racine de l’organisation, o
|
|
|
99
99
|
|
|
100
100
|
## Publication npm (`@nightkatana/kronosys-app`)
|
|
101
101
|
|
|
102
|
-
La version est définie dans `package.json` (référence actuelle : **`1.0.0-beta.
|
|
102
|
+
La version est définie dans `package.json` (référence actuelle : **`1.0.0-beta.22`**). Avant la première publication : créer le scope **@nightkatana** sur [npmjs.com](https://www.npmjs.com/) si besoin, puis `npm login`. Depuis ce dossier :
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
105
|
npm publish --access public
|
package/app/changelog/page.tsx
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { Suspense, useMemo } from "react";
|
|
3
|
+
import { Suspense, useCallback, useMemo } from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { useSearchParams } from "next/navigation";
|
|
6
6
|
import ReactMarkdown, { type Components } from "react-markdown";
|
|
7
7
|
import { AppVersionStamp } from "@/components/dashboard/AppVersionStamp";
|
|
8
|
+
import { AppShellHeaderKronoFocus } from "@/components/dashboard/AppShellHeaderKronoFocus";
|
|
9
|
+
import { AppShellHeaderSessionMeta } from "@/components/dashboard/AppShellHeaderSessionMeta";
|
|
8
10
|
import { AppShellHeaderWallClock } from "@/components/dashboard/AppShellHeaderWallClock";
|
|
11
|
+
import { AppShellHeaderUtilityRibbon } from "@/components/dashboard/AppShellHeaderUtilityRibbon";
|
|
12
|
+
import { AppShellToolbarCommandCenter } from "@/components/dashboard/AppShellToolbarCommandCenter";
|
|
13
|
+
import { AppShellToolbarRouteNav } from "@/components/dashboard/AppShellToolbarRouteNav";
|
|
14
|
+
import { LanguageMenu } from "@/components/dashboard/LanguageMenu";
|
|
9
15
|
import { ThemeToggle } from "@/components/dashboard/ThemeToggle";
|
|
10
16
|
import { PageRefreshButton } from "@/components/dashboard/PageRefreshButton";
|
|
11
17
|
import { ScrollToTopFab } from "@/components/dashboard/ScrollToTopFab";
|
|
12
18
|
import { useKronosysPayload } from "@/components/KronosysPayloadProvider";
|
|
13
19
|
import {
|
|
14
20
|
appShellHeaderClassName,
|
|
15
|
-
|
|
21
|
+
appShellHeaderTitleMetaRowClassName,
|
|
16
22
|
} from "@/lib/appShellHeaderClasses";
|
|
23
|
+
import { AppShellHeaderToolbarLayout } from "@/components/dashboard/AppShellHeaderToolbarLayout";
|
|
17
24
|
import { changelogBundle } from "@/lib/changelogCopy";
|
|
18
25
|
import { dashboardStrings, type Lang } from "@/lib/dashboardCopy";
|
|
19
26
|
import { withDashboardSessionParam } from "@/lib/dashboardSessionNav";
|
|
27
|
+
import { postKronosysAction } from "@/lib/kronosysApi";
|
|
28
|
+
import { reportingNav } from "@/lib/reportingStrings";
|
|
20
29
|
|
|
21
30
|
type LiveShape = { language?: string };
|
|
22
31
|
|
|
@@ -77,11 +86,28 @@ function ChangelogBody() {
|
|
|
77
86
|
const lang: Lang = live?.language === "fr" ? "fr" : "en";
|
|
78
87
|
const dt = dashboardStrings(lang);
|
|
79
88
|
const c = useMemo(() => changelogBundle(lang), [lang]);
|
|
89
|
+
const nav = useMemo(() => reportingNav(lang), [lang]);
|
|
90
|
+
|
|
91
|
+
const postLang = useCallback(
|
|
92
|
+
async (next: Lang) => {
|
|
93
|
+
await postKronosysAction({ type: "setLanguage", lang: next });
|
|
94
|
+
await refresh({ routerInvalidate: true });
|
|
95
|
+
},
|
|
96
|
+
[refresh],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const postHeaderAction = useCallback(
|
|
100
|
+
async (body: Record<string, unknown>) => {
|
|
101
|
+
await postKronosysAction(body);
|
|
102
|
+
await refresh({ routerInvalidate: true });
|
|
103
|
+
},
|
|
104
|
+
[refresh],
|
|
105
|
+
);
|
|
80
106
|
|
|
81
107
|
return (
|
|
82
108
|
<div className="min-h-screen bg-zinc-100 text-zinc-900 dark:bg-zinc-900 dark:text-zinc-100">
|
|
83
109
|
<header className={appShellHeaderClassName}>
|
|
84
|
-
<div className={
|
|
110
|
+
<div className={appShellHeaderTitleMetaRowClassName}>
|
|
85
111
|
<div className="flex min-w-0 flex-col gap-1">
|
|
86
112
|
<div className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5">
|
|
87
113
|
<Link
|
|
@@ -105,23 +131,65 @@ function ChangelogBody() {
|
|
|
105
131
|
<AppVersionStamp ariaLabelTemplate={dt.appVersionAriaLabel} />
|
|
106
132
|
</p>
|
|
107
133
|
</div>
|
|
108
|
-
<
|
|
109
|
-
<AppShellHeaderWallClock lang={lang} dt={dt} />
|
|
110
|
-
<ThemeToggle lang={lang} />
|
|
111
|
-
<PageRefreshButton
|
|
112
|
-
title={dt.pageRefreshTitle}
|
|
113
|
-
ariaLabel={dt.pageRefreshAriaLabel}
|
|
114
|
-
inlineMessages={{
|
|
115
|
-
loading: dt.pageRefreshProgressLabel,
|
|
116
|
-
success: dt.pageRefreshDoneToast,
|
|
117
|
-
error: dt.pageRefreshFailedToast,
|
|
118
|
-
}}
|
|
119
|
-
onRefresh={async () => {
|
|
120
|
-
return await refresh({ routerInvalidate: true });
|
|
121
|
-
}}
|
|
122
|
-
/>
|
|
123
|
-
</div>
|
|
134
|
+
<AppShellHeaderSessionMeta payload={payload} dt={dt} />
|
|
124
135
|
</div>
|
|
136
|
+
<AppShellHeaderToolbarLayout
|
|
137
|
+
leading={
|
|
138
|
+
<>
|
|
139
|
+
<AppShellHeaderWallClock lang={lang} dt={dt} />
|
|
140
|
+
<AppShellHeaderKronoFocus
|
|
141
|
+
payload={payload}
|
|
142
|
+
dt={dt}
|
|
143
|
+
post={postHeaderAction}
|
|
144
|
+
/>
|
|
145
|
+
<AppShellToolbarCommandCenter
|
|
146
|
+
dt={dt}
|
|
147
|
+
lang={lang}
|
|
148
|
+
dashboardSessionNavId={dashboardSessionNavId}
|
|
149
|
+
onManualRefresh={() => refresh({ routerInvalidate: true })}
|
|
150
|
+
/>
|
|
151
|
+
</>
|
|
152
|
+
}
|
|
153
|
+
nav={
|
|
154
|
+
<AppShellToolbarRouteNav
|
|
155
|
+
current="changelog"
|
|
156
|
+
labels={nav}
|
|
157
|
+
navAriaLabel={dt.appShellRouteNavAria}
|
|
158
|
+
dashboardSessionId={dashboardSessionNavId}
|
|
159
|
+
lang={lang}
|
|
160
|
+
dt={dt}
|
|
161
|
+
/>
|
|
162
|
+
}
|
|
163
|
+
trailing={
|
|
164
|
+
<AppShellHeaderUtilityRibbon
|
|
165
|
+
ariaLabel={dt.appShellUtilityToolbarGroupAria}
|
|
166
|
+
>
|
|
167
|
+
<ThemeToggle lang={lang} />
|
|
168
|
+
<PageRefreshButton
|
|
169
|
+
title={dt.pageRefreshTitle}
|
|
170
|
+
ariaLabel={dt.pageRefreshAriaLabel}
|
|
171
|
+
inlineMessages={{
|
|
172
|
+
loading: dt.pageRefreshProgressLabel,
|
|
173
|
+
success: dt.pageRefreshDoneToast,
|
|
174
|
+
error: dt.pageRefreshFailedToast,
|
|
175
|
+
}}
|
|
176
|
+
onRefresh={async () => {
|
|
177
|
+
return await refresh({ routerInvalidate: true });
|
|
178
|
+
}}
|
|
179
|
+
/>
|
|
180
|
+
<LanguageMenu
|
|
181
|
+
lang={lang}
|
|
182
|
+
labelEn="English"
|
|
183
|
+
labelFr="Français"
|
|
184
|
+
menuHeading={lang === "fr" ? "Langue" : "Language"}
|
|
185
|
+
triggerAriaLabel={
|
|
186
|
+
lang === "fr" ? "Langue de l’interface" : "Interface language"
|
|
187
|
+
}
|
|
188
|
+
onSelect={(next) => void postLang(next)}
|
|
189
|
+
/>
|
|
190
|
+
</AppShellHeaderUtilityRibbon>
|
|
191
|
+
}
|
|
192
|
+
/>
|
|
125
193
|
</header>
|
|
126
194
|
|
|
127
195
|
<main className="mx-auto w-full max-w-3xl px-5 pb-16 pt-6 sm:px-8 lg:px-10">
|
package/app/globals.css
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
:root {
|
|
8
8
|
/* Aligné sur le remap zinc clair (chaud, moins d’éblouissement). */
|
|
9
9
|
--background: oklch(93.8% 0.011 82);
|
|
10
|
-
|
|
10
|
+
/* Même teinte que zinc-900 du thème clair (évite texte légèrement bleuté sur fond chaud). */
|
|
11
|
+
--foreground: oklch(24.5% 0.013 84);
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
html.dark {
|
|
@@ -34,13 +35,14 @@ html:not(.dark) {
|
|
|
34
35
|
--color-zinc-100: oklch(93.8% 0.011 82);
|
|
35
36
|
--color-zinc-200: oklch(88.5% 0.012 84);
|
|
36
37
|
--color-zinc-300: oklch(82% 0.014 84);
|
|
37
|
-
|
|
38
|
-
--color-zinc-
|
|
39
|
-
--color-zinc-
|
|
40
|
-
--color-zinc-
|
|
41
|
-
--color-zinc-
|
|
42
|
-
--color-zinc-
|
|
43
|
-
--color-zinc-
|
|
38
|
+
/* Même famille chaude que zinc-50…300 (évite le saut vers ~280° qui « violettait » bordures / secondaire). */
|
|
39
|
+
--color-zinc-400: oklch(68% 0.014 84);
|
|
40
|
+
--color-zinc-500: oklch(54% 0.016 84);
|
|
41
|
+
--color-zinc-600: oklch(44% 0.015 84);
|
|
42
|
+
--color-zinc-700: oklch(37% 0.014 84);
|
|
43
|
+
--color-zinc-800: oklch(30% 0.013 84);
|
|
44
|
+
--color-zinc-900: oklch(24.5% 0.013 84);
|
|
45
|
+
--color-zinc-950: oklch(18% 0.012 84);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
body {
|
package/app/guide/page.tsx
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Suspense,
|
|
5
|
+
useCallback,
|
|
6
|
+
useMemo,
|
|
7
|
+
useState,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
} from "react";
|
|
4
10
|
import Link from "next/link";
|
|
5
11
|
import { useSearchParams } from "next/navigation";
|
|
6
12
|
import { BookOpen, Search, X } from "lucide-react";
|
|
@@ -10,12 +16,14 @@ import { AppVersionStamp } from "@/components/dashboard/AppVersionStamp";
|
|
|
10
16
|
import {
|
|
11
17
|
appShellHeaderClassName,
|
|
12
18
|
appShellHeaderTitleMetaRowClassName,
|
|
13
|
-
appShellHeaderToolbarClassName,
|
|
14
19
|
} from "@/lib/appShellHeaderClasses";
|
|
15
|
-
import {
|
|
20
|
+
import { AppShellHeaderToolbarLayout } from "@/components/dashboard/AppShellHeaderToolbarLayout";
|
|
21
|
+
import { AppShellToolbarCommandCenter } from "@/components/dashboard/AppShellToolbarCommandCenter";
|
|
16
22
|
import { AppShellHeaderSessionMeta } from "@/components/dashboard/AppShellHeaderSessionMeta";
|
|
17
23
|
import { AppShellHeaderWallClock } from "@/components/dashboard/AppShellHeaderWallClock";
|
|
18
|
-
import {
|
|
24
|
+
import { AppShellHeaderKronoFocus } from "@/components/dashboard/AppShellHeaderKronoFocus";
|
|
25
|
+
import { AppShellHeaderUtilityRibbon } from "@/components/dashboard/AppShellHeaderUtilityRibbon";
|
|
26
|
+
import { AppShellToolbarRouteNav } from "@/components/dashboard/AppShellToolbarRouteNav";
|
|
19
27
|
import { UserGuideBodyText } from "@/components/dashboard/UserGuideBodyText";
|
|
20
28
|
import { ThemeToggle } from "@/components/dashboard/ThemeToggle";
|
|
21
29
|
import { PageRefreshButton } from "@/components/dashboard/PageRefreshButton";
|
|
@@ -64,6 +72,14 @@ function GuideContent() {
|
|
|
64
72
|
await refresh();
|
|
65
73
|
};
|
|
66
74
|
|
|
75
|
+
const postHeaderAction = useCallback(
|
|
76
|
+
async (body: Record<string, unknown>) => {
|
|
77
|
+
await postKronosysAction(body);
|
|
78
|
+
await refresh({ routerInvalidate: true });
|
|
79
|
+
},
|
|
80
|
+
[refresh],
|
|
81
|
+
);
|
|
82
|
+
|
|
67
83
|
const bulletList = (
|
|
68
84
|
lines: string[],
|
|
69
85
|
idPrefix: string,
|
|
@@ -120,42 +136,63 @@ function GuideContent() {
|
|
|
120
136
|
</div>
|
|
121
137
|
<AppShellHeaderSessionMeta payload={payload} dt={dt} />
|
|
122
138
|
</div>
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
139
|
+
<AppShellHeaderToolbarLayout
|
|
140
|
+
leading={
|
|
141
|
+
<>
|
|
142
|
+
<AppShellHeaderWallClock lang={lang} dt={dt} />
|
|
143
|
+
<AppShellHeaderKronoFocus
|
|
144
|
+
payload={payload}
|
|
145
|
+
dt={dt}
|
|
146
|
+
post={postHeaderAction}
|
|
147
|
+
/>
|
|
148
|
+
<AppShellToolbarCommandCenter
|
|
149
|
+
dt={dt}
|
|
150
|
+
lang={lang}
|
|
151
|
+
dashboardSessionNavId={dashboardSessionNavId}
|
|
152
|
+
onManualRefresh={() => refresh({ routerInvalidate: true })}
|
|
153
|
+
/>
|
|
154
|
+
</>
|
|
155
|
+
}
|
|
156
|
+
nav={
|
|
157
|
+
<AppShellToolbarRouteNav
|
|
128
158
|
current="guide"
|
|
129
159
|
labels={nav}
|
|
130
160
|
navAriaLabel={dt.appShellRouteNavAria}
|
|
131
161
|
dashboardSessionId={dashboardSessionNavId}
|
|
132
|
-
reserveGlobalPauseSlot
|
|
133
|
-
/>
|
|
134
|
-
<ThemeToggle lang={lang} />
|
|
135
|
-
<PageRefreshButton
|
|
136
|
-
title={dt.pageRefreshTitle}
|
|
137
|
-
ariaLabel={dt.pageRefreshAriaLabel}
|
|
138
|
-
inlineMessages={{
|
|
139
|
-
loading: dt.pageRefreshProgressLabel,
|
|
140
|
-
success: dt.pageRefreshDoneToast,
|
|
141
|
-
error: dt.pageRefreshFailedToast,
|
|
142
|
-
}}
|
|
143
|
-
onRefresh={async () => {
|
|
144
|
-
return await refresh({ routerInvalidate: true });
|
|
145
|
-
}}
|
|
146
|
-
/>
|
|
147
|
-
<LanguageMenu
|
|
148
162
|
lang={lang}
|
|
149
|
-
|
|
150
|
-
labelFr="Français"
|
|
151
|
-
menuHeading={lang === "fr" ? "Langue" : "Language"}
|
|
152
|
-
triggerAriaLabel={
|
|
153
|
-
lang === "fr" ? "Langue de l’interface" : "Interface language"
|
|
154
|
-
}
|
|
155
|
-
onSelect={(next) => void postLang(next)}
|
|
163
|
+
dt={dt}
|
|
156
164
|
/>
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
}
|
|
166
|
+
trailing={
|
|
167
|
+
<AppShellHeaderUtilityRibbon
|
|
168
|
+
ariaLabel={dt.appShellUtilityToolbarGroupAria}
|
|
169
|
+
>
|
|
170
|
+
<ThemeToggle lang={lang} />
|
|
171
|
+
<PageRefreshButton
|
|
172
|
+
title={dt.pageRefreshTitle}
|
|
173
|
+
ariaLabel={dt.pageRefreshAriaLabel}
|
|
174
|
+
inlineMessages={{
|
|
175
|
+
loading: dt.pageRefreshProgressLabel,
|
|
176
|
+
success: dt.pageRefreshDoneToast,
|
|
177
|
+
error: dt.pageRefreshFailedToast,
|
|
178
|
+
}}
|
|
179
|
+
onRefresh={async () => {
|
|
180
|
+
return await refresh({ routerInvalidate: true });
|
|
181
|
+
}}
|
|
182
|
+
/>
|
|
183
|
+
<LanguageMenu
|
|
184
|
+
lang={lang}
|
|
185
|
+
labelEn="English"
|
|
186
|
+
labelFr="Français"
|
|
187
|
+
menuHeading={lang === "fr" ? "Langue" : "Language"}
|
|
188
|
+
triggerAriaLabel={
|
|
189
|
+
lang === "fr" ? "Langue de l’interface" : "Interface language"
|
|
190
|
+
}
|
|
191
|
+
onSelect={(next) => void postLang(next)}
|
|
192
|
+
/>
|
|
193
|
+
</AppShellHeaderUtilityRibbon>
|
|
194
|
+
}
|
|
195
|
+
/>
|
|
159
196
|
</header>
|
|
160
197
|
|
|
161
198
|
<main
|
|
@@ -10,29 +10,23 @@ import {
|
|
|
10
10
|
} from "react";
|
|
11
11
|
import Link from "next/link";
|
|
12
12
|
import { useSearchParams } from "next/navigation";
|
|
13
|
-
import {
|
|
14
|
-
Ban,
|
|
15
|
-
Check,
|
|
16
|
-
ChevronDown,
|
|
17
|
-
Copy,
|
|
18
|
-
FileCode2,
|
|
19
|
-
ScrollText,
|
|
20
|
-
X,
|
|
21
|
-
} from "lucide-react";
|
|
13
|
+
import { Ban, Check, ChevronDown, Copy, FileCode2, X } from "lucide-react";
|
|
22
14
|
import { AppVersionStamp } from "@/components/dashboard/AppVersionStamp";
|
|
23
15
|
import { ThemeToggle } from "@/components/dashboard/ThemeToggle";
|
|
24
16
|
import { PageRefreshButton } from "@/components/dashboard/PageRefreshButton";
|
|
25
17
|
import { ScrollToTopFab } from "@/components/dashboard/ScrollToTopFab";
|
|
26
|
-
import {
|
|
18
|
+
import { AppShellToolbarRouteNav } from "@/components/dashboard/AppShellToolbarRouteNav";
|
|
27
19
|
import { useKronosysPayload } from "@/components/KronosysPayloadProvider";
|
|
28
20
|
import {
|
|
29
21
|
appShellHeaderClassName,
|
|
30
22
|
appShellHeaderTitleMetaRowClassName,
|
|
31
|
-
appShellHeaderToolbarClassName,
|
|
32
23
|
} from "@/lib/appShellHeaderClasses";
|
|
33
|
-
import {
|
|
24
|
+
import { AppShellHeaderToolbarLayout } from "@/components/dashboard/AppShellHeaderToolbarLayout";
|
|
25
|
+
import { AppShellToolbarCommandCenter } from "@/components/dashboard/AppShellToolbarCommandCenter";
|
|
34
26
|
import { AppShellHeaderSessionMeta } from "@/components/dashboard/AppShellHeaderSessionMeta";
|
|
35
27
|
import { AppShellHeaderWallClock } from "@/components/dashboard/AppShellHeaderWallClock";
|
|
28
|
+
import { AppShellHeaderKronoFocus } from "@/components/dashboard/AppShellHeaderKronoFocus";
|
|
29
|
+
import { AppShellHeaderUtilityRibbon } from "@/components/dashboard/AppShellHeaderUtilityRibbon";
|
|
36
30
|
import { dashboardStrings, type Lang } from "@/lib/dashboardCopy";
|
|
37
31
|
import { withDashboardSessionParam } from "@/lib/dashboardSessionNav";
|
|
38
32
|
import { implementationNotesBundle } from "@/lib/implementationNotes";
|
|
@@ -75,12 +69,7 @@ function coverageScreenReaderLabel(
|
|
|
75
69
|
? `${columnLabel} : sans objet pour une ligne écartée.`
|
|
76
70
|
: `${columnLabel}: not applicable for a discarded intent.`;
|
|
77
71
|
}
|
|
78
|
-
const yn =
|
|
79
|
-
lang === "fr"
|
|
80
|
-
? checked ? "oui" : "non"
|
|
81
|
-
: checked
|
|
82
|
-
? "yes"
|
|
83
|
-
: "no";
|
|
72
|
+
const yn = lang === "fr" ? (checked ? "oui" : "non") : checked ? "yes" : "no";
|
|
84
73
|
return `${columnLabel}: ${yn}`;
|
|
85
74
|
}
|
|
86
75
|
|
|
@@ -145,7 +134,10 @@ function ImplementationGlyph(
|
|
|
145
134
|
const { implemented, discarded } = props;
|
|
146
135
|
if (discarded) {
|
|
147
136
|
return (
|
|
148
|
-
<span
|
|
137
|
+
<span
|
|
138
|
+
className="inline-flex text-zinc-400 dark:text-zinc-500"
|
|
139
|
+
aria-hidden
|
|
140
|
+
>
|
|
149
141
|
<Ban className="size-4 shrink-0" strokeWidth={2.5} />
|
|
150
142
|
</span>
|
|
151
143
|
);
|
|
@@ -310,6 +302,14 @@ function ImplementationBody() {
|
|
|
310
302
|
await refresh();
|
|
311
303
|
};
|
|
312
304
|
|
|
305
|
+
const postHeaderAction = useCallback(
|
|
306
|
+
async (body: Record<string, unknown>) => {
|
|
307
|
+
await postKronosysAction(body);
|
|
308
|
+
await refresh({ routerInvalidate: true });
|
|
309
|
+
},
|
|
310
|
+
[refresh],
|
|
311
|
+
);
|
|
312
|
+
|
|
313
313
|
const copyStoryId = useCallback((storyId: string) => {
|
|
314
314
|
copyTextToClipboard(storyId).then((ok) =>
|
|
315
315
|
applyStoryCopyResult(storyId, ok, setCopyFeedback),
|
|
@@ -351,53 +351,63 @@ function ImplementationBody() {
|
|
|
351
351
|
</div>
|
|
352
352
|
<AppShellHeaderSessionMeta payload={payload} dt={dt} />
|
|
353
353
|
</div>
|
|
354
|
-
<
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
354
|
+
<AppShellHeaderToolbarLayout
|
|
355
|
+
leading={
|
|
356
|
+
<>
|
|
357
|
+
<AppShellHeaderWallClock lang={lang} dt={dt} />
|
|
358
|
+
<AppShellHeaderKronoFocus
|
|
359
|
+
payload={payload}
|
|
360
|
+
dt={dt}
|
|
361
|
+
post={postHeaderAction}
|
|
362
|
+
/>
|
|
363
|
+
<AppShellToolbarCommandCenter
|
|
364
|
+
dt={dt}
|
|
365
|
+
lang={lang}
|
|
366
|
+
dashboardSessionNavId={dashboardSessionNavId}
|
|
367
|
+
onManualRefresh={() => refresh({ routerInvalidate: true })}
|
|
368
|
+
/>
|
|
369
|
+
</>
|
|
370
|
+
}
|
|
371
|
+
nav={
|
|
372
|
+
<AppShellToolbarRouteNav
|
|
370
373
|
current="implementation"
|
|
371
374
|
labels={nav}
|
|
372
375
|
navAriaLabel={dt.appShellRouteNavAria}
|
|
373
376
|
dashboardSessionId={dashboardSessionNavId}
|
|
374
|
-
reserveGlobalPauseSlot
|
|
375
|
-
/>
|
|
376
|
-
<ThemeToggle lang={lang} />
|
|
377
|
-
<PageRefreshButton
|
|
378
|
-
title={dt.pageRefreshTitle}
|
|
379
|
-
ariaLabel={dt.pageRefreshAriaLabel}
|
|
380
|
-
inlineMessages={{
|
|
381
|
-
loading: dt.pageRefreshProgressLabel,
|
|
382
|
-
success: dt.pageRefreshDoneToast,
|
|
383
|
-
error: dt.pageRefreshFailedToast,
|
|
384
|
-
}}
|
|
385
|
-
onRefresh={async () => {
|
|
386
|
-
return await refresh({ routerInvalidate: true });
|
|
387
|
-
}}
|
|
388
|
-
/>
|
|
389
|
-
<LanguageMenu
|
|
390
377
|
lang={lang}
|
|
391
|
-
|
|
392
|
-
labelFr="Français"
|
|
393
|
-
menuHeading={lang === "fr" ? "Langue" : "Language"}
|
|
394
|
-
triggerAriaLabel={
|
|
395
|
-
lang === "fr" ? "Langue de l’interface" : "Interface language"
|
|
396
|
-
}
|
|
397
|
-
onSelect={(next) => void postLang(next)}
|
|
378
|
+
dt={dt}
|
|
398
379
|
/>
|
|
399
|
-
|
|
400
|
-
|
|
380
|
+
}
|
|
381
|
+
trailing={
|
|
382
|
+
<AppShellHeaderUtilityRibbon
|
|
383
|
+
ariaLabel={dt.appShellUtilityToolbarGroupAria}
|
|
384
|
+
>
|
|
385
|
+
<ThemeToggle lang={lang} />
|
|
386
|
+
<PageRefreshButton
|
|
387
|
+
title={dt.pageRefreshTitle}
|
|
388
|
+
ariaLabel={dt.pageRefreshAriaLabel}
|
|
389
|
+
inlineMessages={{
|
|
390
|
+
loading: dt.pageRefreshProgressLabel,
|
|
391
|
+
success: dt.pageRefreshDoneToast,
|
|
392
|
+
error: dt.pageRefreshFailedToast,
|
|
393
|
+
}}
|
|
394
|
+
onRefresh={async () => {
|
|
395
|
+
return await refresh({ routerInvalidate: true });
|
|
396
|
+
}}
|
|
397
|
+
/>
|
|
398
|
+
<LanguageMenu
|
|
399
|
+
lang={lang}
|
|
400
|
+
labelEn="English"
|
|
401
|
+
labelFr="Français"
|
|
402
|
+
menuHeading={lang === "fr" ? "Langue" : "Language"}
|
|
403
|
+
triggerAriaLabel={
|
|
404
|
+
lang === "fr" ? "Langue de l’interface" : "Interface language"
|
|
405
|
+
}
|
|
406
|
+
onSelect={(next) => void postLang(next)}
|
|
407
|
+
/>
|
|
408
|
+
</AppShellHeaderUtilityRibbon>
|
|
409
|
+
}
|
|
410
|
+
/>
|
|
401
411
|
</header>
|
|
402
412
|
|
|
403
413
|
<main className="mx-auto w-full max-w-4xl px-5 pb-16 pt-6 sm:px-8 lg:px-10">
|