Warranty polish: hero badges everywhere, search/pagination, re-check, shared apiError

- Shared utils/apiError.js reads the correct nested error message (with
  fallbacks); swept 37 views/components off the shallow path so real backend
  messages (e.g. in-use 409s) surface instead of generic "Failed".
- useWarrantyBadge composable: warranty hero status/end-date badge now on PC,
  equipment, printer, and network detail heroes (one shared fetch feeds the
  badge + the WarrantyPanel).
- Warranties list: client-side search (vendor/level/tag/asset) + pagination;
  truncate long service levels so they stop blowing out the table width.
- "Re-check all" button + POST /warranty/sync/dell?all=true to re-pull dated
  Dell warranties, not just missing ones.
- Deprecate the standalone pxe-images/warranty_sync.py in favor of the plugin.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-09 17:23:21 -04:00
parent 640b8de1b2
commit ec2de635ed
46 changed files with 4091 additions and 3968 deletions

View File

@@ -0,0 +1,44 @@
// Shared warranty fetch + hero-badge derivation for asset detail pages.
// Pass a getter for the asset id; get back the warranties list (to feed a
// WarrantyPanel) and a heroWarranty for a compact status badge.
import { ref, computed, watch } from 'vue'
import { warrantyApi } from '../api'
const STATUS_RANK = { expired: 0, expiring: 1, active: 2, unknown: 3 }
const STATUS_LABELS = {
active: 'Under Warranty',
expiring: 'Warranty Expiring',
expired: 'Warranty Expired',
unknown: 'Warranty',
}
export function useWarrantyBadge(getAssetId) {
const warranties = ref([])
// Worst-case warranty drives the badge: expired > expiring > active > unknown.
const heroWarranty = computed(() => {
if (!warranties.value.length) return null
const worst = [...warranties.value]
.sort((a, b) => (STATUS_RANK[a.status] ?? 9) - (STATUS_RANK[b.status] ?? 9))[0]
return { ...worst, label: STATUS_LABELS[worst.status] || 'Warranty' }
})
function warrantyDate(d) {
return d ? new Date(d + 'T00:00:00').toLocaleDateString() : ''
}
async function load() {
const assetid = getAssetId()
if (!assetid) { warranties.value = []; return }
try {
const response = await warrantyApi.forAsset(assetid)
warranties.value = response.data.data || []
} catch (err) {
warranties.value = []
}
}
watch(getAssetId, load, { immediate: true })
return { warranties, heroWarranty, warrantyDate, reloadWarranties: load }
}