@firecms/core 3.0.0-tw4.6 → 3.0.1

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 (35) hide show
  1. package/README.md +1 -1
  2. package/dist/components/VirtualTable/VirtualTable.performance.test.d.ts +1 -0
  3. package/dist/form/components/LocalChangesMenu.d.ts +2 -2
  4. package/dist/form/components/StorageUploadProgress.d.ts +1 -1
  5. package/dist/index.es.js +218 -238
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/index.umd.js +218 -238
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/types/entities.d.ts +1 -0
  10. package/dist/types/properties.d.ts +9 -0
  11. package/dist/types/storage.d.ts +8 -0
  12. package/dist/util/useStorageUploadController.d.ts +1 -1
  13. package/package.json +6 -5
  14. package/src/app/Scaffold.tsx +1 -1
  15. package/src/components/ArrayContainer.tsx +1 -1
  16. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +1 -1
  17. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +3 -3
  18. package/src/components/EntityPreview.tsx +1 -1
  19. package/src/components/ReferenceWidget.tsx +1 -1
  20. package/src/components/SelectableTable/SelectableTable.tsx +1 -1
  21. package/src/components/VirtualTable/VirtualTable.performance.test.tsx +386 -0
  22. package/src/components/VirtualTable/VirtualTable.tsx +3 -3
  23. package/src/components/VirtualTable/VirtualTableHeader.tsx +1 -1
  24. package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
  25. package/src/core/DefaultDrawer.tsx +1 -1
  26. package/src/core/DrawerNavigationItem.tsx +3 -4
  27. package/src/form/EntityForm.tsx +3 -10
  28. package/src/form/components/LocalChangesMenu.tsx +6 -6
  29. package/src/form/components/StorageUploadProgress.tsx +4 -3
  30. package/src/preview/components/EmptyValue.tsx +1 -1
  31. package/src/preview/components/ReferencePreview.tsx +6 -1
  32. package/src/types/entities.ts +10 -0
  33. package/src/types/properties.ts +10 -0
  34. package/src/types/storage.ts +9 -0
  35. package/src/util/useStorageUploadController.tsx +11 -1
@@ -328,14 +328,7 @@ export function EntityForm<M extends Record<string, any>>({
328
328
  return [initialValues, initialDirty];
329
329
  }, [autoApplyLocalChanges, localChangesDataRaw, baseInitialValues, initialDirtyValues]);
330
330
 
331
- const localChangesData = useMemo(() => {
332
- if (!localChangesDataRaw) {
333
- return undefined;
334
- }
335
- return getChanges(localChangesDataRaw, initialValues);
336
- }, [localChangesDataRaw, initialValues]);
337
-
338
- const hasLocalChanges = !localChangesCleared && localChangesData && Object.keys(localChangesData).length > 0;
331
+ const hasLocalChanges = !localChangesCleared && localChangesDataRaw && Object.keys(localChangesDataRaw).length > 0;
339
332
 
340
333
  const formex: FormexController<M> = formexProp ?? useCreateFormex<M>({
341
334
  initialValues: initialValues as M,
@@ -851,7 +844,7 @@ export function EntityForm<M extends Record<string, any>>({
851
844
  <LocalChangesMenu
852
845
  cacheKey={status === "new" || status === "copy" ? path + "#new" : path + "/" + entityId}
853
846
  properties={resolvedCollection.properties}
854
- localChangesData={localChangesData as Partial<M>}
847
+ cachedData={localChangesDataRaw as Partial<M>}
855
848
  formex={formex}
856
849
  onClearLocalChanges={() => setLocalChangesCleared(true)}
857
850
  />}
@@ -863,7 +856,7 @@ export function EntityForm<M extends Record<string, any>>({
863
856
  </Chip>
864
857
  </Tooltip>
865
858
  : <Tooltip title={"The current form is in sync with the database"}>
866
- <Chip size={"small"} className={"py-1"} >
859
+ <Chip size={"small"} className={"py-1"}>
867
860
  <CheckIcon size={"smallest"}/>
868
861
  </Chip>
869
862
  </Tooltip>}
@@ -24,14 +24,14 @@ import { PropertyCollectionView } from "../../components/PropertyCollectionView"
24
24
 
25
25
  interface LocalChangesMenuProps<M extends object> {
26
26
  cacheKey: string;
27
- localChangesData: Partial<M>;
27
+ cachedData: Partial<M>;
28
28
  formex: FormexController<M>;
29
29
  onClearLocalChanges?: () => void;
30
30
  properties: ResolvedProperties<M>;
31
31
  }
32
32
 
33
33
  export function LocalChangesMenu<M extends object>({
34
- localChangesData,
34
+ cachedData,
35
35
  formex,
36
36
  onClearLocalChanges,
37
37
  cacheKey,
@@ -51,10 +51,10 @@ export function LocalChangesMenu<M extends object>({
51
51
  };
52
52
 
53
53
  const handleApply = () => {
54
- const mergedValues = mergeDeep(formex.values, localChangesData);
54
+ const mergedValues = mergeDeep(formex.values, cachedData);
55
55
  const touched = { ...formex.touched };
56
- const previewKeys = flattenKeys(localChangesData);
57
- previewKeys.forEach((key) => {
56
+ const cachedKeys = flattenKeys(cachedData);
57
+ cachedKeys.forEach((key) => {
58
58
  touched[key] = true;
59
59
  });
60
60
 
@@ -121,7 +121,7 @@ export function LocalChangesMenu<M extends object>({
121
121
  overflow: "auto"
122
122
  }}>
123
123
  <div className="p-4">
124
- <PropertyCollectionView data={localChangesData}
124
+ <PropertyCollectionView data={cachedData}
125
125
  properties={properties as ResolvedProperties}/>
126
126
  </div>
127
127
  </div>
@@ -11,7 +11,8 @@ export interface StorageUploadItemProps {
11
11
  entry: StorageFieldItem,
12
12
  onFileUploadComplete: (value: string,
13
13
  entry: StorageFieldItem,
14
- metadata?: any) => Promise<void>;
14
+ metadata?: any,
15
+ uploadedUrl?: string) => Promise<void>;
15
16
  imageSize: number;
16
17
  simple: boolean;
17
18
  }
@@ -47,9 +48,9 @@ export function StorageUploadProgress({
47
48
  path: storagePath,
48
49
  metadata
49
50
  })
50
- .then(async ({ path }) => {
51
+ .then(async ({ path, storageUrl }) => {
51
52
  console.debug("Upload successful", path);
52
- await onFileUploadComplete(path, entry, metadata);
53
+ await onFileUploadComplete(path, entry, metadata, storageUrl);
53
54
  if (mounted.current)
54
55
  setLoading(false);
55
56
  })
@@ -6,5 +6,5 @@ import React from "react";
6
6
  export function EmptyValue() {
7
7
 
8
8
  return <div
9
- className="rounded-full bg-surface-200 bg-opacity-30 bg-surface-200/30 dark:bg-opacity-20 dark:bg-surface-200/20 w-5 h-2 inline-block"/>;
9
+ className="rounded-full bg-surface-200 bg-opacity-30 dark:bg-opacity-20 w-5 h-2 inline-block"/>;
10
10
  }
@@ -57,7 +57,12 @@ function ReferencePreviewInternal({
57
57
  if (customizationController.components?.missingReference) {
58
58
  return <customizationController.components.missingReference path={reference.path}/>;
59
59
  } else {
60
- throw Error(`Couldn't find the corresponding collection view for the path: ${reference.path}`);
60
+ return <EntityPreviewContainer
61
+ onClick={onClick}
62
+ size={size ?? "medium"}>
63
+ <ErrorView error={"Unexpected reference value. Click to edit"}
64
+ tooltip={reference.pathWithId}/>
65
+ </EntityPreviewContainer>;
61
66
  }
62
67
  }
63
68
 
@@ -65,6 +65,16 @@ export class EntityReference {
65
65
  return `${this.path}/${this.id}`;
66
66
  }
67
67
 
68
+ get pathWithIdAndDatabase() {
69
+ if (this.databaseId) {
70
+ if (this.databaseId === "(default)") {
71
+ return this.pathWithId;
72
+ }
73
+ return `${this.databaseId}:::${this.path}/${this.id}`;
74
+ }
75
+ return this.pathWithId;
76
+ }
77
+
68
78
  isEntityReference() {
69
79
  return true;
70
80
  }
@@ -828,6 +828,16 @@ export type StorageConfig = {
828
828
  */
829
829
  storagePath: string | ((context: UploadedFileContext) => string);
830
830
 
831
+ /**
832
+ * When set to true, this flag indicates that the bucket name will be
833
+ * included in the saved storage path.
834
+ *
835
+ * E.g. `gs://my-bucket/path/to/file.png` instead of just `path/to/file.png`
836
+ *
837
+ * Defaults to false.
838
+ */
839
+ includeBucketUrl?: boolean;
840
+
831
841
  /**
832
842
  * When set to true, this flag indicates that the download URL of the file
833
843
  * will be saved in the datasource, instead of the storage path.
@@ -21,6 +21,15 @@ export interface UploadFileResult {
21
21
  * Bucket where the file was uploaded
22
22
  */
23
23
  bucket: string;
24
+
25
+ /**
26
+ * Fully qualified storage URL for the uploaded file.
27
+ *
28
+ * For example: `gs://my-bucket/path/to/file.png`.
29
+ *
30
+ * This is optional for backwards compatibility.
31
+ */
32
+ storageUrl?: string;
24
33
  }
25
34
 
26
35
  /**
@@ -134,11 +134,21 @@ export function useStorageUploadController<M extends object>({
134
134
 
135
135
  const onFileUploadComplete = useCallback(async (uploadedPath: string,
136
136
  entry: StorageFieldItem,
137
- metadata?: any) => {
137
+ metadata?: any,
138
+ uploadedUrl?: string) => {
138
139
 
139
140
  console.debug("onFileUploadComplete", uploadedPath, entry);
140
141
 
141
142
  let uploadPathOrDownloadUrl: string | null = uploadedPath;
143
+
144
+ if (storage.includeBucketUrl) {
145
+ if (!uploadedUrl) {
146
+ console.warn("includeBucketUrl is set but no fully-qualified storage URL was returned by the StorageSource. Falling back to the storage path.");
147
+ } else {
148
+ uploadPathOrDownloadUrl = uploadedUrl;
149
+ }
150
+ }
151
+
142
152
  if (storage.storeUrl) {
143
153
  uploadPathOrDownloadUrl = (await storageSource.getDownloadURL(uploadedPath)).url;
144
154
  }