@rebasepro/app 0.0.1-canary.4829d6e

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 (268) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/dist/auth/api.d.ts +66 -0
  4. package/dist/auth/index.d.ts +13 -0
  5. package/dist/auth/types.d.ts +127 -0
  6. package/dist/auth/useRebaseAuthController.d.ts +13 -0
  7. package/dist/components/AIIcon.d.ts +17 -0
  8. package/dist/components/AuthSimulationMenu.d.ts +0 -0
  9. package/dist/components/ConfirmationDialog.d.ts +9 -0
  10. package/dist/components/Debug/UIReferenceView.d.ts +13 -0
  11. package/dist/components/Debug/UIStyleGuide.d.ts +2 -0
  12. package/dist/components/Debug/collection-views/CardViewDemo.d.ts +2 -0
  13. package/dist/components/Debug/collection-views/CollectionTableDemo.d.ts +2 -0
  14. package/dist/components/Debug/collection-views/KanbanBoardDemo.d.ts +2 -0
  15. package/dist/components/Debug/collection-views/index.d.ts +3 -0
  16. package/dist/components/Debug/collection-views/sample_data.d.ts +23 -0
  17. package/dist/components/Debug/crm-dashboard/CalendarWidget.d.ts +22 -0
  18. package/dist/components/Debug/crm-dashboard/CrmDashboardDemo.d.ts +2 -0
  19. package/dist/components/Debug/crm-dashboard/DashboardMetrics.d.ts +15 -0
  20. package/dist/components/Debug/crm-dashboard/PipelineOverview.d.ts +34 -0
  21. package/dist/components/Debug/crm-dashboard/RecentActivity.d.ts +19 -0
  22. package/dist/components/Debug/crm-dashboard/TaskFilters.d.ts +30 -0
  23. package/dist/components/Debug/crm-dashboard/TaskTable.d.ts +50 -0
  24. package/dist/components/Debug/crm-dashboard/TasksView.d.ts +41 -0
  25. package/dist/components/ErrorTooltip.d.ts +3 -0
  26. package/dist/components/ErrorView.d.ts +21 -0
  27. package/dist/components/LanguageToggle.d.ts +2 -0
  28. package/dist/components/LoginView/LoginView.d.ts +113 -0
  29. package/dist/components/LoginView/index.d.ts +2 -0
  30. package/dist/components/NotFoundPage.d.ts +2 -0
  31. package/dist/components/RebaseAuth.d.ts +10 -0
  32. package/dist/components/RebaseLogo.d.ts +7 -0
  33. package/dist/components/SchemaDriftBanner.d.ts +27 -0
  34. package/dist/components/UnsavedChangesDialog.d.ts +9 -0
  35. package/dist/components/UserDisplay.d.ts +7 -0
  36. package/dist/components/UserSelectPopover.d.ts +63 -0
  37. package/dist/components/UserSettingsView.d.ts +2 -0
  38. package/dist/components/common/index.d.ts +6 -0
  39. package/dist/components/common/table_height.d.ts +5 -0
  40. package/dist/components/common/types.d.ts +66 -0
  41. package/dist/components/common/useColumnsIds.d.ts +9 -0
  42. package/dist/components/common/useDataTableController.d.ts +45 -0
  43. package/dist/components/common/useDebouncedData.d.ts +9 -0
  44. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  45. package/dist/components/index.d.ts +18 -0
  46. package/dist/contexts/AdminModeController.d.ts +4 -0
  47. package/dist/contexts/AnalyticsContext.d.ts +3 -0
  48. package/dist/contexts/AuthControllerContext.d.ts +3 -0
  49. package/dist/contexts/CollectionScopeContext.d.ts +50 -0
  50. package/dist/contexts/ComponentOverrideContext.d.ts +42 -0
  51. package/dist/contexts/CustomizationControllerContext.d.ts +3 -0
  52. package/dist/contexts/DataDriverContext.d.ts +3 -0
  53. package/dist/contexts/DataSourcesContext.d.ts +31 -0
  54. package/dist/contexts/DatabaseAdminContext.d.ts +3 -0
  55. package/dist/contexts/DialogsProvider.d.ts +4 -0
  56. package/dist/contexts/EffectiveRoleController.d.ts +4 -0
  57. package/dist/contexts/ModeController.d.ts +4 -0
  58. package/dist/contexts/RebaseClientInstanceContext.d.ts +6 -0
  59. package/dist/contexts/RebaseDataContext.d.ts +3 -0
  60. package/dist/contexts/SnackbarProvider.d.ts +2 -0
  61. package/dist/contexts/StorageSourceContext.d.ts +3 -0
  62. package/dist/contexts/StorageSourcesContext.d.ts +25 -0
  63. package/dist/contexts/UserConfigurationPersistenceContext.d.ts +3 -0
  64. package/dist/contexts/index.d.ts +17 -0
  65. package/dist/core/PluginLifecycleManager.d.ts +17 -0
  66. package/dist/core/PluginProviderStack.d.ts +21 -0
  67. package/dist/core/Rebase.d.ts +15 -0
  68. package/dist/core/RebaseProps.d.ts +291 -0
  69. package/dist/core/RebaseRouter.d.ts +4 -0
  70. package/dist/core/RebaseRoutes.d.ts +17 -0
  71. package/dist/core/index.d.ts +4 -0
  72. package/dist/hooks/ApiConfigContext.d.ts +24 -0
  73. package/dist/hooks/data/delete.d.ts +33 -0
  74. package/dist/hooks/data/save.d.ts +40 -0
  75. package/dist/hooks/data/useCollection.d.ts +62 -0
  76. package/dist/hooks/data/useData.d.ts +13 -0
  77. package/dist/hooks/data/useDataOrder.d.ts +12 -0
  78. package/dist/hooks/data/useFetch.d.ts +43 -0
  79. package/dist/hooks/data/useRelationSelector.d.ts +52 -0
  80. package/dist/hooks/index.d.ts +36 -0
  81. package/dist/hooks/useAdminModeController.d.ts +19 -0
  82. package/dist/hooks/useAnalyticsController.d.ts +5 -0
  83. package/dist/hooks/useAuthController.d.ts +11 -0
  84. package/dist/hooks/useAuthSubscription.d.ts +2 -0
  85. package/dist/hooks/useBackendStorageSource.d.ts +30 -0
  86. package/dist/hooks/useBridgeRegistration.d.ts +18 -0
  87. package/dist/hooks/useBrowserTitleAndIcon.d.ts +6 -0
  88. package/dist/hooks/useBuildAdminModeController.d.ts +6 -0
  89. package/dist/hooks/useBuildEffectiveRoleController.d.ts +8 -0
  90. package/dist/hooks/useBuildLocalConfigurationPersistence.d.ts +2 -0
  91. package/dist/hooks/useBuildModeController.d.ts +6 -0
  92. package/dist/hooks/useClipboard.d.ts +57 -0
  93. package/dist/hooks/useCollapsedGroups.d.ts +27 -0
  94. package/dist/hooks/useComponentOverride.d.ts +32 -0
  95. package/dist/hooks/useCustomizationController.d.ts +11 -0
  96. package/dist/hooks/useDialogsController.d.ts +11 -0
  97. package/dist/hooks/useEffectiveRoleController.d.ts +7 -0
  98. package/dist/hooks/useLargeLayout.d.ts +1 -0
  99. package/dist/hooks/useModeController.d.ts +19 -0
  100. package/dist/hooks/usePermissions.d.ts +12 -0
  101. package/dist/hooks/useRebaseClient.d.ts +5 -0
  102. package/dist/hooks/useRebaseContext.d.ts +11 -0
  103. package/dist/hooks/useRebaseRegistry.d.ts +34 -0
  104. package/dist/hooks/useResolvedComponent.d.ts +47 -0
  105. package/dist/hooks/useSlot.d.ts +18 -0
  106. package/dist/hooks/useSnackbarController.d.ts +20 -0
  107. package/dist/hooks/useStorageSource.d.ts +6 -0
  108. package/dist/hooks/useStudioBridge.d.ts +79 -0
  109. package/dist/hooks/useTranslation.d.ts +17 -0
  110. package/dist/hooks/useUnsavedChangesDialog.d.ts +12 -0
  111. package/dist/hooks/useUserConfigurationPersistence.d.ts +8 -0
  112. package/dist/i18n/RebaseI18nProvider.d.ts +33 -0
  113. package/dist/index.d.ts +16 -0
  114. package/dist/index.es.js +16843 -0
  115. package/dist/index.es.js.map +1 -0
  116. package/dist/index.umd.js +17021 -0
  117. package/dist/index.umd.js.map +1 -0
  118. package/dist/internal/common.d.ts +14 -0
  119. package/dist/internal/useRestoreScroll.d.ts +15 -0
  120. package/dist/locales/de.d.ts +2 -0
  121. package/dist/locales/en.d.ts +10 -0
  122. package/dist/locales/es.d.ts +10 -0
  123. package/dist/locales/fr.d.ts +2 -0
  124. package/dist/locales/hi.d.ts +2 -0
  125. package/dist/locales/it.d.ts +2 -0
  126. package/dist/locales/pt.d.ts +7 -0
  127. package/dist/util/constants.d.ts +1 -0
  128. package/dist/util/createFormexStub.d.ts +2 -0
  129. package/dist/util/entity_cache.d.ts +22 -0
  130. package/dist/util/enums.d.ts +5 -0
  131. package/dist/util/icon_list.d.ts +5 -0
  132. package/dist/util/icons.d.ts +20 -0
  133. package/dist/util/index.d.ts +8 -0
  134. package/dist/util/previews.d.ts +4 -0
  135. package/dist/util/useStorageUploadController.d.ts +44 -0
  136. package/dist/vitePlugin.d.ts +60 -0
  137. package/dist/vitePlugin.js +113 -0
  138. package/package.json +145 -0
  139. package/src/auth/api.ts +148 -0
  140. package/src/auth/index.ts +25 -0
  141. package/src/auth/types.ts +115 -0
  142. package/src/auth/useRebaseAuthController.ts +328 -0
  143. package/src/components/AIIcon.tsx +47 -0
  144. package/src/components/AuthSimulationMenu.tsx +0 -0
  145. package/src/components/ConfirmationDialog.tsx +48 -0
  146. package/src/components/Debug/UIReferenceView.tsx +958 -0
  147. package/src/components/Debug/UIStyleGuide.tsx +156 -0
  148. package/src/components/Debug/collection-views/CardViewDemo.tsx +85 -0
  149. package/src/components/Debug/collection-views/CollectionTableDemo.tsx +107 -0
  150. package/src/components/Debug/collection-views/KanbanBoardDemo.tsx +90 -0
  151. package/src/components/Debug/collection-views/index.ts +3 -0
  152. package/src/components/Debug/collection-views/sample_data.ts +42 -0
  153. package/src/components/Debug/crm-dashboard/CalendarWidget.tsx +389 -0
  154. package/src/components/Debug/crm-dashboard/CrmDashboardDemo.tsx +1102 -0
  155. package/src/components/Debug/crm-dashboard/DashboardMetrics.tsx +133 -0
  156. package/src/components/Debug/crm-dashboard/PipelineOverview.tsx +290 -0
  157. package/src/components/Debug/crm-dashboard/RecentActivity.tsx +215 -0
  158. package/src/components/Debug/crm-dashboard/TaskFilters.tsx +184 -0
  159. package/src/components/Debug/crm-dashboard/TaskTable.tsx +427 -0
  160. package/src/components/Debug/crm-dashboard/TasksView.tsx +234 -0
  161. package/src/components/ErrorTooltip.tsx +12 -0
  162. package/src/components/ErrorView.tsx +94 -0
  163. package/src/components/LanguageToggle.tsx +59 -0
  164. package/src/components/LoginView/LoginView.tsx +932 -0
  165. package/src/components/LoginView/index.ts +2 -0
  166. package/src/components/NotFoundPage.tsx +27 -0
  167. package/src/components/RebaseAuth.tsx +27 -0
  168. package/src/components/RebaseLogo.tsx +29 -0
  169. package/src/components/SchemaDriftBanner.tsx +102 -0
  170. package/src/components/UnsavedChangesDialog.tsx +46 -0
  171. package/src/components/UserDisplay.tsx +54 -0
  172. package/src/components/UserSelectPopover.tsx +399 -0
  173. package/src/components/UserSettingsView.tsx +318 -0
  174. package/src/components/common/index.ts +6 -0
  175. package/src/components/common/table_height.tsx +21 -0
  176. package/src/components/common/types.tsx +66 -0
  177. package/src/components/common/useColumnsIds.tsx +222 -0
  178. package/src/components/common/useDataTableController.tsx +514 -0
  179. package/src/components/common/useDebouncedData.ts +49 -0
  180. package/src/components/common/useScrollRestoration.tsx +68 -0
  181. package/src/components/index.tsx +26 -0
  182. package/src/contexts/AdminModeController.tsx +11 -0
  183. package/src/contexts/AnalyticsContext.tsx +4 -0
  184. package/src/contexts/AuthControllerContext.tsx +4 -0
  185. package/src/contexts/CollectionScopeContext.tsx +67 -0
  186. package/src/contexts/ComponentOverrideContext.tsx +81 -0
  187. package/src/contexts/CustomizationControllerContext.tsx +4 -0
  188. package/src/contexts/DataDriverContext.tsx +4 -0
  189. package/src/contexts/DataSourcesContext.tsx +36 -0
  190. package/src/contexts/DatabaseAdminContext.tsx +4 -0
  191. package/src/contexts/DialogsProvider.tsx +56 -0
  192. package/src/contexts/EffectiveRoleController.tsx +12 -0
  193. package/src/contexts/ModeController.tsx +11 -0
  194. package/src/contexts/RebaseClientInstanceContext.tsx +7 -0
  195. package/src/contexts/RebaseDataContext.tsx +4 -0
  196. package/src/contexts/SnackbarProvider.tsx +15 -0
  197. package/src/contexts/StorageSourceContext.tsx +4 -0
  198. package/src/contexts/StorageSourcesContext.tsx +30 -0
  199. package/src/contexts/UserConfigurationPersistenceContext.tsx +4 -0
  200. package/src/contexts/index.ts +17 -0
  201. package/src/core/PluginLifecycleManager.tsx +95 -0
  202. package/src/core/PluginProviderStack.tsx +40 -0
  203. package/src/core/Rebase.tsx +439 -0
  204. package/src/core/RebaseProps.tsx +320 -0
  205. package/src/core/RebaseRouter.tsx +17 -0
  206. package/src/core/RebaseRoutes.tsx +24 -0
  207. package/src/core/index.tsx +5 -0
  208. package/src/hooks/ApiConfigContext.tsx +41 -0
  209. package/src/hooks/data/delete.ts +55 -0
  210. package/src/hooks/data/save.ts +77 -0
  211. package/src/hooks/data/useCollection.tsx +176 -0
  212. package/src/hooks/data/useData.tsx +18 -0
  213. package/src/hooks/data/useDataOrder.ts +26 -0
  214. package/src/hooks/data/useFetch.tsx +140 -0
  215. package/src/hooks/data/useRelationSelector.tsx +234 -0
  216. package/src/hooks/index.tsx +45 -0
  217. package/src/hooks/useAdminModeController.tsx +23 -0
  218. package/src/hooks/useAnalyticsController.tsx +8 -0
  219. package/src/hooks/useAuthController.tsx +14 -0
  220. package/src/hooks/useAuthSubscription.ts +87 -0
  221. package/src/hooks/useBackendStorageSource.ts +288 -0
  222. package/src/hooks/useBridgeRegistration.tsx +32 -0
  223. package/src/hooks/useBrowserTitleAndIcon.tsx +23 -0
  224. package/src/hooks/useBuildAdminModeController.tsx +24 -0
  225. package/src/hooks/useBuildEffectiveRoleController.tsx +31 -0
  226. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +75 -0
  227. package/src/hooks/useBuildModeController.tsx +71 -0
  228. package/src/hooks/useClipboard.tsx +158 -0
  229. package/src/hooks/useCollapsedGroups.ts +116 -0
  230. package/src/hooks/useComponentOverride.tsx +59 -0
  231. package/src/hooks/useCustomizationController.tsx +14 -0
  232. package/src/hooks/useDialogsController.tsx +15 -0
  233. package/src/hooks/useEffectiveRoleController.tsx +10 -0
  234. package/src/hooks/useLargeLayout.tsx +65 -0
  235. package/src/hooks/useModeController.tsx +23 -0
  236. package/src/hooks/usePermissions.ts +44 -0
  237. package/src/hooks/useRebaseClient.tsx +10 -0
  238. package/src/hooks/useRebaseContext.tsx +83 -0
  239. package/src/hooks/useRebaseRegistry.tsx +91 -0
  240. package/src/hooks/useResolvedComponent.tsx +159 -0
  241. package/src/hooks/useSlot.tsx +64 -0
  242. package/src/hooks/useSnackbarController.tsx +52 -0
  243. package/src/hooks/useStorageSource.tsx +11 -0
  244. package/src/hooks/useStudioBridge.tsx +209 -0
  245. package/src/hooks/useTranslation.ts +33 -0
  246. package/src/hooks/useUnsavedChangesDialog.tsx +64 -0
  247. package/src/hooks/useUserConfigurationPersistence.tsx +11 -0
  248. package/src/i18n/RebaseI18nProvider.tsx +160 -0
  249. package/src/index.ts +25 -0
  250. package/src/internal/common.tsx +16 -0
  251. package/src/internal/useRestoreScroll.tsx +69 -0
  252. package/src/locales/de.ts +902 -0
  253. package/src/locales/en.ts +980 -0
  254. package/src/locales/es.ts +922 -0
  255. package/src/locales/fr.ts +901 -0
  256. package/src/locales/hi.ts +901 -0
  257. package/src/locales/it.ts +901 -0
  258. package/src/locales/pt.ts +909 -0
  259. package/src/util/constants.ts +7 -0
  260. package/src/util/createFormexStub.tsx +66 -0
  261. package/src/util/entity_cache.ts +239 -0
  262. package/src/util/enums.ts +32 -0
  263. package/src/util/icon_list.ts +22 -0
  264. package/src/util/icons.tsx +149 -0
  265. package/src/util/index.ts +12 -0
  266. package/src/util/previews.ts +105 -0
  267. package/src/util/useStorageUploadController.tsx +350 -0
  268. package/src/vitePlugin.ts +196 -0
@@ -0,0 +1,7 @@
1
+ export const STUDIO_NAVIGATION_GROUPS = [
2
+ "Database",
3
+ "Compute",
4
+ "API",
5
+ "Storage",
6
+ "Access Control"
7
+ ];
@@ -0,0 +1,66 @@
1
+ import { FormexController } from "@rebasepro/forms";
2
+
3
+ export function createFormexStub<T extends object>(values: T): FormexController<T> {
4
+ const errorMessage = "You are in a read-only context. You cannot modify the formex controller.";
5
+
6
+ return {
7
+ debugId: "",
8
+ values,
9
+ initialValues: values,
10
+ touched: {} as Record<string, boolean>,
11
+ dirty: false,
12
+ errors: {} as Record<string, string>,
13
+ submitCount: 0,
14
+ isSubmitting: false,
15
+ isValidating: false,
16
+ version: 0,
17
+ canUndo: false,
18
+ canRedo: false,
19
+
20
+ setValues: () => {
21
+ throw new Error(errorMessage);
22
+ },
23
+ setTouched(touched: Record<string, boolean>): void {
24
+ throw new Error(errorMessage);
25
+ },
26
+ setFieldValue: () => {
27
+ throw new Error(errorMessage);
28
+ },
29
+ setFieldTouched: () => {
30
+ throw new Error(errorMessage);
31
+ },
32
+ setDirty: () => {
33
+ throw new Error(errorMessage);
34
+ },
35
+ setSubmitCount: () => {
36
+ throw new Error(errorMessage);
37
+ },
38
+ setFieldError: () => {
39
+ throw new Error(errorMessage);
40
+ },
41
+ handleChange: () => {
42
+ throw new Error(errorMessage);
43
+ },
44
+ handleBlur: () => {
45
+ throw new Error(errorMessage);
46
+ },
47
+ handleSubmit: () => {
48
+ throw new Error(errorMessage);
49
+ },
50
+ validate: () => {
51
+ throw new Error(errorMessage);
52
+ },
53
+ resetForm: () => {
54
+ throw new Error(errorMessage);
55
+ },
56
+ setSubmitting: () => {
57
+ throw new Error(errorMessage);
58
+ },
59
+ undo: () => {
60
+ throw new Error(errorMessage);
61
+ },
62
+ redo: () => {
63
+ throw new Error(errorMessage);
64
+ }
65
+ };
66
+ }
@@ -0,0 +1,239 @@
1
+ import { EntityReference, EntityRelation, GeoPoint, Vector } from "@rebasepro/types";
2
+ import { isObject, isPlainObject } from "@rebasepro/utils";
3
+
4
+ // Define a unique prefix for entity keys in sessionStorage to avoid key collisions
5
+ const LOCAL_STORAGE_PREFIX = "entity_cache::";
6
+
7
+ // In-memory cache to store entities for quick access
8
+ const entityCache: Map<string, object> = new Map();
9
+
10
+ // Check `sessionStorage` availability once during initialization
11
+ const isSessionStorageAvailable = typeof sessionStorage !== "undefined";
12
+
13
+ // Define custom replacer for JSON.stringify
14
+ function customReplacer(this: Record<string, unknown>, key: string): unknown {
15
+
16
+ const value = this[key];
17
+
18
+ // Handle Date objects
19
+ if (value instanceof Date) {
20
+ return {
21
+ __type: "Date",
22
+ value: value.toISOString()
23
+ };
24
+ }
25
+
26
+ // Handle EntityReference
27
+ if (value instanceof EntityReference) {
28
+ return {
29
+ __type: "EntityReference",
30
+ id: value.id,
31
+ path: value.path,
32
+ driver: value.driver,
33
+ databaseId: value.databaseId
34
+ };
35
+ }
36
+
37
+ if (value instanceof EntityRelation) {
38
+ return {
39
+ __type: "EntityRelation",
40
+ id: value.id,
41
+ path: value.path,
42
+ data: value.data
43
+ };
44
+ }
45
+
46
+ // Handle GeoPoint
47
+ if (value instanceof GeoPoint) {
48
+ return {
49
+ __type: "GeoPoint",
50
+ latitude: value.latitude,
51
+ longitude: value.longitude
52
+ };
53
+ }
54
+
55
+ // Handle Vector
56
+ if (value instanceof Vector) {
57
+ return {
58
+ __type: "Vector",
59
+ value: value.value
60
+ };
61
+ }
62
+
63
+ return value;
64
+ }
65
+
66
+ // Define custom reviver for JSON.parse
67
+ function customReviver(_key: string, value: unknown): unknown {
68
+ if (value && typeof value === "object" && "__type" in value) {
69
+ const record = value as Record<string, unknown>;
70
+ switch (record.__type) {
71
+ case "date":
72
+ case "Date":
73
+ return new Date(record.value as string);
74
+ case "reference":
75
+ case "EntityReference":
76
+ return new EntityReference({
77
+ id: record.id as string,
78
+ path: record.path as string,
79
+ driver: record.driver as string | undefined,
80
+ databaseId: record.databaseId as string | undefined
81
+ });
82
+ case "relation":
83
+ case "EntityRelation":
84
+ return new EntityRelation(record.id as string, record.path as string, record.data as Record<string, unknown> | undefined);
85
+ case "GeoPoint":
86
+ return new GeoPoint(record.latitude as number, record.longitude as number);
87
+ case "Vector":
88
+ return new Vector(record.value as number[]);
89
+ default:
90
+ return value;
91
+ }
92
+ }
93
+ return value;
94
+ }
95
+
96
+ // Initialize the in-memory cache by loading entities from `sessionStorage`
97
+ if (isSessionStorageAvailable) {
98
+ try {
99
+ // Iterate over all keys in sessionStorage to find those with the specified prefix
100
+ for (let i = 0; i < sessionStorage.length; i++) {
101
+ const fullKey = sessionStorage.key(i);
102
+ if (fullKey && fullKey.startsWith(LOCAL_STORAGE_PREFIX)) {
103
+ const path = fullKey.substring(LOCAL_STORAGE_PREFIX.length);
104
+ const entityString = sessionStorage.getItem(fullKey);
105
+ if (entityString) {
106
+ try {
107
+ const entity: object = JSON.parse(entityString, customReviver);
108
+ entityCache.set(path, entity);
109
+ } catch (parseError) {
110
+ console.error(
111
+ `Failed to parse entity for path "${path}" from sessionStorage:`,
112
+ parseError
113
+ );
114
+ }
115
+ }
116
+ }
117
+ }
118
+ } catch (error) {
119
+ console.error("Error accessing sessionStorage during initialization:", error);
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Saves data to the in-memory cache and persists it individually in `sessionStorage`.
125
+ * @param path - The unique path/key for the data.
126
+ * @param data - The data to cache and persist.
127
+ */
128
+ export function saveEntityToCache(path: string, data: object): void {
129
+ // Persist the data individually in sessionStorage
130
+ if (isSessionStorageAvailable) {
131
+ try {
132
+ const key = LOCAL_STORAGE_PREFIX + path;
133
+
134
+ const entityString = JSON.stringify(data, customReplacer);
135
+ sessionStorage.setItem(key, entityString);
136
+ } catch (error) {
137
+ console.error(
138
+ `Failed to save entity for path "${path}" to sessionStorage:`,
139
+ error
140
+ );
141
+ }
142
+ }
143
+ }
144
+
145
+ export function removeEntityFromMemoryCache(path: string): void {
146
+ entityCache.delete(path);
147
+ }
148
+
149
+ export function saveEntityToMemoryCache(path: string, data: object): void {
150
+ entityCache.set(path, data);
151
+ }
152
+
153
+ export function getEntityFromMemoryCache(path: string): object | undefined {
154
+ return entityCache.get(path);
155
+ }
156
+
157
+
158
+ /**
159
+ * Retrieves a entity from the in-memory cache or `sessionStorage`.
160
+ * If the entity is not in the cache but exists in `sessionStorage`, it loads it into the cache.
161
+ * @param path - The unique path/key for the entity.
162
+ * @returns The cached entity or `undefined` if not found.
163
+ */
164
+ export function getEntityFromCache(path: string): object | undefined {
165
+
166
+ // If not in the cache, attempt to load it from sessionStorage
167
+ if (isSessionStorageAvailable) {
168
+ try {
169
+ const key = LOCAL_STORAGE_PREFIX + path;
170
+ const entityString = sessionStorage.getItem(key);
171
+ if (entityString) {
172
+ const entity: object = JSON.parse(entityString, customReviver);
173
+ return entity;
174
+ }
175
+ } catch (error) {
176
+ console.error(
177
+ `Failed to load entity for path "${path}" from sessionStorage:`,
178
+ error
179
+ );
180
+ }
181
+ }
182
+
183
+ // Entity not found
184
+ return undefined;
185
+ }
186
+
187
+ /**
188
+ * Removes a entity from both the in-memory cache and `sessionStorage`.
189
+ * @param path - The unique path/key for the entity to remove.
190
+ */
191
+ export function removeEntityFromCache(path: string): void {
192
+
193
+ console.debug("Removing entity from cache", path);
194
+
195
+ // Remove from the in-memory cache
196
+ entityCache.delete(path);
197
+
198
+ // Remove from sessionStorage
199
+ if (isSessionStorageAvailable) {
200
+ try {
201
+ const key = LOCAL_STORAGE_PREFIX + path;
202
+ sessionStorage.removeItem(key);
203
+ } catch (error) {
204
+ console.error(
205
+ `Failed to remove entity for path "${path}" from sessionStorage:`,
206
+ error
207
+ );
208
+ }
209
+ }
210
+ }
211
+
212
+
213
+ export function flattenKeys(obj: Record<string, unknown> | unknown[], prefix = "", result: string[] = []): string[] {
214
+
215
+ if (isObject(obj) || Array.isArray(obj)) {
216
+ const plainObject = isPlainObject(obj);
217
+ if (!plainObject && prefix) {
218
+ result.push(prefix);
219
+ } else {
220
+ const record = obj as Record<string, unknown>;
221
+ for (const key in record) {
222
+ if (Object.prototype.hasOwnProperty.call(record, key)) {
223
+ const newKey = prefix
224
+ ? Array.isArray(obj)
225
+ ? `${prefix}[${key}]`
226
+ : `${prefix}.${key}`
227
+ : key;
228
+ const val = record[key];
229
+ if (isObject(val) || Array.isArray(val)) {
230
+ flattenKeys(val as Record<string, unknown> | unknown[], newKey, result);
231
+ } else {
232
+ result.push(newKey);
233
+ }
234
+ }
235
+ }
236
+ }
237
+ }
238
+ return result;
239
+ }
@@ -0,0 +1,32 @@
1
+ import { EnumValueConfig } from "@rebasepro/types";
2
+ import { CHIP_COLORS, ChipColorScheme, getColorSchemeForSeed } from "@rebasepro/ui";
3
+ import { getLabelOrConfigFrom } from "@rebasepro/common";
4
+
5
+ export function getColorScheme(enumValues: EnumValueConfig[], key: string | number): ChipColorScheme | undefined {
6
+ const labelOrConfig = getLabelOrConfigFrom(enumValues, key);
7
+ if (!labelOrConfig?.color)
8
+ return getColorSchemeForSeed(key.toString());
9
+ if (typeof labelOrConfig === "object" && "color" in labelOrConfig) {
10
+ if (typeof labelOrConfig.color === "string")
11
+ return CHIP_COLORS[labelOrConfig.color];
12
+ if (typeof labelOrConfig.color === "object")
13
+ return labelOrConfig.color;
14
+ }
15
+ return undefined;
16
+ }
17
+
18
+ export function isEnumValueDisabled(labelOrConfig?: string | EnumValueConfig) {
19
+ return typeof labelOrConfig === "object" && (labelOrConfig as EnumValueConfig).disabled;
20
+ }
21
+
22
+ export function buildEnumLabel(
23
+ labelOrConfig?: string | EnumValueConfig
24
+ ): string | undefined {
25
+ if (labelOrConfig === undefined)
26
+ return undefined;
27
+ if (typeof labelOrConfig === "object") {
28
+ return labelOrConfig.label;
29
+ } else {
30
+ return labelOrConfig;
31
+ }
32
+ }
@@ -0,0 +1,22 @@
1
+ const iconSynonyms: Record<string, string> = {};
2
+ import { iconKeys } from "@rebasepro/ui";
3
+ import Fuse from "fuse.js";
4
+
5
+
6
+ const map = iconKeys
7
+ .map((importName) => {
8
+ const iconSynonym = importName in iconSynonyms ? iconSynonyms[importName] : "";
9
+ return {
10
+ key: importName,
11
+ synonyms: iconSynonym
12
+ }
13
+ });
14
+ export const iconsSearch = new Fuse(map, {
15
+ isCaseSensitive: false,
16
+ shouldSort: true,
17
+ ignoreLocation: true,
18
+ distance: 0,
19
+ keys: ["key", "synonyms"]
20
+ })
21
+
22
+
@@ -0,0 +1,149 @@
1
+ import React from "react";
2
+ import {
3
+ cls,
4
+ colorClassesMapping,
5
+ coolIconKeys,
6
+ IconColor,
7
+ iconKeys,
8
+ iconSize,
9
+ lucideIcons
10
+ } from "@rebasepro/ui";
11
+ import { deepEqual as equal } from "fast-equals"
12
+ import { hashString, slugify } from "@rebasepro/utils";
13
+
14
+ // iconKeys are now PascalCase strings (e.g. "ShoppingCart", "Users")
15
+ const iconKeysMap: Record<string, string> = iconKeys.reduce((acc: Record<string, string>, key) => {
16
+ // Also add lowercase versions and snake_case versions to support legacy lookups
17
+ const lower = key.toLowerCase();
18
+ const snake = key.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
19
+ acc[lower] = key;
20
+ acc[snake] = key;
21
+ acc[key] = key;
22
+ return acc;
23
+ }, {});
24
+
25
+ function toPascalCase(str: string): string {
26
+ return str.split(/[-_]/).map(word => word.charAt(0).toUpperCase() + word.slice(1)).join("");
27
+ }
28
+
29
+ /**
30
+ * Resolve a Lucide icon component by string key.
31
+ * Tries direct match, PascalCase conversion, and falls back to CircleAlert.
32
+ */
33
+ function resolveIcon(iconKey: string): React.ComponentType<{ size?: number; className?: string }> | null {
34
+ const iconsMap = lucideIcons as Record<string, React.ComponentType<{ size?: number; className?: string }> | undefined>;
35
+ let icon = iconsMap[iconKey];
36
+ if (!icon) {
37
+ icon = iconsMap[toPascalCase(iconKey)];
38
+ }
39
+ if (!icon) {
40
+ icon = iconsMap.CircleAlert;
41
+ }
42
+ return icon ?? null;
43
+ }
44
+
45
+ /**
46
+ * Render an icon element from a string key or existing React element.
47
+ * This resolves the icon from the lucide-react icons map directly.
48
+ */
49
+ export function getIcon(iconKey?: string | React.ReactNode,
50
+ className?: string,
51
+ color?: IconColor,
52
+ size?: "smallest" | "small" | "medium" | "large" | number): React.ReactElement | undefined {
53
+
54
+ if (React.isValidElement(iconKey)) {
55
+ return iconKey;
56
+ }
57
+
58
+ if (!iconKey) return undefined;
59
+ if (typeof iconKey === "string") {
60
+ const lowerKey = iconKey.toLowerCase();
61
+ const slugifiedKey = slugify(iconKey).replace(/-/g, "_");
62
+
63
+ const mappedKey = iconKeysMap[iconKey] || iconKeysMap[lowerKey] || iconKeysMap[slugifiedKey];
64
+
65
+ if (!mappedKey) {
66
+ return undefined;
67
+ }
68
+
69
+ const LucideIcon = resolveIcon(mappedKey);
70
+ if (!LucideIcon) return undefined;
71
+
72
+ const sizeInPx = typeof size === "number" ? size : iconSize[size ?? "medium"];
73
+ return <LucideIcon
74
+ size={sizeInPx}
75
+ className={cls(
76
+ color ? colorClassesMapping[color] : "",
77
+ "select-none shrink-0",
78
+ className
79
+ )}
80
+ />;
81
+ }
82
+
83
+ console.warn("Invalid icon key provided:", iconKey);
84
+ return undefined;
85
+ }
86
+
87
+ export type IconViewProps = {
88
+ slug: string;
89
+ name: string;
90
+ singularName?: string;
91
+ group?: string;
92
+ icon?: string | React.ReactNode;
93
+ }
94
+
95
+ export const IconForView = React.memo(
96
+ function IconForView({
97
+ collectionOrView,
98
+ className,
99
+ color,
100
+ size = "medium"
101
+ }: {
102
+ collectionOrView?: IconViewProps,
103
+ color?: IconColor,
104
+ className?: string,
105
+ size?: "smallest" | "small" | "medium" | "large" | number,
106
+ }): React.ReactElement {
107
+ if (!collectionOrView) return <></>;
108
+ const icon = getIcon(collectionOrView.icon, className, color, size);
109
+ if (collectionOrView?.icon && icon)
110
+ return icon;
111
+
112
+ let pathname = slugify(("singularName" in collectionOrView ? collectionOrView.singularName : undefined) ?? collectionOrView.name).replace(/-/g, "_");
113
+
114
+ let key: string | undefined;
115
+ if (pathname in iconKeysMap)
116
+ key = iconKeysMap[pathname];
117
+
118
+ if (!key) {
119
+ pathname = slugify(collectionOrView.slug).replace(/-/g, "_");
120
+ if (pathname in iconKeysMap)
121
+ key = iconKeysMap[pathname];
122
+ }
123
+
124
+ const iconsCount = coolIconKeys.length;
125
+
126
+ if (!key)
127
+ key = coolIconKeys[hashString(collectionOrView.slug) % iconsCount];
128
+
129
+ const LucideIcon = resolveIcon(key);
130
+ if (!LucideIcon) return <></>;
131
+
132
+ const sizeInPx = typeof size === "number" ? size : iconSize[size];
133
+ return <LucideIcon
134
+ size={sizeInPx}
135
+ className={cls(
136
+ color ? colorClassesMapping[color] : "",
137
+ "select-none shrink-0",
138
+ className
139
+ )}
140
+ />;
141
+ }, (prevProps, nextProps) => {
142
+ return equal(prevProps.collectionOrView?.icon, nextProps.collectionOrView?.icon) &&
143
+ prevProps.collectionOrView?.name === nextProps.collectionOrView?.name &&
144
+ prevProps.collectionOrView?.slug === nextProps.collectionOrView?.slug &&
145
+ prevProps.collectionOrView?.singularName === nextProps.collectionOrView?.singularName &&
146
+ equal(prevProps.color, nextProps.color) &&
147
+ prevProps.className === nextProps.className &&
148
+ prevProps.size === nextProps.size;
149
+ });
@@ -0,0 +1,12 @@
1
+
2
+ export * from "./icon_list";
3
+
4
+ export * from "./icons";
5
+ export * from "./createFormexStub";
6
+ export * from "./entity_cache";
7
+
8
+ export * from "./useStorageUploadController";
9
+
10
+ export * from "./previews";
11
+ export * from "./enums";
12
+ export * from "./constants";
@@ -0,0 +1,105 @@
1
+ import type { CollectionConfig, Property, PropertyConfig } from "@rebasepro/types";
2
+ import { AuthController } from "@rebasepro/types";
3
+ import { isPropertyBuilder } from "@rebasepro/common";
4
+
5
+ function isReferenceProperty(property: Property) {
6
+ if (!property) return null;
7
+ if (property.type === "reference") return true;
8
+ if (property.type === "array") {
9
+ if (Array.isArray(property.of)) return false;
10
+ else return property.of?.type === "reference";
11
+ }
12
+ return false;
13
+ }
14
+
15
+ function isRelationProperty(property: Property) {
16
+ if (!property) return null;
17
+ if (property.type === "relation") return true;
18
+ if (property.type === "array") {
19
+ if (Array.isArray(property.of)) return false;
20
+ else return property.of?.type === "relation";
21
+ }
22
+ return false;
23
+ }
24
+
25
+ function isHiddenProperty(property: Property | undefined): boolean {
26
+ if (!property) return false;
27
+ return Boolean(property.ui?.hideFromCollection);
28
+ }
29
+
30
+ /**
31
+ * Returns true when the property holds file-storage content (single image,
32
+ * array of images, generic upload, …). These properties are rendered by the
33
+ * dedicated image-slot and should NOT appear as regular preview columns.
34
+ */
35
+ function isStorageProperty(property: Property | undefined): boolean {
36
+ if (!property) return false;
37
+ // Single string with storage config
38
+ if (property.type === "string" && property.storage) return true;
39
+ // String displayed as image URL
40
+ if (property.type === "string" && property.ui?.url === "image") return true;
41
+ // Array whose inner element has storage config or image URL
42
+ if (property.type === "array" && property.of && !Array.isArray(property.of)) {
43
+ const inner = property.of;
44
+ if (inner.type === "string" && (inner.storage || inner.ui?.url === "image")) return true;
45
+ }
46
+ return false;
47
+ }
48
+
49
+ export function getEntityPreviewKeys(
50
+ authController: AuthController,
51
+ targetCollection: CollectionConfig<any>,
52
+ fields: Record<string, PropertyConfig>,
53
+ previewProperties?: string[],
54
+ limit = 3) {
55
+ const allProperties = Object.keys(targetCollection.properties);
56
+ let listProperties = previewProperties?.filter(p => allProperties.includes(p as string));
57
+ if (!listProperties && targetCollection.previewProperties) {
58
+ listProperties = targetCollection.previewProperties?.filter(p => allProperties.includes(p as string));
59
+ }
60
+ if (listProperties && listProperties.length > 0) {
61
+ return listProperties;
62
+ } else {
63
+ listProperties = (targetCollection.propertiesOrder as string[]) || allProperties;
64
+ return listProperties
65
+ .filter(key => {
66
+ const prop = targetCollection.properties[key];
67
+ const isIdProp = prop && typeof prop === "object" && "isId" in prop && Boolean((prop as { isId?: boolean }).isId);
68
+ return !isIdProp && key !== "id";
69
+ })
70
+ .filter(key => {
71
+ const property = targetCollection.properties[key];
72
+ return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isRelationProperty(property) && !isHiddenProperty(property) && !isStorageProperty(property as Property);
73
+ }).slice(0, limit);
74
+ }
75
+ }
76
+
77
+ export function getEntityTitlePropertyKey<M extends Record<string, any>>(collection: CollectionConfig<M>, propertyConfigs: Record<string, PropertyConfig>): string | undefined {
78
+ if (collection.titleProperty) {
79
+ return collection.titleProperty as string;
80
+ }
81
+
82
+ const orderToSearch = (collection.propertiesOrder as string[]) || Object.keys(collection.properties);
83
+ let firstStringCandidate: string | undefined;
84
+
85
+ for (const key of orderToSearch) {
86
+ const property = collection.properties[key];
87
+ if (property && !isPropertyBuilder(property)) {
88
+ const prop = property as Property;
89
+ if (isHiddenProperty(prop)) {
90
+ continue;
91
+ }
92
+ if (prop.type === "string" && !prop.ui?.multiline && !prop.ui?.markdown && !prop.storage && !prop.isId) {
93
+ if (!firstStringCandidate) {
94
+ firstStringCandidate = key;
95
+ }
96
+ const lowerKey = key.toLowerCase();
97
+ if (["name", "title", "label", "displayname", "username"].includes(lowerKey)) {
98
+ return key; // Immediate return if it's a strong title candidate
99
+ }
100
+ }
101
+ }
102
+ }
103
+ return firstStringCandidate;
104
+ }
105
+