New Plugins: - USB plugin: Device checkout/checkin with employee lookup, checkout history - Notifications plugin: Announcements with types, scheduling, shopfloor display - Network plugin: Network device management with subnets and VLANs - Equipment and Computers plugins: Asset type separation Frontend: - EmployeeSearch component: Reusable employee lookup with autocomplete - USB views: List, detail, checkout/checkin modals - Notifications views: List, form with recognition mode - Network views: Device list, detail, form - Calendar view with FullCalendar integration - Shopfloor and TV dashboard views - Reports index page - Map editor for asset positioning - Light/dark mode fixes for map tooltips Backend: - Employee search API with external lookup service - Collector API for PowerShell data collection - Reports API endpoints - Slides API for TV dashboard - Fixed AppVersion model (removed BaseModel inheritance) - Added checkout_name column to usbcheckouts table Styling: - Unified detail page styles - Improved pagination (page numbers instead of prev/next) - Dark/light mode theme improvements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
657 lines
14 KiB
JavaScript
657 lines
14 KiB
JavaScript
import axios from 'axios'
|
|
|
|
const api = axios.create({
|
|
baseURL: '/api',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
})
|
|
|
|
// Add auth token to requests
|
|
api.interceptors.request.use(config => {
|
|
const token = localStorage.getItem('token')
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`
|
|
}
|
|
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)
|
|
if (hadToken) {
|
|
window.location.href = '/login'
|
|
}
|
|
}
|
|
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}` }
|
|
})
|
|
}
|
|
}
|
|
|
|
// Machines API
|
|
export const machinesApi = {
|
|
list(params = {}) {
|
|
return api.get('/machines', { params })
|
|
},
|
|
get(id) {
|
|
return api.get(`/machines/${id}`)
|
|
},
|
|
create(data) {
|
|
return api.post('/machines', data)
|
|
},
|
|
update(id, data) {
|
|
return api.put(`/machines/${id}`, data)
|
|
},
|
|
delete(id) {
|
|
return api.delete(`/machines/${id}`)
|
|
},
|
|
updateCommunication(id, data) {
|
|
return api.put(`/machines/${id}/communication`, data)
|
|
},
|
|
// Relationships
|
|
getRelationships(id) {
|
|
return api.get(`/machines/${id}/relationships`)
|
|
},
|
|
createRelationship(id, data) {
|
|
return api.post(`/machines/${id}/relationships`, data)
|
|
},
|
|
deleteRelationship(relationshipId) {
|
|
return api.delete(`/machines/relationships/${relationshipId}`)
|
|
}
|
|
}
|
|
|
|
// Relationship Types API
|
|
export const relationshipTypesApi = {
|
|
list() {
|
|
return api.get('/machines/relationshiptypes')
|
|
},
|
|
create(data) {
|
|
return api.post('/machines/relationshiptypes', data)
|
|
}
|
|
}
|
|
|
|
// Machine Types API
|
|
export const machinetypesApi = {
|
|
list(params = {}) {
|
|
return api.get('/machinetypes', { params })
|
|
},
|
|
create(data) {
|
|
return api.post('/machinetypes', data)
|
|
},
|
|
update(id, data) {
|
|
return api.put(`/machinetypes/${id}`, data)
|
|
},
|
|
delete(id) {
|
|
return api.delete(`/machinetypes/${id}`)
|
|
}
|
|
}
|
|
|
|
// Statuses API
|
|
export const statusesApi = {
|
|
list(params = {}) {
|
|
return api.get('/statuses', { params })
|
|
},
|
|
get(id) {
|
|
return api.get(`/statuses/${id}`)
|
|
},
|
|
create(data) {
|
|
return api.post('/statuses', data)
|
|
},
|
|
update(id, data) {
|
|
return api.put(`/statuses/${id}`, data)
|
|
},
|
|
delete(id) {
|
|
return api.delete(`/statuses/${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}`)
|
|
}
|
|
}
|
|
|
|
// Printers API
|
|
export const printersApi = {
|
|
list(params = {}) {
|
|
return api.get('/printers', { params })
|
|
},
|
|
get(id) {
|
|
return api.get(`/printers/${id}`)
|
|
},
|
|
updateExtension(id, data) {
|
|
return api.put(`/printers/${id}/printerdata`, data)
|
|
},
|
|
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')
|
|
},
|
|
dashboardSummary() {
|
|
return api.get('/printers/dashboard/summary')
|
|
},
|
|
drivers: {
|
|
list() {
|
|
return api.get('/printers/drivers')
|
|
},
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dashboard API
|
|
export const dashboardApi = {
|
|
summary() {
|
|
return api.get('/dashboard/summary')
|
|
}
|
|
}
|
|
|
|
// Models API
|
|
export const modelsApi = {
|
|
list(params = {}) {
|
|
return api.get('/models', { params })
|
|
},
|
|
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}`)
|
|
}
|
|
}
|
|
|
|
// PC Types API
|
|
export const pctypesApi = {
|
|
list(params = {}) {
|
|
return api.get('/pctypes', { params })
|
|
},
|
|
get(id) {
|
|
return api.get(`/pctypes/${id}`)
|
|
},
|
|
create(data) {
|
|
return api.post('/pctypes', data)
|
|
},
|
|
update(id, data) {
|
|
return api.put(`/pctypes/${id}`, data)
|
|
},
|
|
delete(id) {
|
|
return api.delete(`/pctypes/${id}`)
|
|
}
|
|
}
|
|
|
|
// 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
|
|
getSupportTeams() {
|
|
return api.get('/applications/supportteams')
|
|
},
|
|
createSupportTeam(data) {
|
|
return api.post('/applications/supportteams', data)
|
|
},
|
|
// App owners
|
|
getAppOwners() {
|
|
return api.get('/applications/appowners')
|
|
},
|
|
createAppOwner(data) {
|
|
return api.post('/applications/appowners', data)
|
|
}
|
|
}
|
|
|
|
// Search API
|
|
export const searchApi = {
|
|
search(query) {
|
|
return api.get('/search', { params: { q: query } })
|
|
}
|
|
}
|
|
|
|
// 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}`)
|
|
}
|
|
},
|
|
statuses: {
|
|
list() {
|
|
return api.get('/assets/statuses')
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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')
|
|
},
|
|
create(data) {
|
|
return api.post('/notifications/types', 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)
|
|
},
|
|
delete(id) {
|
|
return api.delete(`/usb/${id}`)
|
|
},
|
|
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 })
|
|
},
|
|
getAvailable() {
|
|
return api.get('/usb/available')
|
|
},
|
|
getCheckedOut() {
|
|
return api.get('/usb/checkedout')
|
|
},
|
|
getUserCheckouts(userId) {
|
|
return api.get(`/usb/user/${userId}`)
|
|
},
|
|
dashboardSummary() {
|
|
return api.get('/usb/dashboard/summary')
|
|
},
|
|
types: {
|
|
list() {
|
|
return api.get('/usb/types')
|
|
},
|
|
create(data) {
|
|
return api.post('/usb/types', data)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reports API
|
|
export const reportsApi = {
|
|
list() {
|
|
return api.get('/reports')
|
|
},
|
|
equipmentByType(params = {}) {
|
|
return api.get('/reports/equipment-by-type', { params })
|
|
},
|
|
assetsByStatus(params = {}) {
|
|
return api.get('/reports/assets-by-status', { params })
|
|
},
|
|
kbPopularity(params = {}) {
|
|
return api.get('/reports/kb-popularity', { params })
|
|
},
|
|
warrantyStatus(params = {}) {
|
|
return api.get('/reports/warranty-status', { params })
|
|
},
|
|
softwareCompliance(params = {}) {
|
|
return api.get('/reports/software-compliance', { params })
|
|
},
|
|
assetInventory(params = {}) {
|
|
return api.get('/reports/asset-inventory', { params })
|
|
}
|
|
}
|
|
|
|
// 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 } })
|
|
}
|
|
}
|
|
|
|
// Alias for different casing
|
|
export const businessUnitsApi = businessunitsApi
|
|
|
|
// 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)
|
|
}
|
|
},
|
|
// 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}`)
|
|
}
|
|
}
|
|
}
|