feat: groupes de travail (P5)
Ajoute la notion de groupe — collection nommée de repos (membership légère persistée, many-to-many) — pour piloter plusieurs repos en simultané : - DB : migration #5 (tables groups + group_repos, FK ON DELETE CASCADE). - GroupManager (synchrone, EventEmitter) + routes REST /api/v1/groups ; ne persiste que la membership, worktrees/sessions filtrés par repoId côté client. - Protocole : GroupSummary, DTOs, topic WS « groups », events group_update/removed (additifs, PROTOCOL_VERSION inchangé). - Web : store groups, GroupsListView, GroupView (réutilise RepoSection), grille multi-terminaux (TerminalGrid/TerminalCell), action « feature cross-repo » (orchestration client, tolérante aux échecs partiels), routes + i18n EN/FR. - Tests : group-manager.test.ts + extension protocol.test.ts ; acceptance-p5.mjs.
This commit is contained in:
28
packages/web/src/components/TerminalGrid.vue
Normal file
28
packages/web/src/components/TerminalGrid.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<p v-if="sessions.length === 0" class="text-sm text-zinc-500">{{ t('groups.gridEmpty') }}</p>
|
||||
<template v-else>
|
||||
<p v-if="sessions.length > MAX_CELLS" class="text-xs text-amber-400">
|
||||
{{ t('groups.gridCapped', { shown: MAX_CELLS, total: sessions.length }) }}
|
||||
</p>
|
||||
<!-- une seule socket WS multiplexe tous les terminaux ; cap dur pour préserver GPU/canaux.
|
||||
Sur mobile la grille retombe à une colonne (empilement). -->
|
||||
<div class="grid grid-cols-1 gap-3 lg:grid-cols-2 2xl:grid-cols-3">
|
||||
<TerminalCell v-for="s in shown" :key="s.id" :session="s" class="h-80" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import type { SessionSummary } from '@arboretum/shared';
|
||||
import TerminalCell from './TerminalCell.vue';
|
||||
|
||||
const props = defineProps<{ sessions: SessionSummary[] }>();
|
||||
const { t } = useI18n();
|
||||
|
||||
const MAX_CELLS = 6;
|
||||
const shown = computed(() => props.sessions.slice(0, MAX_CELLS));
|
||||
</script>
|
||||
Reference in New Issue
Block a user