reviewflow 3.17.1 → 3.19.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 (184) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/config/projectConfig.d.ts +8 -0
  3. package/dist/config/projectConfig.d.ts.map +1 -1
  4. package/dist/config/projectConfig.js +59 -7
  5. package/dist/config/projectConfig.js.map +1 -1
  6. package/dist/dashboard/index.html +303 -175
  7. package/dist/dashboard/modules/budgetSettings.d.ts.map +1 -1
  8. package/dist/dashboard/modules/budgetSettings.js +2 -4
  9. package/dist/dashboard/modules/budgetSettings.js.map +1 -1
  10. package/dist/dashboard/modules/desktopNotifications.d.ts.map +1 -1
  11. package/dist/dashboard/modules/desktopNotifications.js +1 -0
  12. package/dist/dashboard/modules/desktopNotifications.js.map +1 -1
  13. package/dist/dashboard/modules/i18n.d.ts.map +1 -1
  14. package/dist/dashboard/modules/i18n.js +12 -0
  15. package/dist/dashboard/modules/i18n.js.map +1 -1
  16. package/dist/dashboard/modules/pendingReviews.d.ts +49 -0
  17. package/dist/dashboard/modules/pendingReviews.d.ts.map +1 -0
  18. package/dist/dashboard/modules/pendingReviews.js +80 -0
  19. package/dist/dashboard/modules/pendingReviews.js.map +1 -0
  20. package/dist/dashboard/styles.css +162 -8
  21. package/dist/frameworks/config/configLoader.d.ts +2 -0
  22. package/dist/frameworks/config/configLoader.d.ts.map +1 -1
  23. package/dist/frameworks/config/configLoader.js +27 -2
  24. package/dist/frameworks/config/configLoader.js.map +1 -1
  25. package/dist/main/routes.d.ts.map +1 -1
  26. package/dist/main/routes.js +57 -2
  27. package/dist/main/routes.js.map +1 -1
  28. package/dist/main/websocket.d.ts +1 -0
  29. package/dist/main/websocket.d.ts.map +1 -1
  30. package/dist/main/websocket.js +11 -0
  31. package/dist/main/websocket.js.map +1 -1
  32. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.d.ts.map +1 -1
  33. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.js +24 -6
  34. package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.js.map +1 -1
  35. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/github.controller.d.ts +2 -0
  36. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/github.controller.d.ts.map +1 -1
  37. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/github.controller.js +54 -6
  38. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/github.controller.js.map +1 -1
  39. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/gitlab.controller.d.ts +6 -0
  40. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/gitlab.controller.d.ts.map +1 -1
  41. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/gitlab.controller.js +76 -21
  42. package/dist/modules/platform-integration/interface-adapters/controllers/webhook/gitlab.controller.js.map +1 -1
  43. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.gateway.d.ts +8 -0
  44. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.gateway.d.ts.map +1 -0
  45. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.gateway.js +2 -0
  46. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.gateway.js.map +1 -0
  47. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.guard.d.ts +29 -0
  48. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.guard.d.ts.map +1 -0
  49. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.guard.js +4 -0
  50. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.guard.js.map +1 -0
  51. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.schema.d.ts +94 -0
  52. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.schema.d.ts.map +1 -0
  53. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.schema.js +40 -0
  54. package/dist/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.schema.js.map +1 -0
  55. package/dist/modules/review-execution/entities/progress/agentDefinition.type.d.ts +4 -0
  56. package/dist/modules/review-execution/entities/progress/agentDefinition.type.d.ts.map +1 -1
  57. package/dist/modules/review-execution/entities/progress/agentDefinition.type.js +42 -0
  58. package/dist/modules/review-execution/entities/progress/agentDefinition.type.js.map +1 -1
  59. package/dist/modules/review-execution/entities/progress/reviewFocus.type.d.ts +8 -0
  60. package/dist/modules/review-execution/entities/progress/reviewFocus.type.d.ts.map +1 -0
  61. package/dist/modules/review-execution/entities/progress/reviewFocus.type.js +30 -0
  62. package/dist/modules/review-execution/entities/progress/reviewFocus.type.js.map +1 -0
  63. package/dist/modules/review-execution/interface-adapters/controllers/http/pendingReviews.routes.d.ts +13 -0
  64. package/dist/modules/review-execution/interface-adapters/controllers/http/pendingReviews.routes.d.ts.map +1 -0
  65. package/dist/modules/review-execution/interface-adapters/controllers/http/pendingReviews.routes.js +34 -0
  66. package/dist/modules/review-execution/interface-adapters/controllers/http/pendingReviews.routes.js.map +1 -0
  67. package/dist/modules/review-execution/interface-adapters/gateways/pendingReviewRequest.fileSystem.gateway.d.ts +16 -0
  68. package/dist/modules/review-execution/interface-adapters/gateways/pendingReviewRequest.fileSystem.gateway.d.ts.map +1 -0
  69. package/dist/modules/review-execution/interface-adapters/gateways/pendingReviewRequest.fileSystem.gateway.js +81 -0
  70. package/dist/modules/review-execution/interface-adapters/gateways/pendingReviewRequest.fileSystem.gateway.js.map +1 -0
  71. package/dist/modules/review-execution/interface-adapters/presenters/pendingReview.presenter.d.ts +25 -0
  72. package/dist/modules/review-execution/interface-adapters/presenters/pendingReview.presenter.d.ts.map +1 -0
  73. package/dist/modules/review-execution/interface-adapters/presenters/pendingReview.presenter.js +41 -0
  74. package/dist/modules/review-execution/interface-adapters/presenters/pendingReview.presenter.js.map +1 -0
  75. package/dist/modules/review-execution/services/processorRegistry.d.ts +15 -0
  76. package/dist/modules/review-execution/services/processorRegistry.d.ts.map +1 -0
  77. package/dist/modules/review-execution/services/processorRegistry.js +23 -0
  78. package/dist/modules/review-execution/services/processorRegistry.js.map +1 -0
  79. package/dist/modules/review-execution/usecases/confirmPendingReview.usecase.d.ts +32 -0
  80. package/dist/modules/review-execution/usecases/confirmPendingReview.usecase.d.ts.map +1 -0
  81. package/dist/modules/review-execution/usecases/confirmPendingReview.usecase.js +29 -0
  82. package/dist/modules/review-execution/usecases/confirmPendingReview.usecase.js.map +1 -0
  83. package/dist/modules/review-execution/usecases/dismissPendingReview.usecase.d.ts +26 -0
  84. package/dist/modules/review-execution/usecases/dismissPendingReview.usecase.d.ts.map +1 -0
  85. package/dist/modules/review-execution/usecases/dismissPendingReview.usecase.js +22 -0
  86. package/dist/modules/review-execution/usecases/dismissPendingReview.usecase.js.map +1 -0
  87. package/dist/modules/review-execution/usecases/gateClaudeInvocation.usecase.d.ts +36 -0
  88. package/dist/modules/review-execution/usecases/gateClaudeInvocation.usecase.d.ts.map +1 -0
  89. package/dist/modules/review-execution/usecases/gateClaudeInvocation.usecase.js +36 -0
  90. package/dist/modules/review-execution/usecases/gateClaudeInvocation.usecase.js.map +1 -0
  91. package/dist/modules/review-execution/usecases/listPendingReviews.usecase.d.ts +11 -0
  92. package/dist/modules/review-execution/usecases/listPendingReviews.usecase.d.ts.map +1 -0
  93. package/dist/modules/review-execution/usecases/listPendingReviews.usecase.js +10 -0
  94. package/dist/modules/review-execution/usecases/listPendingReviews.usecase.js.map +1 -0
  95. package/dist/modules/tracking/interface-adapters/controllers/http/mrTrackingAdvanced.routes.d.ts +2 -0
  96. package/dist/modules/tracking/interface-adapters/controllers/http/mrTrackingAdvanced.routes.d.ts.map +1 -1
  97. package/dist/modules/tracking/interface-adapters/controllers/http/mrTrackingAdvanced.routes.js +22 -4
  98. package/dist/modules/tracking/interface-adapters/controllers/http/mrTrackingAdvanced.routes.js.map +1 -1
  99. package/dist/tests/acceptance/174-semi-auto-review-trigger-mode.acceptance.test.d.ts +2 -0
  100. package/dist/tests/acceptance/174-semi-auto-review-trigger-mode.acceptance.test.d.ts.map +1 -0
  101. package/dist/tests/acceptance/174-semi-auto-review-trigger-mode.acceptance.test.js +161 -0
  102. package/dist/tests/acceptance/174-semi-auto-review-trigger-mode.acceptance.test.js.map +1 -0
  103. package/dist/tests/acceptance/46-github-followup-review-on-push.acceptance.test.js +1 -0
  104. package/dist/tests/acceptance/46-github-followup-review-on-push.acceptance.test.js.map +1 -1
  105. package/dist/tests/acceptance/reviewFocus.acceptance.test.d.ts +2 -0
  106. package/dist/tests/acceptance/reviewFocus.acceptance.test.d.ts.map +1 -0
  107. package/dist/tests/acceptance/reviewFocus.acceptance.test.js +114 -0
  108. package/dist/tests/acceptance/reviewFocus.acceptance.test.js.map +1 -0
  109. package/dist/tests/factories/config.factory.d.ts.map +1 -1
  110. package/dist/tests/factories/config.factory.js +1 -0
  111. package/dist/tests/factories/config.factory.js.map +1 -1
  112. package/dist/tests/factories/pendingReviewRequest.factory.d.ts +5 -0
  113. package/dist/tests/factories/pendingReviewRequest.factory.d.ts.map +1 -0
  114. package/dist/tests/factories/pendingReviewRequest.factory.js +25 -0
  115. package/dist/tests/factories/pendingReviewRequest.factory.js.map +1 -0
  116. package/dist/tests/factories/projectConfig.factory.d.ts +21 -0
  117. package/dist/tests/factories/projectConfig.factory.d.ts.map +1 -0
  118. package/dist/tests/factories/projectConfig.factory.js +43 -0
  119. package/dist/tests/factories/projectConfig.factory.js.map +1 -0
  120. package/dist/tests/stubs/pendingReviewRequest.stub.d.ts +14 -0
  121. package/dist/tests/stubs/pendingReviewRequest.stub.d.ts.map +1 -0
  122. package/dist/tests/stubs/pendingReviewRequest.stub.js +29 -0
  123. package/dist/tests/stubs/pendingReviewRequest.stub.js.map +1 -0
  124. package/dist/tests/units/config/projectConfig.test.js +101 -1
  125. package/dist/tests/units/config/projectConfig.test.js.map +1 -1
  126. package/dist/tests/units/dashboard/modules/pendingReviews.test.d.ts +2 -0
  127. package/dist/tests/units/dashboard/modules/pendingReviews.test.d.ts.map +1 -0
  128. package/dist/tests/units/dashboard/modules/pendingReviews.test.js +60 -0
  129. package/dist/tests/units/dashboard/modules/pendingReviews.test.js.map +1 -0
  130. package/dist/tests/units/frameworks/config/configLoader.test.js +85 -0
  131. package/dist/tests/units/frameworks/config/configLoader.test.js.map +1 -1
  132. package/dist/tests/units/interface-adapters/controllers/webhook/github.controller.test.js +1 -0
  133. package/dist/tests/units/interface-adapters/controllers/webhook/github.controller.test.js.map +1 -1
  134. package/dist/tests/units/interface-adapters/controllers/webhook/gitlab.controller.test.js +1 -0
  135. package/dist/tests/units/interface-adapters/controllers/webhook/gitlab.controller.test.js.map +1 -1
  136. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.d.ts +2 -0
  137. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.d.ts.map +1 -0
  138. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.js +130 -0
  139. package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.js.map +1 -0
  140. package/dist/tests/units/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.guard.test.d.ts +2 -0
  141. package/dist/tests/units/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.guard.test.d.ts.map +1 -0
  142. package/dist/tests/units/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.guard.test.js +32 -0
  143. package/dist/tests/units/modules/review-execution/entities/pendingReviewRequest/pendingReviewRequest.guard.test.js.map +1 -0
  144. package/dist/tests/units/modules/review-execution/entities/progress/agentDefinition.type.test.d.ts +2 -0
  145. package/dist/tests/units/modules/review-execution/entities/progress/agentDefinition.type.test.d.ts.map +1 -0
  146. package/dist/tests/units/modules/review-execution/entities/progress/agentDefinition.type.test.js +108 -0
  147. package/dist/tests/units/modules/review-execution/entities/progress/agentDefinition.type.test.js.map +1 -0
  148. package/dist/tests/units/modules/review-execution/entities/progress/reviewFocus.type.test.d.ts +2 -0
  149. package/dist/tests/units/modules/review-execution/entities/progress/reviewFocus.type.test.d.ts.map +1 -0
  150. package/dist/tests/units/modules/review-execution/entities/progress/reviewFocus.type.test.js +73 -0
  151. package/dist/tests/units/modules/review-execution/entities/progress/reviewFocus.type.test.js.map +1 -0
  152. package/dist/tests/units/modules/review-execution/interface-adapters/controllers/http/pendingReviews.routes.test.d.ts +2 -0
  153. package/dist/tests/units/modules/review-execution/interface-adapters/controllers/http/pendingReviews.routes.test.d.ts.map +1 -0
  154. package/dist/tests/units/modules/review-execution/interface-adapters/controllers/http/pendingReviews.routes.test.js +114 -0
  155. package/dist/tests/units/modules/review-execution/interface-adapters/controllers/http/pendingReviews.routes.test.js.map +1 -0
  156. package/dist/tests/units/modules/review-execution/interface-adapters/gateways/pendingReviewRequest.fileSystem.gateway.test.d.ts +2 -0
  157. package/dist/tests/units/modules/review-execution/interface-adapters/gateways/pendingReviewRequest.fileSystem.gateway.test.d.ts.map +1 -0
  158. package/dist/tests/units/modules/review-execution/interface-adapters/gateways/pendingReviewRequest.fileSystem.gateway.test.js +67 -0
  159. package/dist/tests/units/modules/review-execution/interface-adapters/gateways/pendingReviewRequest.fileSystem.gateway.test.js.map +1 -0
  160. package/dist/tests/units/modules/review-execution/interface-adapters/presenters/pendingReview.presenter.test.d.ts +2 -0
  161. package/dist/tests/units/modules/review-execution/interface-adapters/presenters/pendingReview.presenter.test.d.ts.map +1 -0
  162. package/dist/tests/units/modules/review-execution/interface-adapters/presenters/pendingReview.presenter.test.js +40 -0
  163. package/dist/tests/units/modules/review-execution/interface-adapters/presenters/pendingReview.presenter.test.js.map +1 -0
  164. package/dist/tests/units/modules/review-execution/services/processorRegistry.test.d.ts +2 -0
  165. package/dist/tests/units/modules/review-execution/services/processorRegistry.test.d.ts.map +1 -0
  166. package/dist/tests/units/modules/review-execution/services/processorRegistry.test.js +54 -0
  167. package/dist/tests/units/modules/review-execution/services/processorRegistry.test.js.map +1 -0
  168. package/dist/tests/units/modules/review-execution/usecases/confirmPendingReview.usecase.test.d.ts +2 -0
  169. package/dist/tests/units/modules/review-execution/usecases/confirmPendingReview.usecase.test.d.ts.map +1 -0
  170. package/dist/tests/units/modules/review-execution/usecases/confirmPendingReview.usecase.test.js +86 -0
  171. package/dist/tests/units/modules/review-execution/usecases/confirmPendingReview.usecase.test.js.map +1 -0
  172. package/dist/tests/units/modules/review-execution/usecases/dismissPendingReview.usecase.test.d.ts +2 -0
  173. package/dist/tests/units/modules/review-execution/usecases/dismissPendingReview.usecase.test.d.ts.map +1 -0
  174. package/dist/tests/units/modules/review-execution/usecases/dismissPendingReview.usecase.test.js +50 -0
  175. package/dist/tests/units/modules/review-execution/usecases/dismissPendingReview.usecase.test.js.map +1 -0
  176. package/dist/tests/units/modules/review-execution/usecases/gateClaudeInvocation.usecase.test.d.ts +2 -0
  177. package/dist/tests/units/modules/review-execution/usecases/gateClaudeInvocation.usecase.test.d.ts.map +1 -0
  178. package/dist/tests/units/modules/review-execution/usecases/gateClaudeInvocation.usecase.test.js +134 -0
  179. package/dist/tests/units/modules/review-execution/usecases/gateClaudeInvocation.usecase.test.js.map +1 -0
  180. package/dist/tests/units/modules/review-execution/usecases/listPendingReviews.usecase.test.d.ts +2 -0
  181. package/dist/tests/units/modules/review-execution/usecases/listPendingReviews.usecase.test.d.ts.map +1 -0
  182. package/dist/tests/units/modules/review-execution/usecases/listPendingReviews.usecase.test.js +27 -0
  183. package/dist/tests/units/modules/review-execution/usecases/listPendingReviews.usecase.test.js.map +1 -0
  184. package/package.json +1 -1
@@ -66,204 +66,227 @@
66
66
  </select>
67
67
  </div>
68
68
  </div>
69
- <div class="card">
70
- <div class="card-label" id="i18n-card-language"></div>
71
- <div class="card-model">
69
+ </div>
70
+
71
+ <div class="dashboard-layout">
72
+ <aside class="dashboard-sidebar" aria-label="Project tools">
73
+ <div class="sidebar-language">
74
+ <label class="sidebar-language-label" for="language-select" id="i18n-card-language"></label>
72
75
  <select id="language-select" class="model-select" onchange="changeLanguage(this.value)">
73
76
  <option value="en">English</option>
74
77
  <option value="fr">Français</option>
75
78
  </select>
76
79
  </div>
77
- </div>
78
- </div>
79
80
 
80
- <div class="focus-strip">
81
- <div class="focus-chip focus-now">
82
- <div class="focus-copy">
83
- <span class="focus-label" id="i18n-strip-now"></span>
84
- <span class="focus-meta" id="i18n-strip-now-meta"></span>
85
- </div>
86
- <span class="focus-value" id="focus-now-count">-</span>
87
- </div>
88
- <div class="focus-chip focus-next">
89
- <div class="focus-copy">
90
- <span class="focus-label" id="i18n-strip-next"></span>
91
- <span class="focus-meta" id="i18n-strip-next-meta"></span>
92
- </div>
93
- <span class="focus-value" id="focus-next-count">-</span>
94
- </div>
95
- <div class="focus-chip focus-blocked">
96
- <div class="focus-copy">
97
- <span class="focus-label" id="i18n-strip-blocked"></span>
98
- <span class="focus-meta" id="i18n-strip-blocked-meta"></span>
81
+ <div class="project-loader">
82
+ <select id="project-select" class="project-input" onchange="onProjectSelect(this.value)">
83
+ <option value="" id="i18n-project-placeholder"></option>
84
+ </select>
85
+ <input type="text" id="project-path-input" class="project-input" value="">
86
+ <button class="btn btn-primary" onclick="loadProjectConfig()">
87
+ <i data-lucide="folder-open"></i> <span id="i18n-project-load"></span>
88
+ </button>
89
+ <button id="remove-project-btn" class="btn btn-secondary" onclick="removeCurrentProject()">
90
+ <i data-lucide="trash-2"></i>
91
+ </button>
92
+ <span id="config-status" class="config-status hidden"></span>
99
93
  </div>
100
- <span class="focus-value" id="focus-blocked-count">-</span>
101
- </div>
102
- <button id="focus-strip-toggle" class="focus-toggle-btn" onclick="toggleFocusStripMode()"></button>
103
- </div>
104
94
 
105
- <div id="data-loading-state" class="data-loading hidden" role="status" aria-live="polite">
106
- <i data-lucide="loader-circle"></i>
107
- <span id="i18n-loading-data"></span>
108
- </div>
95
+ <div class="focus-strip">
96
+ <div class="focus-chip focus-now">
97
+ <div class="focus-copy">
98
+ <span class="focus-label" id="i18n-strip-now"></span>
99
+ <span class="focus-meta" id="i18n-strip-now-meta"></span>
100
+ </div>
101
+ <span class="focus-value" id="focus-now-count">-</span>
102
+ </div>
103
+ <div class="focus-chip focus-next">
104
+ <div class="focus-copy">
105
+ <span class="focus-label" id="i18n-strip-next"></span>
106
+ <span class="focus-meta" id="i18n-strip-next-meta"></span>
107
+ </div>
108
+ <span class="focus-value" id="focus-next-count">-</span>
109
+ </div>
110
+ <div class="focus-chip focus-blocked">
111
+ <div class="focus-copy">
112
+ <span class="focus-label" id="i18n-strip-blocked"></span>
113
+ <span class="focus-meta" id="i18n-strip-blocked-meta"></span>
114
+ </div>
115
+ <span class="focus-value" id="focus-blocked-count">-</span>
116
+ </div>
117
+ <button id="focus-strip-toggle" class="focus-toggle-btn" onclick="toggleFocusStripMode()"></button>
118
+ </div>
109
119
 
110
- <div class="project-loader">
111
- <select id="project-select" class="project-input" style="min-width: 350px;" onchange="onProjectSelect(this.value)">
112
- <option value="" id="i18n-project-placeholder"></option>
113
- </select>
114
- <input type="text" id="project-path-input" class="project-input" style="min-width: 250px;"
115
- value="">
116
- <button class="btn btn-primary" onclick="loadProjectConfig()">
117
- <i data-lucide="folder-open"></i> <span id="i18n-project-load"></span>
118
- </button>
119
- <button id="remove-project-btn" class="btn btn-secondary" onclick="removeCurrentProject()">
120
- <i data-lucide="trash-2"></i>
121
- </button>
122
- <span id="config-status" class="config-status hidden"></span>
123
- </div>
124
- <div id="config-info" class="config-info hidden"></div>
120
+ <section id="worktree-section" aria-label="Worktree pool"></section>
121
+ </aside>
125
122
 
126
- <div id="claude-login-section" class="login-instructions hidden">
127
- <strong><i data-lucide="alert-triangle"></i> <span id="i18n-claude-login-title"></span></strong>
128
- <p style="margin-top: 0.5rem;" id="i18n-claude-login-instruction"></p>
129
- <p style="margin-top: 0.5rem;"><code>claude login</code></p>
130
- <p style="margin-top: 0.5rem; font-size: 0.875rem; color: #a1a1aa;" id="i18n-claude-login-reload"></p>
131
- </div>
123
+ <main class="dashboard-main">
124
+ <div id="data-loading-state" class="data-loading hidden" role="status" aria-live="polite">
125
+ <i data-lucide="loader-circle"></i>
126
+ <span id="i18n-loading-data"></span>
127
+ </div>
132
128
 
133
- <div id="git-login-section" class="login-instructions hidden">
134
- <strong id="git-login-title"><i data-lucide="alert-triangle"></i> <span id="i18n-git-login-title"></span></strong>
135
- <div style="margin-top: 0.75rem;" id="git-login-instructions"></div>
136
- </div>
129
+ <div id="config-info" class="config-info hidden"></div>
137
130
 
138
- <div id="logs-section" class="section hidden">
139
- <div class="section-header">
140
- <i data-lucide="scroll-text"></i> <span id="i18n-section-logs"></span>
141
- <span id="error-count" class="badge-count hidden"></span>
142
- </div>
143
- <div id="logs-content" class="section-content logs">
144
- <div class="empty-state" id="i18n-empty-logs"></div>
145
- </div>
146
- </div>
131
+ <div id="claude-login-section" class="login-instructions hidden">
132
+ <strong><i data-lucide="alert-triangle"></i> <span id="i18n-claude-login-title"></span></strong>
133
+ <p style="margin-top: 0.5rem;" id="i18n-claude-login-instruction"></p>
134
+ <p style="margin-top: 0.5rem;"><code>claude login</code></p>
135
+ <p style="margin-top: 0.5rem; font-size: 0.875rem; color: #a1a1aa;" id="i18n-claude-login-reload"></p>
136
+ </div>
147
137
 
148
- <div id="stats-section" class="section hidden">
149
- <div class="section-header clickable" onclick="toggleStats()" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
150
- <i data-lucide="bar-chart-3"></i> <span id="i18n-section-stats"></span>
151
- <span id="stats-toggle" class="toggle-icon collapsed"><i data-lucide="chevron-down"></i></span>
152
- <button id="recalculate-btn" class="btn btn-sm btn-secondary" onclick="event.stopPropagation(); recalculateStats()" style="margin-left: auto; font-size: 0.75rem; padding: 2px 8px;">
153
- <i data-lucide="refresh-cw" style="width: 12px; height: 12px;"></i>
154
- <span id="recalculate-label"></span>
155
- </button>
156
- <span id="backfill-progress" class="badge-count hidden" style="margin-left: 4px;"></span>
157
- </div>
158
- <div id="project-stats" class="section-content stats-grid hidden">
159
- <div class="empty-state" id="i18n-empty-stats"></div>
160
- </div>
161
- </div>
138
+ <div id="git-login-section" class="login-instructions hidden">
139
+ <strong id="git-login-title"><i data-lucide="alert-triangle"></i> <span id="i18n-git-login-title"></span></strong>
140
+ <div style="margin-top: 0.75rem;" id="git-login-instructions"></div>
141
+ </div>
162
142
 
163
- <div id="team-section" class="section hidden">
164
- <div class="section-header clickable" onclick="toggleTeamSection()" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
165
- <i data-lucide="users"></i> <span id="i18n-section-team"></span>
166
- <span id="team-toggle" class="toggle-icon collapsed"><i data-lucide="chevron-down"></i></span>
167
- </div>
168
- <div id="team-tab-content" class="section-content hidden">
169
- <div class="empty-state" id="i18n-empty-team"></div>
170
- </div>
171
- </div>
143
+ <div class="section" id="pending-reviews-section">
144
+ <div class="section-header">
145
+ <i data-lucide="hourglass"></i> <span id="i18n-section-pending-reviews"></span>
146
+ <span id="pending-reviews-count" class="badge-count hidden">0</span>
147
+ </div>
148
+ <div id="pending-reviews" class="section-content">
149
+ <div class="empty-state" id="i18n-empty-pending-reviews"></div>
150
+ </div>
151
+ </div>
172
152
 
173
- <div id="token-usage-section" class="section hidden">
174
- <div class="section-header">
175
- <i data-lucide="coins"></i> <span>Claude token usage</span>
176
- </div>
177
- <div id="token-usage-content" class="section-content">
178
- <div class="empty-state">Loading…</div>
179
- </div>
180
- </div>
153
+ <div id="logs-section" class="section hidden">
154
+ <div class="section-header">
155
+ <i data-lucide="scroll-text"></i> <span id="i18n-section-logs"></span>
156
+ <span id="error-count" class="badge-count hidden"></span>
157
+ </div>
158
+ <div id="logs-content" class="section-content logs">
159
+ <div class="empty-state" id="i18n-empty-logs"></div>
160
+ </div>
161
+ </div>
181
162
 
182
- <div id="budget-section" class="section">
183
- <div class="section-header">
184
- <i data-lucide="wallet"></i> <span>Monthly Claude budget</span>
185
- </div>
186
- <div class="section-content">
187
- <div id="budget-tile">
188
- <div class="empty-state">Loading…</div>
163
+ <div id="stats-section" class="section hidden">
164
+ <div class="section-header clickable" onclick="toggleStats()" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
165
+ <i data-lucide="bar-chart-3"></i> <span id="i18n-section-stats"></span>
166
+ <span id="stats-toggle" class="toggle-icon collapsed"><i data-lucide="chevron-down"></i></span>
167
+ <button id="recalculate-btn" class="btn btn-sm btn-secondary" onclick="event.stopPropagation(); recalculateStats()" style="margin-left: auto; font-size: 0.75rem; padding: 2px 8px;">
168
+ <i data-lucide="refresh-cw" style="width: 12px; height: 12px;"></i>
169
+ <span id="recalculate-label"></span>
170
+ </button>
171
+ <span id="backfill-progress" class="badge-count hidden" style="margin-left: 4px;"></span>
172
+ </div>
173
+ <div id="project-stats" class="section-content stats-grid hidden">
174
+ <div class="empty-state" id="i18n-empty-stats"></div>
175
+ </div>
189
176
  </div>
190
- <div class="budget-slider-row">
191
- <label for="budget-slider" id="budget-slider-label">Cap: <span id="budget-slider-value">$200</span></label>
192
- <input type="range" id="budget-slider" min="0" max="600" step="10" value="200" />
193
- <button id="budget-slider-submit" type="button">Apply</button>
194
- <span id="budget-slider-status" class="budget-slider-status"></span>
177
+
178
+ <div id="team-section" class="section hidden">
179
+ <div class="section-header clickable" onclick="toggleTeamSection()" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
180
+ <i data-lucide="users"></i> <span id="i18n-section-team"></span>
181
+ <span id="team-toggle" class="toggle-icon collapsed"><i data-lucide="chevron-down"></i></span>
182
+ </div>
183
+ <div id="team-tab-content" class="section-content hidden">
184
+ <div class="empty-state" id="i18n-empty-team"></div>
185
+ </div>
195
186
  </div>
196
- </div>
197
- </div>
198
187
 
199
- <div class="section" id="active-reviews-section">
200
- <div class="section-header">
201
- <i data-lucide="file-search"></i> <span id="i18n-section-active-reviews"></span>
202
- <span id="active-reviews-count" class="badge-count hidden">0</span>
203
- </div>
204
- <div id="active-reviews" class="section-content">
205
- <div class="empty-state" id="i18n-empty-active-reviews"></div>
206
- </div>
207
- </div>
188
+ <div id="claude-economics-section" class="section">
189
+ <div class="section-header clickable" onclick="toggleSection('claude-economics-section')" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
190
+ <i data-lucide="circuit-board"></i> <span id="i18n-section-claude-economics"></span>
191
+ <span class="section-toggle collapsed"><i data-lucide="chevron-down"></i></span>
192
+ </div>
193
+ <div class="section-content economics-content hidden">
194
+ <div class="economics-panel">
195
+ <div class="economics-panel-header">
196
+ <span class="economics-panel-title" id="i18n-economics-token-usage"></span>
197
+ </div>
198
+ <div class="economics-panel-body" id="token-usage-content">
199
+ <div class="empty-state">Loading…</div>
200
+ </div>
201
+ </div>
208
202
 
209
- <div class="section hidden" id="active-followups-section">
210
- <div class="section-header clickable" onclick="toggleSection('active-followups-section')" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
211
- <i data-lucide="refresh-cw"></i> <span id="i18n-section-active-followups"></span>
212
- <span id="active-followups-count" class="badge-count hidden">0</span>
213
- <span class="section-toggle collapsed"><i data-lucide="chevron-down"></i></span>
214
- </div>
215
- <div id="active-followups" class="section-content">
216
- <div class="empty-state" id="i18n-empty-active-followups"></div>
217
- </div>
218
- </div>
203
+ <div class="economics-panel">
204
+ <div class="economics-panel-header">
205
+ <span class="economics-panel-title" id="i18n-economics-monthly-budget"></span>
206
+ </div>
207
+ <div class="economics-panel-body">
208
+ <div id="budget-tile">
209
+ <div class="empty-state">Loading…</div>
210
+ </div>
211
+ <div class="budget-slider-row">
212
+ <label for="budget-slider" id="budget-slider-label">Cap: <span id="budget-slider-value">$200</span></label>
213
+ <input type="range" id="budget-slider" min="0" max="600" step="10" value="200" />
214
+ <button id="budget-slider-submit" type="button">Apply</button>
215
+ <span id="budget-slider-status" class="budget-slider-status"></span>
216
+ </div>
217
+ </div>
218
+ </div>
219
+ </div>
220
+ </div>
219
221
 
220
- <div class="section hidden" id="pending-fix-section">
221
- <div class="section-header">
222
- <i data-lucide="wrench"></i> <span id="i18n-section-pending-fix"></span>
223
- <span id="pending-fix-count" class="badge-count hidden">0</span>
224
- <button id="sync-threads-btn" class="btn-icon btn-sync" onclick="syncGitLabThreads()">
225
- <i data-lucide="refresh-cw"></i>
226
- </button>
227
- </div>
228
- <div id="pending-fix-reviews" class="section-content">
229
- <div class="empty-state" id="i18n-empty-pending-fix"></div>
230
- </div>
231
- </div>
222
+ <div class="section" id="active-reviews-section">
223
+ <div class="section-header">
224
+ <i data-lucide="file-search"></i> <span id="i18n-section-active-reviews"></span>
225
+ <span id="active-reviews-count" class="badge-count hidden">0</span>
226
+ </div>
227
+ <div id="active-reviews" class="section-content">
228
+ <div class="empty-state" id="i18n-empty-active-reviews"></div>
229
+ </div>
230
+ </div>
232
231
 
233
- <div class="section hidden" id="pending-approval-section">
234
- <div class="section-header clickable" onclick="toggleSection('pending-approval-section')" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
235
- <i data-lucide="circle-check"></i> <span id="i18n-section-pending-approval"></span>
236
- <span id="pending-approval-count" class="badge-count hidden">0</span>
237
- <span class="section-toggle collapsed"><i data-lucide="chevron-down"></i></span>
238
- </div>
239
- <div id="pending-approval-reviews" class="section-content">
240
- <div class="empty-state" id="i18n-empty-pending-approval"></div>
241
- </div>
242
- </div>
232
+ <div class="section hidden" id="active-followups-section">
233
+ <div class="section-header clickable" onclick="toggleSection('active-followups-section')" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
234
+ <i data-lucide="refresh-cw"></i> <span id="i18n-section-active-followups"></span>
235
+ <span id="active-followups-count" class="badge-count hidden">0</span>
236
+ <span class="section-toggle collapsed"><i data-lucide="chevron-down"></i></span>
237
+ </div>
238
+ <div id="active-followups" class="section-content">
239
+ <div class="empty-state" id="i18n-empty-active-followups"></div>
240
+ </div>
241
+ </div>
243
242
 
244
- <div class="section" id="completed-reviews-section">
245
- <div class="section-header clickable" onclick="toggleSection('completed-reviews-section')" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
246
- <i data-lucide="file-check"></i> <span id="i18n-section-completed-reviews"></span>
247
- <span class="section-toggle collapsed"><i data-lucide="chevron-down"></i></span>
248
- </div>
249
- <div id="recent-reviews" class="section-content">
250
- <div class="empty-state" id="i18n-empty-loading"></div>
251
- </div>
252
- </div>
243
+ <div class="section hidden" id="pending-fix-section">
244
+ <div class="section-header">
245
+ <i data-lucide="wrench"></i> <span id="i18n-section-pending-fix"></span>
246
+ <span id="pending-fix-count" class="badge-count hidden">0</span>
247
+ <button id="sync-threads-btn" class="btn-icon btn-sync" onclick="syncGitLabThreads()">
248
+ <i data-lucide="refresh-cw"></i>
249
+ </button>
250
+ </div>
251
+ <div id="pending-fix-reviews" class="section-content">
252
+ <div class="empty-state" id="i18n-empty-pending-fix"></div>
253
+ </div>
254
+ </div>
253
255
 
254
- <div class="section" id="cleanup-section">
255
- <div class="section-header">
256
- <i data-lucide="trash-2"></i> <span>Nettoyage</span>
257
- </div>
258
- <div class="section-content" id="cleanup-content"></div>
259
- </div>
256
+ <div class="section hidden" id="pending-approval-section">
257
+ <div class="section-header clickable" onclick="toggleSection('pending-approval-section')" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
258
+ <i data-lucide="circle-check"></i> <span id="i18n-section-pending-approval"></span>
259
+ <span id="pending-approval-count" class="badge-count hidden">0</span>
260
+ <span class="section-toggle collapsed"><i data-lucide="chevron-down"></i></span>
261
+ </div>
262
+ <div id="pending-approval-reviews" class="section-content">
263
+ <div class="empty-state" id="i18n-empty-pending-approval"></div>
264
+ </div>
265
+ </div>
266
+
267
+ <div class="section" id="completed-reviews-section">
268
+ <div class="section-header clickable" onclick="toggleSection('completed-reviews-section')" role="button" tabindex="0" onkeydown="activateOnKeydown(event)">
269
+ <i data-lucide="file-check"></i> <span id="i18n-section-completed-reviews"></span>
270
+ <span class="section-toggle collapsed"><i data-lucide="chevron-down"></i></span>
271
+ </div>
272
+ <div id="recent-reviews" class="section-content">
273
+ <div class="empty-state" id="i18n-empty-loading"></div>
274
+ </div>
275
+ </div>
260
276
 
261
- <section id="worktree-section" aria-label="Worktree pool"></section>
277
+ <div class="section" id="cleanup-section">
278
+ <div class="section-header">
279
+ <i data-lucide="trash-2"></i> <span>Nettoyage</span>
280
+ </div>
281
+ <div class="section-content" id="cleanup-content"></div>
282
+ </div>
262
283
 
263
- <div class="refresh-info">
264
- <span id="connection-mode"></span> • <span id="i18n-connection-fallback"></span>
265
- <span class="refresh-separator"> • </span>
266
- <span id="session-metrics"></span>
284
+ <div class="refresh-info">
285
+ <span id="connection-mode"></span> • <span id="i18n-connection-fallback"></span>
286
+ <span class="refresh-separator"> • </span>
287
+ <span id="session-metrics"></span>
288
+ </div>
289
+ </main>
267
290
  </div>
268
291
  </div>
269
292
 
@@ -313,6 +336,7 @@
313
336
  import { renderDeveloperSheetContent, drawRadarChart } from './modules/developerSheet.js';
314
337
  import { buildInsightsReport } from './modules/insightsReport.js';
315
338
  import { fetchTokenUsageSummary, renderTokenUsageTile } from './modules/tokenUsage.js';
339
+ import { buildPendingReviewsModel, renderPendingReviewsHtml } from './modules/pendingReviews.js';
316
340
  import {
317
341
  renderWorktreeSection,
318
342
  fetchWorktreeOverview,
@@ -337,7 +361,7 @@
337
361
  let reconnectAttempts = 0;
338
362
  let logsVisible = false;
339
363
 
340
- let currentData = { activeReviews: [], recentReviews: [], logs: [], reviewFiles: [], pendingFix: [], pendingApproval: [] };
364
+ let currentData = { activeReviews: [], recentReviews: [], logs: [], reviewFiles: [], pendingFix: [], pendingApproval: [], pendingReviews: [] };
341
365
  const mrDataStore = new Map();
342
366
  let loadedReviews = {};
343
367
  let statsCollapsed = true;
@@ -348,7 +372,7 @@
348
372
  let currentInsightsData = null;
349
373
  const loadingState = { status: 0, reviewFiles: 0, stats: 0, mrTracking: 0 };
350
374
  let hasLoadedStatusOnce = false;
351
- const secondarySections = ['active-followups-section', 'pending-approval-section', 'completed-reviews-section'];
375
+ const secondarySections = ['active-followups-section', 'pending-approval-section', 'completed-reviews-section', 'claude-economics-section'];
352
376
  const sectionExpandedState = Object.fromEntries(secondarySections.map((sectionIdentifier) => [sectionIdentifier, false]));
353
377
  const quietRefreshSections = [
354
378
  'active-reviews-section',
@@ -1801,6 +1825,90 @@
1801
1825
  refreshIcons();
1802
1826
  }
1803
1827
 
1828
+ async function fetchPendingReviews() {
1829
+ try {
1830
+ const response = await fetch(`${API_URL}/api/pending-reviews`);
1831
+ const data = await response.json();
1832
+ currentData.pendingReviews = Array.isArray(data?.pendingReviews) ? data.pendingReviews : [];
1833
+ updatePendingReviewsUI();
1834
+ } catch (error) {
1835
+ console.error('Error fetching pending reviews:', error);
1836
+ }
1837
+ }
1838
+
1839
+ function updatePendingReviewsUI() {
1840
+ const section = document.getElementById('pending-reviews-section');
1841
+ const container = document.getElementById('pending-reviews');
1842
+ const countBadge = document.getElementById('pending-reviews-count');
1843
+ if (!container || !countBadge || !section) return;
1844
+
1845
+ const model = buildPendingReviewsModel(currentData.pendingReviews || []);
1846
+ container.innerHTML = renderPendingReviewsHtml(model);
1847
+
1848
+ if (model.isEmpty) {
1849
+ countBadge.classList.add('hidden');
1850
+ countBadge.textContent = '0';
1851
+ } else {
1852
+ countBadge.textContent = String(model.count);
1853
+ countBadge.classList.remove('hidden');
1854
+ }
1855
+
1856
+ container.querySelectorAll('.btn-confirm-pending').forEach((btn) => {
1857
+ const pendingId = btn.getAttribute('data-pending-id');
1858
+ if (!pendingId) return;
1859
+ btn.addEventListener('click', () => confirmPendingReview(pendingId), { once: true });
1860
+ });
1861
+ container.querySelectorAll('.btn-dismiss-pending').forEach((btn) => {
1862
+ const pendingId = btn.getAttribute('data-pending-id');
1863
+ if (!pendingId) return;
1864
+ btn.addEventListener('click', () => dismissPendingReview(pendingId), { once: true });
1865
+ });
1866
+
1867
+ refreshIcons();
1868
+ }
1869
+
1870
+ async function confirmPendingReview(pendingId) {
1871
+ try {
1872
+ const response = await fetch(`${API_URL}/api/pending-reviews/${encodeURIComponent(pendingId)}/confirm`, {
1873
+ method: 'POST',
1874
+ });
1875
+ const data = await response.json();
1876
+ if (response.ok) {
1877
+ showToast('Review confirmée', 'info');
1878
+ } else if (data?.message) {
1879
+ showToast(data.message, 'error');
1880
+ } else {
1881
+ showToast('Erreur lors de la confirmation', 'error');
1882
+ }
1883
+ } catch (error) {
1884
+ console.error('Error confirming pending review:', error);
1885
+ showToast('Erreur lors de la confirmation', 'error');
1886
+ } finally {
1887
+ await fetchPendingReviews();
1888
+ }
1889
+ }
1890
+
1891
+ async function dismissPendingReview(pendingId) {
1892
+ try {
1893
+ const response = await fetch(`${API_URL}/api/pending-reviews/${encodeURIComponent(pendingId)}`, {
1894
+ method: 'DELETE',
1895
+ });
1896
+ const data = await response.json();
1897
+ if (response.ok) {
1898
+ showToast('Review ignorée', 'info');
1899
+ } else if (data?.message) {
1900
+ showToast(data.message, 'error');
1901
+ } else {
1902
+ showToast('Erreur lors du rejet', 'error');
1903
+ }
1904
+ } catch (error) {
1905
+ console.error('Error dismissing pending review:', error);
1906
+ showToast('Erreur lors du rejet', 'error');
1907
+ } finally {
1908
+ await fetchPendingReviews();
1909
+ }
1910
+ }
1911
+
1804
1912
  async function fetchMrTracking() {
1805
1913
  setLoadingFlag('mrTracking', true);
1806
1914
  if (!currentProjectPath) {
@@ -2027,6 +2135,9 @@
2027
2135
  }
2028
2136
  break;
2029
2137
  }
2138
+ case 'pending-changed':
2139
+ fetchPendingReviews();
2140
+ break;
2030
2141
  case 'pong':
2031
2142
  break;
2032
2143
  }
@@ -2273,7 +2384,6 @@
2273
2384
 
2274
2385
  document.getElementById('stats-section').classList.remove('hidden');
2275
2386
  document.getElementById('team-section').classList.remove('hidden');
2276
- document.getElementById('token-usage-section').classList.remove('hidden');
2277
2387
 
2278
2388
  const platformIcon = activePlatform === 'gitlab' ? '<i data-lucide="gitlab"></i> GitLab' : '<i data-lucide="github"></i> GitHub';
2279
2389
  info.innerHTML = `
@@ -2537,6 +2647,9 @@
2537
2647
  const sectionTeam = document.getElementById('i18n-section-team');
2538
2648
  if (sectionTeam) sectionTeam.textContent = t('team.title');
2539
2649
 
2650
+ const sectionPendingReviews = document.getElementById('i18n-section-pending-reviews');
2651
+ if (sectionPendingReviews) sectionPendingReviews.textContent = t('section.pendingReviews');
2652
+
2540
2653
  const sectionActiveReviews = document.getElementById('i18n-section-active-reviews');
2541
2654
  if (sectionActiveReviews) sectionActiveReviews.textContent = t('section.activeReviews');
2542
2655
 
@@ -2552,6 +2665,15 @@
2552
2665
  const sectionCompletedReviews = document.getElementById('i18n-section-completed-reviews');
2553
2666
  if (sectionCompletedReviews) sectionCompletedReviews.textContent = t('section.completedReviews');
2554
2667
 
2668
+ const sectionClaudeEconomics = document.getElementById('i18n-section-claude-economics');
2669
+ if (sectionClaudeEconomics) sectionClaudeEconomics.textContent = t('section.claudeEconomics');
2670
+
2671
+ const economicsTokenUsage = document.getElementById('i18n-economics-token-usage');
2672
+ if (economicsTokenUsage) economicsTokenUsage.textContent = t('economics.tokenUsage');
2673
+
2674
+ const economicsMonthlyBudget = document.getElementById('i18n-economics-monthly-budget');
2675
+ if (economicsMonthlyBudget) economicsMonthlyBudget.textContent = t('economics.monthlyBudget');
2676
+
2555
2677
  // Empty states
2556
2678
  const emptyLogs = document.getElementById('i18n-empty-logs');
2557
2679
  if (emptyLogs) emptyLogs.textContent = t('empty.logs');
@@ -2559,6 +2681,9 @@
2559
2681
  const emptyStats = document.getElementById('i18n-empty-stats');
2560
2682
  if (emptyStats) emptyStats.textContent = t('empty.stats');
2561
2683
 
2684
+ const emptyPendingReviews = document.getElementById('i18n-empty-pending-reviews');
2685
+ if (emptyPendingReviews) emptyPendingReviews.textContent = t('empty.pendingReviews');
2686
+
2562
2687
  const emptyActiveReviews = document.getElementById('i18n-empty-active-reviews');
2563
2688
  if (emptyActiveReviews) emptyActiveReviews.textContent = t('empty.activeReviews');
2564
2689
 
@@ -2813,9 +2938,12 @@
2813
2938
  fetchReviewFiles();
2814
2939
  fetchProjectStats();
2815
2940
  fetchMrTracking();
2941
+ fetchPendingReviews();
2816
2942
  fetchTeamInsights();
2817
2943
  }, 30000);
2818
2944
 
2945
+ fetchPendingReviews();
2946
+
2819
2947
  setInterval(() => {
2820
2948
  document.querySelectorAll('.review-item').forEach(el => {
2821
2949
  const jobId = el.dataset.jobId;
@@ -1 +1 @@
1
- {"version":3,"file":"budgetSettings.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/budgetSettings.js"],"names":[],"mappings":"AAoDA;;;;;GAKG;AACH,4CAHW,qBAAqB,GACnB,MAAM,CA0BlB;AAED;;;;;;GAMG;AACH,kDAHW,OAAO,GACL,qBAAqB,GAAG,IAAI,CASxC;AAED;;;;;;GAMG;AACH,oDAHW,OAAO,GACL,qBAAqB,GAAG,IAAI,CASxC;AAED;;;;;GAKG;AACH,wCAHW,OAAO,KAAK,GACV,OAAO,CAAC,qBAAqB,CAAC,CAQ1C;AAED;;;;;GAKG;AACH,8CAHW,OAAO,KAAK,GACV,OAAO,CAAC,qBAAqB,CAAC,CAQ1C;AAED;;;;;;GAMG;AACH,uCAJW,MAAM,cACN,OAAO,KAAK,GACV,OAAO,CAAC,kBAAkB,CAAC,CASvC;;uBAtJa,MAAM;0BACN,MAAM;2BACN,MAAM;0BACN,MAAM;uBACN,MAAM;cACN,OAAO;iBACP,MAAM;;;cAKN,MAAM;cACN,QAAQ,GAAC,QAAQ;iBACjB,MAAM;cACN,MAAM;iBACN,MAAM;;;cAKN,MAAM;;;aAKN,OAAO"}
1
+ {"version":3,"file":"budgetSettings.d.ts","sourceRoot":"","sources":["../../../src/dashboard/modules/budgetSettings.js"],"names":[],"mappings":"AAoDA;;;;;GAKG;AACH,4CAHW,qBAAqB,GACnB,MAAM,CAwBlB;AAED;;;;;;GAMG;AACH,kDAHW,OAAO,GACL,qBAAqB,GAAG,IAAI,CASxC;AAED;;;;;;GAMG;AACH,oDAHW,OAAO,GACL,qBAAqB,GAAG,IAAI,CASxC;AAED;;;;;GAKG;AACH,wCAHW,OAAO,KAAK,GACV,OAAO,CAAC,qBAAqB,CAAC,CAQ1C;AAED;;;;;GAKG;AACH,8CAHW,OAAO,KAAK,GACV,OAAO,CAAC,qBAAqB,CAAC,CAQ1C;AAED;;;;;;GAMG;AACH,uCAJW,MAAM,cACN,OAAO,KAAK,GACV,OAAO,CAAC,kBAAkB,CAAC,CASvC;;uBApJa,MAAM;0BACN,MAAM;2BACN,MAAM;0BACN,MAAM;uBACN,MAAM;cACN,OAAO;iBACP,MAAM;;;cAKN,MAAM;cACN,QAAQ,GAAC,QAAQ;iBACjB,MAAM;cACN,MAAM;iBACN,MAAM;;;cAKN,MAAM;;;aAKN,OAAO"}
@@ -61,13 +61,11 @@ export function renderBudgetTile(viewModel) {
61
61
  ? '<span class="budget-tile-badge budget-tile-badge--exceeded">Budget exceeded</span>'
62
62
  : '';
63
63
  const gaugeClass = viewModel.exceeded ? 'budget-gauge-fill budget-gauge-fill--exceeded' : 'budget-gauge-fill';
64
+ const headerSection = viewModel.exceeded ? `<div class="budget-tile-header">${exceededBadge}</div>` : '';
64
65
 
65
66
  return `
66
67
  <div class="budget-tile">
67
- <div class="budget-tile-header">
68
- <span class="budget-tile-title">Monthly Claude budget</span>
69
- ${exceededBadge}
70
- </div>
68
+ ${headerSection}
71
69
  <div class="budget-tile-figures">
72
70
  <span class="budget-tile-consumed">${escapeHtml(viewModel.consumedUsdFormatted)}</span>
73
71
  <span class="budget-tile-separator">/</span>