Retire the legacy Machine model (ADR-001 cutover)
The asset/computer model is now the single source of truth. Remove the Machine instance layer end to end: - Delete models Machine, MachineStatus, PCType, MachineRelationship, InstalledApp, PrinterData; keep MachineType (models.machinetypeid still references it). - Delete the /api/machines, /api/statuses, /api/pctypes blueprints and the legacy /api/printers/legacy (PrinterData) blueprint. - Drop the deprecated communications.machineid column and its FK. - Migration 7c01 drops tables machines, machinestatuses, pctypes, machinerelationships, installedapps, printerdata (idempotent). - Fix remaining readers (applications install counts) to ComputerInstalledApp. - Frontend: remove dead machinesApi/statusesApi/pctypesApi wrappers; repoint the PC Types settings page at computer types. 143 tests pass; all asset/computer/dashboard/report/collector endpoints 200. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -66,10 +66,10 @@
|
||||
<option value="">Select type...</option>
|
||||
<option
|
||||
v-for="pt in pcTypes"
|
||||
:key="pt.machinetypeid"
|
||||
:value="pt.machinetypeid"
|
||||
:key="pt.computertypeid"
|
||||
:value="pt.computertypeid"
|
||||
>
|
||||
{{ pt.machinetype }}
|
||||
{{ pt.computertype }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -268,7 +268,7 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { machinesApi, machinetypesApi, assetsApi, vendorsApi, locationsApi, modelsApi, operatingsystemsApi } from '../../api'
|
||||
import { computersApi, assetsApi, vendorsApi, locationsApi, modelsApi, operatingsystemsApi } from '../../api'
|
||||
import ShopFloorMap from '../../components/ShopFloorMap.vue'
|
||||
import Modal from '../../components/Modal.vue'
|
||||
import { currentTheme } from '../../stores/theme'
|
||||
@@ -316,17 +316,10 @@ const operatingsystems = ref([])
|
||||
|
||||
// Filter models by selected vendor and PC type
|
||||
const filteredModels = computed(() => {
|
||||
return models.value.filter(m => {
|
||||
if (form.value.vendorid && m.vendorid !== form.value.vendorid) {
|
||||
return false
|
||||
}
|
||||
// only exclude models that have a type set and it differs; most models
|
||||
// have no machinetypeid, so a strict check hides the PC's own model
|
||||
if (form.value.machinetypeid && m.machinetypeid && m.machinetypeid !== form.value.machinetypeid) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
// filter by vendor only (PC type now maps to computertypeid, a different id
|
||||
// space than a model's machinetypeid)
|
||||
if (!form.value.vendorid) return models.value
|
||||
return models.value.filter(m => m.vendorid === form.value.vendorid)
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -334,7 +327,7 @@ onMounted(async () => {
|
||||
// Load reference data
|
||||
// perpage 100 so dropdowns aren't truncated to the default 20-row page
|
||||
const [ptRes, statusRes, vendorRes, allModels, locRes, osRes] = await Promise.all([
|
||||
machinetypesApi.list({ category: 'PC', perpage: 100 }),
|
||||
computersApi.types.list({ perpage: 100 }),
|
||||
assetsApi.statuses.list(),
|
||||
vendorsApi.list({ perpage: 100 }),
|
||||
modelsApi.listAll(), // backend caps perpage at 100; page through all
|
||||
@@ -349,28 +342,28 @@ onMounted(async () => {
|
||||
locations.value = locRes.data.data || []
|
||||
operatingsystems.value = osRes.data.data || []
|
||||
|
||||
// Load PC if editing
|
||||
// Load PC if editing (asset-based shape: extension under pc.computer)
|
||||
if (isEdit.value) {
|
||||
const response = await machinesApi.get(route.params.id)
|
||||
const response = await computersApi.get(route.params.id)
|
||||
const pc = response.data.data
|
||||
const ext = pc.computer || {}
|
||||
|
||||
// Get IP from communications
|
||||
const primaryComm = pc.communications?.find(c => c.isprimary) || pc.communications?.[0]
|
||||
|
||||
form.value = {
|
||||
machinenumber: pc.machinenumber || '',
|
||||
alias: pc.alias || '',
|
||||
hostname: pc.hostname || '',
|
||||
machinenumber: pc.assetnumber || '',
|
||||
alias: pc.name && pc.name.toUpperCase() !== 'NONE' ? pc.name : '',
|
||||
hostname: ext.hostname || '',
|
||||
serialnumber: pc.serialnumber || '',
|
||||
machinetypeid: pc.machinetype?.machinetypeid || '',
|
||||
statusid: pc.status?.statusid || '',
|
||||
vendorid: pc.vendor?.vendorid || '',
|
||||
modelnumberid: pc.model?.modelnumberid || '',
|
||||
locationid: pc.location?.locationid || '',
|
||||
osid: pc.operatingsystem?.osid || '',
|
||||
loggedinuser: pc.loggedinuser || '',
|
||||
isvnc: pc.isvnc || false,
|
||||
iswinrm: pc.iswinrm || false,
|
||||
machinetypeid: ext.computertypeid || '',
|
||||
statusid: pc.statusid || '',
|
||||
vendorid: ext.vendorid || '',
|
||||
modelnumberid: ext.modelnumberid || '',
|
||||
locationid: pc.locationid || '',
|
||||
osid: ext.osid || '',
|
||||
loggedinuser: ext.loggedinuser || '',
|
||||
isvnc: ext.isvnc || false,
|
||||
iswinrm: ext.iswinrm || false,
|
||||
notes: pc.notes || '',
|
||||
mapx: pc.mapx ?? null,
|
||||
mapy: pc.mapy ?? null,
|
||||
@@ -408,40 +401,35 @@ async function savePC() {
|
||||
saving.value = true
|
||||
|
||||
try {
|
||||
const machineData = {
|
||||
machinenumber: form.value.machinenumber,
|
||||
alias: form.value.alias,
|
||||
hostname: form.value.hostname,
|
||||
serialnumber: form.value.serialnumber,
|
||||
machinetypeid: form.value.machinetypeid || null,
|
||||
// One payload for the computers plugin (asset core + computer extension +
|
||||
// primary IP). "PC Number" is the business identifier (assetnumber).
|
||||
const payload = {
|
||||
assetnumber: form.value.machinenumber,
|
||||
hostname: form.value.hostname || null,
|
||||
serialnumber: form.value.serialnumber || null,
|
||||
computertypeid: form.value.machinetypeid || null,
|
||||
statusid: form.value.statusid || null,
|
||||
vendorid: form.value.vendorid || null,
|
||||
modelnumberid: form.value.modelnumberid || null,
|
||||
locationid: form.value.locationid || null,
|
||||
osid: form.value.osid || null,
|
||||
loggedinuser: form.value.loggedinuser,
|
||||
loggedinuser: form.value.loggedinuser || null,
|
||||
isvnc: form.value.isvnc,
|
||||
iswinrm: form.value.iswinrm,
|
||||
notes: form.value.notes,
|
||||
notes: form.value.notes || null,
|
||||
ipaddress: form.value.ipaddress || null,
|
||||
mapx: form.value.mapx,
|
||||
mapy: form.value.mapy
|
||||
}
|
||||
|
||||
let machineId
|
||||
if (isEdit.value) {
|
||||
await machinesApi.update(route.params.id, machineData)
|
||||
machineId = route.params.id
|
||||
} else {
|
||||
const response = await machinesApi.create(machineData)
|
||||
machineId = response.data.data.machineid
|
||||
// only set display name when an alias is given, so we don't clobber it
|
||||
if (form.value.alias) {
|
||||
payload.name = form.value.alias
|
||||
}
|
||||
|
||||
// Handle IP address - update communication record
|
||||
if (form.value.ipaddress) {
|
||||
await machinesApi.updateCommunication(machineId, {
|
||||
ipaddress: form.value.ipaddress,
|
||||
isprimary: true
|
||||
})
|
||||
if (isEdit.value) {
|
||||
await computersApi.update(route.params.id, payload)
|
||||
} else {
|
||||
await computersApi.create(payload)
|
||||
}
|
||||
|
||||
router.push('/pcs')
|
||||
|
||||
Reference in New Issue
Block a user