Add print badges, pagination, route splitting, JWT auth fixes, and list page alignment

- Fix equipment badge barcode not rendering (loading race condition)
- Fix printer QR code not rendering on initial load (same race condition)
- Add model image to equipment badge via imageurl from Model table
- Fix white-on-white machine number text on badge, tighten barcode spacing
- Add PaginationBar component used across all list pages
- Split monolithic router into per-plugin route modules
- Fix 25 GET API endpoints returning 401 (jwt_required -> optional=True)
- Align list page columns across Equipment, PCs, and Network pages
- Add print views: EquipmentBadge, PrinterQRSingle, PrinterQRBatch, USBLabelBatch
- Add PC Relationships report, migration docs, and CLAUDE.md project guide
- Various plugin model, API, and frontend refinements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-02-04 07:32:44 -05:00
parent fe7a00b260
commit 83caaa7b7c
89 changed files with 3951 additions and 1138 deletions

View File

@@ -130,10 +130,10 @@
<h3 class="form-section-title">Controller</h3>
<div class="form-row">
<div class="form-group">
<label for="controller_vendorid">Controller Vendor</label>
<label for="controllervendorid">Controller Vendor</label>
<select
id="controller_vendorid"
v-model="form.controller_vendorid"
id="controllervendorid"
v-model="form.controllervendorid"
class="form-control"
>
<option value="">Select vendor...</option>
@@ -149,10 +149,10 @@
</div>
<div class="form-group">
<label for="controller_modelid">Controller Model</label>
<label for="controllermodelid">Controller Model</label>
<select
id="controller_modelid"
v-model="form.controller_modelid"
id="controllermodelid"
v-model="form.controllermodelid"
class="form-control"
>
<option value="">Select model...</option>
@@ -164,7 +164,7 @@
{{ m.modelnumber }}
</option>
</select>
<small class="form-help" v-if="form.controller_vendorid">Filtered by controller vendor</small>
<small class="form-help" v-if="form.controllervendorid">Filtered by controller vendor</small>
</div>
</div>
@@ -351,8 +351,8 @@ const form = ref({
equipmenttypeid: '',
vendorid: '',
modelnumberid: '',
controller_vendorid: '',
controller_modelid: '',
controllervendorid: '',
controllermodelid: '',
locationid: '',
businessunitid: '',
requiresmanualconfig: false,
@@ -383,8 +383,8 @@ const filteredModels = computed(() => {
// Filter models by selected controller vendor
const filteredControllerModels = computed(() => {
if (!form.value.controller_vendorid) return models.value
return models.value.filter(m => m.vendorid === form.value.controller_vendorid)
if (!form.value.controllervendorid) return models.value
return models.value.filter(m => m.vendorid === form.value.controllervendorid)
})
// Clear model selection when vendor changes
@@ -398,11 +398,11 @@ watch(() => form.value.vendorid, (newVal, oldVal) => {
})
// Clear controller model when controller vendor changes
watch(() => form.value.controller_vendorid, (newVal, oldVal) => {
watch(() => form.value.controllervendorid, (newVal, oldVal) => {
if (oldVal && newVal !== oldVal) {
const currentModel = models.value.find(m => m.modelnumberid === form.value.controller_modelid)
const currentModel = models.value.find(m => m.modelnumberid === form.value.controllermodelid)
if (currentModel && currentModel.vendorid !== newVal) {
form.value.controller_modelid = ''
form.value.controllermodelid = ''
}
}
})
@@ -413,11 +413,11 @@ onMounted(async () => {
const [typesRes, statusRes, vendorRes, locRes, modelsRes, buRes, pcsRes, relTypesRes] = await Promise.all([
equipmentApi.types.list(),
assetsApi.statuses.list(),
vendorsApi.list({ per_page: 500 }),
locationsApi.list({ per_page: 500 }),
modelsApi.list({ per_page: 1000 }),
businessunitsApi.list({ per_page: 500 }),
computersApi.list({ per_page: 500 }),
vendorsApi.list({ perpage: 500 }),
locationsApi.list({ perpage: 500 }),
modelsApi.list({ perpage: 1000 }),
businessunitsApi.list({ perpage: 500 }),
computersApi.list({ perpage: 500 }),
assetsApi.types.list() // Used for relationship types, will fix below
])
@@ -461,8 +461,8 @@ onMounted(async () => {
equipmenttypeid: data.equipment?.equipmenttypeid || '',
vendorid: data.equipment?.vendorid || '',
modelnumberid: data.equipment?.modelnumberid || '',
controller_vendorid: data.equipment?.controller_vendorid || '',
controller_modelid: data.equipment?.controller_modelid || '',
controllervendorid: data.equipment?.controllervendorid || '',
controllermodelid: data.equipment?.controllermodelid || '',
locationid: data.locationid || '',
businessunitid: data.businessunitid || '',
requiresmanualconfig: data.equipment?.requiresmanualconfig || false,
@@ -480,8 +480,8 @@ onMounted(async () => {
// Check incoming relationships for a controlling PC
for (const rel of relationships.incoming || []) {
if (rel.source_asset?.assettype_name === 'computer' && rel.relationship_type_name === 'Controls') {
controllingPcId.value = rel.source_asset.assetid
if (rel.sourceasset?.assettypename === 'computer' && rel.relationshiptypename === 'Controls') {
controllingPcId.value = rel.sourceasset.assetid
relationshipTypeId.value = rel.relationshiptypeid
existingRelationshipId.value = rel.assetrelationshipid
break
@@ -531,8 +531,8 @@ async function saveEquipment() {
equipmenttypeid: form.value.equipmenttypeid || null,
vendorid: form.value.vendorid || null,
modelnumberid: form.value.modelnumberid || null,
controller_vendorid: form.value.controller_vendorid || null,
controller_modelid: form.value.controller_modelid || null,
controllervendorid: form.value.controllervendorid || null,
controllermodelid: form.value.controllermodelid || null,
locationid: form.value.locationid || null,
businessunitid: form.value.businessunitid || null,
requiresmanualconfig: form.value.requiresmanualconfig,
@@ -588,8 +588,8 @@ async function saveRelationship(assetId) {
// Create new relationship (PC controls Equipment, so PC is source, Equipment is target)
await assetsApi.createRelationship({
source_assetid: controllingPcId.value,
target_assetid: assetId,
sourceassetid: controllingPcId.value,
targetassetid: assetId,
relationshiptypeid: relationshipTypeId.value
})
}