Wire measuring tools into identifiers and global search
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:
@@ -108,6 +108,14 @@ ADR-007 and ADR-002.
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Measuring tools are now wired into the asset-identifier matrix and global
|
||||||
|
search. The Settings identifier matrix gains a Measuring Tool column and the
|
||||||
|
gauge-lab and maintenance reference inputs/rows on the measuring-tool form
|
||||||
|
and detail pages honor those per-type toggles (a maintenance-reference field
|
||||||
|
was added, matching the other asset types). Global search gains a Measuring
|
||||||
|
Tools domain toggle and filter chip, routes measuring-tool hits to
|
||||||
|
`/measuringtools/<id>` (previously the generic `/assets/<id>` fallback), and
|
||||||
|
matches on `gaugelabreference` so a gage-tag lookup resolves the tool.
|
||||||
- Site & Facility settings page renders booleans as toggles and the
|
- Site & Facility settings page renders booleans as toggles and the
|
||||||
directory-mode settings as dropdowns, with labels and help text for every
|
directory-mode settings as dropdowns, with labels and help text for every
|
||||||
field (no more raw keys or type-true/false boxes).
|
field (no more raw keys or type-true/false boxes).
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const state = reactive({
|
|||||||
|
|
||||||
let inflight = null
|
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) {
|
function applySetting(key, value) {
|
||||||
const match = KEY_RE.exec(key)
|
const match = KEY_RE.exec(key)
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ export const assetTypeCols = [
|
|||||||
{ key: 'machine', label: 'Machine' },
|
{ key: 'machine', label: 'Machine' },
|
||||||
{ key: 'computer', label: 'PC' },
|
{ key: 'computer', label: 'PC' },
|
||||||
{ key: 'printer', label: 'Printer' },
|
{ 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.
|
// Global-search domain toggles: keys follow search_<type>_enabled.
|
||||||
@@ -49,6 +50,7 @@ export const searchDomains = [
|
|||||||
{ key: 'computer', label: 'PCs' },
|
{ key: 'computer', label: 'PCs' },
|
||||||
{ key: 'printer', label: 'Printers' },
|
{ key: 'printer', label: 'Printers' },
|
||||||
{ key: 'network_device', label: 'Network Devices' },
|
{ key: 'network_device', label: 'Network Devices' },
|
||||||
|
{ key: 'measuring_tool', label: 'Measuring Tools' },
|
||||||
{ key: 'notification', label: 'Notifications' },
|
{ key: 'notification', label: 'Notifications' },
|
||||||
{ key: 'subnet', label: 'Subnets' }
|
{ key: 'subnet', label: 'Subnets' }
|
||||||
]
|
]
|
||||||
@@ -153,7 +155,7 @@ export function useSystemSettings() {
|
|||||||
for (const setting of data.data) {
|
for (const setting of data.data) {
|
||||||
if (setting.key in settings) {
|
if (setting.key in settings) {
|
||||||
settings[setting.key] = setting.value
|
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
|
identifierMatrix[setting.key] = setting.value !== false
|
||||||
} else if (/^search_.+_enabled$/.test(setting.key)) {
|
} else if (/^search_.+_enabled$/.test(setting.key)) {
|
||||||
searchMatrix[setting.key] = setting.value !== false
|
searchMatrix[setting.key] = setting.value !== false
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const ASSET_TYPE_LABELS = {
|
|||||||
'printer': 'Printers',
|
'printer': 'Printers',
|
||||||
'network_device': 'Network Devices',
|
'network_device': 'Network Devices',
|
||||||
'network device': 'Network Devices',
|
'network device': 'Network Devices',
|
||||||
|
'measuring_tool': 'Measuring Tools',
|
||||||
}
|
}
|
||||||
|
|
||||||
const ASSET_TYPE_ROUTES = {
|
const ASSET_TYPE_ROUTES = {
|
||||||
@@ -17,6 +18,7 @@ const ASSET_TYPE_ROUTES = {
|
|||||||
'printer': '/printers',
|
'printer': '/printers',
|
||||||
'network_device': '/network',
|
'network_device': '/network',
|
||||||
'network device': '/network',
|
'network device': '/network',
|
||||||
|
'measuring_tool': '/measuringtools',
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plugin-specific id field inside asset.typedata for each asset type.
|
// Plugin-specific id field inside asset.typedata for each asset type.
|
||||||
@@ -26,6 +28,7 @@ const ASSET_TYPE_ID_KEYS = {
|
|||||||
'printer': 'printerid',
|
'printer': 'printerid',
|
||||||
'network_device': 'networkdeviceid',
|
'network_device': 'networkdeviceid',
|
||||||
'network device': 'networkdeviceid',
|
'network device': 'networkdeviceid',
|
||||||
|
'measuring_tool': 'measuringtoolid',
|
||||||
}
|
}
|
||||||
|
|
||||||
function titleCase(text) {
|
function titleCase(text) {
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ const typeLabels = {
|
|||||||
knowledgebase: 'KB',
|
knowledgebase: 'KB',
|
||||||
printer: 'Printer',
|
printer: 'Printer',
|
||||||
network_device: 'Network',
|
network_device: 'Network',
|
||||||
|
measuring_tool: 'Measuring Tool',
|
||||||
employee: 'Employee',
|
employee: 'Employee',
|
||||||
notification: 'Notice',
|
notification: 'Notice',
|
||||||
subnet: 'Subnet'
|
subnet: 'Subnet'
|
||||||
@@ -127,6 +128,7 @@ const filterTypeMap = {
|
|||||||
computers: ['computer'],
|
computers: ['computer'],
|
||||||
printers: ['printer'],
|
printers: ['printer'],
|
||||||
network: ['network_device', 'subnet'],
|
network: ['network_device', 'subnet'],
|
||||||
|
measuringtools: ['measuring_tool'],
|
||||||
applications: ['application'],
|
applications: ['application'],
|
||||||
knowledgebase: ['knowledgebase'],
|
knowledgebase: ['knowledgebase'],
|
||||||
notifications: ['notification'],
|
notifications: ['notification'],
|
||||||
@@ -139,6 +141,7 @@ const filterList = [
|
|||||||
{ key: 'computers', label: 'PCs' },
|
{ key: 'computers', label: 'PCs' },
|
||||||
{ key: 'printers', label: 'Printers' },
|
{ key: 'printers', label: 'Printers' },
|
||||||
{ key: 'network', label: 'Network' },
|
{ key: 'network', label: 'Network' },
|
||||||
|
{ key: 'measuringtools', label: 'Measuring Tools' },
|
||||||
{ key: 'applications', label: 'Apps' },
|
{ key: 'applications', label: 'Apps' },
|
||||||
{ key: 'knowledgebase', label: 'KB' },
|
{ key: 'knowledgebase', label: 'KB' },
|
||||||
{ key: 'notifications', label: 'Notices' },
|
{ key: 'notifications', label: 'Notices' },
|
||||||
@@ -413,6 +416,11 @@ watch(results, () => {
|
|||||||
color: #f57f17;
|
color: #f57f17;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result-type.measuring_tool {
|
||||||
|
background: #e0f7fa;
|
||||||
|
color: #00838f;
|
||||||
|
}
|
||||||
|
|
||||||
.result-type.employee {
|
.result-type.employee {
|
||||||
background: #e0f2f1;
|
background: #e0f2f1;
|
||||||
color: #00695c;
|
color: #00695c;
|
||||||
@@ -513,6 +521,11 @@ watch(results, () => {
|
|||||||
color: #ffd54f;
|
color: #ffd54f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result-type.measuring_tool {
|
||||||
|
background: rgba(0, 131, 143, 0.2);
|
||||||
|
color: #80deea;
|
||||||
|
}
|
||||||
|
|
||||||
.result-type.employee {
|
.result-type.employee {
|
||||||
background: rgba(0, 105, 92, 0.2);
|
background: rgba(0, 105, 92, 0.2);
|
||||||
color: #80cbc4;
|
color: #80cbc4;
|
||||||
|
|||||||
@@ -64,10 +64,14 @@
|
|||||||
<span class="info-label">Name</span>
|
<span class="info-label">Name</span>
|
||||||
<span class="info-value">{{ tool.name }}</span>
|
<span class="info-value">{{ tool.name }}</span>
|
||||||
</div>
|
</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-label">Gauge Lab Reference</span>
|
||||||
<span class="info-value mono">{{ tool.gaugelabreference }}</span>
|
<span class="info-value mono">{{ tool.gaugelabreference }}</span>
|
||||||
</div>
|
</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">
|
<div class="info-row" v-if="tool.serialnumber">
|
||||||
<span class="info-label">Serial Number</span>
|
<span class="info-label">Serial Number</span>
|
||||||
<span class="info-value mono">{{ tool.serialnumber }}</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 WarrantyPanel from '../../components/WarrantyPanel.vue'
|
||||||
import AssetRelationships from '../../components/AssetRelationships.vue'
|
import AssetRelationships from '../../components/AssetRelationships.vue'
|
||||||
import { useWarrantyBadge } from '../../composables/warrantyBadge'
|
import { useWarrantyBadge } from '../../composables/warrantyBadge'
|
||||||
|
import { useIdentifierFlags } from '../../composables/identifierSettings'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
|
const { isEnabled } = useIdentifierFlags()
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const tool = ref(null)
|
const tool = ref(null)
|
||||||
const { warranties } = useWarrantyBadge(() => tool.value?.assetid)
|
const { warranties } = useWarrantyBadge(() => tool.value?.assetid)
|
||||||
|
|||||||
@@ -27,13 +27,21 @@
|
|||||||
<label for="serialnumber">Serial Number (vendor)</label>
|
<label for="serialnumber">Serial Number (vendor)</label>
|
||||||
<input id="serialnumber" v-model="form.serialnumber" type="text" class="form-control" />
|
<input id="serialnumber" v-model="form.serialnumber" type="text" class="form-control" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group" v-if="isEnabled('gaugelabreference', 'measuring_tool')">
|
||||||
<label for="gaugelabreference">Gauge Lab Reference</label>
|
<label for="gaugelabreference">Gauge Lab Reference</label>
|
||||||
<input id="gaugelabreference" v-model="form.gaugelabreference" type="text" class="form-control" />
|
<input id="gaugelabreference" v-model="form.gaugelabreference" type="text" class="form-control" />
|
||||||
<small class="form-help">Authoritative gauge lab asset reference (if tracked)</small>
|
<small class="form-help">Authoritative gauge lab asset reference (if tracked)</small>
|
||||||
</div>
|
</div>
|
||||||
</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-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="measuringtooltypeid">Type</label>
|
<label for="measuringtooltypeid">Type</label>
|
||||||
@@ -126,11 +134,14 @@ import { ref, onMounted, computed } from 'vue'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { measuringtoolsApi, assetsApi, locationsApi, businessunitsApi } from '../../api'
|
import { measuringtoolsApi, assetsApi, locationsApi, businessunitsApi } from '../../api'
|
||||||
import CustomFieldsInputs from '../../components/CustomFieldsInputs.vue'
|
import CustomFieldsInputs from '../../components/CustomFieldsInputs.vue'
|
||||||
|
import { useIdentifierFlags } from '../../composables/identifierSettings'
|
||||||
import { apiError } from '../../utils/apiError'
|
import { apiError } from '../../utils/apiError'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
const { isEnabled } = useIdentifierFlags()
|
||||||
|
|
||||||
const isEdit = computed(() => !!route.params.id)
|
const isEdit = computed(() => !!route.params.id)
|
||||||
|
|
||||||
// Resolved dynamically from /api/assets/types (no hardcoded id) so custom
|
// Resolved dynamically from /api/assets/types (no hardcoded id) so custom
|
||||||
@@ -147,6 +158,7 @@ const form = ref({
|
|||||||
assetnumber: '',
|
assetnumber: '',
|
||||||
name: '',
|
name: '',
|
||||||
gaugelabreference: '',
|
gaugelabreference: '',
|
||||||
|
maintenancereference: '',
|
||||||
serialnumber: '',
|
serialnumber: '',
|
||||||
statusid: '',
|
statusid: '',
|
||||||
measuringtooltypeid: '',
|
measuringtooltypeid: '',
|
||||||
@@ -190,6 +202,7 @@ onMounted(async () => {
|
|||||||
assetnumber: data.assetnumber || '',
|
assetnumber: data.assetnumber || '',
|
||||||
name: data.name || '',
|
name: data.name || '',
|
||||||
gaugelabreference: data.gaugelabreference || '',
|
gaugelabreference: data.gaugelabreference || '',
|
||||||
|
maintenancereference: data.maintenancereference || '',
|
||||||
serialnumber: data.serialnumber || '',
|
serialnumber: data.serialnumber || '',
|
||||||
statusid: data.statusid || '',
|
statusid: data.statusid || '',
|
||||||
measuringtooltypeid: ext.measuringtooltypeid || '',
|
measuringtooltypeid: ext.measuringtooltypeid || '',
|
||||||
@@ -218,6 +231,7 @@ async function saveTool() {
|
|||||||
assetnumber: form.value.assetnumber,
|
assetnumber: form.value.assetnumber,
|
||||||
name: form.value.name || null,
|
name: form.value.name || null,
|
||||||
gaugelabreference: form.value.gaugelabreference || null,
|
gaugelabreference: form.value.gaugelabreference || null,
|
||||||
|
maintenancereference: form.value.maintenancereference || null,
|
||||||
serialnumber: form.value.serialnumber || null,
|
serialnumber: form.value.serialnumber || null,
|
||||||
statusid: form.value.statusid || null,
|
statusid: form.value.statusid || null,
|
||||||
measuringtooltypeid: form.value.measuringtooltypeid || null,
|
measuringtooltypeid: form.value.measuringtooltypeid || null,
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ def create_tool():
|
|||||||
assetnumber=data['assetnumber'],
|
assetnumber=data['assetnumber'],
|
||||||
name=data.get('name'),
|
name=data.get('name'),
|
||||||
gaugelabreference=data.get('gaugelabreference'),
|
gaugelabreference=data.get('gaugelabreference'),
|
||||||
|
maintenancereference=data.get('maintenancereference'),
|
||||||
serialnumber=data.get('serialnumber'),
|
serialnumber=data.get('serialnumber'),
|
||||||
assettypeid=assettypeid,
|
assettypeid=assettypeid,
|
||||||
statusid=data.get('statusid', 1),
|
statusid=data.get('statusid', 1),
|
||||||
@@ -281,7 +282,8 @@ def create_tool():
|
|||||||
|
|
||||||
|
|
||||||
# Asset core fields writable through this plugin's write path.
|
# Asset core fields writable through this plugin's write path.
|
||||||
_ASSET_FIELDS = ('assetnumber', 'name', 'gaugelabreference', 'serialnumber',
|
_ASSET_FIELDS = ('assetnumber', 'name', 'gaugelabreference',
|
||||||
|
'maintenancereference', 'serialnumber',
|
||||||
'statusid', 'locationid', 'businessunitid', 'mapx', 'mapy',
|
'statusid', 'locationid', 'businessunitid', 'mapx', 'mapy',
|
||||||
'notes', 'isactive')
|
'notes', 'isactive')
|
||||||
# Extension fields with plain assignment (dates handled separately).
|
# Extension fields with plain assignment (dates handled separately).
|
||||||
|
|||||||
@@ -118,12 +118,15 @@ def _get_asset_result(asset, query, relevance=None):
|
|||||||
plugin_id = asset.network_device.networkdeviceid
|
plugin_id = asset.network_device.networkdeviceid
|
||||||
elif asset_type_name == 'printer' and hasattr(asset, 'printer') and asset.printer:
|
elif asset_type_name == 'printer' and hasattr(asset, 'printer') and asset.printer:
|
||||||
plugin_id = asset.printer.printerid
|
plugin_id = asset.printer.printerid
|
||||||
|
elif asset_type_name == 'measuring_tool' and hasattr(asset, 'measuringtool') and asset.measuringtool:
|
||||||
|
plugin_id = asset.measuringtool.measuringtoolid
|
||||||
|
|
||||||
url_map = {
|
url_map = {
|
||||||
'machine': f"/machines/{plugin_id}",
|
'machine': f"/machines/{plugin_id}",
|
||||||
'computer': f"/pcs/{plugin_id}",
|
'computer': f"/pcs/{plugin_id}",
|
||||||
'network_device': f"/network/{plugin_id}",
|
'network_device': f"/network/{plugin_id}",
|
||||||
'printer': f"/printers/{plugin_id}",
|
'printer': f"/printers/{plugin_id}",
|
||||||
|
'measuring_tool': f"/measuringtools/{plugin_id}",
|
||||||
}
|
}
|
||||||
url = url_map.get(asset_type_name, f"/assets/{asset.assetid}")
|
url = url_map.get(asset_type_name, f"/assets/{asset.assetid}")
|
||||||
|
|
||||||
@@ -296,6 +299,50 @@ def _search_assets(query, search_term):
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def _search_measuringtools(query, search_term):
|
||||||
|
"""Search measuring tools, including the gaugelabreference identifier.
|
||||||
|
|
||||||
|
The generic asset search already matches number/name/serial across all asset
|
||||||
|
types; this gated searcher adds gaugelabreference (the gage tag the gage lab
|
||||||
|
searches by) and drops out when the measuringtools plugin is disabled.
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
try:
|
||||||
|
_require_enabled('measuringtools')
|
||||||
|
from plugins.measuringtools.models import MeasuringTool
|
||||||
|
assets = db.session.query(Asset).join(
|
||||||
|
MeasuringTool, MeasuringTool.assetid == Asset.assetid
|
||||||
|
).options(
|
||||||
|
joinedload(Asset.assettype),
|
||||||
|
joinedload(Asset.location),
|
||||||
|
).filter(
|
||||||
|
Asset.isactive == True,
|
||||||
|
db.or_(
|
||||||
|
Asset.assetnumber.ilike(search_term),
|
||||||
|
Asset.name.ilike(search_term),
|
||||||
|
Asset.serialnumber.ilike(search_term),
|
||||||
|
Asset.gaugelabreference.ilike(search_term),
|
||||||
|
)
|
||||||
|
).limit(15).all()
|
||||||
|
|
||||||
|
for asset in assets:
|
||||||
|
relevance = 15
|
||||||
|
if asset.assetnumber and query.lower() == asset.assetnumber.lower():
|
||||||
|
relevance = 100
|
||||||
|
elif asset.gaugelabreference and query.lower() == asset.gaugelabreference.lower():
|
||||||
|
relevance = 90
|
||||||
|
elif asset.serialnumber and query.lower() == asset.serialnumber.lower():
|
||||||
|
relevance = 85
|
||||||
|
elif asset.name and query.lower() in asset.name.lower():
|
||||||
|
relevance = 50
|
||||||
|
results.append(_get_asset_result(asset, query, relevance))
|
||||||
|
except ImportError:
|
||||||
|
pass # measuringtools plugin absent or disabled
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Measuring tool search failed: {e}")
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
def _search_by_ip(query, search_term):
|
def _search_by_ip(query, search_term):
|
||||||
"""Search Communications table for IP address matches."""
|
"""Search Communications table for IP address matches."""
|
||||||
results = []
|
results = []
|
||||||
@@ -751,6 +798,7 @@ def global_search():
|
|||||||
results.extend(_search_knowledgebase(query, search_term))
|
results.extend(_search_knowledgebase(query, search_term))
|
||||||
results.extend(_search_employees(query, search_term))
|
results.extend(_search_employees(query, search_term))
|
||||||
results.extend(_search_assets(query, search_term))
|
results.extend(_search_assets(query, search_term))
|
||||||
|
results.extend(_search_measuringtools(query, search_term))
|
||||||
results.extend(_search_notifications(query, search_term))
|
results.extend(_search_notifications(query, search_term))
|
||||||
results.extend(_search_hostnames(query, search_term))
|
results.extend(_search_hostnames(query, search_term))
|
||||||
results.extend(_search_vendor_model_type(query, search_term))
|
results.extend(_search_vendor_model_type(query, search_term))
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ IDENTIFIER_LABELS = {
|
|||||||
'maintenancereference': 'Maintenance Reference',
|
'maintenancereference': 'Maintenance Reference',
|
||||||
'fqdn': 'FQDN / hostname',
|
'fqdn': 'FQDN / hostname',
|
||||||
}
|
}
|
||||||
IDENTIFIER_ASSETTYPES = ['machine', 'computer', 'printer', 'network_device']
|
IDENTIFIER_ASSETTYPES = ['machine', 'computer', 'printer', 'network_device',
|
||||||
|
'measuring_tool']
|
||||||
|
|
||||||
# Global-search result types that can be toggled on/off independently of whether
|
# Global-search result types that can be toggled on/off independently of whether
|
||||||
# the owning plugin is enabled. Keys match the `type` field on search results;
|
# the owning plugin is enabled. Keys match the `type` field on search results;
|
||||||
@@ -67,6 +68,7 @@ SEARCH_DOMAINS = {
|
|||||||
'computer': 'PCs',
|
'computer': 'PCs',
|
||||||
'printer': 'Printers',
|
'printer': 'Printers',
|
||||||
'network_device': 'Network Devices',
|
'network_device': 'Network Devices',
|
||||||
|
'measuring_tool': 'Measuring Tools',
|
||||||
'notification': 'Notifications',
|
'notification': 'Notifications',
|
||||||
'subnet': 'Subnets',
|
'subnet': 'Subnets',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,6 +240,74 @@ def test_list_filter_by_calibrationstatus(client, auth_headers):
|
|||||||
assert all(r['measuringtool']['calibrationstatus'] == 'overdue' for r in rows)
|
assert all(r['measuringtool']['calibrationstatus'] == 'overdue' for r in rows)
|
||||||
|
|
||||||
|
|
||||||
|
# -- Maintenance reference identifier -----------------------------------------
|
||||||
|
|
||||||
|
def test_maintenancereference_roundtrip(client, auth_headers):
|
||||||
|
"""Maintenance reference persists on create and update."""
|
||||||
|
created = client.post('/api/measuringtools', headers=auth_headers, json={
|
||||||
|
'assetnumber': 'MT-MNT-1', 'statusid': _status_id(client),
|
||||||
|
'maintenancereference': 'MNT-9',
|
||||||
|
})
|
||||||
|
assert created.status_code == 201, created.get_json()
|
||||||
|
assert created.get_json()['data']['maintenancereference'] == 'MNT-9'
|
||||||
|
tool_id = created.get_json()['data']['measuringtool']['measuringtoolid']
|
||||||
|
|
||||||
|
updated = client.put(f'/api/measuringtools/{tool_id}', headers=auth_headers,
|
||||||
|
json={'maintenancereference': 'MNT-10'})
|
||||||
|
assert updated.status_code == 200
|
||||||
|
assert updated.get_json()['data']['maintenancereference'] == 'MNT-10'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Global search ------------------------------------------------------------
|
||||||
|
|
||||||
|
def _mt_search_hits(client, auth_headers, term):
|
||||||
|
resp = client.get(f'/api/search?q={term}', headers=auth_headers)
|
||||||
|
assert resp.status_code == 200, resp.get_json()
|
||||||
|
return [r for r in resp.get_json()['data']['results']
|
||||||
|
if r.get('type') == 'measuring_tool']
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_finds_tool_by_assetnumber(mt_app, client, auth_headers, monkeypatch):
|
||||||
|
"""A measuring tool appears in global search by asset number, routed right."""
|
||||||
|
client.post('/api/measuringtools', headers=auth_headers, json={
|
||||||
|
'assetnumber': 'MT-SEARCH-AN', 'statusid': _status_id(client)})
|
||||||
|
pm = mt_app.extensions['plugin_manager']
|
||||||
|
monkeypatch.setattr(pm.registry, 'is_enabled', lambda name: True)
|
||||||
|
hits = _mt_search_hits(client, auth_headers, 'MT-SEARCH-AN')
|
||||||
|
assert hits
|
||||||
|
assert hits[0]['url'].startswith('/measuringtools/')
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_finds_tool_by_gaugelabreference(mt_app, client, auth_headers, monkeypatch):
|
||||||
|
"""A gage-tag lookup by gaugelabreference finds the tool."""
|
||||||
|
client.post('/api/measuringtools', headers=auth_headers, json={
|
||||||
|
'assetnumber': 'MT-SEARCH-GL', 'statusid': _status_id(client),
|
||||||
|
'gaugelabreference': 'GLREF-778'})
|
||||||
|
pm = mt_app.extensions['plugin_manager']
|
||||||
|
monkeypatch.setattr(pm.registry, 'is_enabled', lambda name: True)
|
||||||
|
hits = _mt_search_hits(client, auth_headers, 'GLREF-778')
|
||||||
|
assert hits
|
||||||
|
assert hits[0]['url'].startswith('/measuringtools/')
|
||||||
|
|
||||||
|
|
||||||
|
def test_search_excludes_tools_when_domain_disabled(mt_app, client, auth_headers, monkeypatch):
|
||||||
|
"""search_measuring_tool_enabled=false hides measuring tools from search."""
|
||||||
|
from shopdb.core.models import Setting
|
||||||
|
client.post('/api/measuringtools', headers=auth_headers, json={
|
||||||
|
'assetnumber': 'MT-SEARCH-OFF', 'statusid': _status_id(client),
|
||||||
|
'gaugelabreference': 'GLREF-OFF-1'})
|
||||||
|
pm = mt_app.extensions['plugin_manager']
|
||||||
|
monkeypatch.setattr(pm.registry, 'is_enabled', lambda name: True)
|
||||||
|
Setting.set('search_measuring_tool_enabled', False, valuetype='boolean',
|
||||||
|
category='search')
|
||||||
|
try:
|
||||||
|
assert _mt_search_hits(client, auth_headers, 'MT-SEARCH-OFF') == []
|
||||||
|
assert _mt_search_hits(client, auth_headers, 'GLREF-OFF-1') == []
|
||||||
|
finally:
|
||||||
|
Setting.set('search_measuring_tool_enabled', True, valuetype='boolean',
|
||||||
|
category='search')
|
||||||
|
|
||||||
|
|
||||||
# -- Report shape -------------------------------------------------------------
|
# -- Report shape -------------------------------------------------------------
|
||||||
|
|
||||||
def test_calibration_report_shape(client, auth_headers):
|
def test_calibration_report_shape(client, auth_headers):
|
||||||
|
|||||||
Reference in New Issue
Block a user