@firecms/core 3.0.0-beta.7 → 3.0.0-beta.8

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 (94) hide show
  1. package/dist/app/AppBar.d.ts +12 -0
  2. package/dist/app/Drawer.d.ts +17 -0
  3. package/dist/app/Scaffold.d.ts +30 -0
  4. package/dist/app/index.d.ts +4 -0
  5. package/dist/app/useApp.d.ts +16 -0
  6. package/dist/components/VirtualTable/VirtualTableProps.d.ts +4 -0
  7. package/dist/components/index.d.ts +1 -1
  8. package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +2 -7
  9. package/dist/core/DefaultDrawer.d.ts +19 -0
  10. package/dist/core/EntityEditView.d.ts +17 -3
  11. package/dist/core/NavigationRoutes.d.ts +1 -1
  12. package/dist/core/index.d.ts +2 -2
  13. package/dist/form/PropertiesForm.d.ts +8 -0
  14. package/dist/form/components/FieldHelperText.d.ts +3 -3
  15. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  16. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  17. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +2 -4
  18. package/dist/form/index.d.ts +0 -2
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.es.js +5595 -5574
  21. package/dist/index.es.js.map +1 -1
  22. package/dist/index.umd.js +5 -5
  23. package/dist/index.umd.js.map +1 -1
  24. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  25. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  26. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  27. package/dist/types/auth.d.ts +1 -1
  28. package/dist/types/collections.d.ts +14 -0
  29. package/dist/types/datasource.d.ts +18 -8
  30. package/dist/types/fields.d.ts +31 -30
  31. package/dist/types/plugins.d.ts +11 -3
  32. package/dist/types/properties.d.ts +7 -2
  33. package/dist/util/icons.d.ts +2 -2
  34. package/dist/util/storage.d.ts +23 -2
  35. package/dist/util/useStorageUploadController.d.ts +1 -1
  36. package/package.json +13 -22
  37. package/src/app/AppBar.tsx +18 -0
  38. package/src/app/Drawer.tsx +25 -0
  39. package/src/{core → app}/Scaffold.tsx +61 -107
  40. package/src/app/index.ts +4 -0
  41. package/src/app/useApp.tsx +32 -0
  42. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +7 -9
  43. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -1
  44. package/src/components/EntityCollectionView/EntityCollectionView.tsx +7 -4
  45. package/src/components/VirtualTable/VirtualTable.tsx +3 -1
  46. package/src/components/VirtualTable/VirtualTableProps.tsx +5 -0
  47. package/src/components/common/useTableSearchHelper.ts +52 -12
  48. package/src/components/index.tsx +1 -1
  49. package/src/contexts/DialogsProvider.tsx +2 -2
  50. package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +26 -28
  51. package/src/core/DefaultDrawer.tsx +177 -0
  52. package/src/core/EntityEditView.tsx +669 -129
  53. package/src/core/EntitySidePanel.tsx +0 -1
  54. package/src/core/NavigationRoutes.tsx +3 -3
  55. package/src/core/index.tsx +2 -2
  56. package/src/form/PropertiesForm.tsx +81 -0
  57. package/src/form/PropertyFieldBinding.tsx +29 -5
  58. package/src/form/components/FieldHelperText.tsx +3 -3
  59. package/src/form/components/StorageItemPreview.tsx +19 -10
  60. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
  61. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +5 -4
  62. package/src/form/field_bindings/KeyValueFieldBinding.tsx +40 -35
  63. package/src/form/field_bindings/MapFieldBinding.tsx +11 -3
  64. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +0 -7
  65. package/src/form/field_bindings/RepeatFieldBinding.tsx +10 -7
  66. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +6 -35
  67. package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
  68. package/src/form/index.tsx +4 -4
  69. package/src/form/validation.ts +1 -17
  70. package/src/index.ts +1 -0
  71. package/src/internal/useBuildDataSource.ts +12 -0
  72. package/src/preview/PropertyPreview.tsx +5 -2
  73. package/src/preview/PropertyPreviewProps.tsx +6 -0
  74. package/src/preview/components/ImagePreview.tsx +21 -33
  75. package/src/preview/components/ReferencePreview.tsx +2 -1
  76. package/src/preview/components/StorageThumbnail.tsx +5 -1
  77. package/src/preview/components/UrlComponentPreview.tsx +44 -11
  78. package/src/types/auth.tsx +1 -1
  79. package/src/types/collections.ts +14 -0
  80. package/src/types/customization_controller.tsx +0 -1
  81. package/src/types/datasource.ts +20 -16
  82. package/src/types/fields.tsx +33 -33
  83. package/src/types/plugins.tsx +12 -3
  84. package/src/types/properties.ts +7 -2
  85. package/src/util/entities.ts +4 -3
  86. package/src/util/objects.ts +17 -7
  87. package/src/util/permissions.ts +1 -0
  88. package/src/util/storage.ts +75 -21
  89. package/src/util/useStorageUploadController.tsx +21 -3
  90. package/dist/core/Drawer.d.ts +0 -16
  91. package/dist/core/Scaffold.d.ts +0 -51
  92. package/dist/form/EntityForm.d.ts +0 -77
  93. package/src/core/Drawer.tsx +0 -139
  94. package/src/form/EntityForm.tsx +0 -736
@@ -1,14 +1,6 @@
1
1
  import React, { useCallback } from "react";
2
2
 
3
- import {
4
- ArrayProperty,
5
- Entity,
6
- EntityCollection,
7
- FieldProps,
8
- ResolvedArrayProperty,
9
- ResolvedStringProperty,
10
- StorageConfig
11
- } from "../../types";
3
+ import { ArrayProperty, FieldProps, ResolvedArrayProperty, ResolvedStringProperty, StorageConfig } from "../../types";
12
4
  import { useDropzone } from "react-dropzone";
13
5
  import { PreviewSize } from "../../preview";
14
6
  import { FieldHelperText, LabelWithIcon } from "../components";
@@ -31,7 +23,7 @@ import { useClearRestoreValue } from "../useClearRestoreValue";
31
23
 
32
24
  const dropZoneClasses = "box-border relative pt-[2px] items-center border border-transparent min-h-[254px] outline-none rounded-md duration-200 ease-[cubic-bezier(0.4,0,0.2,1)] focus:border-primary-solid";
33
25
  const disabledClasses = "border-dotted-gray"
34
- const nonActiveDropClasses = "hover:bg-field-hover dark:hover:bg-field-hover-dark"
26
+ const nonActiveDropClasses = fieldBackgroundHoverMixin
35
27
  const activeDropClasses = "pt-0 border-2 border-solid"
36
28
  const acceptDropClasses = "transition-colors duration-200 ease-[cubic-bezier(0,0,0.2,1)] border-2 border-solid border-green-500"
37
29
  const rejectDropClasses = "transition-colors duration-200 ease-[cubic-bezier(0,0,0.2,1)] border-2 border-solid border-red-500"
@@ -81,7 +73,7 @@ export function StorageUploadFieldBinding({
81
73
  propertyKey,
82
74
  value,
83
75
  storageSource,
84
- disabled,
76
+ disabled: disabled ?? false,
85
77
  onChange: setValue
86
78
  });
87
79
 
@@ -91,12 +83,6 @@ export function StorageUploadFieldBinding({
91
83
  setValue
92
84
  });
93
85
 
94
- const entity: Entity<any> = {
95
- id: context.entityId,
96
- values: context.values,
97
- path: context.path
98
- };
99
-
100
86
  return (
101
87
 
102
88
  <>
@@ -109,15 +95,13 @@ export function StorageUploadFieldBinding({
109
95
 
110
96
  <StorageUpload
111
97
  value={internalValue}
112
- collection={context.collection}
113
98
  name={propertyKey}
114
- disabled={disabled}
115
- autoFocus={autoFocus}
99
+ disabled={disabled ?? false}
100
+ autoFocus={autoFocus ?? false}
116
101
  property={property}
117
102
  onChange={setValue}
118
103
  setInternalValue={setInternalValue}
119
104
  onFilesAdded={onFilesAdded}
120
- entity={entity}
121
105
  onFileUploadComplete={onFileUploadComplete}
122
106
  storagePathBuilder={storagePathBuilder}
123
107
  storage={storage}
@@ -135,7 +119,6 @@ export function StorageUploadFieldBinding({
135
119
 
136
120
  function FileDropComponent({
137
121
  storage,
138
- collection,
139
122
  disabled,
140
123
  isDraggingOver,
141
124
  onFilesAdded,
@@ -144,7 +127,6 @@ function FileDropComponent({
144
127
  autoFocus,
145
128
  internalValue,
146
129
  property,
147
- entity,
148
130
  onClear,
149
131
  metadata,
150
132
  storagePathBuilder,
@@ -154,7 +136,6 @@ function FileDropComponent({
154
136
  helpText
155
137
  }: {
156
138
  storage: StorageConfig,
157
- collection: EntityCollection,
158
139
  disabled: boolean,
159
140
  isDraggingOver: boolean,
160
141
  droppableProvided: any,
@@ -165,7 +146,6 @@ function FileDropComponent({
165
146
  property: ResolvedStringProperty,
166
147
  onClear: (clearedStoragePathOrDownloadUrl: string) => void,
167
148
  metadata: any,
168
- entity: Entity<any>;
169
149
  storagePathBuilder: (file: File) => string,
170
150
  onFileUploadComplete: (uploadedPath: string, entry: StorageFieldItem, fileMetadata?: any) => Promise<void>,
171
151
  size: PreviewSize,
@@ -235,11 +215,9 @@ function FileDropComponent({
235
215
  if (entry.storagePathOrDownloadUrl) {
236
216
  child = (
237
217
  <StorageItemPreview
238
- collection={collection}
239
218
  name={`storage_preview_${entry.storagePathOrDownloadUrl}`}
240
219
  property={property}
241
220
  disabled={disabled}
242
- entity={entity}
243
221
  value={entry.storagePathOrDownloadUrl}
244
222
  onRemove={onClear}
245
223
  size={entry.size}/>
@@ -299,7 +277,6 @@ function FileDropComponent({
299
277
 
300
278
  export interface StorageUploadProps {
301
279
  value: StorageFieldItem[];
302
- collection: EntityCollection;
303
280
  setInternalValue: (v: StorageFieldItem[]) => void;
304
281
  name: string;
305
282
  property: ResolvedStringProperty | ResolvedArrayProperty<string[]>;
@@ -307,7 +284,6 @@ export interface StorageUploadProps {
307
284
  multipleFilesSupported: boolean;
308
285
  autoFocus: boolean;
309
286
  disabled: boolean;
310
- entity: Entity<any>;
311
287
  storage: StorageConfig;
312
288
  onFilesAdded: (acceptedFiles: File[]) => void;
313
289
  storagePathBuilder: (file: File) => string;
@@ -315,7 +291,6 @@ export interface StorageUploadProps {
315
291
  }
316
292
 
317
293
  export function StorageUpload({
318
- collection,
319
294
  property,
320
295
  name,
321
296
  value,
@@ -327,7 +302,6 @@ export function StorageUpload({
327
302
  onFilesAdded,
328
303
  autoFocus,
329
304
  storage,
330
- entity,
331
305
  storagePathBuilder,
332
306
  }: StorageUploadProps) {
333
307
 
@@ -408,11 +382,10 @@ export function StorageUpload({
408
382
  className="rounded"
409
383
  >
410
384
  <StorageItemPreview
411
- collection={collection}
412
385
  name={`storage_preview_${entry.storagePathOrDownloadUrl}`}
386
+ placeholder={true}
413
387
  property={renderProperty}
414
388
  disabled={true}
415
- entity={entity}
416
389
  value={entry.storagePathOrDownloadUrl as string}
417
390
  onRemove={onClear}
418
391
  size={entry.size}/>
@@ -422,7 +395,6 @@ export function StorageUpload({
422
395
  >
423
396
  {(provided, snapshot) => {
424
397
  return <FileDropComponent storage={storage}
425
- collection={collection}
426
398
  disabled={disabled}
427
399
  isDraggingOver={snapshot.isDraggingOver}
428
400
  droppableProvided={provided}
@@ -431,7 +403,6 @@ export function StorageUpload({
431
403
  autoFocus={autoFocus}
432
404
  internalValue={value}
433
405
  property={renderProperty}
434
- entity={entity}
435
406
  onClear={onClear}
436
407
  metadata={metadata}
437
408
  storagePathBuilder={storagePathBuilder}
@@ -46,7 +46,7 @@ export const SwitchFieldBinding = React.forwardRef(function SwitchFieldBinding({
46
46
  title={property.name}/>}
47
47
  disabled={disabled}
48
48
  autoFocus={autoFocus}
49
- size={"medium"}
49
+ size={"large"}
50
50
  />
51
51
 
52
52
  <FieldHelperText includeDescription={includeDescription}
@@ -34,10 +34,10 @@ export {
34
34
 
35
35
  export * from "./components";
36
36
 
37
- export type { EntityFormProps } from "./EntityForm";
38
- export {
39
- EntityForm
40
- } from "./EntityForm";
37
+ // export type { EntityFormProps } from "./EntityForm";
38
+ // export {
39
+ // EntityForm
40
+ // } from "./EntityForm";
41
41
 
42
42
  export { PropertyFieldBinding } from "./PropertyFieldBinding";
43
43
  export * from "./useClearRestoreValue";
@@ -112,23 +112,7 @@ export function getYupMapObjectSchema({
112
112
  if (validation?.required) {
113
113
  return shape.required(validation?.requiredMessage ? validation.requiredMessage : "Required").nullable(true);
114
114
  }
115
- return shape.nullable(true);
116
- // const object: ObjectSchema<any> = yup.object().shape(objectSchema);
117
- // return validation?.required
118
- // ? object.required(validation?.requiredMessage ? validation.requiredMessage : "Required").nullable(true)
119
- // : yup.object().optional().default(undefined).notRequired().nullable(true).test(
120
- // "empty-check",
121
- // "Optional map can be empty",
122
- // (o: any, testContext: any) => {
123
- // try {
124
- // if (!o || Object.keys(o).length === 0) return true;
125
- // return object.validateSync(o);
126
- // } catch (e) {
127
- // testContext.createError(e);
128
- // console.error(e);
129
- // return false;
130
- // }
131
- // });
115
+ return yup.object().shape(shape.fields).default(undefined).notRequired().nullable(true);
132
116
  }
133
117
 
134
118
  function getYupStringSchema({
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./core";
2
+ export * from "./app";
2
3
  export * from "./types";
3
4
  export * from "./form";
4
5
  export * from "./preview";
@@ -9,6 +9,7 @@ import {
9
9
  FetchCollectionProps,
10
10
  FetchEntityProps,
11
11
  FilterValues,
12
+ FireCMSContext,
12
13
  ListenCollectionProps,
13
14
  ListenEntityProps,
14
15
  NavigationController,
@@ -313,6 +314,17 @@ export function useBuildDataSource({
313
314
  )
314
315
  }, [delegate.isFilterCombinationValid]),
315
316
 
317
+ initTextSearch: useCallback(async (props: {
318
+ context: FireCMSContext,
319
+ path: string,
320
+ collection: EntityCollection,
321
+ parentCollectionIds?: string[]
322
+ }): Promise<boolean> => {
323
+ if (!delegate.initTextSearch)
324
+ return false;
325
+ return delegate.initTextSearch(props)
326
+ }, [delegate.initTextSearch]),
327
+
316
328
  };
317
329
 
318
330
  }
@@ -47,7 +47,7 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
47
47
  size,
48
48
  height,
49
49
  width,
50
- // entity
50
+ interactive
51
51
  } = props;
52
52
 
53
53
  const property = resolveProperty({
@@ -84,12 +84,15 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
84
84
  content =
85
85
  <UrlComponentPreview size={props.size}
86
86
  url={value}
87
+ interactive={interactive}
87
88
  previewType={stringProperty.url}/>;
88
89
  } else if (stringProperty.storage) {
90
+ const filePath = stringProperty.storage.previewUrl ? stringProperty.storage.previewUrl(value) : value;
89
91
  content = <StorageThumbnail
92
+ interactive={interactive}
90
93
  storeUrl={property.storage?.storeUrl ?? false}
91
94
  size={props.size}
92
- storagePathOrDownloadUrl={value}/>;
95
+ storagePathOrDownloadUrl={filePath}/>;
93
96
  } else if (stringProperty.markdown) {
94
97
  content = <Markdown source={value} size={"small"}/>;
95
98
  } else {
@@ -46,4 +46,10 @@ export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any
46
46
  */
47
47
  customProps?: CustomProps;
48
48
 
49
+ /**
50
+ * If the preview should be interactive or not.
51
+ * This applies only to videos.
52
+ */
53
+ interactive?: boolean;
54
+
49
55
  }
@@ -1,4 +1,4 @@
1
- import React, { CSSProperties, useMemo, useState } from "react";
1
+ import React, { CSSProperties, useMemo } from "react";
2
2
 
3
3
  import { getThumbnailMeasure } from "../util";
4
4
  import { PreviewSize } from "../PropertyPreviewProps";
@@ -20,8 +20,6 @@ export function ImagePreview({
20
20
  url
21
21
  }: ImagePreviewProps) {
22
22
 
23
- const [onHover, setOnHover] = useState(false);
24
-
25
23
  const imageSize = useMemo(() => getThumbnailMeasure(size), [size]);
26
24
 
27
25
  if (size === "tiny") {
@@ -47,60 +45,50 @@ export function ImagePreview({
47
45
 
48
46
  return (
49
47
  <div
50
- className="relative flex items-center justify-center max-w-full max-h-full"
48
+ className="relative flex items-center justify-center max-w-full max-h-full group"
51
49
  style={{
52
50
  width: imageSize,
53
51
  height: imageSize
54
52
  }}
55
- key={"image_preview_" + url}
56
- onMouseEnter={() => setOnHover(true)}
57
- onMouseMove={() => setOnHover(true)}
58
- onMouseLeave={() => setOnHover(false)}>
53
+ key={"image_preview_" + url}>
59
54
 
60
55
  <img src={url}
61
56
  className={"rounded-md"}
62
57
  style={imageStyle}/>
63
58
 
64
- {onHover && <>
65
59
 
66
- {navigator && <Tooltip title="Copy url to clipboard">
67
- <div
68
- className="rounded-full absolute bottom-[-4px] right-8">
69
- <IconButton
70
- variant={"filled"}
71
- size={"small"}
72
- onClick={(e) => {
73
- e.stopPropagation();
74
- e.preventDefault();
75
- return navigator.clipboard.writeText(url);
76
- }}>
77
- <ContentCopyIcon className={"text-gray-500"}
78
- size={"small"}/>
79
- </IconButton>
80
- </div>
60
+ <div className={"flex flex-row gap-2 absolute bottom-[-4px] right-[-4px] invisible group-hover:visible"}>
61
+ {navigator && <Tooltip title="Copy url to clipboard" side={"bottom"}>
62
+ <IconButton
63
+ variant={"filled"}
64
+ size={"small"}
65
+ onClick={(e) => {
66
+ e.stopPropagation();
67
+ e.preventDefault();
68
+ return navigator.clipboard.writeText(url);
69
+ }}>
70
+ <ContentCopyIcon className={"text-gray-700 dark:text-gray-300"}
71
+ size={"small"}/>
72
+ </IconButton>
81
73
  </Tooltip>}
82
74
 
83
- <Tooltip title="Open image in new tab">
75
+ <Tooltip title="Open image in new tab" side={"bottom"}>
84
76
  <IconButton
77
+ className="invisible group-hover:visible"
85
78
  variant={"filled"}
86
79
  component={"a" as React.ElementType}
87
- style={{
88
- position: "absolute",
89
- bottom: -4,
90
- right: -4
91
- }}
92
80
  href={url}
93
81
  rel="noopener noreferrer"
94
82
  target="_blank"
95
83
  size={"small"}
96
84
  onClick={(e: any) => e.stopPropagation()}
97
85
  >
98
- <OpenInNewIcon className={"text-gray-500"}
86
+ <OpenInNewIcon className={"text-gray-700 dark:text-gray-300"}
99
87
  size={"small"}/>
100
88
  </IconButton>
101
89
  </Tooltip>
102
- </>
103
- }
90
+ </div>
91
+
104
92
  </div>
105
93
  );
106
94
  }
@@ -41,7 +41,8 @@ function areEqual(prevProps: ReferencePreviewProps, nextProps: ReferencePreviewP
41
41
  prevProps.hover === nextProps.hover &&
42
42
  prevProps.reference?.id === nextProps.reference?.id &&
43
43
  prevProps.reference?.path === nextProps.reference?.path &&
44
- prevProps.includeEntityLink === nextProps.includeEntityLink
44
+ prevProps.includeEntityLink === nextProps.includeEntityLink &&
45
+ prevProps.onClick === nextProps.onClick
45
46
  ;
46
47
  }
47
48
 
@@ -11,6 +11,7 @@ type StorageThumbnailProps = {
11
11
  storagePathOrDownloadUrl: string;
12
12
  storeUrl: boolean;
13
13
  size: PreviewSize;
14
+ interactive?: boolean;
14
15
  };
15
16
 
16
17
  /**
@@ -21,13 +22,15 @@ export const StorageThumbnail = React.memo<StorageThumbnailProps>(StorageThumbna
21
22
  function areEqual(prevProps: StorageThumbnailProps, nextProps: StorageThumbnailProps) {
22
23
  return prevProps.size === nextProps.size &&
23
24
  prevProps.storagePathOrDownloadUrl === nextProps.storagePathOrDownloadUrl &&
24
- prevProps.storeUrl === nextProps.storeUrl;
25
+ prevProps.storeUrl === nextProps.storeUrl&&
26
+ prevProps.interactive === nextProps.interactive;
25
27
  }
26
28
 
27
29
  const URL_CACHE: Record<string, DownloadConfig> = {};
28
30
 
29
31
  export function StorageThumbnailInternal({
30
32
  storeUrl,
33
+ interactive,
31
34
  storagePathOrDownloadUrl,
32
35
  size
33
36
  }: StorageThumbnailProps) {
@@ -68,6 +71,7 @@ export function StorageThumbnailInternal({
68
71
  return downloadConfig?.url
69
72
  ? <UrlComponentPreview previewType={previewType}
70
73
  url={downloadConfig.url}
74
+ interactive={interactive}
71
75
  size={size}
72
76
  hint={storagePathOrDownloadUrl}/>
73
77
  : renderSkeletonImageThumbnail(size);
@@ -1,10 +1,10 @@
1
- import React from "react";
1
+ import React, { useMemo } from "react";
2
2
 
3
3
  import { ImagePreview } from "./ImagePreview";
4
4
  import { getThumbnailMeasure } from "../util";
5
5
  import { PreviewType } from "../../types";
6
6
  import { PreviewSize } from "../PropertyPreviewProps";
7
- import { DescriptionIcon, OpenInNewIcon, Tooltip, Typography } from "@firecms/ui";
7
+ import { cls, DescriptionIcon, OpenInNewIcon, Tooltip, Typography } from "@firecms/ui";
8
8
  import { EmptyValue } from "./EmptyValue";
9
9
 
10
10
  /**
@@ -14,12 +14,15 @@ export function UrlComponentPreview({
14
14
  url,
15
15
  previewType,
16
16
  size,
17
- hint
17
+ hint,
18
+ interactive = true
18
19
  }: {
19
20
  url: string,
20
21
  previewType?: PreviewType,
21
22
  size: PreviewSize,
22
- hint?: string
23
+ hint?: string,
24
+ // for video controls
25
+ interactive?: boolean
23
26
  }): React.ReactElement {
24
27
 
25
28
  if (!previewType) {
@@ -43,17 +46,13 @@ export function UrlComponentPreview({
43
46
  size={size}/>;
44
47
  } else if (previewType === "audio") {
45
48
  return <audio controls
49
+ className={"max-w-100%"}
46
50
  src={url}>
47
51
  Your browser does not support the
48
52
  <code>audio</code> element.
49
53
  </audio>;
50
54
  } else if (previewType === "video") {
51
- return <video
52
- className={`max-w-${size === "small" ? "sm" : "md"}`}
53
- controls
54
- >
55
- <source src={url}/>
56
- </video>;
55
+ return <VideoPreview size={size} src={url} interactive={interactive}/>;
57
56
  } else {
58
57
  return (
59
58
  <a
@@ -66,7 +65,7 @@ export function UrlComponentPreview({
66
65
  width: getThumbnailMeasure(size),
67
66
  height: getThumbnailMeasure(size)
68
67
  }}>
69
- <DescriptionIcon className="flex-grow"/>
68
+ <DescriptionIcon className="text-gray-700 dark:text-gray-300"/>
70
69
  {hint &&
71
70
  <Tooltip title={hint}>
72
71
  <Typography
@@ -77,3 +76,37 @@ export function UrlComponentPreview({
77
76
  );
78
77
  }
79
78
  }
79
+
80
+ function VideoPreview({
81
+ size,
82
+ src,
83
+ interactive
84
+ }: { size: PreviewSize, src: string, interactive: boolean }) {
85
+
86
+ const imageSize = useMemo(() => {
87
+ if (size === "tiny")
88
+ return "140px";
89
+ else if (size === "small")
90
+ return "240px";
91
+ else if (size === "medium")
92
+ return "100%";
93
+ else throw new Error("Invalid size");
94
+ }, [size]);
95
+
96
+ const videoProps = {
97
+ controls: interactive
98
+ };
99
+ return <video
100
+ style={{
101
+ position: "relative",
102
+ objectFit: "cover",
103
+ width: imageSize,
104
+ minWidth: "140px",
105
+ // height: imageSize,
106
+ maxHeight: "100%"
107
+ }}
108
+ {...videoProps}
109
+ className={cls("max-w-100% rounded", { "pointer-events-none": !interactive })}>
110
+ <source src={src}/>
111
+ </video>;
112
+ }
@@ -38,7 +38,7 @@ export type AuthController<UserType extends User = any, ExtraData extends any =
38
38
  /**
39
39
  * Sign out
40
40
  */
41
- signOut: () => void;
41
+ signOut: () => Promise<void>;
42
42
 
43
43
  /**
44
44
  * Error initializing the authentication
@@ -477,8 +477,22 @@ export interface AdditionalFieldDelegate<M extends Record<string, any> = any,
477
477
  */
478
478
  export type EntityCustomView<M extends Record<string, any> = any> =
479
479
  {
480
+ /**
481
+ * Key of this custom view.
482
+ */
480
483
  key: string,
484
+ /**
485
+ * Name of this custom view.
486
+ */
481
487
  name: string,
488
+ /**
489
+ * If set to true, the actions of the entity will be included in the
490
+ * bottom of the panel (save buttons, delete buttons, etc.)
491
+ */
492
+ includeActions?: boolean;
493
+ /**
494
+ * Builder for rendering the custom view
495
+ */
482
496
  Builder?: React.ComponentType<EntityCustomViewParams<M>>;
483
497
  }
484
498
 
@@ -24,7 +24,6 @@ export type CustomizationController = {
24
24
  *
25
25
  * You can also define an entity view from the UI.
26
26
  */
27
-
28
27
  entityViews?: EntityCustomView[];
29
28
 
30
29
  /**
@@ -1,6 +1,7 @@
1
1
  import { Entity, EntityReference, EntityStatus, EntityValues, GeoPoint } from "./entities";
2
2
  import { EntityCollection, FilterValues } from "./collections";
3
3
  import { ResolvedEntityCollection } from "./resolved_entities";
4
+ import { FireCMSContext } from "./firecms_context";
4
5
 
5
6
  /**
6
7
  * @group Datasource
@@ -217,6 +218,18 @@ export interface DataSource {
217
218
  */
218
219
  isFilterCombinationValid?(props: FilterCombinationValidProps): boolean;
219
220
 
221
+ /**
222
+ * Called when the user clicks on the search bar in a collection view.
223
+ * Useful for initializing a text search index.
224
+ * @param props
225
+ */
226
+ initTextSearch?: (props: {
227
+ context: FireCMSContext,
228
+ path: string,
229
+ collection: EntityCollection,
230
+ parentCollectionIds?: string[]
231
+ }) => Promise<boolean>;
232
+
220
233
  }
221
234
 
222
235
  export type FilterCombinationValidProps = {
@@ -363,30 +376,21 @@ export interface DataSourceDelegate {
363
376
  */
364
377
  isFilterCombinationValid?(props: Omit<FilterCombinationValidProps, "collection">): boolean;
365
378
 
366
- /**
367
- * Convert a FireCMS reference to a reference that can be used by the datasource
368
- * @param reference
369
- */
370
- // buildReference: (reference: EntityReference) => any,
371
-
372
- /**
373
- * Convert a FireCMS GeoPoint to a GeoPoint that can be used by the datasource
374
- * @param geoPoint
375
- */
376
- // buildGeoPoint: (geoPoint: GeoPoint) => any,
377
-
378
379
  /**
379
380
  * Get the object to generate the current time in the datasource
380
381
  */
381
382
  currentTime(): any;
382
383
 
383
- // buildDate: (date: Date) => any;
384
-
385
- // buildDeleteFieldValue: () => any;
386
-
387
384
  delegateToCMSModel: (data: any) => any;
388
385
 
389
386
  cmsToDelegateModel: (data: any) => any;
390
387
 
391
388
  setDateToMidnight: (input?: any) => any;
389
+
390
+ initTextSearch?: (props: {
391
+ context: FireCMSContext,
392
+ path: string,
393
+ collection: EntityCollection,
394
+ parentCollectionIds?: string[]
395
+ }) => Promise<boolean>;
392
396
  }