Network devices: manage buttons where every other asset keeps them

Machines, PCs, printers and measuring tools all carry Print Label / Edit /
Retire / Back to List in a page header. A network device had no header at all:
Edit was tucked inside the hero title row, and Print Label and Delete sat in a
bar at the very bottom of the page, past every card. Managing one meant looking
somewhere different from every other asset type.

They move to the standard header. The bottom bar is removed rather than left as
a second copy, and the two delete handlers collapse into one - the route is a
soft delete, so it is called Retire here as it is everywhere else, and the
confirm says what is kept.
This commit is contained in:
cproudlock
2026-08-27 09:25:45 -04:00
parent 933740aae4
commit 21e66c6749

View File

@@ -1,5 +1,25 @@
<template>
<div class="detail-page" v-if="device">
<!--
The same page-header + header-actions block every other asset detail page
uses. This page had no header at all: Edit was tucked inside the hero
title row and there was no Print Label, no Retire and no way back to the
list, so managing a network device meant looking somewhere different from
every other asset type.
-->
<div class="page-header">
<h2>Network Device Details</h2>
<div class="header-actions">
<router-link :to="`/print/asset-label/network_device/${deviceId}`"
class="btn btn-secondary" target="_blank">Print Label</router-link>
<router-link v-if="authStore.isAuthenticated" :to="`/network/${deviceId}/edit`"
class="btn btn-primary">Edit</router-link>
<button v-if="authStore.isAuthenticated" @click="confirmRetire"
class="btn btn-danger">Retire</button>
<router-link to="/network" class="btn btn-secondary">Back to List</router-link>
</div>
</div>
<div class="hero-card">
<div class="hero-image">
<img v-if="device.networkdevice?.imageurl" :src="withBase(device.networkdevice.imageurl)" alt="Model photo" />
@@ -10,13 +30,6 @@
<div class="hero-content">
<div class="hero-title-row">
<h1 class="hero-title">{{ device.networkdevice?.hostname || device.name || device.assetnumber }}</h1>
<router-link
v-if="authStore.isAuthenticated"
:to="`/network/${deviceId}/edit`"
class="btn btn-secondary"
>
Edit
</router-link>
</div>
<div class="hero-meta">
<span class="badge" :style="colorStyle(device.statuscolor)">
@@ -184,18 +197,9 @@
</div>
</div>
<!-- Actions -->
<div class="action-bar" v-if="authStore.isAuthenticated">
<router-link :to="`/print/asset-label/network_device/${deviceId}`" class="btn btn-secondary" target="_blank">
Print Label
</router-link>
<router-link :to="`/network/${deviceId}/edit`" class="btn btn-primary">
Edit Device
</router-link>
<button @click="confirmDelete" class="btn btn-danger">
Delete Device
</button>
</div>
<!-- The manage actions live in the page header, where every other asset
detail page puts them. They used to sit down here instead, which is
why finding them on a network device meant looking somewhere else. -->
<!-- Audit Footer -->
<div class="audit-footer">
@@ -228,6 +232,7 @@ import PluginAssetPanels from '@/components/PluginAssetPanels.vue'
import { useWarrantyBadge } from '@/composables/warrantyBadge'
import { useIdentifierFlags } from '@/composables/identifierSettings'
import { useToast } from '@/composables/toast'
import { apiError } from '@/utils/apiError'
import { setRecordTitle } from '@/composables/pageTitle'
const toast = useToast()
@@ -293,17 +298,24 @@ function formatDate(dateStr) {
})
}
async function confirmDelete() {
if (confirm(`Are you sure you want to delete ${device.value.networkdevice?.hostname || device.value.assetnumber}?`)) {
try {
await networkApi.delete(deviceId)
router.push('/network')
} catch (error) {
console.error('Error deleting device:', error)
toast.error('Failed to delete device')
}
// Soft delete, like every other asset type: the record leaves the lists while
// its history and relationships stay put, and it can be restored by setting
// isactive back. Called Retire rather than Delete for exactly that reason.
async function confirmRetire () {
const label = device.value?.networkdevice?.hostname
|| device.value?.name || device.value?.assetnumber || 'this device'
if (!confirm(`Retire ${label}?\n\nIt will no longer appear in ShopDB. `
+ `History and relationships are kept, and it can be restored.`)) return
try {
await networkApi.delete(deviceId)
toast.success(`Retired ${label}`)
router.push('/network')
} catch (error) {
console.error('Error retiring network device:', error)
toast.error(apiError(error, 'Failed to retire network device'))
}
}
</script>
<style scoped>