Settings Consolidation (37+ pages to 8 hubs): - Asset Type Hub: Unified type management with plugin descriptors - Model Catalog Hub: Vendors, types, models, operating systems - Asset Configuration Hub: Statuses, relationships, fields, identifiers - Security Hub: Authentication, tokens, users, audit - Site Configuration Hub: Site settings, floor map, branding, imports - Integrations Hub: ServiceNow, Zabbix, Dell warranty - Locations Hub: Locations, business units, employees - Network Infrastructure Hub: VLANs, subnets Plugin Descriptor Pattern: - Add get_asset_type_descriptor hook to BasePlugin - Implement descriptors in 6 plugins (printers, computers, machines, network, measuringtools, locations) - Add /api/pluginui/asset-type-descriptors and core-type-descriptors endpoints - Generic SubtypesTab component renders CRUD UI from descriptor schema Security Fixes: - Fix stored XSS via javascript: URIs in Models and Support Teams - Add URL scheme validation (allow only http/https) in create/update endpoints - Fix plugin contract violations in endpoints plugin (use shopdb.api imports) - Add missing requiresAdmin guard to printer model supplies route - Add user-facing error messages to API token load failures Integration Improvements: - Add persistent tab navigation to ServiceNow, Zabbix, and Dell Warranty settings - Standardize integration settings UI across all three pages - Fix tab visibility when navigating between integrations Tested with 94-agent orchestrated review for ADR compliance and security.
119 lines
2.4 KiB
Vue
119 lines
2.4 KiB
Vue
<template>
|
|
<div class="security-hub">
|
|
<div class="hub-header">
|
|
<h2>Access & Security</h2>
|
|
<p class="description">Manage authentication, API tokens, users, roles, and audit logs</p>
|
|
</div>
|
|
|
|
<div class="tabs">
|
|
<router-link
|
|
:to="{ name: 'security-authentication' }"
|
|
class="tab"
|
|
:class="{ active: $route.name === 'security-authentication' }"
|
|
>
|
|
Authentication
|
|
</router-link>
|
|
<router-link
|
|
:to="{ name: 'security-tokens' }"
|
|
class="tab"
|
|
:class="{ active: $route.name === 'security-tokens' }"
|
|
>
|
|
API Tokens
|
|
</router-link>
|
|
<router-link
|
|
:to="{ name: 'security-users' }"
|
|
class="tab"
|
|
:class="{ active: $route.name === 'security-users' }"
|
|
>
|
|
Users & Roles
|
|
</router-link>
|
|
<router-link
|
|
:to="{ name: 'security-audit' }"
|
|
class="tab"
|
|
:class="{ active: $route.name === 'security-audit' }"
|
|
>
|
|
Audit Settings
|
|
</router-link>
|
|
<router-link
|
|
:to="{ name: 'security-auditlogs' }"
|
|
class="tab"
|
|
:class="{ active: $route.name === 'security-auditlogs' }"
|
|
>
|
|
Audit Logs
|
|
</router-link>
|
|
</div>
|
|
|
|
<div class="tab-content">
|
|
<router-view />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { onMounted } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
|
|
onMounted(() => {
|
|
if (route.name === 'security') {
|
|
router.replace({ name: 'security-authentication' })
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.security-hub {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.hub-header {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.hub-header h2 {
|
|
margin: 0 0 0.5rem;
|
|
font-size: 1.75rem;
|
|
}
|
|
|
|
.description {
|
|
margin: 0;
|
|
color: var(--text-light);
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.tabs {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
border-bottom: 1px solid var(--border-color);
|
|
background: var(--bg-secondary);
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.tab {
|
|
padding: 0.75rem 1.5rem;
|
|
text-decoration: none;
|
|
color: var(--text-light);
|
|
border-bottom: 2px solid transparent;
|
|
transition: all 0.15s;
|
|
font-weight: 500;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.tab:hover {
|
|
color: var(--text);
|
|
background: var(--hover-bg);
|
|
}
|
|
|
|
.tab.active {
|
|
color: var(--primary);
|
|
border-bottom-color: var(--primary);
|
|
}
|
|
|
|
.tab-content {
|
|
/* Content styled by child components */
|
|
}
|
|
</style>
|