Password Policy/App rename/PM Scheduling Improvements

This commit is contained in:
2026-06-06 02:32:47 -05:00
parent dfd999b6a9
commit f024286b5e
59 changed files with 3814 additions and 299 deletions

View File

@@ -25,6 +25,11 @@
<span class="font-weight-bold">{{ row.name }}</span>
</template>
<template #cell-code="{ row }">{{ row.code || '—' }}</template>
<template #cell-asset_class_number="{ row }">
<span v-if="row.asset_class_label" :title="row.asset_class_label">{{ row.asset_class_label }}</span>
<span v-else-if="row.asset_class_number">{{ row.asset_class_number }}</span>
<span v-else class="quiet"></span>
</template>
<template #cell-id_template_name="{ row }">
<span v-if="row.id_template_name">{{ row.id_template_name }} <span class="quiet">({{ row.id_template_pattern }})</span></span>
<span v-else class="quiet">Default (MA-#####)</span>
@@ -59,6 +64,7 @@
label="Asset class number (optional)"
:hint="classHint || 'Shared by every asset in this category'"
persistent-hint
@update:model-value="onClassNumberInput"
/>
<v-select
v-model="form.id_template_id"
@@ -133,7 +139,7 @@ export default {
dialog: false,
deleteDialog: false,
deleteTarget: null,
form: { id: null, name: '', code: '', asset_class_number: '', id_template_id: null },
form: { id: null, name: '', code: '', asset_class_id: null, asset_class_number: '', id_template_id: null },
saving: false,
error: '',
dialogError: '',
@@ -155,14 +161,18 @@ export default {
},
assetClassItems() {
const tableLabels = { common: 'Common', industry: 'Manufacturing', business: 'Business', custom: 'Custom' };
return this.pickableClasses.map((c, index) => ({
// Value is the class's unique id — class numbers are not unique, so an index/number would
// collide (e.g. 00.12 is both Computers and Casinos).
return this.pickableClasses.map((c) => ({
title: `${c.class_number}${c.description} (GDS ${c.gds ?? '—'} / ADS ${c.ads ?? '—'}) · ${tableLabels[c.table] || 'Common'}`,
value: index
value: c.id
}));
},
classHint() {
const match = this.assetClasses.find((c) => c.class_number && c.class_number === String(this.form.asset_class_number || '').trim());
if (!match) return '';
const match = this.form.asset_class_id ? this.assetClasses.find((c) => c.id === this.form.asset_class_id) : null;
if (!match) {
return this.form.asset_class_number ? `Manual entry — not linked to a catalog class.` : '';
}
return `IRS ${match.class_number} · ${match.description} · GDS ${match.gds ?? '—'} / ADS ${match.ads ?? '—'} yrs`;
}
},
@@ -200,20 +210,27 @@ export default {
this.assetClasses = [];
}
},
applyAssetClass(index) {
const entry = index != null ? this.pickableClasses[index] : null;
if (entry) this.form.asset_class_number = entry.class_number;
applyAssetClass(id) {
const entry = id != null ? this.assetClasses.find((c) => c.id === id) : null;
if (entry) {
this.form.asset_class_id = entry.id;
this.form.asset_class_number = entry.class_number;
}
this.$nextTick(() => { this.classLookup = null; });
},
onClassNumberInput() {
// Typing a number by hand detaches it from a catalog class (manual override).
this.form.asset_class_id = null;
},
openNew() {
this.loadTemplates(); this.loadAssetClasses(); this.classLookup = null;
this.form = { id: null, name: '', code: '', asset_class_number: '', id_template_id: null };
this.form = { id: null, name: '', code: '', asset_class_id: null, asset_class_number: '', id_template_id: null };
this.dialogError = '';
this.dialog = true;
},
openEdit(row) {
this.loadTemplates(); this.loadAssetClasses(); this.classLookup = null;
this.form = { id: row.id, name: row.name, code: row.code || '', asset_class_number: row.asset_class_number || '', id_template_id: row.id_template_id || null };
this.form = { id: row.id, name: row.name, code: row.code || '', asset_class_id: row.asset_class_id || null, asset_class_number: row.asset_class_number || '', id_template_id: row.id_template_id || null };
this.dialogError = '';
this.dialog = true;
},
@@ -225,7 +242,7 @@ export default {
try {
const method = this.form.id ? 'PUT' : 'POST';
const url = this.form.id ? `/api/asset-categories/${this.form.id}` : '/api/asset-categories';
await this.api(url, { method, body: JSON.stringify({ name, code: this.form.code || null, asset_class_number: this.form.asset_class_number || null, id_template_id: this.form.id_template_id || null }) });
await this.api(url, { method, body: JSON.stringify({ name, code: this.form.code || null, asset_class_id: this.form.asset_class_id || null, asset_class_number: this.form.asset_class_number || null, id_template_id: this.form.id_template_id || null }) });
this.dialog = false;
await this.load();
this.$emit('updated');