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<{ const emit = defineEmits<{
(e: 'select-host', host: Host): void (e: 'select-host', host: Host): void
(e: 'new-host', groupId?: number): void (e: 'new-host', groupId?: number): void
(e: 'delete-group', groupId: number): void
}>() }>()
const expanded = ref<Set<number>>(new Set()) const expanded = ref<Set<number>>(new Set())
@ -57,15 +58,20 @@ function countHosts(group: HostGroup): number {
<div> <div>
<!-- Group header --> <!-- Group header -->
<div <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)" @click="toggleGroup(group.id)"
> >
<span class="text-xs w-3">{{ isExpanded(group.id) ? '▾' : '▸' }}</span> <span class="text-xs w-3">{{ isExpanded(group.id) ? '▾' : '▸' }}</span>
<span class="font-medium truncate flex-1">{{ group.name }}</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> <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 <button
@click.stop="emit('new-host', group.id)" @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" title="Add host to group"
>+</button> >+</button>
</div> </div>
@ -78,6 +84,7 @@ function countHosts(group: HostGroup): number {
:groups="group.children" :groups="group.children"
@select-host="(h) => emit('select-host', h)" @select-host="(h) => emit('select-host', h)"
@new-host="(gid) => emit('new-host', gid)" @new-host="(gid) => emit('new-host', gid)"
@delete-group="(gid) => emit('delete-group', gid)"
/> />
<!-- Hosts in this group --> <!-- Hosts in this group -->

View File

@ -154,6 +154,13 @@ const recentHosts = computed(() => {
.slice(0, 5) .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() { async function deleteSelectedHost() {
if (!selectedHost.value) return if (!selectedHost.value) return
if (!confirm(`Delete "${selectedHost.value.name}"?`)) 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> <button @click="openNewHost()" class="text-xs text-gray-500 hover:text-wraith-400" title="New Host">+ Host</button>
</div> </div>
</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> </aside>
<!-- Main: host grid with search + recent --> <!-- Main: host grid with search + recent -->