Files
shopdb-flask/frontend/src/api/index.js
cproudlock 0d40780f53 printers: printer installer map + install-batch endpoint
Rebuilds the classic printer-installer feature: pick printers on the shopfloor
map, download a .bat that installs them.

Backend (asset_routes.py): GET /api/printers/install-batch?printerids=1,2,3
returns a .bat attachment. Groups printers the way the classic installprinter.asp
did - HP/Xerox via the universal PrinterInstaller.exe /PRINTER="a,b,c", printers
with a .exe installpath via that installer /SILENT, and anything else (no
installpath, or a .zip) listed for manual install instead of being run blindly.
Download URLs derive from the site_base_url setting + the IIS-served /installers
folder (no hardcoded host). Reuses the existing install-list query shape.

Frontend: PrinterInstallerMap.vue - full-screen Leaflet shopfloor map (reuses
mapConfig), a marker per network printer at its mapx/mapy, click to toggle-select,
sidebar with the selection + an Install button that downloads the batch. Toplevel
route /printer-installer, printersApi.installList(), and an Installer Map button
on the printers list.

Tests: install-batch grouping (universal/specific/manual) + requires-ids.
2026-07-29 12:38:51 -04:00

1194 lines
30 KiB
JavaScript

import axios from 'axios'
import { withBase, stripBase } from './../utils/basePath'
// BASE_URL ends in '/', so this is '/api' at root or '/ops/api' under a subpath
// mount. Keeps the SPA, its API, and IIS all on the same mount path.
const api = axios.create({
baseURL: import.meta.env.BASE_URL + 'api',
headers: {
'Content-Type': 'application/json'
}
})
// Add auth token and normalize pagination params
api.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
// Send both perpage and per_page for backend compatibility
if (config.params?.perpage) {
config.params.per_page = config.params.perpage
}
return config
})
// Handle 401 errors (token expired) - only redirect if user was logged in
api.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
const hadToken = localStorage.getItem('token')
localStorage.removeItem('token')
localStorage.removeItem('user')
// Only redirect if user was previously logged in (session expired).
// Preserve the destination so login returns the user to this page.
if (hadToken) {
const loginPath = withBase('/login')
// Router paths exclude the mount base; strip it or login's
// router.push double-prefixes under a subpath mount.
const here = stripBase(window.location.pathname) + window.location.search
const target = here && here !== '/login'
? loginPath + '?redirect=' + encodeURIComponent(here)
: loginPath
window.location.href = target
}
}
return Promise.reject(error)
}
)
export default api
// Auth API
export const authApi = {
login(username, password) {
return api.post('/auth/login', { username, password })
},
logout() {
return api.post('/auth/logout')
},
me() {
return api.get('/auth/me')
},
refresh() {
const refreshToken = localStorage.getItem('refreshToken')
return api.post('/auth/refresh', {}, {
headers: { Authorization: `Bearer ${refreshToken}` }
})
},
changePassword(payload) {
return api.post('/auth/change-password', payload)
}
}
// Machines API (plugin)
export const machinesApi = {
list(params = {}) {
return api.get('/machines', { params })
},
get(id) {
return api.get(`/machines/${id}`)
},
getByAsset(assetId) {
return api.get(`/machines/by-asset/${assetId}`)
},
create(data) {
return api.post('/machines', data)
},
update(id, data) {
return api.put(`/machines/${id}`, data)
},
delete(id) {
return api.delete(`/machines/${id}`)
},
dashboardSummary() {
return api.get('/machines/dashboard/summary')
},
// Machine types
types: {
list(params = {}) {
return api.get('/machines/types', { params })
},
get(id) {
return api.get(`/machines/types/${id}`)
},
create(data) {
return api.post('/machines/types', data)
},
update(id, data) {
return api.put(`/machines/types/${id}`, data)
},
remove(id) {
return api.delete(`/machines/types/${id}`)
}
}
}
// Computers API (plugin)
export const computersApi = {
list(params = {}) {
return api.get('/computers', { params })
},
displayKiosks() {
return api.get('/computers/display-kiosks')
},
get(id) {
return api.get(`/computers/${id}`)
},
getByAsset(assetId) {
return api.get(`/computers/by-asset/${assetId}`)
},
getByHostname(hostname) {
return api.get(`/computers/by-hostname/${hostname}`)
},
create(data) {
return api.post('/computers', data)
},
update(id, data) {
return api.put(`/computers/${id}`, data)
},
delete(id) {
return api.delete(`/computers/${id}`)
},
dashboardSummary() {
return api.get('/computers/dashboard/summary')
},
// Computer types
types: {
list(params = {}) {
return api.get('/computers/types', { params })
},
get(id) {
return api.get(`/computers/types/${id}`)
},
create(data) {
return api.post('/computers/types', data)
},
update(id, data) {
return api.put(`/computers/types/${id}`, data)
},
remove(id) {
return api.delete(`/computers/types/${id}`)
}
},
// Remote-access protocol catalog
protocols: {
list(params = {}) {
return api.get('/computers/protocols', { params })
},
create(data) {
return api.post('/computers/protocols', data)
},
update(id, data) {
return api.put(`/computers/protocols/${id}`, data)
},
remove(id) {
return api.delete(`/computers/protocols/${id}`)
}
}
}
// Relationship Types API
export const relationshipTypesApi = {
list() {
return api.get('/assets/relationshiptypes')
},
create(data) {
return api.post('/assets/relationshiptypes', data)
},
update(id, data) {
return api.put(`/assets/relationshiptypes/${id}`, data)
},
remove(id) {
return api.delete(`/assets/relationshiptypes/${id}`)
}
}
// Model Types API (the vendor models catalog: modeltypeid)
export const modeltypesApi = {
list(params = {}) {
return api.get('/modeltypes', { params })
},
create(data) {
return api.post('/modeltypes', data)
},
update(id, data) {
return api.put(`/modeltypes/${id}`, data)
},
delete(id) {
return api.delete(`/modeltypes/${id}`)
}
}
// Vendors API
export const vendorsApi = {
list(params = {}) {
return api.get('/vendors', { params })
},
get(id) {
return api.get(`/vendors/${id}`)
},
create(data) {
return api.post('/vendors', data)
},
update(id, data) {
return api.put(`/vendors/${id}`, data)
},
delete(id) {
return api.delete(`/vendors/${id}`)
}
}
// Locations API
export const locationsApi = {
list(params = {}) {
return api.get('/locations', { params })
},
get(id) {
return api.get(`/locations/${id}`)
},
create(data) {
return api.post('/locations', data)
},
update(id, data) {
return api.put(`/locations/${id}`, data)
},
delete(id) {
return api.delete(`/locations/${id}`)
},
types: {
list(params = {}) {
return api.get('/locations/types', { params })
},
create(data) {
return api.post('/locations/types', data)
},
update(id, data) {
return api.put(`/locations/types/${id}`, data)
},
remove(id) {
return api.delete(`/locations/types/${id}`)
}
}
}
// Printers API
export const printersApi = {
list(params = {}) {
return api.get('/printers', { params })
},
get(id) {
return api.get(`/printers/${id}`)
},
// create/update write asset core + printer extension in one call (the
// printers plugin owns both). Use these instead of the legacy machinesApi.
create(data) {
return api.post('/printers', data)
},
update(id, data) {
return api.put(`/printers/${id}`, data)
},
updateExtension(id, data) {
return api.put(`/printers/${id}/printerdata`, data)
},
// printer sub-types (Laser, Inkjet, Label, Card, Wide Format, ...)
types: {
list(params = {}) {
return api.get('/printers/types', { params })
},
create(data) {
return api.post('/printers/types', data)
},
update(id, data) {
return api.put(`/printers/types/${id}`, data)
},
remove(id) {
return api.delete(`/printers/types/${id}`)
}
},
updateCommunication(id, data) {
return api.put(`/printers/${id}/communication`, data)
},
getSupplies(id) {
return api.get(`/printers/${id}/supplies`)
},
getDrivers(id) {
return api.get(`/printers/${id}/drivers`)
},
lowSupplies() {
return api.get('/printers/lowsupplies')
},
refreshSupplies() {
return api.post('/printers/supplies/refresh')
},
lookup({ ip, fqdn } = {}) {
return api.get('/printers/lookup', { params: { ip, fqdn } })
},
dashboardSummary() {
return api.get('/printers/dashboard/summary')
},
// Flat network-printer list (with mapx/mapy) for the installer map.
installList() {
return api.get('/printers/install-list')
},
drivers: {
list(params = {}) {
return api.get('/printers/drivers', { params })
},
create(data) {
return api.post('/printers/drivers', data)
},
update(id, data) {
return api.put(`/printers/drivers/${id}`, data)
},
delete(id) {
return api.delete(`/printers/drivers/${id}`)
}
},
supplyTypes: {
list() {
return api.get('/printers/supplytypes')
},
create(data) {
return api.post('/printers/supplytypes', data)
}
},
// model -> toner/drum/waste part-number management
modelSupplies: {
meta() {
return api.get('/printers/supplies/meta')
},
listModels(params = {}) {
return api.get('/printers/models', { params })
},
list(modelnumberid) {
return api.get(`/printers/models/${modelnumberid}/supplies`)
},
create(modelnumberid, data) {
return api.post(`/printers/models/${modelnumberid}/supplies`, data)
},
update(modelsupplyid, data) {
return api.put(`/printers/supplies/${modelsupplyid}`, data)
},
delete(modelsupplyid) {
return api.delete(`/printers/supplies/${modelsupplyid}`)
}
}
}
// Dashboard API
export const dashboardApi = {
summary() {
return api.get('/dashboard/summary')
},
navigation() {
return api.get('/dashboard/navigation')
}
}
// Models API
export const modelsApi = {
list(params = {}) {
return api.get('/models', { params })
},
// Backend caps perpage at 100, so page through every model. Returns the
// full array directly (not an axios response). Use in forms whose model
// dropdown must include the editing record's model regardless of page.
async listAll() {
const first = await api.get('/models', { params: { perpage: 100, page: 1 } })
let items = first.data.data || []
const totalpages = first.data.meta?.pagination?.totalpages || 1
if (totalpages > 1) {
const rest = await Promise.all(
Array.from({ length: totalpages - 1 }, (_, i) =>
api.get('/models', { params: { perpage: 100, page: i + 2 } })
)
)
rest.forEach(r => { items = items.concat(r.data.data || []) })
}
return items
},
get(id) {
return api.get(`/models/${id}`)
},
create(data) {
return api.post('/models', data)
},
update(id, data) {
return api.put(`/models/${id}`, data)
},
delete(id) {
return api.delete(`/models/${id}`)
},
uploadImage(id, file) {
// multipart photo upload; backend sets imageurl to the served URL
const form = new FormData()
form.append('file', file)
return api.post(`/models/${id}/image`, form, { headers: { 'Content-Type': 'multipart/form-data' } })
},
removeImage(id) {
return api.delete(`/models/${id}/image`)
}
}
// Operating Systems API
export const operatingsystemsApi = {
list(params = {}) {
return api.get('/operatingsystems', { params })
},
get(id) {
return api.get(`/operatingsystems/${id}`)
},
create(data) {
return api.post('/operatingsystems', data)
},
update(id, data) {
return api.put(`/operatingsystems/${id}`, data)
},
delete(id) {
return api.delete(`/operatingsystems/${id}`)
}
}
// Business Units API
export const businessunitsApi = {
list(params = {}) {
return api.get('/businessunits', { params })
},
get(id) {
return api.get(`/businessunits/${id}`)
},
create(data) {
return api.post('/businessunits', data)
},
update(id, data) {
return api.put(`/businessunits/${id}`, data)
},
delete(id) {
return api.delete(`/businessunits/${id}`)
}
}
// Applications API
export const applicationsApi = {
list(params = {}) {
return api.get('/applications', { params })
},
get(id) {
return api.get(`/applications/${id}`)
},
create(data) {
return api.post('/applications', data)
},
update(id, data) {
return api.put(`/applications/${id}`, data)
},
delete(id) {
return api.delete(`/applications/${id}`)
},
// Versions
getVersions(appId) {
return api.get(`/applications/${appId}/versions`)
},
createVersion(appId, data) {
return api.post(`/applications/${appId}/versions`, data)
},
// Get PCs that have this app installed
getInstalledOn(appId) {
return api.get(`/applications/${appId}/installed`)
},
// Machine applications (installed apps)
getMachineApps(machineId) {
return api.get(`/applications/machines/${machineId}`)
},
installApp(machineId, data) {
return api.post(`/applications/machines/${machineId}`, data)
},
uninstallApp(machineId, appId) {
return api.delete(`/applications/machines/${machineId}/${appId}`)
},
updateInstalledApp(machineId, appId, data) {
return api.put(`/applications/machines/${machineId}/${appId}`, data)
}
}
// Support Teams API (teams + nested contacts)
export const supportteamsApi = {
list(params = {}) {
return api.get('/supportteams', { params })
},
get(id) {
return api.get(`/supportteams/${id}`)
},
create(data) {
return api.post('/supportteams', data)
},
update(id, data) {
return api.put(`/supportteams/${id}`, data)
},
remove(id) {
return api.delete(`/supportteams/${id}`)
},
contacts: {
add(teamId, data) {
return api.post(`/supportteams/${teamId}/contacts`, data)
},
update(teamId, contactId, data) {
return api.put(`/supportteams/${teamId}/contacts/${contactId}`, data)
},
remove(teamId, contactId) {
return api.delete(`/supportteams/${teamId}/contacts/${contactId}`)
}
}
}
// Search API
export const searchApi = {
search(query, params = {}) {
return api.get('/search', { params: { q: query, ...params } })
}
}
// Knowledge Base API
export const knowledgebaseApi = {
list(params = {}) {
return api.get('/knowledgebase', { params })
},
get(id) {
return api.get(`/knowledgebase/${id}`)
},
create(data) {
return api.post('/knowledgebase', data)
},
update(id, data) {
return api.put(`/knowledgebase/${id}`, data)
},
delete(id) {
return api.delete(`/knowledgebase/${id}`)
},
trackClick(id) {
return api.post(`/knowledgebase/${id}/click`)
},
getStats() {
return api.get('/knowledgebase/stats')
}
}
// Assets API (unified)
export const assetsApi = {
list(params = {}) {
return api.get('/assets', { params })
},
get(id) {
return api.get(`/assets/${id}`)
},
create(data) {
return api.post('/assets', data)
},
update(id, data) {
return api.put(`/assets/${id}`, data)
},
delete(id) {
return api.delete(`/assets/${id}`)
},
getMap(params = {}) {
return api.get('/assets/map', { params })
},
// Relationships
getRelationships(id) {
return api.get(`/assets/${id}/relationships`)
},
createRelationship(data) {
return api.post('/assets/relationships', data)
},
deleteRelationship(relationshipId) {
return api.delete(`/assets/relationships/${relationshipId}`)
},
// Search assets (for relationship picker)
search(query, params = {}) {
return api.get('/assets', { params: { search: query, ...params } })
},
// Lookup asset by asset/machine number
lookup(assetnumber) {
return api.get(`/assets/lookup/${encodeURIComponent(assetnumber)}`)
},
types: {
list() {
return api.get('/assets/types')
},
get(id) {
return api.get(`/assets/types/${id}`)
},
update(id, data) {
return api.put(`/assets/types/${id}`, data)
}
},
statuses: {
list(params = {}) {
return api.get('/assets/statuses', { params })
},
create(data) {
return api.post('/assets/statuses', data)
},
update(id, data) {
return api.put(`/assets/statuses/${id}`, data)
},
delete(id) {
return api.delete(`/assets/statuses/${id}`)
}
}
}
// Notifications API
export const notificationsApi = {
list(params = {}) {
return api.get('/notifications', { params })
},
get(id) {
return api.get(`/notifications/${id}`)
},
create(data) {
return api.post('/notifications', data)
},
update(id, data) {
return api.put(`/notifications/${id}`, data)
},
delete(id) {
return api.delete(`/notifications/${id}`)
},
getActive() {
return api.get('/notifications/active')
},
getCalendar(params = {}) {
return api.get('/notifications/calendar', { params })
},
dashboardSummary() {
return api.get('/notifications/dashboard/summary')
},
getShopfloor(params = {}) {
return api.get('/notifications/shopfloor', { params })
},
getEmployeeRecognitions(sso) {
return api.get(`/notifications/employee/${sso}`)
},
types: {
list() {
return api.get('/notifications/types')
},
get(id) {
return api.get(`/notifications/types/${id}`)
},
create(data) {
return api.post('/notifications/types', data)
},
update(id, data) {
return api.put(`/notifications/types/${id}`, data)
}
}
}
// USB Devices API
export const usbApi = {
list(params = {}) {
return api.get('/usb', { params })
},
get(id) {
return api.get(`/usb/${id}`)
},
create(data) {
return api.post('/usb', data)
},
update(id, data) {
return api.put(`/usb/${id}`, data)
},
checkout(id, data) {
return api.post(`/usb/${id}/checkout`, data)
},
checkin(id, data = {}) {
return api.post(`/usb/${id}/checkin`, data)
},
getHistory(id, params = {}) {
return api.get(`/usb/${id}/history`, { params })
},
// check-out log rows for one badge; activeonly = only currently-held devices
getUserCheckouts(badge, activeonly = true) {
const path = activeonly ? '/usb/checkouts/active' : '/usb/checkouts'
return api.get(path, { params: { badge } })
}
}
// Reports API
export const reportsApi = {
list() {
return api.get('/reports')
},
machinesByType(params = {}) {
return api.get('/reports/machines-by-type', { params })
},
assetsByStatus(params = {}) {
return api.get('/reports/assets-by-status', { params })
},
kbPopularity(params = {}) {
return api.get('/reports/kb-popularity', { params })
},
softwareCompliance(params = {}) {
return api.get('/reports/software-compliance', { params })
},
assetInventory(params = {}) {
return api.get('/reports/asset-inventory', { params })
},
pcRelationships(params = {}) {
return api.get('/reports/pc-relationships', { params })
},
// On-demand report delivery: email the given rows as an HTML table.
// Recipients default to the site Alert Recipients when `to` is omitted.
email(payload) {
return api.post('/reports/email', payload)
}
}
// Employees API (wjf_employees database)
export const employeesApi = {
search(query, limit = 10) {
return api.get('/employees/search', { params: { q: query, limit } })
},
lookup(sso) {
return api.get(`/employees/lookup/${sso}`)
},
lookupMultiple(ssoList) {
return api.get('/employees/lookup', { params: { sso: ssoList } })
},
// Self-hosted directory management (directory_mode=selfhosted)
directory: {
list() {
return api.get('/employees/directory')
},
create(data) {
return api.post('/employees/directory', data)
},
update(sso, data) {
return api.put(`/employees/directory/${sso}`, data)
},
remove(sso) {
return api.delete(`/employees/directory/${sso}`)
},
importCsv(csv) {
return api.post('/employees/directory/import', { csv })
},
// multipart photo upload; backend sets photofilename + returns photourl
uploadPhoto(sso, file) {
const form = new FormData()
form.append('file', file)
return api.post(`/employees/${sso}/photo`, form, { headers: { 'Content-Type': 'multipart/form-data' } })
},
removePhoto(sso) {
return api.delete(`/employees/${sso}/photo`)
}
}
}
// Alias for different casing
export const businessUnitsApi = businessunitsApi
// Dashboard defaults: visitor-IP -> business-unit mapping for kiosks
export const dashboardDefaultsApi = {
list() {
return api.get('/dashboarddefaults')
},
create(data) {
return api.post('/dashboarddefaults', data)
},
update(id, data) {
return api.put(`/dashboarddefaults/${id}`, data)
},
delete(id) {
return api.delete(`/dashboarddefaults/${id}`)
},
// Resolve the calling display's business unit by its IP
visitorLocation() {
return api.get('/dashboarddefaults/visitor-location')
}
}
// System Settings API
export const pluginsApi = {
list() {
return api.get('/plugins')
},
// Flat array of enabled plugin names. jwt-optional, safe for kiosk routes.
enabled() {
return api.get('/plugins/enabled')
},
setEnabled(name, enabled) {
return api.put(`/plugins/${name}`, { enabled })
}
}
export const setupApi = {
needsAdmin() {
return api.get('/setup/needs-admin')
},
createAdmin(data) {
return api.post('/setup/create-admin', data)
},
seedReference() {
return api.post('/setup/seed-reference')
},
seedStarter() {
return api.post('/setup/seed-starter')
},
complete() {
return api.post('/setup/complete')
}
}
export const settingsApi = {
list(params = {}) {
return api.get('/settings', { params })
},
get(key) {
return api.get(`/settings/${key}`)
},
update(key, value) {
return api.put(`/settings/${key}`, { value })
},
testEmail(to) {
return api.post('/settings/test-email', { to })
},
create(data) {
return api.post('/settings', data)
},
uploadMapBlueprint(theme, file) {
const form = new FormData()
form.append('theme', theme)
form.append('file', file)
return api.post('/settings/map-blueprint', form, { headers: { 'Content-Type': 'multipart/form-data' } })
},
uploadBrandingLogo(kind, file) {
// kind is one of site/qr/badge/favicon; backend writes the matching setting
const form = new FormData()
form.append('kind', kind)
form.append('file', file)
return api.post('/settings/branding-logo', form, { headers: { 'Content-Type': 'multipart/form-data' } })
}
}
// Slide manager (lobby display + shopfloor screensaver)
export const slidesApi = {
list(surface) {
return api.get(`/slides/${surface}`)
},
upload(surface, formData) {
return api.post(`/slides/${surface}/upload`, formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
},
reorder(surface, order) {
return api.post(`/slides/${surface}/order`, { order })
},
remove(surface, files) {
return api.post(`/slides/${surface}/delete`, { files })
}
}
// Audit Logs API
export const auditLogsApi = {
list(params = {}) {
return api.get('/auditlogs', { params })
},
getEntityHistory(entitytype, entityid) {
return api.get(`/auditlogs/entity/${entitytype}/${entityid}`)
},
getStats() {
return api.get('/auditlogs/stats')
}
}
// Users API
export const usersApi = {
list() {
return api.get('/users')
},
get(id) {
return api.get(`/users/${id}`)
},
create(data) {
return api.post('/users', data)
},
update(id, data) {
return api.put(`/users/${id}`, data)
},
delete(id) {
return api.delete(`/users/${id}`)
},
// Permissions
permissions: {
list() {
return api.get('/users/permissions')
}
},
// Roles
roles: {
list() {
return api.get('/users/roles')
},
create(data) {
return api.post('/users/roles', data)
},
update(id, data) {
return api.put(`/users/roles/${id}`, data)
},
delete(id) {
return api.delete(`/users/roles/${id}`)
}
}
}
// Personal API tokens: authenticate scripts/integrations as a user without
// the hourly-expiring login JWT. The secret is returned ONCE, on create.
export const apitokensApi = {
// all=true (admin) lists everyone's tokens; otherwise just the caller's.
list(params = {}) {
return api.get('/apitokens', { params })
},
create(data) {
return api.post('/apitokens', data)
},
update(id, data) {
return api.put(`/apitokens/${id}`, data)
},
remove(id) {
return api.delete(`/apitokens/${id}`)
}
}
// Network API (devices, subnets, and VLANs)
export const networkApi = {
// Network devices
list(params = {}) {
return api.get('/network', { params })
},
get(id) {
return api.get(`/network/${id}`)
},
getByAsset(assetId) {
return api.get(`/network/by-asset/${assetId}`)
},
getByHostname(hostname) {
return api.get(`/network/by-hostname/${hostname}`)
},
create(data) {
return api.post('/network', data)
},
update(id, data) {
return api.put(`/network/${id}`, data)
},
delete(id) {
return api.delete(`/network/${id}`)
},
dashboardSummary() {
return api.get('/network/dashboard/summary')
},
// Network device types
types: {
list(params = {}) {
return api.get('/network/types', { params })
},
get(id) {
return api.get(`/network/types/${id}`)
},
create(data) {
return api.post('/network/types', data)
},
update(id, data) {
return api.put(`/network/types/${id}`, data)
},
remove(id) {
return api.delete(`/network/types/${id}`)
}
},
// VLANs
vlans: {
list(params = {}) {
return api.get('/network/vlans', { params })
},
get(id) {
return api.get(`/network/vlans/${id}`)
},
create(data) {
return api.post('/network/vlans', data)
},
update(id, data) {
return api.put(`/network/vlans/${id}`, data)
},
delete(id) {
return api.delete(`/network/vlans/${id}`)
}
},
// Subnets
subnets: {
list(params = {}) {
return api.get('/network/subnets', { params })
},
get(id) {
return api.get(`/network/subnets/${id}`)
},
create(data) {
return api.post('/network/subnets', data)
},
update(id, data) {
return api.put(`/network/subnets/${id}`, data)
},
delete(id) {
return api.delete(`/network/subnets/${id}`)
}
}
}
// Custom fields: site-defined attributes per asset type.
export const customFieldsApi = {
// Definitions
list(params = {}) {
return api.get('/customfields', { params })
},
create(data) {
return api.post('/customfields', data)
},
update(fieldid, data) {
return api.put(`/customfields/${fieldid}`, data)
},
remove(fieldid) {
return api.delete(`/customfields/${fieldid}`)
},
// Per-asset values (defs merged with the asset's stored values)
forAsset(assetid) {
return api.get(`/customfields/asset/${assetid}`)
},
saveForAsset(assetid, values) {
return api.put(`/customfields/asset/${assetid}`, { values })
}
}
// Warranty plugin: asset warranty tracking (manual + provider lookups).
export const warrantyApi = {
list(params = {}) {
return api.get('/warranty', { params })
},
get(id) {
return api.get(`/warranty/${id}`)
},
forAsset(assetid) {
return api.get(`/warranty/asset/${assetid}`)
},
create(data) {
return api.post('/warranty', data)
},
update(id, data) {
return api.put(`/warranty/${id}`, data)
},
remove(id) {
return api.delete(`/warranty/${id}`)
},
refresh(id) {
return api.post(`/warranty/${id}/refresh`)
},
syncDell(all = false) {
return api.post('/warranty/sync/dell', null, { params: all ? { all: 'true' } : {} })
},
report() {
return api.get('/warranty/report')
}
}
// Measuring tools API (plugin)
export const measuringtoolsApi = {
list(params = {}) {
return api.get('/measuringtools', { params })
},
get(id) {
return api.get(`/measuringtools/${id}`)
},
getByAsset(assetid) {
return api.get(`/measuringtools/by-asset/${assetid}`)
},
create(data) {
return api.post('/measuringtools', data)
},
update(id, data) {
return api.put(`/measuringtools/${id}`, data)
},
remove(id) {
return api.delete(`/measuringtools/${id}`)
},
calibrationReport() {
return api.get('/measuringtools/report/calibration')
},
// Measuring-tool types
types: {
list(params = {}) {
return api.get('/measuringtools/types', { params })
},
get(id) {
return api.get(`/measuringtools/types/${id}`)
},
create(data) {
return api.post('/measuringtools/types', data)
},
update(id, data) {
return api.put(`/measuringtools/types/${id}`, data)
},
remove(id) {
return api.delete(`/measuringtools/types/${id}`)
}
}
}
// 3D printed parts (printedparts plugin)
export const printedpartsApi = {
list(params = {}) {
return api.get('/printedparts/items', { params })
},
get(printeditemid) {
return api.get(`/printedparts/items/${printeditemid}`)
},
create(data) {
return api.post('/printedparts/items', data)
},
update(printeditemid, data) {
return api.put(`/printedparts/items/${printeditemid}`, data)
},
remove(printeditemid) {
return api.delete(`/printedparts/items/${printeditemid}`)
},
restore(printeditemid) {
return api.post(`/printedparts/items/${printeditemid}/restore`)
},
uploadImage(printeditemid, file) {
const formData = new FormData()
formData.append('file', file)
return api.post(`/printedparts/items/${printeditemid}/image`, formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
},
deleteImage(printeditemid) {
return api.delete(`/printedparts/items/${printeditemid}/image`)
},
restock(printeditemid, data) {
return api.post(`/printedparts/items/${printeditemid}/restock`, data)
},
adjust(printeditemid, data) {
return api.post(`/printedparts/items/${printeditemid}/adjust`, data)
},
kioskItem(itemcode) {
return api.get(`/printedparts/kiosk/item/${encodeURIComponent(itemcode)}`)
},
kioskTake(data) {
return api.post('/printedparts/kiosk/take', data)
},
listFiles(printeditemid) {
return api.get(`/printedparts/items/${printeditemid}/files`)
},
uploadFile(printeditemid, file, note) {
const formData = new FormData()
formData.append('file', file)
if (note) formData.append('note', note)
return api.post(`/printedparts/items/${printeditemid}/files`, formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
},
removeFile(fileid) {
return api.delete(`/printedparts/files/${fileid}`)
}
}