Migrate frontend to plugin-based asset architecture

- Add equipmentApi and computersApi to replace legacy machinesApi
- Add controller vendor/model fields to Equipment model and forms
- Fix map marker navigation to use plugin-specific IDs (equipmentid,
  computerid, printerid, networkdeviceid) instead of assetid
- Fix search to use unified Asset table with correct plugin IDs
- Remove legacy printer search that used non-existent field names
- Enable optional JWT auth for detail endpoints (public read access)
- Clean up USB plugin models (remove unused checkout model)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-01-29 16:07:41 -05:00
parent c8b325d2e7
commit 180e6a0915
28 changed files with 4123 additions and 3454 deletions

View File

@@ -1,8 +1,8 @@
<template>
<div>
<div class="page-header">
<h2>PCs</h2>
<router-link to="/pcs/new" class="btn btn-primary">Add PC</router-link>
<h2>Computers</h2>
<router-link to="/pcs/new" class="btn btn-primary">Add Computer</router-link>
</div>
<!-- Filters -->
@@ -11,7 +11,7 @@
v-model="search"
type="text"
class="form-control"
placeholder="Search PCs..."
placeholder="Search computers..."
@input="debouncedSearch"
/>
</div>
@@ -24,41 +24,43 @@
<table>
<thead>
<tr>
<th>Machine #</th>
<th>Asset #</th>
<th>Hostname</th>
<th>Serial Number</th>
<th>PC Type</th>
<th>Type</th>
<th>Features</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="pc in pcs" :key="pc.machineid">
<td>{{ pc.machinenumber }}</td>
<td class="mono">{{ pc.serialnumber || '-' }}</td>
<td>{{ pc.pctype || '-' }}</td>
<tr v-for="item in computers" :key="item.assetid">
<td>{{ item.assetnumber }}</td>
<td>{{ item.computer?.hostname || '-' }}</td>
<td class="mono">{{ item.serialnumber || '-' }}</td>
<td>{{ item.computer?.computertype_name || '-' }}</td>
<td class="features">
<span v-if="pc.isvnc" class="feature-tag active">VNC</span>
<span v-if="pc.iswinrm" class="feature-tag active">WinRM</span>
<span v-if="!pc.isvnc && !pc.iswinrm">-</span>
<span v-if="item.computer?.isvnc" class="feature-tag active">VNC</span>
<span v-if="item.computer?.iswinrm" class="feature-tag active">WinRM</span>
<span v-if="!item.computer?.isvnc && !item.computer?.iswinrm">-</span>
</td>
<td>
<span class="badge" :class="getStatusClass(pc.status)">
{{ pc.status || 'Unknown' }}
<span class="badge" :class="getStatusClass(item.status_name)">
{{ item.status_name || 'Unknown' }}
</span>
</td>
<td class="actions">
<router-link
:to="`/pcs/${pc.machineid}`"
:to="`/pcs/${item.computer?.computerid || item.assetid}`"
class="btn btn-secondary btn-sm"
>
View
</router-link>
</td>
</tr>
<tr v-if="pcs.length === 0">
<td colspan="6" style="text-align: center; color: var(--text-light);">
No PCs found
<tr v-if="computers.length === 0">
<td colspan="7" style="text-align: center; color: var(--text-light);">
No computers found
</td>
</tr>
</tbody>
@@ -83,9 +85,9 @@
<script setup>
import { ref, onMounted } from 'vue'
import { machinesApi } from '../../api'
import { computersApi } from '../../api'
const pcs = ref([])
const computers = ref([])
const loading = ref(true)
const search = ref('')
const page = ref(1)
@@ -94,24 +96,23 @@ const totalPages = ref(1)
let searchTimeout = null
onMounted(() => {
loadPCs()
loadComputers()
})
async function loadPCs() {
async function loadComputers() {
loading.value = true
try {
const params = {
page: page.value,
perpage: 20,
category: 'PC'
per_page: 20
}
if (search.value) params.search = search.value
const response = await machinesApi.list(params)
pcs.value = response.data.data || []
const response = await computersApi.list(params)
computers.value = response.data.data || []
totalPages.value = response.data.meta?.pagination?.total_pages || 1
} catch (error) {
console.error('Error loading PCs:', error)
console.error('Error loading computers:', error)
} finally {
loading.value = false
}
@@ -121,13 +122,13 @@ function debouncedSearch() {
clearTimeout(searchTimeout)
searchTimeout = setTimeout(() => {
page.value = 1
loadPCs()
loadComputers()
}, 300)
}
function goToPage(p) {
page.value = p
loadPCs()
loadComputers()
}
function getStatusClass(status) {