Relocate warranty, measuringtools, network, printers, usb, notifications, computers, and slides into plugins/<name>/frontend/. Each plugin's views are pulled from wherever they lived (own dir, plus the shared views/settings/, views/reports/, views/print/ dirs, and top-level views) into the plugin's frontend/views/, and its route file becomes the self-contained routes.js. Handled the messy cases: - computers: name mismatch (its views live in views/pcs/) - moved by following the route file's own imports, so the dir name did not matter. Its OS/access- protocol/PC-type settings views move with it (only computers.js routed them). - network: NetworkHub's sibling sub-views (NetworkDevicesList, SubnetsBrowse, not directly routed) moved too so its `./` imports resolve. - printers: the qrLogo helper is SHARED with core AssetLabel, so it stays in views/print/ and PrinterQR imports it via @/views/print/qrLogo. - slides: route file is toplevel-only (TVDashboard); SlideManager stays core (core.js routes /settings/slides). frontend/src/views/ now holds only core views; frontend/src/router/routes/ holds only core.js. All 13 plugins are self-contained under plugins/<name>/frontend/. Verified live: Network (hub + moved sub-views), Computers (name mismatch), GE-Enforce (helper), printedparts all render from their staged frontends. Build + 58 vitest + naming green.
89 lines
3.3 KiB
Vue
89 lines
3.3 KiB
Vue
<template>
|
|
<div class="detail-page">
|
|
<div v-if="loading" class="loading">Loading...</div>
|
|
<div v-else-if="!subnet" class="empty-state"><p>Network not found.</p></div>
|
|
<template v-else>
|
|
<div class="page-header">
|
|
<h1>{{ subnet.name || subnet.cidr }}</h1>
|
|
<router-link to="/networks" class="btn btn-secondary">Back to Networks</router-link>
|
|
</div>
|
|
|
|
<div class="content-grid">
|
|
<div class="content-column">
|
|
<div class="section-card">
|
|
<h3 class="section-title">Network</h3>
|
|
<div class="info-list">
|
|
<div class="info-row"><span class="info-label">CIDR</span><span class="info-value mono">{{ subnet.cidr }}</span></div>
|
|
<div class="info-row"><span class="info-label">Network Address</span><span class="info-value mono">{{ subnet.networkaddress || '-' }}</span></div>
|
|
<div class="info-row"><span class="info-label">Type</span><span class="info-value">{{ subnet.subnettype || '-' }}</span></div>
|
|
<div class="info-row"><span class="info-label">VLAN</span><span class="info-value">{{ subnet.vlannumber || subnet.vlanid || '-' }}</span></div>
|
|
<div class="info-row" v-if="subnet.gatewayip"><span class="info-label">Gateway</span><span class="info-value mono">{{ subnet.gatewayip }}</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section-card" v-if="subnet.description">
|
|
<h3 class="section-title">Notes</h3>
|
|
<div class="notes-content">{{ subnet.description }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content-column">
|
|
<div class="section-card">
|
|
<h3 class="section-title">Devices on this network ({{ devices.length }})</h3>
|
|
<div v-if="devices.length === 0" class="empty-state"><p>No devices found in this range.</p></div>
|
|
<div v-else class="table-container">
|
|
<table>
|
|
<thead>
|
|
<tr><th>Device</th><th>IP</th><th>Type</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="dev in devices" :key="dev.assetid">
|
|
<td>
|
|
<router-link v-if="dev.url" :to="dev.url">{{ dev.name || dev.assetnumber }}</router-link>
|
|
<span v-else>{{ dev.name || dev.assetnumber }}</span>
|
|
</td>
|
|
<td class="mono">{{ dev.ipaddress }}</td>
|
|
<td>{{ typeLabel(dev.assettype) }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { useRoute } from 'vue-router'
|
|
import { networkApi } from '@/api'
|
|
|
|
const route = useRoute()
|
|
const subnet = ref(null)
|
|
const loading = ref(true)
|
|
|
|
const devices = computed(() => subnet.value?.devices || [])
|
|
|
|
const TYPE_LABELS = {
|
|
computer: 'PC', network_device: 'Network Device', printer: 'Printer',
|
|
machine: 'Machine', measuring_tool: 'Measuring Tool',
|
|
}
|
|
function typeLabel(type) {
|
|
return TYPE_LABELS[type] || type || '-'
|
|
}
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
try {
|
|
const response = await networkApi.subnets.get(route.params.id)
|
|
subnet.value = response.data?.data || response.data
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
onMounted(load)
|
|
</script>
|