@motor-cms/ui-admin 1.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +77 -0
  2. package/app/components/form/inputs/CategoryTreeInput.vue +154 -0
  3. package/app/components/form/inputs/CategoryTreePicker.vue +355 -0
  4. package/app/components/form/inputs/NestedDraggable.vue +217 -0
  5. package/app/components/form/inputs/QuicklinksInput.vue +186 -0
  6. package/app/lang/de/motor-admin/CLAUDE.md +21 -0
  7. package/app/lang/de/motor-admin/ai_system_prompts.json +12 -0
  8. package/app/lang/de/motor-admin/categories.json +12 -0
  9. package/app/lang/de/motor-admin/category_trees.json +14 -0
  10. package/app/lang/de/motor-admin/clients.json +26 -0
  11. package/app/lang/de/motor-admin/config_variables.json +14 -0
  12. package/app/lang/de/motor-admin/domains.json +19 -0
  13. package/app/lang/de/motor-admin/email_templates.json +38 -0
  14. package/app/lang/de/motor-admin/global.json +5 -0
  15. package/app/lang/de/motor-admin/languages.json +16 -0
  16. package/app/lang/de/motor-admin/permissions.json +14 -0
  17. package/app/lang/de/motor-admin/roles.json +15 -0
  18. package/app/lang/de/motor-admin/users.json +22 -0
  19. package/app/lang/en/motor-admin/CLAUDE.md +7 -0
  20. package/app/lang/en/motor-admin/ai_system_prompts.json +12 -0
  21. package/app/lang/en/motor-admin/categories.json +12 -0
  22. package/app/lang/en/motor-admin/category_trees.json +14 -0
  23. package/app/lang/en/motor-admin/clients.json +26 -0
  24. package/app/lang/en/motor-admin/config_variables.json +14 -0
  25. package/app/lang/en/motor-admin/domains.json +18 -0
  26. package/app/lang/en/motor-admin/email_templates.json +33 -0
  27. package/app/lang/en/motor-admin/global.json +5 -0
  28. package/app/lang/en/motor-admin/languages.json +16 -0
  29. package/app/lang/en/motor-admin/permissions.json +14 -0
  30. package/app/lang/en/motor-admin/roles.json +15 -0
  31. package/app/lang/en/motor-admin/users.json +22 -0
  32. package/app/pages/dashboard.vue +5 -0
  33. package/app/pages/index.vue +39 -0
  34. package/app/pages/login.vue +85 -0
  35. package/app/pages/motor-admin/ai-system-prompts/CLAUDE.md +7 -0
  36. package/app/pages/motor-admin/ai-system-prompts/[id]/edit.vue +48 -0
  37. package/app/pages/motor-admin/ai-system-prompts/create.vue +40 -0
  38. package/app/pages/motor-admin/ai-system-prompts/index.vue +68 -0
  39. package/app/pages/motor-admin/category-trees/CLAUDE.md +7 -0
  40. package/app/pages/motor-admin/category-trees/[id]/CLAUDE.md +7 -0
  41. package/app/pages/motor-admin/category-trees/[id]/categories/[categoryId]/edit.vue +73 -0
  42. package/app/pages/motor-admin/category-trees/[id]/categories/create.vue +64 -0
  43. package/app/pages/motor-admin/category-trees/[id]/edit.vue +45 -0
  44. package/app/pages/motor-admin/category-trees/[id]/index.vue +81 -0
  45. package/app/pages/motor-admin/category-trees/create.vue +37 -0
  46. package/app/pages/motor-admin/category-trees/index.vue +54 -0
  47. package/app/pages/motor-admin/clients/CLAUDE.md +11 -0
  48. package/app/pages/motor-admin/clients/[id]/CLAUDE.md +11 -0
  49. package/app/pages/motor-admin/clients/[id]/edit.vue +45 -0
  50. package/app/pages/motor-admin/clients/create.vue +37 -0
  51. package/app/pages/motor-admin/clients/index.vue +46 -0
  52. package/app/pages/motor-admin/config-variables/CLAUDE.md +11 -0
  53. package/app/pages/motor-admin/config-variables/[id]/edit.vue +44 -0
  54. package/app/pages/motor-admin/config-variables/create.vue +36 -0
  55. package/app/pages/motor-admin/config-variables/index.vue +66 -0
  56. package/app/pages/motor-admin/domains/CLAUDE.md +11 -0
  57. package/app/pages/motor-admin/domains/[id]/edit.vue +54 -0
  58. package/app/pages/motor-admin/domains/create.vue +46 -0
  59. package/app/pages/motor-admin/domains/index.vue +98 -0
  60. package/app/pages/motor-admin/email-templates/CLAUDE.md +12 -0
  61. package/app/pages/motor-admin/email-templates/[id]/CLAUDE.md +7 -0
  62. package/app/pages/motor-admin/email-templates/[id]/edit.vue +56 -0
  63. package/app/pages/motor-admin/email-templates/create.vue +48 -0
  64. package/app/pages/motor-admin/email-templates/index.vue +67 -0
  65. package/app/pages/motor-admin/index.vue +12 -0
  66. package/app/pages/motor-admin/languages/CLAUDE.md +7 -0
  67. package/app/pages/motor-admin/languages/[id]/edit.vue +44 -0
  68. package/app/pages/motor-admin/languages/create.vue +36 -0
  69. package/app/pages/motor-admin/languages/index.vue +44 -0
  70. package/app/pages/motor-admin/permission-groups/CLAUDE.md +14 -0
  71. package/app/pages/motor-admin/permission-groups/[id]/CLAUDE.md +11 -0
  72. package/app/pages/motor-admin/permission-groups/[id]/edit.vue +49 -0
  73. package/app/pages/motor-admin/permission-groups/create.vue +41 -0
  74. package/app/pages/motor-admin/permission-groups/index.vue +43 -0
  75. package/app/pages/motor-admin/roles/CLAUDE.md +7 -0
  76. package/app/pages/motor-admin/roles/[id]/edit.vue +47 -0
  77. package/app/pages/motor-admin/roles/create.vue +40 -0
  78. package/app/pages/motor-admin/roles/index.vue +45 -0
  79. package/app/pages/motor-admin/theme-preview/CLAUDE.md +7 -0
  80. package/app/pages/motor-admin/theme-preview/index.vue +4801 -0
  81. package/app/pages/motor-admin/theme-preview/themes/CLAUDE.md +11 -0
  82. package/app/pages/motor-admin/theme-preview/themes/asymmetric-brutalist.md +381 -0
  83. package/app/pages/motor-admin/theme-preview/themes/bold-modern.md +231 -0
  84. package/app/pages/motor-admin/theme-preview/themes/geometric-minimal.md +778 -0
  85. package/app/pages/motor-admin/theme-preview/themes/gradient-flow.md +1057 -0
  86. package/app/pages/motor-admin/theme-preview/themes/liquid-glass.md +823 -0
  87. package/app/pages/motor-admin/theme-preview/themes/neon-amber.md +1223 -0
  88. package/app/pages/motor-admin/theme-preview/themes/neon-terminal.md +779 -0
  89. package/app/pages/motor-admin/theme-preview/themes/neon-violet.md +1134 -0
  90. package/app/pages/motor-admin/theme-preview/themes/professional-clean.md +232 -0
  91. package/app/pages/motor-admin/theme-preview/themes/refined-brutalist.md +462 -0
  92. package/app/pages/motor-admin/theme-preview/themes/wild-card.md +263 -0
  93. package/app/pages/motor-admin/users/CLAUDE.md +17 -0
  94. package/app/pages/motor-admin/users/[id]/CLAUDE.md +11 -0
  95. package/app/pages/motor-admin/users/[id]/edit.vue +83 -0
  96. package/app/pages/motor-admin/users/create.vue +40 -0
  97. package/app/pages/motor-admin/users/index.vue +66 -0
  98. package/app/pages/profile.vue +363 -0
  99. package/app/pages/search.vue +91 -0
  100. package/app/types/generated/form-meta.ts +258 -0
  101. package/app/types/generated/grid-meta.ts +172 -0
  102. package/nuxt.config.ts +1 -0
  103. package/package.json +26 -0
@@ -0,0 +1,98 @@
1
+ <!-- app/pages/motor-admin/domains/index.vue -->
2
+ <script setup lang="ts">
3
+ import type { ColumnDef } from '@motor-cms/ui-core/app/types/grid'
4
+ import { domainMeta } from '../../../types/generated/grid-meta'
5
+
6
+ definePageMeta({ permission: 'domains.read' })
7
+
8
+ interface DomainApi {
9
+ id: number
10
+ name: string
11
+ client?: { id: number, name: string }
12
+ client_id: string
13
+ is_active: boolean
14
+ protocol: string
15
+ host: string
16
+ port: number
17
+ path: string
18
+ created_at: string
19
+ updated_at: string
20
+ }
21
+
22
+ interface Domain {
23
+ id: number
24
+ name: string
25
+ client_name: string
26
+ is_active: boolean
27
+ protocol: string
28
+ host: string
29
+ port: string
30
+ path: string
31
+ created_at: string
32
+ updated_at: string
33
+ }
34
+
35
+ const { t } = useI18n()
36
+
37
+ const columns: ColumnDef<Domain>[] = [
38
+ ...columnsFromMeta<Domain>(domainMeta, t, {
39
+ pick: ['name', 'host', 'is_active'],
40
+ overrides: {
41
+ is_active: { renderer: 'boolean' }
42
+ }
43
+ })
44
+ ]
45
+
46
+ // Insert client_name after name
47
+ columns.splice(1, 0, { key: 'client_name', label: t('motor-admin.clients.client') })
48
+
49
+ // Insert protocol before is_active (index 3 after splice)
50
+ columns.splice(3, 0, {
51
+ key: 'protocol',
52
+ label: t('motor-admin.domains.protocol'),
53
+ renderer: 'badge',
54
+ rendererProps: {
55
+ color: (value: string | null) => value === 'https' ? 'success' : 'warning'
56
+ }
57
+ })
58
+
59
+ columns.push(createdAtColumn(t))
60
+
61
+ const filters = [useClientFilter(), useIsActiveFilter()]
62
+
63
+ const fetchDomains = useGridFetch<DomainApi, Domain>('/api/v2/domains', {
64
+ transform: record => ({
65
+ id: record.id,
66
+ name: record.name,
67
+ client_name: record.client?.name ?? '-',
68
+ is_active: record.is_active,
69
+ protocol: record.protocol,
70
+ host: record.host,
71
+ port: String(record.port),
72
+ path: record.path,
73
+ created_at: record.created_at,
74
+ updated_at: record.updated_at
75
+ })
76
+ })
77
+ </script>
78
+
79
+ <template>
80
+ <GridPage
81
+ :title="t('motor-admin.domains.title')"
82
+ :subtitle="t('motor-admin.domains.subtitle')"
83
+ add-route="/motor-admin/domains/create"
84
+ :add-label="t('motor-admin.domains.add')"
85
+ write-permission="domains.write"
86
+ >
87
+ <GridBase
88
+ id="domains-grid"
89
+ :fetch="fetchDomains"
90
+ :columns="columns"
91
+ :filters="filters"
92
+ base-path="/motor-admin/domains"
93
+ :row-click-to="(row: any) => `/motor-admin/domains/${row.id}/edit`"
94
+ write-permission="domains.write"
95
+ delete-permission="domains.delete"
96
+ />
97
+ </GridPage>
98
+ </template>
@@ -0,0 +1,12 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ ### Feb 12, 2026
7
+
8
+ | ID | Time | T | Title | Read |
9
+ |----|------|---|-------|------|
10
+ | #24261 | 3:09 PM | 🔵 | Email Templates Form Pattern with Slug Auto-Generation | ~414 |
11
+ | #24248 | 1:06 PM | 🔄 | Grid Filters Now Use Cached Entity Options via fetchResourceOptions | ~402 |
12
+ </claude-mem-context>
@@ -0,0 +1,7 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ *No recent activity*
7
+ </claude-mem-context>
@@ -0,0 +1,56 @@
1
+ <!-- app/pages/motor-admin/email-templates/[id]/edit.vue -->
2
+ <script setup lang="ts">
3
+ import { emailTemplateFormMeta } from '../../../../types/generated/form-meta'
4
+ import { emailTemplateFormConfig, emailTemplateSelectOptionConfigs } from '@motor-cms/ui-core/app/types/config/email-template'
5
+
6
+ definePageMeta({ layout: 'default', permission: 'email-templates.write' })
7
+
8
+ const route = useRoute()
9
+ const { t } = useI18n()
10
+ const { fields: rawFields, schema, groups, state, loading, fetching, fetchError, formRef, selectOptions, selectOptionsLoading, onSubmit, onSaveAndContinue, onSaveAndNew, deleteRecord, deleting } = await useEntityForm({
11
+ apiEndpoint: '/api/v2/email-templates',
12
+ routePrefix: '/motor-admin/email-templates',
13
+ translationPrefix: 'motor-admin.email_templates',
14
+ formMeta: emailTemplateFormMeta,
15
+ formConfig: emailTemplateFormConfig,
16
+ mode: 'edit',
17
+ id: route.params.id as string,
18
+ selectOptionConfigs: emailTemplateSelectOptionConfigs
19
+ })
20
+
21
+ const fields = reactive(rawFields)
22
+ const bodyHtmlField = fields.find(f => f.key === 'body_html')
23
+ if (bodyHtmlField) {
24
+ watchEffect(() => {
25
+ bodyHtmlField.hidden = !state.has_body_html
26
+ })
27
+ }
28
+ </script>
29
+
30
+ <template>
31
+ <FormPage
32
+ :title="t('motor-admin.email_templates.edit_title')"
33
+ back-route="/motor-admin/email-templates"
34
+ :loading="fetching"
35
+ :error="fetchError"
36
+ >
37
+ <FormBase
38
+ ref="formRef"
39
+ v-model:state="state"
40
+ :fields="fields"
41
+ :schema="schema"
42
+ :groups="groups"
43
+ :select-options="selectOptions"
44
+ :select-options-loading="selectOptionsLoading"
45
+ :loading="loading"
46
+ :delete-record="deleteRecord"
47
+ :deleting="deleting"
48
+ cancel-route="/motor-admin/email-templates"
49
+ show-save-and-continue
50
+ show-save-and-new
51
+ @submit="onSubmit"
52
+ @save-and-continue="onSaveAndContinue"
53
+ @save-and-new="onSaveAndNew"
54
+ />
55
+ </FormPage>
56
+ </template>
@@ -0,0 +1,48 @@
1
+ <!-- app/pages/motor-admin/email-templates/create.vue -->
2
+ <script setup lang="ts">
3
+ import { emailTemplateFormMeta } from '../../../types/generated/form-meta'
4
+ import { emailTemplateFormConfig, emailTemplateSelectOptionConfigs } from '@motor-cms/ui-core/app/types/config/email-template'
5
+
6
+ definePageMeta({ layout: 'default', permission: 'email-templates.write' })
7
+
8
+ const { t } = useI18n()
9
+ const { fields: rawFields, schema, groups, state, loading, selectOptions, selectOptionsLoading, formRef, onSubmit, onSaveAndNew } = await useEntityForm({
10
+ apiEndpoint: '/api/v2/email-templates',
11
+ routePrefix: '/motor-admin/email-templates',
12
+ translationPrefix: 'motor-admin.email_templates',
13
+ formMeta: emailTemplateFormMeta,
14
+ formConfig: emailTemplateFormConfig,
15
+ mode: 'create',
16
+ selectOptionConfigs: emailTemplateSelectOptionConfigs
17
+ })
18
+
19
+ const fields = reactive(rawFields)
20
+ const bodyHtmlField = fields.find(f => f.key === 'body_html')
21
+ if (bodyHtmlField) {
22
+ watchEffect(() => {
23
+ bodyHtmlField.hidden = !state.has_body_html
24
+ })
25
+ }
26
+ </script>
27
+
28
+ <template>
29
+ <FormPage
30
+ :title="t('motor-admin.email_templates.create_title')"
31
+ back-route="/motor-admin/email-templates"
32
+ >
33
+ <FormBase
34
+ ref="formRef"
35
+ v-model:state="state"
36
+ :fields="fields"
37
+ :schema="schema"
38
+ :groups="groups"
39
+ :select-options="selectOptions"
40
+ :select-options-loading="selectOptionsLoading"
41
+ :loading="loading"
42
+ cancel-route="/motor-admin/email-templates"
43
+ show-save-and-new
44
+ @submit="onSubmit"
45
+ @save-and-new="onSaveAndNew"
46
+ />
47
+ </FormPage>
48
+ </template>
@@ -0,0 +1,67 @@
1
+ <!-- app/pages/motor-admin/email-templates/index.vue -->
2
+ <script setup lang="ts">
3
+ import type { components } from '@motor-cms/ui-core/app/types/generated/api'
4
+ import type { RowActionDef } from '@motor-cms/ui-core/app/types/grid'
5
+ import { emailTemplateMeta } from '../../../types/generated/grid-meta'
6
+ import { emailTemplateGridConfig } from '@motor-cms/ui-core/app/types/config/email-template'
7
+
8
+ definePageMeta({ permission: 'email-templates.read' })
9
+
10
+ type EmailTemplate = components['schemas']['EmailTemplateResource']
11
+
12
+ const { t } = useI18n()
13
+
14
+ const usageModalOpen = ref(false)
15
+ const usageEndpoint = ref('')
16
+
17
+ const columns = columnsFromMeta<EmailTemplate>(emailTemplateMeta, t, emailTemplateGridConfig)
18
+
19
+ columns.push(createdAtColumn(t))
20
+
21
+ const rowActions: RowActionDef<EmailTemplate>[] = [
22
+ {
23
+ key: 'usage',
24
+ label: t('motor-admin.email_templates.usage_title'),
25
+ icon: 'i-lucide-link',
26
+ silent: true,
27
+ handler: (row: EmailTemplate) => {
28
+ usageEndpoint.value = `/api/v2/email-templates/${row.id}/usage`
29
+ usageModalOpen.value = true
30
+ }
31
+ }
32
+ ]
33
+
34
+ const filters = [useClientFilter(), useLanguageFilter()]
35
+
36
+ const fetchEmailTemplates = useGridFetch<EmailTemplate>('/api/v2/email-templates')
37
+ </script>
38
+
39
+ <template>
40
+ <div>
41
+ <GridPage
42
+ :title="t('motor-admin.email_templates.title')"
43
+ :subtitle="t('motor-admin.email_templates.subtitle')"
44
+ add-route="/motor-admin/email-templates/create"
45
+ :add-label="t('motor-admin.email_templates.add')"
46
+ write-permission="email-templates.write"
47
+ >
48
+ <GridBase
49
+ id="email-templates-grid"
50
+ :fetch="fetchEmailTemplates"
51
+ :columns="columns"
52
+ :filters="filters"
53
+ :row-actions="rowActions"
54
+ base-path="/motor-admin/email-templates"
55
+ :row-click-to="(row: any) => `/motor-admin/email-templates/${row.id}/edit`"
56
+ write-permission="email-templates.write"
57
+ delete-permission="email-templates.delete"
58
+ />
59
+ </GridPage>
60
+
61
+ <EntityUsageModal
62
+ v-model:open="usageModalOpen"
63
+ :endpoint="usageEndpoint"
64
+ :title="t('motor-admin.email_templates.usage_title')"
65
+ />
66
+ </div>
67
+ </template>
@@ -0,0 +1,12 @@
1
+ <!-- app/pages/motor-admin/index.vue -->
2
+ <script setup lang="ts">
3
+ definePageMeta({ permission: 'administration.read' })
4
+ </script>
5
+
6
+ <template>
7
+ <SectionLanding
8
+ section-prefix="motor-admin"
9
+ title-key="motor-core.global.administration"
10
+ subtitle-key="motor-core.global.section_subtitle"
11
+ />
12
+ </template>
@@ -0,0 +1,7 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ *No recent activity*
7
+ </claude-mem-context>
@@ -0,0 +1,44 @@
1
+ <script setup lang="ts">
2
+ import { languageFormMeta } from '../../../../types/generated/form-meta'
3
+ import { languageFormConfig } from '@motor-cms/ui-core/app/types/config/language'
4
+
5
+ definePageMeta({ layout: 'default', permission: 'languages.write' })
6
+
7
+ const route = useRoute()
8
+ const { t } = useI18n()
9
+ const { fields, schema, groups, state, loading, fetching, fetchError, formRef, onSubmit, onSaveAndContinue, onSaveAndNew, deleteRecord, deleting } = await useEntityForm({
10
+ apiEndpoint: '/api/v2/languages',
11
+ routePrefix: '/motor-admin/languages',
12
+ translationPrefix: 'motor-admin.languages',
13
+ formMeta: languageFormMeta,
14
+ formConfig: languageFormConfig,
15
+ mode: 'edit',
16
+ id: route.params.id as string
17
+ })
18
+ </script>
19
+
20
+ <template>
21
+ <FormPage
22
+ :title="t('motor-admin.languages.edit_title')"
23
+ back-route="/motor-admin/languages"
24
+ :loading="fetching"
25
+ :error="fetchError"
26
+ >
27
+ <FormBase
28
+ ref="formRef"
29
+ v-model:state="state"
30
+ :fields="fields"
31
+ :schema="schema"
32
+ :groups="groups"
33
+ :loading="loading"
34
+ :delete-record="deleteRecord"
35
+ :deleting="deleting"
36
+ cancel-route="/motor-admin/languages"
37
+ show-save-and-continue
38
+ show-save-and-new
39
+ @submit="onSubmit"
40
+ @save-and-continue="onSaveAndContinue"
41
+ @save-and-new="onSaveAndNew"
42
+ />
43
+ </FormPage>
44
+ </template>
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import { languageFormMeta } from '../../../types/generated/form-meta'
3
+ import { languageFormConfig } from '@motor-cms/ui-core/app/types/config/language'
4
+
5
+ definePageMeta({ layout: 'default', permission: 'languages.write' })
6
+
7
+ const { t } = useI18n()
8
+ const { fields, schema, groups, state, loading, formRef, onSubmit, onSaveAndNew } = await useEntityForm({
9
+ apiEndpoint: '/api/v2/languages',
10
+ routePrefix: '/motor-admin/languages',
11
+ translationPrefix: 'motor-admin.languages',
12
+ formMeta: languageFormMeta,
13
+ formConfig: languageFormConfig,
14
+ mode: 'create'
15
+ })
16
+ </script>
17
+
18
+ <template>
19
+ <FormPage
20
+ :title="t('motor-admin.languages.create_title')"
21
+ back-route="/motor-admin/languages"
22
+ >
23
+ <FormBase
24
+ ref="formRef"
25
+ v-model:state="state"
26
+ :fields="fields"
27
+ :schema="schema"
28
+ :groups="groups"
29
+ :loading="loading"
30
+ cancel-route="/motor-admin/languages"
31
+ show-save-and-new
32
+ @submit="onSubmit"
33
+ @save-and-new="onSaveAndNew"
34
+ />
35
+ </FormPage>
36
+ </template>
@@ -0,0 +1,44 @@
1
+ <!-- app/pages/motor-admin/languages/index.vue -->
2
+ <script setup lang="ts">
3
+ import type { components } from '@motor-cms/ui-core/app/types/generated/api'
4
+ import { languageMeta } from '../../../types/generated/grid-meta'
5
+
6
+ definePageMeta({ permission: 'languages.read' })
7
+
8
+ type Language = components['schemas']['LanguageResource']
9
+
10
+ const { t } = useI18n()
11
+
12
+ const columns = columnsFromMeta<Language>(languageMeta, t, {
13
+ pick: ['iso_639_1', 'english_name', 'native_name'],
14
+ overrides: {
15
+ iso_639_1: { renderer: 'badge', sortable: true, hideable: false },
16
+ english_name: { sortable: true, hideable: false },
17
+ native_name: { sortable: true }
18
+ }
19
+ })
20
+
21
+ columns.push(createdAtColumn(t))
22
+
23
+ const { fetch: fetchLanguages } = useGridData<Language>('/api/v2/languages')
24
+ </script>
25
+
26
+ <template>
27
+ <GridPage
28
+ :title="t('motor-admin.languages.title')"
29
+ :subtitle="t('motor-admin.languages.subtitle')"
30
+ add-route="/motor-admin/languages/create"
31
+ :add-label="t('motor-admin.languages.add')"
32
+ write-permission="languages.write"
33
+ >
34
+ <GridBase
35
+ id="languages-grid"
36
+ :fetch="fetchLanguages"
37
+ :columns="columns"
38
+ base-path="/motor-admin/languages"
39
+ :row-click-to="(row: any) => `/motor-admin/languages/${row.id}/edit`"
40
+ write-permission="languages.write"
41
+ delete-permission="languages.delete"
42
+ />
43
+ </GridPage>
44
+ </template>
@@ -0,0 +1,14 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ ### Feb 12, 2026
7
+
8
+ | ID | Time | T | Title | Read |
9
+ |----|------|---|-------|------|
10
+ | #24287 | 3:18 PM | ✅ | Permissions Endpoint Query Updated to Fetch All Permissions | ~260 |
11
+ | #24277 | 3:14 PM | ✅ | Permission Groups Form Uses Checkbox Group Instead of Multi-Select | ~254 |
12
+ | #24268 | 3:10 PM | 🟣 | Permission Groups Form Now Supports Multi-Checkbox Permission Assignment | ~299 |
13
+ | #24263 | " | 🟣 | Users Create Form with Cached Select Options | ~329 |
14
+ </claude-mem-context>
@@ -0,0 +1,11 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ ### Feb 12, 2026
7
+
8
+ | ID | Time | T | Title | Read |
9
+ |----|------|---|-------|------|
10
+ | #24269 | 3:11 PM | 🟣 | Permissions Multi-Select Field Added to Permission-Groups Form | ~435 |
11
+ </claude-mem-context>
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts">
2
+ import { permissionGroupFormMeta } from '../../../../types/generated/form-meta'
3
+ import { permissionGroupFormConfig, permissionGroupSelectOptionConfigs, permissionGroupExtraFields } from '@motor-cms/ui-core/app/types/config/permission-group'
4
+
5
+ definePageMeta({ layout: 'default', permission: 'permission-groups.write' })
6
+
7
+ const route = useRoute()
8
+ const { t } = useI18n()
9
+ const { fields, schema, groups, state, loading, fetching, fetchError, formRef, selectOptions, selectOptionsLoading, onSubmit, onSaveAndContinue, onSaveAndNew, deleteRecord, deleting } = await useEntityForm({
10
+ apiEndpoint: '/api/v2/permission-groups',
11
+ routePrefix: '/motor-admin/permission-groups',
12
+ translationPrefix: 'motor-admin.permissions',
13
+ formMeta: permissionGroupFormMeta,
14
+ formConfig: permissionGroupFormConfig,
15
+ mode: 'edit',
16
+ id: route.params.id as string,
17
+ selectOptionConfigs: permissionGroupSelectOptionConfigs,
18
+ extraFields: permissionGroupExtraFields,
19
+ extraState: { permissions: [] }
20
+ })
21
+ </script>
22
+
23
+ <template>
24
+ <FormPage
25
+ :title="t('motor-admin.permissions.edit_title')"
26
+ back-route="/motor-admin/permission-groups"
27
+ :loading="fetching"
28
+ :error="fetchError"
29
+ >
30
+ <FormBase
31
+ ref="formRef"
32
+ v-model:state="state"
33
+ :fields="fields"
34
+ :schema="schema"
35
+ :groups="groups"
36
+ :select-options="selectOptions"
37
+ :select-options-loading="selectOptionsLoading"
38
+ :loading="loading"
39
+ :delete-record="deleteRecord"
40
+ :deleting="deleting"
41
+ cancel-route="/motor-admin/permission-groups"
42
+ show-save-and-continue
43
+ show-save-and-new
44
+ @submit="onSubmit"
45
+ @save-and-continue="onSaveAndContinue"
46
+ @save-and-new="onSaveAndNew"
47
+ />
48
+ </FormPage>
49
+ </template>
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ import { permissionGroupFormMeta } from '../../../types/generated/form-meta'
3
+ import { permissionGroupFormConfig, permissionGroupSelectOptionConfigs, permissionGroupExtraFields } from '@motor-cms/ui-core/app/types/config/permission-group'
4
+
5
+ definePageMeta({ layout: 'default', permission: 'permission-groups.write' })
6
+
7
+ const { t } = useI18n()
8
+ const { fields, schema, groups, state, loading, selectOptions, selectOptionsLoading, formRef, onSubmit, onSaveAndNew } = await useEntityForm({
9
+ apiEndpoint: '/api/v2/permission-groups',
10
+ routePrefix: '/motor-admin/permission-groups',
11
+ translationPrefix: 'motor-admin.permissions',
12
+ formMeta: permissionGroupFormMeta,
13
+ formConfig: permissionGroupFormConfig,
14
+ mode: 'create',
15
+ selectOptionConfigs: permissionGroupSelectOptionConfigs,
16
+ extraFields: permissionGroupExtraFields,
17
+ extraState: { permissions: [] }
18
+ })
19
+ </script>
20
+
21
+ <template>
22
+ <FormPage
23
+ :title="t('motor-admin.permissions.create_title')"
24
+ back-route="/motor-admin/permission-groups"
25
+ >
26
+ <FormBase
27
+ ref="formRef"
28
+ v-model:state="state"
29
+ :fields="fields"
30
+ :schema="schema"
31
+ :groups="groups"
32
+ :select-options="selectOptions"
33
+ :select-options-loading="selectOptionsLoading"
34
+ :loading="loading"
35
+ cancel-route="/motor-admin/permission-groups"
36
+ show-save-and-new
37
+ @submit="onSubmit"
38
+ @save-and-new="onSaveAndNew"
39
+ />
40
+ </FormPage>
41
+ </template>
@@ -0,0 +1,43 @@
1
+ <!-- app/pages/motor-admin/permission-groups/index.vue -->
2
+ <script setup lang="ts">
3
+ import type { components } from '@motor-cms/ui-core/app/types/generated/api'
4
+ import { permissionGroupMeta } from '../../../types/generated/grid-meta'
5
+
6
+ definePageMeta({ permission: 'permission-groups.read' })
7
+
8
+ type PermissionGroup = components['schemas']['PermissionGroupResource']
9
+
10
+ const { t } = useI18n()
11
+
12
+ const columns = columnsFromMeta<PermissionGroup>(permissionGroupMeta, t, {
13
+ pick: ['name', 'sort_position', 'permissions'],
14
+ overrides: {
15
+ sort_position: { label: t('motor-admin.permissions.position'), sortable: true }
16
+ },
17
+ translationPrefix: 'motor-admin.permissions'
18
+ })
19
+
20
+ columns.push(createdAtColumn(t))
21
+
22
+ const fetchPermissionGroups = useGridFetch<PermissionGroup>('/api/v2/permission-groups')
23
+ </script>
24
+
25
+ <template>
26
+ <GridPage
27
+ :title="t('motor-admin.permissions.title')"
28
+ :subtitle="t('motor-admin.permissions.subtitle')"
29
+ add-route="/motor-admin/permission-groups/create"
30
+ :add-label="t('motor-admin.permissions.add')"
31
+ write-permission="permission-groups.write"
32
+ >
33
+ <GridBase
34
+ id="permission-groups-grid"
35
+ :fetch="fetchPermissionGroups"
36
+ :columns="columns"
37
+ base-path="/motor-admin/permission-groups"
38
+ :row-click-to="(row: any) => `/motor-admin/permission-groups/${row.id}/edit`"
39
+ write-permission="permission-groups.write"
40
+ delete-permission="permission-groups.delete"
41
+ />
42
+ </GridPage>
43
+ </template>
@@ -0,0 +1,7 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ *No recent activity*
7
+ </claude-mem-context>
@@ -0,0 +1,47 @@
1
+ <script setup lang="ts">
2
+ import { roleFormMeta } from '../../../../types/generated/form-meta'
3
+ import { roleFormConfig, roleSelectOptionConfigs } from '@motor-cms/ui-core/app/types/config/role'
4
+
5
+ definePageMeta({ layout: 'default', permission: 'roles.write' })
6
+
7
+ const route = useRoute()
8
+ const { t } = useI18n()
9
+ const { fields, schema, groups, state, loading, fetching, fetchError, formRef, selectOptions, selectOptionsLoading, onSubmit, onSaveAndContinue, onSaveAndNew, deleteRecord, deleting } = await useEntityForm({
10
+ apiEndpoint: '/api/v2/roles',
11
+ routePrefix: '/motor-admin/roles',
12
+ translationPrefix: 'motor-admin.roles',
13
+ formMeta: roleFormMeta,
14
+ formConfig: roleFormConfig,
15
+ mode: 'edit',
16
+ id: route.params.id as string,
17
+ selectOptionConfigs: roleSelectOptionConfigs
18
+ })
19
+ </script>
20
+
21
+ <template>
22
+ <FormPage
23
+ :title="t('motor-admin.roles.edit_title')"
24
+ back-route="/motor-admin/roles"
25
+ :loading="fetching"
26
+ :error="fetchError"
27
+ >
28
+ <FormBase
29
+ ref="formRef"
30
+ v-model:state="state"
31
+ :fields="fields"
32
+ :schema="schema"
33
+ :groups="groups"
34
+ :select-options="selectOptions"
35
+ :select-options-loading="selectOptionsLoading"
36
+ :loading="loading"
37
+ :delete-record="deleteRecord"
38
+ :deleting="deleting"
39
+ cancel-route="/motor-admin/roles"
40
+ show-save-and-continue
41
+ show-save-and-new
42
+ @submit="onSubmit"
43
+ @save-and-continue="onSaveAndContinue"
44
+ @save-and-new="onSaveAndNew"
45
+ />
46
+ </FormPage>
47
+ </template>