qdadm 0.16.0 → 0.17.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 (58) hide show
  1. package/README.md +153 -1
  2. package/package.json +15 -2
  3. package/src/components/forms/FormField.vue +64 -6
  4. package/src/components/forms/FormPage.vue +276 -0
  5. package/src/components/index.js +11 -0
  6. package/src/components/layout/BaseLayout.vue +183 -0
  7. package/src/components/layout/DashboardLayout.vue +100 -0
  8. package/src/components/layout/FormLayout.vue +261 -0
  9. package/src/components/layout/ListLayout.vue +334 -0
  10. package/src/components/layout/Zone.vue +165 -0
  11. package/src/components/layout/defaults/DefaultBreadcrumb.vue +140 -0
  12. package/src/components/layout/defaults/DefaultFooter.vue +56 -0
  13. package/src/components/layout/defaults/DefaultFormActions.vue +53 -0
  14. package/src/components/layout/defaults/DefaultHeader.vue +69 -0
  15. package/src/components/layout/defaults/DefaultMenu.vue +197 -0
  16. package/src/components/layout/defaults/DefaultPagination.vue +79 -0
  17. package/src/components/layout/defaults/DefaultTable.vue +130 -0
  18. package/src/components/layout/defaults/DefaultToaster.vue +16 -0
  19. package/src/components/layout/defaults/DefaultUserInfo.vue +96 -0
  20. package/src/components/layout/defaults/index.js +17 -0
  21. package/src/composables/index.js +6 -6
  22. package/src/composables/useForm.js +135 -0
  23. package/src/composables/useFormPageBuilder.js +1154 -0
  24. package/src/composables/useHooks.js +53 -0
  25. package/src/composables/useLayoutResolver.js +260 -0
  26. package/src/composables/useListPageBuilder.js +336 -52
  27. package/src/composables/useNavigation.js +38 -2
  28. package/src/composables/useSignals.js +49 -0
  29. package/src/composables/useZoneRegistry.js +162 -0
  30. package/src/core/bundles.js +406 -0
  31. package/src/core/decorator.js +322 -0
  32. package/src/core/extension.js +386 -0
  33. package/src/core/index.js +28 -0
  34. package/src/entity/EntityManager.js +314 -16
  35. package/src/entity/auth/AuthAdapter.js +125 -0
  36. package/src/entity/auth/PermissiveAdapter.js +64 -0
  37. package/src/entity/auth/index.js +11 -0
  38. package/src/entity/index.js +3 -0
  39. package/src/entity/storage/MockApiStorage.js +349 -0
  40. package/src/entity/storage/SdkStorage.js +478 -0
  41. package/src/entity/storage/index.js +2 -0
  42. package/src/hooks/HookRegistry.js +411 -0
  43. package/src/hooks/index.js +12 -0
  44. package/src/index.js +9 -0
  45. package/src/kernel/Kernel.js +136 -4
  46. package/src/kernel/SignalBus.js +180 -0
  47. package/src/kernel/index.js +7 -0
  48. package/src/module/moduleRegistry.js +124 -6
  49. package/src/orchestrator/Orchestrator.js +73 -1
  50. package/src/zones/ZoneRegistry.js +821 -0
  51. package/src/zones/index.js +16 -0
  52. package/src/zones/zones.js +189 -0
  53. package/src/composables/useEntityTitle.js +0 -121
  54. package/src/composables/useManager.js +0 -20
  55. package/src/composables/usePageBuilder.js +0 -334
  56. package/src/composables/useStatus.js +0 -146
  57. package/src/composables/useSubEditor.js +0 -165
  58. package/src/composables/useTabSync.js +0 -110
@@ -0,0 +1,53 @@
1
+ <script setup>
2
+ /**
3
+ * DefaultFormActions - Default component for the form actions zone
4
+ *
5
+ * Renders save/cancel buttons with loading states, using the form state
6
+ * provided by FormLayout via Vue injection.
7
+ *
8
+ * This component is rendered by Zone when no blocks are registered
9
+ * in the 'actions' zone and no slot override is provided.
10
+ *
11
+ * Uses FormActions component for consistent button rendering.
12
+ *
13
+ * Inject:
14
+ * - qdadmFormState: { loading, saving, dirty, isEdit }
15
+ * - qdadmFormEmit: { save, saveAndClose, cancel, delete }
16
+ */
17
+ import { inject, computed } from 'vue'
18
+ import FormActions from '../../forms/FormActions.vue'
19
+
20
+ // Inject form state from FormLayout
21
+ const formState = inject('qdadmFormState', null)
22
+ const formEmit = inject('qdadmFormEmit', null)
23
+
24
+ // Fallback values if not injected (for standalone testing)
25
+ const isEdit = computed(() => formState?.value?.isEdit ?? false)
26
+ const saving = computed(() => formState?.value?.saving ?? false)
27
+ const dirty = computed(() => formState?.value?.dirty ?? true)
28
+
29
+ // Event handlers
30
+ function onSave() {
31
+ formEmit?.save()
32
+ }
33
+
34
+ function onSaveAndClose() {
35
+ formEmit?.saveAndClose()
36
+ }
37
+
38
+ function onCancel() {
39
+ formEmit?.cancel()
40
+ }
41
+ </script>
42
+
43
+ <template>
44
+ <FormActions
45
+ :isEdit="isEdit"
46
+ :saving="saving"
47
+ :dirty="dirty"
48
+ :showSaveAndClose="true"
49
+ @save="onSave"
50
+ @saveAndClose="onSaveAndClose"
51
+ @cancel="onCancel"
52
+ />
53
+ </template>
@@ -0,0 +1,69 @@
1
+ <script setup>
2
+ /**
3
+ * DefaultHeader - Default header component for BaseLayout
4
+ *
5
+ * Displays app branding (logo or name) and version badge.
6
+ * Extracted from AppLayout for zone-based architecture.
7
+ *
8
+ * This is the default component rendered in the "header" zone
9
+ * when no blocks are registered.
10
+ */
11
+ import { inject, computed } from 'vue'
12
+
13
+ const features = inject('qdadmFeatures', { poweredBy: true })
14
+
15
+ // App config from useApp (injected by createQdadm plugin)
16
+ const app = inject('qdadmApp', {
17
+ name: 'Admin',
18
+ shortName: 'adm',
19
+ version: null,
20
+ logo: null
21
+ })
22
+ </script>
23
+
24
+ <template>
25
+ <div class="default-header">
26
+ <div class="header-branding">
27
+ <img v-if="app.logo" :src="app.logo" :alt="app.name" class="header-logo" />
28
+ <h1 v-else class="header-title">{{ app.name }}</h1>
29
+ </div>
30
+ <span v-if="app.version" class="header-version">v{{ app.version }}</span>
31
+ </div>
32
+ </template>
33
+
34
+ <style scoped>
35
+ .default-header {
36
+ display: flex;
37
+ flex-direction: column;
38
+ align-items: flex-start;
39
+ gap: 0.5rem;
40
+ padding: 1.5rem;
41
+ border-bottom: 1px solid var(--p-surface-700, #334155);
42
+ }
43
+
44
+ .header-branding {
45
+ display: flex;
46
+ align-items: center;
47
+ gap: 0.5rem;
48
+ }
49
+
50
+ .header-title {
51
+ font-size: 1.25rem;
52
+ font-weight: 600;
53
+ margin: 0;
54
+ color: var(--p-surface-0, white);
55
+ }
56
+
57
+ .header-logo {
58
+ max-height: 32px;
59
+ max-width: 160px;
60
+ }
61
+
62
+ .header-version {
63
+ font-size: 0.625rem;
64
+ color: var(--p-surface-400, #94a3b8);
65
+ background: var(--p-surface-700, #334155);
66
+ padding: 0.125rem 0.375rem;
67
+ border-radius: 0.25rem;
68
+ }
69
+ </style>
@@ -0,0 +1,197 @@
1
+ <script setup>
2
+ /**
3
+ * DefaultMenu - Default navigation menu for BaseLayout
4
+ *
5
+ * Displays sidebar navigation with collapsible sections.
6
+ * Navigation items are auto-built from moduleRegistry.
7
+ * Extracted from AppLayout for zone-based architecture.
8
+ *
9
+ * This is the default component rendered in the "menu" zone
10
+ * when no blocks are registered.
11
+ */
12
+ import { ref, watch, onMounted, computed, inject } from 'vue'
13
+ import { RouterLink, useRouter, useRoute } from 'vue-router'
14
+ import { useNavigation } from '../../../composables/useNavigation'
15
+
16
+ const router = useRouter()
17
+ const route = useRoute()
18
+ const { navSections, isNavActive, sectionHasActiveItem, handleNavClick } = useNavigation()
19
+
20
+ // App config for storage key namespacing
21
+ const app = inject('qdadmApp', { shortName: 'qdadm' })
22
+
23
+ // LocalStorage key for collapsed sections state
24
+ const STORAGE_KEY = computed(() => `${app.shortName.toLowerCase()}_nav_collapsed`)
25
+
26
+ // Collapsed sections state (section title -> boolean)
27
+ const collapsedSections = ref({})
28
+
29
+ /**
30
+ * Load collapsed state from localStorage
31
+ */
32
+ function loadCollapsedState() {
33
+ try {
34
+ const stored = localStorage.getItem(STORAGE_KEY.value)
35
+ if (stored) {
36
+ collapsedSections.value = JSON.parse(stored)
37
+ }
38
+ } catch (e) {
39
+ console.warn('Failed to load nav state:', e)
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Save collapsed state to localStorage
45
+ */
46
+ function saveCollapsedState() {
47
+ try {
48
+ localStorage.setItem(STORAGE_KEY.value, JSON.stringify(collapsedSections.value))
49
+ } catch (e) {
50
+ console.warn('Failed to save nav state:', e)
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Toggle section collapsed state
56
+ */
57
+ function toggleSection(sectionTitle) {
58
+ collapsedSections.value[sectionTitle] = !collapsedSections.value[sectionTitle]
59
+ saveCollapsedState()
60
+ }
61
+
62
+ /**
63
+ * Check if section should be shown expanded
64
+ * - Never collapsed if it contains active item
65
+ * - Otherwise respect user preference
66
+ */
67
+ function isSectionExpanded(section) {
68
+ if (sectionHasActiveItem(section)) {
69
+ return true
70
+ }
71
+ return !collapsedSections.value[section.title]
72
+ }
73
+
74
+ // Load state on mount
75
+ onMounted(() => {
76
+ loadCollapsedState()
77
+ })
78
+
79
+ // Auto-expand section when navigating to an item in it
80
+ watch(() => route?.path, () => {
81
+ if (!route) return
82
+ for (const section of navSections.value) {
83
+ if (sectionHasActiveItem(section) && collapsedSections.value[section.title]) {
84
+ // Auto-expand but don't save (user can collapse again if they want)
85
+ collapsedSections.value[section.title] = false
86
+ }
87
+ }
88
+ })
89
+ </script>
90
+
91
+ <template>
92
+ <nav class="default-menu">
93
+ <div v-for="section in navSections" :key="section.title" class="nav-section">
94
+ <div
95
+ class="nav-section-title"
96
+ :class="{ 'nav-section-active': sectionHasActiveItem(section) }"
97
+ @click="toggleSection(section.title)"
98
+ >
99
+ <span>{{ section.title }}</span>
100
+ <i
101
+ class="nav-section-chevron pi"
102
+ :class="isSectionExpanded(section) ? 'pi-chevron-down' : 'pi-chevron-right'"
103
+ ></i>
104
+ </div>
105
+ <div class="nav-section-items" :class="{ 'nav-section-collapsed': !isSectionExpanded(section) }">
106
+ <RouterLink
107
+ v-for="item in section.items"
108
+ :key="item.route"
109
+ :to="{ name: item.route }"
110
+ class="nav-item"
111
+ :class="{ 'nav-item-active': isNavActive(item) }"
112
+ @click="handleNavClick($event, item)"
113
+ >
114
+ <i :class="item.icon"></i>
115
+ <span>{{ item.label }}</span>
116
+ </RouterLink>
117
+ </div>
118
+ </div>
119
+ </nav>
120
+ </template>
121
+
122
+ <style scoped>
123
+ .default-menu {
124
+ flex: 1;
125
+ overflow-y: auto;
126
+ padding: 1rem 0;
127
+ }
128
+
129
+ .nav-section {
130
+ margin-bottom: 0.5rem;
131
+ }
132
+
133
+ .nav-section-title {
134
+ padding: 0.5rem 1.5rem;
135
+ font-size: 0.75rem;
136
+ font-weight: 600;
137
+ text-transform: uppercase;
138
+ letter-spacing: 0.05em;
139
+ color: var(--p-surface-400, #94a3b8);
140
+ display: flex;
141
+ justify-content: space-between;
142
+ align-items: center;
143
+ cursor: pointer;
144
+ user-select: none;
145
+ transition: color 0.15s;
146
+ }
147
+
148
+ .nav-section-title:hover {
149
+ color: var(--p-surface-200, #e2e8f0);
150
+ }
151
+
152
+ .nav-section-active {
153
+ color: var(--p-primary-400, #60a5fa);
154
+ }
155
+
156
+ .nav-section-chevron {
157
+ font-size: 0.625rem;
158
+ transition: transform 0.2s;
159
+ }
160
+
161
+ .nav-section-items {
162
+ max-height: 500px;
163
+ overflow: hidden;
164
+ transition: max-height 0.2s ease-out, opacity 0.15s;
165
+ }
166
+
167
+ .nav-section-collapsed {
168
+ max-height: 0;
169
+ opacity: 0;
170
+ }
171
+
172
+ .nav-item {
173
+ display: flex;
174
+ align-items: center;
175
+ gap: 0.75rem;
176
+ padding: 0.625rem 1.5rem;
177
+ color: var(--p-surface-300, #cbd5e1);
178
+ text-decoration: none;
179
+ transition: all 0.15s;
180
+ }
181
+
182
+ .nav-item:hover {
183
+ background: var(--p-surface-700, #334155);
184
+ color: var(--p-surface-0, white);
185
+ }
186
+
187
+ .nav-item-active {
188
+ background: var(--p-primary-600, #2563eb);
189
+ color: var(--p-surface-0, white);
190
+ }
191
+
192
+ .nav-item i {
193
+ font-size: 1rem;
194
+ width: 1.25rem;
195
+ text-align: center;
196
+ }
197
+ </style>
@@ -0,0 +1,79 @@
1
+ <script setup>
2
+ /**
3
+ * DefaultPagination - Default pagination component for ListLayout
4
+ *
5
+ * Renders a PrimeVue Paginator with standard configuration.
6
+ * Used as the default for the "pagination" zone in ListLayout.
7
+ *
8
+ * When `lazy` is false and pagination is handled by DataTable,
9
+ * this component is typically not shown (DataTable has its own paginator).
10
+ *
11
+ * This is useful for:
12
+ * - Separate pagination controls outside the table
13
+ * - Custom pagination layouts
14
+ * - Server-side (lazy) pagination with separate paginator
15
+ */
16
+ import Paginator from 'primevue/paginator'
17
+
18
+ const props = defineProps({
19
+ /**
20
+ * First record index (0-based)
21
+ */
22
+ first: {
23
+ type: Number,
24
+ default: 0
25
+ },
26
+ /**
27
+ * Number of rows per page
28
+ */
29
+ rows: {
30
+ type: Number,
31
+ default: 10
32
+ },
33
+ /**
34
+ * Total number of records
35
+ */
36
+ totalRecords: {
37
+ type: Number,
38
+ default: 0
39
+ },
40
+ /**
41
+ * Options for rows per page dropdown
42
+ */
43
+ rowsPerPageOptions: {
44
+ type: Array,
45
+ default: () => [10, 25, 50, 100]
46
+ },
47
+ /**
48
+ * Template for the paginator layout
49
+ */
50
+ template: {
51
+ type: String,
52
+ default: 'FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown'
53
+ }
54
+ })
55
+
56
+ const emit = defineEmits(['page'])
57
+
58
+ function onPage(event) {
59
+ emit('page', event)
60
+ }
61
+ </script>
62
+
63
+ <template>
64
+ <Paginator
65
+ :first="first"
66
+ :rows="rows"
67
+ :totalRecords="totalRecords"
68
+ :rowsPerPageOptions="rowsPerPageOptions"
69
+ :template="template"
70
+ @page="onPage"
71
+ class="default-pagination"
72
+ />
73
+ </template>
74
+
75
+ <style scoped>
76
+ .default-pagination {
77
+ margin-top: 1rem;
78
+ }
79
+ </style>
@@ -0,0 +1,130 @@
1
+ <script setup>
2
+ /**
3
+ * DefaultTable - Default table component for ListLayout
4
+ *
5
+ * Renders a PrimeVue DataTable with standard configuration.
6
+ * Used as the default for the "table" zone in ListLayout.
7
+ *
8
+ * Accepts props from the list page builder for data binding.
9
+ * Supports slots for column definitions.
10
+ *
11
+ * This is a minimal wrapper that expects:
12
+ * - items: Array of data to display
13
+ * - loading: Boolean loading state
14
+ * - Columns via default slot
15
+ */
16
+ import { computed, useSlots } from 'vue'
17
+ import DataTable from 'primevue/datatable'
18
+ import Column from 'primevue/column'
19
+
20
+ const props = defineProps({
21
+ /**
22
+ * Data items to display in the table
23
+ */
24
+ items: {
25
+ type: Array,
26
+ default: () => []
27
+ },
28
+ /**
29
+ * Loading state
30
+ */
31
+ loading: {
32
+ type: Boolean,
33
+ default: false
34
+ },
35
+ /**
36
+ * Field to use as unique key for rows
37
+ */
38
+ dataKey: {
39
+ type: String,
40
+ default: 'id'
41
+ },
42
+ /**
43
+ * Current selection (for selectable tables)
44
+ */
45
+ selection: {
46
+ type: Array,
47
+ default: undefined
48
+ },
49
+ /**
50
+ * Enable row selection
51
+ */
52
+ selectable: {
53
+ type: Boolean,
54
+ default: false
55
+ },
56
+ /**
57
+ * Enable striped rows
58
+ */
59
+ stripedRows: {
60
+ type: Boolean,
61
+ default: true
62
+ },
63
+ /**
64
+ * Enable removable sort
65
+ */
66
+ removableSort: {
67
+ type: Boolean,
68
+ default: true
69
+ },
70
+ /**
71
+ * Current sort field
72
+ */
73
+ sortField: {
74
+ type: String,
75
+ default: null
76
+ },
77
+ /**
78
+ * Current sort order (1 = asc, -1 = desc)
79
+ */
80
+ sortOrder: {
81
+ type: Number,
82
+ default: 1
83
+ }
84
+ })
85
+
86
+ const emit = defineEmits(['update:selection', 'sort'])
87
+
88
+ const slots = useSlots()
89
+ const hasDefaultSlot = computed(() => !!slots.default)
90
+
91
+ function onSelectionChange(value) {
92
+ emit('update:selection', value)
93
+ }
94
+
95
+ function onSort(event) {
96
+ emit('sort', event)
97
+ }
98
+ </script>
99
+
100
+ <template>
101
+ <DataTable
102
+ :value="items"
103
+ :loading="loading"
104
+ :dataKey="dataKey"
105
+ :selection="selection"
106
+ :sortField="sortField"
107
+ :sortOrder="sortOrder"
108
+ :stripedRows="stripedRows"
109
+ :removableSort="removableSort"
110
+ @update:selection="onSelectionChange"
111
+ @sort="onSort"
112
+ class="default-table"
113
+ >
114
+ <!-- Columns from slot -->
115
+ <slot />
116
+
117
+ <!-- Selection column if selectable -->
118
+ <Column
119
+ v-if="selectable && !hasDefaultSlot"
120
+ selectionMode="multiple"
121
+ headerStyle="width: 3rem"
122
+ />
123
+ </DataTable>
124
+ </template>
125
+
126
+ <style scoped>
127
+ .default-table {
128
+ width: 100%;
129
+ }
130
+ </style>
@@ -0,0 +1,16 @@
1
+ <script setup>
2
+ /**
3
+ * DefaultToaster - Default toaster component for BaseLayout
4
+ *
5
+ * Renders the Toast component for notifications.
6
+ * Uses PrimeVue Toast with default positioning.
7
+ *
8
+ * This is the default component rendered in the "toaster" zone
9
+ * when no blocks are registered.
10
+ */
11
+ import Toast from 'primevue/toast'
12
+ </script>
13
+
14
+ <template>
15
+ <Toast />
16
+ </template>
@@ -0,0 +1,96 @@
1
+ <script setup>
2
+ /**
3
+ * DefaultUserInfo - Default user info component for sidebar
4
+ *
5
+ * Displays user avatar, name, role, and logout button.
6
+ * Extracted from AppLayout for zone-based architecture.
7
+ *
8
+ * This component is used when auth is enabled.
9
+ */
10
+ import { computed, inject } from 'vue'
11
+ import { useRouter } from 'vue-router'
12
+ import { useAuth } from '../../../composables/useAuth'
13
+ import Button from 'primevue/button'
14
+
15
+ const router = useRouter()
16
+ const { isAuthenticated, user, logout, authEnabled } = useAuth()
17
+
18
+ const userInitials = computed(() => {
19
+ const username = user.value?.username
20
+ if (!username) return '?'
21
+ return username.substring(0, 2).toUpperCase()
22
+ })
23
+
24
+ const userDisplayName = computed(() => {
25
+ return user.value?.username || user.value?.name || 'User'
26
+ })
27
+
28
+ const userSubtitle = computed(() => {
29
+ return user.value?.email || user.value?.role || ''
30
+ })
31
+
32
+ function handleLogout() {
33
+ logout()
34
+ router.push({ name: 'login' })
35
+ }
36
+ </script>
37
+
38
+ <template>
39
+ <div v-if="authEnabled" class="default-user-info">
40
+ <div class="user-avatar">{{ userInitials }}</div>
41
+ <div class="user-details">
42
+ <div class="user-name">{{ userDisplayName }}</div>
43
+ <div class="user-role">{{ userSubtitle }}</div>
44
+ </div>
45
+ <Button
46
+ icon="pi pi-sign-out"
47
+ severity="secondary"
48
+ text
49
+ rounded
50
+ @click="handleLogout"
51
+ v-tooltip.top="'Logout'"
52
+ />
53
+ </div>
54
+ </template>
55
+
56
+ <style scoped>
57
+ .default-user-info {
58
+ display: flex;
59
+ align-items: center;
60
+ gap: 0.75rem;
61
+ padding: 1rem 1.5rem;
62
+ border-top: 1px solid var(--p-surface-700, #334155);
63
+ }
64
+
65
+ .user-avatar {
66
+ width: 36px;
67
+ height: 36px;
68
+ border-radius: 50%;
69
+ background: var(--p-primary-600, #2563eb);
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ font-size: 0.875rem;
74
+ font-weight: 600;
75
+ color: var(--p-surface-0, white);
76
+ }
77
+
78
+ .user-details {
79
+ flex: 1;
80
+ min-width: 0;
81
+ }
82
+
83
+ .user-name {
84
+ font-weight: 500;
85
+ font-size: 0.875rem;
86
+ color: var(--p-surface-0, white);
87
+ }
88
+
89
+ .user-role {
90
+ font-size: 0.75rem;
91
+ color: var(--p-surface-400, #94a3b8);
92
+ overflow: hidden;
93
+ text-overflow: ellipsis;
94
+ white-space: nowrap;
95
+ }
96
+ </style>
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Default zone components for layouts
3
+ *
4
+ * These components are rendered when no blocks are registered
5
+ * in their respective zones.
6
+ */
7
+
8
+ // BaseLayout defaults
9
+ export { default as DefaultHeader } from './DefaultHeader.vue'
10
+ export { default as DefaultMenu } from './DefaultMenu.vue'
11
+ export { default as DefaultFooter } from './DefaultFooter.vue'
12
+ export { default as DefaultUserInfo } from './DefaultUserInfo.vue'
13
+ export { default as DefaultBreadcrumb } from './DefaultBreadcrumb.vue'
14
+ export { default as DefaultToaster } from './DefaultToaster.vue'
15
+
16
+ // FormLayout defaults
17
+ export { default as DefaultFormActions } from './DefaultFormActions.vue'
@@ -5,18 +5,18 @@
5
5
  export { useBareForm } from './useBareForm'
6
6
  export { useBreadcrumb } from './useBreadcrumb'
7
7
  export { useDirtyState } from './useDirtyState'
8
- export { useEntityTitle } from './useEntityTitle'
9
8
  export { useForm } from './useForm'
9
+ export { useFormPageBuilder } from './useFormPageBuilder'
10
10
  export * from './useJsonSyntax'
11
11
  export { useListPageBuilder, PAGE_SIZE_OPTIONS } from './useListPageBuilder'
12
- export { usePageBuilder } from './usePageBuilder'
13
12
  export { usePageTitle } from './usePageTitle'
14
- export { useSubEditor } from './useSubEditor'
15
- export { useTabSync } from './useTabSync'
16
13
  export { useApp } from './useApp'
17
14
  export { useAuth } from './useAuth'
18
15
  export { useNavContext } from './useNavContext'
19
16
  export { useNavigation } from './useNavigation'
20
- export { useStatus } from './useStatus'
21
17
  export { useUnsavedChangesGuard } from './useUnsavedChangesGuard'
22
- export { useManager } from './useManager'
18
+ export { useGuardDialog } from './useGuardStore'
19
+ export { useSignals } from './useSignals'
20
+ export { useZoneRegistry } from './useZoneRegistry'
21
+ export { useHooks } from './useHooks'
22
+ export { useLayoutResolver, createLayoutComponents, layoutMeta, LAYOUT_TYPES } from './useLayoutResolver'