feat(web): coquille IDE + arbre de projets unifié (route /ide)
Some checks failed
CI / Build & test (Node 24) (push) Has been cancelled
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
CI / No em/en dashes (push) Has been cancelled
CI / Build & test (Node 22) (push) Has been cancelled

components/ide/ : IdeShell (grille barre d'activité + panneau gauche + zone centrale + dock + barre de statut, splitters persistés, réconciliation des ressources ouvertes contre les données live), ActivityBar (Explorer/Git/Sessions/Groupes + Réglages/Aide), PrimarySidebar, ProjectTree + ProjectTreeNode (arbre unique repos -> worktrees -> sessions, fichiers embarqués via FileTree en mode sans chrome, dépliage paresseux), StatusBar.

Route /ide (layout 'ide'), entrée de nav « IDE », namespace i18n ide (EN/FR). Clics de l'arbre pilotent le store (contexte worktree, ouverture de fichier/terminal). Centre et dock en placeholders (remplis en B4/B5). FileTree gagne un mode embedded. 427 tests.
This commit is contained in:
2026-07-17 17:08:35 +02:00
parent 6acd4a16fd
commit c96d929c7a
13 changed files with 446 additions and 11 deletions

View File

@@ -122,18 +122,21 @@ describe('store IDE', () => {
expect(ide.leftVisible).toBe(true);
});
it('pruneDeadResources retire onglets/terminaux morts et reset dirty', () => {
it('pruneDeadResources retire onglets/terminaux morts ; dirty gardé pour les conservés, nettoyé pour les retirés', () => {
const ide = useIdeStore();
ide.openFile('r', '/w1', 'a');
ide.openFile('r', '/w2', 'b');
ide.openFile('r', '/w1', 'a'); // worktree connu -> gardé
ide.openFile('r', '/w2', 'b'); // worktree inconnu -> retiré
ide.setTabDirty(tabId('r', '/w1', 'a'), true);
ide.setTabDirty(tabId('r', '/w2', 'b'), true);
ide.openTerminal('sLive');
ide.openTerminal('sDead');
ide.pruneDeadResources(new Set(['sLive']), new Set([wtKey('r', '/w1')]));
expect(ide.editorTabs.map((t) => t.wtPath)).toEqual(['/w1']); // /w2 inconnu -> retiré
expect(ide.editorTabs.map((t) => t.wtPath)).toEqual(['/w1']);
expect(ide.dockSessionIds).toEqual(['sLive']); // sDead retiré
expect(ide.hasUnsaved).toBe(false); // dirty remis à zéro
expect(ide.isDirty(tabId('r', '/w1', 'a'))).toBe(true); // onglet gardé : dirty conservé
expect(ide.isDirty(tabId('r', '/w2', 'b'))).toBe(false); // onglet retiré : dirty nettoyé
expect(ide.hasUnsaved).toBe(true); // il reste l'onglet /w1 modifié
});
});