@qwickapps/server 1.3.0 → 1.4.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 (241) hide show
  1. package/README.md +311 -0
  2. package/dist/core/control-panel.d.ts.map +1 -1
  3. package/dist/core/control-panel.js +144 -2
  4. package/dist/core/control-panel.js.map +1 -1
  5. package/dist/core/plugin-registry.d.ts +36 -0
  6. package/dist/core/plugin-registry.d.ts.map +1 -1
  7. package/dist/core/plugin-registry.js +26 -0
  8. package/dist/core/plugin-registry.js.map +1 -1
  9. package/dist/core/types.d.ts +19 -0
  10. package/dist/core/types.d.ts.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +4 -2
  14. package/dist/index.js.map +1 -1
  15. package/dist/plugins/auth/adapter-wrapper.d.ts +47 -0
  16. package/dist/plugins/auth/adapter-wrapper.d.ts.map +1 -0
  17. package/dist/plugins/auth/adapter-wrapper.js +166 -0
  18. package/dist/plugins/auth/adapter-wrapper.js.map +1 -0
  19. package/dist/plugins/auth/adapter-wrapper.test.d.ts +7 -0
  20. package/dist/plugins/auth/adapter-wrapper.test.d.ts.map +1 -0
  21. package/dist/plugins/auth/adapter-wrapper.test.js +303 -0
  22. package/dist/plugins/auth/adapter-wrapper.test.js.map +1 -0
  23. package/dist/plugins/auth/adapters/index.d.ts +1 -0
  24. package/dist/plugins/auth/adapters/index.d.ts.map +1 -1
  25. package/dist/plugins/auth/adapters/index.js +1 -0
  26. package/dist/plugins/auth/adapters/index.js.map +1 -1
  27. package/dist/plugins/auth/adapters/supabase-adapter.d.ts.map +1 -1
  28. package/dist/plugins/auth/adapters/supabase-adapter.js.map +1 -1
  29. package/dist/plugins/auth/adapters/supertokens-adapter.d.ts +18 -0
  30. package/dist/plugins/auth/adapters/supertokens-adapter.d.ts.map +1 -0
  31. package/dist/plugins/auth/adapters/supertokens-adapter.js +267 -0
  32. package/dist/plugins/auth/adapters/supertokens-adapter.js.map +1 -0
  33. package/dist/plugins/auth/config-store.d.ts +11 -0
  34. package/dist/plugins/auth/config-store.d.ts.map +1 -0
  35. package/dist/plugins/auth/config-store.js +232 -0
  36. package/dist/plugins/auth/config-store.js.map +1 -0
  37. package/dist/plugins/auth/config-store.test.d.ts +7 -0
  38. package/dist/plugins/auth/config-store.test.d.ts.map +1 -0
  39. package/dist/plugins/auth/config-store.test.js +299 -0
  40. package/dist/plugins/auth/config-store.test.js.map +1 -0
  41. package/dist/plugins/auth/env-config.d.ts +138 -0
  42. package/dist/plugins/auth/env-config.d.ts.map +1 -0
  43. package/dist/plugins/auth/env-config.js +1122 -0
  44. package/dist/plugins/auth/env-config.js.map +1 -0
  45. package/dist/plugins/auth/index.d.ts +7 -1
  46. package/dist/plugins/auth/index.d.ts.map +1 -1
  47. package/dist/plugins/auth/index.js +7 -0
  48. package/dist/plugins/auth/index.js.map +1 -1
  49. package/dist/plugins/auth/supertokens-adapter.test.d.ts +10 -0
  50. package/dist/plugins/auth/supertokens-adapter.test.d.ts.map +1 -0
  51. package/dist/plugins/auth/supertokens-adapter.test.js +486 -0
  52. package/dist/plugins/auth/supertokens-adapter.test.js.map +1 -0
  53. package/dist/plugins/auth/types.d.ts +176 -0
  54. package/dist/plugins/auth/types.d.ts.map +1 -1
  55. package/dist/plugins/auth/types.js.map +1 -1
  56. package/dist/plugins/cache-plugin.test.js +3 -0
  57. package/dist/plugins/cache-plugin.test.js.map +1 -1
  58. package/dist/plugins/index.d.ts +6 -2
  59. package/dist/plugins/index.d.ts.map +1 -1
  60. package/dist/plugins/index.js +5 -1
  61. package/dist/plugins/index.js.map +1 -1
  62. package/dist/plugins/postgres-plugin.test.js +3 -0
  63. package/dist/plugins/postgres-plugin.test.js.map +1 -1
  64. package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts +7 -0
  65. package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts.map +1 -0
  66. package/dist/plugins/preferences/__tests__/deep-merge.test.js +215 -0
  67. package/dist/plugins/preferences/__tests__/deep-merge.test.js.map +1 -0
  68. package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts +7 -0
  69. package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts.map +1 -0
  70. package/dist/plugins/preferences/__tests__/preferences-plugin.test.js +265 -0
  71. package/dist/plugins/preferences/__tests__/preferences-plugin.test.js.map +1 -0
  72. package/dist/plugins/preferences/index.d.ts +12 -0
  73. package/dist/plugins/preferences/index.d.ts.map +1 -0
  74. package/dist/plugins/preferences/index.js +13 -0
  75. package/dist/plugins/preferences/index.js.map +1 -0
  76. package/dist/plugins/preferences/preferences-plugin.d.ts +39 -0
  77. package/dist/plugins/preferences/preferences-plugin.d.ts.map +1 -0
  78. package/dist/plugins/preferences/preferences-plugin.js +226 -0
  79. package/dist/plugins/preferences/preferences-plugin.js.map +1 -0
  80. package/dist/plugins/preferences/stores/index.d.ts +9 -0
  81. package/dist/plugins/preferences/stores/index.d.ts.map +1 -0
  82. package/dist/plugins/preferences/stores/index.js +9 -0
  83. package/dist/plugins/preferences/stores/index.js.map +1 -0
  84. package/dist/plugins/preferences/stores/postgres-store.d.ts +41 -0
  85. package/dist/plugins/preferences/stores/postgres-store.d.ts.map +1 -0
  86. package/dist/plugins/preferences/stores/postgres-store.js +181 -0
  87. package/dist/plugins/preferences/stores/postgres-store.js.map +1 -0
  88. package/dist/plugins/preferences/types.d.ts +91 -0
  89. package/dist/plugins/preferences/types.d.ts.map +1 -0
  90. package/dist/plugins/preferences/types.js +10 -0
  91. package/dist/plugins/preferences/types.js.map +1 -0
  92. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts +7 -0
  93. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts.map +1 -0
  94. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js +220 -0
  95. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js.map +1 -0
  96. package/dist/plugins/rate-limit/cleanup.d.ts +40 -0
  97. package/dist/plugins/rate-limit/cleanup.d.ts.map +1 -0
  98. package/dist/plugins/rate-limit/cleanup.js +72 -0
  99. package/dist/plugins/rate-limit/cleanup.js.map +1 -0
  100. package/dist/plugins/rate-limit/env-config.d.ts +91 -0
  101. package/dist/plugins/rate-limit/env-config.d.ts.map +1 -0
  102. package/dist/plugins/rate-limit/env-config.js +318 -0
  103. package/dist/plugins/rate-limit/env-config.js.map +1 -0
  104. package/dist/plugins/rate-limit/index.d.ts +76 -0
  105. package/dist/plugins/rate-limit/index.d.ts.map +1 -0
  106. package/dist/plugins/rate-limit/index.js +79 -0
  107. package/dist/plugins/rate-limit/index.js.map +1 -0
  108. package/dist/plugins/rate-limit/middleware.d.ts +40 -0
  109. package/dist/plugins/rate-limit/middleware.d.ts.map +1 -0
  110. package/dist/plugins/rate-limit/middleware.js +169 -0
  111. package/dist/plugins/rate-limit/middleware.js.map +1 -0
  112. package/dist/plugins/rate-limit/rate-limit-plugin.d.ts +44 -0
  113. package/dist/plugins/rate-limit/rate-limit-plugin.d.ts.map +1 -0
  114. package/dist/plugins/rate-limit/rate-limit-plugin.js +354 -0
  115. package/dist/plugins/rate-limit/rate-limit-plugin.js.map +1 -0
  116. package/dist/plugins/rate-limit/rate-limit-service.d.ts +110 -0
  117. package/dist/plugins/rate-limit/rate-limit-service.d.ts.map +1 -0
  118. package/dist/plugins/rate-limit/rate-limit-service.js +172 -0
  119. package/dist/plugins/rate-limit/rate-limit-service.js.map +1 -0
  120. package/dist/plugins/rate-limit/stores/cache-store.d.ts +33 -0
  121. package/dist/plugins/rate-limit/stores/cache-store.d.ts.map +1 -0
  122. package/dist/plugins/rate-limit/stores/cache-store.js +225 -0
  123. package/dist/plugins/rate-limit/stores/cache-store.js.map +1 -0
  124. package/dist/plugins/rate-limit/stores/index.d.ts +8 -0
  125. package/dist/plugins/rate-limit/stores/index.d.ts.map +1 -0
  126. package/dist/plugins/rate-limit/stores/index.js +8 -0
  127. package/dist/plugins/rate-limit/stores/index.js.map +1 -0
  128. package/dist/plugins/rate-limit/stores/postgres-store.d.ts +34 -0
  129. package/dist/plugins/rate-limit/stores/postgres-store.d.ts.map +1 -0
  130. package/dist/plugins/rate-limit/stores/postgres-store.js +320 -0
  131. package/dist/plugins/rate-limit/stores/postgres-store.js.map +1 -0
  132. package/dist/plugins/rate-limit/strategies/fixed-window.d.ts +21 -0
  133. package/dist/plugins/rate-limit/strategies/fixed-window.d.ts.map +1 -0
  134. package/dist/plugins/rate-limit/strategies/fixed-window.js +97 -0
  135. package/dist/plugins/rate-limit/strategies/fixed-window.js.map +1 -0
  136. package/dist/plugins/rate-limit/strategies/index.d.ts +14 -0
  137. package/dist/plugins/rate-limit/strategies/index.d.ts.map +1 -0
  138. package/dist/plugins/rate-limit/strategies/index.js +27 -0
  139. package/dist/plugins/rate-limit/strategies/index.js.map +1 -0
  140. package/dist/plugins/rate-limit/strategies/sliding-window.d.ts +22 -0
  141. package/dist/plugins/rate-limit/strategies/sliding-window.d.ts.map +1 -0
  142. package/dist/plugins/rate-limit/strategies/sliding-window.js +122 -0
  143. package/dist/plugins/rate-limit/strategies/sliding-window.js.map +1 -0
  144. package/dist/plugins/rate-limit/strategies/token-bucket.d.ts +28 -0
  145. package/dist/plugins/rate-limit/strategies/token-bucket.d.ts.map +1 -0
  146. package/dist/plugins/rate-limit/strategies/token-bucket.js +121 -0
  147. package/dist/plugins/rate-limit/strategies/token-bucket.js.map +1 -0
  148. package/dist/plugins/rate-limit/types.d.ts +265 -0
  149. package/dist/plugins/rate-limit/types.d.ts.map +1 -0
  150. package/dist/plugins/rate-limit/types.js +9 -0
  151. package/dist/plugins/rate-limit/types.js.map +1 -0
  152. package/dist/plugins/users/__tests__/users-plugin.test.d.ts +9 -0
  153. package/dist/plugins/users/__tests__/users-plugin.test.d.ts.map +1 -0
  154. package/dist/plugins/users/__tests__/users-plugin.test.js +546 -0
  155. package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -0
  156. package/dist/plugins/users/index.d.ts +2 -2
  157. package/dist/plugins/users/index.d.ts.map +1 -1
  158. package/dist/plugins/users/index.js +1 -1
  159. package/dist/plugins/users/index.js.map +1 -1
  160. package/dist/plugins/users/types.d.ts +36 -0
  161. package/dist/plugins/users/types.d.ts.map +1 -1
  162. package/dist/plugins/users/users-plugin.d.ts +8 -2
  163. package/dist/plugins/users/users-plugin.d.ts.map +1 -1
  164. package/dist/plugins/users/users-plugin.js +122 -5
  165. package/dist/plugins/users/users-plugin.js.map +1 -1
  166. package/dist-ui/assets/index-D7DoZ9rL.js +478 -0
  167. package/dist-ui/assets/index-D7DoZ9rL.js.map +1 -0
  168. package/dist-ui/index.html +1 -1
  169. package/dist-ui-lib/api/controlPanelApi.d.ts +194 -7
  170. package/dist-ui-lib/dashboard/WidgetComponentRegistry.d.ts +9 -5
  171. package/dist-ui-lib/dashboard/builtInWidgets.d.ts +7 -1
  172. package/dist-ui-lib/dashboard/widgets/AuthStatusWidget.d.ts +9 -0
  173. package/dist-ui-lib/dashboard/widgets/IntegrationStatusWidget.d.ts +9 -0
  174. package/dist-ui-lib/dashboard/widgets/index.d.ts +2 -0
  175. package/dist-ui-lib/index.js +3665 -3945
  176. package/dist-ui-lib/index.js.map +1 -1
  177. package/dist-ui-lib/pages/AuthPage.d.ts +1 -0
  178. package/dist-ui-lib/pages/IntegrationsPage.d.ts +1 -0
  179. package/dist-ui-lib/pages/PluginsPage.d.ts +1 -0
  180. package/dist-ui-lib/pages/RateLimitPage.d.ts +1 -0
  181. package/package.json +7 -2
  182. package/src/core/control-panel.ts +161 -2
  183. package/src/core/plugin-registry.ts +63 -0
  184. package/src/core/types.ts +17 -0
  185. package/src/index.ts +45 -0
  186. package/src/plugins/auth/adapter-wrapper.test.ts +395 -0
  187. package/src/plugins/auth/adapter-wrapper.ts +205 -0
  188. package/src/plugins/auth/adapters/index.ts +1 -0
  189. package/src/plugins/auth/adapters/supabase-adapter.ts +22 -14
  190. package/src/plugins/auth/adapters/supertokens-adapter.ts +326 -0
  191. package/src/plugins/auth/config-store.test.ts +417 -0
  192. package/src/plugins/auth/config-store.ts +305 -0
  193. package/src/plugins/auth/env-config.ts +1279 -0
  194. package/src/plugins/auth/index.ts +30 -0
  195. package/src/plugins/auth/supertokens-adapter.test.ts +621 -0
  196. package/src/plugins/auth/types.ts +218 -0
  197. package/src/plugins/cache-plugin.test.ts +3 -0
  198. package/src/plugins/index.ts +75 -0
  199. package/src/plugins/postgres-plugin.test.ts +3 -0
  200. package/src/plugins/preferences/__tests__/deep-merge.test.ts +242 -0
  201. package/src/plugins/preferences/__tests__/preferences-plugin.test.ts +350 -0
  202. package/src/plugins/preferences/index.ts +30 -0
  203. package/src/plugins/preferences/preferences-plugin.ts +270 -0
  204. package/src/plugins/preferences/stores/index.ts +9 -0
  205. package/src/plugins/preferences/stores/postgres-store.ts +252 -0
  206. package/src/plugins/preferences/types.ts +100 -0
  207. package/src/plugins/rate-limit/__tests__/rate-limit-plugin.test.ts +259 -0
  208. package/src/plugins/rate-limit/cleanup.ts +117 -0
  209. package/src/plugins/rate-limit/env-config.ts +400 -0
  210. package/src/plugins/rate-limit/index.ts +128 -0
  211. package/src/plugins/rate-limit/middleware.ts +212 -0
  212. package/src/plugins/rate-limit/rate-limit-plugin.ts +400 -0
  213. package/src/plugins/rate-limit/rate-limit-service.ts +228 -0
  214. package/src/plugins/rate-limit/stores/cache-store.ts +261 -0
  215. package/src/plugins/rate-limit/stores/index.ts +8 -0
  216. package/src/plugins/rate-limit/stores/postgres-store.ts +402 -0
  217. package/src/plugins/rate-limit/strategies/fixed-window.ts +116 -0
  218. package/src/plugins/rate-limit/strategies/index.ts +30 -0
  219. package/src/plugins/rate-limit/strategies/sliding-window.ts +157 -0
  220. package/src/plugins/rate-limit/strategies/token-bucket.ts +154 -0
  221. package/src/plugins/rate-limit/types.ts +338 -0
  222. package/src/plugins/users/__tests__/users-plugin.test.ts +690 -0
  223. package/src/plugins/users/index.ts +3 -0
  224. package/src/plugins/users/types.ts +38 -0
  225. package/src/plugins/users/users-plugin.ts +142 -5
  226. package/ui/src/App.tsx +35 -14
  227. package/ui/src/api/controlPanelApi.ts +326 -1
  228. package/ui/src/components/ControlPanelApp.tsx +3 -0
  229. package/ui/src/dashboard/PluginWidgetRenderer.tsx +13 -10
  230. package/ui/src/dashboard/WidgetComponentRegistry.tsx +13 -9
  231. package/ui/src/dashboard/builtInWidgets.tsx +13 -3
  232. package/ui/src/dashboard/widgets/AuthStatusWidget.tsx +143 -0
  233. package/ui/src/dashboard/widgets/IntegrationStatusWidget.tsx +135 -0
  234. package/ui/src/dashboard/widgets/index.ts +2 -0
  235. package/ui/src/pages/AuthPage.tsx +1103 -0
  236. package/ui/src/pages/IntegrationsPage.tsx +288 -0
  237. package/ui/src/pages/PluginsPage.tsx +394 -0
  238. package/ui/src/pages/RateLimitPage.tsx +292 -0
  239. package/ui/vite.lib.config.ts +5 -0
  240. package/dist-ui/assets/index-Bsp2ntcw.js +0 -465
  241. package/dist-ui/assets/index-Bsp2ntcw.js.map +0 -1
@@ -36,6 +36,7 @@ import { defaultConfig } from '../config/AppConfig';
36
36
  import { DashboardPage } from '../pages/DashboardPage';
37
37
  import { LogsPage } from '../pages/LogsPage';
38
38
  import { SystemPage } from '../pages/SystemPage';
39
+ import { AuthPage } from '../pages/AuthPage';
39
40
  import { NotFoundPage } from '../pages/NotFoundPage';
40
41
 
41
42
  // Dashboard widget system
@@ -122,6 +123,7 @@ function getBaseNavigationItems(): MenuItem[] {
122
123
  return [
123
124
  { id: 'dashboard', label: 'Dashboard', route: '/', icon: 'dashboard' },
124
125
  { id: 'logs', label: 'Logs', route: '/logs', icon: 'article' },
126
+ { id: 'auth', label: 'Auth', route: '/auth', icon: 'lock' },
125
127
  { id: 'system', label: 'System', route: '/system', icon: 'settings' },
126
128
  ];
127
129
  }
@@ -192,6 +194,7 @@ export function ControlPanelApp({
192
194
  <>
193
195
  {!hideBaseNavItems.includes('dashboard') && <Route path="/" element={<DashboardPage />} />}
194
196
  {!hideBaseNavItems.includes('logs') && <Route path="/logs" element={<LogsPage />} />}
197
+ {!hideBaseNavItems.includes('auth') && <Route path="/auth" element={<AuthPage />} />}
195
198
  {!hideBaseNavItems.includes('system') && <Route path="/system" element={<SystemPage />} />}
196
199
  </>
197
200
  )}
@@ -100,16 +100,19 @@ export function PluginWidgetRenderer({
100
100
 
101
101
  return (
102
102
  <>
103
- {visibleWidgets.map(widget => (
104
- <Box key={widget.id} sx={{ mt: 4 }}>
105
- {widget.title && (
106
- <Typography variant="h6" sx={{ mb: 2, color: 'var(--theme-text-primary)' }}>
107
- {widget.title}
108
- </Typography>
109
- )}
110
- {getComponent(widget.component)}
111
- </Box>
112
- ))}
103
+ {visibleWidgets.map(widget => {
104
+ const Component = getComponent(widget.component);
105
+ return (
106
+ <Box key={widget.id} sx={{ mt: 4 }}>
107
+ {widget.title && (
108
+ <Typography variant="h6" sx={{ mb: 2, color: 'var(--theme-text-primary)' }}>
109
+ {widget.title}
110
+ </Typography>
111
+ )}
112
+ {Component && <Component />}
113
+ </Box>
114
+ );
115
+ })}
113
116
  </>
114
117
  );
115
118
  }
@@ -7,25 +7,29 @@
7
7
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
8
  */
9
9
 
10
- import { ReactNode, createContext, useContext, useState, useCallback, useMemo } from 'react';
10
+ import React, { createContext, useContext, useState, useCallback, useMemo, type ReactNode } from 'react';
11
11
 
12
12
  /**
13
13
  * Widget component definition
14
+ *
15
+ * IMPORTANT: We store component functions (ComponentType), not JSX instances (ReactNode).
16
+ * This ensures cross-React-version compatibility when the library is used in apps
17
+ * with different React versions.
14
18
  */
15
19
  export interface WidgetComponent {
16
20
  /** Component name (must match server-side WidgetContribution.component) */
17
21
  name: string;
18
- /** The React component to render */
19
- component: ReactNode;
22
+ /** The React component function to render */
23
+ component: React.ComponentType;
20
24
  }
21
25
 
22
26
  interface WidgetComponentRegistryContextValue {
23
27
  /** Register a widget component */
24
- registerComponent: (name: string, component: ReactNode) => void;
28
+ registerComponent: (name: string, component: React.ComponentType) => void;
25
29
  /** Register multiple widget components */
26
30
  registerComponents: (components: WidgetComponent[]) => void;
27
31
  /** Get a component by name */
28
- getComponent: (name: string) => ReactNode | null;
32
+ getComponent: (name: string) => React.ComponentType | null;
29
33
  /** Check if a component is registered */
30
34
  hasComponent: (name: string) => boolean;
31
35
  /** Get all registered component names */
@@ -47,15 +51,15 @@ export function WidgetComponentRegistryProvider({
47
51
  initialComponents = [],
48
52
  children,
49
53
  }: WidgetComponentRegistryProviderProps) {
50
- const [components, setComponents] = useState<Map<string, ReactNode>>(() => {
51
- const map = new Map<string, ReactNode>();
54
+ const [components, setComponents] = useState<Map<string, React.ComponentType>>(() => {
55
+ const map = new Map<string, React.ComponentType>();
52
56
  for (const comp of initialComponents) {
53
57
  map.set(comp.name, comp.component);
54
58
  }
55
59
  return map;
56
60
  });
57
61
 
58
- const registerComponent = useCallback((name: string, component: ReactNode) => {
62
+ const registerComponent = useCallback((name: string, component: React.ComponentType) => {
59
63
  setComponents(prev => {
60
64
  const next = new Map(prev);
61
65
  next.set(name, component);
@@ -73,7 +77,7 @@ export function WidgetComponentRegistryProvider({
73
77
  });
74
78
  }, []);
75
79
 
76
- const getComponent = useCallback((name: string): ReactNode | null => {
80
+ const getComponent = useCallback((name: string): React.ComponentType | null => {
77
81
  return components.get(name) ?? null;
78
82
  }, [components]);
79
83
 
@@ -4,10 +4,13 @@
4
4
  * Maps built-in widget component names to their React components.
5
5
  * These are the widgets that qwickapps-server provides out of the box.
6
6
  *
7
+ * IMPORTANT: We export component functions, not JSX instances.
8
+ * This ensures cross-React-version compatibility.
9
+ *
7
10
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
11
  */
9
12
 
10
- import { ServiceHealthWidget } from './widgets';
13
+ import { ServiceHealthWidget, IntegrationStatusWidget, AuthStatusWidget } from './widgets';
11
14
  import type { WidgetComponent } from './WidgetComponentRegistry';
12
15
 
13
16
  /**
@@ -16,14 +19,21 @@ import type { WidgetComponent } from './WidgetComponentRegistry';
16
19
  */
17
20
  export const builtInWidgetComponents: Record<string, React.ComponentType> = {
18
21
  ServiceHealthWidget: ServiceHealthWidget,
22
+ IntegrationStatusWidget: IntegrationStatusWidget,
23
+ AuthStatusWidget: AuthStatusWidget,
19
24
  };
20
25
 
21
26
  /**
22
- * Get built-in widget components as WidgetComponent array with JSX elements.
27
+ * Get built-in widget components as WidgetComponent array.
23
28
  * Use this when registering with WidgetComponentRegistryProvider.
29
+ *
30
+ * Returns component functions (not JSX instances) to ensure compatibility
31
+ * across different React versions.
24
32
  */
25
33
  export function getBuiltInWidgetComponents(): WidgetComponent[] {
26
34
  return [
27
- { name: 'ServiceHealthWidget', component: <ServiceHealthWidget /> },
35
+ { name: 'ServiceHealthWidget', component: ServiceHealthWidget },
36
+ { name: 'IntegrationStatusWidget', component: IntegrationStatusWidget },
37
+ { name: 'AuthStatusWidget', component: AuthStatusWidget },
28
38
  ];
29
39
  }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Auth Status Widget
3
+ *
4
+ * Displays the authentication plugin status on the dashboard.
5
+ * Shows whether auth is enabled, the adapter type, and configuration status.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ import { useState, useEffect } from 'react';
11
+ import { Box, Typography, Chip, CircularProgress, Alert } from '@mui/material';
12
+ import CheckCircleIcon from '@mui/icons-material/CheckCircle';
13
+ import ErrorIcon from '@mui/icons-material/Error';
14
+ import BlockIcon from '@mui/icons-material/Block';
15
+ import { api } from '../../api/controlPanelApi';
16
+
17
+ interface AuthStatus {
18
+ state: 'enabled' | 'disabled' | 'error';
19
+ adapter: string | null;
20
+ error?: string;
21
+ missingVars?: string[];
22
+ }
23
+
24
+ const adapterLabels: Record<string, string> = {
25
+ supertokens: 'SuperTokens',
26
+ auth0: 'Auth0',
27
+ supabase: 'Supabase',
28
+ basic: 'Basic Auth',
29
+ };
30
+
31
+ export function AuthStatusWidget() {
32
+ const [status, setStatus] = useState<AuthStatus | null>(null);
33
+ const [loading, setLoading] = useState(true);
34
+ const [error, setError] = useState<string | null>(null);
35
+
36
+ useEffect(() => {
37
+ const fetchStatus = async () => {
38
+ try {
39
+ const data = await api.fetch<AuthStatus>('/auth/config/status');
40
+ setStatus(data);
41
+ } catch (err) {
42
+ setError(err instanceof Error ? err.message : 'Failed to fetch auth status');
43
+ } finally {
44
+ setLoading(false);
45
+ }
46
+ };
47
+
48
+ fetchStatus();
49
+ }, []);
50
+
51
+ if (loading) {
52
+ return (
53
+ <Box sx={{ display: 'flex', justifyContent: 'center', py: 2 }}>
54
+ <CircularProgress size={20} />
55
+ </Box>
56
+ );
57
+ }
58
+
59
+ if (error) {
60
+ return (
61
+ <Alert severity="warning" sx={{ py: 0.5, fontSize: 13 }}>
62
+ Unable to load auth status
63
+ </Alert>
64
+ );
65
+ }
66
+
67
+ if (!status) return null;
68
+
69
+ const getStateIcon = () => {
70
+ switch (status.state) {
71
+ case 'enabled':
72
+ return <CheckCircleIcon sx={{ color: 'var(--theme-success)', fontSize: 32 }} />;
73
+ case 'error':
74
+ return <ErrorIcon sx={{ color: 'var(--theme-error)', fontSize: 32 }} />;
75
+ case 'disabled':
76
+ default:
77
+ return <BlockIcon sx={{ color: 'var(--theme-text-secondary)', fontSize: 32 }} />;
78
+ }
79
+ };
80
+
81
+ const getStateColor = () => {
82
+ switch (status.state) {
83
+ case 'enabled':
84
+ return 'var(--theme-success)';
85
+ case 'error':
86
+ return 'var(--theme-error)';
87
+ case 'disabled':
88
+ default:
89
+ return 'var(--theme-text-secondary)';
90
+ }
91
+ };
92
+
93
+ return (
94
+ <Box
95
+ sx={{
96
+ bgcolor: 'var(--theme-surface)',
97
+ borderRadius: 2,
98
+ p: 2,
99
+ border: '1px solid var(--theme-border)',
100
+ }}
101
+ >
102
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
103
+ {getStateIcon()}
104
+ <Box sx={{ flex: 1 }}>
105
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5 }}>
106
+ <Typography variant="subtitle1" sx={{ color: 'var(--theme-text-primary)', fontWeight: 600 }}>
107
+ {status.state === 'enabled' && status.adapter
108
+ ? adapterLabels[status.adapter] || status.adapter
109
+ : status.state === 'disabled'
110
+ ? 'Not Configured'
111
+ : 'Configuration Error'}
112
+ </Typography>
113
+ <Chip
114
+ label={status.state.toUpperCase()}
115
+ size="small"
116
+ sx={{
117
+ bgcolor: `${getStateColor()}20`,
118
+ color: getStateColor(),
119
+ fontWeight: 600,
120
+ fontSize: 10,
121
+ height: 20,
122
+ }}
123
+ />
124
+ </Box>
125
+ <Typography variant="body2" sx={{ color: 'var(--theme-text-secondary)' }}>
126
+ {status.state === 'enabled'
127
+ ? 'Authentication is active'
128
+ : status.state === 'disabled'
129
+ ? 'Set AUTH_ADAPTER environment variable'
130
+ : status.error || 'Check configuration'}
131
+ </Typography>
132
+ </Box>
133
+ </Box>
134
+
135
+ {/* Missing vars warning */}
136
+ {status.missingVars && status.missingVars.length > 0 && (
137
+ <Alert severity="warning" sx={{ mt: 2, py: 0.5, '& .MuiAlert-message': { fontSize: 12 } }}>
138
+ Missing: {status.missingVars.join(', ')}
139
+ </Alert>
140
+ )}
141
+ </Box>
142
+ );
143
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Integration Status Widget
3
+ *
4
+ * Displays the status of configured integrations with their connection status.
5
+ * Used in the dashboard to show a quick overview of integration health.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ import { useState, useEffect } from 'react';
11
+ import { Box, Typography, Chip, CircularProgress, Alert } from '@mui/material';
12
+ import CheckCircleIcon from '@mui/icons-material/CheckCircle';
13
+ import ErrorIcon from '@mui/icons-material/Error';
14
+ import { api } from '../../api/controlPanelApi';
15
+
16
+ interface Integration {
17
+ id: string;
18
+ name: string;
19
+ description: string;
20
+ configured: boolean;
21
+ }
22
+
23
+ interface IntegrationsConfig {
24
+ integrations: Integration[];
25
+ stats: {
26
+ totalRequests: number;
27
+ };
28
+ }
29
+
30
+ export function IntegrationStatusWidget() {
31
+ const [config, setConfig] = useState<IntegrationsConfig | null>(null);
32
+ const [loading, setLoading] = useState(true);
33
+ const [error, setError] = useState<string | null>(null);
34
+
35
+ useEffect(() => {
36
+ const fetchConfig = async () => {
37
+ try {
38
+ const data = await api.fetch<IntegrationsConfig>('/ai-proxy/config');
39
+ setConfig(data);
40
+ } catch (err) {
41
+ setError(err instanceof Error ? err.message : 'Failed to fetch integrations');
42
+ } finally {
43
+ setLoading(false);
44
+ }
45
+ };
46
+
47
+ fetchConfig();
48
+ }, []);
49
+
50
+ if (loading) {
51
+ return (
52
+ <Box sx={{ display: 'flex', justifyContent: 'center', py: 2 }}>
53
+ <CircularProgress size={20} />
54
+ </Box>
55
+ );
56
+ }
57
+
58
+ if (error) {
59
+ return (
60
+ <Alert severity="warning" sx={{ py: 0.5, fontSize: 13 }}>
61
+ Unable to load integrations
62
+ </Alert>
63
+ );
64
+ }
65
+
66
+ if (!config) return null;
67
+
68
+ const configuredCount = config.integrations.filter((i) => i.configured).length;
69
+ const totalCount = config.integrations.length;
70
+
71
+ return (
72
+ <Box
73
+ sx={{
74
+ bgcolor: 'var(--theme-surface)',
75
+ borderRadius: 2,
76
+ p: 2,
77
+ border: '1px solid var(--theme-border)',
78
+ }}
79
+ >
80
+ {/* Summary */}
81
+ <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
82
+ <Typography variant="subtitle2" sx={{ color: 'var(--theme-text-secondary)' }}>
83
+ {configuredCount} of {totalCount} configured
84
+ </Typography>
85
+ <Typography variant="subtitle2" sx={{ color: 'var(--theme-text-secondary)' }}>
86
+ {config.stats.totalRequests} requests
87
+ </Typography>
88
+ </Box>
89
+
90
+ {/* Integration List */}
91
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
92
+ {config.integrations.map((integration) => (
93
+ <Box
94
+ key={integration.id}
95
+ sx={{
96
+ display: 'flex',
97
+ alignItems: 'center',
98
+ justifyContent: 'space-between',
99
+ p: 1.5,
100
+ bgcolor: 'var(--theme-background)',
101
+ borderRadius: 1,
102
+ }}
103
+ >
104
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
105
+ {integration.configured ? (
106
+ <CheckCircleIcon sx={{ color: 'var(--theme-success)', fontSize: 18 }} />
107
+ ) : (
108
+ <ErrorIcon sx={{ color: 'var(--theme-text-secondary)', fontSize: 18 }} />
109
+ )}
110
+ <Box>
111
+ <Typography variant="body2" sx={{ color: 'var(--theme-text-primary)', fontWeight: 500 }}>
112
+ {integration.name}
113
+ </Typography>
114
+ <Typography variant="caption" sx={{ color: 'var(--theme-text-secondary)' }}>
115
+ {integration.description}
116
+ </Typography>
117
+ </Box>
118
+ </Box>
119
+ <Chip
120
+ label={integration.configured ? 'Connected' : 'Not Configured'}
121
+ size="small"
122
+ sx={{
123
+ bgcolor: integration.configured ? 'var(--theme-success)20' : 'transparent',
124
+ color: integration.configured ? 'var(--theme-success)' : 'var(--theme-text-secondary)',
125
+ border: integration.configured ? 'none' : '1px solid var(--theme-border)',
126
+ fontWeight: 500,
127
+ fontSize: 11,
128
+ }}
129
+ />
130
+ </Box>
131
+ ))}
132
+ </Box>
133
+ </Box>
134
+ );
135
+ }
@@ -5,3 +5,5 @@
5
5
  */
6
6
 
7
7
  export { ServiceHealthWidget } from './ServiceHealthWidget';
8
+ export { IntegrationStatusWidget } from './IntegrationStatusWidget';
9
+ export { AuthStatusWidget } from './AuthStatusWidget';