Wire measuring tools into identifiers and global search
All checks were successful
CI / backend (push) Successful in 1m14s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 7s

The measuringtools plugin was missing from two cross-cutting surfaces:
the asset-identifier matrix (no measuring_tool column or per-type
keys - gauge lab reference is their primary identifier) and global
search (results fell to a generic URL and gaugelabreference was never
searched). Measuring tools now have identifier toggles, gated
gauge-lab and maintenance-reference fields on their form and detail,
a search domain toggle, gage-tag search, and proper labels, routes,
and filter chips in search results.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-12 08:11:39 -04:00
parent 31f5e07294
commit 64a5abdb08
11 changed files with 174 additions and 7 deletions

View File

@@ -14,7 +14,7 @@ const state = reactive({
let inflight = null
const KEY_RE = /^identifier_(.+?)(?:_(machine|computer|printer|network_device))?_enabled$/
const KEY_RE = /^identifier_(.+?)(?:_(machine|computer|printer|network_device|measuring_tool))?_enabled$/
function applySetting(key, value) {
const match = KEY_RE.exec(key)

View File

@@ -36,7 +36,8 @@ export const assetTypeCols = [
{ key: 'machine', label: 'Machine' },
{ key: 'computer', label: 'PC' },
{ key: 'printer', label: 'Printer' },
{ key: 'network_device', label: 'Network' }
{ key: 'network_device', label: 'Network' },
{ key: 'measuring_tool', label: 'Measuring Tool' }
]
// Global-search domain toggles: keys follow search_<type>_enabled.
@@ -49,6 +50,7 @@ export const searchDomains = [
{ key: 'computer', label: 'PCs' },
{ key: 'printer', label: 'Printers' },
{ key: 'network_device', label: 'Network Devices' },
{ key: 'measuring_tool', label: 'Measuring Tools' },
{ key: 'notification', label: 'Notifications' },
{ key: 'subnet', label: 'Subnets' }
]
@@ -153,7 +155,7 @@ export function useSystemSettings() {
for (const setting of data.data) {
if (setting.key in settings) {
settings[setting.key] = setting.value
} else if (/^identifier_.+_(machine|computer|printer|network_device)_enabled$/.test(setting.key)) {
} else if (/^identifier_.+_(machine|computer|printer|network_device|measuring_tool)_enabled$/.test(setting.key)) {
identifierMatrix[setting.key] = setting.value !== false
} else if (/^search_.+_enabled$/.test(setting.key)) {
searchMatrix[setting.key] = setting.value !== false

View File

@@ -9,6 +9,7 @@ const ASSET_TYPE_LABELS = {
'printer': 'Printers',
'network_device': 'Network Devices',
'network device': 'Network Devices',
'measuring_tool': 'Measuring Tools',
}
const ASSET_TYPE_ROUTES = {
@@ -17,6 +18,7 @@ const ASSET_TYPE_ROUTES = {
'printer': '/printers',
'network_device': '/network',
'network device': '/network',
'measuring_tool': '/measuringtools',
}
// Plugin-specific id field inside asset.typedata for each asset type.
@@ -26,6 +28,7 @@ const ASSET_TYPE_ID_KEYS = {
'printer': 'printerid',
'network_device': 'networkdeviceid',
'network device': 'networkdeviceid',
'measuring_tool': 'measuringtoolid',
}
function titleCase(text) {

View File

@@ -116,6 +116,7 @@ const typeLabels = {
knowledgebase: 'KB',
printer: 'Printer',
network_device: 'Network',
measuring_tool: 'Measuring Tool',
employee: 'Employee',
notification: 'Notice',
subnet: 'Subnet'
@@ -127,6 +128,7 @@ const filterTypeMap = {
computers: ['computer'],
printers: ['printer'],
network: ['network_device', 'subnet'],
measuringtools: ['measuring_tool'],
applications: ['application'],
knowledgebase: ['knowledgebase'],
notifications: ['notification'],
@@ -139,6 +141,7 @@ const filterList = [
{ key: 'computers', label: 'PCs' },
{ key: 'printers', label: 'Printers' },
{ key: 'network', label: 'Network' },
{ key: 'measuringtools', label: 'Measuring Tools' },
{ key: 'applications', label: 'Apps' },
{ key: 'knowledgebase', label: 'KB' },
{ key: 'notifications', label: 'Notices' },
@@ -413,6 +416,11 @@ watch(results, () => {
color: #f57f17;
}
.result-type.measuring_tool {
background: #e0f7fa;
color: #00838f;
}
.result-type.employee {
background: #e0f2f1;
color: #00695c;
@@ -513,6 +521,11 @@ watch(results, () => {
color: #ffd54f;
}
.result-type.measuring_tool {
background: rgba(0, 131, 143, 0.2);
color: #80deea;
}
.result-type.employee {
background: rgba(0, 105, 92, 0.2);
color: #80cbc4;

View File

@@ -64,10 +64,14 @@
<span class="info-label">Name</span>
<span class="info-value">{{ tool.name }}</span>
</div>
<div class="info-row" v-if="tool.gaugelabreference">
<div class="info-row" v-if="tool.gaugelabreference && isEnabled('gaugelabreference', 'measuring_tool')">
<span class="info-label">Gauge Lab Reference</span>
<span class="info-value mono">{{ tool.gaugelabreference }}</span>
</div>
<div class="info-row" v-if="tool.maintenancereference && isEnabled('maintenancereference', 'measuring_tool')">
<span class="info-label">Maintenance Reference</span>
<span class="info-value mono">{{ tool.maintenancereference }}</span>
</div>
<div class="info-row" v-if="tool.serialnumber">
<span class="info-label">Serial Number</span>
<span class="info-value mono">{{ tool.serialnumber }}</span>
@@ -167,9 +171,12 @@ import CustomFieldsSection from '../../components/CustomFieldsSection.vue'
import WarrantyPanel from '../../components/WarrantyPanel.vue'
import AssetRelationships from '../../components/AssetRelationships.vue'
import { useWarrantyBadge } from '../../composables/warrantyBadge'
import { useIdentifierFlags } from '../../composables/identifierSettings'
const route = useRoute()
const { isEnabled } = useIdentifierFlags()
const loading = ref(true)
const tool = ref(null)
const { warranties } = useWarrantyBadge(() => tool.value?.assetid)

View File

@@ -27,13 +27,21 @@
<label for="serialnumber">Serial Number (vendor)</label>
<input id="serialnumber" v-model="form.serialnumber" type="text" class="form-control" />
</div>
<div class="form-group">
<div class="form-group" v-if="isEnabled('gaugelabreference', 'measuring_tool')">
<label for="gaugelabreference">Gauge Lab Reference</label>
<input id="gaugelabreference" v-model="form.gaugelabreference" type="text" class="form-control" />
<small class="form-help">Authoritative gauge lab asset reference (if tracked)</small>
</div>
</div>
<div class="form-row" v-if="isEnabled('maintenancereference', 'measuring_tool')">
<div class="form-group">
<label for="maintenancereference">Maintenance Reference</label>
<input id="maintenancereference" v-model="form.maintenancereference" type="text" class="form-control" />
<small class="form-help">Maintenance system asset reference (if tracked)</small>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="measuringtooltypeid">Type</label>
@@ -126,11 +134,14 @@ import { ref, onMounted, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { measuringtoolsApi, assetsApi, locationsApi, businessunitsApi } from '../../api'
import CustomFieldsInputs from '../../components/CustomFieldsInputs.vue'
import { useIdentifierFlags } from '../../composables/identifierSettings'
import { apiError } from '../../utils/apiError'
const route = useRoute()
const router = useRouter()
const { isEnabled } = useIdentifierFlags()
const isEdit = computed(() => !!route.params.id)
// Resolved dynamically from /api/assets/types (no hardcoded id) so custom
@@ -147,6 +158,7 @@ const form = ref({
assetnumber: '',
name: '',
gaugelabreference: '',
maintenancereference: '',
serialnumber: '',
statusid: '',
measuringtooltypeid: '',
@@ -190,6 +202,7 @@ onMounted(async () => {
assetnumber: data.assetnumber || '',
name: data.name || '',
gaugelabreference: data.gaugelabreference || '',
maintenancereference: data.maintenancereference || '',
serialnumber: data.serialnumber || '',
statusid: data.statusid || '',
measuringtooltypeid: ext.measuringtooltypeid || '',
@@ -218,6 +231,7 @@ async function saveTool() {
assetnumber: form.value.assetnumber,
name: form.value.name || null,
gaugelabreference: form.value.gaugelabreference || null,
maintenancereference: form.value.maintenancereference || null,
serialnumber: form.value.serialnumber || null,
statusid: form.value.statusid || null,
measuringtooltypeid: form.value.measuringtooltypeid || null,