feat(worktrees): création intelligente (auto) + commit/push/promotion + grille agrandissable
- addWorktree résout la branche par dépôt (branchExists) : checkout si présente, suivi de origin/<b> si seulement remote, sinon création (-b) depuis la branche par défaut. Corrige le 'fatal: invalid reference' sur les groupes hétérogènes ; newBranch -> mode (déprécié, mappé en route).
- Nouvelles opérations git : commit (add -A), push (upstream auto), promotion « en principal » (la branche du worktree devient le checkout principal, sans merge ni conflit, ancienne branche conservée). Routes /worktrees/{commit,push,promote} auditées + GET /repos/:id/branches.
- Web : actions Commit/Push/Promouvoir sur WorktreeCard, sélecteur de branche de base (datalist) dans RepoSection et GroupSessionModal, agrandissement d'un terminal au choix dans TerminalGrid.
- Court-circuite la session de groupe quand aucun worktree n'a pu être créé (fini le masquage par « no resolvable worktree »).
- Tests : git.ts (branchExists/listBranches/commitAll/auto), worktree-manager (commit/promote/branches) ; acceptance P5 étend le scénario worktree de groupe sur branche neuve + commit + promotion.
This commit is contained in:
@@ -2,19 +2,24 @@
|
||||
<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">
|
||||
<p v-if="!activeMax && 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). Hauteur relative au viewport
|
||||
(dvh) : terminaux grands sur PC, exploitables sur mobile ; xterm re-fit via ResizeObserver.
|
||||
Plancher min-h-80 pour les fenêtres courtes. -->
|
||||
<div class="grid grid-cols-1 gap-3 lg:grid-cols-2 2xl:grid-cols-3">
|
||||
<!-- une cellule maximisée → plein cadre ; sinon la grille responsive -->
|
||||
<div v-if="activeMax" class="grid grid-cols-1">
|
||||
<TerminalCell :session="activeMax" maximized class="h-[calc(100dvh-8rem)] min-h-80" @toggle-maximize="toggleMax(activeMax.id)" />
|
||||
</div>
|
||||
<div v-else 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-[68dvh] min-h-80 lg:h-[calc((100dvh-9rem)/2)]"
|
||||
@toggle-maximize="toggleMax(s.id)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -22,7 +27,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import type { SessionSummary } from '@arboretum/shared';
|
||||
import TerminalCell from './TerminalCell.vue';
|
||||
@@ -32,4 +37,14 @@ const { t } = useI18n();
|
||||
|
||||
const MAX_CELLS = 6;
|
||||
const shown = computed(() => props.sessions.slice(0, MAX_CELLS));
|
||||
|
||||
// Maximisation d'une cellule au choix (état purement présentation, local à la grille). Si la session
|
||||
// maximisée disparaît (terminée), on retombe automatiquement sur la grille.
|
||||
const maximizedId = ref<string | null>(null);
|
||||
function toggleMax(id: string): void {
|
||||
maximizedId.value = maximizedId.value === id ? null : id;
|
||||
}
|
||||
const activeMax = computed<SessionSummary | null>(() =>
|
||||
maximizedId.value ? (shown.value.find((s) => s.id === maximizedId.value) ?? null) : null,
|
||||
);
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user