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,77 @@
1
+ /**
2
+ * @typedef {Object} SettingsModalConfigInput
3
+ * @property {'haiku' | 'sonnet' | 'opus'} defaultModel
4
+ * @property {string} reviewSkill
5
+ * @property {string} reviewFollowupSkill
6
+ * @property {'en' | 'fr'} language
7
+ * @property {string} [externalLink]
8
+ * @property {boolean} [github]
9
+ * @property {boolean} [gitlab]
10
+ * @property {number} [retentionDays]
11
+ */
12
+ /**
13
+ * @typedef {Object} SettingsModalBuildInput
14
+ * @property {SettingsModalConfigInput} config
15
+ * @property {string} [projectName]
16
+ */
17
+ /**
18
+ * @typedef {Object} SettingsModalViewModel
19
+ * @property {'en' | 'fr'} language
20
+ * @property {'haiku' | 'sonnet' | 'opus'} defaultModel
21
+ * @property {string} reviewSkill
22
+ * @property {string} reviewFollowupSkill
23
+ * @property {string} externalLink
24
+ * @property {string} projectName
25
+ */
26
+ /**
27
+ * @param {SettingsModalBuildInput} input
28
+ * @returns {SettingsModalViewModel}
29
+ */
30
+ export function buildSettingsViewModel(input: SettingsModalBuildInput): SettingsModalViewModel;
31
+ /**
32
+ * @param {SettingsModalViewModel} viewModel
33
+ * @returns {string}
34
+ */
35
+ export function renderSettingsModalHtml(viewModel: SettingsModalViewModel): string;
36
+ /**
37
+ * Mirrors the server-side regex from updateProjectConfig.usecase.ts.
38
+ *
39
+ * @param {string} value
40
+ * @returns {{ ok: true } | { ok: false; message: string }}
41
+ */
42
+ export function validateExternalLink(value: string): {
43
+ ok: true;
44
+ } | {
45
+ ok: false;
46
+ message: string;
47
+ };
48
+ /**
49
+ * Extracts a whitelisted payload from a FormData-like object (FormData or Map).
50
+ *
51
+ * @param {FormData | Map<string, string>} form
52
+ * @returns {Record<string, string>}
53
+ */
54
+ export function extractFormPayload(form: FormData | Map<string, string>): Record<string, string>;
55
+ export type SettingsModalConfigInput = {
56
+ defaultModel: "haiku" | "sonnet" | "opus";
57
+ reviewSkill: string;
58
+ reviewFollowupSkill: string;
59
+ language: "en" | "fr";
60
+ externalLink?: string | undefined;
61
+ github?: boolean | undefined;
62
+ gitlab?: boolean | undefined;
63
+ retentionDays?: number | undefined;
64
+ };
65
+ export type SettingsModalBuildInput = {
66
+ config: SettingsModalConfigInput;
67
+ projectName?: string | undefined;
68
+ };
69
+ export type SettingsModalViewModel = {
70
+ language: "en" | "fr";
71
+ defaultModel: "haiku" | "sonnet" | "opus";
72
+ reviewSkill: string;
73
+ reviewFollowupSkill: string;
74
+ externalLink: string;
75
+ projectName: string;
76
+ };
77
+ //# sourceMappingURL=settingsModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settingsModal.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/settingsModal.js"],"names":[],"mappings":"AAwBA;;;;;;;;;;GAUG;AAEH;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH;;;GAGG;AACH,8CAHW,uBAAuB,GACrB,sBAAsB,CAclC;AAkCD;;;GAGG;AACH,mDAHW,sBAAsB,GACpB,MAAM,CA0ClB;AAED;;;;;GAKG;AACH,4CAHW,MAAM,GACJ;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAWzD;AAED;;;;;GAKG;AACH,yCAHW,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYlC;;kBA3Ja,OAAO,GAAG,QAAQ,GAAG,MAAM;iBAC3B,MAAM;yBACN,MAAM;cACN,IAAI,GAAG,IAAI;;;;;;;YASX,wBAAwB;;;;cAMxB,IAAI,GAAG,IAAI;kBACX,OAAO,GAAG,QAAQ,GAAG,MAAM;iBAC3B,MAAM;yBACN,MAAM;kBACN,MAAM;iBACN,MAAM"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Dashboard module — Settings modal humble object (SPEC-179).
3
+ *
4
+ * Pure functions, no global state, no DOM access. Builds a viewmodel from a
5
+ * ProjectConfig payload, renders the dialog form HTML, validates the
6
+ * externalLink field client-side, and extracts a whitelisted patch payload
7
+ * from a FormData-like object.
8
+ *
9
+ * Visual DNA: "Agentic OS" — see project_agentic_os_design_dna.md.
10
+ */
11
+
12
+ import { escapeHtml } from './html.js';
13
+
14
+ const EDITABLE_KEYS = [
15
+ 'language',
16
+ 'defaultModel',
17
+ 'reviewSkill',
18
+ 'reviewFollowupSkill',
19
+ 'externalLink',
20
+ ];
21
+
22
+ const SUPPORTED_LANGUAGES = ['fr', 'en'];
23
+ const SUPPORTED_MODELS = ['haiku', 'sonnet', 'opus'];
24
+
25
+ /**
26
+ * @typedef {Object} SettingsModalConfigInput
27
+ * @property {'haiku' | 'sonnet' | 'opus'} defaultModel
28
+ * @property {string} reviewSkill
29
+ * @property {string} reviewFollowupSkill
30
+ * @property {'en' | 'fr'} language
31
+ * @property {string} [externalLink]
32
+ * @property {boolean} [github]
33
+ * @property {boolean} [gitlab]
34
+ * @property {number} [retentionDays]
35
+ */
36
+
37
+ /**
38
+ * @typedef {Object} SettingsModalBuildInput
39
+ * @property {SettingsModalConfigInput} config
40
+ * @property {string} [projectName]
41
+ */
42
+
43
+ /**
44
+ * @typedef {Object} SettingsModalViewModel
45
+ * @property {'en' | 'fr'} language
46
+ * @property {'haiku' | 'sonnet' | 'opus'} defaultModel
47
+ * @property {string} reviewSkill
48
+ * @property {string} reviewFollowupSkill
49
+ * @property {string} externalLink
50
+ * @property {string} projectName
51
+ */
52
+
53
+ /**
54
+ * @param {SettingsModalBuildInput} input
55
+ * @returns {SettingsModalViewModel}
56
+ */
57
+ export function buildSettingsViewModel(input) {
58
+ const config = input.config;
59
+ return {
60
+ language: config.language,
61
+ defaultModel: config.defaultModel,
62
+ reviewSkill: config.reviewSkill,
63
+ reviewFollowupSkill: config.reviewFollowupSkill,
64
+ externalLink: typeof config.externalLink === 'string' ? config.externalLink : '',
65
+ projectName: typeof input.projectName === 'string' && input.projectName.length > 0
66
+ ? input.projectName
67
+ : '—',
68
+ };
69
+ }
70
+
71
+ /**
72
+ * @param {SettingsModalViewModel} viewModel
73
+ * @returns {string}
74
+ */
75
+ function renderLanguageRadios(viewModel) {
76
+ return SUPPORTED_LANGUAGES
77
+ .map((value) => {
78
+ const checked = viewModel.language === value ? ' checked' : '';
79
+ const label = value === 'fr' ? 'Français' : 'English';
80
+ return `
81
+ <label class="settings-modal__radio">
82
+ <input type="radio" name="language" value="${escapeHtml(value)}"${checked} />
83
+ <span>${escapeHtml(label)}</span>
84
+ </label>
85
+ `.trim();
86
+ })
87
+ .join('');
88
+ }
89
+
90
+ /**
91
+ * @param {SettingsModalViewModel} viewModel
92
+ * @returns {string}
93
+ */
94
+ function renderModelOptions(viewModel) {
95
+ return SUPPORTED_MODELS
96
+ .map((value) => {
97
+ const selected = viewModel.defaultModel === value ? ' selected' : '';
98
+ return `<option value="${escapeHtml(value)}"${selected}>${escapeHtml(value)}</option>`;
99
+ })
100
+ .join('');
101
+ }
102
+
103
+ /**
104
+ * @param {SettingsModalViewModel} viewModel
105
+ * @returns {string}
106
+ */
107
+ export function renderSettingsModalHtml(viewModel) {
108
+ return `
109
+ <form class="settings-modal__form" method="dialog">
110
+ <h2 class="settings-modal__title" id="settings-modal-title">// SETTINGS — ${escapeHtml(viewModel.projectName)}</h2>
111
+
112
+ <fieldset class="settings-modal__field">
113
+ <legend class="settings-modal__legend">Langue</legend>
114
+ ${renderLanguageRadios(viewModel)}
115
+ </fieldset>
116
+
117
+ <label class="settings-modal__field">
118
+ <span class="settings-modal__label">Modèle par défaut</span>
119
+ <select name="defaultModel" class="settings-modal__select">
120
+ ${renderModelOptions(viewModel)}
121
+ </select>
122
+ </label>
123
+
124
+ <label class="settings-modal__field">
125
+ <span class="settings-modal__label">Skill de review</span>
126
+ <input type="text" name="reviewSkill" value="${escapeHtml(viewModel.reviewSkill)}" class="settings-modal__input" />
127
+ </label>
128
+
129
+ <label class="settings-modal__field">
130
+ <span class="settings-modal__label">Skill de review followup</span>
131
+ <input type="text" name="reviewFollowupSkill" value="${escapeHtml(viewModel.reviewFollowupSkill)}" class="settings-modal__input" />
132
+ </label>
133
+
134
+ <label class="settings-modal__field">
135
+ <span class="settings-modal__label">Lien externe (HTTPS)</span>
136
+ <input type="url" name="externalLink" value="${escapeHtml(viewModel.externalLink)}" placeholder="https://notion.so/team/projet" class="settings-modal__input" />
137
+ </label>
138
+
139
+ <p class="settings-modal__error" aria-live="polite"></p>
140
+
141
+ <div class="settings-modal__actions">
142
+ <button type="button" class="settings-modal__cancel">Annuler</button>
143
+ <button type="submit" class="settings-modal__submit">Enregistrer</button>
144
+ </div>
145
+ </form>
146
+ `.trim();
147
+ }
148
+
149
+ /**
150
+ * Mirrors the server-side regex from updateProjectConfig.usecase.ts.
151
+ *
152
+ * @param {string} value
153
+ * @returns {{ ok: true } | { ok: false; message: string }}
154
+ */
155
+ export function validateExternalLink(value) {
156
+ if (value === '') return { ok: true };
157
+ if (value.startsWith('http://')) {
158
+ return { ok: false, message: 'Le lien doit être en HTTPS' };
159
+ }
160
+ if (!/^https:\/\/.+/.test(value)) {
161
+ return { ok: false, message: 'URL invalide' };
162
+ }
163
+ return { ok: true };
164
+ }
165
+
166
+ /**
167
+ * Extracts a whitelisted payload from a FormData-like object (FormData or Map).
168
+ *
169
+ * @param {FormData | Map<string, string>} form
170
+ * @returns {Record<string, string>}
171
+ */
172
+ export function extractFormPayload(form) {
173
+ /** @type {Record<string, string>} */
174
+ const payload = {};
175
+ for (const key of EDITABLE_KEYS) {
176
+ const value = typeof form.get === 'function' ? form.get(key) : undefined;
177
+ if (typeof value === 'string') {
178
+ payload[key] = value;
179
+ }
180
+ }
181
+ return payload;
182
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settingsModal.js","sourceRoot":"","sources":["../../../src/dashboard/modules/settingsModal.js"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @typedef {Object} TabBarRepositoryInput
3
+ * @property {string} name
4
+ * @property {string} localPath
5
+ * @property {boolean} enabled
6
+ */
7
+ /**
8
+ * @typedef {Object} TabBarBuildInput
9
+ * @property {TabBarRepositoryInput[]} repositories
10
+ * @property {string | null} activeTabId
11
+ */
12
+ /**
13
+ * @typedef {Object} TabBarTabViewModel
14
+ * @property {string} id
15
+ * @property {string} label
16
+ * @property {boolean} isActive
17
+ * @property {boolean} enabled
18
+ */
19
+ /**
20
+ * @typedef {Object} TabBarViewModel
21
+ * @property {TabBarTabViewModel[]} tabs
22
+ */
23
+ /**
24
+ * @param {TabBarBuildInput} input
25
+ * @returns {TabBarViewModel}
26
+ */
27
+ export function buildTabBarModel(input: TabBarBuildInput): TabBarViewModel;
28
+ /**
29
+ * @param {TabBarViewModel} viewModel
30
+ * @returns {string}
31
+ */
32
+ export function renderTabBarHtml(viewModel: TabBarViewModel): string;
33
+ /**
34
+ * @returns {string | null}
35
+ */
36
+ export function readActiveTab(): string | null;
37
+ /**
38
+ * @param {string} tabId
39
+ * @returns {void}
40
+ */
41
+ export function writeActiveTab(tabId: string): void;
42
+ export type TabBarRepositoryInput = {
43
+ name: string;
44
+ localPath: string;
45
+ enabled: boolean;
46
+ };
47
+ export type TabBarBuildInput = {
48
+ repositories: TabBarRepositoryInput[];
49
+ activeTabId: string | null;
50
+ };
51
+ export type TabBarTabViewModel = {
52
+ id: string;
53
+ label: string;
54
+ isActive: boolean;
55
+ enabled: boolean;
56
+ };
57
+ export type TabBarViewModel = {
58
+ tabs: TabBarTabViewModel[];
59
+ };
60
+ //# sourceMappingURL=tabBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabBar.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/tabBar.js"],"names":[],"mappings":"AAcA;;;;;GAKG;AAEH;;;;GAIG;AAEH;;;;;;GAMG;AAEH;;;GAGG;AAEH;;;GAGG;AACH,wCAHW,gBAAgB,GACd,eAAe,CAsB3B;AAED;;;GAGG;AACH,4CAHW,eAAe,GACb,MAAM,CAWlB;AAED;;GAEG;AACH,iCAFa,MAAM,GAAG,IAAI,CAQzB;AAED;;;GAGG;AACH,sCAHW,MAAM,GACJ,IAAI,CAQhB;;UAtFa,MAAM;eACN,MAAM;aACN,OAAO;;;kBAKP,qBAAqB,EAAE;iBACvB,MAAM,GAAG,IAAI;;;QAKb,MAAM;WACN,MAAM;cACN,OAAO;aACP,OAAO;;;UAKP,kBAAkB,EAAE"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Dashboard module — tab bar humble object (SPEC-91).
3
+ * Pure functions, no global state, no DOM access in render helpers.
4
+ * localStorage is touched only by readActiveTab / writeActiveTab.
5
+ *
6
+ * Visual DNA: "Agentic OS" — see project_agentic_os_design_dna.md.
7
+ */
8
+
9
+ import { STORAGE_KEY_ACTIVE_TAB } from './constants.js';
10
+ import { escapeHtml } from './html.js';
11
+
12
+ const OVERVIEW_TAB_ID = 'overview';
13
+ const OVERVIEW_TAB_LABEL = 'Overview';
14
+
15
+ /**
16
+ * @typedef {Object} TabBarRepositoryInput
17
+ * @property {string} name
18
+ * @property {string} localPath
19
+ * @property {boolean} enabled
20
+ */
21
+
22
+ /**
23
+ * @typedef {Object} TabBarBuildInput
24
+ * @property {TabBarRepositoryInput[]} repositories
25
+ * @property {string | null} activeTabId
26
+ */
27
+
28
+ /**
29
+ * @typedef {Object} TabBarTabViewModel
30
+ * @property {string} id
31
+ * @property {string} label
32
+ * @property {boolean} isActive
33
+ * @property {boolean} enabled
34
+ */
35
+
36
+ /**
37
+ * @typedef {Object} TabBarViewModel
38
+ * @property {TabBarTabViewModel[]} tabs
39
+ */
40
+
41
+ /**
42
+ * @param {TabBarBuildInput} input
43
+ * @returns {TabBarViewModel}
44
+ */
45
+ export function buildTabBarModel(input) {
46
+ const repositories = Array.isArray(input.repositories) ? input.repositories : [];
47
+ const projectTabIds = new Set(repositories.map((repository) => repository.localPath));
48
+ const activeTabIdMatchesProject = input.activeTabId !== null && projectTabIds.has(input.activeTabId);
49
+ const effectiveActiveId = activeTabIdMatchesProject ? input.activeTabId : OVERVIEW_TAB_ID;
50
+
51
+ const overviewTab = {
52
+ id: OVERVIEW_TAB_ID,
53
+ label: OVERVIEW_TAB_LABEL,
54
+ isActive: effectiveActiveId === OVERVIEW_TAB_ID,
55
+ enabled: true,
56
+ };
57
+ const projectTabs = repositories.map((repository) => ({
58
+ id: repository.localPath,
59
+ label: repository.name,
60
+ isActive: effectiveActiveId === repository.localPath,
61
+ enabled: repository.enabled !== false,
62
+ }));
63
+
64
+ return { tabs: [overviewTab, ...projectTabs] };
65
+ }
66
+
67
+ /**
68
+ * @param {TabBarViewModel} viewModel
69
+ * @returns {string}
70
+ */
71
+ export function renderTabBarHtml(viewModel) {
72
+ const buttons = viewModel.tabs
73
+ .map((tab) => {
74
+ const activeClass = tab.isActive ? ' is-active' : '';
75
+ const enabledAttribute = tab.enabled ? 'true' : 'false';
76
+ return `<button type="button" class="dashboard-tab${activeClass}" data-tab-id="${escapeHtml(tab.id)}" data-enabled="${enabledAttribute}" role="tab" aria-selected="${tab.isActive ? 'true' : 'false'}">${escapeHtml(tab.label)}</button>`;
77
+ })
78
+ .join('');
79
+ return `<nav class="dashboard-tab-bar" role="tablist">${buttons}</nav>`;
80
+ }
81
+
82
+ /**
83
+ * @returns {string | null}
84
+ */
85
+ export function readActiveTab() {
86
+ try {
87
+ return localStorage.getItem(STORAGE_KEY_ACTIVE_TAB);
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+
93
+ /**
94
+ * @param {string} tabId
95
+ * @returns {void}
96
+ */
97
+ export function writeActiveTab(tabId) {
98
+ try {
99
+ localStorage.setItem(STORAGE_KEY_ACTIVE_TAB, tabId);
100
+ } catch {
101
+ // localStorage may be unavailable (private mode, server-side rendering); ignore.
102
+ }
103
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabBar.js","sourceRoot":"","sources":["../../../src/dashboard/modules/tabBar.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,eAAe,GAAG,UAAU,CAAC;AACnC,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAEtC;;;;;GAKG;AAEH;;;;GAIG;AAEH;;;;;;GAMG;AAEH;;;GAGG;AAEH;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAK;IACpC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IACtF,MAAM,yBAAyB,GAAG,KAAK,CAAC,WAAW,KAAK,IAAI,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACrG,MAAM,iBAAiB,GAAG,yBAAyB,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC;IAE1F,MAAM,WAAW,GAAG;QAClB,EAAE,EAAE,eAAe;QACnB,KAAK,EAAE,kBAAkB;QACzB,QAAQ,EAAE,iBAAiB,KAAK,eAAe;QAC/C,OAAO,EAAE,IAAI;KACd,CAAC;IACF,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACpD,EAAE,EAAE,UAAU,CAAC,SAAS;QACxB,KAAK,EAAE,UAAU,CAAC,IAAI;QACtB,QAAQ,EAAE,iBAAiB,KAAK,UAAU,CAAC,SAAS;QACpD,OAAO,EAAE,UAAU,CAAC,OAAO,KAAK,KAAK;KACtC,CAAC,CAAC,CAAC;IAEJ,OAAO,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAS;IACxC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI;SAC3B,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,MAAM,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QACxD,OAAO,6CAA6C,WAAW,kBAAkB,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,mBAAmB,gBAAgB,+BAA+B,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC;IAC5O,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,iDAAiD,OAAO,QAAQ,CAAC;AAC1E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAK;IAClC,IAAI,CAAC;QACH,YAAY,CAAC,OAAO,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,iFAAiF;IACnF,CAAC;AACH,CAAC"}