Add system settings, audit logging, user management, and dark mode fixes

System Settings:
- Add SystemSettings.vue with Zabbix integration, SMTP/email config, SAML SSO settings
- Add Setting model with key-value storage and typed values
- Add settings API with caching

Audit Logging:
- Add AuditLog model tracking user, IP, action, entity changes
- Add comprehensive audit logging to all CRUD operations:
  - Machines, Computers, Equipment, Network devices, VLANs, Subnets
  - Printers, USB devices (including checkout/checkin)
  - Applications, Settings, Users/Roles
- Track old/new values for all field changes
- Mask sensitive values (passwords, tokens) in logs

User Management:
- Add UsersList.vue with full user CRUD
- Add Role management with granular permissions
- Add 41 predefined permissions across 10 categories
- Add users API with roles and permissions endpoints

Reports:
- Add TonerReport.vue for printer supply monitoring

Dark Mode Fixes:
- Fix map position section in PCForm, PrinterForm
- Fix alert-warning in KnowledgeBaseDetail
- All components now use CSS variables for theming

CLI Commands:
- Add flask seed permissions
- Add flask seed settings

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-02-04 22:16:56 -05:00
parent 83caaa7b7c
commit 2c36c0c873
40 changed files with 4221 additions and 39 deletions

View File

@@ -48,6 +48,25 @@
</aside>
<main class="main-content">
<div v-if="activeNotifications.length" class="notification-banner">
<div
v-for="n in activeNotifications"
:key="n.notificationid"
class="notification-item"
:class="getNotificationType(n)"
>
<span class="notification-text">{{ n.notification }}</span>
<span class="notification-meta">
<span v-if="n.starttime" class="notification-date">{{ formatDate(n.starttime) }}</span>
<a
v-if="n.ticketnumber"
:href="`https://geit.service-now.com/now/nav/ui/search/0f8b85d0c7922010099a308dc7c2606a/params/search-term/${n.ticketnumber}/global-search-data-config-id/c861cea2c7022010099a308dc7c26041/back-button-label/IT4IT%20Homepage/search-context/now%2Fnav%2Fui`"
target="_blank"
class="notification-ticket"
>{{ n.ticketnumber }}</a>
</span>
</div>
</div>
<router-view />
</main>
</div>
@@ -62,12 +81,13 @@ import {
} from 'lucide-vue-next'
import { useAuthStore } from '../stores/auth'
import { currentTheme, toggleTheme } from '../stores/theme'
import { dashboardApi } from '../api'
import { dashboardApi, notificationsApi } from '../api'
const router = useRouter()
const authStore = useAuthStore()
const searchQuery = ref('')
const navItems = ref([])
const activeNotifications = ref([])
// Map backend icon names to Lucide components
const iconMap = {
@@ -136,11 +156,31 @@ onMounted(async () => {
const response = await dashboardApi.navigation()
navItems.value = buildNavItems(response.data.data || [])
} catch (err) {
// Fall back to default navigation if API unavailable
navItems.value = buildNavItems(defaultNav)
}
try {
const resp = await notificationsApi.active()
activeNotifications.value = resp.data.data?.notifications || []
} catch (err) {
// Notifications banner is non-critical
}
})
function getNotificationType(n) {
const type = (n.typename || '').toLowerCase()
if (type.includes('incident')) return 'type-incident'
if (type.includes('change')) return 'type-change'
if (type.includes('awareness')) return 'type-awareness'
return 'type-default'
}
function formatDate(dateStr) {
if (!dateStr) return ''
const d = new Date(dateStr)
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' })
}
function performSearch() {
if (searchQuery.value.trim()) {
router.push({ path: '/search', query: { q: searchQuery.value.trim() } })