@nightkatana/kronosys-app 1.0.0-beta.2 → 1.0.0-beta.21

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.
Files changed (112) hide show
  1. package/README.md +28 -1
  2. package/app/api/action/route.ts +39 -3
  3. package/app/api/action-logs/route.ts +24 -0
  4. package/app/api/backup/route.ts +1 -1
  5. package/app/api/restore/route.ts +145 -0
  6. package/app/changelog/page.tsx +71 -4
  7. package/app/globals.css +127 -0
  8. package/app/guide/page.tsx +61 -15
  9. package/app/implementation/page.tsx +700 -0
  10. package/app/layout.tsx +14 -3
  11. package/app/licenses/page.tsx +99 -37
  12. package/app/logs/page.tsx +258 -0
  13. package/app/manifest.ts +5 -5
  14. package/app/page.tsx +784 -229
  15. package/app/reporting/page.tsx +1266 -474
  16. package/app/settings/page.tsx +252 -18
  17. package/bin/kronosys.mjs +140 -15
  18. package/components/KronosysPayloadProvider.tsx +2 -0
  19. package/components/RouteTransition.tsx +18 -0
  20. package/components/dashboard/AppShellCommandCenterPlaceholder.tsx +17 -0
  21. package/components/dashboard/AppShellHeaderSessionMeta.tsx +210 -0
  22. package/components/dashboard/AppShellHeaderWallClock.tsx +54 -0
  23. package/components/dashboard/AppShellLiveSessionDrawer.tsx +154 -38
  24. package/components/dashboard/AppShellRouteNav.tsx +323 -48
  25. package/components/dashboard/DashboardPauseBackdrop.tsx +50 -0
  26. package/components/dashboard/DashboardSimpleModal.tsx +168 -25
  27. package/components/dashboard/DashboardTour.tsx +115 -29
  28. package/components/dashboard/GlobalPauseConfirmModal.tsx +183 -0
  29. package/components/dashboard/KronosysDatetimePopoverField.tsx +167 -122
  30. package/components/dashboard/KronosysTimePopoverField.tsx +54 -12
  31. package/components/dashboard/NewSessionScopeModal.tsx +211 -20
  32. package/components/dashboard/PlannedTaskBoundaryConflictWatcher.tsx +275 -0
  33. package/components/dashboard/ReportingTour.tsx +87 -21
  34. package/components/dashboard/SavedProjectPicker.tsx +16 -3
  35. package/components/dashboard/SelectedSessionSidebarBlock.tsx +512 -142
  36. package/components/dashboard/SessionListPanel.tsx +327 -44
  37. package/components/dashboard/SettingsTagsProjectsSection.tsx +1073 -264
  38. package/components/dashboard/SettingsTaskTemplatesSection.tsx +316 -0
  39. package/components/dashboard/SettingsTour.tsx +86 -21
  40. package/components/dashboard/TagPills.tsx +14 -1
  41. package/components/dashboard/TaskFocusPanel.tsx +1081 -478
  42. package/components/dashboard/TaskSessionLiveCard.tsx +650 -135
  43. package/components/dashboard/TaskTimelineGanttModal.tsx +601 -0
  44. package/components/dashboard/taskFieldStyles.ts +20 -4
  45. package/components/dashboard/useReportingInteractionState.ts +80 -0
  46. package/lib/appShellHeaderClasses.ts +13 -0
  47. package/lib/businessRulesMatrix.ts +210 -0
  48. package/lib/copyToClipboard.ts +43 -0
  49. package/lib/dashboardCopy.ts +494 -84
  50. package/lib/dashboardQuickSearch.ts +54 -2
  51. package/lib/dashboardTimeZone.ts +109 -0
  52. package/lib/formatAppShellWallClock.ts +66 -0
  53. package/lib/formatSessionNameTemplate.ts +141 -0
  54. package/lib/generatedUserChangelog.ts +177 -6
  55. package/lib/globalPausePreview.ts +292 -0
  56. package/lib/implementationNotes.ts +1188 -0
  57. package/lib/kronosysApi.ts +6 -0
  58. package/lib/kronosysDashboardModalGates.ts +24 -0
  59. package/lib/plannedBoundaryAttention.ts +9 -0
  60. package/lib/plannedBoundaryConflict.ts +23 -0
  61. package/lib/reportingAggregate.ts +517 -75
  62. package/lib/reportingMetricHelp.ts +8 -0
  63. package/lib/reportingStrings.ts +37 -3
  64. package/lib/sessionListMerge.ts +4 -0
  65. package/lib/sessionTaskSidebarStats.ts +182 -21
  66. package/lib/settingsCopy.ts +178 -4
  67. package/lib/taskParsing.ts +360 -103
  68. package/lib/taskTemplateDraft.ts +135 -0
  69. package/lib/taskTimelineGantt.ts +265 -0
  70. package/lib/temporalDisplayPlanned.ts +71 -0
  71. package/lib/userGuideCopy.ts +121 -47
  72. package/next.config.ts +7 -0
  73. package/package.json +12 -24
  74. package/server/actionDispatch.ts +1000 -77
  75. package/server/actionTaskSession.ts +337 -24
  76. package/server/db.ts +7 -15
  77. package/server/dbSchema.ts +24 -0
  78. package/server/defaultCfg.ts +5 -0
  79. package/server/gitlabTokenStore.ts +0 -12
  80. package/server/liveHistorySync.ts +53 -0
  81. package/server/mainTimerHydrate.ts +38 -2
  82. package/server/payloadStore.ts +33 -11
  83. package/server/sessionWallHydrate.ts +66 -3
  84. package/server/userActionLog.ts +126 -0
  85. package/sonar-project.properties +11 -0
  86. package/tsconfig.json +2 -1
  87. package/components/dashboard/IssuePickerModal.tsx +0 -168
  88. package/components/dashboard/ThemeToggle.test.tsx +0 -26
  89. package/lib/backupCsvExport.test.ts +0 -149
  90. package/lib/dashboardQuickSearchQuery.test.ts +0 -63
  91. package/lib/dataDir.test.ts +0 -87
  92. package/lib/formatIsoShort.test.ts +0 -46
  93. package/lib/kronoFocusRhythm.test.ts +0 -130
  94. package/lib/kronoFocusTimerUrgency.test.ts +0 -74
  95. package/lib/legacyKronoFocusStorageKeys.test.ts +0 -29
  96. package/lib/reportingAggregate.test.ts +0 -325
  97. package/lib/reportingNonFinalIndicators.test.ts +0 -157
  98. package/lib/reportingTagWeekBreakdown.test.ts +0 -141
  99. package/lib/reportingWeekLayout.test.ts +0 -239
  100. package/lib/sessionAssiduity.test.ts +0 -25
  101. package/lib/sessionEndWarnings.test.ts +0 -200
  102. package/lib/sessionListMerge.test.ts +0 -101
  103. package/lib/sessionTaskSidebarStats.test.ts +0 -24
  104. package/lib/taskParsing.test.ts +0 -153
  105. package/lib/usageProfile.test.ts +0 -84
  106. package/server/actionDispatch.test.ts +0 -723
  107. package/server/actionTaskSession.test.ts +0 -713
  108. package/server/kronoFocusHydrate.test.ts +0 -142
  109. package/server/kronoFocusMigrate.test.ts +0 -53
  110. package/server/mainTimerHydrate.test.ts +0 -65
  111. package/server/payloadStore.test.ts +0 -78
  112. package/server/sessionWallHydrate.test.ts +0 -46
@@ -1,153 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import {
4
- buildStartTaskFromDraft,
5
- buildStartTaskFromInput,
6
- DEFAULT_FALLBACK_TASK_TAG,
7
- displayRawTaskTitle,
8
- filterTaskTagsForProject,
9
- formatDuration,
10
- formatTagDisplay,
11
- formatTagDisplayForTask,
12
- formatWallDurationMs,
13
- formatStopwatchMs,
14
- mergeQuickAddFromOptionValues,
15
- normalizeProjectKey,
16
- normalizeTagKey,
17
- normalizeTaskTagsForStorage,
18
- parseProjectScopedTag,
19
- parseQuickAddTagOrProjectLine,
20
- parseTaskWithAutoTags,
21
- readTaskDefaultTagBucketEnabled,
22
- rebuildTaskRawString,
23
- removeSavedTagFromDraft,
24
- resolveProjectForTaskUpdate,
25
- resolveProjectFromFullTaskLine,
26
- splitTaskTitleSegments,
27
- stripProjectsAndTakeFirst,
28
- stripScopedProjectAtTokens,
29
- } from "./taskParsing";
30
-
31
- describe("taskParsing core", () => {
32
- it("normalizeProjectKey retire les @", () => {
33
- expect(normalizeProjectKey("@@acme")).toBe("acme");
34
- expect(normalizeProjectKey("@")).toBe("");
35
- });
36
-
37
- it("normalizeTagKey retire les #", () => {
38
- expect(normalizeTagKey("#bug")).toBe("bug");
39
- });
40
-
41
- it("parseProjectScopedTag identifie proj#tag", () => {
42
- expect(parseProjectScopedTag("acme#dev")).toEqual({ projectKey: "acme", localTag: "dev" });
43
- expect(parseProjectScopedTag("global")).toBeNull();
44
- expect(parseProjectScopedTag("#tag")).toBeNull();
45
- expect(parseProjectScopedTag("acme#")).toBeNull();
46
- });
47
- });
48
-
49
- describe("title parsing & projects", () => {
50
- it("stripScopedProjectAtTokens extrait @p#t", () => {
51
- const r = stripScopedProjectAtTokens("Hello @p#t world");
52
- expect(r.core).toBe("Hello world");
53
- expect(r.scopedTags).toEqual(["p#t"]);
54
- expect(r.scopedProjectHint).toBe("p");
55
- });
56
-
57
- it("stripProjectsAndTakeFirst gère @p seul et @p#t", () => {
58
- const r = stripProjectsAndTakeFirst("Task @acme and @ignored#tag");
59
- expect(r.project).toBe("acme");
60
- expect(r.scopedTags).toEqual(["ignored#tag"]);
61
- expect(r.core).toBe("Task and");
62
- });
63
-
64
- it("resolveProjectForTaskUpdate", () => {
65
- expect(resolveProjectForTaskUpdate("No project here")).toBeUndefined();
66
- expect(resolveProjectForTaskUpdate("Project @demo")).toBe("demo");
67
- expect(resolveProjectForTaskUpdate("Project @")).toBeNull();
68
- });
69
-
70
- it("resolveProjectFromFullTaskLine", () => {
71
- expect(resolveProjectFromFullTaskLine("Hello @world")).toBe("world");
72
- expect(resolveProjectFromFullTaskLine("Hello")).toBeNull();
73
- });
74
- });
75
-
76
- describe("tag handling", () => {
77
- it("normalizeTaskTagsForStorage déduplique et gère default", () => {
78
- expect(normalizeTaskTagsForStorage(["A", "a", ""])).toEqual(["A"]);
79
- expect(normalizeTaskTagsForStorage([])).toEqual([DEFAULT_FALLBACK_TASK_TAG]);
80
- expect(normalizeTaskTagsForStorage([], { assignDefaultTagBucket: false })).toEqual([]);
81
- });
82
-
83
- it("filterTaskTagsForProject nettoie les tags incompatibles", () => {
84
- const tags = ["global", "acme#dev", "beta#design"];
85
- expect(filterTaskTagsForProject(tags, "acme")).toEqual(["global", "acme#dev"]);
86
- expect(filterTaskTagsForProject(tags, null)).toEqual(["global"]);
87
- });
88
-
89
- it("splitTaskTitleSegments découpe texte et tags", () => {
90
- const segs = splitTaskTitleSegments("Fix #bug now #urgent");
91
- expect(segs).toHaveLength(4);
92
- expect(segs[1]).toEqual({ kind: "tag", value: "#bug" });
93
- });
94
-
95
- it("parseTaskWithAutoTags moteur complet", () => {
96
- const r = parseTaskWithAutoTags("Fix #bug @acme");
97
- expect(r.name).toBe("Fix");
98
- expect(r.tags).toEqual(["bug"]);
99
- expect(r.project).toBe("acme");
100
- });
101
- });
102
-
103
- describe("rebuild & display", () => {
104
- it("rebuildTaskRawString", () => {
105
- expect(rebuildTaskRawString("Name", ["tag"], "proj")).toBe("Name#tag@proj");
106
- expect(rebuildTaskRawString("Name", ["p#t"], "p")).toBe("Name@p#t");
107
- });
108
-
109
- it("displayRawTaskTitle", () => {
110
- expect(displayRawTaskTitle("Name #t", ["t"], "p")).toBe("Name #t@p");
111
- expect(displayRawTaskTitle("Name", ["t"], "p")).toBe("Name #t@p");
112
- });
113
-
114
- it("formatTagDisplay", () => {
115
- expect(formatTagDisplay("dev")).toBe("#dev");
116
- expect(formatTagDisplay("acme#dev")).toBe("@acme#dev");
117
- });
118
- });
119
-
120
- describe("quick add & draft builders", () => {
121
- it("parseQuickAddTagOrProjectLine", () => {
122
- expect(parseQuickAddTagOrProjectLine("just text")).toEqual({ tags: ["justtext"], project: undefined });
123
- expect(parseQuickAddTagOrProjectLine("#tag")).toEqual({ tags: ["tag"], project: undefined });
124
- expect(parseQuickAddTagOrProjectLine("@proj")).toEqual({ tags: [], project: "proj" });
125
- });
126
-
127
- it("buildStartTaskFromInput", () => {
128
- expect(buildStartTaskFromInput("#tag @proj")).toEqual({ name: "tag", tags: ["tag"], project: "proj" });
129
- expect(buildStartTaskFromInput("Task #tag")).toEqual({ name: "Task", tags: ["tag"], project: undefined });
130
- });
131
-
132
- it("buildStartTaskFromDraft", () => {
133
- const r = buildStartTaskFromDraft("Title", ["tag"], "proj");
134
- expect(r.name).toBe("Title");
135
- expect(r.tags).toEqual(["tag"]);
136
- expect(r.project).toBe("proj");
137
- });
138
- });
139
-
140
- describe("durations", () => {
141
- it("formatDuration", () => {
142
- expect(formatDuration(1.5)).toBe("1 min 30 s");
143
- expect(formatDuration(120)).toBe("2h");
144
- });
145
-
146
- it("formatWallDurationMs", () => {
147
- expect(formatWallDurationMs(61000)).toBe("1 min 1 s");
148
- });
149
-
150
- it("formatStopwatchMs", () => {
151
- expect(formatStopwatchMs(61000)).toBe("1:01.00");
152
- });
153
- });
@@ -1,84 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import type { KronosysUpdatePayload } from "./kronosysApi";
4
- import {
5
- extensionLinkedDeveloperMetrics,
6
- showIdeLinkedCodeTimingMetrics,
7
- showWorkspaceFoldersEmptyMessage,
8
- trackCodeMetricsFromCfg,
9
- workspaceCodeMetricsEnabled,
10
- } from "./usageProfile";
11
-
12
- describe("trackCodeMetricsFromCfg", () => {
13
- it("gestionnaire : pas de métriques code", () => {
14
- expect(trackCodeMetricsFromCfg({ usageProfile: "manager" })).toBe(false);
15
- });
16
-
17
- it("défaut (vide) : pas de métriques code", () => {
18
- expect(trackCodeMetricsFromCfg({})).toBe(false);
19
- expect(trackCodeMetricsFromCfg(undefined)).toBe(false);
20
- });
21
-
22
- it("développeur : métriques code", () => {
23
- expect(trackCodeMetricsFromCfg({ usageProfile: "developer" })).toBe(true);
24
- });
25
- });
26
-
27
- describe("showWorkspaceFoldersEmptyMessage", () => {
28
- const devPayload = (origin: KronosysUpdatePayload["dashboardDataOrigin"]): KronosysUpdatePayload =>
29
- ({
30
- viewType: "dashboard",
31
- cfg: { usageProfile: "developer" },
32
- dashboardDataOrigin: origin,
33
- }) as KronosysUpdatePayload;
34
-
35
- it("affiche en développeur + local_next + aucun chemin", () => {
36
- expect(showWorkspaceFoldersEmptyMessage(devPayload("local_next"), 0)).toBe(true);
37
- });
38
-
39
- it("masque en profil gestionnaire même avec origine héritée", () => {
40
- const p = {
41
- viewType: "dashboard",
42
- cfg: { usageProfile: "manager" },
43
- dashboardDataOrigin: "legacy_external" as const,
44
- } as KronosysUpdatePayload;
45
- expect(showWorkspaceFoldersEmptyMessage(p, 0)).toBe(false);
46
- });
47
-
48
- it("affiche en développeur + legacy_external + aucun chemin", () => {
49
- expect(showWorkspaceFoldersEmptyMessage(devPayload("legacy_external"), 0)).toBe(true);
50
- });
51
-
52
- it("masque dès qu’au moins un chemin est résolu", () => {
53
- expect(showWorkspaceFoldersEmptyMessage(devPayload("legacy_external"), 1)).toBe(false);
54
- });
55
- });
56
-
57
- describe("workspaceCodeMetricsEnabled / showIdeLinkedCodeTimingMetrics", () => {
58
- const dev = {
59
- viewType: "dashboard",
60
- cfg: { usageProfile: "developer" },
61
- dashboardDataOrigin: "local_next" as const,
62
- } as KronosysUpdatePayload;
63
-
64
- it("workspaceCodeMetricsEnabled est vrai en profil développeur", () => {
65
- expect(workspaceCodeMetricsEnabled(dev, dev.cfg as Record<string, unknown>)).toBe(true);
66
- });
67
-
68
- it("extensionLinkedDeveloperMetrics reste aligné (alias)", () => {
69
- expect(extensionLinkedDeveloperMetrics(dev, dev.cfg as Record<string, unknown>)).toBe(true);
70
- });
71
-
72
- it("showIdeLinkedCodeTimingMetrics suit la même règle", () => {
73
- expect(showIdeLinkedCodeTimingMetrics(dev, dev.cfg as Record<string, unknown>)).toBe(true);
74
- });
75
-
76
- it("faux en profil gestionnaire", () => {
77
- const p = {
78
- viewType: "dashboard",
79
- cfg: { usageProfile: "manager" },
80
- dashboardDataOrigin: "local_next" as const,
81
- } as KronosysUpdatePayload;
82
- expect(showIdeLinkedCodeTimingMetrics(p, p.cfg as Record<string, unknown>)).toBe(false);
83
- });
84
- });