@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
package/lib/reportingStrings.ts
CHANGED
|
@@ -15,8 +15,32 @@ export type ReportingNavStrings = {
|
|
|
15
15
|
guide: string;
|
|
16
16
|
/** Page inventaire des user stories (`/implementation`). */
|
|
17
17
|
implementation: string;
|
|
18
|
+
/** Journal des versions (`/changelog`). */
|
|
19
|
+
changelog: string;
|
|
18
20
|
/** Infobulle lorsque l’icône tableau de bord pulse (rappel conflit minuteurs). */
|
|
19
21
|
dashboardAttentionHint?: string;
|
|
22
|
+
/** Infobulle : Gantt du jour réservé au tableau de bord. */
|
|
23
|
+
navGanttDashboardOnlyTooltip: string;
|
|
24
|
+
/** Infobulle : pause globale réservée au tableau de bord (session live). */
|
|
25
|
+
navGlobalPauseDashboardOnlyTooltip: string;
|
|
26
|
+
/** Infobulle : pause globale indisponible sur le tableau de bord (archive ou chargement). */
|
|
27
|
+
navGlobalPauseNoSessionContextTooltip: string;
|
|
28
|
+
/** Infobulle : changelog indisponible (libellé vide sur cette route). */
|
|
29
|
+
navChangelogUnavailableTooltip: string;
|
|
30
|
+
/** Infobulle : implémentation indisponible (libellé vide sur cette route). */
|
|
31
|
+
navImplementationUnavailableTooltip: string;
|
|
32
|
+
/** Libellé du bouton Gantt (barre de navigation). */
|
|
33
|
+
navGanttButtonLabel: string;
|
|
34
|
+
/** Libellé du bouton pause globale (barre de navigation). */
|
|
35
|
+
navGlobalPauseButtonLabel: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Libellés passés à `AppShellRouteNav` (inclut les groupes type ruban pour l’accessibilité). */
|
|
39
|
+
export type AppShellRouteNavLabelBundle = ReportingNavStrings & {
|
|
40
|
+
navGroupAppAria: string;
|
|
41
|
+
navGroupDocsAria: string;
|
|
42
|
+
navGroupToolsAria: string;
|
|
43
|
+
navGroupLegalAria: string;
|
|
20
44
|
};
|
|
21
45
|
|
|
22
46
|
export type ReportingStrings = ReportingNavStrings &
|
|
@@ -110,6 +134,12 @@ export type ReportingStrings = ReportingNavStrings &
|
|
|
110
134
|
projectColTime: string;
|
|
111
135
|
projectUnassigned: string;
|
|
112
136
|
projectTableHint: string;
|
|
137
|
+
/** Légende du sélecteur Travail / Personnel sur la grille par projet. */
|
|
138
|
+
projectScopeLegend: string;
|
|
139
|
+
/** aria-label du radiogroupe Travail / Personnel. */
|
|
140
|
+
projectScopeGroupAria: string;
|
|
141
|
+
projectScopeWork: string;
|
|
142
|
+
projectScopePersonal: string;
|
|
113
143
|
/** Temps tâche par #tag — usage type affectation WBS / NWA (SAP). */
|
|
114
144
|
tagTimeSectionTitle: string;
|
|
115
145
|
tagTimeSectionHint: string;
|
|
@@ -175,6 +205,18 @@ export type ReportingStrings = ReportingNavStrings &
|
|
|
175
205
|
weekNavNoProjectDataThisWeek: string;
|
|
176
206
|
/** Section lignes écrites + tableaux par langage (agrégés). */
|
|
177
207
|
tocLocSection: string;
|
|
208
|
+
/** Sommaire : entrée des trois vues (facturation / rythme / avancé). */
|
|
209
|
+
tocViewTabs: string;
|
|
210
|
+
/** Onglet — temps par #tag et @projet pour codifier la facturation. */
|
|
211
|
+
reportingViewTabBilling: string;
|
|
212
|
+
/** Onglet — graphiques d’activité par jour. */
|
|
213
|
+
reportingViewTabRhythm: string;
|
|
214
|
+
/** Onglet — indicateurs détaillés, tableau journalier, instantané workspace. */
|
|
215
|
+
reportingViewTabAdvanced: string;
|
|
216
|
+
/** aria-label du groupe d’onglets sous les filtres. */
|
|
217
|
+
reportingViewTabGroupAria: string;
|
|
218
|
+
/** Court texte d’intention sous l’onglet facturation. */
|
|
219
|
+
reportingViewBillingIntro: string;
|
|
178
220
|
/** Bouton flottant retour en haut de page. */
|
|
179
221
|
scrollToTopAria: string;
|
|
180
222
|
};
|
|
@@ -185,10 +227,24 @@ const en: ReportingStrings = {
|
|
|
185
227
|
settings: "Settings",
|
|
186
228
|
logs: "Action logs",
|
|
187
229
|
guide: "User guide",
|
|
230
|
+
changelog: "Changelog",
|
|
188
231
|
implementation: "User stories — implementation",
|
|
232
|
+
navGanttDashboardOnlyTooltip:
|
|
233
|
+
"Today’s Gantt is available from the dashboard only.",
|
|
234
|
+
navGlobalPauseDashboardOnlyTooltip:
|
|
235
|
+
"Global pause is available from the dashboard when a live session is loaded.",
|
|
236
|
+
navGlobalPauseNoSessionContextTooltip:
|
|
237
|
+
"Global pause is not available while you inspect an archived session or before the live session is loaded.",
|
|
238
|
+
navChangelogUnavailableTooltip:
|
|
239
|
+
"Changelog shortcut is hidden on this screen (no label).",
|
|
240
|
+
navImplementationUnavailableTooltip:
|
|
241
|
+
"Implementation shortcut is hidden on this screen (no label).",
|
|
242
|
+
navGanttButtonLabel: "Open today timeline (Gantt)",
|
|
243
|
+
navGlobalPauseButtonLabel:
|
|
244
|
+
"Pause session, tasks, and subtasks in this context",
|
|
189
245
|
title: "Reporting",
|
|
190
246
|
subtitle:
|
|
191
|
-
"
|
|
247
|
+
"See where time was allocated on the range (tags, projects) to help encode billing lines. Filters apply to history below; the workspace snapshot (if shown) is under Advanced.",
|
|
192
248
|
archivedSessionsReportingNote:
|
|
193
249
|
"Archived sessions: task rows, recorded task time, time by project, and per-task KronoFocus counts include only tasks marked done with every subtask checked. Session-level coding and active time still cover the whole session.",
|
|
194
250
|
reportingArchivedExcludedAside:
|
|
@@ -210,9 +266,11 @@ const en: ReportingStrings = {
|
|
|
210
266
|
filtersHelpAriaLabel: "How reporting filters apply",
|
|
211
267
|
filtersHelpBody: `Where dates and tags apply on this page
|
|
212
268
|
|
|
213
|
-
•
|
|
269
|
+
• Three tabs under the filters: Billing allocation (#tags and @projects), Rhythm (per-day charts), Advanced (summary KPIs, day table, lines/signals, workspace snapshot when enabled).
|
|
214
270
|
|
|
215
|
-
•
|
|
271
|
+
• Workspace folder snapshot (lines in the open project): under Advanced when code metrics are on; ignores filters — not Kronosys history.
|
|
272
|
+
|
|
273
|
+
• Summary KPIs, day-by-day table: filters apply. Session-day side: session count, session coding/active/wall time, KronoFocus sessions completed, lines written, breakdown of sessions by closure type when the host saved one at session end, and (when the host stored a planned start) punctuality aggregates: reference count, late session count, cumulative and average late minutes. Task-day side: task rows, recorded task time, done/in-progress counts, task KronoFocus used/cycles.
|
|
216
274
|
|
|
217
275
|
• “Lines by language” and “Coding signals” tables: session day within the range; with tags selected, a whole session is dropped if no task matches (same rule as elsewhere).
|
|
218
276
|
|
|
@@ -277,7 +335,11 @@ Archived sessions: task-based metrics only count fully completed tasks (subtasks
|
|
|
277
335
|
projectColTime: "Recorded time",
|
|
278
336
|
projectUnassigned: "(no project)",
|
|
279
337
|
projectTableHint:
|
|
280
|
-
"One line per calendar week, then one table: each
|
|
338
|
+
"One line per calendar week, then one table: each project on its own row, seven day columns and a week total — same week navigation and week-start setting as the tag calendar above. Use the Work (@) / Personal (!) control under the title to switch ledgers: Work is the default and excludes the personal ledger; Personal lists only that ledger (tasks flagged personal, or a recognized ! token in the title if the flag was not saved), with ! labels.",
|
|
339
|
+
projectScopeLegend: "Project ledger",
|
|
340
|
+
projectScopeGroupAria: "Recorded time by project: work or personal ledger",
|
|
341
|
+
projectScopeWork: "Work (@)",
|
|
342
|
+
projectScopePersonal: "Personal (!)",
|
|
281
343
|
tagTimeSectionTitle: "Recorded task time by tag",
|
|
282
344
|
tagTimeSectionHint:
|
|
283
345
|
"Map each #tag to an external key (e.g. SAP WBS or NWA). A task’s full recorded time is counted under every tag on that task (tag totals can overlap). In the by-day table and the weekly calendar, several `project#code` tags for the same project (same day or same week) appear under one @project row—expand to see each tag line.",
|
|
@@ -337,6 +399,13 @@ Archived sessions: task-based metrics only count fully completed tasks (subtasks
|
|
|
337
399
|
weekNavNoTagDataThisWeek: "No recorded task time for this week.",
|
|
338
400
|
weekNavNoProjectDataThisWeek: "No recorded task time by project for this week.",
|
|
339
401
|
tocLocSection: "Lines & coding signals",
|
|
402
|
+
tocViewTabs: "Views (tabs)",
|
|
403
|
+
reportingViewTabBilling: "Billing allocation",
|
|
404
|
+
reportingViewTabRhythm: "Rhythm",
|
|
405
|
+
reportingViewTabAdvanced: "Advanced",
|
|
406
|
+
reportingViewTabGroupAria: "Reporting views",
|
|
407
|
+
reportingViewBillingIntro:
|
|
408
|
+
"Map recorded time to #tags and @projects for your billing codes. Totals follow the same filters as above; open work is flagged in Filters when relevant.",
|
|
340
409
|
scrollToTopAria: "Back to top",
|
|
341
410
|
...reportingMetricHelpEn,
|
|
342
411
|
};
|
|
@@ -347,10 +416,24 @@ const fr: ReportingStrings = {
|
|
|
347
416
|
settings: "Paramètres",
|
|
348
417
|
logs: "Journal des actions",
|
|
349
418
|
guide: "Guide d’utilisation",
|
|
419
|
+
changelog: "Journal des versions",
|
|
350
420
|
implementation: "User stories — implémentation",
|
|
421
|
+
navGanttDashboardOnlyTooltip:
|
|
422
|
+
"Le Gantt du jour n’est disponible que depuis le tableau de bord.",
|
|
423
|
+
navGlobalPauseDashboardOnlyTooltip:
|
|
424
|
+
"La pause globale n’est disponible que depuis le tableau de bord lorsqu’une session live est chargée.",
|
|
425
|
+
navGlobalPauseNoSessionContextTooltip:
|
|
426
|
+
"La pause globale n’est pas disponible pendant la consultation d’une archive ou avant le chargement de la session live.",
|
|
427
|
+
navChangelogUnavailableTooltip:
|
|
428
|
+
"Raccourci changelog masqué sur cet écran (libellé vide).",
|
|
429
|
+
navImplementationUnavailableTooltip:
|
|
430
|
+
"Raccourci implémentation masqué sur cet écran (libellé vide).",
|
|
431
|
+
navGanttButtonLabel: "Ouvrir le fil de la journée (vue Gantt)",
|
|
432
|
+
navGlobalPauseButtonLabel:
|
|
433
|
+
"Mettre en pause la session, les tâches et les sous-tâches dans ce contexte",
|
|
351
434
|
title: "Rapports",
|
|
352
435
|
subtitle:
|
|
353
|
-
"
|
|
436
|
+
"Voir où le temps s’est réparti sur la période (#étiquettes, @projets) pour aider à coder les lignes de facturation. Les filtres s’appliquent à l’historique ci-dessous ; l’instantané du workspace (s’il est affiché) est sous Avancé.",
|
|
354
437
|
archivedSessionsReportingNote:
|
|
355
438
|
"Sessions archivées : les lignes de tâches, le temps enregistré sur les tâches, le temps par projet et les comptes KronoFocus par tâche ne retiennent que les tâches marquées terminées dont toutes les sous-tâches sont cochées. Les temps de codage et d’activité au niveau session restent ceux de la session entière.",
|
|
356
439
|
reportingArchivedExcludedAside:
|
|
@@ -373,9 +456,11 @@ const fr: ReportingStrings = {
|
|
|
373
456
|
filtersHelpAriaLabel: "Comment s’appliquent les filtres des rapports",
|
|
374
457
|
filtersHelpBody: `Où agissent les dates et les étiquettes sur cette page
|
|
375
458
|
|
|
376
|
-
•
|
|
459
|
+
• Trois volets sous les filtres : Allocation facturation (#étiquettes et @projets), Rythme (graphiques par jour), Avancé (indicateurs de synthèse, tableau journalier, lignes / signaux, instantané workspace si activé).
|
|
460
|
+
|
|
461
|
+
• Instantané « Dossier ouvert » : sous **Avancé** lorsque les métriques code sont activées ; hors filtres — ce n’est pas l’historique Kronosys.
|
|
377
462
|
|
|
378
|
-
• Indicateurs de synthèse,
|
|
463
|
+
• Indicateurs de synthèse, tableau par jour : la plage et les étiquettes s’appliquent. Côté jour de session : nombre de sessions, temps de codage et d’activité, durée murale, KronoFocus « sessions terminées », lignes écrites, ventilation des sessions par type de clôture lorsque l’hôte en a enregistré un à la fin de session, et (si l’hôte a enregistré un début prévu) indicateurs d’assiduité : sessions avec référence, sessions en retard, retard cumulé, retard moyen lorsqu’en retard. Côté jour de tâche : lignes de tâches, temps enregistré, tâches terminées / en cours, KronoFocus côté tâches.
|
|
379
464
|
|
|
380
465
|
• Tableaux « Lignes par langage » et « Signaux de codage » : jour de session dans la plage ; avec étiquettes sélectionnées, toute la session est exclue si aucune tâche ne correspond (même règle qu’ailleurs).
|
|
381
466
|
|
|
@@ -441,7 +526,11 @@ Sessions archivées : pour les métriques basées sur les tâches, seules les t
|
|
|
441
526
|
projectColTime: "Temps enregistré",
|
|
442
527
|
projectUnassigned: "(sans projet)",
|
|
443
528
|
projectTableHint:
|
|
444
|
-
"Une ligne par semaine calendaire, puis un tableau : chaque
|
|
529
|
+
"Une ligne par semaine calendaire, puis un tableau : chaque projet sur sa propre ligne, sept colonnes jour et le total de la semaine — même navigation par semaine et même premier jour de semaine que le calendrier par étiquette ci-dessus. Utilisez le contrôle Travail (@) / Personnel (!) sous le titre pour changer de registre : Travail (défaut) exclut le registre personnel ; Personnel n’affiche que celui-ci (tâches marquées personnelles, ou titre avec jeton ! reconnu si le drapeau n’a pas été enregistré), avec le préfixe « ! ».",
|
|
530
|
+
projectScopeLegend: "Registre projet",
|
|
531
|
+
projectScopeGroupAria: "Temps par projet : registre travail ou personnel",
|
|
532
|
+
projectScopeWork: "Travail (@)",
|
|
533
|
+
projectScopePersonal: "Personnel (!)",
|
|
445
534
|
tagTimeSectionTitle: "Temps enregistré par étiquette",
|
|
446
535
|
tagTimeSectionHint:
|
|
447
536
|
"Chaque #tag peut correspondre à une clé externe (ex. poste WBS ou NWA dans SAP). La durée enregistrée complète d’une tâche est comptée pour chaque étiquette associée (les totaux par étiquette peuvent se chevaucher). Dans le tableau par jour et le calendrier hebdomadaire, plusieurs étiquettes `projet#code` pour un même projet (même jour ou même semaine) sont regroupées sous une ligne @projet : développez-la pour voir chaque ligne d’étiquette.",
|
|
@@ -502,6 +591,13 @@ Sessions archivées : pour les métriques basées sur les tâches, seules les t
|
|
|
502
591
|
weekNavNoTagDataThisWeek: "Aucun temps de tâche enregistré pour cette semaine.",
|
|
503
592
|
weekNavNoProjectDataThisWeek: "Aucun temps de tâche par projet pour cette semaine.",
|
|
504
593
|
tocLocSection: "Lignes et signaux de codage",
|
|
594
|
+
tocViewTabs: "Vues (onglets)",
|
|
595
|
+
reportingViewTabBilling: "Allocation facturation",
|
|
596
|
+
reportingViewTabRhythm: "Rythme",
|
|
597
|
+
reportingViewTabAdvanced: "Avancé",
|
|
598
|
+
reportingViewTabGroupAria: "Vues des rapports",
|
|
599
|
+
reportingViewBillingIntro:
|
|
600
|
+
"Associez le temps enregistré aux #étiquettes et aux @projets pour vos codes de facturation. Les totaux suivent les mêmes filtres qu’en haut ; le travail encore ouvert est rappelé dans Filtres le cas échéant.",
|
|
505
601
|
scrollToTopAria: "Retour en haut de la page",
|
|
506
602
|
...reportingMetricHelpFr,
|
|
507
603
|
};
|
|
@@ -510,7 +606,7 @@ export function reportingStrings(lang: Lang): ReportingStrings {
|
|
|
510
606
|
return lang === "fr" ? fr : en;
|
|
511
607
|
}
|
|
512
608
|
|
|
513
|
-
export function reportingNav(lang: Lang):
|
|
609
|
+
export function reportingNav(lang: Lang): AppShellRouteNavLabelBundle {
|
|
514
610
|
const s = reportingStrings(lang);
|
|
515
611
|
const d = dashboardStrings(lang);
|
|
516
612
|
return {
|
|
@@ -520,6 +616,19 @@ export function reportingNav(lang: Lang): ReportingNavStrings {
|
|
|
520
616
|
logs: s.logs,
|
|
521
617
|
guide: s.guide,
|
|
522
618
|
implementation: s.implementation,
|
|
619
|
+
changelog: s.changelog,
|
|
523
620
|
dashboardAttentionHint: d.navDashboardPlannedConflictPulseHint,
|
|
621
|
+
navGanttDashboardOnlyTooltip: s.navGanttDashboardOnlyTooltip,
|
|
622
|
+
navGlobalPauseDashboardOnlyTooltip: s.navGlobalPauseDashboardOnlyTooltip,
|
|
623
|
+
navGlobalPauseNoSessionContextTooltip:
|
|
624
|
+
s.navGlobalPauseNoSessionContextTooltip,
|
|
625
|
+
navChangelogUnavailableTooltip: s.navChangelogUnavailableTooltip,
|
|
626
|
+
navImplementationUnavailableTooltip: s.navImplementationUnavailableTooltip,
|
|
627
|
+
navGanttButtonLabel: s.navGanttButtonLabel,
|
|
628
|
+
navGlobalPauseButtonLabel: s.navGlobalPauseButtonLabel,
|
|
629
|
+
navGroupAppAria: d.appShellRouteNavGroupAppAria,
|
|
630
|
+
navGroupDocsAria: d.appShellRouteNavGroupDocsAria,
|
|
631
|
+
navGroupToolsAria: d.appShellRouteNavGroupToolsAria,
|
|
632
|
+
navGroupLegalAria: d.appShellRouteNavGroupLegalAria,
|
|
524
633
|
};
|
|
525
634
|
}
|
|
@@ -8,11 +8,28 @@ import {
|
|
|
8
8
|
parseProjectScopedTag,
|
|
9
9
|
} from "@/lib/taskParsing";
|
|
10
10
|
|
|
11
|
+
/** Registre projet pour une clé d’étiquette `…#…` déjà canonique (`@` / `!`). */
|
|
12
|
+
function reportingScopedTagLedgerFromKey(tagKey: string): "p" | "w" {
|
|
13
|
+
return tagKey.trim().toLowerCase().startsWith("!") ? "p" : "w";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function scopedRollupBucketId(tagKey: string): string | null {
|
|
17
|
+
const scoped = parseProjectScopedTag(tagKey);
|
|
18
|
+
if (!scoped) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const pk = normalizeProjectKey(scoped.projectKey).toLowerCase();
|
|
22
|
+
return `${pk}:::${reportingScopedTagLedgerFromKey(tagKey)}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
11
25
|
export type TagWeekDisplayLeaf = { kind: "leaf"; row: TagWeekCalendarRow };
|
|
12
26
|
|
|
13
27
|
export type TagWeekDisplayRollup = {
|
|
14
28
|
kind: "rollup";
|
|
29
|
+
/** Projet normalisé (sans @ / !), pour descriptions et clés métier. */
|
|
15
30
|
projectKeyLower: string;
|
|
31
|
+
/** Clef stable pour l’état replié (registre @ vs ! séparés). */
|
|
32
|
+
rollupStableKey: string;
|
|
16
33
|
displayProject: string;
|
|
17
34
|
weekStart: string;
|
|
18
35
|
parentSlots: number[];
|
|
@@ -34,7 +51,7 @@ function sumSlots(rows: readonly TagWeekCalendarRow[]): number[] {
|
|
|
34
51
|
|
|
35
52
|
/**
|
|
36
53
|
* Prépare les lignes du calendrier hebdo par étiquette : étiquettes globales et sans étiquette telles quelles ;
|
|
37
|
-
* les étiquettes `projet#suffixe`
|
|
54
|
+
* les étiquettes `projet#suffixe` deviennent un bloc repliable avec total par projet **et par registre** (`@` vs `!` : pas de fusion entre travail et personnel pour le même nom de projet).
|
|
38
55
|
*/
|
|
39
56
|
export function buildTagWeekDisplayBlocks(rows: readonly TagWeekCalendarRow[]): TagWeekDisplayBlock[] {
|
|
40
57
|
const scopedBuckets = new Map<string, TagWeekCalendarRow[]>();
|
|
@@ -51,10 +68,14 @@ export function buildTagWeekDisplayBlocks(rows: readonly TagWeekCalendarRow[]):
|
|
|
51
68
|
globals.push(row);
|
|
52
69
|
continue;
|
|
53
70
|
}
|
|
54
|
-
const
|
|
55
|
-
|
|
71
|
+
const bucketId = scopedRollupBucketId(row.tagKey);
|
|
72
|
+
if (!bucketId) {
|
|
73
|
+
globals.push(row);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const list = scopedBuckets.get(bucketId) ?? [];
|
|
56
77
|
list.push(row);
|
|
57
|
-
scopedBuckets.set(
|
|
78
|
+
scopedBuckets.set(bucketId, list);
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
globals.sort((a, b) => normalizeTagKey(a.tagKey).localeCompare(normalizeTagKey(b.tagKey)));
|
|
@@ -65,20 +86,28 @@ export function buildTagWeekDisplayBlocks(rows: readonly TagWeekCalendarRow[]):
|
|
|
65
86
|
}
|
|
66
87
|
|
|
67
88
|
const projKeys = [...scopedBuckets.keys()].sort((a, b) => a.localeCompare(b));
|
|
68
|
-
for (const
|
|
69
|
-
const children = [...scopedBuckets.get(
|
|
89
|
+
for (const rollupStableKey of projKeys) {
|
|
90
|
+
const children = [...scopedBuckets.get(rollupStableKey)!].sort((a, b) =>
|
|
70
91
|
normalizeTagKey(a.tagKey).localeCompare(normalizeTagKey(b.tagKey))
|
|
71
92
|
);
|
|
93
|
+
const pk =
|
|
94
|
+
rollupStableKey.includes(":::")
|
|
95
|
+
? rollupStableKey.slice(0, rollupStableKey.indexOf(":::"))
|
|
96
|
+
: rollupStableKey;
|
|
72
97
|
if (children.length === 1) {
|
|
73
98
|
blocks.push({ kind: "leaf", row: children[0] });
|
|
74
99
|
continue;
|
|
75
100
|
}
|
|
76
101
|
const first = parseProjectScopedTag(children[0].tagKey);
|
|
77
|
-
const
|
|
102
|
+
const personalRollup = reportingScopedTagLedgerFromKey(children[0].tagKey) === "p";
|
|
103
|
+
const displayProject = first
|
|
104
|
+
? formatProjectDisplay(first.projectKey, personalRollup ? { personal: true } : undefined)
|
|
105
|
+
: pk;
|
|
78
106
|
const weekStart = children[0].weekStart;
|
|
79
107
|
blocks.push({
|
|
80
108
|
kind: "rollup",
|
|
81
109
|
projectKeyLower: pk,
|
|
110
|
+
rollupStableKey,
|
|
82
111
|
displayProject,
|
|
83
112
|
weekStart,
|
|
84
113
|
parentSlots: sumSlots(children),
|
|
@@ -99,6 +128,7 @@ export type TagDayDisplayLeaf = { kind: "leaf"; row: ReportingTagTimeDayRow };
|
|
|
99
128
|
export type TagDayDisplayRollup = {
|
|
100
129
|
kind: "rollup";
|
|
101
130
|
projectKeyLower: string;
|
|
131
|
+
rollupStableKey: string;
|
|
102
132
|
displayProject: string;
|
|
103
133
|
day: string;
|
|
104
134
|
parentMinutes: number;
|
|
@@ -122,10 +152,14 @@ function buildTagDaySegmentBlocks(segment: readonly ReportingTagTimeDayRow[]): T
|
|
|
122
152
|
globals.push(row);
|
|
123
153
|
continue;
|
|
124
154
|
}
|
|
125
|
-
const
|
|
126
|
-
|
|
155
|
+
const bucketId = scopedRollupBucketId(row.tagKey);
|
|
156
|
+
if (!bucketId) {
|
|
157
|
+
globals.push(row);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const list = scopedBuckets.get(bucketId) ?? [];
|
|
127
161
|
list.push(row);
|
|
128
|
-
scopedBuckets.set(
|
|
162
|
+
scopedBuckets.set(bucketId, list);
|
|
129
163
|
}
|
|
130
164
|
|
|
131
165
|
globals.sort((a, b) => normalizeTagKey(a.tagKey).localeCompare(normalizeTagKey(b.tagKey)));
|
|
@@ -136,21 +170,29 @@ function buildTagDaySegmentBlocks(segment: readonly ReportingTagTimeDayRow[]): T
|
|
|
136
170
|
}
|
|
137
171
|
|
|
138
172
|
const projKeys = [...scopedBuckets.keys()].sort((a, b) => a.localeCompare(b));
|
|
139
|
-
for (const
|
|
140
|
-
const children = [...scopedBuckets.get(
|
|
173
|
+
for (const rollupStableKey of projKeys) {
|
|
174
|
+
const children = [...scopedBuckets.get(rollupStableKey)!].sort((a, b) =>
|
|
141
175
|
normalizeTagKey(a.tagKey).localeCompare(normalizeTagKey(b.tagKey))
|
|
142
176
|
);
|
|
177
|
+
const pk =
|
|
178
|
+
rollupStableKey.includes(":::")
|
|
179
|
+
? rollupStableKey.slice(0, rollupStableKey.indexOf(":::"))
|
|
180
|
+
: rollupStableKey;
|
|
143
181
|
if (children.length === 1) {
|
|
144
182
|
blocks.push({ kind: "leaf", row: children[0] });
|
|
145
183
|
continue;
|
|
146
184
|
}
|
|
147
185
|
const first = parseProjectScopedTag(children[0].tagKey);
|
|
148
|
-
const
|
|
186
|
+
const personalRollup = reportingScopedTagLedgerFromKey(children[0].tagKey) === "p";
|
|
187
|
+
const displayProject = first
|
|
188
|
+
? formatProjectDisplay(first.projectKey, personalRollup ? { personal: true } : undefined)
|
|
189
|
+
: pk;
|
|
149
190
|
const day = children[0].day;
|
|
150
191
|
const parentMinutes = children.reduce((s, c) => s + c.minutes, 0);
|
|
151
192
|
blocks.push({
|
|
152
193
|
kind: "rollup",
|
|
153
194
|
projectKeyLower: pk,
|
|
195
|
+
rollupStableKey,
|
|
154
196
|
displayProject,
|
|
155
197
|
day,
|
|
156
198
|
parentMinutes,
|
package/lib/settingsCopy.ts
CHANGED
|
@@ -34,8 +34,8 @@ export type SettingsCopy = {
|
|
|
34
34
|
sectionPrivacy: string;
|
|
35
35
|
/** Tableau de bord web : affichage du KronoFocus. */
|
|
36
36
|
sectionKronoFocus: string;
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
/** KronoFocus dans la barre d’outils : toujours affiché (navigation stable). */
|
|
38
|
+
kronoFocusHeaderPinnedNote: string;
|
|
39
39
|
kronoFocusShowInTaskOps: string;
|
|
40
40
|
kronoFocusShowInTaskOpsDesc: string;
|
|
41
41
|
/** Comportement des tâches sans étiquette explicite (#). */
|
|
@@ -491,8 +491,8 @@ const en: SettingsCopy = {
|
|
|
491
491
|
sectionGeneral: "General",
|
|
492
492
|
sectionPrivacy: "Privacy",
|
|
493
493
|
sectionKronoFocus: "KronoFocus (dashboard)",
|
|
494
|
-
|
|
495
|
-
|
|
494
|
+
kronoFocusHeaderPinnedNote:
|
|
495
|
+
"The KronoFocus timer and controls always stay in the app header toolbar (next to the clock and command palette) so the navigation bar keeps the same width on every page. While you inspect an archive, the controls stay visible but target the live session.",
|
|
496
496
|
kronoFocusShowInTaskOps: "Show in task action buttons",
|
|
497
497
|
kronoFocusShowInTaskOpsDesc:
|
|
498
498
|
"KronoFocus start on active tasks and the optional “start KronoFocus with new task” toggle in the task launcher.",
|
|
@@ -975,9 +975,8 @@ const fr: SettingsCopy = {
|
|
|
975
975
|
sectionGeneral: "Général",
|
|
976
976
|
sectionPrivacy: "Confidentialité",
|
|
977
977
|
sectionKronoFocus: "KronoFocus (tableau de bord)",
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
"Minuteur KronoFocus et contrôles dans la barre du haut du tableau de bord dans le navigateur.",
|
|
978
|
+
kronoFocusHeaderPinnedNote:
|
|
979
|
+
"Le minuteur KronoFocus et ses contrôles restent toujours dans la barre d’outils de l’application (à côté de l’horloge et de la palette de commandes), afin que la barre de navigation garde la même largeur sur toutes les pages. En consultation d’archive, les contrôles restent visibles mais ciblent la session live.",
|
|
981
980
|
kronoFocusShowInTaskOps: "Afficher dans les boutons opérationnels des tâches",
|
|
982
981
|
kronoFocusShowInTaskOpsDesc:
|
|
983
982
|
"Bouton pour lancer le KronoFocus depuis une tâche suivie et option « lancer aussi le KronoFocus » lors de la création d’une tâche.",
|
package/lib/userGuideCopy.ts
CHANGED
|
@@ -50,7 +50,7 @@ function frBundle(): UserGuideBundle {
|
|
|
50
50
|
searchNoResults: "Aucune rubrique ne correspond à votre recherche. Essayez un autre mot-clé ou effacez le filtre.",
|
|
51
51
|
tocHeading: "Sur cette page",
|
|
52
52
|
tocNavAria: "Sommaire du guide d’utilisation",
|
|
53
|
-
lastUpdated: "Dernière mise à jour :
|
|
53
|
+
lastUpdated: "Dernière mise à jour : 13 mai 2026",
|
|
54
54
|
sections: [
|
|
55
55
|
{
|
|
56
56
|
id: "ug-essence",
|
|
@@ -64,7 +64,7 @@ function frBundle(): UserGuideBundle {
|
|
|
64
64
|
optionsTitle: "Trois « pièces » pour trois gestes",
|
|
65
65
|
options: [
|
|
66
66
|
"**Tableau de bord** — l’*atelier* (sessions, tâches, minuteur, raccourcis **#étiquettes** / **@projets** travail / **!projets** personnels).",
|
|
67
|
-
"**Rapports** —
|
|
67
|
+
"**Rapports** — la période en **trois vues** (allocation facturation, rythme, avancé) à partir de l’historique déjà enregistré.",
|
|
68
68
|
"**Paramètres** — l’*arrière-boutique* (habitudes, raccordements, zone où l’on *efface* l’histoire *avec prudence*). [Ouvrir Paramètres](/settings#settings-usage-profile).",
|
|
69
69
|
],
|
|
70
70
|
stepsTitle: "Premier contact en cinq pas (sans tout maîtriser le jour 1)",
|
|
@@ -79,9 +79,10 @@ function frBundle(): UserGuideBundle {
|
|
|
79
79
|
{
|
|
80
80
|
id: "ug-nav-theme",
|
|
81
81
|
title: "Barre d’outils, thème et langue",
|
|
82
|
-
searchIndex: "thème clair sombre mode violet zinc langue fr en",
|
|
82
|
+
searchIndex: "thème clair sombre mode violet zinc langue fr en ruban groupe navigation repli plusieurs rangées",
|
|
83
83
|
paragraphs: [
|
|
84
|
-
"La **barre du haut** est *toujours* la même famille : mêmes outils, même **ton** (zinc, accents **violet**), pour ne pas recharger le cerveau *à chaque page*. L’icône **roue** mène à [Paramètres](/settings#settings-usage-profile) (raccourci **Alt+Shift+S** depuis le tableau de bord).",
|
|
84
|
+
"La **barre du haut** est *toujours* la même famille : mêmes outils, même **ton** (zinc, accents **violet**), pour ne pas recharger le cerveau *à chaque page*. Les **raccourcis** de pages sont **regroupés** en **petits blocs** par **contexte** (zones principales, aide et documentation, outils de session ou informations légales), sur le modèle d’un **ruban** léger. L’icône **roue** mène à [Paramètres](/settings#settings-usage-profile) (raccourci **Alt+Shift+S** depuis le tableau de bord).",
|
|
85
|
+
"Sur **écran étroit** (petit portable, fenêtre réduite, **PWA** côté tablette), la rangée se **replie** en **plusieurs lignes centrées** au lieu d’afficher une **barre de défilement horizontale** — les **blocs** (horloge, KronoFocus, navigation, utilitaires) restent **groupés** et accessibles **sans glisser** latéralement.",
|
|
85
86
|
],
|
|
86
87
|
steps: [
|
|
87
88
|
"En **tableau de bord** : l’icône **Livre** mène ici, puis **Rapports** (graphe), **Paramètres** (roue) et **Implémentation** (code — inventaire des user stories).",
|
|
@@ -106,10 +107,10 @@ function frBundle(): UserGuideBundle {
|
|
|
106
107
|
],
|
|
107
108
|
options: [
|
|
108
109
|
"**Tableau de bord** — à gauche la **file des sessions** ; au centre les **tâches** (minuteurs, détail) ; à droite les raccourcis d’**étiquettes** et de **projets** (**@** travail, **!** personnel) pour ne pas retaper les mêmes mots. C’est l’usage **quotidien**.",
|
|
109
|
-
"**Rapports** — choisir une **plage de dates** et, si besoin, des **#étiquettes** ;
|
|
110
|
+
"**Rapports** — choisir une **plage de dates** et, si besoin, des **#étiquettes** ; puis les **onglets** (allocation facturation, rythme, avancé). Une **visite guidée** est proposée la première fois sur l’écran.",
|
|
110
111
|
"**Paramètres** — profil, collecte, planification, étiquettes avancées, **Git** ou miroir en **option** ; la **zone dangereuse** supprime l’historique (avec saisie de confirmation). [Sommaire des paramètres](/settings#settings-usage-profile) · [zone de danger](/settings#settings-danger-zone). N’y entrez **que** quand vous le **décidez**.",
|
|
111
112
|
"**Licences** — textes MIT, logiciels tiers, polices ; icône **document** **uniquement** sur cette page.",
|
|
112
|
-
"Une **horloge murale** (fuseau et format 12/24 h des paramètres **Tableau de bord web**) tourne en permanence dans la **barre d’outils** de l’en-tête
|
|
113
|
+
"Une **horloge murale** (fuseau et format 12/24 h des paramètres **Tableau de bord web**) tourne en permanence dans la **barre d’outils** de l’en-tête ; le **KronoFocus** se place **juste à côté**, avant les icônes de navigation — il reste **toujours** visible pour garder la barre stable. En consultation d’**archive**, ses **boutons** restent **visibles** mais **désactivés** : ils reflètent toujours la **session live**. La **palette données** (Ctrl+K / ⌘K), le **Gantt du jour** et la **pause globale** sont **les mêmes** sur **toutes** les pages (tableau de bord, rapports, paramètres, journaux, guide, implémentation, changelog, licences) ; hors tableau de bord, certaines actions **vous y ramènent** pour terminer (ex. ouvrir un résultat de recherche)."
|
|
113
114
|
],
|
|
114
115
|
},
|
|
115
116
|
{
|
|
@@ -178,7 +179,7 @@ function frBundle(): UserGuideBundle {
|
|
|
178
179
|
],
|
|
179
180
|
optionsTitle: "Où c’est proposé, quoi cliquer",
|
|
180
181
|
options: [
|
|
181
|
-
"Section [KronoFocus (tableau de bord)](/settings#settings-kronoFocus) dans **Paramètres** : minuteur **dans
|
|
182
|
+
"Section [KronoFocus (tableau de bord)](/settings#settings-kronoFocus) dans **Paramètres** : le minuteur reste **dans la barre d’outils** ; vous choisissez encore s’il apparaît **près des actions de tâche** (le **profil** d’usage peut **masquer** d’autres blocs ailleurs).",
|
|
182
183
|
"Sur le **panneau** : **Démarrer**, **Pause**, reprise ; **durée** en `HH:MM:SS` ; **durée par défaut** (p. ex. 25 min) d’un clic ; **historique** des durées pour **réappliquer** la même mesure **sans** la retaper.",
|
|
183
184
|
"Lier le KronoFocus **à** la tâche **active** : utile pour **retrouver** dans l’historique **quelle** tâche portait ce **bloc** de focus."
|
|
184
185
|
],
|
|
@@ -224,23 +225,24 @@ function frBundle(): UserGuideBundle {
|
|
|
224
225
|
{
|
|
225
226
|
id: "ug-reporting",
|
|
226
227
|
title: "Rapports : la mémoire qui tient, quand on doit la raconter",
|
|
227
|
-
searchIndex: "agregats kpi plage date étiquette semaine assiduité retard heure planifiée",
|
|
228
|
+
searchIndex: "agregats kpi plage date étiquette semaine assiduité retard heure planifiée onglets allocation facturation rythme avancé",
|
|
228
229
|
paragraphs: [
|
|
229
230
|
"Les **rapports** ne jaugent pas votre humanité : ils aident à **répondre** à *est-ce qu’on peut, ensemble, s’y retrouver sur une période ?* Ce qui n’est **pas** **encore** fini reste **indiqué** (brouillon **honnête**, pas punition).",
|
|
230
|
-
"
|
|
231
|
-
"Lorsque l’**hôte** d’enregistrement a **fourni** l’heure de **début prévue** à l’ouverture d’une session (p. ex. moteur lié à l’[horaire](/settings#settings-schedule) ou aux [sessions planifiées](/settings#settings-planned-sessions)), l’**écart** (retard ou avance) est **sauvegardé** sur la session et des **indicateurs d’assiduité** apparaissent dans le **résumé**
|
|
231
|
+
"Sous les filtres, **trois vues** orientent la lecture : **Allocation facturation** (#étiquettes, @projets) pour le temps à mapper vers vos lignes de facturation ; **Rythme** (graphiques par jour) ; **Avancé** (synthèse, tableau journalier, lignes de code / signaux et instantané workspace **si** le profil l’expose). L’appli **agrège** ce que vous avez **déjà** enregistré ; une **visite** sur l’écran adoucit le **premier** tour.",
|
|
232
|
+
"Lorsque l’**hôte** d’enregistrement a **fourni** l’heure de **début prévue** à l’ouverture d’une session (p. ex. moteur lié à l’[horaire](/settings#settings-schedule) ou aux [sessions planifiées](/settings#settings-planned-sessions)), l’**écart** (retard ou avance) est **sauvegardé** sur la session et des **indicateurs d’assiduité** apparaissent dans le **résumé** (vue **Avancé**) : ce n’est en général **pas** rempli par le seul bouton *Nouvelle session* du navigateur, sauf intégration explicite."
|
|
232
233
|
],
|
|
233
234
|
stepsTitle: "Parcours type sur l’écran Rapports",
|
|
234
235
|
steps: [
|
|
235
236
|
"Ouvrir **Rapports** (icône **graphe** ou raccourci **Alt+Shift+G** sur le tableau de bord).",
|
|
236
237
|
"Choisir une **plage** : champs **Du** / **Au**, bouton **Aujourd’hui**, ou préréglages **jour** / **semaine** / **mois** / **année** (selon ce que l’UI expose).",
|
|
237
238
|
"Optionnel : **sélectionner** une ou plusieurs **#étiquettes** pour **restreindre** les tâches (les **sessions** **sans** tâche **correspondante** **disparaissent** des **vues** **basées** **tâches**).",
|
|
238
|
-
"
|
|
239
|
+
"Choisir une **vue** sous les filtres : **Allocation facturation** pour le temps par #étiquette et @projet (grilles hebdo, navigation de semaine, début de semaine) ; **Rythme** pour les graphiques par jour ; **Avancé** pour les indicateurs de synthèse, le tableau journalier, les lignes de code (si activées) et l’instantané workspace.",
|
|
240
|
+
"**Lancer** la **visite** **guidée** **si** la **pancarte** **le** **propose**.",
|
|
239
241
|
],
|
|
240
242
|
options: [
|
|
241
243
|
"**Indicateurs non finaux** (pastilles) : rappellent le **travail encore ouvert** dans la plage — lire prudemment, pas de chiffrage *figé* tant que des tâches *bougent* encore.",
|
|
242
|
-
"Sous le **résum
|
|
243
|
-
"Le **tableau par jour** inclut aussi un total de temps tâche **non concurrent** (sans chevauchement des intervalles horodatés) pour comparer avec le temps enregistré brut.",
|
|
244
|
+
"Sous le **résumé** (vue **Avancé**), une **ventilation** peut compter les **sessions** par **type de clôture** enregistré à la fin de session (lorsque l’hôte en a choisi un) ; les sessions **sans** catégorie y figurent à part.",
|
|
245
|
+
"Le **tableau par jour** (vue **Avancé**) inclut aussi un total de temps tâche **non concurrent** (sans chevauchement des intervalles horodatés) pour comparer avec le temps enregistré brut.",
|
|
244
246
|
"**Début de semaine** (lundi, dimanche ou samedi) : réglage souvent près des **calendriers** hebdo des rapports — choisissez **ce** qui coïncide avec **votre** semaine réelle.",
|
|
245
247
|
"Relancer la visite **Rapports** (aide **premier pas** sur l’écran) : [Paramètres — visite Rapports](/settings#settings-reporting-tour).",
|
|
246
248
|
"Une **deuxième grille** dédiée au seul temps personnel (`!`), **miroir** de celle des projets `@`, **n’est pas** encore dans l’interface ; les agrégats côté moteur prévoient déjà les filtres pour une version ultérieure.",
|
|
@@ -286,7 +288,7 @@ function enBundle(): UserGuideBundle {
|
|
|
286
288
|
searchNoResults: "No section matches. Try another keyword or clear the filter.",
|
|
287
289
|
tocHeading: "On this page",
|
|
288
290
|
tocNavAria: "User guide table of contents",
|
|
289
|
-
lastUpdated: "Last updated:
|
|
291
|
+
lastUpdated: "Last updated: 13 May 2026",
|
|
290
292
|
sections: [
|
|
291
293
|
{
|
|
292
294
|
id: "ug-essence",
|
|
@@ -300,7 +302,7 @@ function enBundle(): UserGuideBundle {
|
|
|
300
302
|
optionsTitle: "Three “rooms” for three moves",
|
|
301
303
|
options: [
|
|
302
304
|
"**Dashboard** — the workbench (sessions, tasks, focus timer, **#** tags, **@** work projects, and **!** personal projects).",
|
|
303
|
-
"**Reports** — the
|
|
305
|
+
"**Reports** — the span in **three tabs** (billing allocation, rhythm, advanced) from what you **already** logged.",
|
|
304
306
|
"**Settings** — the back room (habits, connections, the **danger** zone where you wipe history **carefully**). [Open Settings](/settings#settings-usage-profile).",
|
|
305
307
|
],
|
|
306
308
|
stepsTitle: "A calm first run (day one need not be perfect)",
|
|
@@ -315,9 +317,10 @@ function enBundle(): UserGuideBundle {
|
|
|
315
317
|
{
|
|
316
318
|
id: "ug-nav-theme",
|
|
317
319
|
title: "Toolbar, theme, and language",
|
|
318
|
-
searchIndex: "theme light dark language fr en
|
|
320
|
+
searchIndex: "theme light dark language fr en ribbon group navigation wrap multiple rows narrow screen",
|
|
319
321
|
paragraphs: [
|
|
320
|
-
"The top bar reuses the **same** **family** of controls (zinc, **violet** accents) on every page so **navigation** stays **light** on the brain. The **cog** icon opens [Settings](/settings#settings-usage-profile) (shortcut **Alt+Shift+S** from the dashboard).",
|
|
322
|
+
"The top bar reuses the **same** **family** of controls (zinc, **violet** accents) on every page so **navigation** stays **light** on the brain. **Page shortcuts** sit in **small grouped blocks** by **context** (main areas, help and docs, in-session tools or legal info when shown), like a **lightweight ribbon**. The **cog** icon opens [Settings](/settings#settings-usage-profile) (shortcut **Alt+Shift+S** from the dashboard).",
|
|
323
|
+
"On a **narrow screen** (small laptop, shrunk window, tablet **PWA**), the row **wraps** into **multiple centered lines** instead of showing a **horizontal scrollbar** — the **blocks** (clock, KronoFocus, navigation, utilities) stay **grouped** and reachable **without side-scrolling**.",
|
|
321
324
|
],
|
|
322
325
|
steps: [
|
|
323
326
|
"On the **dashboard**: **Book** → this guide; **chart** → **Reports**; **cog** → **Settings**; **code** → user stories (implementation status).",
|
|
@@ -342,10 +345,10 @@ function enBundle(): UserGuideBundle {
|
|
|
342
345
|
],
|
|
343
346
|
options: [
|
|
344
347
|
"**Dashboard** — **sessions** on the left, **tasks** in the **centre**, **tag** and **project** shortcuts (**@** work, **!** personal) on the right so you stop retyping the same words.",
|
|
345
|
-
"**Reports** — pick a **date range** and, if needed, **#** tags;
|
|
348
|
+
"**Reports** — pick a **date range** and, if needed, **#** tags; then use the **tabs** (billing allocation, rhythm, advanced); the **tour** may offer itself the first time you land there.",
|
|
346
349
|
"**Settings** — profile, collection, scheduling, **advanced** tags, optional **Git** or **remote**; the **danger zone** can **delete** all **history** (type-to-confirm). [Settings overview](/settings#settings-usage-profile) · [danger zone](/settings#settings-danger-zone).",
|
|
347
350
|
"**Licenses** — MIT, third parties, **fonts**; the **file** icon **only** on that page.",
|
|
348
|
-
"A **wall clock** (time zone and 12/24 h from **Web dashboard** settings) stays visible in the header **toolbar**,
|
|
351
|
+
"A **wall clock** (time zone and 12/24 h from **Web dashboard** settings) stays visible in the header **toolbar**; **KronoFocus** sits **right beside it**, before the navigation icons — it is **always** shown so the bar stays stable. While you **inspect an archive**, its **buttons** stay **visible but disabled** — they still reflect the **live session**. The **data palette** (Ctrl+K / ⌘K), **Today Gantt**, and **global pause** are the **same** on **every** main page (dashboard, reporting, settings, logs, guide, implementation, changelog, licenses); off the **dashboard**, some actions **return** there to **finish** (e.g. open a search hit)."
|
|
349
352
|
],
|
|
350
353
|
},
|
|
351
354
|
{
|
|
@@ -413,7 +416,7 @@ function enBundle(): UserGuideBundle {
|
|
|
413
416
|
],
|
|
414
417
|
optionsTitle: "Where to find it, what the controls do",
|
|
415
418
|
options: [
|
|
416
|
-
"In **Settings**: the [KronoFocus (dashboard)](/settings#settings-kronoFocus) section —
|
|
419
|
+
"In **Settings**: the [KronoFocus (dashboard)](/settings#settings-kronoFocus) section — the timer **stays in the header**; you can still choose whether it also appears **on** **task** actions (your **usage** profile can hide other panels elsewhere in the app).",
|
|
417
420
|
"On the **card**: **Start**, **Pause**, resume; **duration** as `HH:MM:SS`; a **one-tap** default (e.g. 25 min); **history** of durations to **reapply** without retyping.",
|
|
418
421
|
"Link the timer to the **active** **task** so you can later see **which** **task** carried that focus block in the **archive**.",
|
|
419
422
|
],
|
|
@@ -459,11 +462,11 @@ function enBundle(): UserGuideBundle {
|
|
|
459
462
|
{
|
|
460
463
|
id: "ug-reporting",
|
|
461
464
|
title: "Reports: memory you can read back, not a verdict on you",
|
|
462
|
-
searchIndex: "filter date tag week kpi punctuality late schedule planned",
|
|
465
|
+
searchIndex: "filter date tag week kpi punctuality late schedule planned tabs billing rhythm advanced",
|
|
463
466
|
paragraphs: [
|
|
464
467
|
"Reports are for a **calm** read of a time span, not a moral tally. They help answer: can we, together, make sense of this **period**? Unfinished work stays **indicated** where the UI does — honest draft, not **punishment**.",
|
|
465
|
-
"
|
|
466
|
-
"If the **recording** **host** **passed** a **planned** start instant when a session was opened (for example a worker tied to your [work schedule](/settings#settings-schedule) or [planned sessions](/settings#settings-planned-sessions)), the app stores the **offset** in minutes and shows **punctuality** **summary** KPIs
|
|
468
|
+
"Under the filters, **three tabs** steer the page: **Billing allocation** (#tags, @projects) for time you map to billing lines; **Rhythm** (per-day charts); **Advanced** (summary KPIs, day table, code lines / signals, and a **workspace** snapshot when your profile exposes it). The app **aggregates** what you **already** logged; a **guided** **tour** may soften the **first** visit.",
|
|
469
|
+
"If the **recording** **host** **passed** a **planned** start instant when a session was opened (for example a worker tied to your [work schedule](/settings#settings-schedule) or [planned sessions](/settings#settings-planned-sessions)), the app stores the **offset** in minutes and shows **punctuality** **summary** KPIs under **Advanced** — a browser-only **New session** usually does **not** set this by itself, unless a connector does.",
|
|
467
470
|
],
|
|
468
471
|
stepsTitle: "A typical run on the Reports page",
|
|
469
472
|
steps: [
|
|
@@ -471,13 +474,13 @@ function enBundle(): UserGuideBundle {
|
|
|
471
474
|
"Set **from** and **to** (or a day / week / month / year **preset**, depending on what the UI offers).",
|
|
472
475
|
"Use **Today** / **Now** quick actions in date/time pickers whenever available to jump to the current value.",
|
|
473
476
|
"Optionally pick one or more **#** **tags** (sessions with **no** **matching** task may **disappear** from some **task**-based **views**).",
|
|
474
|
-
"
|
|
477
|
+
"Pick a **tab** under the filters: **Billing allocation** for time by #tag and @project (weekly grids, week nudger, week start); **Rhythm** for per-day charts; **Advanced** for summary KPIs, the day table, lines-of-code (when on), and the workspace snapshot.",
|
|
475
478
|
"Start the **guided** **tour** if a prompt appears the **first** time.",
|
|
476
479
|
],
|
|
477
480
|
options: [
|
|
478
481
|
"**Non-final** chips mark work that is not **closed** in the **range** you are looking at: read them gently; the **draft** is not a **failure**.",
|
|
479
|
-
"
|
|
480
|
-
"The **day table**
|
|
482
|
+
"Under **Advanced**, below the **summary** KPIs, a **breakdown** may count **sessions** by **closure type** saved when a session ended (when the host picked one); sessions **without** a stored category are grouped separately.",
|
|
483
|
+
"The **day table** (under **Advanced**) includes a **non-concurrent** task-time total (timestamped overlap removed) so you can compare it against raw recorded task time.",
|
|
481
484
|
"**Week** starts on (Monday, Sunday, or Saturday) — often next to the tag-week **grids**; pick the one that **matches** how you read a week.",
|
|
482
485
|
"Re-launch the **Reports** first-time **tour** from [Settings — Reporting tour](/settings#settings-reporting-tour).",
|
|
483
486
|
"A **second** grid that shows **only** personal (`!`) project time, **parallel** to the `@` project grid, is **not** in the UI yet; the aggregation layer already has filters for a future release.",
|