feat(sessions): masquer les sessions externes + terminal plein écran
Masquage persistant des sessions Claude découvertes (lancées hors Arboretum) qui polluent la liste — calqué sur repos.hidden : - table hidden_sessions (#9) clé claudeSessionId ; helpers DB - DiscoveryService pose le champ additif SessionSummary.hidden (resume/fork restent possibles, survit à un re-scan) - routes POST/DELETE /sessions/:id/hide, POST /sessions/hide-discovered (masse, un clic), GET /sessions?includeHidden=true - UI : bouton Masquer par ligne, « Masquer l'historique externe », toggle « Afficher les masquées », badge masquée ; store + i18n EN/FR + audit Terminal plein écran (corrige le sizing) : - SessionView root s'étire (flex-1) → xterm calcule les bonnes dimensions - refit robuste (requestAnimationFrame + après resync), h-full sur le wrapper - bouton plein écran (API Fullscreen), tabbar mobile masquée en fullbleed DialogPrompt : options en liste verticale pleine largeur (plus de troncature ni de chevauchement sur les libellés longs / multi-lignes). Doc : centre d'aide (sessions), README EN/FR, site (showcase), CLAUDE.md. Tests : discovery (hidden) + route hide/unhide/hide-discovered.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import type { CreateSessionRequest, SessionResponse, SessionSummary, SessionsListResponse } from '@arboretum/shared';
|
||||
import type { CreateSessionRequest, HideDiscoveredResponse, SessionResponse, SessionSummary, SessionsListResponse } from '@arboretum/shared';
|
||||
import { api } from '../lib/api';
|
||||
import { wsClient, type SessionEvent } from '../lib/ws-client';
|
||||
|
||||
@@ -8,6 +8,8 @@ export const useSessionsStore = defineStore('sessions', () => {
|
||||
const sessions = ref<SessionSummary[]>([]);
|
||||
const loading = ref(false);
|
||||
const loadError = ref<string | null>(null);
|
||||
// false (défaut) : les sessions masquées sont exclues ; true : on les inclut (mode « afficher les masquées »).
|
||||
const showHidden = ref(false);
|
||||
let unsubscribe: (() => void) | null = null;
|
||||
|
||||
// vivantes d'abord, puis par date de création décroissante (même ordre que le serveur)
|
||||
@@ -15,7 +17,17 @@ export const useSessionsStore = defineStore('sessions', () => {
|
||||
return [...list].sort((a, b) => Number(b.live) - Number(a.live) || b.createdAt.localeCompare(a.createdAt));
|
||||
}
|
||||
|
||||
function remove(id: string): void {
|
||||
const idx = sessions.value.findIndex((s) => s.id === id);
|
||||
if (idx >= 0) sessions.value.splice(idx, 1);
|
||||
}
|
||||
|
||||
function upsert(session: SessionSummary): void {
|
||||
// session masquée et mode « afficher les masquées » inactif : on la retire de la liste.
|
||||
if (session.hidden && !showHidden.value) {
|
||||
remove(session.id);
|
||||
return;
|
||||
}
|
||||
const idx = sessions.value.findIndex((s) => s.id === session.id);
|
||||
if (idx >= 0) sessions.value.splice(idx, 1, session);
|
||||
else sessions.value.push(session);
|
||||
@@ -43,7 +55,8 @@ export const useSessionsStore = defineStore('sessions', () => {
|
||||
loading.value = true;
|
||||
loadError.value = null;
|
||||
try {
|
||||
const res = await api.get<SessionsListResponse>('/api/v1/sessions');
|
||||
const url = showHidden.value ? '/api/v1/sessions?includeHidden=true' : '/api/v1/sessions';
|
||||
const res = await api.get<SessionsListResponse>(url);
|
||||
sessions.value = sorted(res.sessions);
|
||||
} catch (err) {
|
||||
loadError.value = err instanceof Error ? err.message : String(err);
|
||||
@@ -52,6 +65,31 @@ export const useSessionsStore = defineStore('sessions', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function setShowHidden(value: boolean): Promise<void> {
|
||||
showHidden.value = value;
|
||||
await fetchSessions();
|
||||
}
|
||||
|
||||
// Masque une session découverte (retrait optimiste si on n'affiche pas les masquées).
|
||||
async function hideSession(id: string): Promise<void> {
|
||||
await api.post<{ ok: true }>(`/api/v1/sessions/${id}/hide`);
|
||||
if (!showHidden.value) remove(id);
|
||||
}
|
||||
|
||||
// Ré-affiche une session masquée.
|
||||
async function unhideSession(id: string): Promise<void> {
|
||||
await api.delete<{ ok: true }>(`/api/v1/sessions/${id}/hide`);
|
||||
}
|
||||
|
||||
// Masque tout l'historique de sessions externes visible. Renvoie le nombre masqué.
|
||||
async function hideDiscovered(): Promise<number> {
|
||||
const res = await api.post<HideDiscoveredResponse>('/api/v1/sessions/hide-discovered');
|
||||
if (!showHidden.value) {
|
||||
sessions.value = sessions.value.filter((s) => !(s.source === 'discovered' && !s.hidden));
|
||||
}
|
||||
return res.hidden;
|
||||
}
|
||||
|
||||
function startRealtime(): void {
|
||||
unsubscribe ??= wsClient.subscribeSessions(onEvent);
|
||||
}
|
||||
@@ -90,12 +128,17 @@ export const useSessionsStore = defineStore('sessions', () => {
|
||||
sessions,
|
||||
loading,
|
||||
loadError,
|
||||
showHidden,
|
||||
fetchSessions,
|
||||
setShowHidden,
|
||||
startRealtime,
|
||||
stopRealtime,
|
||||
createSession,
|
||||
killSession,
|
||||
resumeSession,
|
||||
forkSession,
|
||||
hideSession,
|
||||
unhideSession,
|
||||
hideDiscovered,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user