| {{ w.vendor }} |
- {{ w.servicelevel || '-' }} |
+ {{ w.servicelevel || '-' }} |
{{ w.enddate ? formatDate(w.enddate) : '-' }} |
{{ a.assetnumber }}
@@ -100,4 +100,5 @@ onMounted(async () => {
background: var(--bg); border-radius: 12px; font-size: 0.8rem; text-decoration: none; color: var(--text);
}
.muted { color: var(--text-light); }
+.servicelevel-cell { max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
diff --git a/frontend/src/views/settings/AccessProtocolsList.vue b/frontend/src/views/settings/AccessProtocolsList.vue
index 14c571f..ec4b71b 100644
--- a/frontend/src/views/settings/AccessProtocolsList.vue
+++ b/frontend/src/views/settings/AccessProtocolsList.vue
@@ -92,6 +92,7 @@
diff --git a/frontend/src/views/settings/DashboardDefaultsList.vue b/frontend/src/views/settings/DashboardDefaultsList.vue
index 7b0653b..17a9b64 100644
--- a/frontend/src/views/settings/DashboardDefaultsList.vue
+++ b/frontend/src/views/settings/DashboardDefaultsList.vue
@@ -105,6 +105,7 @@
import { ref, onMounted } from 'vue'
import { dashboardDefaultsApi, businessUnitsApi } from '../../api'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const items = ref([])
@@ -168,7 +169,7 @@ async function save() {
closeModal()
loadData()
} catch (err) {
- error.value = err.response?.data?.message || 'Failed to save'
+ error.value = apiError(err, 'Failed to save')
} finally {
saving.value = false
}
diff --git a/frontend/src/views/settings/EquipmentTypesList.vue b/frontend/src/views/settings/EquipmentTypesList.vue
index 6b4d2eb..29c901b 100644
--- a/frontend/src/views/settings/EquipmentTypesList.vue
+++ b/frontend/src/views/settings/EquipmentTypesList.vue
@@ -77,6 +77,7 @@ import { equipmentApi } from '../../api'
import ColorSwatchPicker from '@/components/ColorSwatchPicker.vue'
import { colorStyle } from '@/utils/colorStyle'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const items = ref([])
@@ -126,7 +127,7 @@ async function save() {
closeModal()
loadData()
} catch (err) {
- error.value = err.response?.data?.error?.message || err.response?.data?.message || 'Failed to save'
+ error.value = apiError(err, 'Failed to save')
} finally {
saving.value = false
}
@@ -138,7 +139,7 @@ async function deleteType(t) {
await equipmentApi.types.remove(t.equipmenttypeid)
loadData()
} catch (err) {
- toast.error(err.response?.data?.error?.message || err.response?.data?.message || 'Failed to delete')
+ toast.error(apiError(err, 'Failed to delete'))
}
}
diff --git a/frontend/src/views/settings/LocationTypesList.vue b/frontend/src/views/settings/LocationTypesList.vue
index 616b262..c71115b 100644
--- a/frontend/src/views/settings/LocationTypesList.vue
+++ b/frontend/src/views/settings/LocationTypesList.vue
@@ -77,6 +77,7 @@ import { locationsApi } from '../../api'
import ColorSwatchPicker from '@/components/ColorSwatchPicker.vue'
import { colorStyle } from '@/utils/colorStyle'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const items = ref([])
@@ -126,7 +127,7 @@ async function save() {
closeModal()
loadData()
} catch (err) {
- error.value = err.response?.data?.error?.message || err.response?.data?.message || 'Failed to save'
+ error.value = apiError(err, 'Failed to save')
} finally {
saving.value = false
}
@@ -138,7 +139,7 @@ async function deleteType(t) {
await locationsApi.types.remove(t.locationtypeid)
loadData()
} catch (err) {
- toast.error(err.response?.data?.error?.message || err.response?.data?.message || 'Failed to delete')
+ toast.error(apiError(err, 'Failed to delete'))
}
}
diff --git a/frontend/src/views/settings/LocationsList.vue b/frontend/src/views/settings/LocationsList.vue
index 2ac8a98..492ff07 100644
--- a/frontend/src/views/settings/LocationsList.vue
+++ b/frontend/src/views/settings/LocationsList.vue
@@ -212,6 +212,7 @@ import { ref, computed, onMounted } from 'vue'
import { locationsApi } from '../../api'
import PaginationBar from '../../components/PaginationBar.vue'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const locations = ref([])
@@ -354,7 +355,7 @@ async function saveLocation() {
loadLocations()
} catch (err) {
console.error('Error saving location:', err)
- error.value = err.response?.data?.message || 'Failed to save location'
+ error.value = apiError(err, 'Failed to save location')
} finally {
saving.value = false
}
diff --git a/frontend/src/views/settings/MachineTypesList.vue b/frontend/src/views/settings/MachineTypesList.vue
index 16ca6b5..84ec488 100644
--- a/frontend/src/views/settings/MachineTypesList.vue
+++ b/frontend/src/views/settings/MachineTypesList.vue
@@ -146,6 +146,7 @@ import { ref, onMounted } from 'vue'
import { machinetypesApi } from '../../api'
import PaginationBar from '../../components/PaginationBar.vue'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const machineTypes = ref([])
@@ -239,7 +240,7 @@ async function saveType() {
loadTypes()
} catch (err) {
console.error('Error saving machine type:', err)
- error.value = err.response?.data?.message || 'Failed to save machine type'
+ error.value = apiError(err, 'Failed to save machine type')
} finally {
saving.value = false
}
diff --git a/frontend/src/views/settings/ModelSuppliesList.vue b/frontend/src/views/settings/ModelSuppliesList.vue
index 41497fd..421959e 100644
--- a/frontend/src/views/settings/ModelSuppliesList.vue
+++ b/frontend/src/views/settings/ModelSuppliesList.vue
@@ -147,6 +147,7 @@
diff --git a/frontend/src/views/settings/OperatingSystemsList.vue b/frontend/src/views/settings/OperatingSystemsList.vue
index 4d07911..9dd56d0 100644
--- a/frontend/src/views/settings/OperatingSystemsList.vue
+++ b/frontend/src/views/settings/OperatingSystemsList.vue
@@ -120,6 +120,7 @@ import { ref, onMounted } from 'vue'
import { operatingsystemsApi } from '../../api'
import PaginationBar from '../../components/PaginationBar.vue'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const items = ref([])
@@ -193,7 +194,7 @@ async function save() {
closeModal()
loadData()
} catch (err) {
- error.value = err.response?.data?.message || 'Failed to save'
+ error.value = apiError(err, 'Failed to save')
} finally {
saving.value = false
}
diff --git a/frontend/src/views/settings/PCTypesList.vue b/frontend/src/views/settings/PCTypesList.vue
index 61e2871..0118bfd 100644
--- a/frontend/src/views/settings/PCTypesList.vue
+++ b/frontend/src/views/settings/PCTypesList.vue
@@ -87,6 +87,7 @@ import { computersApi } from '../../api'
import ColorSwatchPicker from '@/components/ColorSwatchPicker.vue'
import { colorStyle } from '@/utils/colorStyle'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const pcTypes = ref([])
@@ -132,7 +133,7 @@ async function deleteType(pt) {
await computersApi.types.remove(pt.computertypeid)
loadData()
} catch (err) {
- toast.error(err.response?.data?.error?.message || err.response?.data?.message || 'Failed to delete')
+ toast.error(apiError(err, 'Failed to delete'))
}
}
@@ -148,7 +149,7 @@ async function save() {
closeModal()
loadData()
} catch (err) {
- error.value = err.response?.data?.message || 'Failed to save'
+ error.value = apiError(err, 'Failed to save')
} finally {
saving.value = false
}
diff --git a/frontend/src/views/settings/PrinterDriversList.vue b/frontend/src/views/settings/PrinterDriversList.vue
index 3eb5b52..efa2d14 100644
--- a/frontend/src/views/settings/PrinterDriversList.vue
+++ b/frontend/src/views/settings/PrinterDriversList.vue
@@ -98,6 +98,7 @@
import { ref, computed, onMounted } from 'vue'
import { printersApi } from '../../api'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const items = ref([])
@@ -161,7 +162,7 @@ async function save() {
closeModal()
loadData()
} catch (err) {
- error.value = err.response?.data?.error?.message || err.response?.data?.message || 'Failed to save'
+ error.value = apiError(err, 'Failed to save')
} finally {
saving.value = false
}
@@ -173,7 +174,7 @@ async function deleteDriver(d) {
await printersApi.drivers.delete(d.driverid)
loadData()
} catch (err) {
- toast.error(err.response?.data?.error?.message || err.response?.data?.message || 'Failed to delete')
+ toast.error(apiError(err, 'Failed to delete'))
}
}
diff --git a/frontend/src/views/settings/PrinterTypesList.vue b/frontend/src/views/settings/PrinterTypesList.vue
index ef05974..7510cd0 100644
--- a/frontend/src/views/settings/PrinterTypesList.vue
+++ b/frontend/src/views/settings/PrinterTypesList.vue
@@ -77,6 +77,7 @@ import { printersApi } from '../../api'
import ColorSwatchPicker from '@/components/ColorSwatchPicker.vue'
import { colorStyle } from '@/utils/colorStyle'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const items = ref([])
@@ -126,7 +127,7 @@ async function save() {
closeModal()
loadData()
} catch (err) {
- error.value = err.response?.data?.error?.message || err.response?.data?.message || 'Failed to save'
+ error.value = apiError(err, 'Failed to save')
} finally {
saving.value = false
}
@@ -138,7 +139,7 @@ async function deleteType(t) {
await printersApi.types.remove(t.printertypeid)
loadData()
} catch (err) {
- toast.error(err.response?.data?.error?.message || err.response?.data?.message || 'Failed to delete')
+ toast.error(apiError(err, 'Failed to delete'))
}
}
diff --git a/frontend/src/views/settings/RelationshipTypesList.vue b/frontend/src/views/settings/RelationshipTypesList.vue
index 8a79490..3615c23 100644
--- a/frontend/src/views/settings/RelationshipTypesList.vue
+++ b/frontend/src/views/settings/RelationshipTypesList.vue
@@ -77,6 +77,7 @@ import { relationshipTypesApi } from '../../api'
import ColorSwatchPicker from '@/components/ColorSwatchPicker.vue'
import { colorStyle } from '@/utils/colorStyle'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const items = ref([])
@@ -126,7 +127,7 @@ async function save() {
closeModal()
loadData()
} catch (err) {
- error.value = err.response?.data?.error?.message || err.response?.data?.message || 'Failed to save'
+ error.value = apiError(err, 'Failed to save')
} finally {
saving.value = false
}
@@ -138,7 +139,7 @@ async function deleteType(t) {
await relationshipTypesApi.remove(t.relationshiptypeid)
loadData()
} catch (err) {
- toast.error(err.response?.data?.error?.message || err.response?.data?.message || 'Failed to delete')
+ toast.error(apiError(err, 'Failed to delete'))
}
}
diff --git a/frontend/src/views/settings/SiteSettings.vue b/frontend/src/views/settings/SiteSettings.vue
index 4501f11..00d5f69 100644
--- a/frontend/src/views/settings/SiteSettings.vue
+++ b/frontend/src/views/settings/SiteSettings.vue
@@ -31,6 +31,7 @@
diff --git a/frontend/src/views/settings/SystemSettings.vue b/frontend/src/views/settings/SystemSettings.vue
index 366631a..c117ba1 100644
--- a/frontend/src/views/settings/SystemSettings.vue
+++ b/frontend/src/views/settings/SystemSettings.vue
@@ -657,6 +657,7 @@ import { ref, reactive, onMounted, computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import { settingsApi, computersApi } from '../../api'
import { setIdentifierFlag } from '../../composables/identifierSettings'
+import { apiError } from '../../utils/apiError'
// Section tabs - one section visible at a time to avoid a long scroll. The
// search box filters tabs (and, while searching, shows every matching section).
@@ -900,7 +901,7 @@ async function changePcTypeMapping(pxetype, computertype) {
success.value = 'Setting saved'
setTimeout(() => { success.value = '' }, 2000)
} catch (e) {
- error.value = e.response?.data?.message || 'Failed to save setting'
+ error.value = apiError(e, 'Failed to save setting')
console.error(e)
} finally {
saving.value = false
@@ -943,7 +944,7 @@ async function toggleIdentifier(name, assettype) {
success.value = 'Setting saved'
setTimeout(() => { success.value = '' }, 2000)
} catch (e) {
- error.value = e.response?.data?.message || 'Failed to save setting'
+ error.value = apiError(e, 'Failed to save setting')
console.error(e)
} finally {
saving.value = false
@@ -977,7 +978,7 @@ async function toggleSearchDomain(domainKey) {
success.value = 'Setting saved'
setTimeout(() => { success.value = '' }, 2000)
} catch (e) {
- error.value = e.response?.data?.message || 'Failed to save setting'
+ error.value = apiError(e, 'Failed to save setting')
console.error(e)
} finally {
saving.value = false
@@ -996,7 +997,7 @@ async function saveSetting(key, value) {
success.value = 'Setting saved'
setTimeout(() => { success.value = '' }, 2000)
} catch (e) {
- error.value = e.response?.data?.message || 'Failed to save setting'
+ error.value = apiError(e, 'Failed to save setting')
console.error(e)
} finally {
saving.value = false
@@ -1013,7 +1014,7 @@ async function testEmail() {
// await settingsApi.testEmail()
success.value = 'Test email feature coming soon'
} catch (e) {
- error.value = e.response?.data?.message || 'Failed to send test email'
+ error.value = apiError(e, 'Failed to send test email')
} finally {
testingEmail.value = false
setTimeout(() => { success.value = '' }, 3000)
diff --git a/frontend/src/views/settings/UsersList.vue b/frontend/src/views/settings/UsersList.vue
index 6b6b8c4..f9dc557 100644
--- a/frontend/src/views/settings/UsersList.vue
+++ b/frontend/src/views/settings/UsersList.vue
@@ -1,745 +1,746 @@
-
-
-
-
-
-
-
-
- | Username |
- Email |
- Name |
- Roles |
- Status |
- Last Login |
- Actions |
-
-
-
-
- | Loading... |
-
-
- | No users found |
-
-
- | {{ user.username }} |
- {{ user.email }} |
- {{ [user.firstname, user.lastname].filter(Boolean).join(' ') || '-' }} |
-
-
- {{ role.rolename }}
-
- None
- |
-
- Locked
- Inactive
- Active
- |
- {{ formatDate(user.lastlogindate) }} |
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- | Role Name |
- Description |
- Permissions |
- Users |
- Actions |
-
-
-
-
- |
-
- {{ role.rolename }}
-
- |
- {{ role.description || '-' }} |
-
- All permissions
- {{ role.permissions.length }} permissions
- None
- |
- {{ role.usercount }} |
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Are you sure you want to delete user {{ deletingUser.username }}?
- This action cannot be undone.
-
-
-
-
-
-
-
-
- {{ error }}
-
-
-
-
-
+
+
+
+
+
+
+
+
+ | Username |
+ Email |
+ Name |
+ Roles |
+ Status |
+ Last Login |
+ Actions |
+
+
+
+
+ | Loading... |
+
+
+ | No users found |
+
+
+ | {{ user.username }} |
+ {{ user.email }} |
+ {{ [user.firstname, user.lastname].filter(Boolean).join(' ') || '-' }} |
+
+
+ {{ role.rolename }}
+
+ None
+ |
+
+ Locked
+ Inactive
+ Active
+ |
+ {{ formatDate(user.lastlogindate) }} |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Role Name |
+ Description |
+ Permissions |
+ Users |
+ Actions |
+
+
+
+
+ |
+
+ {{ role.rolename }}
+
+ |
+ {{ role.description || '-' }} |
+
+ All permissions
+ {{ role.permissions.length }} permissions
+ None
+ |
+ {{ role.usercount }} |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Are you sure you want to delete user {{ deletingUser.username }}?
+ This action cannot be undone.
+
+
+
+
+
+
+
+
+ {{ error }}
+
+
+
+
+
diff --git a/frontend/src/views/settings/VLANsList.vue b/frontend/src/views/settings/VLANsList.vue
index 4f423ae..66f505e 100644
--- a/frontend/src/views/settings/VLANsList.vue
+++ b/frontend/src/views/settings/VLANsList.vue
@@ -188,6 +188,7 @@ import { ref, onMounted } from 'vue'
import { networkApi } from '../../api'
import PaginationBar from '../../components/PaginationBar.vue'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const vlans = ref([])
@@ -309,7 +310,7 @@ async function saveVLAN() {
loadVLANs()
} catch (err) {
console.error('Error saving VLAN:', err)
- error.value = err.response?.data?.message || 'Failed to save VLAN'
+ error.value = apiError(err, 'Failed to save VLAN')
} finally {
saving.value = false
}
@@ -328,7 +329,7 @@ async function deleteVLAN() {
loadVLANs()
} catch (err) {
console.error('Error deleting VLAN:', err)
- toast.error(err.response?.data?.message || 'Failed to delete VLAN')
+ toast.error(apiError(err, 'Failed to delete VLAN'))
}
}
diff --git a/frontend/src/views/usb/USBDetail.vue b/frontend/src/views/usb/USBDetail.vue
index 7a848f3..dd0a9de 100644
--- a/frontend/src/views/usb/USBDetail.vue
+++ b/frontend/src/views/usb/USBDetail.vue
@@ -169,6 +169,7 @@ import { useRoute } from 'vue-router'
import { usbApi } from '../../api'
import Modal from '../../components/Modal.vue'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const route = useRoute()
@@ -219,7 +220,7 @@ async function doCheckout() {
await loadDevice()
} catch (error) {
console.error('Checkout error:', error)
- toast.error(error.response?.data?.message || 'Checkout failed')
+ toast.error(apiError(error, 'Checkout failed'))
}
}
@@ -230,7 +231,7 @@ async function doCheckin() {
await loadDevice()
} catch (error) {
console.error('Checkin error:', error)
- toast.error(error.response?.data?.message || 'Check in failed')
+ toast.error(apiError(error, 'Check in failed'))
}
}
diff --git a/frontend/src/views/usb/USBForm.vue b/frontend/src/views/usb/USBForm.vue
index 78c24ef..8b92658 100644
--- a/frontend/src/views/usb/USBForm.vue
+++ b/frontend/src/views/usb/USBForm.vue
@@ -1,230 +1,231 @@
-
-
-
-
-
-
-
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/views/usb/USBList.vue b/frontend/src/views/usb/USBList.vue
index c6aa94a..469eb8d 100644
--- a/frontend/src/views/usb/USBList.vue
+++ b/frontend/src/views/usb/USBList.vue
@@ -148,6 +148,7 @@ import Modal from '../../components/Modal.vue'
import EmployeeSearch from '../../components/EmployeeSearch.vue'
import PaginationBar from '../../components/PaginationBar.vue'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const devices = ref([])
@@ -243,7 +244,7 @@ async function doCheckout() {
loadDevices()
} catch (error) {
console.error('Checkout error:', error)
- toast.error(error.response?.data?.message || 'Checkout failed')
+ toast.error(apiError(error, 'Checkout failed'))
}
}
@@ -254,7 +255,7 @@ async function doCheckin() {
loadDevices()
} catch (error) {
console.error('Checkin error:', error)
- toast.error(error.response?.data?.message || 'Check in failed')
+ toast.error(apiError(error, 'Check in failed'))
}
}
diff --git a/frontend/src/views/vendors/VendorsList.vue b/frontend/src/views/vendors/VendorsList.vue
index 6f63483..3697352 100644
--- a/frontend/src/views/vendors/VendorsList.vue
+++ b/frontend/src/views/vendors/VendorsList.vue
@@ -187,6 +187,7 @@ import { ref, onMounted } from 'vue'
import { vendorsApi } from '../../api'
import PaginationBar from '../../components/PaginationBar.vue'
import { useToast } from '../../composables/toast'
+import { apiError } from '../../utils/apiError'
const toast = useToast()
const vendors = ref([])
@@ -304,7 +305,7 @@ async function saveVendor() {
loadVendors()
} catch (err) {
console.error('Error saving vendor:', err)
- error.value = err.response?.data?.message || 'Failed to save vendor'
+ error.value = apiError(err, 'Failed to save vendor')
} finally {
saving.value = false
}
diff --git a/frontend/src/views/warranty/WarrantiesList.vue b/frontend/src/views/warranty/WarrantiesList.vue
index f6d3e69..c01f4ea 100644
--- a/frontend/src/views/warranty/WarrantiesList.vue
+++ b/frontend/src/views/warranty/WarrantiesList.vue
@@ -3,14 +3,17 @@
-
+
+ {{ filteredItems.length }} of {{ items.length }}
@@ -39,10 +44,10 @@
|