ADR-013 Phase 4 complete: all plugin frontends self-contained + lint rule

This commit is contained in:
2026-07-19 00:03:33 -04:00
parent d1592b84c7
commit de93b613cc
20 changed files with 110 additions and 84 deletions

View File

@@ -28,24 +28,6 @@ export default [
name: 'reports',
component: () => import('../../views/reports/ReportsIndex.vue')
},
{
path: 'reports/pc-relationships',
name: 'report-pc-relationships',
component: () => import('../../views/reports/PCRelationshipsReport.vue'),
meta: { plugin: 'computers' }
},
{
path: 'reports/toner',
name: 'toner-report',
component: () => import('../../views/reports/TonerReport.vue'),
meta: { plugin: 'printers' }
},
{
path: 'employees/:sso',
name: 'employee-detail',
component: () => import('../../views/employees/EmployeeDetail.vue'),
meta: { plugin: 'employees' }
},
// Settings
{
path: 'settings',
@@ -107,30 +89,6 @@ export default [
component: () => import('../../views/settings/SiteSettings.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/slides',
name: 'slide-manager',
component: () => import('../../views/settings/SlideManager.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'slides' }
},
{
path: 'settings/machinetypes',
name: 'machinetypes',
component: () => import('../../views/settings/MachineTypesList.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/networktypes',
name: 'network-types',
component: () => import('../../views/settings/NetworkTypesList.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/printertypes',
name: 'printer-types',
component: () => import('../../views/settings/PrinterTypesList.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/relationshiptypes',
name: 'relationship-types',
@@ -155,12 +113,6 @@ export default [
component: () => import('../../views/settings/CustomFieldsList.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/employeedirectory',
name: 'employee-directory',
component: () => import('../../views/settings/EmployeeDirectory.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
// The old monolithic System Settings tab page is split into one routed page
// per section (below). This redirect keeps old bookmarks working: bare
// /settings/system and every /settings/system?tab=<key> land on the right page.
@@ -192,24 +144,6 @@ export default [
component: () => import('../../views/settings/ServiceNowSettings.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/zabbix',
name: 'zabbix-settings',
component: () => import('../../views/settings/ZabbixSettings.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/dellwarranty',
name: 'dell-warranty-settings',
component: () => import('../../views/settings/DellWarrantySettings.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/pctypemapping',
name: 'pctype-mapping-settings',
component: () => import('../../views/settings/PCTypeMappingSettings.vue'),
meta: { requiresAuth: true, requiresAdmin: true }
},
{
path: 'settings/branding',
name: 'branding-settings',

View File

@@ -2,6 +2,18 @@
* Computers plugin routes
*/
export default [
{
path: 'reports/pc-relationships',
name: 'report-pc-relationships',
component: () => import('./views/PCRelationshipsReport.vue'),
meta: { plugin: 'computers' }
},
{
path: 'settings/pctypemapping',
name: 'pctype-mapping-settings',
component: () => import('./views/PCTypeMappingSettings.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'computers' }
},
{
path: 'pcs',
name: 'pcs',

View File

@@ -54,7 +54,7 @@
<script setup>
import { ref, onMounted } from 'vue'
import { reportsApi } from '../../api'
import { reportsApi } from '@/api'
const loading = ref(true)
const data = ref([])

View File

@@ -0,0 +1,18 @@
/**
* Employees plugin frontend routes (ADR-013 Phase 4). Extracted from core.js -
* employee detail + the directory settings page belong to the employees plugin.
*/
export default [
{
path: 'employees/:sso',
name: 'employee-detail',
component: () => import('./views/EmployeeDetail.vue'),
meta: { plugin: 'employees' }
},
{
path: 'settings/employeedirectory',
name: 'employee-directory',
component: () => import('./views/EmployeeDirectory.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'employees' }
}
]

View File

@@ -149,10 +149,10 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { withBase } from '../../utils/basePath'
import { withBase } from '@/utils/basePath'
import { employeesApi, usbApi, notificationsApi } from '@/api'
import { isPluginEnabled, loadEnabledPlugins } from '@/composables/enabledPlugins'
import { useToast } from '../../composables/toast'
import { useToast } from '@/composables/toast'
const toast = useToast()
const route = useRoute()

View File

@@ -134,9 +134,9 @@
<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { employeesApi, settingsApi } from '../../api'
import { useToast } from '../../composables/toast'
import { apiError } from '../../utils/apiError'
import { employeesApi, settingsApi } from '@/api'
import { useToast } from '@/composables/toast'
import { apiError } from '@/utils/apiError'
const toast = useToast()
const selfhosted = ref(false)

View File

@@ -2,6 +2,12 @@
* Machines plugin routes
*/
export default [
{
path: 'settings/machinetypes',
name: 'machinetypes',
component: () => import('./views/MachineTypesList.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'machines' }
},
{
path: 'machines',
name: 'machines',

View File

@@ -73,11 +73,11 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import { machinesApi } from '../../api'
import { machinesApi } from '@/api'
import ColorSwatchPicker from '@/components/ColorSwatchPicker.vue'
import { colorStyle } from '@/utils/colorStyle'
import { useToast } from '../../composables/toast'
import { apiError } from '../../utils/apiError'
import { useToast } from '@/composables/toast'
import { apiError } from '@/utils/apiError'
const toast = useToast()
const items = ref([])

View File

@@ -2,6 +2,12 @@
* Network plugin routes
*/
export default [
{
path: 'settings/networktypes',
name: 'network-types',
component: () => import('./views/NetworkTypesList.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'network' }
},
{
path: 'network',
name: 'network',

View File

@@ -73,11 +73,11 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import { networkApi } from '../../api'
import { networkApi } from '@/api'
import ColorSwatchPicker from '@/components/ColorSwatchPicker.vue'
import { colorStyle } from '@/utils/colorStyle'
import { useToast } from '../../composables/toast'
import { apiError } from '../../utils/apiError'
import { useToast } from '@/composables/toast'
import { apiError } from '@/utils/apiError'
const toast = useToast()
const items = ref([])

View File

@@ -2,6 +2,24 @@
* Printers plugin routes
*/
export default [
{
path: 'reports/toner',
name: 'toner-report',
component: () => import('./views/TonerReport.vue'),
meta: { plugin: 'printers' }
},
{
path: 'settings/printertypes',
name: 'printer-types',
component: () => import('./views/PrinterTypesList.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'printers' }
},
{
path: 'settings/zabbix',
name: 'zabbix-settings',
component: () => import('./views/ZabbixSettings.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'printers' }
},
{
path: 'printers',
name: 'printers',

View File

@@ -73,11 +73,11 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import { printersApi } from '../../api'
import { printersApi } from '@/api'
import ColorSwatchPicker from '@/components/ColorSwatchPicker.vue'
import { colorStyle } from '@/utils/colorStyle'
import { useToast } from '../../composables/toast'
import { apiError } from '../../utils/apiError'
import { useToast } from '@/composables/toast'
import { apiError } from '@/utils/apiError'
const toast = useToast()
const items = ref([])

View File

@@ -101,7 +101,7 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import { printersApi } from '@/api'
import EmailReportButton from '../../components/EmailReportButton.vue'
import EmailReportButton from '@/components/EmailReportButton.vue'
const emailColumns = [
{ key: 'printer', label: 'Printer' },

View File

@@ -65,7 +65,7 @@
<script setup>
import { onMounted, computed } from 'vue'
import { useSystemSettings } from '../../composables/systemSettings'
import { useSystemSettings } from '@/composables/systemSettings'
const {
settings, saving, error, success,

View File

@@ -1,4 +1,13 @@
export default [
{
path: 'settings/slides',
name: 'slide-manager',
component: () => import('./views/SlideManager.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'slides' }
}
]
export const toplevel = [
{
path: '/tv',

View File

@@ -2,6 +2,12 @@
* Warranty plugin routes
*/
export default [
{
path: 'settings/dellwarranty',
name: 'dell-warranty-settings',
component: () => import('./views/DellWarrantySettings.vue'),
meta: { requiresAuth: true, requiresAdmin: true, plugin: 'warranty' }
},
{
path: 'warranties',
name: 'warranties',

View File

@@ -92,7 +92,7 @@
<script setup>
import { onMounted, computed } from 'vue'
import { useSystemSettings } from '../../composables/systemSettings'
import { useSystemSettings } from '@/composables/systemSettings'
const {
settings, saving, error, success,

View File

@@ -106,6 +106,23 @@ if [ -n "$SNAKE_FE" ]; then
VIOLATIONS=$((VIOLATIONS + 1))
fi
# ADR-013 Phase 4: a plugin frontend (plugins/<name>/frontend/) may import core
# via the @/ alias or its own tree (./, ../ within the plugin), never another
# plugin's tree and never an escaping ../../ into src. Keeps plugin frontends
# self-contained so a per-site build can drop one cleanly.
echo "==> Checking for cross-plugin / escaping imports in plugin frontends..."
if [ -d plugins ]; then
PLUGIN_FE_IMPORTS=$(grep -rPn "(import|from)\s+['\"]([^'\"]*\.\./\.\./|[^'\"]*/plugins/)" \
--include='*.vue' --include='*.js' plugins/*/frontend/ 2>/dev/null || true)
if [ -n "$PLUGIN_FE_IMPORTS" ]; then
echo "FAIL: plugin frontend imports must use the @/ alias for core, not"
echo " an escaping ../../ or another plugin's path:"
echo "$PLUGIN_FE_IMPORTS"
echo
VIOLATIONS=$((VIOLATIONS + 1))
fi
fi
if [ "$VIOLATIONS" -gt 0 ]; then
echo "=================================================="
echo "$VIOLATIONS naming/style violation(s) found."