@revealui/core 0.2.0 → 0.3.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 (341) hide show
  1. package/README.md +137 -30
  2. package/dist/api/compression.d.ts.map +1 -1
  3. package/dist/api/payload-optimization.d.ts.map +1 -1
  4. package/dist/api/rate-limit.d.ts +30 -29
  5. package/dist/api/rate-limit.d.ts.map +1 -1
  6. package/dist/api/rate-limit.js +79 -4
  7. package/dist/api/response-cache.d.ts.map +1 -1
  8. package/dist/api/response-cache.js +1 -1
  9. package/dist/api/rest.d.ts.map +1 -1
  10. package/dist/api/rest.js +5 -4
  11. package/dist/auth/access.d.ts.map +1 -1
  12. package/dist/auth/index.d.ts.map +1 -1
  13. package/dist/cache/query-cache.d.ts +12 -10
  14. package/dist/cache/query-cache.d.ts.map +1 -1
  15. package/dist/cache/query-cache.js +38 -42
  16. package/dist/caching/app-cache.d.ts +5 -0
  17. package/dist/caching/app-cache.d.ts.map +1 -1
  18. package/dist/caching/app-cache.js +9 -1
  19. package/dist/caching/cdn-config.d.ts +2 -2
  20. package/dist/caching/cdn-config.d.ts.map +1 -1
  21. package/dist/caching/cdn-config.js +5 -15
  22. package/dist/caching/edge-cache.d.ts +1 -1
  23. package/dist/caching/edge-cache.d.ts.map +1 -1
  24. package/dist/caching/edge-cache.js +44 -11
  25. package/dist/caching/index.d.ts +6 -0
  26. package/dist/caching/index.d.ts.map +1 -0
  27. package/dist/caching/index.js +5 -0
  28. package/dist/caching/service-worker.d.ts +10 -18
  29. package/dist/caching/service-worker.d.ts.map +1 -1
  30. package/dist/caching/service-worker.js +5 -4
  31. package/dist/client/admin/RichText.d.ts +1 -1
  32. package/dist/client/admin/RichText.d.ts.map +1 -1
  33. package/dist/client/admin/components/AdminDashboard.d.ts.map +1 -1
  34. package/dist/client/admin/components/AdminDashboard.js +178 -205
  35. package/dist/client/admin/components/CollectionList.d.ts.map +1 -1
  36. package/dist/client/admin/components/DocumentForm.d.ts.map +1 -1
  37. package/dist/client/admin/components/DocumentForm.js +130 -6
  38. package/dist/client/admin/components/GlobalForm.d.ts.map +1 -1
  39. package/dist/client/admin/context/ServerFunctionContext.d.ts +8 -0
  40. package/dist/client/admin/context/ServerFunctionContext.d.ts.map +1 -0
  41. package/dist/client/admin/context/ServerFunctionContext.js +15 -0
  42. package/dist/client/admin/i18n/en.d.ts.map +1 -1
  43. package/dist/client/admin/index.d.ts +1 -0
  44. package/dist/client/admin/index.d.ts.map +1 -1
  45. package/dist/client/admin/index.js +1 -0
  46. package/dist/client/admin/layout.d.ts +1 -1
  47. package/dist/client/admin/layout.d.ts.map +1 -1
  48. package/dist/client/admin/layout.js +3 -2
  49. package/dist/client/admin/page.d.ts.map +1 -1
  50. package/dist/client/admin/utils/apiClient.d.ts.map +1 -1
  51. package/dist/client/admin/utils/apiClient.js +0 -4
  52. package/dist/client/admin/utils/auth.d.ts +0 -4
  53. package/dist/client/admin/utils/auth.d.ts.map +1 -1
  54. package/dist/client/admin/utils/auth.js +0 -6
  55. package/dist/client/admin/utils/index.d.ts +0 -1
  56. package/dist/client/admin/utils/index.d.ts.map +1 -1
  57. package/dist/client/admin/utils/index.js +0 -1
  58. package/dist/client/admin/utils/serializeConfig.d.ts.map +1 -1
  59. package/dist/client/hooks.d.ts.map +1 -1
  60. package/dist/client/index.d.ts +0 -1
  61. package/dist/client/index.d.ts.map +1 -1
  62. package/dist/client/index.js +0 -2
  63. package/dist/client/richtext/RichTextEditor.d.ts.map +1 -1
  64. package/dist/client/richtext/components/ImageNodeComponent.d.ts.map +1 -1
  65. package/dist/client/richtext/components/ImageNodeComponent.js +0 -1
  66. package/dist/client/richtext/components/ImageUploadButton.d.ts +2 -0
  67. package/dist/client/richtext/components/ImageUploadButton.d.ts.map +1 -1
  68. package/dist/client/richtext/components/ImageUploadButton.js +30 -15
  69. package/dist/client/richtext/index.d.ts.map +1 -1
  70. package/dist/client/richtext/nodes/DecoratorBlockNode.d.ts.map +1 -1
  71. package/dist/client/richtext/nodes/ImageNode.d.ts.map +1 -1
  72. package/dist/client/richtext/plugins/CollaborationPlugin.d.ts.map +1 -1
  73. package/dist/client/richtext/plugins/CursorsOverlayPlugin.d.ts.map +1 -1
  74. package/dist/client/richtext/plugins/FloatingToolbarPlugin.d.ts.map +1 -1
  75. package/dist/client/richtext/plugins/ImagePlugin.d.ts.map +1 -1
  76. package/dist/client/richtext/plugins/ToolbarPlugin.d.ts.map +1 -1
  77. package/dist/client/ui/index.d.ts.map +1 -1
  78. package/dist/client/ui/index.js +1 -1
  79. package/dist/collections/CollectionOperations.d.ts +7 -7
  80. package/dist/collections/CollectionOperations.d.ts.map +1 -1
  81. package/dist/collections/CollectionOperations.js +15 -1
  82. package/dist/collections/hooks.d.ts.map +1 -1
  83. package/dist/collections/index.d.ts.map +1 -1
  84. package/dist/collections/operations/create.d.ts +2 -4
  85. package/dist/collections/operations/create.d.ts.map +1 -1
  86. package/dist/collections/operations/create.js +9 -7
  87. package/dist/collections/operations/createMany.d.ts +12 -0
  88. package/dist/collections/operations/createMany.d.ts.map +1 -0
  89. package/dist/collections/operations/createMany.js +43 -0
  90. package/dist/collections/operations/delete.d.ts +1 -1
  91. package/dist/collections/operations/delete.d.ts.map +1 -1
  92. package/dist/collections/operations/delete.js +31 -2
  93. package/dist/collections/operations/deleteMany.d.ts +11 -0
  94. package/dist/collections/operations/deleteMany.d.ts.map +1 -0
  95. package/dist/collections/operations/deleteMany.js +50 -0
  96. package/dist/collections/operations/fieldHooks.d.ts +2 -2
  97. package/dist/collections/operations/fieldHooks.d.ts.map +1 -1
  98. package/dist/collections/operations/fieldHooks.js +4 -4
  99. package/dist/collections/operations/find.d.ts +2 -4
  100. package/dist/collections/operations/find.d.ts.map +1 -1
  101. package/dist/collections/operations/find.js +115 -8
  102. package/dist/collections/operations/findById.d.ts +3 -4
  103. package/dist/collections/operations/findById.d.ts.map +1 -1
  104. package/dist/collections/operations/findById.js +53 -1
  105. package/dist/collections/operations/sqlAdapter.d.ts +23 -0
  106. package/dist/collections/operations/sqlAdapter.d.ts.map +1 -0
  107. package/dist/collections/operations/sqlAdapter.js +76 -0
  108. package/dist/collections/operations/update.d.ts +3 -5
  109. package/dist/collections/operations/update.d.ts.map +1 -1
  110. package/dist/collections/operations/update.js +103 -11
  111. package/dist/collections/operations/updateMany.d.ts +11 -0
  112. package/dist/collections/operations/updateMany.d.ts.map +1 -0
  113. package/dist/collections/operations/updateMany.js +52 -0
  114. package/dist/collections/registry.d.ts +12 -0
  115. package/dist/collections/registry.d.ts.map +1 -0
  116. package/dist/collections/registry.js +38 -0
  117. package/dist/config/index.d.ts.map +1 -1
  118. package/dist/config/runtime.d.ts.map +1 -1
  119. package/dist/config/utils.d.ts +0 -10
  120. package/dist/config/utils.d.ts.map +1 -1
  121. package/dist/config/utils.js +18 -17
  122. package/dist/database/index.d.ts +3 -0
  123. package/dist/database/index.d.ts.map +1 -1
  124. package/dist/database/index.js +1 -5
  125. package/dist/database/safe-parse.d.ts +26 -0
  126. package/dist/database/safe-parse.d.ts.map +1 -0
  127. package/dist/database/safe-parse.js +42 -0
  128. package/dist/database/ssl-config.d.ts.map +1 -1
  129. package/dist/database/type-adapter.d.ts.map +1 -1
  130. package/dist/database/universal-postgres.d.ts.map +1 -1
  131. package/dist/database/universal-postgres.js +18 -13
  132. package/dist/dataloader.d.ts.map +1 -1
  133. package/dist/dataloader.js +16 -2
  134. package/dist/error-handling/circuit-breaker.d.ts +1 -1
  135. package/dist/error-handling/circuit-breaker.d.ts.map +1 -1
  136. package/dist/error-handling/circuit-breaker.js +11 -3
  137. package/dist/error-handling/error-boundary.d.ts.map +1 -1
  138. package/dist/error-handling/error-reporter.d.ts +6 -5
  139. package/dist/error-handling/error-reporter.d.ts.map +1 -1
  140. package/dist/error-handling/error-reporter.js +26 -41
  141. package/dist/error-handling/fallback-components.d.ts.map +1 -1
  142. package/dist/error-handling/fallback-components.js +1 -1
  143. package/dist/error-handling/index.d.ts +3 -5
  144. package/dist/error-handling/index.d.ts.map +1 -1
  145. package/dist/error-handling/index.js +2 -5
  146. package/dist/error-handling/retry.d.ts.map +1 -1
  147. package/dist/error-handling/retry.js +13 -8
  148. package/dist/factories/builders.d.ts.map +1 -1
  149. package/dist/factories/index.d.ts.map +1 -1
  150. package/dist/features.d.ts +5 -5
  151. package/dist/features.d.ts.map +1 -1
  152. package/dist/features.js +6 -5
  153. package/dist/fieldTraversal.d.ts.map +1 -1
  154. package/dist/fields/config/types.d.ts.map +1 -1
  155. package/dist/fields/getDefaultValue.d.ts.map +1 -1
  156. package/dist/fields/getFieldPaths.d.ts.map +1 -1
  157. package/dist/fields/hooks/afterRead/index.d.ts.map +1 -1
  158. package/dist/fields/hooks/afterRead/promise.d.ts.map +1 -1
  159. package/dist/fields/hooks/afterRead/traverseFields.d.ts.map +1 -1
  160. package/dist/generated/types/cms.d.ts.map +1 -1
  161. package/dist/generated/types/cms.js +0 -1
  162. package/dist/generated/types/index.d.ts +0 -3
  163. package/dist/generated/types/index.d.ts.map +1 -1
  164. package/dist/generated/types/index.js +0 -7
  165. package/dist/generated/types/neon.d.ts.map +1 -1
  166. package/dist/generated/types/neon.js +4 -2
  167. package/dist/globals/GlobalOperations.d.ts.map +1 -1
  168. package/dist/globals/GlobalOperations.js +4 -2
  169. package/dist/globals/index.d.ts.map +1 -1
  170. package/dist/index.d.ts +4 -4
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +4 -6
  173. package/dist/instance/RevealUIInstance.d.ts.map +1 -1
  174. package/dist/instance/RevealUIInstance.js +50 -69
  175. package/dist/instance/index.d.ts.map +1 -1
  176. package/dist/instance/logger.d.ts.map +1 -1
  177. package/dist/instance/methods/create.d.ts.map +1 -1
  178. package/dist/instance/methods/create.js +4 -4
  179. package/dist/instance/methods/delete.d.ts.map +1 -1
  180. package/dist/instance/methods/delete.js +5 -5
  181. package/dist/instance/methods/find.d.ts.map +1 -1
  182. package/dist/instance/methods/find.js +0 -3
  183. package/dist/instance/methods/findById.d.ts.map +1 -1
  184. package/dist/instance/methods/findById.js +0 -3
  185. package/dist/instance/methods/hooks.d.ts.map +1 -1
  186. package/dist/instance/methods/hooks.js +3 -1
  187. package/dist/instance/methods/update.d.ts.map +1 -1
  188. package/dist/instance/methods/update.js +4 -4
  189. package/dist/jobs/index.d.ts +16 -0
  190. package/dist/jobs/index.d.ts.map +1 -0
  191. package/dist/jobs/index.js +14 -0
  192. package/dist/jobs/queue.d.ts +57 -0
  193. package/dist/jobs/queue.d.ts.map +1 -0
  194. package/dist/jobs/queue.js +134 -0
  195. package/dist/license-encryption.d.ts +21 -0
  196. package/dist/license-encryption.d.ts.map +1 -0
  197. package/dist/license-encryption.js +74 -0
  198. package/dist/license.d.ts +33 -7
  199. package/dist/license.d.ts.map +1 -1
  200. package/dist/license.js +119 -16
  201. package/dist/monitoring/alerts.d.ts.map +1 -1
  202. package/dist/monitoring/cleanup-manager.d.ts.map +1 -1
  203. package/dist/monitoring/health-monitor.d.ts.map +1 -1
  204. package/dist/monitoring/index.d.ts.map +1 -1
  205. package/dist/monitoring/process-registry.d.ts.map +1 -1
  206. package/dist/monitoring/query-monitor.d.ts.map +1 -1
  207. package/dist/monitoring/types.d.ts.map +1 -1
  208. package/dist/monitoring/zombie-detector.d.ts.map +1 -1
  209. package/dist/monitoring/zombie-detector.js +5 -0
  210. package/dist/nextjs/index.d.ts.map +1 -1
  211. package/dist/nextjs/utilities.d.ts.map +1 -1
  212. package/dist/nextjs/withRevealUI.d.ts.map +1 -1
  213. package/dist/observability/alerts.d.ts.map +1 -1
  214. package/dist/observability/alerts.js +1 -2
  215. package/dist/observability/health-check.d.ts +1 -5
  216. package/dist/observability/health-check.d.ts.map +1 -1
  217. package/dist/observability/health-check.js +37 -43
  218. package/dist/observability/index.d.ts.map +1 -1
  219. package/dist/observability/logger.d.ts.map +1 -1
  220. package/dist/observability/logger.js +1 -1
  221. package/dist/observability/metrics.d.ts.map +1 -1
  222. package/dist/observability/tracing.d.ts.map +1 -1
  223. package/dist/observability/tracing.js +0 -1
  224. package/dist/optimization/asset-optimizer.d.ts +6 -2
  225. package/dist/optimization/asset-optimizer.d.ts.map +1 -1
  226. package/dist/optimization/asset-optimizer.js +31 -7
  227. package/dist/optimization/bundle-analyzer.d.ts +1 -1
  228. package/dist/optimization/bundle-analyzer.d.ts.map +1 -1
  229. package/dist/optimization/bundle-analyzer.js +29 -5
  230. package/dist/optimization/code-splitting.d.ts +0 -23
  231. package/dist/optimization/code-splitting.d.ts.map +1 -1
  232. package/dist/optimization/code-splitting.js +0 -29
  233. package/dist/plugins/form-builder.d.ts.map +1 -1
  234. package/dist/plugins/index.d.ts.map +1 -1
  235. package/dist/plugins/nested-docs.d.ts +4 -0
  236. package/dist/plugins/nested-docs.d.ts.map +1 -1
  237. package/dist/plugins/nested-docs.js +50 -5
  238. package/dist/plugins/redirects.d.ts.map +1 -1
  239. package/dist/queries/index.d.ts.map +1 -1
  240. package/dist/queries/queryBuilder.d.ts.map +1 -1
  241. package/dist/queries/queryBuilder.js +15 -5
  242. package/dist/relationships/analyzer.d.ts.map +1 -1
  243. package/dist/relationships/analyzer.js +8 -0
  244. package/dist/relationships/index.d.ts.map +1 -1
  245. package/dist/relationships/populate-core.d.ts +57 -0
  246. package/dist/relationships/populate-core.d.ts.map +1 -0
  247. package/dist/relationships/populate-core.js +116 -0
  248. package/dist/relationships/populate-helpers.d.ts +5 -51
  249. package/dist/relationships/populate-helpers.d.ts.map +1 -1
  250. package/dist/relationships/populate-helpers.js +4 -109
  251. package/dist/relationships/population.d.ts +1 -9
  252. package/dist/relationships/population.d.ts.map +1 -1
  253. package/dist/relationships/population.js +8 -3
  254. package/dist/revealui.d.ts.map +1 -1
  255. package/dist/richtext/exports/client/rcc.d.ts.map +1 -1
  256. package/dist/richtext/exports/client/rcc.js +1 -1
  257. package/dist/richtext/exports/server/rsc.d.ts +17 -0
  258. package/dist/richtext/exports/server/rsc.d.ts.map +1 -1
  259. package/dist/richtext/exports/server/rsc.js +61 -5
  260. package/dist/richtext/index.d.ts.map +1 -1
  261. package/dist/richtext/lexical.d.ts.map +1 -1
  262. package/dist/security/audit.d.ts +1 -1
  263. package/dist/security/audit.d.ts.map +1 -1
  264. package/dist/security/audit.js +4 -2
  265. package/dist/security/auth.d.ts +29 -160
  266. package/dist/security/auth.d.ts.map +1 -1
  267. package/dist/security/auth.js +150 -367
  268. package/dist/security/authorization.d.ts +7 -31
  269. package/dist/security/authorization.d.ts.map +1 -1
  270. package/dist/security/authorization.js +72 -14
  271. package/dist/security/encryption.d.ts +56 -44
  272. package/dist/security/encryption.d.ts.map +1 -1
  273. package/dist/security/encryption.js +128 -100
  274. package/dist/security/gdpr-storage.d.ts +102 -0
  275. package/dist/security/gdpr-storage.d.ts.map +1 -0
  276. package/dist/security/gdpr-storage.js +65 -0
  277. package/dist/security/gdpr.d.ts +57 -37
  278. package/dist/security/gdpr.d.ts.map +1 -1
  279. package/dist/security/gdpr.js +155 -94
  280. package/dist/security/headers.d.ts +4 -2
  281. package/dist/security/headers.d.ts.map +1 -1
  282. package/dist/security/headers.js +35 -17
  283. package/dist/security/index.d.ts +3 -16
  284. package/dist/security/index.d.ts.map +1 -1
  285. package/dist/security/index.js +3 -16
  286. package/dist/server/index.d.ts.map +1 -1
  287. package/dist/server/renderPage.d.ts.map +1 -1
  288. package/dist/storage/index.d.ts +1 -0
  289. package/dist/storage/index.d.ts.map +1 -1
  290. package/dist/storage/index.js +2 -4
  291. package/dist/storage/vercel-blob.d.ts.map +1 -1
  292. package/dist/translations/index.d.ts.map +1 -1
  293. package/dist/types/access.d.ts.map +1 -1
  294. package/dist/types/api.d.ts.map +1 -1
  295. package/dist/types/cms.d.ts.map +1 -1
  296. package/dist/types/config.d.ts.map +1 -1
  297. package/dist/types/core.d.ts.map +1 -1
  298. package/dist/types/extensions.d.ts.map +1 -1
  299. package/dist/types/frontend.d.ts.map +1 -1
  300. package/dist/types/generated.d.ts +0 -2
  301. package/dist/types/generated.d.ts.map +1 -1
  302. package/dist/types/generated.js +0 -1
  303. package/dist/types/hooks.d.ts.map +1 -1
  304. package/dist/types/index.d.ts +1 -1
  305. package/dist/types/index.d.ts.map +1 -1
  306. package/dist/types/interfaces/app.d.ts.map +1 -1
  307. package/dist/types/jobs.d.ts.map +1 -1
  308. package/dist/types/legacy.d.ts.map +1 -1
  309. package/dist/types/plugins.d.ts.map +1 -1
  310. package/dist/types/query.d.ts.map +1 -1
  311. package/dist/types/request.d.ts.map +1 -1
  312. package/dist/types/richtext.d.ts.map +1 -1
  313. package/dist/types/runtime.d.ts +59 -1
  314. package/dist/types/runtime.d.ts.map +1 -1
  315. package/dist/types/schema.d.ts.map +1 -1
  316. package/dist/types/user.d.ts.map +1 -1
  317. package/dist/utils/access-conversion.d.ts.map +1 -1
  318. package/dist/utils/api-wrapper.d.ts.map +1 -1
  319. package/dist/utils/api-wrapper.js +1 -1
  320. package/dist/utils/block-conversion.d.ts.map +1 -1
  321. package/dist/utils/cache.d.ts.map +1 -1
  322. package/dist/utils/deep-clone.js +0 -1
  323. package/dist/utils/error-responses.d.ts.map +1 -1
  324. package/dist/utils/errors.d.ts +36 -0
  325. package/dist/utils/errors.d.ts.map +1 -1
  326. package/dist/utils/errors.js +103 -0
  327. package/dist/utils/field-conversion.d.ts +1 -1
  328. package/dist/utils/field-conversion.d.ts.map +1 -1
  329. package/dist/utils/flattenResult.d.ts.map +1 -1
  330. package/dist/utils/flattenResult.js +0 -1
  331. package/dist/utils/getBlockSelect.d.ts.map +1 -1
  332. package/dist/utils/getSelectMode.d.ts.map +1 -1
  333. package/dist/utils/isValidID.d.ts.map +1 -1
  334. package/dist/utils/json-parsing.d.ts.map +1 -1
  335. package/dist/utils/logger-client.d.ts.map +1 -1
  336. package/dist/utils/logger-server.d.ts.map +1 -1
  337. package/dist/utils/logger.d.ts.map +1 -1
  338. package/dist/utils/request-context.d.ts.map +1 -1
  339. package/dist/utils/stripUnselectedFields.d.ts.map +1 -1
  340. package/dist/utils/type-guards.d.ts.map +1 -1
  341. package/package.json +39 -16
@@ -1,193 +1,217 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { logger } from '@revealui/core/utils/logger';
4
- import { useEffect, useState } from 'react';
4
+ import { useEffect, useReducer } from 'react';
5
5
  import { APIError, APIErrorType, apiClient } from '../utils/index.js';
6
6
  import { CollectionList } from './CollectionList.js';
7
7
  import { DocumentForm } from './DocumentForm.js';
8
8
  import { GlobalForm } from './GlobalForm.js';
9
+ const initialState = {
10
+ view: { type: 'dashboard' },
11
+ documents: [],
12
+ totalDocs: 0,
13
+ page: 1,
14
+ totalPages: 1,
15
+ collectionLoading: false,
16
+ globalDocument: null,
17
+ globalLoading: false,
18
+ saving: false,
19
+ deleting: null,
20
+ error: null,
21
+ successMessage: null,
22
+ };
23
+ function reducer(state, action) {
24
+ switch (action.type) {
25
+ case 'NAVIGATE':
26
+ return { ...state, view: action.view, error: null, successMessage: null };
27
+ case 'COLLECTION_LOADING':
28
+ return { ...state, collectionLoading: true };
29
+ case 'COLLECTION_LOADED':
30
+ return {
31
+ ...state,
32
+ documents: action.documents,
33
+ totalDocs: action.totalDocs,
34
+ page: action.page,
35
+ totalPages: action.totalPages,
36
+ collectionLoading: false,
37
+ };
38
+ case 'GLOBAL_LOADING':
39
+ return { ...state, globalDocument: null, globalLoading: true };
40
+ case 'GLOBAL_LOADED':
41
+ return { ...state, globalDocument: action.document, globalLoading: false };
42
+ case 'SET_SAVING':
43
+ return { ...state, saving: action.saving };
44
+ case 'SET_DELETING':
45
+ return { ...state, deleting: action.id };
46
+ case 'SET_ERROR':
47
+ return { ...state, error: action.error };
48
+ case 'SET_SUCCESS':
49
+ return { ...state, successMessage: action.message };
50
+ }
51
+ }
52
+ // =============================================================================
53
+ // Shared sub-components
54
+ // =============================================================================
55
+ function AdminHeader({ title, onBack }) {
56
+ return (_jsx("header", { className: "bg-white shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsx("div", { className: "flex justify-between items-center py-4", children: _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { type: "button", onClick: onBack, className: "text-gray-400 hover:text-gray-600", children: "\u2190 Back to Dashboard" }), _jsx("h1", { className: "text-2xl font-bold text-gray-900 capitalize", children: title })] }) }) }) }));
57
+ }
58
+ function StatusBanners({ error, successMessage, }) {
59
+ return (_jsxs(_Fragment, { children: [error && (_jsxs("div", { className: "mb-4 bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Error" }), _jsx("p", { className: "text-sm", children: error })] })), successMessage && (_jsxs("div", { className: "mb-4 bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Success" }), _jsx("p", { className: "text-sm", children: successMessage })] }))] }));
60
+ }
61
+ function LoadingSpinner() {
62
+ return (_jsxs("div", { className: "mb-4 text-center py-8", children: [_jsx("div", { className: "inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900" }), _jsx("p", { className: "mt-2 text-sm text-gray-600", children: "Loading..." })] }));
63
+ }
64
+ // =============================================================================
65
+ // Dashboard home view
66
+ // =============================================================================
67
+ function DashboardHome({ collections, globals, onCollectionClick, onGlobalClick, }) {
68
+ return (_jsxs("div", { className: "min-h-screen bg-gray-50", children: [_jsx("header", { className: "bg-white shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-4", children: [_jsx("div", { className: "flex items-center", children: _jsx("h1", { className: "text-2xl font-bold text-gray-900", children: "RevealUI Admin" }) }), _jsx("div", { className: "flex items-center space-x-4", children: _jsx("span", { className: "text-sm text-gray-500", children: "v0.1.0" }) })] }) }) }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsx("div", { className: "px-4 py-6 sm:px-0", children: _jsxs("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: [_jsxs("div", { className: "bg-white overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsxs("svg", { className: "h-8 w-8 text-gray-400", "aria-label": "Collections", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", role: "img", children: [_jsx("title", { children: "Collections" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" })] }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-gray-500 truncate", children: "Collections" }), _jsx("dd", { className: "text-lg font-medium text-gray-900", children: collections.length })] }) })] }) }), _jsx("div", { className: "bg-gray-50 px-5 py-3", children: _jsx("div", { className: "text-sm", children: collections.length > 0 ? (_jsx("ul", { className: "space-y-1 max-h-48 overflow-y-auto", children: collections.map((collection) => (_jsx("li", { className: "text-gray-600 hover:text-gray-900", children: _jsx("button", { type: "button", onClick: () => onCollectionClick(collection), className: "hover:underline cursor-pointer", children: String(collection.slug) }) }, String(collection.slug)))) })) : (_jsx("p", { className: "text-gray-500", children: "No collections configured" })) }) })] }), _jsxs("div", { className: "bg-white overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsxs("svg", { className: "h-8 w-8 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-labelledby": "globals-icon-title", role: "img", children: [_jsx("title", { id: "globals-icon-title", children: "Globals" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4" })] }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-gray-500 truncate", children: "Globals" }), _jsx("dd", { className: "text-lg font-medium text-gray-900", children: globals.length })] }) })] }) }), _jsx("div", { className: "bg-gray-50 px-5 py-3", children: _jsx("div", { className: "text-sm", children: globals.length > 0 ? (_jsx("ul", { className: "space-y-1 max-h-32 overflow-y-auto", children: globals.map((global) => (_jsx("li", { className: "text-gray-600 hover:text-gray-900", children: _jsx("button", { type: "button", onClick: () => onGlobalClick(global), className: "hover:underline cursor-pointer", children: global.label || String(global.slug) }) }, String(global.slug)))) })) : (_jsx("p", { className: "text-gray-500", children: "No globals configured" })) }) })] }), _jsxs("div", { className: "bg-white overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx("div", { className: "h-8 w-8 bg-green-100 rounded-full flex items-center justify-center", children: _jsxs("svg", { className: "h-5 w-5 text-green-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-labelledby": "system-status-icon-title", role: "img", children: [_jsx("title", { id: "system-status-icon-title", children: "System Status: Healthy" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" })] }) }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-gray-500 truncate", children: "System Status" }), _jsx("dd", { className: "text-lg font-medium text-gray-900", children: "Healthy" })] }) })] }) }), _jsx("div", { className: "bg-gray-50 px-5 py-3", children: _jsx("div", { className: "text-sm text-gray-600", children: "RevealUI CMS is running successfully" }) })] })] }) }) })] }));
69
+ }
70
+ // =============================================================================
71
+ // Error handling helpers
72
+ // =============================================================================
73
+ function extractErrorMessage(err, fallback) {
74
+ return err instanceof APIError ? err.message : fallback;
75
+ }
76
+ function logApiError(err, context) {
77
+ logger.error(context, { error: err });
78
+ if (err instanceof APIError && err.type === APIErrorType.Authentication) {
79
+ logger.warn('Authentication required');
80
+ }
81
+ }
82
+ // =============================================================================
83
+ // Main component
84
+ // =============================================================================
9
85
  export function AdminDashboard({ config }) {
10
- const [currentView, setCurrentView] = useState({
11
- type: 'dashboard',
12
- });
13
- const [collectionData, setCollectionData] = useState({
14
- documents: [],
15
- totalDocs: 0,
16
- page: 1,
17
- totalPages: 1,
18
- loading: false,
19
- error: null,
20
- });
21
- const [saving, setSaving] = useState(false);
22
- const [deleting, setDeleting] = useState(null);
23
- const [error, setError] = useState(null);
24
- const [successMessage, setSuccessMessage] = useState(null);
25
- const [globalData, setGlobalData] = useState({
26
- document: null,
27
- loading: false,
28
- error: null,
29
- });
86
+ const [state, dispatch] = useReducer(reducer, initialState);
30
87
  const collections = config.collections || [];
31
88
  const globals = config.globals || [];
32
89
  // Auto-dismiss success messages
33
90
  useEffect(() => {
34
- if (successMessage) {
35
- const timer = setTimeout(() => setSuccessMessage(null), 3000);
91
+ if (state.successMessage) {
92
+ const timer = setTimeout(() => dispatch({ type: 'SET_SUCCESS', message: null }), 3000);
36
93
  return () => clearTimeout(timer);
37
94
  }
38
95
  return;
39
- }, [successMessage]);
96
+ }, [state.successMessage]);
40
97
  // Auto-dismiss error messages
41
98
  useEffect(() => {
42
- if (error) {
43
- const timer = setTimeout(() => setError(null), 5000);
99
+ if (state.error) {
100
+ const timer = setTimeout(() => dispatch({ type: 'SET_ERROR', error: null }), 5000);
44
101
  return () => clearTimeout(timer);
45
102
  }
46
103
  return;
47
- }, [error]);
48
- const handleCollectionClick = async (collection) => {
49
- setCurrentView({ type: 'collection', collection });
50
- setError(null);
51
- setSuccessMessage(null);
104
+ }, [state.error]);
105
+ const goToDashboard = () => dispatch({ type: 'NAVIGATE', view: { type: 'dashboard' } });
106
+ const fetchCollection = async (collection, page = 1) => {
52
107
  try {
53
- // Show loading state
54
- setCollectionData((prev) => ({ ...prev, loading: true, error: null }));
55
- // Fetch first page of documents
108
+ dispatch({ type: 'COLLECTION_LOADING' });
56
109
  const response = await apiClient.find({
57
110
  collection: String(collection.slug),
58
- page: 1,
111
+ page,
59
112
  limit: 10,
60
113
  });
61
- setCollectionData({
114
+ dispatch({
115
+ type: 'COLLECTION_LOADED',
62
116
  documents: response.docs || [],
63
117
  totalDocs: response.totalDocs || 0,
64
118
  page: response.page || 1,
65
119
  totalPages: response.totalPages || 1,
66
- loading: false,
67
- error: null,
68
120
  });
69
121
  }
70
122
  catch (err) {
71
- // Handle error
72
- const errorMessage = err instanceof APIError ? err.message : 'Failed to fetch collection data. Please try again.';
73
- logger.error('Failed to fetch collection data', { error: err });
74
- setCollectionData((prev) => ({
75
- ...prev,
76
- loading: false,
77
- error: errorMessage,
78
- }));
79
- setError(errorMessage);
80
- // Handle authentication errors
81
- if (err instanceof APIError && err.type === APIErrorType.Authentication) {
82
- // Redirect to login would be handled by the auth system
83
- logger.warn('Authentication required');
84
- }
123
+ const msg = extractErrorMessage(err, 'Failed to fetch collection data. Please try again.');
124
+ logApiError(err, 'Failed to fetch collection data');
125
+ dispatch({
126
+ type: 'COLLECTION_LOADED',
127
+ documents: state.documents,
128
+ totalDocs: state.totalDocs,
129
+ page: state.page,
130
+ totalPages: state.totalPages,
131
+ });
132
+ dispatch({ type: 'SET_ERROR', error: msg });
85
133
  }
86
134
  };
135
+ const handleCollectionClick = async (collection) => {
136
+ dispatch({ type: 'NAVIGATE', view: { type: 'collection', collection } });
137
+ await fetchCollection(collection);
138
+ };
87
139
  const handleGlobalClick = async (global) => {
88
- setCurrentView({ type: 'global', global });
89
- setError(null);
90
- setSuccessMessage(null);
140
+ dispatch({ type: 'NAVIGATE', view: { type: 'global', global } });
91
141
  try {
92
- // Show loading state
93
- setGlobalData({ document: null, loading: true, error: null });
94
- // Fetch global data
142
+ dispatch({ type: 'GLOBAL_LOADING' });
95
143
  const document = await apiClient.findGlobal({
96
144
  slug: String(global.slug),
97
145
  depth: 0,
98
146
  });
99
- setGlobalData({
100
- document,
101
- loading: false,
102
- error: null,
103
- });
147
+ dispatch({ type: 'GLOBAL_LOADED', document });
104
148
  }
105
149
  catch (err) {
106
- // Handle error
107
- const errorMessage = err instanceof APIError ? err.message : 'Failed to fetch global data. Please try again.';
108
- logger.error('Failed to fetch global data', { error: err });
109
- setGlobalData({
110
- document: null,
111
- loading: false,
112
- error: errorMessage,
113
- });
114
- setError(errorMessage);
115
- // Handle authentication errors
116
- if (err instanceof APIError && err.type === APIErrorType.Authentication) {
117
- logger.warn('Authentication required');
118
- }
150
+ const msg = extractErrorMessage(err, 'Failed to fetch global data. Please try again.');
151
+ logApiError(err, 'Failed to fetch global data');
152
+ dispatch({ type: 'SET_ERROR', error: msg });
119
153
  }
120
154
  };
121
155
  const handleCreate = () => {
122
- if (currentView.collection) {
123
- setCurrentView({ type: 'edit', collection: currentView.collection });
156
+ if (state.view.collection) {
157
+ dispatch({
158
+ type: 'NAVIGATE',
159
+ view: { type: 'edit', collection: state.view.collection },
160
+ });
124
161
  }
125
162
  };
126
163
  const handleEdit = (document) => {
127
- if (currentView.collection) {
128
- setCurrentView({
129
- type: 'edit',
130
- collection: currentView.collection,
131
- document,
164
+ if (state.view.collection) {
165
+ dispatch({
166
+ type: 'NAVIGATE',
167
+ view: { type: 'edit', collection: state.view.collection, document },
132
168
  });
133
169
  }
134
170
  };
135
171
  const handleDelete = async (document) => {
136
- if (!(currentView.collection && document.id))
172
+ if (!(state.view.collection && document.id))
137
173
  return;
138
- // Show confirmation dialog
139
- const confirmed = window.confirm(`Are you sure you want to delete this ${String(currentView.collection.slug)}? This action cannot be undone.`);
174
+ const confirmed = window.confirm(`Are you sure you want to delete this ${String(state.view.collection.slug)}? This action cannot be undone.`);
140
175
  if (!confirmed)
141
176
  return;
142
177
  try {
143
- setDeleting(String(document.id));
144
- setError(null);
145
- setSuccessMessage(null);
178
+ dispatch({ type: 'SET_DELETING', id: String(document.id) });
179
+ dispatch({ type: 'SET_ERROR', error: null });
146
180
  await apiClient.delete({
147
- collection: String(currentView.collection.slug),
181
+ collection: String(state.view.collection.slug),
148
182
  id: String(document.id),
149
183
  });
150
- // Refresh collection list
151
- if (currentView.collection) {
152
- await handleCollectionClick(currentView.collection);
184
+ if (state.view.collection) {
185
+ await fetchCollection(state.view.collection);
153
186
  }
154
- // Show success message
155
- setSuccessMessage('Document deleted successfully');
187
+ dispatch({ type: 'SET_SUCCESS', message: 'Document deleted successfully' });
156
188
  }
157
189
  catch (err) {
158
- const errorMessage = err instanceof APIError ? err.message : 'Failed to delete document. Please try again.';
159
- logger.error('Failed to delete document', { error: err });
160
- setError(errorMessage);
161
- // Handle authentication errors
162
- if (err instanceof APIError && err.type === APIErrorType.Authentication) {
163
- logger.warn('Authentication required');
164
- }
190
+ const msg = extractErrorMessage(err, 'Failed to delete document. Please try again.');
191
+ logApiError(err, 'Failed to delete document');
192
+ dispatch({ type: 'SET_ERROR', error: msg });
165
193
  }
166
194
  finally {
167
- setDeleting(null);
195
+ dispatch({ type: 'SET_DELETING', id: null });
168
196
  }
169
197
  };
170
198
  const handleSave = async (data) => {
171
- if (!currentView.collection)
199
+ if (!state.view.collection)
172
200
  return;
173
201
  try {
174
- setSaving(true);
175
- setError(null);
176
- setSuccessMessage(null);
177
- if (currentView.document?.id) {
178
- // Update existing document
202
+ dispatch({ type: 'SET_SAVING', saving: true });
203
+ dispatch({ type: 'SET_ERROR', error: null });
204
+ if (state.view.document?.id) {
179
205
  await apiClient.update({
180
- collection: String(currentView.collection.slug),
181
- id: String(currentView.document.id),
206
+ collection: String(state.view.collection.slug),
207
+ id: String(state.view.document.id),
182
208
  data,
183
209
  });
184
- setSuccessMessage('Document updated successfully');
210
+ dispatch({ type: 'SET_SUCCESS', message: 'Document updated successfully' });
185
211
  }
186
212
  else {
187
- // Auto-generate slug from title if the collection has a slug field but none was
188
- // submitted. Server-side beforeValidate field hooks may not run for all routes,
189
- // so we replicate the slug-generation logic here as a reliable client-side fallback.
190
- const hasSlugField = currentView.collection.fields.some((f) => 'name' in f && f.name === 'slug');
213
+ // Auto-generate slug from title if needed
214
+ const hasSlugField = state.view.collection.fields.some((f) => 'name' in f && f.name === 'slug');
191
215
  const submitData = hasSlugField && !data.slug && typeof data.title === 'string'
192
216
  ? {
193
217
  ...data,
@@ -197,122 +221,71 @@ export function AdminDashboard({ config }) {
197
221
  .toLowerCase(),
198
222
  }
199
223
  : data;
200
- // Create new document
201
224
  await apiClient.create({
202
- collection: String(currentView.collection.slug),
225
+ collection: String(state.view.collection.slug),
203
226
  data: submitData,
204
227
  });
205
- setSuccessMessage('Document created successfully');
206
- }
207
- // Refresh collection list
208
- if (currentView.collection) {
209
- await handleCollectionClick(currentView.collection);
228
+ dispatch({ type: 'SET_SUCCESS', message: 'Document created successfully' });
210
229
  }
211
- // Navigate back to collection view
212
- setCurrentView({
213
- type: 'collection',
214
- collection: currentView.collection,
230
+ await fetchCollection(state.view.collection);
231
+ dispatch({
232
+ type: 'NAVIGATE',
233
+ view: { type: 'collection', collection: state.view.collection },
215
234
  });
216
235
  }
217
236
  catch (err) {
218
- const errorMessage = err instanceof APIError ? err.message : 'Failed to save document. Please try again.';
219
- logger.error('Failed to save document', { error: err });
220
- setError(errorMessage);
221
- // Handle validation errors
237
+ const msg = extractErrorMessage(err, 'Failed to save document. Please try again.');
238
+ logApiError(err, 'Failed to save document');
239
+ dispatch({ type: 'SET_ERROR', error: msg });
222
240
  if (err instanceof APIError && err.type === APIErrorType.Validation) {
223
- // Validation errors are already in the error message
224
- logger.warn('Validation error', {
225
- field: err.field,
226
- message: err.message,
227
- });
228
- }
229
- // Handle authentication errors
230
- if (err instanceof APIError && err.type === APIErrorType.Authentication) {
231
- logger.warn('Authentication required');
241
+ logger.warn('Validation error', { field: err.field, message: err.message });
232
242
  }
233
243
  }
234
244
  finally {
235
- setSaving(false);
245
+ dispatch({ type: 'SET_SAVING', saving: false });
236
246
  }
237
247
  };
238
248
  const handleSaveGlobal = async (data) => {
239
- if (!currentView.global)
249
+ if (!state.view.global)
240
250
  return;
241
251
  try {
242
- setSaving(true);
243
- setError(null);
244
- setSuccessMessage(null);
245
- // Update global
252
+ dispatch({ type: 'SET_SAVING', saving: true });
253
+ dispatch({ type: 'SET_ERROR', error: null });
246
254
  await apiClient.updateGlobal({
247
- slug: String(currentView.global.slug),
255
+ slug: String(state.view.global.slug),
248
256
  data,
249
257
  });
250
- setSuccessMessage('Global updated successfully');
251
- // Navigate back to dashboard
252
- setCurrentView({ type: 'dashboard' });
258
+ dispatch({ type: 'SET_SUCCESS', message: 'Global updated successfully' });
259
+ goToDashboard();
253
260
  }
254
261
  catch (err) {
255
- const errorMessage = err instanceof APIError ? err.message : 'Failed to save global. Please try again.';
256
- logger.error('Failed to save global', { error: err });
257
- setError(errorMessage);
258
- // Handle validation errors
262
+ const msg = extractErrorMessage(err, 'Failed to save global. Please try again.');
263
+ logApiError(err, 'Failed to save global');
264
+ dispatch({ type: 'SET_ERROR', error: msg });
259
265
  if (err instanceof APIError && err.type === APIErrorType.Validation) {
260
- logger.warn('Validation error', {
261
- field: err.field,
262
- message: err.message,
263
- });
264
- }
265
- // Handle authentication errors
266
- if (err instanceof APIError && err.type === APIErrorType.Authentication) {
267
- logger.warn('Authentication required');
266
+ logger.warn('Validation error', { field: err.field, message: err.message });
268
267
  }
269
268
  }
270
269
  finally {
271
- setSaving(false);
272
- }
273
- };
274
- const handleCancel = () => {
275
- setCurrentView({ type: 'dashboard' });
276
- };
277
- const handlePageChange = async (page) => {
278
- if (!currentView.collection)
279
- return;
280
- try {
281
- setCollectionData((prev) => ({ ...prev, loading: true, error: null }));
282
- const response = await apiClient.find({
283
- collection: String(currentView.collection.slug),
284
- page,
285
- limit: 10,
286
- });
287
- setCollectionData({
288
- documents: response.docs || [],
289
- totalDocs: response.totalDocs || 0,
290
- page: response.page || 1,
291
- totalPages: response.totalPages || 1,
292
- loading: false,
293
- error: null,
294
- });
295
- }
296
- catch (err) {
297
- const errorMessage = err instanceof APIError ? err.message : 'Failed to fetch page. Please try again.';
298
- logger.error('Failed to fetch page', { error: err });
299
- setCollectionData((prev) => ({
300
- ...prev,
301
- loading: false,
302
- error: errorMessage,
303
- }));
304
- setError(errorMessage);
270
+ dispatch({ type: 'SET_SAVING', saving: false });
305
271
  }
306
272
  };
307
- if (currentView.type === 'collection' && currentView.collection) {
308
- return (_jsxs("div", { className: "min-h-screen bg-gray-50", children: [_jsx("header", { className: "bg-white shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsx("div", { className: "flex justify-between items-center py-4", children: _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { type: "button", onClick: () => setCurrentView({ type: 'dashboard' }), className: "text-gray-400 hover:text-gray-600", children: "\u2190 Back to Dashboard" }), _jsx("h1", { className: "text-2xl font-bold text-gray-900 capitalize", children: String(currentView.collection.slug) })] }) }) }) }), _jsxs("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: [error && (_jsxs("div", { className: "mb-4 bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Error" }), _jsx("p", { className: "text-sm", children: error })] })), successMessage && (_jsxs("div", { className: "mb-4 bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Success" }), _jsx("p", { className: "text-sm", children: successMessage })] })), collectionData.loading && (_jsxs("div", { className: "mb-4 text-center py-8", children: [_jsx("div", { className: "inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900" }), _jsx("p", { className: "mt-2 text-sm text-gray-600", children: "Loading..." })] })), _jsx(CollectionList, { collection: currentView.collection, documents: collectionData.documents, totalDocs: collectionData.totalDocs, page: collectionData.page, totalPages: collectionData.totalPages, onCreate: handleCreate, onEdit: handleEdit, onDelete: (document) => void handleDelete(document), onPageChange: (nextPage) => void handlePageChange(nextPage), deleting: deleting })] })] }));
273
+ // ── Collection list view ──────────────────────────────────────────────
274
+ if (state.view.type === 'collection' && state.view.collection) {
275
+ return (_jsxs("div", { className: "min-h-screen bg-gray-50", children: [_jsx(AdminHeader, { title: String(state.view.collection.slug), onBack: goToDashboard }), _jsxs("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: [_jsx(StatusBanners, { error: state.error, successMessage: state.successMessage }), state.collectionLoading && _jsx(LoadingSpinner, {}), _jsx(CollectionList, { collection: state.view.collection, documents: state.documents, totalDocs: state.totalDocs, page: state.page, totalPages: state.totalPages, onCreate: handleCreate, onEdit: handleEdit, onDelete: (document) => void handleDelete(document), onPageChange: (nextPage) => {
276
+ const collection = state.view.collection;
277
+ if (collection)
278
+ void fetchCollection(collection, nextPage);
279
+ }, deleting: state.deleting })] })] }));
309
280
  }
310
- if (currentView.type === 'edit' && currentView.collection) {
311
- return (_jsxs("div", { className: "min-h-screen bg-gray-50", children: [_jsx("header", { className: "bg-white shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsx("div", { className: "flex justify-between items-center py-4", children: _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { type: "button", onClick: () => setCurrentView({ type: 'dashboard' }), className: "text-gray-400 hover:text-gray-600", children: "\u2190 Back to Dashboard" }), _jsxs("h1", { className: "text-2xl font-bold text-gray-900 capitalize", children: [currentView.document ? 'Edit' : 'Create', ' ', String(currentView.collection.slug).slice(0, -1)] })] }) }) }) }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsxs("div", { className: "max-w-3xl", children: [error && (_jsxs("div", { className: "mb-4 bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Error" }), _jsx("p", { className: "text-sm", children: error })] })), successMessage && (_jsxs("div", { className: "mb-4 bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Success" }), _jsx("p", { className: "text-sm", children: successMessage })] })), _jsx(DocumentForm, { collection: currentView.collection, document: currentView.document, onSave: (data) => void handleSave(data), onCancel: handleCancel, isLoading: saving })] }) })] }));
281
+ // ── Document edit/create view ─────────────────────────────────────────
282
+ if (state.view.type === 'edit' && state.view.collection) {
283
+ return (_jsxs("div", { className: "min-h-screen bg-gray-50", children: [_jsx(AdminHeader, { title: `${state.view.document ? 'Edit' : 'Create'} ${String(state.view.collection.slug).slice(0, -1)}`, onBack: goToDashboard }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsxs("div", { className: "max-w-3xl", children: [_jsx(StatusBanners, { error: state.error, successMessage: state.successMessage }), _jsx(DocumentForm, { collection: state.view.collection, document: state.view.document, onSave: (data) => void handleSave(data), onCancel: goToDashboard, isLoading: state.saving })] }) })] }));
312
284
  }
313
- if (currentView.type === 'global' && currentView.global) {
314
- return (_jsxs("div", { className: "min-h-screen bg-gray-50", children: [_jsx("header", { className: "bg-white shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsx("div", { className: "flex justify-between items-center py-4", children: _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { type: "button", onClick: () => setCurrentView({ type: 'dashboard' }), className: "text-gray-400 hover:text-gray-600", children: "\u2190 Back to Dashboard" }), _jsx("h1", { className: "text-2xl font-bold text-gray-900 capitalize", children: currentView.global.label || String(currentView.global.slug) })] }) }) }) }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsxs("div", { className: "max-w-3xl", children: [error && (_jsxs("div", { className: "mb-4 bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Error" }), _jsx("p", { className: "text-sm", children: error })] })), successMessage && (_jsxs("div", { className: "mb-4 bg-green-50 border border-green-200 text-green-800 px-4 py-3 rounded", children: [_jsx("p", { className: "font-medium", children: "Success" }), _jsx("p", { className: "text-sm", children: successMessage })] })), globalData.loading && (_jsxs("div", { className: "mb-4 text-center py-8", children: [_jsx("div", { className: "inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900" }), _jsx("p", { className: "mt-2 text-sm text-gray-600", children: "Loading..." })] })), !globalData.loading && globalData.document && (_jsx(GlobalForm, { global: currentView.global, document: globalData.document, onSave: (data) => void handleSaveGlobal(data), onCancel: handleCancel, isLoading: saving }))] }) })] }));
285
+ // ── Global edit view ──────────────────────────────────────────────────
286
+ if (state.view.type === 'global' && state.view.global) {
287
+ return (_jsxs("div", { className: "min-h-screen bg-gray-50", children: [_jsx(AdminHeader, { title: state.view.global.label || String(state.view.global.slug), onBack: goToDashboard }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsxs("div", { className: "max-w-3xl", children: [_jsx(StatusBanners, { error: state.error, successMessage: state.successMessage }), state.globalLoading && _jsx(LoadingSpinner, {}), !state.globalLoading && state.globalDocument && (_jsx(GlobalForm, { global: state.view.global, document: state.globalDocument, onSave: (data) => void handleSaveGlobal(data), onCancel: goToDashboard, isLoading: state.saving }))] }) })] }));
315
288
  }
316
- // Dashboard view
317
- return (_jsxs("div", { className: "min-h-screen bg-gray-50", children: [_jsx("header", { className: "bg-white shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-4", children: [_jsx("div", { className: "flex items-center", children: _jsx("h1", { className: "text-2xl font-bold text-gray-900", children: "RevealUI Admin" }) }), _jsx("div", { className: "flex items-center space-x-4", children: _jsx("span", { className: "text-sm text-gray-500", children: "v0.1.0" }) })] }) }) }), _jsx("main", { className: "max-w-7xl mx-auto py-6 sm:px-6 lg:px-8", children: _jsx("div", { className: "px-4 py-6 sm:px-0", children: _jsxs("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: [_jsxs("div", { className: "bg-white overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsxs("svg", { className: "h-8 w-8 text-gray-400", "aria-label": "Collections", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", role: "img", children: [_jsx("title", { children: "Collections" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" })] }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-gray-500 truncate", children: "Collections" }), _jsx("dd", { className: "text-lg font-medium text-gray-900", children: collections.length })] }) })] }) }), _jsx("div", { className: "bg-gray-50 px-5 py-3", children: _jsx("div", { className: "text-sm", children: collections.length > 0 ? (_jsx("ul", { className: "space-y-1 max-h-48 overflow-y-auto", children: collections.map((collection) => (_jsx("li", { className: "text-gray-600 hover:text-gray-900", children: _jsx("button", { type: "button", onClick: () => void handleCollectionClick(collection), className: "hover:underline cursor-pointer", children: String(collection.slug) }) }, String(collection.slug)))) })) : (_jsx("p", { className: "text-gray-500", children: "No collections configured" })) }) })] }), _jsxs("div", { className: "bg-white overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsxs("svg", { className: "h-8 w-8 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-labelledby": "globals-icon-title", role: "img", children: [_jsx("title", { id: "globals-icon-title", children: "Globals" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4" })] }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-gray-500 truncate", children: "Globals" }), _jsx("dd", { className: "text-lg font-medium text-gray-900", children: globals.length })] }) })] }) }), _jsx("div", { className: "bg-gray-50 px-5 py-3", children: _jsx("div", { className: "text-sm", children: globals.length > 0 ? (_jsx("ul", { className: "space-y-1 max-h-32 overflow-y-auto", children: globals.map((global) => (_jsx("li", { className: "text-gray-600 hover:text-gray-900", children: _jsx("button", { type: "button", onClick: () => void handleGlobalClick(global), className: "hover:underline cursor-pointer", children: global.label || String(global.slug) }) }, String(global.slug)))) })) : (_jsx("p", { className: "text-gray-500", children: "No globals configured" })) }) })] }), _jsxs("div", { className: "bg-white overflow-hidden shadow rounded-lg", children: [_jsx("div", { className: "p-5", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx("div", { className: "h-8 w-8 bg-green-100 rounded-full flex items-center justify-center", children: _jsxs("svg", { className: "h-5 w-5 text-green-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-labelledby": "system-status-icon-title", role: "img", children: [_jsx("title", { id: "system-status-icon-title", children: "System Status: Healthy" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" })] }) }) }), _jsx("div", { className: "ml-5 w-0 flex-1", children: _jsxs("dl", { children: [_jsx("dt", { className: "text-sm font-medium text-gray-500 truncate", children: "System Status" }), _jsx("dd", { className: "text-lg font-medium text-gray-900", children: "Healthy" })] }) })] }) }), _jsx("div", { className: "bg-gray-50 px-5 py-3", children: _jsx("div", { className: "text-sm text-gray-600", children: "RevealUI CMS is running successfully" }) })] })] }) }) })] }));
289
+ // ── Dashboard home ────────────────────────────────────────────────────
290
+ return (_jsx(DashboardHome, { collections: collections, globals: globals, onCollectionClick: (c) => void handleCollectionClick(c), onGlobalClick: (g) => void handleGlobalClick(g) }));
318
291
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionList.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/CollectionList.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAiB,MAAM,yBAAyB,CAAA;AAoCpG,UAAU,mBAAmB;IAC3B,UAAU,EAAE,sBAAsB,CAAA;IAClC,SAAS,EAAE,cAAc,EAAE,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,MAAM,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;IACvC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,SAAS,EACT,SAAS,EACT,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,QAAQ,GACT,EAAE,mBAAmB,2CAqKrB"}
1
+ {"version":3,"file":"CollectionList.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/CollectionList.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,sBAAsB,EACtB,cAAc,EAEf,MAAM,yBAAyB,CAAC;AAoCjC,UAAU,mBAAmB;IAC3B,UAAU,EAAE,sBAAsB,CAAC;IACnC,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EACV,SAAS,EACT,SAAS,EACT,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,QAAQ,GACT,EAAE,mBAAmB,2CAqKrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentForm.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/DocumentForm.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAiB,MAAM,yBAAyB,CAAA;AA4DpG,UAAU,iBAAiB;IACzB,UAAU,EAAE,sBAAsB,CAAA;IAClC,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;IAC/C,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,wBAAgB,YAAY,CAAC,EAC3B,UAAU,EACV,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,SAAiB,GAClB,EAAE,iBAAiB,2CA0DnB"}
1
+ {"version":3,"file":"DocumentForm.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/components/DocumentForm.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,sBAAsB,EACtB,cAAc,EAEf,MAAM,yBAAyB,CAAC;AAiEjC,UAAU,iBAAiB;IACzB,UAAU,EAAE,sBAAsB,CAAC;IACnC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,EAC3B,UAAU,EACV,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,SAAiB,GAClB,EAAE,iBAAiB,2CA0DnB"}