Make gauge/maintenance identifiers per-asset-type and extend to all types
Optional asset identifiers (gauge lab reference, maintenance reference, FQDN) were global per-identifier and only surfaced on equipment. Now they are toggleable per asset type and rendered on every asset type. - settings: replace 3 global identifier toggles with a per-type matrix. New keys identifier_<name>_<assettype>_enabled (3 identifiers x 4 types). IDENTIFIER_LABELS / IDENTIFIER_ASSETTYPES constants drive the seed (API seed and CLI seed settings). - composable: identifierSettings now exposes isEnabled(name, assettype), per-type flag winning over the legacy global key, defaulting on. - backend writes: computers, network, printers asset create + update now accept gaugelabreference and maintenancereference (equipment already did). Reads already flowed through Asset.to_dict. - frontend: Settings page renders an identifier x asset-type toggle matrix. Equipment, PC, printer, network forms and detail pages show gauge/maintenance (and FQDN where applicable) gated by isEnabled(name, type). Legacy global identifier_<name>_enabled keys are still honored as a fallback for older installs. SystemSettings toggles upsert (create on 404) so a deploy that has not re-seeded still works on first toggle. 144 tests pass, naming/style check green, frontend builds. Verified live: matrix renders, PC form shows the fields, PUT persists gauge/maintenance on a PC and reads back. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -382,50 +382,35 @@
|
||||
|
||||
<div class="setting-group">
|
||||
<p class="setting-description">
|
||||
Enable or disable optional asset identifiers. When disabled, the identifier
|
||||
is hidden from asset forms and detail pages across the system.
|
||||
Enable or disable optional asset identifiers per asset type. When disabled
|
||||
for a type, the identifier is hidden from that type's forms and detail
|
||||
pages across the system.
|
||||
</p>
|
||||
|
||||
<div class="setting-row">
|
||||
<label class="toggle-label">
|
||||
<span>Gauge Lab Reference</span>
|
||||
<button
|
||||
class="toggle-btn"
|
||||
:class="{ active: settings.identifier_gaugelabreference_enabled }"
|
||||
@click="toggleSetting('identifier_gaugelabreference_enabled')"
|
||||
:disabled="saving"
|
||||
>
|
||||
<span class="toggle-slider"></span>
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-row">
|
||||
<label class="toggle-label">
|
||||
<span>Maintenance Reference</span>
|
||||
<button
|
||||
class="toggle-btn"
|
||||
:class="{ active: settings.identifier_maintenancereference_enabled }"
|
||||
@click="toggleSetting('identifier_maintenancereference_enabled')"
|
||||
:disabled="saving"
|
||||
>
|
||||
<span class="toggle-slider"></span>
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-row">
|
||||
<label class="toggle-label">
|
||||
<span>FQDN / Hostname</span>
|
||||
<button
|
||||
class="toggle-btn"
|
||||
:class="{ active: settings.identifier_fqdn_enabled }"
|
||||
@click="toggleSetting('identifier_fqdn_enabled')"
|
||||
:disabled="saving"
|
||||
>
|
||||
<span class="toggle-slider"></span>
|
||||
</button>
|
||||
</label>
|
||||
<div class="table-container">
|
||||
<table class="identifier-matrix">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Identifier</th>
|
||||
<th v-for="col in assetTypeCols" :key="col.key">{{ col.label }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in identifierRows" :key="row.name">
|
||||
<td class="identifier-name">{{ row.label }}</td>
|
||||
<td v-for="col in assetTypeCols" :key="col.key">
|
||||
<button
|
||||
class="toggle-btn"
|
||||
:class="{ active: matrixValue(row.name, col.key) }"
|
||||
@click="toggleIdentifier(row.name, col.key)"
|
||||
:disabled="saving"
|
||||
>
|
||||
<span class="toggle-slider"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -463,13 +448,33 @@ const settings = reactive({
|
||||
saml_acs_url: '',
|
||||
saml_allow_local_login: true,
|
||||
saml_auto_create_users: true,
|
||||
saml_admin_group: '',
|
||||
// Asset identifiers
|
||||
identifier_gaugelabreference_enabled: true,
|
||||
identifier_maintenancereference_enabled: true,
|
||||
identifier_fqdn_enabled: true
|
||||
saml_admin_group: ''
|
||||
})
|
||||
|
||||
// Asset identifier matrix: identifier x asset type. Keys follow
|
||||
// identifier_<name>_<assettype>_enabled. Missing = enabled (default on).
|
||||
const identifierRows = [
|
||||
{ name: 'gaugelabreference', label: 'Gauge Lab Reference' },
|
||||
{ name: 'maintenancereference', label: 'Maintenance Reference' },
|
||||
{ name: 'fqdn', label: 'FQDN / Hostname' }
|
||||
]
|
||||
const assetTypeCols = [
|
||||
{ key: 'equipment', label: 'Equipment' },
|
||||
{ key: 'computer', label: 'PC' },
|
||||
{ key: 'printer', label: 'Printer' },
|
||||
{ key: 'network_device', label: 'Network' }
|
||||
]
|
||||
const identifierMatrix = reactive({})
|
||||
|
||||
function identifierKey(name, assettype) {
|
||||
return `identifier_${name}_${assettype}_enabled`
|
||||
}
|
||||
|
||||
function matrixValue(name, assettype) {
|
||||
const key = identifierKey(name, assettype)
|
||||
return key in identifierMatrix ? identifierMatrix[key] : true
|
||||
}
|
||||
|
||||
const loading = ref(true)
|
||||
const saving = ref(false)
|
||||
const testingEmail = ref(false)
|
||||
@@ -530,6 +535,8 @@ async function loadSettings() {
|
||||
for (const setting of data.data) {
|
||||
if (setting.key in settings) {
|
||||
settings[setting.key] = setting.value
|
||||
} else if (/^identifier_.+_(equipment|computer|printer|network_device)_enabled$/.test(setting.key)) {
|
||||
identifierMatrix[setting.key] = setting.value !== false
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -545,6 +552,41 @@ async function toggleSetting(key) {
|
||||
await saveSetting(key, newValue)
|
||||
}
|
||||
|
||||
// Toggle a per-type identifier flag. The key may not be seeded yet on older
|
||||
// installs, so fall back to creating it when the update returns 404.
|
||||
async function toggleIdentifier(name, assettype) {
|
||||
const key = identifierKey(name, assettype)
|
||||
const newValue = !matrixValue(name, assettype)
|
||||
try {
|
||||
saving.value = true
|
||||
error.value = ''
|
||||
success.value = ''
|
||||
try {
|
||||
await settingsApi.update(key, newValue)
|
||||
} catch (e) {
|
||||
if (e.response?.status === 404) {
|
||||
await settingsApi.create({
|
||||
key,
|
||||
value: newValue,
|
||||
valuetype: 'boolean',
|
||||
category: 'identifiers',
|
||||
description: `Show the ${name} identifier on ${assettype} assets`
|
||||
})
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
identifierMatrix[key] = newValue
|
||||
success.value = 'Setting saved'
|
||||
setTimeout(() => { success.value = '' }, 2000)
|
||||
} catch (e) {
|
||||
error.value = e.response?.data?.message || 'Failed to save setting'
|
||||
console.error(e)
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSetting(key, value) {
|
||||
try {
|
||||
saving.value = true
|
||||
@@ -797,4 +839,31 @@ onMounted(loadSettings)
|
||||
margin-top: -0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.identifier-matrix {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.identifier-matrix th,
|
||||
.identifier-matrix td {
|
||||
padding: 0.6rem 0.75rem;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.identifier-matrix th:first-child,
|
||||
.identifier-matrix td.identifier-name {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.identifier-matrix th {
|
||||
color: var(--text-light);
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.identifier-matrix .identifier-name {
|
||||
color: var(--text);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user