Add custom fields + warranty plugin, rework settings into two-pane shell
Feature work from the 2026-07 session: Settings IA - Replace the flat 27-card settings hub with a persistent two-pane shell (SettingsLayout.vue): grouped, searchable left rail + content pane. - Nest all settings/* routes under the shell via router post-processing; shared nav catalog in settingsNav.js. Group by asset class (PCs, Printers, Equipment, Network) so per-type settings stop scattering. Custom fields (core) - customfields + customfieldvalues tables (migration 7d14), CRUD API at /api/customfields, per-asset value get/save. - Settings management page + reusable CustomFieldsSection (detail) and CustomFieldsInputs (form) wired into all four asset types. Warranty (new plugin) - plugins/warranty: warranties + warrantyassets (migration 7d15), derived coverage status, provider abstraction (manual now; Dell/Lenovo/HP stubs). - API CRUD + per-asset panel + report buckets; WarrantyPanel on all four detail pages; Warranties management page; Warranty report + Reports card. - Seed warranty.* permissions. Printer drivers - printerdrivers table (migration 7d13) linked to printer models; drivers now surface on the matching printer's detail page. Other - PCDetail rebalanced (Network + Status + Warranty + custom fields on the right). - Rename PCs list "Features" column to "Remote Access"; fix badge hover underline. - Drop equipment islocationonly field. - Centralize asset-type label/route maps into utils/assetTypes.js. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -263,6 +263,79 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Floor Map Section -->
|
||||
<div class="section-card" v-show="isVisible('map')">
|
||||
<h2 class="section-title">Floor Map</h2>
|
||||
|
||||
<div class="setting-group">
|
||||
<h3>Facility Blueprint</h3>
|
||||
<p class="setting-description">
|
||||
The floor-plan image and its pixel dimensions for this facility. Map
|
||||
markers are positioned against these dimensions, so the width and
|
||||
height must match the native size of the blueprint image. Leave the
|
||||
image paths at their defaults to use the bundled sitemap.
|
||||
</p>
|
||||
|
||||
<div class="setting-row">
|
||||
<label>
|
||||
<span>Blueprint image URL (light theme)</span>
|
||||
<input
|
||||
type="text"
|
||||
v-model="settings.map_blueprint_light"
|
||||
placeholder="/static/images/sitemap2025-light.png"
|
||||
@blur="saveSetting('map_blueprint_light', settings.map_blueprint_light)"
|
||||
:disabled="saving"
|
||||
>
|
||||
<small class="input-hint">Path or URL to the light-theme floor plan</small>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-row">
|
||||
<label>
|
||||
<span>Blueprint image URL (dark theme)</span>
|
||||
<input
|
||||
type="text"
|
||||
v-model="settings.map_blueprint_dark"
|
||||
placeholder="/static/images/sitemap2025-dark.png"
|
||||
@blur="saveSetting('map_blueprint_dark', settings.map_blueprint_dark)"
|
||||
:disabled="saving"
|
||||
>
|
||||
<small class="input-hint">Path or URL to the dark-theme floor plan</small>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-row">
|
||||
<label>
|
||||
<span>Blueprint width (pixels)</span>
|
||||
<input
|
||||
type="number"
|
||||
v-model="settings.map_width"
|
||||
min="1"
|
||||
placeholder="3300"
|
||||
@blur="saveSetting('map_width', settings.map_width)"
|
||||
:disabled="saving"
|
||||
>
|
||||
<small class="input-hint">Native pixel width of the blueprint image</small>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="setting-row">
|
||||
<label>
|
||||
<span>Blueprint height (pixels)</span>
|
||||
<input
|
||||
type="number"
|
||||
v-model="settings.map_height"
|
||||
min="1"
|
||||
placeholder="2550"
|
||||
@blur="saveSetting('map_height', settings.map_height)"
|
||||
:disabled="saving"
|
||||
>
|
||||
<small class="input-hint">Native pixel height of the blueprint image</small>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Authentication Section -->
|
||||
<div class="section-card" v-show="isVisible('auth')">
|
||||
<h2 class="section-title">Authentication</h2>
|
||||
@@ -501,6 +574,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { settingsApi, computersApi } from '../../api'
|
||||
import { setIdentifierFlag } from '../../composables/identifierSettings'
|
||||
|
||||
@@ -513,10 +587,17 @@ const SETTINGS_TABS = [
|
||||
{ key: 'auth', label: 'Authentication', keywords: 'auth saml sso login users idp' },
|
||||
{ key: 'identifiers', label: 'Asset Identifiers', keywords: 'identifier gauge lab maintenance fqdn hostname asset' },
|
||||
{ key: 'search', label: 'Global Search', keywords: 'search results domains' },
|
||||
{ key: 'map', label: 'Floor Map', keywords: 'map floor plan blueprint image facility site dimensions width height' },
|
||||
{ key: 'pctype', label: 'PC Type Mapping', keywords: 'pc type mapping collector enrollment shopfloor computer type' },
|
||||
]
|
||||
const settingsSearch = ref('')
|
||||
const activeTab = ref('integrations')
|
||||
const route = useRoute()
|
||||
// Allow deep-linking to a tab, e.g. /settings/system?tab=map (Floor Map)
|
||||
const activeTab = ref(
|
||||
route.query.tab && SETTINGS_TABS.some(t => t.key === route.query.tab)
|
||||
? String(route.query.tab)
|
||||
: 'integrations'
|
||||
)
|
||||
|
||||
const visibleTabs = computed(() => {
|
||||
const term = settingsSearch.value.trim().toLowerCase()
|
||||
@@ -556,6 +637,11 @@ const settings = reactive({
|
||||
alert_recipients: '',
|
||||
// Audit
|
||||
audit_retention_days: 90,
|
||||
// Floor map blueprint (per-facility)
|
||||
map_blueprint_light: '',
|
||||
map_blueprint_dark: '',
|
||||
map_width: 3300,
|
||||
map_height: 2550,
|
||||
// SAML
|
||||
saml_enabled: false,
|
||||
saml_idp_metadata_url: '',
|
||||
|
||||
Reference in New Issue
Block a user