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.
73 lines
1.8 KiB
Vue
73 lines
1.8 KiB
Vue
<template>
|
|
<div>
|
|
<div class="page-header">
|
|
<h1>Network</h1>
|
|
</div>
|
|
<div class="hub-tabs">
|
|
<button
|
|
v-for="tab in tabs"
|
|
:key="tab.key"
|
|
class="hub-tab"
|
|
:class="{ active: active === tab.key }"
|
|
@click="setTab(tab.key)"
|
|
>{{ tab.label }}</button>
|
|
</div>
|
|
<component :is="current" />
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, watch } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import NetworkDevicesList from './NetworkDevicesList.vue'
|
|
import SubnetsBrowse from './SubnetsBrowse.vue'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
|
|
// VLANs are a layer under a subnet (each Networks row shows its VLAN); VLAN
|
|
// naming lives in Settings, so the hub is just Devices + Networks.
|
|
const tabs = [
|
|
{ key: 'devices', label: 'Devices', comp: NetworkDevicesList },
|
|
{ key: 'networks', label: 'Networks', comp: SubnetsBrowse },
|
|
]
|
|
|
|
const active = ref(tabs.some(t => t.key === route.query.tab) ? route.query.tab : 'devices')
|
|
const current = computed(() => (tabs.find(t => t.key === active.value) || tabs[0]).comp)
|
|
|
|
function setTab(key) {
|
|
active.value = key
|
|
router.replace({ query: { ...route.query, tab: key } })
|
|
}
|
|
|
|
watch(() => route.query.tab, (value) => {
|
|
if (value && value !== active.value && tabs.some(t => t.key === value)) {
|
|
active.value = value
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.hub-tabs {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
border-bottom: 1px solid var(--border);
|
|
margin-bottom: 1.25rem;
|
|
}
|
|
.hub-tab {
|
|
background: none;
|
|
border: none;
|
|
border-bottom: 2px solid transparent;
|
|
padding: 0.6rem 1rem;
|
|
cursor: pointer;
|
|
color: var(--text-light);
|
|
font-size: 0.95rem;
|
|
font-weight: 500;
|
|
}
|
|
.hub-tab:hover { color: var(--text); }
|
|
.hub-tab.active {
|
|
color: var(--primary);
|
|
border-bottom-color: var(--primary);
|
|
}
|
|
</style>
|