Add autocomplete status check and restructure test environments
CI / lint (push) Failing after 26s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / e2e (push) Has been skipped
CI / security (push) Failing after 10s

Add Ollama autocomplete status endpoint to AI routes, update sync panel
UI to display autocomplete state, replace monolithic test compose files
with separate Linux/Windows variants, and add PowerShell build script
for Windows deployment
This commit is contained in:
2026-06-18 09:40:09 -04:00
parent 8acfd1f19a
commit daab917ed1
10 changed files with 460 additions and 137 deletions
+58 -23
View File
@@ -341,15 +341,18 @@ function _renderSyncPanel(panel) {
let _aiProcessing = false;
let _aiConfigured = null; // null = unknown, true/false
let _aiAutocomplete = null; // null = unknown, {available, server_ok, model_loaded, model, error}
/** Check if AI is configured by calling the /api/ai/status endpoint.
* Updates _aiConfigured and refreshes the panel if open. */
* Updates _aiConfigured, _aiAutocomplete and refreshes the panel if open. */
async function _checkAIStatus() {
try {
const status = await api('/api/ai/status');
_aiConfigured = status.configured === true;
_aiAutocomplete = status.autocomplete || null;
} catch {
_aiConfigured = false;
_aiAutocomplete = null;
}
_updateAIStatusInPanel();
}
@@ -359,34 +362,66 @@ function _renderAIStatusSection(panel) {
section.className = 'sync-panel__ai-section';
section.id = 'sync-panel-ai';
let statusIcon, statusText, statusClass;
// ---- External provider status ----
let extIcon, extText, extClass;
if (_aiProcessing) {
statusIcon = 'loader';
statusText = 'Traitement en cours…';
statusClass = 'sync-panel__ai--processing';
extIcon = 'loader';
extText = 'Traitement en cours…';
extClass = 'sync-panel__ai--processing';
} else if (_aiConfigured === true) {
statusIcon = 'check-circle';
statusText = 'IA configurée et active';
statusClass = 'sync-panel__ai--active';
extIcon = 'check-circle';
extText = 'Fournisseur externe actif';
extClass = 'sync-panel__ai--active';
} else if (_aiConfigured === false) {
statusIcon = 'x-circle';
statusText = 'IA non configurée';
statusClass = 'sync-panel__ai--inactive';
extIcon = 'x-circle';
extText = 'Aucun fournisseur';
extClass = 'sync-panel__ai--inactive';
} else {
statusIcon = 'help-circle';
statusText = 'Statut IA inconnu';
statusClass = 'sync-panel__ai--unknown';
extIcon = 'help-circle';
extText = 'Vérification…';
extClass = 'sync-panel__ai--unknown';
}
section.innerHTML = `
<div class="sync-panel__ai-header">
<span class="sync-panel__ai-title">Intelligence Artificielle</span>
<span class="sync-panel__ai-state ${statusClass}" data-lucide-icon="${statusIcon}">
<i data-lucide="${statusIcon}" style="width:14px;height:14px"></i>
${statusText}
</span>
</div>
`;
// ---- Autocomplete (Ollama) status ----
let acIcon, acText, acClass;
if (_aiAutocomplete && _aiAutocomplete.available) {
acIcon = 'check-circle';
acText = 'Auto-complétion active';
acClass = 'sync-panel__ai--active';
} else if (_aiAutocomplete && _aiAutocomplete.server_ok && !_aiAutocomplete.model_loaded) {
acIcon = 'alert-triangle';
acText = 'Modèle non chargé';
acClass = 'sync-panel__ai--inactive';
} else if (_aiAutocomplete && _aiAutocomplete.error) {
acIcon = 'x-circle';
acText = 'Serveur Ollama injoignable';
acClass = 'sync-panel__ai--inactive';
} else if (_aiAutocomplete === null) {
acIcon = 'help-circle';
acText = 'Vérification…';
acClass = 'sync-panel__ai--unknown';
} else {
acIcon = 'x-circle';
acText = 'Non configuré';
acClass = 'sync-panel__ai--inactive';
}
section.innerHTML = '' +
'<div class="sync-panel__ai-title">Intelligence Artificielle</div>' +
'<div class="sync-panel__ai-row">' +
'<span class="sync-panel__ai-label">Fournisseur</span>' +
'<span class="sync-panel__ai-state ' + extClass + '" data-lucide-icon="' + extIcon + '">' +
'<i data-lucide="' + extIcon + '" style="width:14px;height:14px"></i>' +
extText +
'</span>' +
'</div>' +
'<div class="sync-panel__ai-row">' +
'<span class="sync-panel__ai-label">Auto-complétion</span>' +
'<span class="sync-panel__ai-state ' + acClass + '" data-lucide-icon="' + acIcon + '">' +
'<i data-lucide="' + acIcon + '" style="width:14px;height:14px"></i>' +
acText +
'</span>' +
'</div>';
panel.appendChild(section);
// Trigger icon refresh via global
+13 -6
View File
@@ -4239,16 +4239,23 @@ body.resizing-v {
padding: 10px 14px;
}
.sync-panel__ai-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.sync-panel__ai-title {
font-size: 0.78rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
}
.sync-panel__ai-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 5px;
}
.sync-panel__ai-label {
font-size: 0.72rem;
color: var(--text-muted);
}
.sync-panel__ai-state {