reviewflow 3.20.0 → 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.
- package/CHANGELOG.md +7 -0
- package/dist/config/projectConfig.d.ts +7 -0
- package/dist/config/projectConfig.d.ts.map +1 -1
- package/dist/config/projectConfig.js +18 -0
- package/dist/config/projectConfig.js.map +1 -1
- package/dist/dashboard/index.html +374 -137
- package/dist/dashboard/modules/cardCounters.d.ts +32 -0
- package/dist/dashboard/modules/cardCounters.d.ts.map +1 -0
- package/dist/dashboard/modules/cardCounters.js +40 -0
- package/dist/dashboard/modules/cardCounters.js.map +1 -0
- package/dist/dashboard/modules/managePanel.d.ts +49 -0
- package/dist/dashboard/modules/managePanel.d.ts.map +1 -0
- package/dist/dashboard/modules/managePanel.js +123 -0
- package/dist/dashboard/modules/managePanel.js.map +1 -0
- package/dist/dashboard/modules/overview.d.ts +1 -0
- package/dist/dashboard/modules/overview.d.ts.map +1 -1
- package/dist/dashboard/modules/overview.js +14 -0
- package/dist/dashboard/modules/overview.js.map +1 -1
- package/dist/dashboard/modules/settingsModal.d.ts +77 -0
- package/dist/dashboard/modules/settingsModal.d.ts.map +1 -0
- package/dist/dashboard/modules/settingsModal.js +182 -0
- package/dist/dashboard/modules/settingsModal.js.map +1 -0
- package/dist/dashboard/modules/tabBar.d.ts +4 -0
- package/dist/dashboard/modules/tabBar.d.ts.map +1 -1
- package/dist/dashboard/modules/tabBar.js +6 -1
- package/dist/dashboard/modules/tabBar.js.map +1 -1
- package/dist/dashboard/styles.css +612 -0
- package/dist/frameworks/config/configLoader.d.ts +8 -0
- package/dist/frameworks/config/configLoader.d.ts.map +1 -1
- package/dist/frameworks/config/configLoader.js +18 -0
- package/dist/frameworks/config/configLoader.js.map +1 -1
- package/dist/main/routes.d.ts.map +1 -1
- package/dist/main/routes.js +47 -2
- package/dist/main/routes.js.map +1 -1
- package/dist/modules/cli-configuration/entities/projectConfig/projectConfig.gateway.d.ts +20 -0
- package/dist/modules/cli-configuration/entities/projectConfig/projectConfig.gateway.d.ts.map +1 -0
- package/dist/modules/cli-configuration/entities/projectConfig/projectConfig.gateway.js +2 -0
- package/dist/modules/cli-configuration/entities/projectConfig/projectConfig.gateway.js.map +1 -0
- package/dist/modules/cli-configuration/entities/repositoryEntry/repositoryEntry.d.ts +13 -0
- package/dist/modules/cli-configuration/entities/repositoryEntry/repositoryEntry.d.ts.map +1 -0
- package/dist/modules/cli-configuration/entities/repositoryEntry/repositoryEntry.js +2 -0
- package/dist/modules/cli-configuration/entities/repositoryEntry/repositoryEntry.js.map +1 -0
- package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.d.ts +6 -1
- package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.d.ts.map +1 -1
- package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.js +116 -13
- package/dist/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.js.map +1 -1
- package/dist/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.d.ts +36 -0
- package/dist/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.d.ts.map +1 -1
- package/dist/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.js +77 -8
- package/dist/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.js.map +1 -1
- package/dist/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.d.ts +7 -0
- package/dist/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.d.ts.map +1 -0
- package/dist/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.js +48 -0
- package/dist/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.js.map +1 -0
- package/dist/modules/cli-configuration/usecases/cli/addRepositoriesToConfig.usecase.d.ts +1 -6
- package/dist/modules/cli-configuration/usecases/cli/addRepositoriesToConfig.usecase.d.ts.map +1 -1
- package/dist/modules/cli-configuration/usecases/cli/addRepositoriesToConfig.usecase.js.map +1 -1
- package/dist/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.d.ts +21 -0
- package/dist/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.d.ts.map +1 -0
- package/dist/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.js +27 -0
- package/dist/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.js.map +1 -0
- package/dist/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.d.ts +22 -0
- package/dist/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.d.ts.map +1 -0
- package/dist/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.js +27 -0
- package/dist/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.js.map +1 -0
- package/dist/modules/cli-configuration/usecases/cli/writeInitConfig.usecase.d.ts +1 -6
- package/dist/modules/cli-configuration/usecases/cli/writeInitConfig.usecase.d.ts.map +1 -1
- package/dist/modules/cli-configuration/usecases/cli/writeInitConfig.usecase.js.map +1 -1
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/addRepositoryFromDashboard.usecase.d.ts +19 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/addRepositoryFromDashboard.usecase.d.ts.map +1 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/addRepositoryFromDashboard.usecase.js +30 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/addRepositoryFromDashboard.usecase.js.map +1 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/removeRepositoryFromDashboard.usecase.d.ts +16 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/removeRepositoryFromDashboard.usecase.d.ts.map +1 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/removeRepositoryFromDashboard.usecase.js +27 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/removeRepositoryFromDashboard.usecase.js.map +1 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/updateRepositoryEnabledFromDashboard.usecase.d.ts +17 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/updateRepositoryEnabledFromDashboard.usecase.d.ts.map +1 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/updateRepositoryEnabledFromDashboard.usecase.js +28 -0
- package/dist/modules/cli-configuration/usecases/dashboardRepositories/updateRepositoryEnabledFromDashboard.usecase.js.map +1 -0
- package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.d.ts +31 -0
- package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.d.ts.map +1 -0
- package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.js +102 -0
- package/dist/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.js.map +1 -0
- package/dist/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.d.ts +2 -0
- package/dist/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.d.ts.map +1 -1
- package/dist/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.js +14 -0
- package/dist/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.js.map +1 -1
- package/dist/modules/statistics-insights/interface-adapters/presenters/overview.presenter.d.ts +5 -0
- package/dist/modules/statistics-insights/interface-adapters/presenters/overview.presenter.d.ts.map +1 -1
- package/dist/modules/statistics-insights/interface-adapters/presenters/overview.presenter.js +20 -4
- package/dist/modules/statistics-insights/interface-adapters/presenters/overview.presenter.js.map +1 -1
- package/dist/tests/acceptance/177-dashboard-add-project-ui.acceptance.test.d.ts +12 -0
- package/dist/tests/acceptance/177-dashboard-add-project-ui.acceptance.test.d.ts.map +1 -0
- package/dist/tests/acceptance/177-dashboard-add-project-ui.acceptance.test.js +304 -0
- package/dist/tests/acceptance/177-dashboard-add-project-ui.acceptance.test.js.map +1 -0
- package/dist/tests/acceptance/178-dashboard-tabs-reposition.acceptance.test.d.ts +12 -0
- package/dist/tests/acceptance/178-dashboard-tabs-reposition.acceptance.test.d.ts.map +1 -0
- package/dist/tests/acceptance/178-dashboard-tabs-reposition.acceptance.test.js +131 -0
- package/dist/tests/acceptance/178-dashboard-tabs-reposition.acceptance.test.js.map +1 -0
- package/dist/tests/acceptance/179-dashboard-project-settings-modal.acceptance.test.d.ts +12 -0
- package/dist/tests/acceptance/179-dashboard-project-settings-modal.acceptance.test.d.ts.map +1 -0
- package/dist/tests/acceptance/179-dashboard-project-settings-modal.acceptance.test.js +312 -0
- package/dist/tests/acceptance/179-dashboard-project-settings-modal.acceptance.test.js.map +1 -0
- package/dist/tests/acceptance/91-dashboard-multi-project-overview.acceptance.test.js +3 -0
- package/dist/tests/acceptance/91-dashboard-multi-project-overview.acceptance.test.js.map +1 -1
- package/dist/tests/stubs/projectConfigGateway.stub.d.ts +15 -0
- package/dist/tests/stubs/projectConfigGateway.stub.d.ts.map +1 -0
- package/dist/tests/stubs/projectConfigGateway.stub.js +40 -0
- package/dist/tests/stubs/projectConfigGateway.stub.js.map +1 -0
- package/dist/tests/units/config/projectConfig.test.js +43 -0
- package/dist/tests/units/config/projectConfig.test.js.map +1 -1
- package/dist/tests/units/dashboard/modules/cardCounters.test.d.ts +2 -0
- package/dist/tests/units/dashboard/modules/cardCounters.test.d.ts.map +1 -0
- package/dist/tests/units/dashboard/modules/cardCounters.test.js +106 -0
- package/dist/tests/units/dashboard/modules/cardCounters.test.js.map +1 -0
- package/dist/tests/units/dashboard/modules/managePanel.test.d.ts +2 -0
- package/dist/tests/units/dashboard/modules/managePanel.test.d.ts.map +1 -0
- package/dist/tests/units/dashboard/modules/managePanel.test.js +112 -0
- package/dist/tests/units/dashboard/modules/managePanel.test.js.map +1 -0
- package/dist/tests/units/dashboard/modules/overview.test.js +92 -0
- package/dist/tests/units/dashboard/modules/overview.test.js.map +1 -1
- package/dist/tests/units/dashboard/modules/settingsModal.test.d.ts +2 -0
- package/dist/tests/units/dashboard/modules/settingsModal.test.d.ts.map +1 -0
- package/dist/tests/units/dashboard/modules/settingsModal.test.js +166 -0
- package/dist/tests/units/dashboard/modules/settingsModal.test.js.map +1 -0
- package/dist/tests/units/dashboard/modules/tabBar.test.js +40 -11
- package/dist/tests/units/dashboard/modules/tabBar.test.js.map +1 -1
- package/dist/tests/units/frameworks/config/configLoader.test.js +35 -1
- package/dist/tests/units/frameworks/config/configLoader.test.js.map +1 -1
- package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.js +111 -0
- package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/projectConfig.routes.test.js.map +1 -1
- package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.test.js +243 -2
- package/dist/tests/units/modules/cli-configuration/interface-adapters/controllers/http/repositories.routes.test.js.map +1 -1
- package/dist/tests/units/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.test.d.ts +2 -0
- package/dist/tests/units/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.test.d.ts.map +1 -0
- package/dist/tests/units/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.test.js +72 -0
- package/dist/tests/units/modules/cli-configuration/interface-adapters/gateways/projectConfig.fileSystem.gateway.test.js.map +1 -0
- package/dist/tests/units/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.test.d.ts +2 -0
- package/dist/tests/units/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.test.d.ts.map +1 -0
- package/dist/tests/units/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.test.js +76 -0
- package/dist/tests/units/modules/cli-configuration/usecases/cli/removeRepositoryFromConfig.usecase.test.js.map +1 -0
- package/dist/tests/units/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.test.d.ts +2 -0
- package/dist/tests/units/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.test.d.ts.map +1 -0
- package/dist/tests/units/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.test.js +84 -0
- package/dist/tests/units/modules/cli-configuration/usecases/cli/toggleRepositoryEnabled.usecase.test.js.map +1 -0
- package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.d.ts +2 -0
- package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.d.ts.map +1 -0
- package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.js +141 -0
- package/dist/tests/units/modules/cli-configuration/usecases/projectConfig/updateProjectConfig.usecase.test.js.map +1 -0
- package/dist/tests/units/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.test.js +44 -0
- package/dist/tests/units/modules/statistics-insights/interface-adapters/controllers/http/overview.routes.test.js.map +1 -1
- package/dist/tests/units/modules/statistics-insights/interface-adapters/presenters/overview.presenter.test.js +42 -0
- package/dist/tests/units/modules/statistics-insights/interface-adapters/presenters/overview.presenter.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -30,6 +30,20 @@
|
|
|
30
30
|
</div>
|
|
31
31
|
</header>
|
|
32
32
|
|
|
33
|
+
<div class="project-bar" role="region" aria-label="Project navigation">
|
|
34
|
+
<button type="button" id="manage-projects-toggle" class="manage-projects-toggle" aria-expanded="false" aria-controls="manage-panel">
|
|
35
|
+
<span class="manage-projects-toggle-label">// MANAGE PROJECTS</span>
|
|
36
|
+
<i data-lucide="chevron-down" class="manage-projects-toggle-icon"></i>
|
|
37
|
+
</button>
|
|
38
|
+
<section id="manage-panel" class="manage-panel" aria-label="Manage projects" data-open="false"></section>
|
|
39
|
+
<nav id="dashboard-tabs" class="dashboard-tab-bar-wrapper" aria-label="Project tabs"></nav>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div id="cards-scope-marker" class="cards-scope-marker" data-scope-kind="overview">
|
|
43
|
+
<span class="cards-scope-prefix">// SCOPE</span>
|
|
44
|
+
<span class="cards-scope-label">TOUS LES PROJETS</span>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
33
47
|
<div class="cards">
|
|
34
48
|
<div class="card card-priority">
|
|
35
49
|
<div class="card-label" id="i18n-card-running"></div>
|
|
@@ -78,7 +92,6 @@
|
|
|
78
92
|
</select>
|
|
79
93
|
</div>
|
|
80
94
|
|
|
81
|
-
<nav id="dashboard-tabs" class="dashboard-tab-bar-wrapper" aria-label="Project tabs"></nav>
|
|
82
95
|
<span id="config-status" class="config-status hidden"></span>
|
|
83
96
|
|
|
84
97
|
<div class="focus-strip">
|
|
@@ -107,6 +120,10 @@
|
|
|
107
120
|
</div>
|
|
108
121
|
|
|
109
122
|
<section id="worktree-section" aria-label="Worktree pool"></section>
|
|
123
|
+
|
|
124
|
+
<button type="button" id="open-settings-modal-btn" class="sidebar-settings-button" hidden>
|
|
125
|
+
<span class="sidebar-settings-button__prefix">// SETTINGS</span>
|
|
126
|
+
</button>
|
|
110
127
|
</aside>
|
|
111
128
|
|
|
112
129
|
<main class="dashboard-main">
|
|
@@ -304,16 +321,20 @@
|
|
|
304
321
|
<div id="dev-sheet-content" class="sheet-content"></div>
|
|
305
322
|
</div>
|
|
306
323
|
|
|
324
|
+
<dialog id="settings-modal" class="settings-modal" aria-labelledby="settings-modal-title"></dialog>
|
|
325
|
+
|
|
307
326
|
<script type="module">
|
|
308
327
|
import { t, setLanguage, getLanguage } from './modules/i18n.js';
|
|
309
328
|
import { formatTime, formatDuration, formatPhase, formatLogTime } from './modules/formatting.js';
|
|
310
329
|
import { escapeHtml, markdownToHtml, sanitizeHttpUrl } from './modules/html.js';
|
|
311
330
|
import { getAgentIcon, icon, refreshIcons } from './modules/icons.js';
|
|
312
|
-
import { MAX_RECONNECT_ATTEMPTS, RECONNECT_DELAY,
|
|
331
|
+
import { MAX_RECONNECT_ATTEMPTS, RECONNECT_DELAY, STORAGE_KEY_CURRENT, STORAGE_KEY_FOCUS_STRIP_MODE, QUALITY_TARGET_SCORE } from './modules/constants.js';
|
|
313
332
|
import { buildTabBarModel, renderTabBarHtml, readActiveTab, writeActiveTab } from './modules/tabBar.js';
|
|
333
|
+
import { buildManagePanelModel, renderManagePanelHtml, buildOptimisticAddedRow, validateLocalPathInput } from './modules/managePanel.js';
|
|
314
334
|
import { renderOverviewHtml } from './modules/overview.js';
|
|
315
335
|
import { getDesktopNotificationPayload, shouldNotifyDesktop } from './modules/desktopNotifications.js';
|
|
316
336
|
import { getLoadingPresentation, getQuietRefreshSectionIdentifiers } from './modules/loading.js';
|
|
337
|
+
import { computeCardCounters } from './modules/cardCounters.js';
|
|
317
338
|
import { collectReviewNotifications, createReviewNotificationState } from './modules/notifications.js';
|
|
318
339
|
import { resolveReviewAssigneeDisplay } from './modules/assignee.js';
|
|
319
340
|
import { buildQueueLanesModel } from './modules/queueLanes.js';
|
|
@@ -345,6 +366,12 @@
|
|
|
345
366
|
fetchBudgetStatus,
|
|
346
367
|
submitBudget,
|
|
347
368
|
} from './modules/budgetSettings.js';
|
|
369
|
+
import {
|
|
370
|
+
buildSettingsViewModel,
|
|
371
|
+
renderSettingsModalHtml,
|
|
372
|
+
validateExternalLink,
|
|
373
|
+
extractFormPayload,
|
|
374
|
+
} from './modules/settingsModal.js';
|
|
348
375
|
|
|
349
376
|
const API_URL = window.location.origin;
|
|
350
377
|
const WS_URL = `ws://${window.location.host}/ws`;
|
|
@@ -767,14 +794,12 @@
|
|
|
767
794
|
const reviews = currentData.activeReviews.filter(r => r.jobType !== 'followup');
|
|
768
795
|
const followups = currentData.activeReviews.filter(r => r.jobType === 'followup');
|
|
769
796
|
|
|
797
|
+
renderCardCounters();
|
|
798
|
+
const blocked = currentData.pendingFix.length;
|
|
770
799
|
const running = currentData.activeReviews.filter(r => r.status === 'running').length;
|
|
771
800
|
const queued = currentData.activeReviews.filter(r => r.status === 'queued').length;
|
|
772
|
-
const blocked = currentData.pendingFix.length;
|
|
773
801
|
const nowCount = running + blocked;
|
|
774
802
|
const nextCount = queued + currentData.pendingApproval.length;
|
|
775
|
-
document.getElementById('running-count').textContent = running;
|
|
776
|
-
document.getElementById('queued-count').textContent = queued;
|
|
777
|
-
document.getElementById('completed-count').textContent = currentData.reviewFiles.length;
|
|
778
803
|
document.getElementById('focus-now-count').textContent = String(nowCount);
|
|
779
804
|
document.getElementById('focus-next-count').textContent = String(nextCount);
|
|
780
805
|
document.getElementById('focus-blocked-count').textContent = String(blocked);
|
|
@@ -2273,71 +2298,6 @@
|
|
|
2273
2298
|
let currentProjectConfig = null;
|
|
2274
2299
|
let currentProjectPath = null;
|
|
2275
2300
|
|
|
2276
|
-
function getStoredProjects() {
|
|
2277
|
-
try {
|
|
2278
|
-
return JSON.parse(localStorage.getItem(STORAGE_KEY_PROJECTS) || '[]');
|
|
2279
|
-
} catch {
|
|
2280
|
-
return [];
|
|
2281
|
-
}
|
|
2282
|
-
}
|
|
2283
|
-
|
|
2284
|
-
function saveProjects(projects) {
|
|
2285
|
-
localStorage.setItem(STORAGE_KEY_PROJECTS, JSON.stringify(projects));
|
|
2286
|
-
}
|
|
2287
|
-
|
|
2288
|
-
function addProjectToHistory(path) {
|
|
2289
|
-
const projects = getStoredProjects();
|
|
2290
|
-
const filtered = projects.filter(p => p !== path);
|
|
2291
|
-
filtered.unshift(path);
|
|
2292
|
-
saveProjects(filtered.slice(0, 10));
|
|
2293
|
-
updateProjectSelect();
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
|
-
function removeProjectFromHistory(path) {
|
|
2297
|
-
const projects = getStoredProjects().filter(p => p !== path);
|
|
2298
|
-
saveProjects(projects);
|
|
2299
|
-
updateProjectSelect();
|
|
2300
|
-
}
|
|
2301
|
-
|
|
2302
|
-
function updateProjectSelect() {
|
|
2303
|
-
const select = document.getElementById('project-select');
|
|
2304
|
-
if (!select) return;
|
|
2305
|
-
const projects = getStoredProjects();
|
|
2306
|
-
const current = localStorage.getItem(STORAGE_KEY_CURRENT) || '';
|
|
2307
|
-
|
|
2308
|
-
select.innerHTML = `<option value="">${t('project.selectPlaceholder')}</option>`;
|
|
2309
|
-
for (const path of projects) {
|
|
2310
|
-
const shortName = path.split('/').slice(-2).join('/');
|
|
2311
|
-
const option = document.createElement('option');
|
|
2312
|
-
option.value = path;
|
|
2313
|
-
option.textContent = shortName;
|
|
2314
|
-
option.title = path;
|
|
2315
|
-
if (path === current) option.selected = true;
|
|
2316
|
-
select.appendChild(option);
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
|
-
function onProjectSelect(path) {
|
|
2321
|
-
if (path) {
|
|
2322
|
-
const input = document.getElementById('project-path-input');
|
|
2323
|
-
if (input) input.value = '';
|
|
2324
|
-
loadProjectConfigFromPath(path);
|
|
2325
|
-
}
|
|
2326
|
-
}
|
|
2327
|
-
|
|
2328
|
-
async function loadProjectConfig() {
|
|
2329
|
-
const input = document.getElementById('project-path-input');
|
|
2330
|
-
const select = document.getElementById('project-select');
|
|
2331
|
-
const projectPath = (input?.value.trim() ?? '') || (select?.value ?? '');
|
|
2332
|
-
|
|
2333
|
-
if (!projectPath) {
|
|
2334
|
-
showConfigStatus(t('error.selectOrEnterPath'), 'error');
|
|
2335
|
-
return;
|
|
2336
|
-
}
|
|
2337
|
-
|
|
2338
|
-
await loadProjectConfigFromPath(projectPath);
|
|
2339
|
-
}
|
|
2340
|
-
|
|
2341
2301
|
async function loadProjectConfigFromPath(projectPath) {
|
|
2342
2302
|
const status = document.getElementById('config-status');
|
|
2343
2303
|
const info = document.getElementById('config-info');
|
|
@@ -2353,14 +2313,8 @@
|
|
|
2353
2313
|
currentProjectConfig = data.config;
|
|
2354
2314
|
currentProjectPath = projectPath;
|
|
2355
2315
|
|
|
2356
|
-
addProjectToHistory(projectPath);
|
|
2357
2316
|
localStorage.setItem(STORAGE_KEY_CURRENT, projectPath);
|
|
2358
2317
|
|
|
2359
|
-
const legacySelect = document.getElementById('project-select');
|
|
2360
|
-
if (legacySelect) legacySelect.value = projectPath;
|
|
2361
|
-
const legacyInput = document.getElementById('project-path-input');
|
|
2362
|
-
if (legacyInput) legacyInput.value = '';
|
|
2363
|
-
|
|
2364
2318
|
const shortName = projectPath.split('/').slice(-2).join('/');
|
|
2365
2319
|
showConfigStatus(`<i data-lucide="check-circle"></i> ${escapeHtml(shortName)}`, 'success');
|
|
2366
2320
|
refreshIcons();
|
|
@@ -2413,43 +2367,6 @@
|
|
|
2413
2367
|
refreshIcons();
|
|
2414
2368
|
}
|
|
2415
2369
|
|
|
2416
|
-
function removeCurrentProject() {
|
|
2417
|
-
const select = document.getElementById('project-select');
|
|
2418
|
-
const path = select?.value ?? currentProjectPath ?? '';
|
|
2419
|
-
if (!path) {
|
|
2420
|
-
showConfigStatus(t('project.noProjectSelected'), 'error');
|
|
2421
|
-
return;
|
|
2422
|
-
}
|
|
2423
|
-
const shortName = path.split('/').slice(-2).join('/');
|
|
2424
|
-
if (confirm(t('confirm.removeProject', { name: shortName }))) {
|
|
2425
|
-
removeProjectFromHistory(path);
|
|
2426
|
-
localStorage.removeItem(STORAGE_KEY_CURRENT);
|
|
2427
|
-
currentProjectPath = null;
|
|
2428
|
-
currentProjectConfig = null;
|
|
2429
|
-
document.getElementById('config-info')?.classList.add('hidden');
|
|
2430
|
-
showConfigStatus(t('project.removed'), 'success');
|
|
2431
|
-
}
|
|
2432
|
-
}
|
|
2433
|
-
|
|
2434
|
-
async function syncServerRepositories() {
|
|
2435
|
-
try {
|
|
2436
|
-
const response = await fetch(`${API_URL}/api/repositories`);
|
|
2437
|
-
const data = await response.json();
|
|
2438
|
-
if (!data.repositories) return;
|
|
2439
|
-
|
|
2440
|
-
const stored = getStoredProjects();
|
|
2441
|
-
for (const repository of data.repositories) {
|
|
2442
|
-
if (repository.enabled && !stored.includes(repository.localPath)) {
|
|
2443
|
-
stored.push(repository.localPath);
|
|
2444
|
-
}
|
|
2445
|
-
}
|
|
2446
|
-
saveProjects(stored);
|
|
2447
|
-
updateProjectSelect();
|
|
2448
|
-
} catch {
|
|
2449
|
-
// Server unreachable — use localStorage only
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
|
|
2453
2370
|
// SPEC-91 — Dashboard Multi-Project Overview
|
|
2454
2371
|
let availableRepositories = [];
|
|
2455
2372
|
let activeTabId = 'overview';
|
|
@@ -2458,14 +2375,44 @@
|
|
|
2458
2375
|
try {
|
|
2459
2376
|
const response = await fetch(`${API_URL}/api/repositories`);
|
|
2460
2377
|
const data = await response.json();
|
|
2461
|
-
availableRepositories = Array.isArray(data.repositories)
|
|
2462
|
-
? data.repositories.filter((repository) => repository.enabled)
|
|
2463
|
-
: [];
|
|
2378
|
+
availableRepositories = Array.isArray(data.repositories) ? data.repositories : [];
|
|
2464
2379
|
} catch {
|
|
2465
2380
|
availableRepositories = [];
|
|
2466
2381
|
}
|
|
2467
2382
|
}
|
|
2468
2383
|
|
|
2384
|
+
function syncAvailableRepositoriesFromResponse(payload) {
|
|
2385
|
+
availableRepositories = Array.isArray(payload?.repositories) ? payload.repositories : [];
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
function renderCardCounters() {
|
|
2389
|
+
let scope;
|
|
2390
|
+
if (activeTabId === 'overview') {
|
|
2391
|
+
scope = { kind: 'overview' };
|
|
2392
|
+
} else {
|
|
2393
|
+
const repository = availableRepositories.find((r) => r.localPath === activeTabId);
|
|
2394
|
+
const projectName = repository?.name ?? activeTabId.split('/').filter(Boolean).pop() ?? activeTabId;
|
|
2395
|
+
scope = { kind: 'project', localPath: activeTabId, projectName };
|
|
2396
|
+
}
|
|
2397
|
+
const counters = computeCardCounters({
|
|
2398
|
+
activeReviews: currentData.activeReviews,
|
|
2399
|
+
reviewFiles: currentData.reviewFiles,
|
|
2400
|
+
scope,
|
|
2401
|
+
});
|
|
2402
|
+
const runningEl = document.getElementById('running-count');
|
|
2403
|
+
const queuedEl = document.getElementById('queued-count');
|
|
2404
|
+
const completedEl = document.getElementById('completed-count');
|
|
2405
|
+
if (runningEl) runningEl.textContent = counters.running;
|
|
2406
|
+
if (queuedEl) queuedEl.textContent = counters.queued;
|
|
2407
|
+
if (completedEl) completedEl.textContent = counters.completed;
|
|
2408
|
+
const markerEl = document.getElementById('cards-scope-marker');
|
|
2409
|
+
if (markerEl) {
|
|
2410
|
+
markerEl.dataset.scopeKind = counters.markerKind;
|
|
2411
|
+
const labelEl = markerEl.querySelector('.cards-scope-label');
|
|
2412
|
+
if (labelEl) labelEl.textContent = counters.markerLabel;
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2469
2416
|
function renderDashboardTabs() {
|
|
2470
2417
|
const container = document.getElementById('dashboard-tabs');
|
|
2471
2418
|
if (!container) return;
|
|
@@ -2498,6 +2445,8 @@
|
|
|
2498
2445
|
const overviewSection = document.getElementById('overview-section');
|
|
2499
2446
|
if (overviewSection) overviewSection.classList.remove('hidden');
|
|
2500
2447
|
renderDashboardTabs();
|
|
2448
|
+
renderCardCounters();
|
|
2449
|
+
syncSettingsButtonVisibility();
|
|
2501
2450
|
refreshOverviewSection();
|
|
2502
2451
|
}
|
|
2503
2452
|
|
|
@@ -2508,9 +2457,120 @@
|
|
|
2508
2457
|
const overviewSection = document.getElementById('overview-section');
|
|
2509
2458
|
if (overviewSection) overviewSection.classList.add('hidden');
|
|
2510
2459
|
renderDashboardTabs();
|
|
2460
|
+
renderCardCounters();
|
|
2461
|
+
syncSettingsButtonVisibility();
|
|
2511
2462
|
loadProjectConfigFromPath(projectPath);
|
|
2512
2463
|
}
|
|
2513
2464
|
|
|
2465
|
+
function syncSettingsButtonVisibility() {
|
|
2466
|
+
const button = document.getElementById('open-settings-modal-btn');
|
|
2467
|
+
if (!button) return;
|
|
2468
|
+
if (activeTabId === 'overview') {
|
|
2469
|
+
button.hidden = true;
|
|
2470
|
+
} else {
|
|
2471
|
+
button.hidden = false;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
function resolveActiveProjectName() {
|
|
2476
|
+
if (activeTabId === 'overview') return '—';
|
|
2477
|
+
const repository = availableRepositories.find((r) => r.localPath === activeTabId);
|
|
2478
|
+
if (repository?.name) return repository.name;
|
|
2479
|
+
return activeTabId.split('/').filter(Boolean).pop() ?? activeTabId;
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
async function openSettingsModal() {
|
|
2483
|
+
if (activeTabId === 'overview') return;
|
|
2484
|
+
const dialog = document.getElementById('settings-modal');
|
|
2485
|
+
if (!dialog || typeof dialog.showModal !== 'function') return;
|
|
2486
|
+
try {
|
|
2487
|
+
const response = await fetch(
|
|
2488
|
+
`${API_URL}/api/project-config?path=${encodeURIComponent(activeTabId)}`,
|
|
2489
|
+
);
|
|
2490
|
+
const payload = await response.json();
|
|
2491
|
+
if (!payload?.success) {
|
|
2492
|
+
dialog.innerHTML = `<form method="dialog" class="settings-modal__form"><p class="settings-modal__error">${escapeHtml(payload?.error || 'Configuration projet illisible')}</p><div class="settings-modal__actions"><button type="submit" class="settings-modal__cancel">Fermer</button></div></form>`;
|
|
2493
|
+
dialog.showModal();
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
const viewModel = buildSettingsViewModel({
|
|
2497
|
+
config: payload.config,
|
|
2498
|
+
projectName: resolveActiveProjectName(),
|
|
2499
|
+
});
|
|
2500
|
+
dialog.innerHTML = renderSettingsModalHtml(viewModel);
|
|
2501
|
+
bindSettingsModalForm(dialog);
|
|
2502
|
+
dialog.showModal();
|
|
2503
|
+
} catch (error) {
|
|
2504
|
+
showToast(t('toast.error') || 'Erreur', 'error');
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
function closeSettingsModal() {
|
|
2509
|
+
const dialog = document.getElementById('settings-modal');
|
|
2510
|
+
if (dialog && dialog.open) dialog.close();
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
function bindSettingsModalForm(dialog) {
|
|
2514
|
+
const form = dialog.querySelector('form.settings-modal__form');
|
|
2515
|
+
const cancelBtn = dialog.querySelector('.settings-modal__cancel');
|
|
2516
|
+
const errorEl = dialog.querySelector('.settings-modal__error');
|
|
2517
|
+
if (cancelBtn) {
|
|
2518
|
+
cancelBtn.addEventListener('click', (event) => {
|
|
2519
|
+
event.preventDefault();
|
|
2520
|
+
closeSettingsModal();
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
if (!form) return;
|
|
2524
|
+
form.addEventListener('submit', async (event) => {
|
|
2525
|
+
event.preventDefault();
|
|
2526
|
+
if (errorEl) errorEl.textContent = '';
|
|
2527
|
+
const formData = new FormData(form);
|
|
2528
|
+
const payload = extractFormPayload(formData);
|
|
2529
|
+
const linkValidation = validateExternalLink(payload.externalLink ?? '');
|
|
2530
|
+
if (!linkValidation.ok) {
|
|
2531
|
+
if (errorEl) errorEl.textContent = linkValidation.message;
|
|
2532
|
+
return;
|
|
2533
|
+
}
|
|
2534
|
+
try {
|
|
2535
|
+
const response = await fetch(
|
|
2536
|
+
`${API_URL}/api/project-config?path=${encodeURIComponent(activeTabId)}`,
|
|
2537
|
+
{
|
|
2538
|
+
method: 'PATCH',
|
|
2539
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2540
|
+
body: JSON.stringify(payload),
|
|
2541
|
+
},
|
|
2542
|
+
);
|
|
2543
|
+
if (!response.ok) {
|
|
2544
|
+
const errorPayload = await response.json().catch(() => ({ error: 'Échec de la sauvegarde' }));
|
|
2545
|
+
if (errorEl) errorEl.textContent = errorPayload?.error || 'Échec de la sauvegarde';
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
closeSettingsModal();
|
|
2549
|
+
refreshOverviewSection();
|
|
2550
|
+
} catch {
|
|
2551
|
+
if (errorEl) errorEl.textContent = 'Échec de la sauvegarde';
|
|
2552
|
+
}
|
|
2553
|
+
});
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
function bindSettingsModalDismissals() {
|
|
2557
|
+
const dialog = document.getElementById('settings-modal');
|
|
2558
|
+
if (!dialog) return;
|
|
2559
|
+
dialog.addEventListener('click', (event) => {
|
|
2560
|
+
if (event.target === dialog) {
|
|
2561
|
+
closeSettingsModal();
|
|
2562
|
+
}
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
function bindSettingsModalTrigger() {
|
|
2567
|
+
const button = document.getElementById('open-settings-modal-btn');
|
|
2568
|
+
if (!button) return;
|
|
2569
|
+
button.addEventListener('click', () => {
|
|
2570
|
+
openSettingsModal();
|
|
2571
|
+
});
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2514
2574
|
async function refreshOverviewSection() {
|
|
2515
2575
|
const container = document.getElementById('overview-section');
|
|
2516
2576
|
if (!container) return;
|
|
@@ -2525,6 +2585,9 @@
|
|
|
2525
2585
|
if (projectPath) activateProjectTab(projectPath);
|
|
2526
2586
|
});
|
|
2527
2587
|
});
|
|
2588
|
+
container.querySelectorAll('.project-card__external').forEach((anchor) => {
|
|
2589
|
+
anchor.addEventListener('click', (event) => event.stopPropagation());
|
|
2590
|
+
});
|
|
2528
2591
|
} catch {
|
|
2529
2592
|
// Silent: WS reconnection or next refresh will retry
|
|
2530
2593
|
}
|
|
@@ -2532,7 +2595,10 @@
|
|
|
2532
2595
|
|
|
2533
2596
|
async function initOverviewAndTabs() {
|
|
2534
2597
|
await fetchAvailableRepositories();
|
|
2535
|
-
|
|
2598
|
+
renderManagePanel();
|
|
2599
|
+
bindManagePanelToggle();
|
|
2600
|
+
bindSettingsModalTrigger();
|
|
2601
|
+
bindSettingsModalDismissals();
|
|
2536
2602
|
const persistedTab = readActiveTab();
|
|
2537
2603
|
const repositoryPaths = availableRepositories.map((repository) => repository.localPath);
|
|
2538
2604
|
if (persistedTab && persistedTab !== 'overview' && repositoryPaths.includes(persistedTab)) {
|
|
@@ -2542,6 +2608,196 @@
|
|
|
2542
2608
|
}
|
|
2543
2609
|
}
|
|
2544
2610
|
|
|
2611
|
+
let isManagePanelOpen = false;
|
|
2612
|
+
|
|
2613
|
+
function renderManagePanel() {
|
|
2614
|
+
const panel = document.getElementById('manage-panel');
|
|
2615
|
+
if (!panel) return;
|
|
2616
|
+
const model = buildManagePanelModel({ repositories: availableRepositories, isOpen: isManagePanelOpen });
|
|
2617
|
+
panel.innerHTML = renderManagePanelHtml(model);
|
|
2618
|
+
panel.dataset.open = isManagePanelOpen ? 'true' : 'false';
|
|
2619
|
+
bindManagePanelHandlers();
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
function bindManagePanelToggle() {
|
|
2623
|
+
const toggle = document.getElementById('manage-projects-toggle');
|
|
2624
|
+
if (!toggle || toggle.dataset.bound === 'true') return;
|
|
2625
|
+
toggle.dataset.bound = 'true';
|
|
2626
|
+
toggle.addEventListener('click', () => {
|
|
2627
|
+
isManagePanelOpen = !isManagePanelOpen;
|
|
2628
|
+
toggle.setAttribute('aria-expanded', isManagePanelOpen ? 'true' : 'false');
|
|
2629
|
+
renderManagePanel();
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
function bindManagePanelHandlers() {
|
|
2634
|
+
const panel = document.getElementById('manage-panel');
|
|
2635
|
+
if (!panel) return;
|
|
2636
|
+
const form = panel.querySelector('form.add-form');
|
|
2637
|
+
if (form) {
|
|
2638
|
+
form.addEventListener('submit', handleAddProjectSubmit);
|
|
2639
|
+
const input = form.querySelector('input.add-form-input');
|
|
2640
|
+
if (input) {
|
|
2641
|
+
input.addEventListener('keydown', (event) => {
|
|
2642
|
+
if (event.key === 'Escape') {
|
|
2643
|
+
input.value = '';
|
|
2644
|
+
clearManagePanelError();
|
|
2645
|
+
}
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
panel.querySelectorAll('.manage-row-delete').forEach((button) => {
|
|
2650
|
+
button.addEventListener('click', () => {
|
|
2651
|
+
const row = button.closest('.manage-row');
|
|
2652
|
+
const localPath = row?.dataset.localPath;
|
|
2653
|
+
if (localPath) handleDeleteProject(localPath, row);
|
|
2654
|
+
});
|
|
2655
|
+
});
|
|
2656
|
+
panel.querySelectorAll('.manage-row-toggle').forEach((button) => {
|
|
2657
|
+
button.addEventListener('click', () => {
|
|
2658
|
+
const row = button.closest('.manage-row');
|
|
2659
|
+
const localPath = row?.dataset.localPath;
|
|
2660
|
+
const currentlyEnabled = row?.dataset.enabled === 'true';
|
|
2661
|
+
if (localPath) handleToggleProject(localPath, !currentlyEnabled);
|
|
2662
|
+
});
|
|
2663
|
+
});
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
function setManagePanelError(message) {
|
|
2667
|
+
const panel = document.getElementById('manage-panel');
|
|
2668
|
+
const target = panel?.querySelector('[data-role="error-message"]');
|
|
2669
|
+
if (!target) return;
|
|
2670
|
+
target.textContent = message;
|
|
2671
|
+
target.hidden = false;
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
function clearManagePanelError() {
|
|
2675
|
+
const panel = document.getElementById('manage-panel');
|
|
2676
|
+
const target = panel?.querySelector('[data-role="error-message"]');
|
|
2677
|
+
if (!target) return;
|
|
2678
|
+
target.textContent = '';
|
|
2679
|
+
target.hidden = true;
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
function flashAddFormError() {
|
|
2683
|
+
const form = document.querySelector('#manage-panel form.add-form');
|
|
2684
|
+
if (!form) return;
|
|
2685
|
+
form.classList.remove('is-error');
|
|
2686
|
+
requestAnimationFrame(() => form.classList.add('is-error'));
|
|
2687
|
+
setTimeout(() => form.classList.remove('is-error'), 320);
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
function flashAddFormSuccess() {
|
|
2691
|
+
const input = document.querySelector('#manage-panel input.add-form-input');
|
|
2692
|
+
if (!input) return;
|
|
2693
|
+
input.classList.remove('is-success');
|
|
2694
|
+
requestAnimationFrame(() => input.classList.add('is-success'));
|
|
2695
|
+
setTimeout(() => input.classList.remove('is-success'), 1500);
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
function flashTabEntering(localPath) {
|
|
2699
|
+
const tab = document.querySelector(`.dashboard-tab[data-tab-id="${CSS.escape(localPath)}"]`);
|
|
2700
|
+
if (!tab) return;
|
|
2701
|
+
tab.classList.add('is-entering');
|
|
2702
|
+
setTimeout(() => tab.classList.remove('is-entering'), 1500);
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
async function handleAddProjectSubmit(event) {
|
|
2706
|
+
event.preventDefault();
|
|
2707
|
+
const form = event.currentTarget;
|
|
2708
|
+
const input = form.querySelector('input.add-form-input');
|
|
2709
|
+
const submit = form.querySelector('button.add-form-submit');
|
|
2710
|
+
const rawValue = input ? input.value : '';
|
|
2711
|
+
const validation = validateLocalPathInput(rawValue);
|
|
2712
|
+
clearManagePanelError();
|
|
2713
|
+
if (!validation.ok) {
|
|
2714
|
+
const message = validation.reason === 'empty' ? 'Chemin du projet requis' : 'Le chemin doit être absolu';
|
|
2715
|
+
setManagePanelError(message);
|
|
2716
|
+
flashAddFormError();
|
|
2717
|
+
return;
|
|
2718
|
+
}
|
|
2719
|
+
const trimmed = rawValue.trim();
|
|
2720
|
+
if (submit) submit.classList.add('is-busy');
|
|
2721
|
+
try {
|
|
2722
|
+
const response = await fetch(`${API_URL}/api/repositories`, {
|
|
2723
|
+
method: 'POST',
|
|
2724
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2725
|
+
body: JSON.stringify({ localPath: trimmed }),
|
|
2726
|
+
});
|
|
2727
|
+
const body = await response.json().catch(() => ({}));
|
|
2728
|
+
if (!response.ok) {
|
|
2729
|
+
setManagePanelError(typeof body?.error === 'string' ? body.error : 'Erreur inconnue');
|
|
2730
|
+
flashAddFormError();
|
|
2731
|
+
return;
|
|
2732
|
+
}
|
|
2733
|
+
syncAvailableRepositoriesFromResponse(body);
|
|
2734
|
+
if (input) input.value = '';
|
|
2735
|
+
flashAddFormSuccess();
|
|
2736
|
+
renderManagePanel();
|
|
2737
|
+
renderDashboardTabs();
|
|
2738
|
+
flashTabEntering(trimmed);
|
|
2739
|
+
} catch {
|
|
2740
|
+
setManagePanelError('Erreur réseau');
|
|
2741
|
+
flashAddFormError();
|
|
2742
|
+
} finally {
|
|
2743
|
+
if (submit) submit.classList.remove('is-busy');
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
async function handleDeleteProject(localPath, rowElement) {
|
|
2748
|
+
try {
|
|
2749
|
+
const response = await fetch(`${API_URL}/api/repositories?localPath=${encodeURIComponent(localPath)}`, {
|
|
2750
|
+
method: 'DELETE',
|
|
2751
|
+
});
|
|
2752
|
+
const body = await response.json().catch(() => ({}));
|
|
2753
|
+
if (!response.ok) {
|
|
2754
|
+
setManagePanelError(typeof body?.error === 'string' ? body.error : 'Erreur inconnue');
|
|
2755
|
+
return;
|
|
2756
|
+
}
|
|
2757
|
+
syncAvailableRepositoriesFromResponse(body);
|
|
2758
|
+
if (rowElement) {
|
|
2759
|
+
rowElement.classList.add('is-leaving');
|
|
2760
|
+
setTimeout(() => {
|
|
2761
|
+
renderManagePanel();
|
|
2762
|
+
}, 250);
|
|
2763
|
+
} else {
|
|
2764
|
+
renderManagePanel();
|
|
2765
|
+
}
|
|
2766
|
+
const tab = document.querySelector(`.dashboard-tab[data-tab-id="${CSS.escape(localPath)}"]`);
|
|
2767
|
+
if (tab) {
|
|
2768
|
+
tab.classList.add('is-leaving');
|
|
2769
|
+
setTimeout(() => renderDashboardTabs(), 250);
|
|
2770
|
+
} else {
|
|
2771
|
+
renderDashboardTabs();
|
|
2772
|
+
}
|
|
2773
|
+
if (activeTabId === localPath) {
|
|
2774
|
+
activateOverviewTab();
|
|
2775
|
+
}
|
|
2776
|
+
} catch {
|
|
2777
|
+
setManagePanelError('Erreur réseau');
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
async function handleToggleProject(localPath, enabled) {
|
|
2782
|
+
try {
|
|
2783
|
+
const response = await fetch(`${API_URL}/api/repositories?localPath=${encodeURIComponent(localPath)}`, {
|
|
2784
|
+
method: 'PATCH',
|
|
2785
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2786
|
+
body: JSON.stringify({ enabled }),
|
|
2787
|
+
});
|
|
2788
|
+
const body = await response.json().catch(() => ({}));
|
|
2789
|
+
if (!response.ok) {
|
|
2790
|
+
setManagePanelError(typeof body?.error === 'string' ? body.error : 'Erreur inconnue');
|
|
2791
|
+
return;
|
|
2792
|
+
}
|
|
2793
|
+
syncAvailableRepositoriesFromResponse(body);
|
|
2794
|
+
renderManagePanel();
|
|
2795
|
+
renderDashboardTabs();
|
|
2796
|
+
} catch {
|
|
2797
|
+
setManagePanelError('Erreur réseau');
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2545
2801
|
function getMrLabel(platform = activePlatform) {
|
|
2546
2802
|
return platform === 'github' ? 'PR' : 'MR';
|
|
2547
2803
|
}
|
|
@@ -2681,19 +2937,6 @@
|
|
|
2681
2937
|
const modelSonnet = document.getElementById('i18n-model-sonnet');
|
|
2682
2938
|
if (modelSonnet) modelSonnet.textContent = t('model.sonnet');
|
|
2683
2939
|
|
|
2684
|
-
// Project loader
|
|
2685
|
-
const projectPlaceholder = document.getElementById('i18n-project-placeholder');
|
|
2686
|
-
if (projectPlaceholder) projectPlaceholder.textContent = t('project.selectPlaceholder');
|
|
2687
|
-
|
|
2688
|
-
const projectPathInput = document.getElementById('project-path-input');
|
|
2689
|
-
if (projectPathInput) projectPathInput.placeholder = t('project.inputPlaceholder');
|
|
2690
|
-
|
|
2691
|
-
const projectLoad = document.getElementById('i18n-project-load');
|
|
2692
|
-
if (projectLoad) projectLoad.textContent = t('project.load');
|
|
2693
|
-
|
|
2694
|
-
const removeProjectBtn = document.getElementById('remove-project-btn');
|
|
2695
|
-
if (removeProjectBtn) removeProjectBtn.title = t('project.removeTooltip');
|
|
2696
|
-
|
|
2697
2940
|
// Login sections
|
|
2698
2941
|
const claudeLoginTitle = document.getElementById('i18n-claude-login-title');
|
|
2699
2942
|
if (claudeLoginTitle) claudeLoginTitle.textContent = t('login.claude.title');
|
|
@@ -2792,9 +3035,6 @@
|
|
|
2792
3035
|
|
|
2793
3036
|
const modalConfirm = document.getElementById('cancel-modal-confirm');
|
|
2794
3037
|
if (modalConfirm) modalConfirm.textContent = t('modal.confirm');
|
|
2795
|
-
|
|
2796
|
-
// Update project select placeholder (re-render the select)
|
|
2797
|
-
updateProjectSelect();
|
|
2798
3038
|
}
|
|
2799
3039
|
|
|
2800
3040
|
async function checkForUpdates() {
|
|
@@ -2952,9 +3192,6 @@
|
|
|
2952
3192
|
window.toggleStats = toggleStats;
|
|
2953
3193
|
window.changeModel = changeModel;
|
|
2954
3194
|
window.changeLanguage = changeLanguage;
|
|
2955
|
-
window.onProjectSelect = onProjectSelect;
|
|
2956
|
-
window.loadProjectConfig = loadProjectConfig;
|
|
2957
|
-
window.removeCurrentProject = removeCurrentProject;
|
|
2958
3195
|
window.toggleReviewAccordion = toggleReviewAccordion;
|
|
2959
3196
|
window.toggleReviewDescription = toggleReviewDescription;
|
|
2960
3197
|
window.deleteReviewFile = deleteReviewFile;
|
|
@@ -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"}
|