reviewflow 3.19.2 → 3.21.0

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 (185) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/config/projectConfig.d.ts +7 -0
  3. package/dist/config/projectConfig.d.ts.map +1 -1
  4. package/dist/config/projectConfig.js +18 -0
  5. package/dist/config/projectConfig.js.map +1 -1
  6. package/dist/dashboard/index.html +452 -142
  7. package/dist/dashboard/modules/cardCounters.d.ts +32 -0
  8. package/dist/dashboard/modules/cardCounters.d.ts.map +1 -0
  9. package/dist/dashboard/modules/cardCounters.js +40 -0
  10. package/dist/dashboard/modules/cardCounters.js.map +1 -0
  11. package/dist/dashboard/modules/constants.d.ts +1 -0
  12. package/dist/dashboard/modules/constants.d.ts.map +1 -1
  13. package/dist/dashboard/modules/constants.js +1 -0
  14. package/dist/dashboard/modules/constants.js.map +1 -1
  15. package/dist/dashboard/modules/managePanel.d.ts +49 -0
  16. package/dist/dashboard/modules/managePanel.d.ts.map +1 -0
  17. package/dist/dashboard/modules/managePanel.js +123 -0
  18. package/dist/dashboard/modules/managePanel.js.map +1 -0
  19. package/dist/dashboard/modules/overview.d.ts +65 -0
  20. package/dist/dashboard/modules/overview.d.ts.map +1 -0
  21. package/dist/dashboard/modules/overview.js +260 -0
  22. package/dist/dashboard/modules/overview.js.map +1 -0
  23. package/dist/dashboard/modules/settingsModal.d.ts +77 -0
  24. package/dist/dashboard/modules/settingsModal.d.ts.map +1 -0
  25. package/dist/dashboard/modules/settingsModal.js +182 -0
  26. package/dist/dashboard/modules/settingsModal.js.map +1 -0
  27. package/dist/dashboard/modules/tabBar.d.ts +60 -0
  28. package/dist/dashboard/modules/tabBar.d.ts.map +1 -0
  29. package/dist/dashboard/modules/tabBar.js +103 -0
  30. package/dist/dashboard/modules/tabBar.js.map +1 -0
  31. package/dist/dashboard/styles.css +936 -0
  32. package/dist/frameworks/config/configLoader.d.ts +8 -0
  33. package/dist/frameworks/config/configLoader.d.ts.map +1 -1
  34. package/dist/frameworks/config/configLoader.js +18 -0
  35. package/dist/frameworks/config/configLoader.js.map +1 -1
  36. package/dist/main/routes.d.ts.map +1 -1
  37. package/dist/main/routes.js +67 -11
  38. package/dist/main/routes.js.map +1 -1
  39. package/dist/modules/cli-configuration/entities/projectConfig/projectConfig.gateway.d.ts +20 -0
  40. package/dist/modules/cli-configuration/entities/projectConfig/projectConfig.gateway.d.ts.map +1 -0
  41. package/dist/modules/cli-configuration/entities/projectConfig/projectConfig.gateway.js +2 -0
  42. package/dist/modules/cli-configuration/entities/projectConfig/projectConfig.gateway.js.map +1 -0
  43. package/dist/modules/cli-configuration/entities/repositoryEntry/repositoryEntry.d.ts +13 -0
  44. package/dist/modules/cli-configuration/entities/repositoryEntry/repositoryEntry.d.ts.map +1 -0
  45. package/dist/modules/cli-configuration/entities/repositoryEntry/repositoryEntry.js +2 -0
  46. package/dist/modules/cli-configuration/entities/repositoryEntry/repositoryEntry.js.map +1 -0
  47. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.d.ts +6 -1
  48. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.d.ts.map +1 -1
  49. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.js +116 -13
  50. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.js.map +1 -1
  51. package/dist/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.d.ts +43 -0
  52. package/dist/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.d.ts.map +1 -0
  53. package/dist/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.js +82 -0
  54. package/dist/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.js.map +1 -0
  55. package/dist/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.d.ts +7 -0
  56. package/dist/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.d.ts.map +1 -0
  57. package/dist/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.js +48 -0
  58. package/dist/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.js.map +1 -0
  59. package/dist/modules/cli-configuration/usecases/cli/addRepositoriesToConfig.usecase.d.ts +1 -6
  60. package/dist/modules/cli-configuration/usecases/cli/addRepositoriesToConfig.usecase.d.ts.map +1 -1
  61. package/dist/modules/cli-configuration/usecases/cli/addRepositoriesToConfig.usecase.js.map +1 -1
  62. package/dist/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.d.ts +21 -0
  63. package/dist/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.d.ts.map +1 -0
  64. package/dist/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.js +27 -0
  65. package/dist/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.js.map +1 -0
  66. package/dist/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.d.ts +22 -0
  67. package/dist/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.d.ts.map +1 -0
  68. package/dist/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.js +27 -0
  69. package/dist/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.js.map +1 -0
  70. package/dist/modules/cli-configuration/usecases/cli/writeInitConfig.usecase.d.ts +1 -6
  71. package/dist/modules/cli-configuration/usecases/cli/writeInitConfig.usecase.d.ts.map +1 -1
  72. package/dist/modules/cli-configuration/usecases/cli/writeInitConfig.usecase.js.map +1 -1
  73. package/dist/modules/cli-configuration/usecases/dashboardRepositories/addRepositoryFromDashboard.usecase.d.ts +19 -0
  74. package/dist/modules/cli-configuration/usecases/dashboardRepositories/addRepositoryFromDashboard.usecase.d.ts.map +1 -0
  75. package/dist/modules/cli-configuration/usecases/dashboardRepositories/addRepositoryFromDashboard.usecase.js +30 -0
  76. package/dist/modules/cli-configuration/usecases/dashboardRepositories/addRepositoryFromDashboard.usecase.js.map +1 -0
  77. package/dist/modules/cli-configuration/usecases/dashboardRepositories/removeRepositoryFromDashboard.usecase.d.ts +16 -0
  78. package/dist/modules/cli-configuration/usecases/dashboardRepositories/removeRepositoryFromDashboard.usecase.d.ts.map +1 -0
  79. package/dist/modules/cli-configuration/usecases/dashboardRepositories/removeRepositoryFromDashboard.usecase.js +27 -0
  80. package/dist/modules/cli-configuration/usecases/dashboardRepositories/removeRepositoryFromDashboard.usecase.js.map +1 -0
  81. package/dist/modules/cli-configuration/usecases/dashboardRepositories/updateRepositoryEnabledFromDashboard.usecase.d.ts +17 -0
  82. package/dist/modules/cli-configuration/usecases/dashboardRepositories/updateRepositoryEnabledFromDashboard.usecase.d.ts.map +1 -0
  83. package/dist/modules/cli-configuration/usecases/dashboardRepositories/updateRepositoryEnabledFromDashboard.usecase.js +28 -0
  84. package/dist/modules/cli-configuration/usecases/dashboardRepositories/updateRepositoryEnabledFromDashboard.usecase.js.map +1 -0
  85. package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.d.ts +31 -0
  86. package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.d.ts.map +1 -0
  87. package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.js +102 -0
  88. package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.js.map +1 -0
  89. package/dist/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.d.ts +16 -0
  90. package/dist/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.d.ts.map +1 -0
  91. package/dist/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.js +53 -0
  92. package/dist/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.js.map +1 -0
  93. package/dist/modules/statistics-insights/interface-adapters/presenters/overview.presenter.d.ts +93 -0
  94. package/dist/modules/statistics-insights/interface-adapters/presenters/overview.presenter.d.ts.map +1 -0
  95. package/dist/modules/statistics-insights/interface-adapters/presenters/overview.presenter.js +145 -0
  96. package/dist/modules/statistics-insights/interface-adapters/presenters/overview.presenter.js.map +1 -0
  97. package/dist/tests/acceptance/177-dashboard-add-project-ui.acceptance.test.d.ts +12 -0
  98. package/dist/tests/acceptance/177-dashboard-add-project-ui.acceptance.test.d.ts.map +1 -0
  99. package/dist/tests/acceptance/177-dashboard-add-project-ui.acceptance.test.js +304 -0
  100. package/dist/tests/acceptance/177-dashboard-add-project-ui.acceptance.test.js.map +1 -0
  101. package/dist/tests/acceptance/178-dashboard-tabs-reposition.acceptance.test.d.ts +12 -0
  102. package/dist/tests/acceptance/178-dashboard-tabs-reposition.acceptance.test.d.ts.map +1 -0
  103. package/dist/tests/acceptance/178-dashboard-tabs-reposition.acceptance.test.js +131 -0
  104. package/dist/tests/acceptance/178-dashboard-tabs-reposition.acceptance.test.js.map +1 -0
  105. package/dist/tests/acceptance/179-dashboard-project-settings-modal.acceptance.test.d.ts +12 -0
  106. package/dist/tests/acceptance/179-dashboard-project-settings-modal.acceptance.test.d.ts.map +1 -0
  107. package/dist/tests/acceptance/179-dashboard-project-settings-modal.acceptance.test.js +312 -0
  108. package/dist/tests/acceptance/179-dashboard-project-settings-modal.acceptance.test.js.map +1 -0
  109. package/dist/tests/acceptance/91-dashboard-multi-project-overview.acceptance.test.d.ts +10 -0
  110. package/dist/tests/acceptance/91-dashboard-multi-project-overview.acceptance.test.d.ts.map +1 -0
  111. package/dist/tests/acceptance/91-dashboard-multi-project-overview.acceptance.test.js +275 -0
  112. package/dist/tests/acceptance/91-dashboard-multi-project-overview.acceptance.test.js.map +1 -0
  113. package/dist/tests/factories/projectStatsApiResponse.factory.d.ts +16 -0
  114. package/dist/tests/factories/projectStatsApiResponse.factory.d.ts.map +1 -0
  115. package/dist/tests/factories/projectStatsApiResponse.factory.js +39 -0
  116. package/dist/tests/factories/projectStatsApiResponse.factory.js.map +1 -0
  117. package/dist/tests/factories/recentReviewFile.factory.d.ts +5 -0
  118. package/dist/tests/factories/recentReviewFile.factory.d.ts.map +1 -0
  119. package/dist/tests/factories/recentReviewFile.factory.js +16 -0
  120. package/dist/tests/factories/recentReviewFile.factory.js.map +1 -0
  121. package/dist/tests/factories/repositoryConfig.factory.d.ts +5 -0
  122. package/dist/tests/factories/repositoryConfig.factory.d.ts.map +1 -0
  123. package/dist/tests/factories/repositoryConfig.factory.js +14 -0
  124. package/dist/tests/factories/repositoryConfig.factory.js.map +1 -0
  125. package/dist/tests/stubs/projectConfigGateway.stub.d.ts +15 -0
  126. package/dist/tests/stubs/projectConfigGateway.stub.d.ts.map +1 -0
  127. package/dist/tests/stubs/projectConfigGateway.stub.js +40 -0
  128. package/dist/tests/stubs/projectConfigGateway.stub.js.map +1 -0
  129. package/dist/tests/units/config/projectConfig.test.js +43 -0
  130. package/dist/tests/units/config/projectConfig.test.js.map +1 -1
  131. package/dist/tests/units/dashboard/modules/cardCounters.test.d.ts +2 -0
  132. package/dist/tests/units/dashboard/modules/cardCounters.test.d.ts.map +1 -0
  133. package/dist/tests/units/dashboard/modules/cardCounters.test.js +106 -0
  134. package/dist/tests/units/dashboard/modules/cardCounters.test.js.map +1 -0
  135. package/dist/tests/units/dashboard/modules/constants.test.js +2 -1
  136. package/dist/tests/units/dashboard/modules/constants.test.js.map +1 -1
  137. package/dist/tests/units/dashboard/modules/managePanel.test.d.ts +2 -0
  138. package/dist/tests/units/dashboard/modules/managePanel.test.d.ts.map +1 -0
  139. package/dist/tests/units/dashboard/modules/managePanel.test.js +112 -0
  140. package/dist/tests/units/dashboard/modules/managePanel.test.js.map +1 -0
  141. package/dist/tests/units/dashboard/modules/overview.test.d.ts +2 -0
  142. package/dist/tests/units/dashboard/modules/overview.test.d.ts.map +1 -0
  143. package/dist/tests/units/dashboard/modules/overview.test.js +268 -0
  144. package/dist/tests/units/dashboard/modules/overview.test.js.map +1 -0
  145. package/dist/tests/units/dashboard/modules/settingsModal.test.d.ts +2 -0
  146. package/dist/tests/units/dashboard/modules/settingsModal.test.d.ts.map +1 -0
  147. package/dist/tests/units/dashboard/modules/settingsModal.test.js +166 -0
  148. package/dist/tests/units/dashboard/modules/settingsModal.test.js.map +1 -0
  149. package/dist/tests/units/dashboard/modules/tabBar.test.d.ts +2 -0
  150. package/dist/tests/units/dashboard/modules/tabBar.test.d.ts.map +1 -0
  151. package/dist/tests/units/dashboard/modules/tabBar.test.js +128 -0
  152. package/dist/tests/units/dashboard/modules/tabBar.test.js.map +1 -0
  153. package/dist/tests/units/frameworks/config/configLoader.test.js +35 -1
  154. package/dist/tests/units/frameworks/config/configLoader.test.js.map +1 -1
  155. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.js +111 -0
  156. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.js.map +1 -1
  157. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.test.d.ts +2 -0
  158. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.test.d.ts.map +1 -0
  159. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.test.js +298 -0
  160. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.test.js.map +1 -0
  161. package/dist/tests/units/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.test.d.ts +2 -0
  162. package/dist/tests/units/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.test.d.ts.map +1 -0
  163. package/dist/tests/units/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.test.js +72 -0
  164. package/dist/tests/units/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.test.js.map +1 -0
  165. package/dist/tests/units/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.test.d.ts +2 -0
  166. package/dist/tests/units/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.test.d.ts.map +1 -0
  167. package/dist/tests/units/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.test.js +76 -0
  168. package/dist/tests/units/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.test.js.map +1 -0
  169. package/dist/tests/units/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.test.d.ts +2 -0
  170. package/dist/tests/units/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.test.d.ts.map +1 -0
  171. package/dist/tests/units/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.test.js +84 -0
  172. package/dist/tests/units/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.test.js.map +1 -0
  173. package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.d.ts +2 -0
  174. package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.d.ts.map +1 -0
  175. package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.js +141 -0
  176. package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.js.map +1 -0
  177. package/dist/tests/units/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.test.d.ts +2 -0
  178. package/dist/tests/units/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.test.d.ts.map +1 -0
  179. package/dist/tests/units/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.test.js +200 -0
  180. package/dist/tests/units/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.test.js.map +1 -0
  181. package/dist/tests/units/modules/statistics-insights/interface-adapters/presenters/overview.presenter.test.d.ts +2 -0
  182. package/dist/tests/units/modules/statistics-insights/interface-adapters/presenters/overview.presenter.test.d.ts.map +1 -0
  183. package/dist/tests/units/modules/statistics-insights/interface-adapters/presenters/overview.presenter.test.js +331 -0
  184. package/dist/tests/units/modules/statistics-insights/interface-adapters/presenters/overview.presenter.test.js.map +1 -0
  185. package/package.json +1 -1
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @typedef {{ kind: 'overview' } | { kind: 'project', localPath: string, projectName: string }} CardScope
3
+ */
4
+ /**
5
+ * @param {object} input
6
+ * @param {Array<{ project: string, status: string }>} input.activeReviews
7
+ * @param {Array<unknown>} input.reviewFiles
8
+ * @param {CardScope} input.scope
9
+ * @returns {{ running: number, queued: number, completed: number, markerLabel: string, markerKind: 'overview'|'project' }}
10
+ */
11
+ export function computeCardCounters(input: {
12
+ activeReviews: Array<{
13
+ project: string;
14
+ status: string;
15
+ }>;
16
+ reviewFiles: Array<unknown>;
17
+ scope: CardScope;
18
+ }): {
19
+ running: number;
20
+ queued: number;
21
+ completed: number;
22
+ markerLabel: string;
23
+ markerKind: "overview" | "project";
24
+ };
25
+ export type CardScope = {
26
+ kind: "overview";
27
+ } | {
28
+ kind: "project";
29
+ localPath: string;
30
+ projectName: string;
31
+ };
32
+ //# sourceMappingURL=cardCounters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cardCounters.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/cardCounters.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,2CALG;IAA0D,aAAa,EAA/D,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACpB,WAAW,EAAjC,KAAK,CAAC,OAAO,CAAC;IACG,KAAK,EAAtB,SAAS;CACjB,GAAU;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,UAAU,GAAC,SAAS,CAAA;CAAE,CA8BzH;wBAtCY;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @typedef {{ kind: 'overview' } | { kind: 'project', localPath: string, projectName: string }} CardScope
3
+ */
4
+
5
+ /**
6
+ * @param {object} input
7
+ * @param {Array<{ project: string, status: string }>} input.activeReviews
8
+ * @param {Array<unknown>} input.reviewFiles
9
+ * @param {CardScope} input.scope
10
+ * @returns {{ running: number, queued: number, completed: number, markerLabel: string, markerKind: 'overview'|'project' }}
11
+ */
12
+ export function computeCardCounters(input) {
13
+ const { activeReviews, reviewFiles, scope } = input;
14
+
15
+ const scoped = scope.kind === 'project'
16
+ ? activeReviews.filter((review) => review.project === scope.localPath)
17
+ : activeReviews;
18
+
19
+ const running = scoped.filter((review) => review.status === 'running').length;
20
+ const queued = scoped.filter((review) => review.status === 'queued').length;
21
+ const completed = reviewFiles.length;
22
+
23
+ if (scope.kind === 'overview') {
24
+ return {
25
+ running,
26
+ queued,
27
+ completed,
28
+ markerLabel: 'TOUS LES PROJETS',
29
+ markerKind: 'overview',
30
+ };
31
+ }
32
+
33
+ return {
34
+ running,
35
+ queued,
36
+ completed,
37
+ markerLabel: scope.projectName.toUpperCase(),
38
+ markerKind: 'project',
39
+ };
40
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cardCounters.js","sourceRoot":"","sources":["../../../src/dashboard/modules/cardCounters.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAK;IACvC,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IAEpD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS;QACrC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;QACtE,CAAC,CAAC,aAAa,CAAC;IAElB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAC9E,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IAC5E,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC;IAErC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC9B,OAAO;YACL,OAAO;YACP,MAAM;YACN,SAAS;YACT,WAAW,EAAE,kBAAkB;YAC/B,UAAU,EAAE,UAAU;SACvB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO;QACP,MAAM;QACN,SAAS;QACT,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE;QAC5C,UAAU,EAAE,SAAS;KACtB,CAAC;AACJ,CAAC"}
@@ -3,5 +3,6 @@ export const RECONNECT_DELAY: 3000;
3
3
  export const STORAGE_KEY_PROJECTS: "review-flow-projects";
4
4
  export const STORAGE_KEY_CURRENT: "review-flow-current-project";
5
5
  export const STORAGE_KEY_FOCUS_STRIP_MODE: "review-flow-focus-strip-mode";
6
+ export const STORAGE_KEY_ACTIVE_TAB: "review-flow-active-tab";
6
7
  export const QUALITY_TARGET_SCORE: 8;
7
8
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/constants.js"],"names":[],"mappings":"AAAA,qCAAsC,EAAE,CAAC;AACzC,8BAA+B,IAAI,CAAC;AACpC,mCAAoC,sBAAsB,CAAC;AAC3D,kCAAmC,6BAA6B,CAAC;AACjE,2CAA4C,8BAA8B,CAAC;AAC3E,mCAAoC,CAAC,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/constants.js"],"names":[],"mappings":"AAAA,qCAAsC,EAAE,CAAC;AACzC,8BAA+B,IAAI,CAAC;AACpC,mCAAoC,sBAAsB,CAAC;AAC3D,kCAAmC,6BAA6B,CAAC;AACjE,2CAA4C,8BAA8B,CAAC;AAC3E,qCAAsC,wBAAwB,CAAC;AAC/D,mCAAoC,CAAC,CAAC"}
@@ -3,4 +3,5 @@ export const RECONNECT_DELAY = 3000;
3
3
  export const STORAGE_KEY_PROJECTS = 'review-flow-projects';
4
4
  export const STORAGE_KEY_CURRENT = 'review-flow-current-project';
5
5
  export const STORAGE_KEY_FOCUS_STRIP_MODE = 'review-flow-focus-strip-mode';
6
+ export const STORAGE_KEY_ACTIVE_TAB = 'review-flow-active-tab';
6
7
  export const QUALITY_TARGET_SCORE = 8;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/dashboard/modules/constants.js"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AACzC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AACpC,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAC3D,MAAM,CAAC,MAAM,mBAAmB,GAAG,6BAA6B,CAAC;AACjE,MAAM,CAAC,MAAM,4BAA4B,GAAG,8BAA8B,CAAC;AAC3E,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/dashboard/modules/constants.js"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AACzC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AACpC,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAC3D,MAAM,CAAC,MAAM,mBAAmB,GAAG,6BAA6B,CAAC;AACjE,MAAM,CAAC,MAAM,4BAA4B,GAAG,8BAA8B,CAAC;AAC3E,MAAM,CAAC,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @param {ManagePanelBuildInput} input
3
+ * @returns {ManagePanelViewModel}
4
+ */
5
+ export function buildManagePanelModel(input: ManagePanelBuildInput): ManagePanelViewModel;
6
+ /**
7
+ * @param {ManagePanelViewModel} viewModel
8
+ * @returns {string}
9
+ */
10
+ export function renderManagePanelHtml(viewModel: ManagePanelViewModel): string;
11
+ /**
12
+ * @param {ManagePanelRepositoryInput} repository
13
+ * @returns {ManagePanelRowViewModel}
14
+ */
15
+ export function buildOptimisticAddedRow(repository: ManagePanelRepositoryInput): ManagePanelRowViewModel;
16
+ /**
17
+ * @typedef {{ ok: true } | { ok: false, reason: 'empty' | 'relative' }} ValidateLocalPathInputResult
18
+ */
19
+ /**
20
+ * @param {string} rawInput
21
+ * @returns {ValidateLocalPathInputResult}
22
+ */
23
+ export function validateLocalPathInput(rawInput: string): ValidateLocalPathInputResult;
24
+ export type ManagePanelRepositoryInput = {
25
+ name: string;
26
+ localPath: string;
27
+ enabled: boolean;
28
+ };
29
+ export type ManagePanelBuildInput = {
30
+ repositories: ManagePanelRepositoryInput[];
31
+ isOpen: boolean;
32
+ };
33
+ export type ManagePanelRowViewModel = {
34
+ name: string;
35
+ localPath: string;
36
+ shortPath: string;
37
+ enabled: boolean;
38
+ };
39
+ export type ManagePanelViewModel = {
40
+ rows: ManagePanelRowViewModel[];
41
+ isOpen: boolean;
42
+ };
43
+ export type ValidateLocalPathInputResult = {
44
+ ok: true;
45
+ } | {
46
+ ok: false;
47
+ reason: "empty" | "relative";
48
+ };
49
+ //# sourceMappingURL=managePanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"managePanel.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/managePanel.js"],"names":[],"mappings":"AAiDA;;;GAGG;AACH,6CAHW,qBAAqB,GACnB,oBAAoB,CAWhC;AAiBD;;;GAGG;AACH,iDAHW,oBAAoB,GAClB,MAAM,CAalB;AAED;;;GAGG;AACH,oDAHW,0BAA0B,GACxB,uBAAuB,CASnC;AAED;;GAEG;AAEH;;;GAGG;AACH,iDAHW,MAAM,GACJ,4BAA4B,CAOxC;;UA5Ga,MAAM;eACN,MAAM;aACN,OAAO;;;kBAKP,0BAA0B,EAAE;YAC5B,OAAO;;;UAKP,MAAM;eACN,MAAM;eACN,MAAM;aACN,OAAO;;;UAKP,uBAAuB,EAAE;YACzB,OAAO;;2CA0ER;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,UAAU,CAAA;CAAE"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Dashboard module — manage panel humble object (SPEC-177).
3
+ *
4
+ * Pure functions, no global state, no DOM access. Builds a viewmodel and
5
+ * renders HTML for the sidebar manage panel (add form + per-repository rows
6
+ * with delete and enable/disable controls).
7
+ *
8
+ * Visual DNA: "Agentic OS" — see project_agentic_os_design_dna.md.
9
+ */
10
+
11
+ import { escapeHtml } from './html.js';
12
+
13
+ /**
14
+ * @typedef {Object} ManagePanelRepositoryInput
15
+ * @property {string} name
16
+ * @property {string} localPath
17
+ * @property {boolean} enabled
18
+ */
19
+
20
+ /**
21
+ * @typedef {Object} ManagePanelBuildInput
22
+ * @property {ManagePanelRepositoryInput[]} repositories
23
+ * @property {boolean} isOpen
24
+ */
25
+
26
+ /**
27
+ * @typedef {Object} ManagePanelRowViewModel
28
+ * @property {string} name
29
+ * @property {string} localPath
30
+ * @property {string} shortPath
31
+ * @property {boolean} enabled
32
+ */
33
+
34
+ /**
35
+ * @typedef {Object} ManagePanelViewModel
36
+ * @property {ManagePanelRowViewModel[]} rows
37
+ * @property {boolean} isOpen
38
+ */
39
+
40
+ /**
41
+ * @param {string} localPath
42
+ * @returns {string}
43
+ */
44
+ function computeShortPath(localPath) {
45
+ const segments = localPath.split('/').filter(Boolean);
46
+ if (segments.length <= 2) return segments.join('/');
47
+ return segments.slice(-2).join('/');
48
+ }
49
+
50
+ /**
51
+ * @param {ManagePanelBuildInput} input
52
+ * @returns {ManagePanelViewModel}
53
+ */
54
+ export function buildManagePanelModel(input) {
55
+ const repositories = Array.isArray(input.repositories) ? input.repositories : [];
56
+ const rows = repositories.map((repository) => ({
57
+ name: repository.name,
58
+ localPath: repository.localPath,
59
+ shortPath: computeShortPath(repository.localPath),
60
+ enabled: repository.enabled !== false,
61
+ }));
62
+ return { rows, isOpen: input.isOpen === true };
63
+ }
64
+
65
+ /**
66
+ * @param {ManagePanelRowViewModel} row
67
+ * @returns {string}
68
+ */
69
+ function renderRow(row) {
70
+ const toggleState = row.enabled ? 'is-on' : 'is-off';
71
+ const enabledAttribute = row.enabled ? 'true' : 'false';
72
+ return `<div class="manage-row" data-local-path="${escapeHtml(row.localPath)}" data-enabled="${enabledAttribute}">
73
+ <span class="manage-row-name">${escapeHtml(row.name)}</span>
74
+ <span class="manage-row-path" title="${escapeHtml(row.localPath)}">${escapeHtml(row.shortPath)}</span>
75
+ <button type="button" class="manage-row-toggle ${toggleState}" data-action="toggle" aria-label="Toggle ${escapeHtml(row.name)}"><span class="row-toggle-icon"></span></button>
76
+ <button type="button" class="manage-row-delete" data-action="delete" aria-label="Remove ${escapeHtml(row.name)}">×</button>
77
+ </div>`;
78
+ }
79
+
80
+ /**
81
+ * @param {ManagePanelViewModel} viewModel
82
+ * @returns {string}
83
+ */
84
+ export function renderManagePanelHtml(viewModel) {
85
+ const rowsHtml = viewModel.rows.map(renderRow).join('');
86
+ const openAttribute = viewModel.isOpen ? 'true' : 'false';
87
+ return `<div class="manage-panel-inner" data-open="${openAttribute}">
88
+ <div class="manage-rows">${rowsHtml}</div>
89
+ <form class="add-form" data-action="add-repository">
90
+ <input type="text" class="add-form-input" name="localPath" placeholder="/absolute/path/to/project" autocomplete="off" spellcheck="false" />
91
+ <button type="submit" class="add-form-submit">Add</button>
92
+ </form>
93
+ <p class="add-form-error" data-role="error-message" hidden></p>
94
+ </div>`;
95
+ }
96
+
97
+ /**
98
+ * @param {ManagePanelRepositoryInput} repository
99
+ * @returns {ManagePanelRowViewModel}
100
+ */
101
+ export function buildOptimisticAddedRow(repository) {
102
+ return {
103
+ name: repository.name,
104
+ localPath: repository.localPath,
105
+ shortPath: computeShortPath(repository.localPath),
106
+ enabled: repository.enabled !== false,
107
+ };
108
+ }
109
+
110
+ /**
111
+ * @typedef {{ ok: true } | { ok: false, reason: 'empty' | 'relative' }} ValidateLocalPathInputResult
112
+ */
113
+
114
+ /**
115
+ * @param {string} rawInput
116
+ * @returns {ValidateLocalPathInputResult}
117
+ */
118
+ export function validateLocalPathInput(rawInput) {
119
+ const trimmed = typeof rawInput === 'string' ? rawInput.trim() : '';
120
+ if (trimmed.length === 0) return { ok: false, reason: 'empty' };
121
+ if (!trimmed.startsWith('/')) return { ok: false, reason: 'relative' };
122
+ return { ok: true };
123
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"managePanel.js","sourceRoot":"","sources":["../../../src/dashboard/modules/managePanel.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Renders a vector-only sparkline. Returns '' when there is nothing to draw.
3
+ *
4
+ * @param {number[]} points
5
+ * @returns {string}
6
+ */
7
+ export function renderSparklineSvg(points: number[]): string;
8
+ /**
9
+ * Renders the overview HTML from a server-provided view-model.
10
+ * Tolerates missing sections by falling back to empty French defaults — the server
11
+ * is a boundary, so this guards against malformed payloads (deploys, partial fetches).
12
+ *
13
+ * @param {unknown} viewModel
14
+ * @returns {string}
15
+ */
16
+ export function renderOverviewHtml(viewModel: unknown): string;
17
+ export type OverviewActiveReviewItem = {
18
+ jobId: string;
19
+ projectName: string;
20
+ projectPath: string;
21
+ mrPrefix: "MR" | "PR";
22
+ mrNumber: number;
23
+ mrUrl: string;
24
+ elapsedLabel: string;
25
+ jobType: "review" | "followup";
26
+ };
27
+ export type OverviewActiveReviewsSection = {
28
+ items: OverviewActiveReviewItem[];
29
+ isEmpty: boolean;
30
+ emptyMessage: string;
31
+ };
32
+ export type OverviewProjectCardItem = {
33
+ projectName: string;
34
+ projectPath: string;
35
+ platform: "gitlab" | "github";
36
+ totalReviews: number;
37
+ averageScoreLabel: string;
38
+ sparklinePoints: number[];
39
+ isEmptyHistory: boolean;
40
+ externalLink?: string | undefined;
41
+ };
42
+ export type OverviewProjectCardsSection = {
43
+ items: OverviewProjectCardItem[];
44
+ isEmpty: boolean;
45
+ emptyMessage: string;
46
+ };
47
+ export type OverviewRecentReviewItem = {
48
+ filename: string;
49
+ projectName: string;
50
+ mrPrefix: "MR" | "PR";
51
+ mrNumber: string;
52
+ title: string;
53
+ mtime: string;
54
+ };
55
+ export type OverviewRecentReviewsFeedSection = {
56
+ items: OverviewRecentReviewItem[];
57
+ isEmpty: boolean;
58
+ emptyMessage: string;
59
+ };
60
+ export type OverviewViewModel = {
61
+ activeReviews: OverviewActiveReviewsSection;
62
+ projectCards: OverviewProjectCardsSection;
63
+ recentReviewsFeed: OverviewRecentReviewsFeedSection;
64
+ };
65
+ //# sourceMappingURL=overview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overview.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/overview.js"],"names":[],"mappings":"AAgGA;;;;;GAKG;AACH,2CAHW,MAAM,EAAE,GACN,MAAM,CAkBlB;AAiHD;;;;;;;GAOG;AACH,8CAHW,OAAO,GACL,MAAM,CAsBlB;;WAlPa,MAAM;iBACN,MAAM;iBACN,MAAM;cACN,IAAI,GAAG,IAAI;cACX,MAAM;WACN,MAAM;kBACN,MAAM;aACN,QAAQ,GAAG,UAAU;;;WAKrB,wBAAwB,EAAE;aAC1B,OAAO;kBACP,MAAM;;;iBAKN,MAAM;iBACN,MAAM;cACN,QAAQ,GAAG,QAAQ;kBACnB,MAAM;uBACN,MAAM;qBACN,MAAM,EAAE;oBACR,OAAO;;;;WAMP,uBAAuB,EAAE;aACzB,OAAO;kBACP,MAAM;;;cAKN,MAAM;iBACN,MAAM;cACN,IAAI,GAAG,IAAI;cACX,MAAM;WACN,MAAM;WACN,MAAM;;;WAKN,wBAAwB,EAAE;aAC1B,OAAO;kBACP,MAAM;;;mBAKN,4BAA4B;kBAC5B,2BAA2B;uBAC3B,gCAAgC"}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Dashboard module — multi-project overview humble object (SPEC-91).
3
+ * Pure functions, no global state, no DOM access.
4
+ * All presentation logic lives in OverviewPresenter (server-side TypeScript);
5
+ * this module renders its view-model as HTML.
6
+ *
7
+ * Visual DNA: "Agentic OS" — see project_agentic_os_design_dna.md.
8
+ */
9
+
10
+ import { escapeHtml, sanitizeHttpUrl } from './html.js';
11
+
12
+ const SPARKLINE_WIDTH = 96;
13
+ const SPARKLINE_HEIGHT = 28;
14
+ const SPARKLINE_PADDING = 2;
15
+
16
+ /**
17
+ * @typedef {Object} OverviewActiveReviewItem
18
+ * @property {string} jobId
19
+ * @property {string} projectName
20
+ * @property {string} projectPath
21
+ * @property {'MR' | 'PR'} mrPrefix
22
+ * @property {number} mrNumber
23
+ * @property {string} mrUrl
24
+ * @property {string} elapsedLabel
25
+ * @property {'review' | 'followup'} jobType
26
+ */
27
+
28
+ /**
29
+ * @typedef {Object} OverviewActiveReviewsSection
30
+ * @property {OverviewActiveReviewItem[]} items
31
+ * @property {boolean} isEmpty
32
+ * @property {string} emptyMessage
33
+ */
34
+
35
+ /**
36
+ * @typedef {Object} OverviewProjectCardItem
37
+ * @property {string} projectName
38
+ * @property {string} projectPath
39
+ * @property {'gitlab' | 'github'} platform
40
+ * @property {number} totalReviews
41
+ * @property {string} averageScoreLabel
42
+ * @property {number[]} sparklinePoints
43
+ * @property {boolean} isEmptyHistory
44
+ * @property {string} [externalLink]
45
+ */
46
+
47
+ /**
48
+ * @typedef {Object} OverviewProjectCardsSection
49
+ * @property {OverviewProjectCardItem[]} items
50
+ * @property {boolean} isEmpty
51
+ * @property {string} emptyMessage
52
+ */
53
+
54
+ /**
55
+ * @typedef {Object} OverviewRecentReviewItem
56
+ * @property {string} filename
57
+ * @property {string} projectName
58
+ * @property {'MR' | 'PR'} mrPrefix
59
+ * @property {string} mrNumber
60
+ * @property {string} title
61
+ * @property {string} mtime
62
+ */
63
+
64
+ /**
65
+ * @typedef {Object} OverviewRecentReviewsFeedSection
66
+ * @property {OverviewRecentReviewItem[]} items
67
+ * @property {boolean} isEmpty
68
+ * @property {string} emptyMessage
69
+ */
70
+
71
+ /**
72
+ * @typedef {Object} OverviewViewModel
73
+ * @property {OverviewActiveReviewsSection} activeReviews
74
+ * @property {OverviewProjectCardsSection} projectCards
75
+ * @property {OverviewRecentReviewsFeedSection} recentReviewsFeed
76
+ */
77
+
78
+ /**
79
+ * @param {unknown} section
80
+ * @param {string} emptyMessage
81
+ * @returns {{ items: unknown[]; isEmpty: boolean; emptyMessage: string }}
82
+ */
83
+ function sectionWithDefaults(section, emptyMessage) {
84
+ if (!section || typeof section !== 'object') {
85
+ return { items: [], isEmpty: true, emptyMessage };
86
+ }
87
+ const typed = /** @type {Record<string, unknown>} */ (section);
88
+ const items = Array.isArray(typed.items) ? typed.items : [];
89
+ const explicitMessage = typeof typed.emptyMessage === 'string' ? typed.emptyMessage : emptyMessage;
90
+ return {
91
+ items,
92
+ isEmpty: items.length === 0,
93
+ emptyMessage: explicitMessage,
94
+ };
95
+ }
96
+
97
+ /**
98
+ * Renders a vector-only sparkline. Returns '' when there is nothing to draw.
99
+ *
100
+ * @param {number[]} points
101
+ * @returns {string}
102
+ */
103
+ export function renderSparklineSvg(points) {
104
+ if (!Array.isArray(points) || points.length === 0) return '';
105
+ const min = Math.min(...points);
106
+ const max = Math.max(...points);
107
+ const range = max - min || 1;
108
+ const usableWidth = SPARKLINE_WIDTH - SPARKLINE_PADDING * 2;
109
+ const usableHeight = SPARKLINE_HEIGHT - SPARKLINE_PADDING * 2;
110
+ const stepX = points.length === 1 ? 0 : usableWidth / (points.length - 1);
111
+ const coordinates = points
112
+ .map((value, index) => {
113
+ const x = SPARKLINE_PADDING + index * stepX;
114
+ const y = SPARKLINE_PADDING + usableHeight - ((value - min) / range) * usableHeight;
115
+ return `${x.toFixed(1)},${y.toFixed(1)}`;
116
+ })
117
+ .join(' ');
118
+ return `<svg class="overview-sparkline" viewBox="0 0 ${SPARKLINE_WIDTH} ${SPARKLINE_HEIGHT}" preserveAspectRatio="none" aria-hidden="true"><polyline fill="none" stroke="currentColor" stroke-width="1.5" points="${coordinates}" /></svg>`;
119
+ }
120
+
121
+ /**
122
+ * @param {OverviewActiveReviewItem} item
123
+ * @returns {string}
124
+ */
125
+ function renderActiveReviewRow(item) {
126
+ return `
127
+ <li class="overview-active-row" data-job-id="${escapeHtml(item.jobId)}">
128
+ <span class="overview-status-dot" data-status="running"></span>
129
+ <span class="overview-active-project">${escapeHtml(item.projectName)}</span>
130
+ <a class="overview-active-mr" href="${escapeHtml(sanitizeHttpUrl(item.mrUrl))}" target="_blank" rel="noopener">${escapeHtml(item.mrPrefix)} #${escapeHtml(String(item.mrNumber))}</a>
131
+ <span class="overview-active-elapsed">${escapeHtml(item.elapsedLabel)}</span>
132
+ </li>
133
+ `.trim();
134
+ }
135
+
136
+ /**
137
+ * @param {OverviewActiveReviewsSection} section
138
+ * @returns {string}
139
+ */
140
+ function renderActiveReviewsSection(section) {
141
+ const body = section.isEmpty
142
+ ? `<div class="overview-empty">${escapeHtml(section.emptyMessage)}</div>`
143
+ : `<ul class="overview-active-list">${section.items.map(renderActiveReviewRow).join('')}</ul>`;
144
+ return `
145
+ <section class="overview-panel" data-section="active">
146
+ <div class="overview-panel-title">// ACTIVE REVIEWS</div>
147
+ ${body}
148
+ </section>
149
+ `.trim();
150
+ }
151
+
152
+ /**
153
+ * @param {string | undefined} externalLink
154
+ * @returns {string}
155
+ */
156
+ function renderProjectExternalLink(externalLink) {
157
+ if (typeof externalLink !== 'string' || externalLink.length === 0) return '';
158
+ const safeHref = sanitizeHttpUrl(externalLink);
159
+ if (safeHref === '#') return '';
160
+ return `<a class="project-card__external" href="${escapeHtml(safeHref)}" target="_blank" rel="noopener noreferrer" aria-label="Ouvrir la documentation du projet">&#x2197;</a>`;
161
+ }
162
+
163
+ /**
164
+ * @param {OverviewProjectCardItem} card
165
+ * @returns {string}
166
+ */
167
+ function renderProjectCard(card) {
168
+ const sparkline = card.sparklinePoints.length === 0 ? '' : renderSparklineSvg(card.sparklinePoints);
169
+ const externalAnchor = renderProjectExternalLink(card.externalLink);
170
+ return `
171
+ <button type="button" class="overview-project-card" data-project-path="${escapeHtml(card.projectPath)}">
172
+ <div class="overview-project-card-header">
173
+ <span class="overview-project-card-name">${escapeHtml(card.projectName)}</span>
174
+ <span class="overview-project-card-platform" data-platform="${escapeHtml(card.platform)}">${escapeHtml(card.platform)}</span>
175
+ ${externalAnchor}
176
+ </div>
177
+ <div class="overview-project-card-totals">
178
+ <span class="overview-project-card-count">${escapeHtml(String(card.totalReviews))} reviews</span>
179
+ <span class="overview-project-card-score">Score ${escapeHtml(card.averageScoreLabel)}</span>
180
+ </div>
181
+ <div class="overview-project-card-sparkline">${sparkline}</div>
182
+ </button>
183
+ `.trim();
184
+ }
185
+
186
+ /**
187
+ * @param {OverviewProjectCardsSection} section
188
+ * @returns {string}
189
+ */
190
+ function renderProjectCardsSection(section) {
191
+ const body = section.isEmpty
192
+ ? `<div class="overview-empty">${escapeHtml(section.emptyMessage)}</div>`
193
+ : `<div class="overview-project-card-grid">${section.items.map(renderProjectCard).join('')}</div>`;
194
+ return `
195
+ <section class="overview-panel" data-section="projects">
196
+ <div class="overview-panel-title">// PROJECTS</div>
197
+ ${body}
198
+ </section>
199
+ `.trim();
200
+ }
201
+
202
+ /**
203
+ * @param {OverviewRecentReviewItem} item
204
+ * @returns {string}
205
+ */
206
+ function renderRecentReviewRow(item) {
207
+ return `
208
+ <li class="overview-recent-row" data-filename="${escapeHtml(item.filename)}">
209
+ <span class="overview-recent-project">${escapeHtml(item.projectName)}</span>
210
+ <span class="overview-recent-mr">${escapeHtml(item.mrPrefix)} #${escapeHtml(item.mrNumber)}</span>
211
+ <span class="overview-recent-title">${escapeHtml(item.title)}</span>
212
+ </li>
213
+ `.trim();
214
+ }
215
+
216
+ /**
217
+ * @param {OverviewRecentReviewsFeedSection} section
218
+ * @returns {string}
219
+ */
220
+ function renderRecentReviewsSection(section) {
221
+ const body = section.isEmpty
222
+ ? `<div class="overview-empty">${escapeHtml(section.emptyMessage)}</div>`
223
+ : `<ul class="overview-recent-list">${section.items.map(renderRecentReviewRow).join('')}</ul>`;
224
+ return `
225
+ <section class="overview-panel" data-section="recent">
226
+ <div class="overview-panel-title">// RECENT REVIEWS</div>
227
+ ${body}
228
+ </section>
229
+ `.trim();
230
+ }
231
+
232
+ /**
233
+ * Renders the overview HTML from a server-provided view-model.
234
+ * Tolerates missing sections by falling back to empty French defaults — the server
235
+ * is a boundary, so this guards against malformed payloads (deploys, partial fetches).
236
+ *
237
+ * @param {unknown} viewModel
238
+ * @returns {string}
239
+ */
240
+ export function renderOverviewHtml(viewModel) {
241
+ const source = viewModel && typeof viewModel === 'object'
242
+ ? /** @type {Record<string, unknown>} */ (viewModel)
243
+ : {};
244
+ const activeReviews = /** @type {OverviewActiveReviewsSection} */ (
245
+ sectionWithDefaults(source.activeReviews, 'Aucune review en cours')
246
+ );
247
+ const projectCards = /** @type {OverviewProjectCardsSection} */ (
248
+ sectionWithDefaults(source.projectCards, 'Aucun projet configuré')
249
+ );
250
+ const recentReviewsFeed = /** @type {OverviewRecentReviewsFeedSection} */ (
251
+ sectionWithDefaults(source.recentReviewsFeed, 'Aucune review récente')
252
+ );
253
+ return `
254
+ <div class="overview-grid">
255
+ ${renderActiveReviewsSection(activeReviews)}
256
+ ${renderProjectCardsSection(projectCards)}
257
+ ${renderRecentReviewsSection(recentReviewsFeed)}
258
+ </div>
259
+ `.trim();
260
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overview.js","sourceRoot":"","sources":["../../../src/dashboard/modules/overview.js"],"names":[],"mappings":"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"}