Fix PC installed-applications rendering; minor UI cleanups
All checks were successful
CI / backend (push) Successful in 1m24s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 7s

The PC detail Installed Applications section 500d and vanished on any
real PC: ComputerInstalledApp had no to_dict, so the endpoint errored
and the v-if hid the section. Added the serializer (curated version
wins over the raw collected string, app name + description included)
and aligned PCDetail to the flat payload; regression test added.

Also: employee detail skips its USB panels when the usb plugin is
disabled (was firing 404s), and the shopfloor kiosk header is now
light-on-dark for readability.

810 tests pass; PC 259 installed apps verified live.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-12 13:37:58 -04:00
parent 68b6949f1c
commit d187a2c535
6 changed files with 104 additions and 9 deletions

View File

@@ -444,7 +444,7 @@ function handlePhotoError(e) {
.location-title {
font-size: 18px;
font-weight: 600;
color: #888;
color: #b8c4d8;
text-transform: uppercase;
letter-spacing: 2px;
}
@@ -452,6 +452,7 @@ function handlePhotoError(e) {
.header-center h1 {
font-size: 28px;
font-weight: 700;
color: #ffffff;
text-transform: uppercase;
letter-spacing: 2px;
margin: 0;

View File

@@ -64,7 +64,7 @@
</div>
<!-- Currently Checked Out USB Devices -->
<div class="section-card">
<div v-if="usbEnabled" class="section-card">
<h2 class="section-title">Checked Out USB Devices</h2>
<div v-if="usbLoading" class="loading">Loading...</div>
<div v-else-if="usbDevices.length === 0" class="empty">
@@ -99,7 +99,7 @@
</div>
<!-- USB Checkout History -->
<div class="section-card">
<div v-if="usbEnabled" class="section-card">
<h2 class="section-title">USB Checkout History</h2>
<div v-if="historyLoading" class="loading">Loading...</div>
<div v-else-if="checkoutHistory.length === 0" class="empty">
@@ -136,6 +136,7 @@
import { ref, computed, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { employeesApi, usbApi, notificationsApi } from '@/api'
import { isPluginEnabled, loadEnabledPlugins } from '@/composables/enabledPlugins'
import { useToast } from '../../composables/toast'
const toast = useToast()
@@ -145,6 +146,7 @@ const employee = ref(null)
const recognitions = ref([])
const usbDevices = ref([])
const checkoutHistory = ref([])
const usbEnabled = ref(true)
const loading = ref(true)
const recognitionsLoading = ref(true)
const usbLoading = ref(true)
@@ -175,7 +177,13 @@ const initials = computed(() => {
onMounted(async () => {
await loadEmployee()
await Promise.all([loadRecognitions(), loadUSBDevices(), loadCheckoutHistory()])
// Skip the USB panels entirely when the usb plugin is disabled - its
// /api/usb routes 404 otherwise and spam the console.
await loadEnabledPlugins()
usbEnabled.value = isPluginEnabled('usb')
const tasks = [loadRecognitions()]
if (usbEnabled.value) tasks.push(loadUSBDevices(), loadCheckoutHistory())
await Promise.all(tasks)
})
async function loadEmployee() {

View File

@@ -191,15 +191,15 @@
<router-link
v-for="app in installedApps"
:key="app.id"
:to="`/applications/${app.application?.appid}`"
:to="`/applications/${app.appid}`"
class="app-item"
>
<div class="app-info">
<span class="app-name">{{ app.application?.appname }}</span>
<span class="app-version" v-if="app.version">v{{ app.version }}</span>
<span class="app-name">{{ app.appname }}</span>
<span class="app-version" v-if="app.installedversion">v{{ app.installedversion }}</span>
</div>
<div class="app-desc" v-if="app.application?.appdescription">
{{ app.application.appdescription }}
<div class="app-desc" v-if="app.appdescription">
{{ app.appdescription }}
</div>
</router-link>
</div>