@dashadmin/dash-app-common 1.3.24 → 1.3.26
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.
- package/dist/DashApp.js +176 -1
- package/dist/DashAppLoader.js +348 -3
- package/dist/DashDefaultResources.js +10 -1
- package/dist/components/DashDefaultPrivateApp.js +150 -1
- package/dist/components/DashDefaultPrivateResources.js +10 -1
- package/dist/components/DashDefaultPublicApp.js +20 -1
- package/dist/components/DashResourceLoader.js +245 -1
- package/dist/defaults/extensions/bootstrap/DashDefaultErrorBoundary.js +78 -1
- package/dist/defaults/extensions/bootstrap/dashDefaultInitializeApp.js +59 -1
- package/dist/defaults/extensions/bootstrap/index.js +24 -1
- package/dist/defaults/extensions/components/DashDefaultLoader.js +43 -2
- package/dist/defaults/extensions/components/dashDefaultAutoAdminComponents.js +67 -1
- package/dist/defaults/extensions/components/dashDefaultNotification.js +28 -1
- package/dist/defaults/extensions/components/dashDefaultStaticComponents.js +15 -1
- package/dist/defaults/extensions/components/index.js +13 -1
- package/dist/defaults/extensions/electron/dashDefaultIpcListeners.js +38 -1
- package/dist/defaults/extensions/electron/index.js +5 -1
- package/dist/defaults/extensions/hooks/index.js +12 -1
- package/dist/defaults/extensions/hooks/useDashDefaultLazyAutoAdminComponents.js +17 -1
- package/dist/defaults/extensions/hooks/useDashDefaultLazyI18nProvider.js +51 -1
- package/dist/defaults/extensions/hooks/useDashDefaultLazyResources.js +19 -1
- package/dist/defaults/extensions/hooks/useDashDefaultMountTracker.js +22 -1
- package/dist/defaults/extensions/hooks/useDashDefaultRoutePath.js +17 -1
- package/dist/defaults/extensions/i18n/dashDefaultI18nProvider.js +44 -1
- package/dist/defaults/extensions/i18n/dashDefaultTranslations.js +87 -1
- package/dist/defaults/extensions/i18n/index.js +24 -1
- package/dist/defaults/extensions/index.js +190 -1
- package/dist/defaults/extensions/layout/dashDefaultDomainAppLayout.js +58 -1
- package/dist/defaults/extensions/layout/index.js +12 -1
- package/dist/defaults/extensions/managers/DashDefaultWSMessagesManager.js +84 -1
- package/dist/defaults/extensions/managers/index.js +5 -1
- package/dist/defaults/extensions/providers/dashDefaultAuthProvider.js +220 -1
- package/dist/defaults/extensions/providers/dashDefaultDataProvider.js +395 -1
- package/dist/defaults/extensions/providers/index.js +24 -1
- package/dist/defaults/extensions/router/DashDefaultLanding.js +46 -1
- package/dist/defaults/extensions/router/dashDefaultPrivateRoutes.js +38 -1
- package/dist/defaults/extensions/router/dashDefaultPublicRoutes.js +65 -1
- package/dist/defaults/extensions/router/dashDefaultRouter.js +39 -1
- package/dist/defaults/extensions/router/dashDefaultSharedRoutes.js +40 -1
- package/dist/defaults/extensions/router/index.js +12 -1
- package/dist/defaults/extensions/state/dashDefaultAppCommon.js +57 -1
- package/dist/defaults/extensions/state/dashDefaultAppSettings.js +38 -1
- package/dist/defaults/extensions/state/dashDefaultInitialAppState.js +31 -1
- package/dist/defaults/extensions/state/dashDefaultLayoutSettings.js +48 -1
- package/dist/defaults/extensions/state/dashDefaultQueryClient.js +58 -1
- package/dist/defaults/extensions/state/dashDefaultResourcesIcons.js +24 -1
- package/dist/defaults/extensions/state/index.js +29 -1
- package/dist/defaults/extensions/styles/index.js +2 -1
- package/dist/defaults/extensions/theme/dashDefaultThemeOptions.js +74 -1
- package/dist/defaults/extensions/theme/index.js +6 -1
- package/dist/defaults/extensions/utils/IPCMessageBrokerContext.js +12 -1
- package/dist/defaults/extensions/utils/dashDefaultAuthProviderUtils.js +29 -1
- package/dist/defaults/extensions/utils/dashDefaultDataProviderUtils.js +37 -1
- package/dist/defaults/extensions/utils/dashDefaultNotificationsProcessor.js +149 -1
- package/dist/defaults/extensions/utils/index.js +44 -1
- package/dist/defaults/filters/demo/dashDefaultDemoFilters.js +36 -1
- package/dist/defaults/filters/demo/index.js +4 -1
- package/dist/defaults/filters/index.js +5 -1
- package/dist/defaults/index.js +14 -1
- package/dist/defaults/pages/Account/DashDefaultRegister.js +282 -1
- package/dist/defaults/pages/Account/DashDefaultSignUp.js +420 -1
- package/dist/defaults/pages/Account/DashDefaultSignUpSuccess.js +101 -1
- package/dist/defaults/pages/Account/index.js +8 -1
- package/dist/defaults/pages/DashDefaultLogin.js +218 -1
- package/dist/defaults/pages/Misc/DashDefaultNotFound.js +74 -1
- package/dist/defaults/pages/Misc/DashDefaultServerError.js +79 -1
- package/dist/defaults/pages/Misc/DashDefaultUnauthorized.js +90 -1
- package/dist/defaults/pages/Misc/index.js +8 -1
- package/dist/defaults/pages/Static/DashDefaultPrivacyPage.js +48 -1
- package/dist/defaults/pages/Static/DashDefaultStaticPage.js +55 -1
- package/dist/defaults/pages/Static/DashDefaultTermsPage.js +52 -1
- package/dist/defaults/pages/Static/index.js +8 -1
- package/dist/defaults/pages/index.js +25 -1
- package/dist/defaults/schemas/dashDefaultSchema.js +14 -1
- package/dist/defaults/schemas/demo/dashDefaultTodoSchema.js +24 -1
- package/dist/defaults/schemas/demo/index.js +4 -1
- package/dist/defaults/schemas/index.js +7 -1
- package/dist/filters/demo/todoFilters.js +36 -1
- package/dist/index.js +56 -5975
- package/dist/resources/demo/todoResource.js +58 -1
- package/dist/schemas/defaultSchema.js +14 -1
- package/dist/schemas/demo/todoSchema.js +24 -1
- package/package.json +132 -77
- package/src/DashApp.tsx +294 -0
- package/src/DashAppLoader.tsx +717 -0
- package/src/DashDefaultResources.tsx +10 -0
- package/src/components/DashDefaultPrivateApp.tsx +358 -0
- package/src/components/DashDefaultPrivateResources.tsx +10 -0
- package/src/components/DashDefaultPublicApp.tsx +40 -0
- package/src/components/DashResourceLoader.tsx +564 -0
- package/src/defaults/extensions/bootstrap/DashDefaultErrorBoundary.tsx +113 -0
- package/src/defaults/extensions/bootstrap/dashDefaultInitializeApp.ts +81 -0
- package/src/defaults/extensions/bootstrap/index.ts +32 -0
- package/src/defaults/extensions/components/DashDefaultLoader.tsx +59 -0
- package/src/defaults/extensions/components/dashDefaultAutoAdminComponents.tsx +49 -0
- package/src/defaults/extensions/components/dashDefaultNotification.tsx +37 -0
- package/src/defaults/extensions/components/dashDefaultStaticComponents.tsx +34 -0
- package/src/defaults/extensions/components/index.ts +17 -0
- package/src/defaults/extensions/electron/dashDefaultIpcListeners.ts +62 -0
- package/src/defaults/extensions/electron/index.ts +7 -0
- package/src/defaults/extensions/hooks/index.ts +11 -0
- package/src/defaults/extensions/hooks/useDashDefaultLazyAutoAdminComponents.ts +25 -0
- package/src/defaults/extensions/hooks/useDashDefaultLazyI18nProvider.ts +38 -0
- package/src/defaults/extensions/hooks/useDashDefaultLazyResources.ts +29 -0
- package/src/defaults/extensions/hooks/useDashDefaultMountTracker.ts +28 -0
- package/src/defaults/extensions/hooks/useDashDefaultRoutePath.ts +27 -0
- package/src/defaults/extensions/i18n/dashDefaultI18nProvider.ts +66 -0
- package/src/defaults/extensions/i18n/dashDefaultTranslations.ts +82 -0
- package/src/defaults/extensions/i18n/index.ts +22 -0
- package/src/defaults/extensions/index.ts +177 -0
- package/src/defaults/extensions/layout/dashDefaultDomainAppLayout.tsx +126 -0
- package/src/defaults/extensions/layout/index.ts +12 -0
- package/src/defaults/extensions/managers/DashDefaultWSMessagesManager.tsx +99 -0
- package/src/defaults/extensions/managers/index.ts +7 -0
- package/src/defaults/extensions/providers/dashDefaultAuthProvider.ts +256 -0
- package/src/defaults/extensions/providers/dashDefaultDataProvider.ts +513 -0
- package/src/defaults/extensions/providers/index.ts +25 -0
- package/src/defaults/extensions/router/DashDefaultLanding.tsx +51 -0
- package/src/defaults/extensions/router/dashDefaultPrivateRoutes.tsx +50 -0
- package/src/defaults/extensions/router/dashDefaultPublicRoutes.tsx +86 -0
- package/src/defaults/extensions/router/dashDefaultRouter.tsx +54 -0
- package/src/defaults/extensions/router/dashDefaultSharedRoutes.tsx +56 -0
- package/src/defaults/extensions/router/index.ts +13 -0
- package/src/defaults/extensions/state/dashDefaultAppCommon.ts +54 -0
- package/src/defaults/extensions/state/dashDefaultAppSettings.ts +29 -0
- package/src/defaults/extensions/state/dashDefaultInitialAppState.ts +75 -0
- package/src/defaults/extensions/state/dashDefaultLayoutSettings.ts +59 -0
- package/src/defaults/extensions/state/dashDefaultQueryClient.ts +59 -0
- package/src/defaults/extensions/state/dashDefaultResourcesIcons.tsx +23 -0
- package/src/defaults/extensions/state/index.ts +29 -0
- package/src/defaults/extensions/styles/index.ts +17 -0
- package/src/defaults/extensions/theme/dashDefaultThemeOptions.ts +89 -0
- package/src/defaults/extensions/theme/index.ts +7 -0
- package/src/defaults/extensions/utils/IPCMessageBrokerContext.tsx +22 -0
- package/src/defaults/extensions/utils/dashDefaultAuthProviderUtils.ts +36 -0
- package/src/defaults/extensions/utils/dashDefaultDataProviderUtils.ts +46 -0
- package/src/defaults/extensions/utils/dashDefaultNotificationsProcessor.tsx +208 -0
- package/src/defaults/extensions/utils/index.ts +42 -0
- package/src/defaults/filters/demo/dashDefaultDemoFilters.tsx +50 -0
- package/src/defaults/filters/demo/index.ts +6 -0
- package/src/defaults/filters/index.ts +11 -0
- package/src/defaults/index.ts +27 -0
- package/src/defaults/pages/Account/DashDefaultRegister.tsx +281 -0
- package/src/defaults/pages/Account/DashDefaultSignUp.tsx +492 -0
- package/src/defaults/pages/Account/DashDefaultSignUpSuccess.tsx +113 -0
- package/src/defaults/pages/Account/index.ts +8 -0
- package/src/defaults/pages/DashDefaultLogin.tsx +224 -0
- package/src/defaults/pages/Misc/DashDefaultNotFound.tsx +96 -0
- package/src/defaults/pages/Misc/DashDefaultServerError.tsx +102 -0
- package/src/defaults/pages/Misc/DashDefaultUnauthorized.tsx +116 -0
- package/src/defaults/pages/Misc/index.ts +8 -0
- package/src/defaults/pages/Static/DashDefaultPrivacyPage.tsx +85 -0
- package/src/defaults/pages/Static/DashDefaultStaticPage.tsx +75 -0
- package/src/defaults/pages/Static/DashDefaultTermsPage.tsx +69 -0
- package/src/defaults/pages/Static/index.ts +8 -0
- package/src/defaults/pages/index.ts +28 -0
- package/src/defaults/schemas/dashDefaultSchema.tsx +25 -0
- package/src/defaults/schemas/demo/dashDefaultTodoSchema.tsx +39 -0
- package/src/defaults/schemas/demo/index.ts +6 -0
- package/src/defaults/schemas/index.ts +14 -0
- package/src/filters/demo/todoFilters.tsx +39 -0
- package/src/index.ts +131 -0
- package/src/resources/demo/todoResource.tsx +68 -0
- package/src/schemas/defaultSchema.tsx +14 -0
- package/src/schemas/demo/todoSchema.tsx +27 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DashResourceLoader
|
|
3
|
+
*
|
|
4
|
+
* A component and utilities for loading resources dynamically from a manifest.
|
|
5
|
+
* This allows apps to code-split their resource configurations and load them on demand.
|
|
6
|
+
*
|
|
7
|
+
* ============================================================================
|
|
8
|
+
* USAGE
|
|
9
|
+
* ============================================================================
|
|
10
|
+
*
|
|
11
|
+
* // 1. Create a resourceManifest.ts in your app that exports import functions:
|
|
12
|
+
* // export const resourceManifest = {
|
|
13
|
+
* // systemResources: () => import('dash-admin/src/systemResources'),
|
|
14
|
+
* // todoResource: () => import('./resources/demo/todoResource'),
|
|
15
|
+
* // };
|
|
16
|
+
*
|
|
17
|
+
* // 2. Use DashPrivateAppWithManifest in your DASHApp.tsx:
|
|
18
|
+
* import { DashPrivateAppWithManifest } from 'dash-app-common';
|
|
19
|
+
* import { resourceManifest } from './resourceManifest';
|
|
20
|
+
*
|
|
21
|
+
* const DASHApp = () => (
|
|
22
|
+
* <DashPrivateAppWithManifest manifest={resourceManifest} />
|
|
23
|
+
* );
|
|
24
|
+
*
|
|
25
|
+
* // 3. Or use the hook directly:
|
|
26
|
+
* import { useDashResourceManifest } from 'dash-app-common';
|
|
27
|
+
*
|
|
28
|
+
* const MyApp = () => {
|
|
29
|
+
* const { resources, loading, error } = useDashResourceManifest(manifest);
|
|
30
|
+
* if (loading) return <Loading />;
|
|
31
|
+
* if (error) return <Error error={error} />;
|
|
32
|
+
* return <DashDefaultPrivateApp resources={resources} />;
|
|
33
|
+
* };
|
|
34
|
+
*/
|
|
35
|
+
import React, { useState, useEffect, PropsWithChildren, ReactElement } from 'react';
|
|
36
|
+
import { IDashAutoAdminResourceConfig } from 'dash-auto-admin';
|
|
37
|
+
import AppLoadingFallback from 'dash-components/src/components/theme/AppLoadingFallback';
|
|
38
|
+
import DashDefaultPrivateApp from './DashDefaultPrivateApp';
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// TYPES
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Import function type for lazy loading a resource module
|
|
46
|
+
*/
|
|
47
|
+
export type ResourceImportFn = () => Promise<{ default: IDashAutoAdminResourceConfig | IDashAutoAdminResourceConfig[] }>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resource manifest - object mapping names to import functions
|
|
51
|
+
* This allows Vite/Webpack to properly resolve and bundle the imports
|
|
52
|
+
*/
|
|
53
|
+
export type ResourceManifest = Record<string, ResourceImportFn>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Result of the useDashResourceManifest hook
|
|
57
|
+
*/
|
|
58
|
+
export interface UseDashResourceManifestResult {
|
|
59
|
+
/** Loaded resources (null if still loading) */
|
|
60
|
+
resources: IDashAutoAdminResourceConfig[] | null;
|
|
61
|
+
/** Whether resources are currently loading */
|
|
62
|
+
loading: boolean;
|
|
63
|
+
/** Error message if loading failed */
|
|
64
|
+
error: string | null;
|
|
65
|
+
/** Reload resources from manifest */
|
|
66
|
+
reload: () => void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Props for DashPrivateAppWithManifest
|
|
71
|
+
*
|
|
72
|
+
* Includes all DASHAdmin props plus manifest-specific configuration.
|
|
73
|
+
* Props are passed through the hierarchy: DashPrivateAppWithManifest → DashDefaultPrivateApp → DASHAdmin
|
|
74
|
+
*/
|
|
75
|
+
export interface DashPrivateAppWithManifestProps extends PropsWithChildren {
|
|
76
|
+
// ========================================================================
|
|
77
|
+
// MANIFEST-SPECIFIC PROPS
|
|
78
|
+
// ========================================================================
|
|
79
|
+
/** Resource manifest object with import functions */
|
|
80
|
+
manifest: ResourceManifest;
|
|
81
|
+
/** Custom loading component for manifest loading */
|
|
82
|
+
LoadingComponent?: React.ComponentType<{ message?: string }>;
|
|
83
|
+
/** Custom error component for manifest loading failures */
|
|
84
|
+
ErrorComponent?: React.ComponentType<{ error: string; onRetry: () => void }>;
|
|
85
|
+
|
|
86
|
+
// ========================================================================
|
|
87
|
+
// APP CONFIGURATION PROPS
|
|
88
|
+
// ========================================================================
|
|
89
|
+
/** Base path for the admin app (passed to DASHAdmin as basePath) */
|
|
90
|
+
appPath?: string;
|
|
91
|
+
/** Whether to use the internal router */
|
|
92
|
+
useOwnRouter?: boolean;
|
|
93
|
+
/** Global hook component (for global side effects) */
|
|
94
|
+
GlobalHook?: React.ComponentType<any>;
|
|
95
|
+
|
|
96
|
+
// ========================================================================
|
|
97
|
+
// DASHADMIN PROPS (passed through to DASHAdmin)
|
|
98
|
+
// ========================================================================
|
|
99
|
+
/** Custom layout component for the admin */
|
|
100
|
+
customLayout?: React.FC<any>;
|
|
101
|
+
/** Custom login page component */
|
|
102
|
+
customLoginPage?: React.FC<any>;
|
|
103
|
+
/** Custom notification component */
|
|
104
|
+
customNotification?: () => React.JSX.Element;
|
|
105
|
+
/** Custom error/catch-all page component */
|
|
106
|
+
customErrorPage?: any;
|
|
107
|
+
/** Custom data provider */
|
|
108
|
+
customDataProvider?: any;
|
|
109
|
+
/** Custom auth provider */
|
|
110
|
+
customAuthProvider?: any;
|
|
111
|
+
/** Custom i18n provider */
|
|
112
|
+
customI18nProvider?: any;
|
|
113
|
+
/** Whether to use core resources (default: false for manifest apps) */
|
|
114
|
+
useCoreResources?: boolean;
|
|
115
|
+
/** Custom profile page component (false to disable) */
|
|
116
|
+
customProfilePage?: React.JSX.Element | false;
|
|
117
|
+
/** Custom recover password page (false to disable) */
|
|
118
|
+
customRecoverPassword?: React.JSX.Element | false;
|
|
119
|
+
/** Custom change password page (false to disable) */
|
|
120
|
+
customChangePassword?: React.JSX.Element | false;
|
|
121
|
+
/** Custom verify account page (false to disable) */
|
|
122
|
+
customVerifyAccount?: React.JSX.Element | false;
|
|
123
|
+
/** Custom theme configuration */
|
|
124
|
+
customThemeConfig?: any;
|
|
125
|
+
/** Custom authenticated routes */
|
|
126
|
+
customAuthRoutes?: React.ReactElement[];
|
|
127
|
+
/** Custom public routes */
|
|
128
|
+
customRoutes?: React.ReactElement[];
|
|
129
|
+
/** Custom public routes (alias for customRoutes, used by DashDefaultPrivateApp) */
|
|
130
|
+
customPublicRoutes?: () => ReactElement[];
|
|
131
|
+
/** Custom private/auth routes (alias for customAuthRoutes, used by DashDefaultPrivateApp) */
|
|
132
|
+
customPrivateRoutes?: () => ReactElement[];
|
|
133
|
+
/** Custom React Query client */
|
|
134
|
+
customQueryClient?: any;
|
|
135
|
+
/** Custom dictionary for translations */
|
|
136
|
+
customDict?: { [x: string]: string };
|
|
137
|
+
/** Custom string replacements */
|
|
138
|
+
customReplacements?: { [x: string]: string };
|
|
139
|
+
/** Custom history object */
|
|
140
|
+
history?: any;
|
|
141
|
+
/** Initial app constants */
|
|
142
|
+
initialAppConstants?: any;
|
|
143
|
+
/** Admin hook component (wraps admin content) */
|
|
144
|
+
AdminHook?: React.ComponentType<any>;
|
|
145
|
+
/** WebSocket messages manager for real-time notifications */
|
|
146
|
+
wsMessagesManager?: any;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Props for DashPrivateApp (unified component)
|
|
151
|
+
*
|
|
152
|
+
* Supports both manifest-based and direct resource loading via a single `resources` prop.
|
|
153
|
+
* The component automatically detects which format is provided:
|
|
154
|
+
* - ResourceManifest: Object with import functions (for code-splitting)
|
|
155
|
+
* - IDashAutoAdminResourceConfig[]: Direct array of resources (immediate use)
|
|
156
|
+
*/
|
|
157
|
+
export interface DashPrivateAppProps extends PropsWithChildren {
|
|
158
|
+
// ========================================================================
|
|
159
|
+
// RESOURCE PROPS (accepts either format)
|
|
160
|
+
// ========================================================================
|
|
161
|
+
/**
|
|
162
|
+
* Resources can be either:
|
|
163
|
+
* - ResourceManifest: Object with import functions for code-splitting
|
|
164
|
+
* - IDashAutoAdminResourceConfig[]: Direct array for immediate use
|
|
165
|
+
*/
|
|
166
|
+
resources?: ResourceManifest | IDashAutoAdminResourceConfig[];
|
|
167
|
+
|
|
168
|
+
/** Custom loading component for manifest loading */
|
|
169
|
+
LoadingComponent?: React.ComponentType<{ message?: string }>;
|
|
170
|
+
/** Custom error component for manifest loading failures */
|
|
171
|
+
ErrorComponent?: React.ComponentType<{ error: string; onRetry: () => void }>;
|
|
172
|
+
|
|
173
|
+
// ========================================================================
|
|
174
|
+
// APP CONFIGURATION PROPS
|
|
175
|
+
// ========================================================================
|
|
176
|
+
/** Base path for the admin app (passed to DASHAdmin as basePath) */
|
|
177
|
+
appPath?: string;
|
|
178
|
+
/** Whether to use the internal router */
|
|
179
|
+
useOwnRouter?: boolean;
|
|
180
|
+
/** Global hook component (for global side effects) */
|
|
181
|
+
GlobalHook?: React.ComponentType<any>;
|
|
182
|
+
|
|
183
|
+
// ========================================================================
|
|
184
|
+
// DASHADMIN PROPS (passed through to DASHAdmin)
|
|
185
|
+
// ========================================================================
|
|
186
|
+
/** Custom layout component for the admin */
|
|
187
|
+
customLayout?: React.FC<any>;
|
|
188
|
+
/** Custom login page component */
|
|
189
|
+
customLoginPage?: React.FC<any>;
|
|
190
|
+
/** Custom notification component */
|
|
191
|
+
customNotification?: () => React.JSX.Element;
|
|
192
|
+
/** Custom error/catch-all page component */
|
|
193
|
+
customErrorPage?: any;
|
|
194
|
+
/** Custom data provider */
|
|
195
|
+
customDataProvider?: any;
|
|
196
|
+
/** Custom auth provider */
|
|
197
|
+
customAuthProvider?: any;
|
|
198
|
+
/** Custom i18n provider */
|
|
199
|
+
customI18nProvider?: any;
|
|
200
|
+
/** Whether to use core resources (default: false for manifest apps) */
|
|
201
|
+
useCoreResources?: boolean;
|
|
202
|
+
/** Custom profile page component (false to disable) */
|
|
203
|
+
customProfilePage?: React.JSX.Element | false;
|
|
204
|
+
/** Custom recover password page (false to disable) */
|
|
205
|
+
customRecoverPassword?: React.JSX.Element | false;
|
|
206
|
+
/** Custom change password page (false to disable) */
|
|
207
|
+
customChangePassword?: React.JSX.Element | false;
|
|
208
|
+
/** Custom verify account page (false to disable) */
|
|
209
|
+
customVerifyAccount?: React.JSX.Element | false;
|
|
210
|
+
/** Custom theme configuration */
|
|
211
|
+
customThemeConfig?: any;
|
|
212
|
+
/** Custom authenticated routes */
|
|
213
|
+
customAuthRoutes?: React.ReactElement[];
|
|
214
|
+
/** Custom public routes */
|
|
215
|
+
customRoutes?: React.ReactElement[];
|
|
216
|
+
/** Custom public routes (alias for customRoutes, used by DashDefaultPrivateApp) */
|
|
217
|
+
customPublicRoutes?: () => ReactElement[];
|
|
218
|
+
/** Custom private/auth routes (alias for customAuthRoutes, used by DashDefaultPrivateApp) */
|
|
219
|
+
customPrivateRoutes?: () => ReactElement[];
|
|
220
|
+
/** Custom React Query client */
|
|
221
|
+
customQueryClient?: any;
|
|
222
|
+
/** Custom dictionary for translations */
|
|
223
|
+
customDict?: { [x: string]: string };
|
|
224
|
+
/** Custom string replacements */
|
|
225
|
+
customReplacements?: { [x: string]: string };
|
|
226
|
+
/** Custom history object */
|
|
227
|
+
history?: any;
|
|
228
|
+
/** Initial app constants */
|
|
229
|
+
initialAppConstants?: any;
|
|
230
|
+
/** Admin hook component (wraps admin content) */
|
|
231
|
+
AdminHook?: React.ComponentType<any>;
|
|
232
|
+
/** WebSocket messages manager for real-time notifications */
|
|
233
|
+
wsMessagesManager?: any;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ============================================================================
|
|
237
|
+
// TYPE GUARDS
|
|
238
|
+
// ============================================================================
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Check if resources is a ResourceManifest (object with import functions)
|
|
242
|
+
*/
|
|
243
|
+
export const isResourceManifest = (
|
|
244
|
+
resources: ResourceManifest | IDashAutoAdminResourceConfig[] | undefined
|
|
245
|
+
): resources is ResourceManifest => {
|
|
246
|
+
if (!resources) return false;
|
|
247
|
+
if (Array.isArray(resources)) return false;
|
|
248
|
+
// Check if it's an object with function values (import functions)
|
|
249
|
+
return typeof resources === 'object' &&
|
|
250
|
+
Object.values(resources).every(val => typeof val === 'function');
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Check if resources is a direct array of resource configs
|
|
255
|
+
*/
|
|
256
|
+
export const isResourceArray = (
|
|
257
|
+
resources: ResourceManifest | IDashAutoAdminResourceConfig[] | undefined
|
|
258
|
+
): resources is IDashAutoAdminResourceConfig[] => {
|
|
259
|
+
return Array.isArray(resources);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// ============================================================================
|
|
263
|
+
// RESOURCE LOADING UTILITIES
|
|
264
|
+
// ============================================================================
|
|
265
|
+
|
|
266
|
+
// Cache for loaded resources (keyed by manifest object reference)
|
|
267
|
+
const resourceCache = new WeakMap<ResourceManifest, IDashAutoAdminResourceConfig[]>();
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Load resources from a manifest object
|
|
271
|
+
* @param manifest - Object mapping names to import functions
|
|
272
|
+
* @returns Promise resolving to array of resource configs
|
|
273
|
+
*/
|
|
274
|
+
export const loadResourcesFromManifest = async (
|
|
275
|
+
manifest: ResourceManifest
|
|
276
|
+
): Promise<IDashAutoAdminResourceConfig[]> => {
|
|
277
|
+
// Return cached resources if available
|
|
278
|
+
if (resourceCache.has(manifest)) {
|
|
279
|
+
return resourceCache.get(manifest)!;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const entries = Object.entries(manifest);
|
|
283
|
+
|
|
284
|
+
// Load all resource modules in parallel
|
|
285
|
+
const imports = await Promise.all(
|
|
286
|
+
entries.map(async ([name, importFn]) => {
|
|
287
|
+
try {
|
|
288
|
+
const module = await importFn();
|
|
289
|
+
return module.default;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.error(`❌ Failed to load resource "${name}":`, error);
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Flatten and filter out failed imports
|
|
298
|
+
const allResources = imports
|
|
299
|
+
.filter((mod): mod is IDashAutoAdminResourceConfig | IDashAutoAdminResourceConfig[] => mod !== null)
|
|
300
|
+
.flatMap(mod => Array.isArray(mod) ? mod : [mod]);
|
|
301
|
+
|
|
302
|
+
// Deduplicate by model, keeping the LAST occurrence (so overrides win)
|
|
303
|
+
// Resources loaded later in the manifest override earlier ones with the same model
|
|
304
|
+
const resourceMap = new Map<string, IDashAutoAdminResourceConfig>();
|
|
305
|
+
for (const resource of allResources) {
|
|
306
|
+
if (resource.model) {
|
|
307
|
+
resourceMap.set(resource.model, resource);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const resources = Array.from(resourceMap.values());
|
|
311
|
+
|
|
312
|
+
// Cache the results
|
|
313
|
+
resourceCache.set(manifest, resources);
|
|
314
|
+
|
|
315
|
+
return resources;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Clear a specific manifest from cache
|
|
320
|
+
*/
|
|
321
|
+
export const clearResourceCache = (manifest: ResourceManifest): void => {
|
|
322
|
+
resourceCache.delete(manifest);
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// ============================================================================
|
|
326
|
+
// HOOK: useDashResourceManifest
|
|
327
|
+
// ============================================================================
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Hook to load resources from a manifest
|
|
331
|
+
*
|
|
332
|
+
* @param manifest - Object mapping names to import functions
|
|
333
|
+
* @returns Object with resources, loading state, error, and reload function
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```tsx
|
|
337
|
+
* const manifest = {
|
|
338
|
+
* systemResources: () => import('dash-admin/src/systemResources'),
|
|
339
|
+
* myResource: () => import('./resources/myResource'),
|
|
340
|
+
* };
|
|
341
|
+
*
|
|
342
|
+
* const { resources, loading, error, reload } = useDashResourceManifest(manifest);
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
export const useDashResourceManifest = (
|
|
346
|
+
manifest: ResourceManifest
|
|
347
|
+
): UseDashResourceManifestResult => {
|
|
348
|
+
const [resources, setResources] = useState<IDashAutoAdminResourceConfig[] | null>(null);
|
|
349
|
+
const [loading, setLoading] = useState(true);
|
|
350
|
+
const [error, setError] = useState<string | null>(null);
|
|
351
|
+
const [reloadTrigger, setReloadTrigger] = useState(0);
|
|
352
|
+
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
let mounted = true;
|
|
355
|
+
|
|
356
|
+
const load = async () => {
|
|
357
|
+
setLoading(true);
|
|
358
|
+
setError(null);
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
const loadedResources = await loadResourcesFromManifest(manifest);
|
|
362
|
+
|
|
363
|
+
if (mounted) {
|
|
364
|
+
console.log('📦 useDashResourceManifest: Loaded', loadedResources.length, 'resources from manifest');
|
|
365
|
+
setResources(loadedResources);
|
|
366
|
+
setLoading(false);
|
|
367
|
+
}
|
|
368
|
+
} catch (err) {
|
|
369
|
+
if (mounted) {
|
|
370
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to load resources';
|
|
371
|
+
console.error('❌ useDashResourceManifest:', errorMessage);
|
|
372
|
+
setError(errorMessage);
|
|
373
|
+
setLoading(false);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
load();
|
|
379
|
+
|
|
380
|
+
return () => {
|
|
381
|
+
mounted = false;
|
|
382
|
+
};
|
|
383
|
+
}, [manifest, reloadTrigger]);
|
|
384
|
+
|
|
385
|
+
const reload = () => {
|
|
386
|
+
// Clear cache for fresh load
|
|
387
|
+
clearResourceCache(manifest);
|
|
388
|
+
setReloadTrigger(prev => prev + 1);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
return { resources, loading, error, reload };
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// ============================================================================
|
|
395
|
+
// COMPONENT: DashPrivateAppWithManifest
|
|
396
|
+
// ============================================================================
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Default loading component for manifest loading
|
|
400
|
+
*/
|
|
401
|
+
const DefaultManifestLoader: React.FC<{ message?: string }> = ({ message }) => (
|
|
402
|
+
<AppLoadingFallback message={message || "Loading resources..."} />
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Default error component for manifest loading failures
|
|
407
|
+
*/
|
|
408
|
+
const DefaultManifestError: React.FC<{ error: string; onRetry: () => void }> = ({ error, onRetry }) => (
|
|
409
|
+
<div style={{
|
|
410
|
+
display: 'flex',
|
|
411
|
+
flexDirection: 'column',
|
|
412
|
+
justifyContent: 'center',
|
|
413
|
+
alignItems: 'center',
|
|
414
|
+
height: '100vh',
|
|
415
|
+
backgroundColor: 'var(--dash-background, #121212)',
|
|
416
|
+
color: 'var(--dash-text, #ffffff)',
|
|
417
|
+
padding: '20px'
|
|
418
|
+
}}>
|
|
419
|
+
<h2 style={{ color: '#f44336', marginBottom: '16px' }}>Failed to load resources</h2>
|
|
420
|
+
<p style={{ marginBottom: '24px', opacity: 0.8, textAlign: 'center', maxWidth: '500px' }}>
|
|
421
|
+
{error}
|
|
422
|
+
</p>
|
|
423
|
+
<button
|
|
424
|
+
onClick={onRetry}
|
|
425
|
+
style={{
|
|
426
|
+
backgroundColor: 'var(--dash-primary, #90caf9)',
|
|
427
|
+
color: '#000',
|
|
428
|
+
border: 'none',
|
|
429
|
+
padding: '12px 24px',
|
|
430
|
+
borderRadius: '4px',
|
|
431
|
+
cursor: 'pointer',
|
|
432
|
+
fontSize: '14px',
|
|
433
|
+
fontWeight: 500
|
|
434
|
+
}}
|
|
435
|
+
>
|
|
436
|
+
Retry
|
|
437
|
+
</button>
|
|
438
|
+
</div>
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* DashPrivateAppWithManifest
|
|
443
|
+
*
|
|
444
|
+
* A wrapper around DashDefaultPrivateApp that loads resources from a manifest.
|
|
445
|
+
* This component handles the async loading of resources and passes them to the app.
|
|
446
|
+
*
|
|
447
|
+
* @example
|
|
448
|
+
* ```tsx
|
|
449
|
+
* import { DashPrivateAppWithManifest } from 'dash-app-common';
|
|
450
|
+
*
|
|
451
|
+
* // Define manifest with import functions (allows proper bundling)
|
|
452
|
+
* const resourceManifest = {
|
|
453
|
+
* systemResources: () => import('dash-admin/src/systemResources'),
|
|
454
|
+
* todoResource: () => import('./resources/todoResource'),
|
|
455
|
+
* };
|
|
456
|
+
*
|
|
457
|
+
* const DASHApp = () => (
|
|
458
|
+
* <DashPrivateAppWithManifest
|
|
459
|
+
* manifest={resourceManifest}
|
|
460
|
+
* appPath="/admin"
|
|
461
|
+
* />
|
|
462
|
+
* );
|
|
463
|
+
* ```
|
|
464
|
+
*/
|
|
465
|
+
export const DashPrivateAppWithManifest: React.FC<DashPrivateAppWithManifestProps> = ({
|
|
466
|
+
manifest,
|
|
467
|
+
LoadingComponent = DefaultManifestLoader,
|
|
468
|
+
ErrorComponent = DefaultManifestError,
|
|
469
|
+
children,
|
|
470
|
+
...privateAppProps
|
|
471
|
+
}) => {
|
|
472
|
+
const { resources, loading, error, reload } = useDashResourceManifest(manifest);
|
|
473
|
+
|
|
474
|
+
// Show loading state
|
|
475
|
+
if (loading) {
|
|
476
|
+
return <LoadingComponent message="Loading resources..." />;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Show error state
|
|
480
|
+
if (error) {
|
|
481
|
+
return <ErrorComponent error={error} onRetry={reload} />;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Render the private app with loaded resources
|
|
485
|
+
return (
|
|
486
|
+
<DashDefaultPrivateApp
|
|
487
|
+
resources={resources || []}
|
|
488
|
+
{...privateAppProps}
|
|
489
|
+
>
|
|
490
|
+
{children}
|
|
491
|
+
</DashDefaultPrivateApp>
|
|
492
|
+
);
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
// ============================================================================
|
|
496
|
+
// COMPONENT: DashPrivateApp (Unified)
|
|
497
|
+
// ============================================================================
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* DashPrivateApp
|
|
501
|
+
*
|
|
502
|
+
* A unified component that supports both manifest-based and direct resource loading.
|
|
503
|
+
*
|
|
504
|
+
* Use this when you need flexibility:
|
|
505
|
+
* - Pass `resources` as ResourceManifest for code-splitting with dynamic imports (main app)
|
|
506
|
+
* - Pass `resources` as IDashAutoAdminResourceConfig[] directly for immediate use (sub-apps like MallClient)
|
|
507
|
+
*
|
|
508
|
+
* The component automatically detects the format and handles loading accordingly.
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```tsx
|
|
512
|
+
* // With manifest (code-splitting) - loads resources async
|
|
513
|
+
* <DashPrivateApp resources={DASHResourceManifest} />
|
|
514
|
+
*
|
|
515
|
+
* // With direct resources (no loading needed) - immediate render
|
|
516
|
+
* <DashPrivateApp resources={MallClientAppResources} />
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
export const DashPrivateApp: React.FC<DashPrivateAppProps> = ({
|
|
520
|
+
resources,
|
|
521
|
+
LoadingComponent = DefaultManifestLoader,
|
|
522
|
+
ErrorComponent = DefaultManifestError,
|
|
523
|
+
children,
|
|
524
|
+
...privateAppProps
|
|
525
|
+
}) => {
|
|
526
|
+
// Case 1: Direct resource array - use immediately without loading
|
|
527
|
+
if (isResourceArray(resources)) {
|
|
528
|
+
return (
|
|
529
|
+
<DashDefaultPrivateApp
|
|
530
|
+
resources={resources}
|
|
531
|
+
{...privateAppProps}
|
|
532
|
+
>
|
|
533
|
+
{children}
|
|
534
|
+
</DashDefaultPrivateApp>
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Case 2: Resource manifest - load resources asynchronously
|
|
539
|
+
if (isResourceManifest(resources)) {
|
|
540
|
+
return (
|
|
541
|
+
<DashPrivateAppWithManifest
|
|
542
|
+
manifest={resources}
|
|
543
|
+
LoadingComponent={LoadingComponent}
|
|
544
|
+
ErrorComponent={ErrorComponent}
|
|
545
|
+
{...privateAppProps}
|
|
546
|
+
>
|
|
547
|
+
{children}
|
|
548
|
+
</DashPrivateAppWithManifest>
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Case 3: No resources provided - render with empty resources (will use defaults from DashDefaultPrivateApp)
|
|
553
|
+
console.warn('DashPrivateApp: No resources provided. Using empty resources array.');
|
|
554
|
+
return (
|
|
555
|
+
<DashDefaultPrivateApp
|
|
556
|
+
resources={[]}
|
|
557
|
+
{...privateAppProps}
|
|
558
|
+
>
|
|
559
|
+
{children}
|
|
560
|
+
</DashDefaultPrivateApp>
|
|
561
|
+
);
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
export default DashPrivateAppWithManifest;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Error Boundary Component
|
|
3
|
+
*
|
|
4
|
+
* Catches JavaScript errors anywhere in the child component tree,
|
|
5
|
+
* logs those errors, and displays a fallback UI.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
|
|
9
|
+
export interface DashDefaultErrorBoundaryProps {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
/** Custom fallback component to render on error */
|
|
12
|
+
fallback?: React.ReactNode;
|
|
13
|
+
/** Callback when an error is caught */
|
|
14
|
+
onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface DashDefaultErrorBoundaryState {
|
|
18
|
+
hasError: boolean;
|
|
19
|
+
error?: Error;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default error display component
|
|
24
|
+
*/
|
|
25
|
+
const DefaultErrorDisplay: React.FC<{ error?: Error; onReload: () => void }> = ({
|
|
26
|
+
error,
|
|
27
|
+
onReload
|
|
28
|
+
}) => (
|
|
29
|
+
<div style={{
|
|
30
|
+
display: 'flex',
|
|
31
|
+
justifyContent: 'center',
|
|
32
|
+
alignItems: 'center',
|
|
33
|
+
height: '100vh',
|
|
34
|
+
backgroundColor: '#121212',
|
|
35
|
+
color: '#ffffff',
|
|
36
|
+
flexDirection: 'column',
|
|
37
|
+
gap: '20px'
|
|
38
|
+
}}>
|
|
39
|
+
<h2>Something went wrong</h2>
|
|
40
|
+
{error && (
|
|
41
|
+
<p style={{
|
|
42
|
+
color: '#ff6b6b',
|
|
43
|
+
maxWidth: '600px',
|
|
44
|
+
textAlign: 'center',
|
|
45
|
+
padding: '0 20px'
|
|
46
|
+
}}>
|
|
47
|
+
{error.message}
|
|
48
|
+
</p>
|
|
49
|
+
)}
|
|
50
|
+
<button
|
|
51
|
+
onClick={onReload}
|
|
52
|
+
style={{
|
|
53
|
+
padding: '10px 20px',
|
|
54
|
+
backgroundColor: '#007bff',
|
|
55
|
+
color: 'white',
|
|
56
|
+
border: 'none',
|
|
57
|
+
borderRadius: '4px',
|
|
58
|
+
cursor: 'pointer'
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
Reload Page
|
|
62
|
+
</button>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Dash Default Error boundary for catching and handling React component errors
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```tsx
|
|
71
|
+
* <DashDefaultErrorBoundary onError={(error) => logError(error)}>
|
|
72
|
+
* <App />
|
|
73
|
+
* </DashDefaultErrorBoundary>
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export class DashDefaultErrorBoundary extends React.Component<DashDefaultErrorBoundaryProps, DashDefaultErrorBoundaryState> {
|
|
77
|
+
constructor(props: DashDefaultErrorBoundaryProps) {
|
|
78
|
+
super(props);
|
|
79
|
+
this.state = { hasError: false };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static getDerivedStateFromError(error: Error): DashDefaultErrorBoundaryState {
|
|
83
|
+
return { hasError: true, error };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
|
|
87
|
+
console.error('DashDefaultErrorBoundary caught an error:', error, errorInfo);
|
|
88
|
+
this.props.onError?.(error, errorInfo);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
handleReload = (): void => {
|
|
92
|
+
window.location.reload();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
render(): React.ReactNode {
|
|
96
|
+
if (this.state.hasError) {
|
|
97
|
+
if (this.props.fallback) {
|
|
98
|
+
return this.props.fallback;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<DefaultErrorDisplay
|
|
103
|
+
error={this.state.error}
|
|
104
|
+
onReload={this.handleReload}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return this.props.children;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default DashDefaultErrorBoundary;
|