@firecms/core 3.0.0-canary.218 → 3.0.0-canary.219

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.
@@ -143,6 +143,7 @@ export interface FormContext<M extends Record<string, any> = any> {
143
143
  * operate with it
144
144
  */
145
145
  formex: FormexController<M>;
146
+ disabled: boolean;
146
147
  }
147
148
  /**
148
149
  * In case you need to render a field bound to a Property inside your
@@ -159,6 +159,7 @@ export interface PluginFormActionProps<USER extends User = User, EC extends Enti
159
159
  path: string;
160
160
  status: EntityStatus;
161
161
  collection: EC;
162
+ disabled: boolean;
162
163
  formContext?: FormContext<any>;
163
164
  context: FireCMSContext<USER>;
164
165
  currentEntityId?: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@firecms/core",
3
3
  "type": "module",
4
- "version": "3.0.0-canary.218",
4
+ "version": "3.0.0-canary.219",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/firecmsco"
@@ -50,9 +50,9 @@
50
50
  "./package.json": "./package.json"
51
51
  },
52
52
  "dependencies": {
53
- "@firecms/editor": "^3.0.0-canary.218",
54
- "@firecms/formex": "^3.0.0-canary.218",
55
- "@firecms/ui": "^3.0.0-canary.218",
53
+ "@firecms/editor": "^3.0.0-canary.219",
54
+ "@firecms/formex": "^3.0.0-canary.219",
55
+ "@firecms/ui": "^3.0.0-canary.219",
56
56
  "@hello-pangea/dnd": "^17.0.0",
57
57
  "@radix-ui/react-portal": "^1.1.3",
58
58
  "clsx": "^2.1.1",
@@ -105,7 +105,7 @@
105
105
  "dist",
106
106
  "src"
107
107
  ],
108
- "gitHead": "c0efa30360fec2f9be27b9d47bc6a800b17d34f2",
108
+ "gitHead": "dc68bdab1dd594afc37aee70291e031f83996358",
109
109
  "publishConfig": {
110
110
  "access": "public"
111
111
  },
@@ -275,6 +275,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
275
275
  formex,
276
276
  status: "existing",
277
277
  openEntityMode: "side_panel",
278
+ disabled: false,
278
279
  };
279
280
 
280
281
  const property: ResolvedProperty<any> | undefined = propertyKey && getPropertyInPath(collection?.properties ?? {} as ResolvedProperties, propertyKey as string);
@@ -98,6 +98,10 @@ export function EntityEditView<M extends Record<string, any>, USER extends User>
98
98
  }
99
99
  }, [authController, entity, status]);
100
100
 
101
+ console.log({
102
+ canEdit
103
+ })
104
+
101
105
  if ((dataLoading && !cachedValues) || (!entity || canEdit === undefined) && (status === "existing" || status === "copy")) {
102
106
  return <CircularProgressCenter/>;
103
107
  }
@@ -117,7 +121,6 @@ export function EntityEditView<M extends Record<string, any>, USER extends User>
117
121
  />;
118
122
  }
119
123
 
120
-
121
124
  export function EntityEditViewInner<M extends Record<string, any>>({
122
125
  path,
123
126
  entityId,
@@ -215,6 +218,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
215
218
  const formexStub = createFormexStub<M>(usedEntity?.values ?? {} as M);
216
219
  const usedFormContext: FormContext = formContext ?? {
217
220
  entityId,
221
+ disabled: false,
218
222
  openEntityMode: layout,
219
223
  status: status,
220
224
  values: usedEntity?.values ?? {},
@@ -315,61 +319,57 @@ export function EntityEditViewInner<M extends Record<string, any>>({
315
319
  }
316
320
  };
317
321
 
318
- const entityView = !canEdit ?
319
- (
320
- <div
321
- className={cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", !mainViewVisible ? "hidden" : "")}>
322
- <div
323
- className={cls("relative flex flex-col max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-6xl w-full h-fit")}>
324
- <Typography className={"mt-16 mb-8 mx-8"} variant={"h4"}>
325
- {collection.singularName ?? collection.name}
326
- </Typography>
327
- <EntityView
328
- className={"px-8 h-full overflow-auto"}
329
- entity={entity as Entity<M>}
330
- path={path}
331
- collection={collection}/>
332
- </div>
333
- </div>
334
- )
335
- :
336
- (
337
- <EntityForm<M>
338
- collection={collection}
339
- path={path}
340
- entityId={entityId ?? usedEntity?.id}
341
- onValuesModified={onValuesModified}
342
- entity={entity}
343
- initialDirtyValues={cachedDirtyValues}
344
- openEntityMode={layout}
345
- forceActionsAtTheBottom={actionsAtTheBottom}
346
- initialStatus={status}
347
- className={cls(!mainViewVisible ? "hidden" : "", formProps?.className)}
348
- EntityFormActionsComponent={EntityEditViewFormActions}
349
- {...formProps}
350
- onEntityChange={(entity) => {
351
- setUsedEntity(entity);
352
- formProps?.onEntityChange?.(entity);
353
- }}
354
- onStatusChange={(status) => {
355
- setStatus(status);
356
- formProps?.onStatusChange?.(status);
357
- }}
358
- onFormContextReady={(formContext) => {
359
- setFormContext(formContext);
360
- formProps?.onFormContextReady?.(formContext);
361
- }}
362
- onSaved={(params) => {
363
- const res = {
364
- ...params,
365
- selectedTab: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab
366
- };
367
- onSaved?.(res);
368
- formProps?.onSaved?.(res);
369
- }}
370
- Builder={selectedSecondaryForm?.Builder}
371
- />
372
- );
322
+ const entityReadOnlyView = <div
323
+ className={cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", (canEdit || !mainViewVisible || selectedSecondaryForm) ? "hidden" : "")}>
324
+ <div
325
+ className={cls("relative flex flex-col max-w-4xl lg:max-w-3xl xl:max-w-4xl 2xl:max-w-6xl w-full h-fit")}>
326
+ <Typography className={"mt-16 mb-8 mx-8"} variant={"h4"}>
327
+ {collection.singularName ?? collection.name}
328
+ </Typography>
329
+ <EntityView
330
+ className={"px-8 h-full overflow-auto"}
331
+ entity={entity as Entity<M>}
332
+ path={path}
333
+ collection={collection}/>
334
+ </div>
335
+ </div>;
336
+
337
+ const entityView = <EntityForm<M>
338
+ collection={collection}
339
+ path={path}
340
+ entityId={entityId ?? usedEntity?.id}
341
+ onValuesModified={onValuesModified}
342
+ entity={entity}
343
+ initialDirtyValues={cachedDirtyValues}
344
+ openEntityMode={layout}
345
+ forceActionsAtTheBottom={actionsAtTheBottom}
346
+ initialStatus={status}
347
+ className={cls((!mainViewVisible || !canEdit) && !selectedSecondaryForm ? "hidden" : "", formProps?.className)}
348
+ EntityFormActionsComponent={EntityEditViewFormActions}
349
+ disabled={!canEdit}
350
+ {...formProps}
351
+ onEntityChange={(entity) => {
352
+ setUsedEntity(entity);
353
+ formProps?.onEntityChange?.(entity);
354
+ }}
355
+ onStatusChange={(status) => {
356
+ setStatus(status);
357
+ formProps?.onStatusChange?.(status);
358
+ }}
359
+ onFormContextReady={(formContext) => {
360
+ setFormContext(formContext);
361
+ formProps?.onFormContextReady?.(formContext);
362
+ }}
363
+ onSaved={(params) => {
364
+ const res = {
365
+ ...params,
366
+ selectedTab: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab
367
+ };
368
+ onSaved?.(res);
369
+ formProps?.onSaved?.(res);
370
+ }}
371
+ Builder={selectedSecondaryForm?.Builder}
372
+ />;
373
373
 
374
374
  const subcollectionTabs = subcollections && subcollections.map((subcollection) =>
375
375
  <Tab
@@ -436,7 +436,10 @@ export function EntityEditViewInner<M extends Record<string, any>>({
436
436
  ? <div className="w-full pt-12 pb-16 px-4 sm:px-8 md:px-10">
437
437
  <CircularProgressCenter/>
438
438
  </div>
439
- : entityView}
439
+ : <>
440
+ {entityReadOnlyView}
441
+ {entityView}
442
+ </>}
440
443
 
441
444
  {jsonView}
442
445
 
@@ -73,6 +73,10 @@ export type EntityFormProps<M extends Record<string, any>> = {
73
73
  onEntityChange?: (entity: Entity<M>) => void;
74
74
  formex?: FormexController<M>;
75
75
  openEntityMode?: "side_panel" | "full_screen";
76
+ /**
77
+ * If true, the form will be disabled and no actions will be available
78
+ */
79
+ disabled?: boolean;
76
80
  /**
77
81
  * Include the copy and delete actions in the form
78
82
  */
@@ -90,7 +94,6 @@ export type EntityFormProps<M extends Record<string, any>> = {
90
94
  children?: React.ReactNode;
91
95
  };
92
96
 
93
-
94
97
  export function EntityForm<M extends Record<string, any>>({
95
98
  path,
96
99
  entityId: entityIdProp,
@@ -108,6 +111,7 @@ export function EntityForm<M extends Record<string, any>>({
108
111
  onEntityChange,
109
112
  openEntityMode = "full_screen",
110
113
  formex: formexProp,
114
+ disabled: disabledProp,
111
115
  Builder,
112
116
  EntityFormActionsComponent = EntityFormActions,
113
117
  showDefaultActions = true,
@@ -115,6 +119,8 @@ export function EntityForm<M extends Record<string, any>>({
115
119
  children
116
120
  }: EntityFormProps<M>) {
117
121
 
122
+ console.log("disabledProp", disabledProp);
123
+
118
124
  if (collection.customId && collection.formAutoSave) {
119
125
  console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
120
126
  }
@@ -402,6 +408,9 @@ export function EntityForm<M extends Record<string, any>>({
402
408
  });
403
409
  };
404
410
 
411
+ const disabled = formex.isSubmitting || Boolean(disabledProp);
412
+ console.log("disabled", disabled);
413
+
405
414
  const formContext: FormContext<M> = {
406
415
  // @ts-ignore
407
416
  setFieldValue: useCallback(formex.setFieldValue, []),
@@ -414,7 +423,8 @@ export function EntityForm<M extends Record<string, any>>({
414
423
  entity,
415
424
  savingError,
416
425
  status,
417
- openEntityMode
426
+ openEntityMode,
427
+ disabled
418
428
  };
419
429
 
420
430
  useEffect(() => {
@@ -431,6 +441,7 @@ export function EntityForm<M extends Record<string, any>>({
431
441
  const pluginActions: React.ReactNode[] = [];
432
442
  const plugins = customizationController.plugins;
433
443
 
444
+ const actionsDisabled = disabled || formex.isSubmitting || (status === "existing" && !formex.dirty) || Boolean(disabledProp);
434
445
  if (plugins && collection) {
435
446
  const actionProps: PluginFormActionProps = {
436
447
  entityId,
@@ -440,7 +451,8 @@ export function EntityForm<M extends Record<string, any>>({
440
451
  context,
441
452
  currentEntityId: entityId,
442
453
  formContext,
443
- openEntityMode
454
+ openEntityMode,
455
+ disabled: actionsDisabled,
444
456
  };
445
457
  pluginActions.push(...plugins.map((plugin) => (
446
458
  plugin.form?.Actions
@@ -548,7 +560,7 @@ export function EntityForm<M extends Record<string, any>>({
548
560
  !!underlyingChanges &&
549
561
  Object.keys(underlyingChanges).includes(key) &&
550
562
  formex.touched[key];
551
- const disabled = (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
563
+ const disabled = disabledProp || (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
552
564
  const hidden = isHidden(property);
553
565
  if (hidden) return null;
554
566
  const widthPercentage = property.widthPercentage ?? 100;
@@ -658,8 +670,6 @@ export function EntityForm<M extends Record<string, any>>({
658
670
  onIdChange(entityId);
659
671
  }, [entityId, onIdChange]);
660
672
 
661
- const disabled = formex.isSubmitting || (!formex.dirty && status === "existing");
662
-
663
673
  if (!resolvedCollection || !path) {
664
674
  throw Error("INTERNAL: Collection and path must be defined in form context");
665
675
  }
@@ -671,7 +681,7 @@ export function EntityForm<M extends Record<string, any>>({
671
681
  layout={forceActionsAtTheBottom ? "bottom" : "side"}
672
682
  savingError={savingError}
673
683
  formex={formex}
674
- disabled={disabled}
684
+ disabled={actionsDisabled}
675
685
  status={status}
676
686
  pluginActions={pluginActions ?? []}
677
687
  openEntityMode={openEntityMode}
@@ -87,7 +87,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
87
87
  autoFocus,
88
88
  index,
89
89
  size,
90
- onPropertyChange
90
+ onPropertyChange,
91
91
  }: PropertyFieldBindingProps<T, M>): ReactElement<PropertyFieldBindingProps<T, M>> {
92
92
 
93
93
  const authController = useAuthController();
@@ -112,7 +112,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
112
112
  authController
113
113
  });
114
114
 
115
- const disabled = disabledProp || isReadOnly(resolvedProperty) || Boolean(resolvedProperty?.disabled);
115
+ const disabled = disabledProp || isReadOnly(resolvedProperty) || Boolean(resolvedProperty?.disabled) || context.disabled;
116
116
 
117
117
  if (resolvedProperty === null || isHidden(resolvedProperty)) {
118
118
  return <></>;
@@ -66,7 +66,7 @@ export function SelectFieldBinding<T extends EnumType>({
66
66
  />
67
67
  </PropertyIdCopyTooltip>}
68
68
  endAdornment={
69
- property.clearable && <IconButton
69
+ property.clearable && !disabled && <IconButton
70
70
  onClick={handleClearClick}>
71
71
  <CloseIcon/>
72
72
  </IconButton>
@@ -63,7 +63,7 @@ export function StorageUploadFieldBinding({
63
63
  throw new Error("StorageUploadFieldBinding: Entity id is null");
64
64
 
65
65
  const storageSource = useStorageSource(context.collection);
66
- const disabled = isReadOnly(property) || !!property.disabled || isSubmitting;
66
+ const disabled = isReadOnly(property) || !!property.disabled || isSubmitting || context.disabled;
67
67
 
68
68
  const {
69
69
  internalValue,
@@ -176,6 +176,8 @@ export interface FormContext<M extends Record<string, any> = any> {
176
176
  * operate with it
177
177
  */
178
178
  formex: FormexController<M>;
179
+
180
+ disabled: boolean;
179
181
  }
180
182
 
181
183
  /**
@@ -192,6 +192,7 @@ export interface PluginFormActionProps<USER extends User = User, EC extends Enti
192
192
  path: string;
193
193
  status: EntityStatus;
194
194
  collection: EC;
195
+ disabled: boolean;
195
196
  formContext?: FormContext<any>;
196
197
  context: FireCMSContext<USER>;
197
198
  currentEntityId?: string;
@@ -447,7 +447,7 @@ export function resolvedSelectedEntityView<M extends Record<string, any>>(
447
447
  const resolvedEntityViews = customViews ? customViews
448
448
  .map(e => resolveEntityView(e, customizationController.entityViews))
449
449
  .filter((e): e is EntityCustomView<M> => Boolean(e))
450
- .filter((e) => canEdit || !e.includeActions)
450
+ // .filter((e) => canEdit || !e.includeActions)
451
451
  : [];
452
452
 
453
453
  const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);