From 5039aedca59a304f5caaf539c3327b94afeb11db Mon Sep 17 00:00:00 2001 From: Benjamin Date: Mon, 28 Sep 2026 18:56:33 +0200 Subject: [PATCH 1/5] feat(ui): add one shared component per form and navigation control Add TabNav, CountBadge, UiButton, FormField, TextInput, SelectInput, TextareaInput, CheckboxInput, RadioGroup, ToggleSwitch and UiModal, with their demo on /_ds and unit tests. ConfirmDialog is rebuilt on UiModal and UiButton with an unchanged API. ESLint now warns on raw input, select, textarea and button elements outside components/ui, pointing to the shared component to use. --- frontend/eslint.config.ts | 15 ++ frontend/src/components/ui/CheckboxInput.vue | 69 +++++++ frontend/src/components/ui/ConfirmDialog.vue | 124 ++----------- frontend/src/components/ui/CountBadge.vue | 40 ++++ frontend/src/components/ui/FormField.vue | 43 +++++ frontend/src/components/ui/RadioGroup.vue | 55 ++++++ frontend/src/components/ui/SelectInput.vue | 51 +++++ frontend/src/components/ui/TabNav.vue | 77 ++++++++ frontend/src/components/ui/TextInput.vue | 49 +++++ frontend/src/components/ui/TextareaInput.vue | 38 ++++ frontend/src/components/ui/ToggleSwitch.vue | 55 ++++++ frontend/src/components/ui/UiButton.vue | 61 ++++++ frontend/src/components/ui/UiModal.vue | 103 +++++++++++ .../ui/__tests__/CheckboxInput.spec.ts | 30 +++ .../ui/__tests__/ConfirmDialog.spec.ts | 49 +++++ .../ui/__tests__/CountBadge.spec.ts | 26 +++ .../components/ui/__tests__/FormField.spec.ts | 56 ++++++ .../ui/__tests__/RadioGroup.spec.ts | 41 +++++ .../ui/__tests__/SelectInput.spec.ts | 33 ++++ .../components/ui/__tests__/TabNav.spec.ts | 44 +++++ .../components/ui/__tests__/TextInput.spec.ts | 36 ++++ .../ui/__tests__/TextareaInput.spec.ts | 29 +++ .../ui/__tests__/ToggleSwitch.spec.ts | 38 ++++ .../components/ui/__tests__/UiButton.spec.ts | 44 +++++ .../components/ui/__tests__/UiModal.spec.ts | 56 ++++++ frontend/src/pages/DesignSystemPage.vue | 174 +++++++++++++++++- 26 files changed, 1330 insertions(+), 106 deletions(-) create mode 100644 frontend/src/components/ui/CheckboxInput.vue create mode 100644 frontend/src/components/ui/CountBadge.vue create mode 100644 frontend/src/components/ui/FormField.vue create mode 100644 frontend/src/components/ui/RadioGroup.vue create mode 100644 frontend/src/components/ui/SelectInput.vue create mode 100644 frontend/src/components/ui/TabNav.vue create mode 100644 frontend/src/components/ui/TextInput.vue create mode 100644 frontend/src/components/ui/TextareaInput.vue create mode 100644 frontend/src/components/ui/ToggleSwitch.vue create mode 100644 frontend/src/components/ui/UiButton.vue create mode 100644 frontend/src/components/ui/UiModal.vue create mode 100644 frontend/src/components/ui/__tests__/CheckboxInput.spec.ts create mode 100644 frontend/src/components/ui/__tests__/ConfirmDialog.spec.ts create mode 100644 frontend/src/components/ui/__tests__/CountBadge.spec.ts create mode 100644 frontend/src/components/ui/__tests__/FormField.spec.ts create mode 100644 frontend/src/components/ui/__tests__/RadioGroup.spec.ts create mode 100644 frontend/src/components/ui/__tests__/SelectInput.spec.ts create mode 100644 frontend/src/components/ui/__tests__/TabNav.spec.ts create mode 100644 frontend/src/components/ui/__tests__/TextInput.spec.ts create mode 100644 frontend/src/components/ui/__tests__/TextareaInput.spec.ts create mode 100644 frontend/src/components/ui/__tests__/ToggleSwitch.spec.ts create mode 100644 frontend/src/components/ui/__tests__/UiButton.spec.ts create mode 100644 frontend/src/components/ui/__tests__/UiModal.spec.ts diff --git a/frontend/eslint.config.ts b/frontend/eslint.config.ts index 4e90ef70..2937183e 100644 --- a/frontend/eslint.config.ts +++ b/frontend/eslint.config.ts @@ -26,6 +26,21 @@ export default defineConfigWithVueTs( files: ['src/**/__tests__/*'], }, + { + name: 'app/shared-ui-components', + files: ['src/**/*.vue'], + ignores: ['src/components/ui/**', 'src/**/__tests__/**'], + rules: { + 'vue/no-restricted-html-elements': [ + 'warn', + { element: 'input', message: 'Use the shared TextInput, CheckboxInput, or RadioGroup component instead of a raw .' }, + { element: 'select', message: 'Use the shared SelectInput component instead of a raw - + + +
- - + Create + Cancel
@@ -189,15 +190,10 @@ const incidentStatusOptions = ['investigating', 'identified', 'monitoring', 'res {{ inc.title }}
- - + + Delete
@@ -216,19 +212,19 @@ const incidentStatusOptions = ['investigating', 'identified', 'monitoring', 'res
-
- - -
-
- - -
+ + + + + +
- - + Post Update + Cancel
diff --git a/frontend/src/components/StatusMaintenanceManager.vue b/frontend/src/components/StatusMaintenanceManager.vue index b1ed8bfb..8aa68991 100644 --- a/frontend/src/components/StatusMaintenanceManager.vue +++ b/frontend/src/components/StatusMaintenanceManager.vue @@ -21,6 +21,11 @@ import { deleteMaintenance, type MaintenanceWindow, } from '@/services/statusApi' +import FormField from '@/components/ui/FormField.vue' +import TextInput from '@/components/ui/TextInput.vue' +import TextareaInput from '@/components/ui/TextareaInput.vue' +import CheckboxInput from '@/components/ui/CheckboxInput.vue' +import UiButton from '@/components/ui/UiButton.vue' const store = useStatusAdminStore() @@ -101,13 +106,7 @@ function statusStyle(mw: MaintenanceWindow): { bg: string; color: string } {

Maintenance Windows

- + Schedule Maintenance
@@ -115,39 +114,44 @@ function statusStyle(mw: MaintenanceWindow): { bg: string; color: string } { {{ editingId ? 'Edit Maintenance' : 'Schedule Maintenance' }}
-
- - -
-
- - -
+ + + + + +
-
- - -
-
- - -
+ + + + + +
- +

No components configured

- - + {{ editingId ? 'Update' : 'Schedule' }} + Cancel
@@ -174,15 +178,15 @@ function statusStyle(mw: MaintenanceWindow): { bg: string; color: string } { {{ mw.title }}
- - + + Delete

{{ mw.description }}

diff --git a/frontend/src/components/StatusSmtpConfig.vue b/frontend/src/components/StatusSmtpConfig.vue index 95d5c507..6397c528 100644 --- a/frontend/src/components/StatusSmtpConfig.vue +++ b/frontend/src/components/StatusSmtpConfig.vue @@ -14,6 +14,10 @@

- + diff --git a/frontend/src/components/UpdateDetailPanel.vue b/frontend/src/components/UpdateDetailPanel.vue index 997b3d44..badc0df8 100644 --- a/frontend/src/components/UpdateDetailPanel.vue +++ b/frontend/src/components/UpdateDetailPanel.vue @@ -23,6 +23,8 @@ import CveList from '@/components/CveList.vue' import ChangelogViewer from '@/components/ChangelogViewer.vue' import FeatureGate from '@/components/FeatureGate.vue' import AcknowledgeButton from '@/components/ui/AcknowledgeButton.vue' +import UiButton from '@/components/ui/UiButton.vue' +import TextareaInput from '@/components/ui/TextareaInput.vue' import { AlertTriangle, ArrowRight, Check, Copy, ExternalLink, Pin, PinOff } from 'lucide-vue-next' const { hasFeature } = useEdition() @@ -205,14 +207,16 @@ onMounted(loadDetail)

Update Command

- +
           Rollback Command
         
-        
+        
       
       
       
       
- +
-