feat: add delete button for groups in sidebar

Shows × on hover next to the + button. Confirms before deleting.
Hosts in deleted groups become ungrouped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell 2026-03-13 10:23:02 -04:00
parent 3b14a7c1d1
commit 74d3c0bd9a
2 changed files with 17 additions and 3 deletions

View File

@ -24,6 +24,7 @@ const props = defineProps<{
const emit = defineEmits<{
(e: 'select-host', host: Host): void
(e: 'new-host', groupId?: number): void
(e: 'delete-group', groupId: number): void
}>()
const expanded = ref<Set<number>>(new Set())
@ -57,15 +58,20 @@ function countHosts(group: HostGroup): number {
<div>
<!-- Group header -->
<div
class="flex items-center gap-1 px-3 py-1.5 cursor-pointer hover:bg-gray-800 text-gray-400 hover:text-gray-200 select-none"
class="flex items-center gap-1 px-3 py-1.5 cursor-pointer hover:bg-gray-800 text-gray-400 hover:text-gray-200 select-none group/grp"
@click="toggleGroup(group.id)"
>
<span class="text-xs w-3">{{ isExpanded(group.id) ? '▾' : '▸' }}</span>
<span class="font-medium truncate flex-1">{{ group.name }}</span>
<span class="text-xs text-gray-600 tabular-nums mr-1">{{ countHosts(group) }}</span>
<button
@click.stop="emit('delete-group', group.id)"
class="text-xs text-gray-600 hover:text-red-400 px-0.5 opacity-0 group-hover/grp:opacity-100 transition-opacity"
title="Delete group"
>×</button>
<button
@click.stop="emit('new-host', group.id)"
class="text-xs text-gray-600 hover:text-wraith-400 px-1"
class="text-xs text-gray-600 hover:text-wraith-400 px-0.5 opacity-0 group-hover/grp:opacity-100 transition-opacity"
title="Add host to group"
>+</button>
</div>
@ -78,6 +84,7 @@ function countHosts(group: HostGroup): number {
:groups="group.children"
@select-host="(h) => emit('select-host', h)"
@new-host="(gid) => emit('new-host', gid)"
@delete-group="(gid) => emit('delete-group', gid)"
/>
<!-- Hosts in this group -->

View File

@ -154,6 +154,13 @@ const recentHosts = computed(() => {
.slice(0, 5)
})
async function deleteGroup(groupId: number) {
const group = connections.groups.find((g: any) => g.id === groupId)
const name = group?.name || 'this group'
if (!confirm(`Delete "${name}"? Hosts in this group will become ungrouped.`)) return
await connections.deleteGroup(groupId)
}
async function deleteSelectedHost() {
if (!selectedHost.value) return
if (!confirm(`Delete "${selectedHost.value.name}"?`)) return
@ -185,7 +192,7 @@ async function deleteSelectedHost() {
<button @click="openNewHost()" class="text-xs text-gray-500 hover:text-wraith-400" title="New Host">+ Host</button>
</div>
</div>
<ConnectionsHostTree :groups="connections.groups" @select-host="selectHost" @new-host="openNewHost" />
<ConnectionsHostTree :groups="connections.groups" @select-host="selectHost" @new-host="openNewHost" @delete-group="deleteGroup" />
</aside>
<!-- Main: host grid with search + recent -->