@firecms/entity_history 3.0.0-canary.251 → 3.0.0-canary.253

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.
@@ -1,17 +1,17 @@
1
1
  import * as React from "react";
2
- import { Entity, EntityCollection, PreviewSize } from "@firecms/core";
2
+ import { Entity, EntityCollection, EntityValues, PreviewSize } from "@firecms/core";
3
3
  export type EntityPreviewProps = {
4
4
  size: PreviewSize;
5
5
  actions?: React.ReactNode;
6
6
  collection?: EntityCollection;
7
7
  hover?: boolean;
8
8
  previewKeys?: string[];
9
- disabled?: boolean;
10
9
  entity: Entity<any>;
10
+ previousValues?: EntityValues<any>;
11
11
  onClick?: (e: React.SyntheticEvent) => void;
12
12
  };
13
13
  /**
14
14
  * This view is used to display a preview of an entity.
15
15
  * It is used by default in reference fields and whenever a reference is displayed.
16
16
  */
17
- export declare function EntityHistoryEntry({ actions, disabled, hover, collection: collectionProp, previewKeys, onClick, size, entity }: EntityPreviewProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function EntityHistoryEntry({ actions, hover, collection: collectionProp, previewKeys, onClick, size, entity, previousValues }: EntityPreviewProps): import("react/jsx-runtime").JSX.Element;
package/dist/index.es.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import React__default, { useContext, useState, useRef, useEffect, useCallback, useMemo } from "react";
4
- import { useAuthController, useCustomizationController, useNavigationController, useSideEntityController, resolveCollection, getPropertyInPath, getValueInPath, PropertyPreview, SkeletonPropertyComponent, useSnackbarController, useDataSource, ConfirmationDialog, mergeCallbacks } from "@firecms/core";
4
+ import { useAuthController, useCustomizationController, useNavigationController, useSideEntityController, resolveCollection, getPropertyInPath, getValueInPath, PropertyPreview, SkeletonPropertyComponent, useSnackbarController, useDataSource, EntityView, ErrorBoundary, ConfirmationDialog, mergeCallbacks } from "@firecms/core";
5
5
  import { c } from "react-compiler-runtime";
6
- import { Chip, Tooltip, Typography, cls, defaultBorderMixin, IconButton, KeyboardTabIcon, Label, HistoryIcon } from "@firecms/ui";
6
+ import { Chip, Tooltip, Typography, cls, defaultBorderMixin, IconButton, KeyboardTabIcon, KeyboardBackspaceIcon, Label, HistoryIcon } from "@firecms/ui";
7
7
  import equal from "react-fast-compare";
8
8
  const HistoryControllerContext = React__default.createContext({});
9
9
  const useHistoryController = () => {
@@ -83,15 +83,86 @@ function UserChip(t0) {
83
83
  }
84
84
  return t6;
85
85
  }
86
+ function PreviousValueView(t0) {
87
+ const $ = c(12);
88
+ const {
89
+ previousValueInPath,
90
+ childProperty,
91
+ key
92
+ } = t0;
93
+ if (typeof previousValueInPath === "string" || typeof previousValueInPath === "number") {
94
+ let t1;
95
+ if ($[0] !== previousValueInPath) {
96
+ t1 = /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "line-through", children: previousValueInPath });
97
+ $[0] = previousValueInPath;
98
+ $[1] = t1;
99
+ } else {
100
+ t1 = $[1];
101
+ }
102
+ return t1;
103
+ } else {
104
+ if (typeof previousValueInPath === "boolean") {
105
+ const t1 = previousValueInPath ? "true" : "false";
106
+ let t2;
107
+ if ($[2] !== t1) {
108
+ t2 = /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "line-through", children: t1 });
109
+ $[2] = t1;
110
+ $[3] = t2;
111
+ } else {
112
+ t2 = $[3];
113
+ }
114
+ return t2;
115
+ } else {
116
+ let t1;
117
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
118
+ t1 = /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: "Previous value" });
119
+ $[4] = t1;
120
+ } else {
121
+ t1 = $[4];
122
+ }
123
+ const t2 = key;
124
+ const t3 = childProperty;
125
+ let t4;
126
+ if ($[5] !== previousValueInPath || $[6] !== t2 || $[7] !== t3) {
127
+ t4 = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
128
+ t1,
129
+ /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: t2, value: previousValueInPath, property: t3, size: "small" })
130
+ ] });
131
+ $[5] = previousValueInPath;
132
+ $[6] = t2;
133
+ $[7] = t3;
134
+ $[8] = t4;
135
+ } else {
136
+ t4 = $[8];
137
+ }
138
+ let t5;
139
+ if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
140
+ t5 = /* @__PURE__ */ jsx(KeyboardBackspaceIcon, { size: "smallest", color: "disabled", className: "mb-1" });
141
+ $[9] = t5;
142
+ } else {
143
+ t5 = $[9];
144
+ }
145
+ let t6;
146
+ if ($[10] !== t4) {
147
+ t6 = /* @__PURE__ */ jsx(Tooltip, { side: "left", title: t4, children: t5 });
148
+ $[10] = t4;
149
+ $[11] = t6;
150
+ } else {
151
+ t6 = $[11];
152
+ }
153
+ return t6;
154
+ }
155
+ }
156
+ }
86
157
  function EntityHistoryEntry({
87
158
  actions,
88
- disabled,
89
159
  hover,
90
160
  collection: collectionProp,
91
161
  previewKeys,
92
162
  onClick,
93
163
  size,
94
- entity
164
+ entity,
165
+ previousValues
95
166
  }) {
96
167
  const authController = useAuthController();
97
168
  const customizationController = useCustomizationController();
@@ -144,17 +215,21 @@ function EntityHistoryEntry({
144
215
  /* @__PURE__ */ jsx("div", { className: "flex flex-col grow w-full m-1 shrink min-w-0", children: previewKeys && previewKeys.map((key) => {
145
216
  const childProperty = getPropertyInPath(resolvedCollection.properties, key);
146
217
  const valueInPath = getValueInPath(entity.values, key);
218
+ const previousValueInPath = previousValues ? getValueInPath(previousValues, key) : void 0;
147
219
  const element = childProperty ? entity ? /* @__PURE__ */ jsx(PropertyPreview, { propertyKey: key, value: valueInPath, property: childProperty, size: "small" }) : /* @__PURE__ */ jsx(SkeletonPropertyComponent, { property: childProperty, size: "small" }) : /* @__PURE__ */ jsx(Typography, { variant: "body2", children: typeof valueInPath === "string" ? valueInPath : JSON.stringify(valueInPath) });
148
220
  return /* @__PURE__ */ jsxs("div", { className: "flex w-full my-1 items-center", children: [
149
221
  /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "min-w-[140px] md:min-w-[200px] w-1/5 pr-8 overflow-hidden text-ellipsis text-right", children: key }),
150
- /* @__PURE__ */ jsx("div", { className: "w-4/5", children: element })
222
+ /* @__PURE__ */ jsxs("div", { className: "w-4/5", children: [
223
+ previousValueInPath !== void 0 && previousValueInPath !== valueInPath && /* @__PURE__ */ jsx(PreviousValueView, { previousValueInPath, childProperty }, key),
224
+ element
225
+ ] })
151
226
  ] }, "ref_prev_" + key);
152
227
  }) })
153
228
  ] })
154
229
  ] });
155
230
  }
156
231
  function EntityHistoryView(t0) {
157
- const $ = c(53);
232
+ const $ = c(58);
158
233
  const {
159
234
  entity,
160
235
  collection,
@@ -370,7 +445,8 @@ function EntityHistoryView(t0) {
370
445
  if ($[30] !== collection || $[31] !== dirty || $[32] !== snackbarController) {
371
446
  t112 = (revision, index) => {
372
447
  const previewKeys = revision.values?.__metadata?.changed_fields;
373
- return /* @__PURE__ */ jsx("div", { className: "flex flex-cols gap-2 w-full", children: /* @__PURE__ */ jsx(EntityHistoryEntry, { size: "large", entity: revision, collection, previewKeys, actions: /* @__PURE__ */ jsx(Tooltip, { title: "Revert to this version", className: "m-2 grow-0 self-start", children: /* @__PURE__ */ jsx(IconButton, { onClick: () => {
448
+ const previousValues = revision.values?.__metadata?.previous_values;
449
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-cols gap-2 w-full", children: /* @__PURE__ */ jsx(EntityHistoryEntry, { size: "large", entity: revision, collection, previewKeys, previousValues, actions: /* @__PURE__ */ jsx(Tooltip, { title: "Revert to this version", className: "m-2 grow-0 self-start", children: /* @__PURE__ */ jsx(IconButton, { onClick: () => {
374
450
  if (dirty) {
375
451
  snackbarController.open({
376
452
  message: "Please save or discard your changes before reverting",
@@ -454,27 +530,38 @@ function EntityHistoryView(t0) {
454
530
  t16 = $[46];
455
531
  }
456
532
  let t17;
457
- if ($[47] !== t13 || $[48] !== t14) {
458
- t17 = /* @__PURE__ */ jsx(ConfirmationDialog, { open: t13, onAccept: t14, onCancel: t15, title: t16 });
459
- $[47] = t13;
460
- $[48] = t14;
461
- $[49] = t17;
533
+ if ($[47] !== collection || $[48] !== entity?.path || $[49] !== revertVersionDialog) {
534
+ t17 = revertVersionDialog ? /* @__PURE__ */ jsx(EntityView, { entity: revertVersionDialog, collection, path: entity?.path }) : null;
535
+ $[47] = collection;
536
+ $[48] = entity?.path;
537
+ $[49] = revertVersionDialog;
538
+ $[50] = t17;
462
539
  } else {
463
- t17 = $[49];
540
+ t17 = $[50];
464
541
  }
465
542
  let t18;
466
- if ($[50] !== t12 || $[51] !== t17) {
467
- t18 = /* @__PURE__ */ jsxs("div", { ref: containerRef, className: t7, children: [
543
+ if ($[51] !== t13 || $[52] !== t14 || $[53] !== t17) {
544
+ t18 = /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(ConfirmationDialog, { open: t13, onAccept: t14, onCancel: t15, title: t16, body: t17 }) });
545
+ $[51] = t13;
546
+ $[52] = t14;
547
+ $[53] = t17;
548
+ $[54] = t18;
549
+ } else {
550
+ t18 = $[54];
551
+ }
552
+ let t19;
553
+ if ($[55] !== t12 || $[56] !== t18) {
554
+ t19 = /* @__PURE__ */ jsxs("div", { ref: containerRef, className: t7, children: [
468
555
  t12,
469
- t17
556
+ t18
470
557
  ] });
471
- $[50] = t12;
472
- $[51] = t17;
473
- $[52] = t18;
558
+ $[55] = t12;
559
+ $[56] = t18;
560
+ $[57] = t19;
474
561
  } else {
475
- t18 = $[52];
562
+ t19 = $[57];
476
563
  }
477
- return t18;
564
+ return t19;
478
565
  }
479
566
  const entityHistoryCallbacks = {
480
567
  onSaveSuccess: async (props) => {
@@ -485,6 +572,7 @@ const entityHistoryCallbacks = {
485
572
  values: {
486
573
  ...props.values,
487
574
  __metadata: {
575
+ previous_values: props.previousValues,
488
576
  changed_fields: changedFields,
489
577
  updated_on: /* @__PURE__ */ new Date(),
490
578
  updated_by: uid
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/HistoryControllerProvider.tsx","../src/components/UserChip.tsx","../src/components/EntityHistoryEntry.tsx","../src/components/EntityHistoryView.tsx","../src/entity_history_callbacks.ts","../src/useEntityHistoryPlugin.tsx"],"sourcesContent":["import React, { PropsWithChildren, useContext } from \"react\";\nimport equal from \"react-fast-compare\"\n\nimport { User } from \"@firecms/core\";\n\nexport type HistoryConfigController = {\n /**\n * Function to get a user by uid.\n * @param uid\n */\n getUser?: (uid: string) => User | null;\n}\n\nexport const HistoryControllerContext = React.createContext<HistoryConfigController>({} as any);\nexport const useHistoryController = (): HistoryConfigController => useContext(HistoryControllerContext);\n\n\nexport interface HistoryControllerProviderProps {\n\n getUser?: (uid: string) => User | null;\n\n}\n\nexport const HistoryControllerProvider = React.memo(\n function HistoryControllerProvider({\n children,\n getUser,\n }: PropsWithChildren<HistoryControllerProviderProps>) {\n\n return (\n <HistoryControllerContext.Provider\n value={{\n getUser,\n }}>\n\n {children}\n\n </HistoryControllerContext.Provider>\n );\n }, equal);\n","import { User } from \"@firecms/core\";\nimport { Chip, Tooltip } from \"@firecms/ui\";\n\nexport function UserChip({ user }: { user: User }) {\n return (\n <Tooltip title={user.email ?? user.uid}>\n <Chip size={\"small\"} className={\"flex items-center\"}>\n {user.photoURL && <img\n className={\"rounded-full w-6 h-6 mr-2\"}\n src={user.photoURL} alt={user.displayName ?? \"User picture\"}/>}\n <span>{user.displayName ?? user.email ?? user.uid}</span>\n </Chip>\n </Tooltip>\n );\n}\n","import * as React from \"react\";\n\nimport { Chip, cls, defaultBorderMixin, IconButton, KeyboardTabIcon, Tooltip, Typography } from \"@firecms/ui\";\nimport {\n Entity,\n EntityCollection,\n getPropertyInPath,\n getValueInPath,\n PreviewSize,\n PropertyPreview,\n resolveCollection,\n ResolvedProperty,\n SkeletonPropertyComponent,\n useAuthController,\n useCustomizationController,\n useNavigationController,\n useSideEntityController\n} from \"@firecms/core\";\nimport { useHistoryController } from \"../HistoryControllerProvider\";\nimport { UserChip } from \"./UserChip\";\n\nexport type EntityPreviewProps = {\n size: PreviewSize,\n actions?: React.ReactNode,\n collection?: EntityCollection,\n hover?: boolean;\n previewKeys?: string[],\n disabled?: boolean,\n entity: Entity<any>,\n onClick?: (e: React.SyntheticEvent) => void;\n};\n\n/**\n * This view is used to display a preview of an entity.\n * It is used by default in reference fields and whenever a reference is displayed.\n */\nexport function EntityHistoryEntry({\n actions,\n disabled,\n hover,\n collection: collectionProp,\n previewKeys,\n onClick,\n size,\n entity\n }: EntityPreviewProps) {\n\n const authController = useAuthController();\n const customizationController = useCustomizationController();\n\n const navigationController = useNavigationController();\n const sideEntityController = useSideEntityController();\n\n const collection = collectionProp ?? navigationController.getCollection(entity.path);\n const updatedOn = entity.values?.[\"__metadata\"]?.[\"updated_on\"];\n if (!collection) {\n throw Error(`Couldn't find the corresponding collection view for the path: ${entity.path}`);\n }\n\n const updatedBy = entity.values?.[\"__metadata\"]?.[\"updated_by\"];\n const { getUser } = useHistoryController();\n const user = getUser?.(updatedBy);\n\n const resolvedCollection = React.useMemo(() => resolveCollection({\n collection,\n path: entity.path,\n values: entity.values,\n propertyConfigs: customizationController.propertyConfigs,\n authController\n }), [collection]);\n\n return <div className={\"w-full flex flex-col gap-2 mt-4\"}>\n <div className={\"ml-4 flex items-center gap-4\"}>\n <Typography variant={\"body2\"} color={\"secondary\"}>{updatedOn.toLocaleString()}</Typography>\n {!user && updatedBy && <Chip size={\"small\"}>{updatedBy}</Chip>}\n {user && <UserChip user={user}/>}\n </div>\n <div\n className={cls(\n \"bg-white dark:bg-surface-900\",\n \"min-h-[42px]\",\n \"w-full\",\n \"items-center\",\n hover ? \"hover:bg-surface-accent-50 dark:hover:bg-surface-800 group-hover:bg-surface-accent-50 dark:group-hover:bg-surface-800\" : \"\",\n size === \"small\" ? \"p-1\" : \"px-2 py-1\",\n \"flex border rounded-lg\",\n onClick ? \"cursor-pointer\" : \"\",\n defaultBorderMixin\n )}>\n\n\n {actions}\n\n {entity &&\n <Tooltip title={\"See details for this revision\"}\n className={\"my-2 grow-0 shrink-0 self-start\"}>\n <IconButton\n color={\"inherit\"}\n className={\"\"}\n onClick={(e) => {\n\n sideEntityController.open({\n entityId: entity.id,\n path: entity.path,\n allowFullScreen: false,\n collection: {\n ...collection,\n subcollections: undefined,\n entityViews: undefined,\n permissions: {\n create: false,\n delete: false,\n edit: false,\n read: true\n }\n },\n updateUrl: true\n });\n }}>\n <KeyboardTabIcon/>\n </IconButton>\n </Tooltip>}\n\n <div className={\"flex flex-col grow w-full m-1 shrink min-w-0\"}>\n\n {previewKeys && previewKeys.map((key) => {\n const childProperty = getPropertyInPath(resolvedCollection.properties, key);\n\n const valueInPath = getValueInPath(entity.values, key);\n const element = childProperty ? (entity\n ? <PropertyPreview\n propertyKey={key as string}\n value={valueInPath}\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>\n : <SkeletonPropertyComponent\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>) :\n <Typography variant={\"body2\"}>\n {typeof valueInPath === \"string\" ? valueInPath : JSON.stringify(valueInPath)}\n </Typography>;\n return (\n <div key={\"ref_prev_\" + key}\n className=\"flex w-full my-1 items-center\">\n <Typography variant={\"caption\"}\n color={\"secondary\"}\n className=\"min-w-[140px] md:min-w-[200px] w-1/5 pr-8 overflow-hidden text-ellipsis text-right\">\n {key}\n </Typography>\n <div className=\"w-4/5\">\n {\n element\n }\n </div>\n </div>\n );\n })}\n\n </div>\n\n </div>\n </div>\n}\n\n","import { useEffect, useRef, useState } from \"react\";\nimport {\n ConfirmationDialog,\n Entity,\n EntityCustomViewParams,\n useAuthController,\n useDataSource,\n useSnackbarController\n} from \"@firecms/core\";\nimport { cls, HistoryIcon, IconButton, Label, Tooltip, Typography } from \"@firecms/ui\";\nimport { EntityHistoryEntry } from \"./EntityHistoryEntry\";\n\nexport function EntityHistoryView({\n entity,\n collection,\n formContext\n }: EntityCustomViewParams) {\n\n const authController = useAuthController();\n const snackbarController = useSnackbarController();\n const dirty = formContext?.formex.dirty;\n\n const dataSource = useDataSource();\n const pathAndId = entity ? entity?.path + \"/\" + entity?.id : undefined;\n\n const [revertVersionDialog, setRevertVersionDialog] = useState<Entity | undefined>(undefined);\n const [revisions, setRevisions] = useState<Entity[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [hasMore, setHasMore] = useState(true);\n\n const PAGE_SIZE = 5;\n const [limit, setLimit] = useState(PAGE_SIZE);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const observerRef = useRef<IntersectionObserver | null>(null);\n const loadMoreRef = useRef<HTMLDivElement>(null);\n\n // Load revisions with the current limit\n useEffect(() => {\n if (!pathAndId) return;\n\n setIsLoading(true); // Set loading true when fetching starts\n const listener = dataSource.listenCollection?.({\n path: pathAndId + \"/__history\",\n order: \"desc\",\n orderBy: \"__metadata.updated_on\",\n limit: limit,\n startAfter: undefined,\n onUpdate: (entities) => {\n setRevisions(entities);\n setHasMore(entities.length === limit && entities.length >= PAGE_SIZE); // Ensure we fetched a full page to consider hasMore\n setIsLoading(false);\n },\n onError: (error) => {\n console.error(\"Error fetching history:\", error);\n setIsLoading(false);\n setHasMore(false); // Stop trying if there's an error\n }\n });\n return () => {\n if (typeof listener === \"function\") {\n listener();\n }\n };\n }, [pathAndId, limit, dataSource]);\n\n // Setup intersection observer for infinite scroll\n useEffect(() => {\n const currentContainer = containerRef.current;\n const currentLoadMore = loadMoreRef.current;\n\n // Conditions for active observation\n if (!currentContainer || !currentLoadMore || !hasMore || isLoading) {\n // If we shouldn't be observing, ensure any existing observer is disconnected\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n return;\n }\n\n // Options for the IntersectionObserver\n const options = {\n root: currentContainer,\n rootMargin: \"0px 0px 200px 0px\", // Trigger 200px before the sentinel is at the bottom edge\n threshold: 0.01 // Trigger if even a small part is visible within the rootMargin\n };\n\n // The callback for when the sentinel's intersection state changes\n const handleObserver = (entries: IntersectionObserverEntry[]) => {\n const target = entries[0];\n if (target.isIntersecting && hasMore && !isLoading) {\n // No need to setIsLoading(true) here, it's done in the data fetching useEffect\n setLimit(prev => prev + PAGE_SIZE);\n }\n };\n\n const observer = new IntersectionObserver(handleObserver, options);\n observer.observe(currentLoadMore);\n observerRef.current = observer; // Store the new observer\n\n // Cleanup function for this effect instance\n return () => {\n observer.disconnect(); // Disconnect the observer created in *this* effect run\n if (observerRef.current === observer) {\n observerRef.current = null;\n }\n };\n // Re-run if hasMore, isLoading changes, or if revisions.length changes (which might make loadMoreRef available/unavailable)\n }, [hasMore, isLoading, revisions.length]);\n\n if (!entity) {\n return <div className=\"flex items-center justify-center h-full\">\n <Label>History is only available for existing entities</Label>\n </div>\n }\n\n function doRevert(revertVersion: Entity) {\n if (!entity) {\n throw new Error(\"No entity to revert\");\n }\n const revertValues = {\n ...revertVersion.values,\n __metadata: {\n ...revertVersion.values?.[\"__metadata\"],\n reverted: true,\n updated_on: new Date(),\n updated_by: authController.user?.uid ?? null,\n }\n };\n const saveReverted = dataSource.saveEntity({\n path: entity.path,\n entityId: entity.id,\n values: revertValues,\n collection,\n status: \"existing\"\n });\n const saveRevertedHistory = dataSource.saveEntity({\n path: revertVersion.path,\n entityId: revertVersion.id,\n values: revertValues,\n collection,\n status: \"existing\"\n });\n return Promise.all([saveReverted, saveRevertedHistory])\n .then(() => {\n formContext.formex.resetForm({\n values: revertVersion.values\n });\n setRevertVersionDialog(undefined);\n snackbarController.open({\n message: \"Reverted version\",\n type: \"info\"\n });\n }\n ).catch((error) => {\n console.error(\"Error reverting entity:\", error);\n snackbarController.open({\n message: \"Error reverting entity\",\n type: \"error\"\n });\n });\n\n }\n\n return <div\n ref={containerRef}\n className={cls(\"relative flex-1 h-full overflow-auto w-full flex flex-col gap-4 p-8\")}>\n <div className=\"flex flex-col gap-2 max-w-6xl mx-auto w-full\">\n\n <Typography variant={\"h5\"} className={\"mt-24 ml-4\"}>\n History\n </Typography>\n\n {revisions.length === 0 && <>\n <Label className={\"ml-4 mt-8\"}>\n No history available\n </Label>\n <Typography variant={\"caption\"} className={\"ml-4\"}>\n When you save an entity, a new version is created and stored in the history.\n </Typography>\n </>}\n\n {revisions.map((revision, index) => {\n const previewKeys = revision.values?.[\"__metadata\"]?.[\"changed_fields\"];\n return <div key={index} className=\"flex flex-cols gap-2 w-full\">\n <EntityHistoryEntry size={\"large\"}\n entity={revision}\n collection={collection}\n previewKeys={previewKeys}\n actions={\n <Tooltip title={\"Revert to this version\"}\n className={\"m-2 grow-0 self-start\"}>\n <IconButton\n onClick={() => {\n if (dirty) {\n snackbarController.open({\n message: \"Please save or discard your changes before reverting\",\n type: \"warning\"\n });\n } else {\n setRevertVersionDialog(revision);\n }\n }}>\n <HistoryIcon/>\n </IconButton>\n </Tooltip>}\n />\n </div>\n })}\n\n {/* Load more sentinel element */}\n {revisions.length > 0 && (\n <div\n ref={loadMoreRef}\n className=\"py-4 text-center\"\n >\n {isLoading && <Label>Loading more...</Label>}\n {!hasMore && revisions.length > PAGE_SIZE && <Label>No more history available</Label>}\n </div>\n )}\n </div>\n\n <ConfirmationDialog open={Boolean(revertVersionDialog)}\n onAccept={function (): void {\n if (!revertVersionDialog) return;\n doRevert(revertVersionDialog);\n }}\n onCancel={function (): void {\n setRevertVersionDialog(undefined);\n }}\n title={<Typography variant={\"subtitle2\"}>Revert data to this version?</Typography>}/>\n </div>\n}\n","import { EntityCallbacks } from \"@firecms/core\";\nimport equal from \"react-fast-compare\"\n\nexport const entityHistoryCallbacks: EntityCallbacks = {\n onSaveSuccess: async (props) => {\n\n const changedFields = props.previousValues ? findChangedFields(props.previousValues, props.values) : null;\n const uid = props.context.authController.user?.uid;\n props.context.dataSource.saveEntity({\n path: props.path + \"/\" + props.entityId + \"/__history\",\n values: {\n ...props.values,\n __metadata: {\n changed_fields: changedFields,\n updated_on: new Date(),\n updated_by: uid,\n }\n },\n status: \"new\"\n }).then(() => {\n console.debug(\"History saved for\", props.path, props.entityId);\n });\n }\n}\n\nfunction findChangedFields<M extends object>(oldValues: M, newValues: M, prefix: string = \"\"): string[] {\n const changedFields: string[] = [];\n\n // Handle null/undefined cases\n if (equal(oldValues, newValues)) return changedFields;\n if (!oldValues || !newValues) return [prefix || \".\"];\n\n // Get all unique keys from both objects\n const allKeys = new Set([\n ...Object.keys(oldValues),\n ...Object.keys(newValues)\n ]);\n\n for (const key of allKeys) {\n const oldValue = oldValues[key as keyof M];\n const newValue = newValues[key as keyof M];\n const currentPath = prefix ? `${prefix}.${key}` : key;\n\n // If key exists only in one object\n if ((key in oldValues) !== (key in newValues)) {\n changedFields.push(currentPath);\n continue;\n }\n\n // If values are identical (deep equality)\n if (equal(oldValue, newValue)) continue;\n\n // Handle arrays\n if (Array.isArray(oldValue) && Array.isArray(newValue)) {\n if (oldValue.length !== newValue.length) {\n changedFields.push(currentPath);\n } else {\n // Check if any array element changed\n for (let i = 0; i < oldValue.length; i++) {\n if (\n typeof oldValue[i] === \"object\" && oldValue[i] !== null &&\n typeof newValue[i] === \"object\" && newValue[i] !== null\n ) {\n const nestedChanges = findChangedFields(\n oldValue[i] as object,\n newValue[i] as object,\n `${currentPath}[${i}]`\n );\n if (nestedChanges.length > 0) {\n changedFields.push(currentPath);\n break;\n }\n } else if (!equal(oldValue[i], newValue[i])) {\n changedFields.push(currentPath);\n break;\n }\n }\n }\n }\n // Handle nested objects\n else if (\n typeof oldValue === \"object\" && oldValue !== null &&\n typeof newValue === \"object\" && newValue !== null\n ) {\n const nestedChanges = findChangedFields(\n oldValue as object,\n newValue as object,\n currentPath\n );\n changedFields.push(...nestedChanges);\n }\n // Handle primitives\n else {\n changedFields.push(currentPath);\n }\n }\n\n return changedFields;\n}\n","import { useCallback, useMemo } from \"react\";\nimport { EntityCollection, FireCMSPlugin, mergeCallbacks, User } from \"@firecms/core\";\nimport { EntityHistoryView } from \"./components/EntityHistoryView\";\nimport { HistoryIcon } from \"@firecms/ui\";\nimport { entityHistoryCallbacks } from \"./entity_history_callbacks\";\nimport { HistoryControllerProvider } from \"./HistoryControllerProvider\";\n\n/**\n * This plugin adds a history view to the entity side panel.\n */\nexport function useEntityHistoryPlugin(props?: EntityHistoryPluginProps): FireCMSPlugin<any, any, any, EntityHistoryPluginProps> {\n\n const { defaultEnabled = false } = props ?? {};\n\n const modifyCollection = useCallback((collection: EntityCollection) => {\n if (collection.history === true || (defaultEnabled && collection.history !== false)) {\n return {\n ...collection,\n entityViews: [\n ...(collection.entityViews ?? []),\n {\n key: \"__history\",\n name: \"History\",\n tabComponent: <HistoryIcon size={\"small\"}/>,\n Builder: EntityHistoryView,\n position: \"start\"\n }\n ],\n callbacks: mergeCallbacks(collection.callbacks, entityHistoryCallbacks)\n } satisfies EntityCollection;\n }\n return collection;\n }, []);\n\n return useMemo(() => ({\n key: \"entity_history\",\n provider: {\n Component: HistoryControllerProvider,\n props: {\n getUser: props?.getUser\n }\n },\n collection: {\n modifyCollection\n }\n } satisfies FireCMSPlugin), [props]);\n}\n\nexport type EntityHistoryPluginProps = {\n /**\n * If true, the history view will be enabled to all collections by default.\n * Each collection can override this value by setting the `history` property.\n */\n defaultEnabled?: boolean;\n\n /**\n * Function to get the user object from the uid.\n * @param uid\n */\n getUser?: (uid: string) => User | null;\n}\n"],"names":["HistoryControllerContext","React","createContext","useHistoryController","useContext","HistoryControllerProvider","memo","t0","$","_c","children","getUser","t1","t2","equal","UserChip","user","email","uid","displayName","photoURL","t3","t4","t5","t6","EntityHistoryEntry","actions","disabled","hover","collection","collectionProp","previewKeys","onClick","size","entity","authController","useAuthController","customizationController","useCustomizationController","navigationController","useNavigationController","sideEntityController","useSideEntityController","getCollection","path","updatedOn","values","Error","updatedBy","resolvedCollection","useMemo","resolveCollection","propertyConfigs","toLocaleString","cls","defaultBorderMixin","e","open","entityId","id","allowFullScreen","subcollections","undefined","entityViews","permissions","create","delete","edit","read","updateUrl","map","key","childProperty","getPropertyInPath","properties","valueInPath","getValueInPath","element","JSON","stringify","EntityHistoryView","formContext","snackbarController","useSnackbarController","dirty","formex","dataSource","useDataSource","pathAndId","revertVersionDialog","setRevertVersionDialog","useState","Symbol","for","revisions","setRevisions","isLoading","setIsLoading","hasMore","setHasMore","limit","setLimit","containerRef","useRef","observerRef","loadMoreRef","listener","listenCollection","order","orderBy","startAfter","onUpdate","entities","length","onError","error","useEffect","currentContainer","current","currentLoadMore","disconnect","options","root","rootMargin","threshold","handleObserver","entries","target","isIntersecting","prev","observer","IntersectionObserver","observe","doRevert","revertVersion","revertValues","__metadata","reverted","updated_on","Date","updated_by","saveReverted","saveEntity","status","saveRevertedHistory","Promise","all","then","resetForm","message","type","catch","error_0","t7","t8","t9","t10","t11","revision","index","changed_fields","t12","t13","Boolean","t14","t15","t16","t17","t18","entityHistoryCallbacks","onSaveSuccess","props","changedFields","previousValues","findChangedFields","context","console","debug","oldValues","newValues","prefix","allKeys","Set","Object","keys","oldValue","newValue","currentPath","push","Array","isArray","i","nestedChanges","useEntityHistoryPlugin","defaultEnabled","modifyCollection","useCallback","history","name","tabComponent","Builder","position","callbacks","mergeCallbacks","provider","Component"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/HistoryControllerProvider.tsx","../src/components/UserChip.tsx","../src/components/EntityHistoryEntry.tsx","../src/components/EntityHistoryView.tsx","../src/entity_history_callbacks.ts","../src/useEntityHistoryPlugin.tsx"],"sourcesContent":["import React, { PropsWithChildren, useContext } from \"react\";\nimport equal from \"react-fast-compare\"\n\nimport { User } from \"@firecms/core\";\n\nexport type HistoryConfigController = {\n /**\n * Function to get a user by uid.\n * @param uid\n */\n getUser?: (uid: string) => User | null;\n}\n\nexport const HistoryControllerContext = React.createContext<HistoryConfigController>({} as any);\nexport const useHistoryController = (): HistoryConfigController => useContext(HistoryControllerContext);\n\n\nexport interface HistoryControllerProviderProps {\n\n getUser?: (uid: string) => User | null;\n\n}\n\nexport const HistoryControllerProvider = React.memo(\n function HistoryControllerProvider({\n children,\n getUser,\n }: PropsWithChildren<HistoryControllerProviderProps>) {\n\n return (\n <HistoryControllerContext.Provider\n value={{\n getUser,\n }}>\n\n {children}\n\n </HistoryControllerContext.Provider>\n );\n }, equal);\n","import { User } from \"@firecms/core\";\nimport { Chip, Tooltip } from \"@firecms/ui\";\n\nexport function UserChip({ user }: { user: User }) {\n return (\n <Tooltip title={user.email ?? user.uid}>\n <Chip size={\"small\"} className={\"flex items-center\"}>\n {user.photoURL && <img\n className={\"rounded-full w-6 h-6 mr-2\"}\n src={user.photoURL} alt={user.displayName ?? \"User picture\"}/>}\n <span>{user.displayName ?? user.email ?? user.uid}</span>\n </Chip>\n </Tooltip>\n );\n}\n","import * as React from \"react\";\n\nimport {\n Chip,\n cls,\n defaultBorderMixin,\n DescriptionIcon,\n IconButton, KeyboardBackspaceIcon,\n KeyboardTabIcon,\n Tooltip,\n Typography\n} from \"@firecms/ui\";\nimport {\n Entity,\n EntityCollection,\n EntityValues,\n getPropertyInPath,\n getValueInPath,\n PreviewSize,\n Property,\n PropertyPreview,\n resolveCollection,\n ResolvedProperty,\n SkeletonPropertyComponent,\n useAuthController,\n useCustomizationController,\n useNavigationController,\n useSideEntityController\n} from \"@firecms/core\";\nimport { useHistoryController } from \"../HistoryControllerProvider\";\nimport { UserChip } from \"./UserChip\";\n\nexport type EntityPreviewProps = {\n size: PreviewSize,\n actions?: React.ReactNode,\n collection?: EntityCollection,\n hover?: boolean;\n previewKeys?: string[],\n entity: Entity<any>,\n previousValues?: EntityValues<any>;\n onClick?: (e: React.SyntheticEvent) => void;\n};\n\nfunction PreviousValueView({\n previousValueInPath,\n childProperty,\n key\n }: {\n previousValueInPath: any,\n childProperty: Property,\n key: string\n}) {\n if (typeof previousValueInPath === \"string\" || typeof previousValueInPath === \"number\") {\n return <Typography variant={\"caption\"} color={\"secondary\"} className=\"line-through\">\n {previousValueInPath}\n </Typography>;\n } else if (typeof previousValueInPath === \"boolean\") {\n return <Typography variant={\"caption\"} color={\"secondary\"} className=\"line-through\">\n {previousValueInPath ? \"true\" : \"false\"}\n </Typography>;\n\n } else {\n return <Tooltip\n side={\"left\"}\n title={<div className={\"flex flex-col gap-2\"}>\n <Typography variant={\"caption\"} color={\"secondary\"}>\n Previous value\n </Typography>\n <PropertyPreview\n propertyKey={key as string}\n value={previousValueInPath}\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>\n </div>}>\n <KeyboardBackspaceIcon size={\"smallest\"} color={\"disabled\"} className={\"mb-1\"}/>\n </Tooltip>\n }\n}\n\n/**\n * This view is used to display a preview of an entity.\n * It is used by default in reference fields and whenever a reference is displayed.\n */\nexport function EntityHistoryEntry({\n actions,\n hover,\n collection: collectionProp,\n previewKeys,\n onClick,\n size,\n entity,\n previousValues\n }: EntityPreviewProps) {\n\n const authController = useAuthController();\n const customizationController = useCustomizationController();\n\n const navigationController = useNavigationController();\n const sideEntityController = useSideEntityController();\n\n const collection = collectionProp ?? navigationController.getCollection(entity.path);\n const updatedOn = entity.values?.[\"__metadata\"]?.[\"updated_on\"];\n if (!collection) {\n throw Error(`Couldn't find the corresponding collection view for the path: ${entity.path}`);\n }\n\n const updatedBy = entity.values?.[\"__metadata\"]?.[\"updated_by\"];\n const { getUser } = useHistoryController();\n const user = getUser?.(updatedBy);\n\n const resolvedCollection = React.useMemo(() => resolveCollection({\n collection,\n path: entity.path,\n values: entity.values,\n propertyConfigs: customizationController.propertyConfigs,\n authController\n }), [collection]);\n\n return <div className={\"w-full flex flex-col gap-2 mt-4\"}>\n <div className={\"ml-4 flex items-center gap-4\"}>\n <Typography variant={\"body2\"} color={\"secondary\"}>{updatedOn.toLocaleString()}</Typography>\n {!user && updatedBy && <Chip size={\"small\"}>{updatedBy}</Chip>}\n {user && <UserChip user={user}/>}\n </div>\n <div\n className={cls(\n \"bg-white dark:bg-surface-900\",\n \"min-h-[42px]\",\n \"w-full\",\n \"items-center\",\n hover ? \"hover:bg-surface-accent-50 dark:hover:bg-surface-800 group-hover:bg-surface-accent-50 dark:group-hover:bg-surface-800\" : \"\",\n size === \"small\" ? \"p-1\" : \"px-2 py-1\",\n \"flex border rounded-lg\",\n onClick ? \"cursor-pointer\" : \"\",\n defaultBorderMixin\n )}>\n\n\n {actions}\n\n {entity &&\n <Tooltip title={\"See details for this revision\"}\n className={\"my-2 grow-0 shrink-0 self-start\"}>\n <IconButton\n color={\"inherit\"}\n className={\"\"}\n onClick={(e) => {\n\n sideEntityController.open({\n entityId: entity.id,\n path: entity.path,\n allowFullScreen: false,\n collection: {\n ...collection,\n subcollections: undefined,\n entityViews: undefined,\n permissions: {\n create: false,\n delete: false,\n edit: false,\n read: true\n }\n },\n updateUrl: true\n });\n }}>\n <KeyboardTabIcon/>\n </IconButton>\n </Tooltip>}\n\n <div className={\"flex flex-col grow w-full m-1 shrink min-w-0\"}>\n\n {previewKeys && previewKeys.map((key) => {\n const childProperty = getPropertyInPath(resolvedCollection.properties, key);\n\n const valueInPath = getValueInPath(entity.values, key);\n const previousValueInPath = previousValues ? getValueInPath(previousValues, key) : undefined;\n\n const element = childProperty ? (entity\n ? <PropertyPreview\n propertyKey={key as string}\n value={valueInPath}\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>\n : <SkeletonPropertyComponent\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>) :\n <Typography variant={\"body2\"}>\n {typeof valueInPath === \"string\" ? valueInPath : JSON.stringify(valueInPath)}\n </Typography>;\n return (\n <div key={\"ref_prev_\" + key}\n className=\"flex w-full my-1 items-center\">\n <Typography variant={\"caption\"}\n color={\"secondary\"}\n className=\"min-w-[140px] md:min-w-[200px] w-1/5 pr-8 overflow-hidden text-ellipsis text-right\">\n {key}\n </Typography>\n <div className=\"w-4/5\">\n {previousValueInPath !== undefined && previousValueInPath !== valueInPath &&\n <PreviousValueView previousValueInPath={previousValueInPath}\n childProperty={childProperty as ResolvedProperty}\n key={key}/>\n }\n {element}\n </div>\n </div>\n );\n })}\n\n </div>\n\n </div>\n </div>\n}\n\n","import { useEffect, useRef, useState } from \"react\";\nimport {\n ConfirmationDialog,\n Entity,\n EntityCustomViewParams,\n EntityView,\n ErrorBoundary,\n useAuthController,\n useDataSource,\n useSnackbarController\n} from \"@firecms/core\";\nimport { cls, HistoryIcon, IconButton, Label, Tooltip, Typography } from \"@firecms/ui\";\nimport { EntityHistoryEntry } from \"./EntityHistoryEntry\";\n\nexport function EntityHistoryView({\n entity,\n collection,\n formContext\n }: EntityCustomViewParams) {\n\n const authController = useAuthController();\n const snackbarController = useSnackbarController();\n const dirty = formContext?.formex.dirty;\n\n const dataSource = useDataSource();\n const pathAndId = entity ? entity?.path + \"/\" + entity?.id : undefined;\n\n const [revertVersionDialog, setRevertVersionDialog] = useState<Entity | undefined>(undefined);\n const [revisions, setRevisions] = useState<Entity[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [hasMore, setHasMore] = useState(true);\n\n const PAGE_SIZE = 5;\n const [limit, setLimit] = useState(PAGE_SIZE);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const observerRef = useRef<IntersectionObserver | null>(null);\n const loadMoreRef = useRef<HTMLDivElement>(null);\n\n // Load revisions with the current limit\n useEffect(() => {\n if (!pathAndId) return;\n\n setIsLoading(true); // Set loading true when fetching starts\n const listener = dataSource.listenCollection?.({\n path: pathAndId + \"/__history\",\n order: \"desc\",\n orderBy: \"__metadata.updated_on\",\n limit: limit,\n startAfter: undefined,\n onUpdate: (entities) => {\n setRevisions(entities);\n setHasMore(entities.length === limit && entities.length >= PAGE_SIZE); // Ensure we fetched a full page to consider hasMore\n setIsLoading(false);\n },\n onError: (error) => {\n console.error(\"Error fetching history:\", error);\n setIsLoading(false);\n setHasMore(false); // Stop trying if there's an error\n }\n });\n return () => {\n if (typeof listener === \"function\") {\n listener();\n }\n };\n }, [pathAndId, limit, dataSource]);\n\n // Setup intersection observer for infinite scroll\n useEffect(() => {\n const currentContainer = containerRef.current;\n const currentLoadMore = loadMoreRef.current;\n\n // Conditions for active observation\n if (!currentContainer || !currentLoadMore || !hasMore || isLoading) {\n // If we shouldn't be observing, ensure any existing observer is disconnected\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n return;\n }\n\n // Options for the IntersectionObserver\n const options = {\n root: currentContainer,\n rootMargin: \"0px 0px 200px 0px\", // Trigger 200px before the sentinel is at the bottom edge\n threshold: 0.01 // Trigger if even a small part is visible within the rootMargin\n };\n\n // The callback for when the sentinel's intersection state changes\n const handleObserver = (entries: IntersectionObserverEntry[]) => {\n const target = entries[0];\n if (target.isIntersecting && hasMore && !isLoading) {\n // No need to setIsLoading(true) here, it's done in the data fetching useEffect\n setLimit(prev => prev + PAGE_SIZE);\n }\n };\n\n const observer = new IntersectionObserver(handleObserver, options);\n observer.observe(currentLoadMore);\n observerRef.current = observer; // Store the new observer\n\n // Cleanup function for this effect instance\n return () => {\n observer.disconnect(); // Disconnect the observer created in *this* effect run\n if (observerRef.current === observer) {\n observerRef.current = null;\n }\n };\n // Re-run if hasMore, isLoading changes, or if revisions.length changes (which might make loadMoreRef available/unavailable)\n }, [hasMore, isLoading, revisions.length]);\n\n if (!entity) {\n return <div className=\"flex items-center justify-center h-full\">\n <Label>History is only available for existing entities</Label>\n </div>\n }\n\n function doRevert(revertVersion: Entity) {\n if (!entity) {\n throw new Error(\"No entity to revert\");\n }\n const revertValues = {\n ...revertVersion.values,\n __metadata: {\n ...revertVersion.values?.[\"__metadata\"],\n reverted: true,\n updated_on: new Date(),\n updated_by: authController.user?.uid ?? null,\n }\n };\n const saveReverted = dataSource.saveEntity({\n path: entity.path,\n entityId: entity.id,\n values: revertValues,\n collection,\n status: \"existing\"\n });\n const saveRevertedHistory = dataSource.saveEntity({\n path: revertVersion.path,\n entityId: revertVersion.id,\n values: revertValues,\n collection,\n status: \"existing\"\n });\n return Promise.all([saveReverted, saveRevertedHistory])\n .then(() => {\n formContext.formex.resetForm({\n values: revertVersion.values\n });\n setRevertVersionDialog(undefined);\n snackbarController.open({\n message: \"Reverted version\",\n type: \"info\"\n });\n }\n ).catch((error) => {\n console.error(\"Error reverting entity:\", error);\n snackbarController.open({\n message: \"Error reverting entity\",\n type: \"error\"\n });\n });\n\n }\n\n return <div\n ref={containerRef}\n className={cls(\"relative flex-1 h-full overflow-auto w-full flex flex-col gap-4 p-8\")}>\n <div className=\"flex flex-col gap-2 max-w-6xl mx-auto w-full\">\n\n <Typography variant={\"h5\"} className={\"mt-24 ml-4\"}>\n History\n </Typography>\n\n {revisions.length === 0 && <>\n <Label className={\"ml-4 mt-8\"}>\n No history available\n </Label>\n <Typography variant={\"caption\"} className={\"ml-4\"}>\n When you save an entity, a new version is created and stored in the history.\n </Typography>\n </>}\n\n {revisions.map((revision, index) => {\n const previewKeys = revision.values?.[\"__metadata\"]?.[\"changed_fields\"];\n const previousValues: object | undefined = revision.values?.[\"__metadata\"]?.[\"previous_values\"];\n return <div key={index} className=\"flex flex-cols gap-2 w-full\">\n <EntityHistoryEntry size={\"large\"}\n entity={revision}\n collection={collection}\n previewKeys={previewKeys}\n previousValues={previousValues}\n actions={\n <Tooltip title={\"Revert to this version\"}\n className={\"m-2 grow-0 self-start\"}>\n <IconButton\n onClick={() => {\n if (dirty) {\n snackbarController.open({\n message: \"Please save or discard your changes before reverting\",\n type: \"warning\"\n });\n } else {\n setRevertVersionDialog(revision);\n }\n }}>\n <HistoryIcon/>\n </IconButton>\n </Tooltip>}\n />\n </div>\n })}\n\n {/* Load more sentinel element */}\n {revisions.length > 0 && (\n <div\n ref={loadMoreRef}\n className=\"py-4 text-center\"\n >\n {isLoading && <Label>Loading more...</Label>}\n {!hasMore && revisions.length > PAGE_SIZE && <Label>No more history available</Label>}\n </div>\n )}\n </div>\n\n <ErrorBoundary>\n <ConfirmationDialog open={Boolean(revertVersionDialog)}\n onAccept={function (): void {\n if (!revertVersionDialog) return;\n doRevert(revertVersionDialog);\n }}\n onCancel={function (): void {\n setRevertVersionDialog(undefined);\n }}\n title={<Typography variant={\"subtitle2\"}>Revert data to this version?</Typography>}\n body={revertVersionDialog ?\n <EntityView entity={revertVersionDialog}\n collection={collection}\n path={entity?.path}/> : null}/>\n </ErrorBoundary>\n </div>\n}\n","import { EntityCallbacks } from \"@firecms/core\";\nimport equal from \"react-fast-compare\"\n\nexport const entityHistoryCallbacks: EntityCallbacks = {\n onSaveSuccess: async (props) => {\n\n const changedFields = props.previousValues ? findChangedFields(props.previousValues, props.values) : null;\n const uid = props.context.authController.user?.uid;\n props.context.dataSource.saveEntity({\n path: props.path + \"/\" + props.entityId + \"/__history\",\n values: {\n ...props.values,\n __metadata: {\n previous_values: props.previousValues,\n changed_fields: changedFields,\n updated_on: new Date(),\n updated_by: uid,\n }\n },\n status: \"new\"\n }).then(() => {\n console.debug(\"History saved for\", props.path, props.entityId);\n });\n }\n}\n\nfunction findChangedFields<M extends object>(oldValues: M, newValues: M, prefix: string = \"\"): string[] {\n const changedFields: string[] = [];\n\n // Handle null/undefined cases\n if (equal(oldValues, newValues)) return changedFields;\n if (!oldValues || !newValues) return [prefix || \".\"];\n\n // Get all unique keys from both objects\n const allKeys = new Set([\n ...Object.keys(oldValues),\n ...Object.keys(newValues)\n ]);\n\n for (const key of allKeys) {\n const oldValue = oldValues[key as keyof M];\n const newValue = newValues[key as keyof M];\n const currentPath = prefix ? `${prefix}.${key}` : key;\n\n // If key exists only in one object\n if ((key in oldValues) !== (key in newValues)) {\n changedFields.push(currentPath);\n continue;\n }\n\n // If values are identical (deep equality)\n if (equal(oldValue, newValue)) continue;\n\n // Handle arrays\n if (Array.isArray(oldValue) && Array.isArray(newValue)) {\n if (oldValue.length !== newValue.length) {\n changedFields.push(currentPath);\n } else {\n // Check if any array element changed\n for (let i = 0; i < oldValue.length; i++) {\n if (\n typeof oldValue[i] === \"object\" && oldValue[i] !== null &&\n typeof newValue[i] === \"object\" && newValue[i] !== null\n ) {\n const nestedChanges = findChangedFields(\n oldValue[i] as object,\n newValue[i] as object,\n `${currentPath}[${i}]`\n );\n if (nestedChanges.length > 0) {\n changedFields.push(currentPath);\n break;\n }\n } else if (!equal(oldValue[i], newValue[i])) {\n changedFields.push(currentPath);\n break;\n }\n }\n }\n }\n // Handle nested objects\n else if (\n typeof oldValue === \"object\" && oldValue !== null &&\n typeof newValue === \"object\" && newValue !== null\n ) {\n const nestedChanges = findChangedFields(\n oldValue as object,\n newValue as object,\n currentPath\n );\n changedFields.push(...nestedChanges);\n }\n // Handle primitives\n else {\n changedFields.push(currentPath);\n }\n }\n\n return changedFields;\n}\n","import { useCallback, useMemo } from \"react\";\nimport { EntityCollection, FireCMSPlugin, mergeCallbacks, User } from \"@firecms/core\";\nimport { EntityHistoryView } from \"./components/EntityHistoryView\";\nimport { HistoryIcon } from \"@firecms/ui\";\nimport { entityHistoryCallbacks } from \"./entity_history_callbacks\";\nimport { HistoryControllerProvider } from \"./HistoryControllerProvider\";\n\n/**\n * This plugin adds a history view to the entity side panel.\n */\nexport function useEntityHistoryPlugin(props?: EntityHistoryPluginProps): FireCMSPlugin<any, any, any, EntityHistoryPluginProps> {\n\n const { defaultEnabled = false } = props ?? {};\n\n const modifyCollection = useCallback((collection: EntityCollection) => {\n if (collection.history === true || (defaultEnabled && collection.history !== false)) {\n return {\n ...collection,\n entityViews: [\n ...(collection.entityViews ?? []),\n {\n key: \"__history\",\n name: \"History\",\n tabComponent: <HistoryIcon size={\"small\"}/>,\n Builder: EntityHistoryView,\n position: \"start\"\n }\n ],\n callbacks: mergeCallbacks(collection.callbacks, entityHistoryCallbacks)\n } satisfies EntityCollection;\n }\n return collection;\n }, []);\n\n return useMemo(() => ({\n key: \"entity_history\",\n provider: {\n Component: HistoryControllerProvider,\n props: {\n getUser: props?.getUser\n }\n },\n collection: {\n modifyCollection\n }\n } satisfies FireCMSPlugin), [props]);\n}\n\nexport type EntityHistoryPluginProps = {\n /**\n * If true, the history view will be enabled to all collections by default.\n * Each collection can override this value by setting the `history` property.\n */\n defaultEnabled?: boolean;\n\n /**\n * Function to get the user object from the uid.\n * @param uid\n */\n getUser?: (uid: string) => User | null;\n}\n"],"names":["HistoryControllerContext","React","createContext","useHistoryController","useContext","HistoryControllerProvider","memo","t0","$","_c","children","getUser","t1","t2","equal","UserChip","user","email","uid","displayName","photoURL","t3","t4","t5","t6","PreviousValueView","previousValueInPath","childProperty","key","Symbol","for","EntityHistoryEntry","actions","hover","collection","collectionProp","previewKeys","onClick","size","entity","previousValues","authController","useAuthController","customizationController","useCustomizationController","navigationController","useNavigationController","sideEntityController","useSideEntityController","getCollection","path","updatedOn","values","Error","updatedBy","resolvedCollection","useMemo","resolveCollection","propertyConfigs","toLocaleString","cls","defaultBorderMixin","e","open","entityId","id","allowFullScreen","subcollections","undefined","entityViews","permissions","create","delete","edit","read","updateUrl","map","getPropertyInPath","properties","valueInPath","getValueInPath","element","JSON","stringify","EntityHistoryView","formContext","snackbarController","useSnackbarController","dirty","formex","dataSource","useDataSource","pathAndId","revertVersionDialog","setRevertVersionDialog","useState","revisions","setRevisions","isLoading","setIsLoading","hasMore","setHasMore","limit","setLimit","containerRef","useRef","observerRef","loadMoreRef","listener","listenCollection","order","orderBy","startAfter","onUpdate","entities","length","onError","error","useEffect","currentContainer","current","currentLoadMore","disconnect","options","root","rootMargin","threshold","handleObserver","entries","target","isIntersecting","prev","observer","IntersectionObserver","observe","doRevert","revertVersion","revertValues","__metadata","reverted","updated_on","Date","updated_by","saveReverted","saveEntity","status","saveRevertedHistory","Promise","all","then","resetForm","message","type","catch","error_0","t7","t8","t9","t10","t11","revision","index","changed_fields","previous_values","t12","t13","Boolean","t14","t15","t16","t17","t18","t19","entityHistoryCallbacks","onSaveSuccess","props","changedFields","findChangedFields","context","console","debug","oldValues","newValues","prefix","allKeys","Set","Object","keys","oldValue","newValue","currentPath","push","Array","isArray","i","nestedChanges","useEntityHistoryPlugin","defaultEnabled","modifyCollection","useCallback","history","name","tabComponent","Builder","position","callbacks","mergeCallbacks","provider","Component"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -97,15 +97,86 @@
97
97
  }
98
98
  return t6;
99
99
  }
100
+ function PreviousValueView(t0) {
101
+ const $ = reactCompilerRuntime.c(12);
102
+ const {
103
+ previousValueInPath,
104
+ childProperty,
105
+ key
106
+ } = t0;
107
+ if (typeof previousValueInPath === "string" || typeof previousValueInPath === "number") {
108
+ let t1;
109
+ if ($[0] !== previousValueInPath) {
110
+ t1 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", color: "secondary", className: "line-through", children: previousValueInPath });
111
+ $[0] = previousValueInPath;
112
+ $[1] = t1;
113
+ } else {
114
+ t1 = $[1];
115
+ }
116
+ return t1;
117
+ } else {
118
+ if (typeof previousValueInPath === "boolean") {
119
+ const t1 = previousValueInPath ? "true" : "false";
120
+ let t2;
121
+ if ($[2] !== t1) {
122
+ t2 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", color: "secondary", className: "line-through", children: t1 });
123
+ $[2] = t1;
124
+ $[3] = t2;
125
+ } else {
126
+ t2 = $[3];
127
+ }
128
+ return t2;
129
+ } else {
130
+ let t1;
131
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
132
+ t1 = /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", color: "secondary", children: "Previous value" });
133
+ $[4] = t1;
134
+ } else {
135
+ t1 = $[4];
136
+ }
137
+ const t2 = key;
138
+ const t3 = childProperty;
139
+ let t4;
140
+ if ($[5] !== previousValueInPath || $[6] !== t2 || $[7] !== t3) {
141
+ t4 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
142
+ t1,
143
+ /* @__PURE__ */ jsxRuntime.jsx(core.PropertyPreview, { propertyKey: t2, value: previousValueInPath, property: t3, size: "small" })
144
+ ] });
145
+ $[5] = previousValueInPath;
146
+ $[6] = t2;
147
+ $[7] = t3;
148
+ $[8] = t4;
149
+ } else {
150
+ t4 = $[8];
151
+ }
152
+ let t5;
153
+ if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
154
+ t5 = /* @__PURE__ */ jsxRuntime.jsx(ui.KeyboardBackspaceIcon, { size: "smallest", color: "disabled", className: "mb-1" });
155
+ $[9] = t5;
156
+ } else {
157
+ t5 = $[9];
158
+ }
159
+ let t6;
160
+ if ($[10] !== t4) {
161
+ t6 = /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { side: "left", title: t4, children: t5 });
162
+ $[10] = t4;
163
+ $[11] = t6;
164
+ } else {
165
+ t6 = $[11];
166
+ }
167
+ return t6;
168
+ }
169
+ }
170
+ }
100
171
  function EntityHistoryEntry({
101
172
  actions,
102
- disabled,
103
173
  hover,
104
174
  collection: collectionProp,
105
175
  previewKeys,
106
176
  onClick,
107
177
  size,
108
- entity
178
+ entity,
179
+ previousValues
109
180
  }) {
110
181
  const authController = core.useAuthController();
111
182
  const customizationController = core.useCustomizationController();
@@ -158,17 +229,21 @@
158
229
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col grow w-full m-1 shrink min-w-0", children: previewKeys && previewKeys.map((key) => {
159
230
  const childProperty = core.getPropertyInPath(resolvedCollection.properties, key);
160
231
  const valueInPath = core.getValueInPath(entity.values, key);
232
+ const previousValueInPath = previousValues ? core.getValueInPath(previousValues, key) : void 0;
161
233
  const element = childProperty ? entity ? /* @__PURE__ */ jsxRuntime.jsx(core.PropertyPreview, { propertyKey: key, value: valueInPath, property: childProperty, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(core.SkeletonPropertyComponent, { property: childProperty, size: "small" }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "body2", children: typeof valueInPath === "string" ? valueInPath : JSON.stringify(valueInPath) });
162
234
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full my-1 items-center", children: [
163
235
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", color: "secondary", className: "min-w-[140px] md:min-w-[200px] w-1/5 pr-8 overflow-hidden text-ellipsis text-right", children: key }),
164
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-4/5", children: element })
236
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-4/5", children: [
237
+ previousValueInPath !== void 0 && previousValueInPath !== valueInPath && /* @__PURE__ */ jsxRuntime.jsx(PreviousValueView, { previousValueInPath, childProperty }, key),
238
+ element
239
+ ] })
165
240
  ] }, "ref_prev_" + key);
166
241
  }) })
167
242
  ] })
168
243
  ] });
169
244
  }
170
245
  function EntityHistoryView(t0) {
171
- const $ = reactCompilerRuntime.c(53);
246
+ const $ = reactCompilerRuntime.c(58);
172
247
  const {
173
248
  entity,
174
249
  collection,
@@ -384,7 +459,8 @@
384
459
  if ($[30] !== collection || $[31] !== dirty || $[32] !== snackbarController) {
385
460
  t112 = (revision, index) => {
386
461
  const previewKeys = revision.values?.__metadata?.changed_fields;
387
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-cols gap-2 w-full", children: /* @__PURE__ */ jsxRuntime.jsx(EntityHistoryEntry, { size: "large", entity: revision, collection, previewKeys, actions: /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Revert to this version", className: "m-2 grow-0 self-start", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { onClick: () => {
462
+ const previousValues = revision.values?.__metadata?.previous_values;
463
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-cols gap-2 w-full", children: /* @__PURE__ */ jsxRuntime.jsx(EntityHistoryEntry, { size: "large", entity: revision, collection, previewKeys, previousValues, actions: /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Revert to this version", className: "m-2 grow-0 self-start", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { onClick: () => {
388
464
  if (dirty) {
389
465
  snackbarController.open({
390
466
  message: "Please save or discard your changes before reverting",
@@ -468,27 +544,38 @@
468
544
  t16 = $[46];
469
545
  }
470
546
  let t17;
471
- if ($[47] !== t13 || $[48] !== t14) {
472
- t17 = /* @__PURE__ */ jsxRuntime.jsx(core.ConfirmationDialog, { open: t13, onAccept: t14, onCancel: t15, title: t16 });
473
- $[47] = t13;
474
- $[48] = t14;
475
- $[49] = t17;
547
+ if ($[47] !== collection || $[48] !== entity?.path || $[49] !== revertVersionDialog) {
548
+ t17 = revertVersionDialog ? /* @__PURE__ */ jsxRuntime.jsx(core.EntityView, { entity: revertVersionDialog, collection, path: entity?.path }) : null;
549
+ $[47] = collection;
550
+ $[48] = entity?.path;
551
+ $[49] = revertVersionDialog;
552
+ $[50] = t17;
476
553
  } else {
477
- t17 = $[49];
554
+ t17 = $[50];
478
555
  }
479
556
  let t18;
480
- if ($[50] !== t12 || $[51] !== t17) {
481
- t18 = /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: t7, children: [
557
+ if ($[51] !== t13 || $[52] !== t14 || $[53] !== t17) {
558
+ t18 = /* @__PURE__ */ jsxRuntime.jsx(core.ErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx(core.ConfirmationDialog, { open: t13, onAccept: t14, onCancel: t15, title: t16, body: t17 }) });
559
+ $[51] = t13;
560
+ $[52] = t14;
561
+ $[53] = t17;
562
+ $[54] = t18;
563
+ } else {
564
+ t18 = $[54];
565
+ }
566
+ let t19;
567
+ if ($[55] !== t12 || $[56] !== t18) {
568
+ t19 = /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: t7, children: [
482
569
  t12,
483
- t17
570
+ t18
484
571
  ] });
485
- $[50] = t12;
486
- $[51] = t17;
487
- $[52] = t18;
572
+ $[55] = t12;
573
+ $[56] = t18;
574
+ $[57] = t19;
488
575
  } else {
489
- t18 = $[52];
576
+ t19 = $[57];
490
577
  }
491
- return t18;
578
+ return t19;
492
579
  }
493
580
  const entityHistoryCallbacks = {
494
581
  onSaveSuccess: async (props) => {
@@ -499,6 +586,7 @@
499
586
  values: {
500
587
  ...props.values,
501
588
  __metadata: {
589
+ previous_values: props.previousValues,
502
590
  changed_fields: changedFields,
503
591
  updated_on: /* @__PURE__ */ new Date(),
504
592
  updated_by: uid
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/HistoryControllerProvider.tsx","../src/components/UserChip.tsx","../src/components/EntityHistoryEntry.tsx","../src/components/EntityHistoryView.tsx","../src/entity_history_callbacks.ts","../src/useEntityHistoryPlugin.tsx"],"sourcesContent":["import React, { PropsWithChildren, useContext } from \"react\";\nimport equal from \"react-fast-compare\"\n\nimport { User } from \"@firecms/core\";\n\nexport type HistoryConfigController = {\n /**\n * Function to get a user by uid.\n * @param uid\n */\n getUser?: (uid: string) => User | null;\n}\n\nexport const HistoryControllerContext = React.createContext<HistoryConfigController>({} as any);\nexport const useHistoryController = (): HistoryConfigController => useContext(HistoryControllerContext);\n\n\nexport interface HistoryControllerProviderProps {\n\n getUser?: (uid: string) => User | null;\n\n}\n\nexport const HistoryControllerProvider = React.memo(\n function HistoryControllerProvider({\n children,\n getUser,\n }: PropsWithChildren<HistoryControllerProviderProps>) {\n\n return (\n <HistoryControllerContext.Provider\n value={{\n getUser,\n }}>\n\n {children}\n\n </HistoryControllerContext.Provider>\n );\n }, equal);\n","import { User } from \"@firecms/core\";\nimport { Chip, Tooltip } from \"@firecms/ui\";\n\nexport function UserChip({ user }: { user: User }) {\n return (\n <Tooltip title={user.email ?? user.uid}>\n <Chip size={\"small\"} className={\"flex items-center\"}>\n {user.photoURL && <img\n className={\"rounded-full w-6 h-6 mr-2\"}\n src={user.photoURL} alt={user.displayName ?? \"User picture\"}/>}\n <span>{user.displayName ?? user.email ?? user.uid}</span>\n </Chip>\n </Tooltip>\n );\n}\n","import * as React from \"react\";\n\nimport { Chip, cls, defaultBorderMixin, IconButton, KeyboardTabIcon, Tooltip, Typography } from \"@firecms/ui\";\nimport {\n Entity,\n EntityCollection,\n getPropertyInPath,\n getValueInPath,\n PreviewSize,\n PropertyPreview,\n resolveCollection,\n ResolvedProperty,\n SkeletonPropertyComponent,\n useAuthController,\n useCustomizationController,\n useNavigationController,\n useSideEntityController\n} from \"@firecms/core\";\nimport { useHistoryController } from \"../HistoryControllerProvider\";\nimport { UserChip } from \"./UserChip\";\n\nexport type EntityPreviewProps = {\n size: PreviewSize,\n actions?: React.ReactNode,\n collection?: EntityCollection,\n hover?: boolean;\n previewKeys?: string[],\n disabled?: boolean,\n entity: Entity<any>,\n onClick?: (e: React.SyntheticEvent) => void;\n};\n\n/**\n * This view is used to display a preview of an entity.\n * It is used by default in reference fields and whenever a reference is displayed.\n */\nexport function EntityHistoryEntry({\n actions,\n disabled,\n hover,\n collection: collectionProp,\n previewKeys,\n onClick,\n size,\n entity\n }: EntityPreviewProps) {\n\n const authController = useAuthController();\n const customizationController = useCustomizationController();\n\n const navigationController = useNavigationController();\n const sideEntityController = useSideEntityController();\n\n const collection = collectionProp ?? navigationController.getCollection(entity.path);\n const updatedOn = entity.values?.[\"__metadata\"]?.[\"updated_on\"];\n if (!collection) {\n throw Error(`Couldn't find the corresponding collection view for the path: ${entity.path}`);\n }\n\n const updatedBy = entity.values?.[\"__metadata\"]?.[\"updated_by\"];\n const { getUser } = useHistoryController();\n const user = getUser?.(updatedBy);\n\n const resolvedCollection = React.useMemo(() => resolveCollection({\n collection,\n path: entity.path,\n values: entity.values,\n propertyConfigs: customizationController.propertyConfigs,\n authController\n }), [collection]);\n\n return <div className={\"w-full flex flex-col gap-2 mt-4\"}>\n <div className={\"ml-4 flex items-center gap-4\"}>\n <Typography variant={\"body2\"} color={\"secondary\"}>{updatedOn.toLocaleString()}</Typography>\n {!user && updatedBy && <Chip size={\"small\"}>{updatedBy}</Chip>}\n {user && <UserChip user={user}/>}\n </div>\n <div\n className={cls(\n \"bg-white dark:bg-surface-900\",\n \"min-h-[42px]\",\n \"w-full\",\n \"items-center\",\n hover ? \"hover:bg-surface-accent-50 dark:hover:bg-surface-800 group-hover:bg-surface-accent-50 dark:group-hover:bg-surface-800\" : \"\",\n size === \"small\" ? \"p-1\" : \"px-2 py-1\",\n \"flex border rounded-lg\",\n onClick ? \"cursor-pointer\" : \"\",\n defaultBorderMixin\n )}>\n\n\n {actions}\n\n {entity &&\n <Tooltip title={\"See details for this revision\"}\n className={\"my-2 grow-0 shrink-0 self-start\"}>\n <IconButton\n color={\"inherit\"}\n className={\"\"}\n onClick={(e) => {\n\n sideEntityController.open({\n entityId: entity.id,\n path: entity.path,\n allowFullScreen: false,\n collection: {\n ...collection,\n subcollections: undefined,\n entityViews: undefined,\n permissions: {\n create: false,\n delete: false,\n edit: false,\n read: true\n }\n },\n updateUrl: true\n });\n }}>\n <KeyboardTabIcon/>\n </IconButton>\n </Tooltip>}\n\n <div className={\"flex flex-col grow w-full m-1 shrink min-w-0\"}>\n\n {previewKeys && previewKeys.map((key) => {\n const childProperty = getPropertyInPath(resolvedCollection.properties, key);\n\n const valueInPath = getValueInPath(entity.values, key);\n const element = childProperty ? (entity\n ? <PropertyPreview\n propertyKey={key as string}\n value={valueInPath}\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>\n : <SkeletonPropertyComponent\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>) :\n <Typography variant={\"body2\"}>\n {typeof valueInPath === \"string\" ? valueInPath : JSON.stringify(valueInPath)}\n </Typography>;\n return (\n <div key={\"ref_prev_\" + key}\n className=\"flex w-full my-1 items-center\">\n <Typography variant={\"caption\"}\n color={\"secondary\"}\n className=\"min-w-[140px] md:min-w-[200px] w-1/5 pr-8 overflow-hidden text-ellipsis text-right\">\n {key}\n </Typography>\n <div className=\"w-4/5\">\n {\n element\n }\n </div>\n </div>\n );\n })}\n\n </div>\n\n </div>\n </div>\n}\n\n","import { useEffect, useRef, useState } from \"react\";\nimport {\n ConfirmationDialog,\n Entity,\n EntityCustomViewParams,\n useAuthController,\n useDataSource,\n useSnackbarController\n} from \"@firecms/core\";\nimport { cls, HistoryIcon, IconButton, Label, Tooltip, Typography } from \"@firecms/ui\";\nimport { EntityHistoryEntry } from \"./EntityHistoryEntry\";\n\nexport function EntityHistoryView({\n entity,\n collection,\n formContext\n }: EntityCustomViewParams) {\n\n const authController = useAuthController();\n const snackbarController = useSnackbarController();\n const dirty = formContext?.formex.dirty;\n\n const dataSource = useDataSource();\n const pathAndId = entity ? entity?.path + \"/\" + entity?.id : undefined;\n\n const [revertVersionDialog, setRevertVersionDialog] = useState<Entity | undefined>(undefined);\n const [revisions, setRevisions] = useState<Entity[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [hasMore, setHasMore] = useState(true);\n\n const PAGE_SIZE = 5;\n const [limit, setLimit] = useState(PAGE_SIZE);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const observerRef = useRef<IntersectionObserver | null>(null);\n const loadMoreRef = useRef<HTMLDivElement>(null);\n\n // Load revisions with the current limit\n useEffect(() => {\n if (!pathAndId) return;\n\n setIsLoading(true); // Set loading true when fetching starts\n const listener = dataSource.listenCollection?.({\n path: pathAndId + \"/__history\",\n order: \"desc\",\n orderBy: \"__metadata.updated_on\",\n limit: limit,\n startAfter: undefined,\n onUpdate: (entities) => {\n setRevisions(entities);\n setHasMore(entities.length === limit && entities.length >= PAGE_SIZE); // Ensure we fetched a full page to consider hasMore\n setIsLoading(false);\n },\n onError: (error) => {\n console.error(\"Error fetching history:\", error);\n setIsLoading(false);\n setHasMore(false); // Stop trying if there's an error\n }\n });\n return () => {\n if (typeof listener === \"function\") {\n listener();\n }\n };\n }, [pathAndId, limit, dataSource]);\n\n // Setup intersection observer for infinite scroll\n useEffect(() => {\n const currentContainer = containerRef.current;\n const currentLoadMore = loadMoreRef.current;\n\n // Conditions for active observation\n if (!currentContainer || !currentLoadMore || !hasMore || isLoading) {\n // If we shouldn't be observing, ensure any existing observer is disconnected\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n return;\n }\n\n // Options for the IntersectionObserver\n const options = {\n root: currentContainer,\n rootMargin: \"0px 0px 200px 0px\", // Trigger 200px before the sentinel is at the bottom edge\n threshold: 0.01 // Trigger if even a small part is visible within the rootMargin\n };\n\n // The callback for when the sentinel's intersection state changes\n const handleObserver = (entries: IntersectionObserverEntry[]) => {\n const target = entries[0];\n if (target.isIntersecting && hasMore && !isLoading) {\n // No need to setIsLoading(true) here, it's done in the data fetching useEffect\n setLimit(prev => prev + PAGE_SIZE);\n }\n };\n\n const observer = new IntersectionObserver(handleObserver, options);\n observer.observe(currentLoadMore);\n observerRef.current = observer; // Store the new observer\n\n // Cleanup function for this effect instance\n return () => {\n observer.disconnect(); // Disconnect the observer created in *this* effect run\n if (observerRef.current === observer) {\n observerRef.current = null;\n }\n };\n // Re-run if hasMore, isLoading changes, or if revisions.length changes (which might make loadMoreRef available/unavailable)\n }, [hasMore, isLoading, revisions.length]);\n\n if (!entity) {\n return <div className=\"flex items-center justify-center h-full\">\n <Label>History is only available for existing entities</Label>\n </div>\n }\n\n function doRevert(revertVersion: Entity) {\n if (!entity) {\n throw new Error(\"No entity to revert\");\n }\n const revertValues = {\n ...revertVersion.values,\n __metadata: {\n ...revertVersion.values?.[\"__metadata\"],\n reverted: true,\n updated_on: new Date(),\n updated_by: authController.user?.uid ?? null,\n }\n };\n const saveReverted = dataSource.saveEntity({\n path: entity.path,\n entityId: entity.id,\n values: revertValues,\n collection,\n status: \"existing\"\n });\n const saveRevertedHistory = dataSource.saveEntity({\n path: revertVersion.path,\n entityId: revertVersion.id,\n values: revertValues,\n collection,\n status: \"existing\"\n });\n return Promise.all([saveReverted, saveRevertedHistory])\n .then(() => {\n formContext.formex.resetForm({\n values: revertVersion.values\n });\n setRevertVersionDialog(undefined);\n snackbarController.open({\n message: \"Reverted version\",\n type: \"info\"\n });\n }\n ).catch((error) => {\n console.error(\"Error reverting entity:\", error);\n snackbarController.open({\n message: \"Error reverting entity\",\n type: \"error\"\n });\n });\n\n }\n\n return <div\n ref={containerRef}\n className={cls(\"relative flex-1 h-full overflow-auto w-full flex flex-col gap-4 p-8\")}>\n <div className=\"flex flex-col gap-2 max-w-6xl mx-auto w-full\">\n\n <Typography variant={\"h5\"} className={\"mt-24 ml-4\"}>\n History\n </Typography>\n\n {revisions.length === 0 && <>\n <Label className={\"ml-4 mt-8\"}>\n No history available\n </Label>\n <Typography variant={\"caption\"} className={\"ml-4\"}>\n When you save an entity, a new version is created and stored in the history.\n </Typography>\n </>}\n\n {revisions.map((revision, index) => {\n const previewKeys = revision.values?.[\"__metadata\"]?.[\"changed_fields\"];\n return <div key={index} className=\"flex flex-cols gap-2 w-full\">\n <EntityHistoryEntry size={\"large\"}\n entity={revision}\n collection={collection}\n previewKeys={previewKeys}\n actions={\n <Tooltip title={\"Revert to this version\"}\n className={\"m-2 grow-0 self-start\"}>\n <IconButton\n onClick={() => {\n if (dirty) {\n snackbarController.open({\n message: \"Please save or discard your changes before reverting\",\n type: \"warning\"\n });\n } else {\n setRevertVersionDialog(revision);\n }\n }}>\n <HistoryIcon/>\n </IconButton>\n </Tooltip>}\n />\n </div>\n })}\n\n {/* Load more sentinel element */}\n {revisions.length > 0 && (\n <div\n ref={loadMoreRef}\n className=\"py-4 text-center\"\n >\n {isLoading && <Label>Loading more...</Label>}\n {!hasMore && revisions.length > PAGE_SIZE && <Label>No more history available</Label>}\n </div>\n )}\n </div>\n\n <ConfirmationDialog open={Boolean(revertVersionDialog)}\n onAccept={function (): void {\n if (!revertVersionDialog) return;\n doRevert(revertVersionDialog);\n }}\n onCancel={function (): void {\n setRevertVersionDialog(undefined);\n }}\n title={<Typography variant={\"subtitle2\"}>Revert data to this version?</Typography>}/>\n </div>\n}\n","import { EntityCallbacks } from \"@firecms/core\";\nimport equal from \"react-fast-compare\"\n\nexport const entityHistoryCallbacks: EntityCallbacks = {\n onSaveSuccess: async (props) => {\n\n const changedFields = props.previousValues ? findChangedFields(props.previousValues, props.values) : null;\n const uid = props.context.authController.user?.uid;\n props.context.dataSource.saveEntity({\n path: props.path + \"/\" + props.entityId + \"/__history\",\n values: {\n ...props.values,\n __metadata: {\n changed_fields: changedFields,\n updated_on: new Date(),\n updated_by: uid,\n }\n },\n status: \"new\"\n }).then(() => {\n console.debug(\"History saved for\", props.path, props.entityId);\n });\n }\n}\n\nfunction findChangedFields<M extends object>(oldValues: M, newValues: M, prefix: string = \"\"): string[] {\n const changedFields: string[] = [];\n\n // Handle null/undefined cases\n if (equal(oldValues, newValues)) return changedFields;\n if (!oldValues || !newValues) return [prefix || \".\"];\n\n // Get all unique keys from both objects\n const allKeys = new Set([\n ...Object.keys(oldValues),\n ...Object.keys(newValues)\n ]);\n\n for (const key of allKeys) {\n const oldValue = oldValues[key as keyof M];\n const newValue = newValues[key as keyof M];\n const currentPath = prefix ? `${prefix}.${key}` : key;\n\n // If key exists only in one object\n if ((key in oldValues) !== (key in newValues)) {\n changedFields.push(currentPath);\n continue;\n }\n\n // If values are identical (deep equality)\n if (equal(oldValue, newValue)) continue;\n\n // Handle arrays\n if (Array.isArray(oldValue) && Array.isArray(newValue)) {\n if (oldValue.length !== newValue.length) {\n changedFields.push(currentPath);\n } else {\n // Check if any array element changed\n for (let i = 0; i < oldValue.length; i++) {\n if (\n typeof oldValue[i] === \"object\" && oldValue[i] !== null &&\n typeof newValue[i] === \"object\" && newValue[i] !== null\n ) {\n const nestedChanges = findChangedFields(\n oldValue[i] as object,\n newValue[i] as object,\n `${currentPath}[${i}]`\n );\n if (nestedChanges.length > 0) {\n changedFields.push(currentPath);\n break;\n }\n } else if (!equal(oldValue[i], newValue[i])) {\n changedFields.push(currentPath);\n break;\n }\n }\n }\n }\n // Handle nested objects\n else if (\n typeof oldValue === \"object\" && oldValue !== null &&\n typeof newValue === \"object\" && newValue !== null\n ) {\n const nestedChanges = findChangedFields(\n oldValue as object,\n newValue as object,\n currentPath\n );\n changedFields.push(...nestedChanges);\n }\n // Handle primitives\n else {\n changedFields.push(currentPath);\n }\n }\n\n return changedFields;\n}\n","import { useCallback, useMemo } from \"react\";\nimport { EntityCollection, FireCMSPlugin, mergeCallbacks, User } from \"@firecms/core\";\nimport { EntityHistoryView } from \"./components/EntityHistoryView\";\nimport { HistoryIcon } from \"@firecms/ui\";\nimport { entityHistoryCallbacks } from \"./entity_history_callbacks\";\nimport { HistoryControllerProvider } from \"./HistoryControllerProvider\";\n\n/**\n * This plugin adds a history view to the entity side panel.\n */\nexport function useEntityHistoryPlugin(props?: EntityHistoryPluginProps): FireCMSPlugin<any, any, any, EntityHistoryPluginProps> {\n\n const { defaultEnabled = false } = props ?? {};\n\n const modifyCollection = useCallback((collection: EntityCollection) => {\n if (collection.history === true || (defaultEnabled && collection.history !== false)) {\n return {\n ...collection,\n entityViews: [\n ...(collection.entityViews ?? []),\n {\n key: \"__history\",\n name: \"History\",\n tabComponent: <HistoryIcon size={\"small\"}/>,\n Builder: EntityHistoryView,\n position: \"start\"\n }\n ],\n callbacks: mergeCallbacks(collection.callbacks, entityHistoryCallbacks)\n } satisfies EntityCollection;\n }\n return collection;\n }, []);\n\n return useMemo(() => ({\n key: \"entity_history\",\n provider: {\n Component: HistoryControllerProvider,\n props: {\n getUser: props?.getUser\n }\n },\n collection: {\n modifyCollection\n }\n } satisfies FireCMSPlugin), [props]);\n}\n\nexport type EntityHistoryPluginProps = {\n /**\n * If true, the history view will be enabled to all collections by default.\n * Each collection can override this value by setting the `history` property.\n */\n defaultEnabled?: boolean;\n\n /**\n * Function to get the user object from the uid.\n * @param uid\n */\n getUser?: (uid: string) => User | null;\n}\n"],"names":["HistoryControllerContext","React","createContext","useHistoryController","useContext","HistoryControllerProvider","memo","t0","$","_c","children","getUser","t1","t2","equal","UserChip","user","email","uid","displayName","photoURL","jsx","t3","t4","t5","jsxs","Chip","t6","Tooltip","EntityHistoryEntry","actions","disabled","hover","collection","collectionProp","previewKeys","onClick","size","entity","authController","useAuthController","customizationController","useCustomizationController","navigationController","useNavigationController","sideEntityController","useSideEntityController","getCollection","path","updatedOn","values","Error","updatedBy","resolvedCollection","useMemo","resolveCollection","propertyConfigs","Typography","toLocaleString","cls","defaultBorderMixin","IconButton","e","open","entityId","id","allowFullScreen","subcollections","undefined","entityViews","permissions","create","delete","edit","read","updateUrl","KeyboardTabIcon","map","key","childProperty","getPropertyInPath","properties","valueInPath","getValueInPath","element","PropertyPreview","SkeletonPropertyComponent","JSON","stringify","EntityHistoryView","formContext","snackbarController","useSnackbarController","dirty","formex","dataSource","useDataSource","pathAndId","revertVersionDialog","setRevertVersionDialog","useState","Symbol","for","revisions","setRevisions","isLoading","setIsLoading","hasMore","setHasMore","limit","setLimit","containerRef","useRef","observerRef","loadMoreRef","listener","listenCollection","order","orderBy","startAfter","onUpdate","entities","length","onError","error","useEffect","currentContainer","current","currentLoadMore","disconnect","options","root","rootMargin","threshold","handleObserver","entries","target","isIntersecting","prev","observer","IntersectionObserver","observe","Label","doRevert","revertVersion","revertValues","__metadata","reverted","updated_on","Date","updated_by","saveReverted","saveEntity","status","saveRevertedHistory","Promise","all","then","resetForm","message","type","catch","error_0","t7","t8","t9","Fragment","t10","t11","revision","index","changed_fields","HistoryIcon","t12","t13","Boolean","t14","t15","t16","t17","ConfirmationDialog","t18","entityHistoryCallbacks","onSaveSuccess","props","changedFields","previousValues","findChangedFields","context","console","debug","oldValues","newValues","prefix","allKeys","Set","Object","keys","oldValue","newValue","currentPath","push","Array","isArray","i","nestedChanges","useEntityHistoryPlugin","defaultEnabled","modifyCollection","useCallback","history","name","tabComponent","Builder","position","callbacks","mergeCallbacks","provider","Component"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/HistoryControllerProvider.tsx","../src/components/UserChip.tsx","../src/components/EntityHistoryEntry.tsx","../src/components/EntityHistoryView.tsx","../src/entity_history_callbacks.ts","../src/useEntityHistoryPlugin.tsx"],"sourcesContent":["import React, { PropsWithChildren, useContext } from \"react\";\nimport equal from \"react-fast-compare\"\n\nimport { User } from \"@firecms/core\";\n\nexport type HistoryConfigController = {\n /**\n * Function to get a user by uid.\n * @param uid\n */\n getUser?: (uid: string) => User | null;\n}\n\nexport const HistoryControllerContext = React.createContext<HistoryConfigController>({} as any);\nexport const useHistoryController = (): HistoryConfigController => useContext(HistoryControllerContext);\n\n\nexport interface HistoryControllerProviderProps {\n\n getUser?: (uid: string) => User | null;\n\n}\n\nexport const HistoryControllerProvider = React.memo(\n function HistoryControllerProvider({\n children,\n getUser,\n }: PropsWithChildren<HistoryControllerProviderProps>) {\n\n return (\n <HistoryControllerContext.Provider\n value={{\n getUser,\n }}>\n\n {children}\n\n </HistoryControllerContext.Provider>\n );\n }, equal);\n","import { User } from \"@firecms/core\";\nimport { Chip, Tooltip } from \"@firecms/ui\";\n\nexport function UserChip({ user }: { user: User }) {\n return (\n <Tooltip title={user.email ?? user.uid}>\n <Chip size={\"small\"} className={\"flex items-center\"}>\n {user.photoURL && <img\n className={\"rounded-full w-6 h-6 mr-2\"}\n src={user.photoURL} alt={user.displayName ?? \"User picture\"}/>}\n <span>{user.displayName ?? user.email ?? user.uid}</span>\n </Chip>\n </Tooltip>\n );\n}\n","import * as React from \"react\";\n\nimport {\n Chip,\n cls,\n defaultBorderMixin,\n DescriptionIcon,\n IconButton, KeyboardBackspaceIcon,\n KeyboardTabIcon,\n Tooltip,\n Typography\n} from \"@firecms/ui\";\nimport {\n Entity,\n EntityCollection,\n EntityValues,\n getPropertyInPath,\n getValueInPath,\n PreviewSize,\n Property,\n PropertyPreview,\n resolveCollection,\n ResolvedProperty,\n SkeletonPropertyComponent,\n useAuthController,\n useCustomizationController,\n useNavigationController,\n useSideEntityController\n} from \"@firecms/core\";\nimport { useHistoryController } from \"../HistoryControllerProvider\";\nimport { UserChip } from \"./UserChip\";\n\nexport type EntityPreviewProps = {\n size: PreviewSize,\n actions?: React.ReactNode,\n collection?: EntityCollection,\n hover?: boolean;\n previewKeys?: string[],\n entity: Entity<any>,\n previousValues?: EntityValues<any>;\n onClick?: (e: React.SyntheticEvent) => void;\n};\n\nfunction PreviousValueView({\n previousValueInPath,\n childProperty,\n key\n }: {\n previousValueInPath: any,\n childProperty: Property,\n key: string\n}) {\n if (typeof previousValueInPath === \"string\" || typeof previousValueInPath === \"number\") {\n return <Typography variant={\"caption\"} color={\"secondary\"} className=\"line-through\">\n {previousValueInPath}\n </Typography>;\n } else if (typeof previousValueInPath === \"boolean\") {\n return <Typography variant={\"caption\"} color={\"secondary\"} className=\"line-through\">\n {previousValueInPath ? \"true\" : \"false\"}\n </Typography>;\n\n } else {\n return <Tooltip\n side={\"left\"}\n title={<div className={\"flex flex-col gap-2\"}>\n <Typography variant={\"caption\"} color={\"secondary\"}>\n Previous value\n </Typography>\n <PropertyPreview\n propertyKey={key as string}\n value={previousValueInPath}\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>\n </div>}>\n <KeyboardBackspaceIcon size={\"smallest\"} color={\"disabled\"} className={\"mb-1\"}/>\n </Tooltip>\n }\n}\n\n/**\n * This view is used to display a preview of an entity.\n * It is used by default in reference fields and whenever a reference is displayed.\n */\nexport function EntityHistoryEntry({\n actions,\n hover,\n collection: collectionProp,\n previewKeys,\n onClick,\n size,\n entity,\n previousValues\n }: EntityPreviewProps) {\n\n const authController = useAuthController();\n const customizationController = useCustomizationController();\n\n const navigationController = useNavigationController();\n const sideEntityController = useSideEntityController();\n\n const collection = collectionProp ?? navigationController.getCollection(entity.path);\n const updatedOn = entity.values?.[\"__metadata\"]?.[\"updated_on\"];\n if (!collection) {\n throw Error(`Couldn't find the corresponding collection view for the path: ${entity.path}`);\n }\n\n const updatedBy = entity.values?.[\"__metadata\"]?.[\"updated_by\"];\n const { getUser } = useHistoryController();\n const user = getUser?.(updatedBy);\n\n const resolvedCollection = React.useMemo(() => resolveCollection({\n collection,\n path: entity.path,\n values: entity.values,\n propertyConfigs: customizationController.propertyConfigs,\n authController\n }), [collection]);\n\n return <div className={\"w-full flex flex-col gap-2 mt-4\"}>\n <div className={\"ml-4 flex items-center gap-4\"}>\n <Typography variant={\"body2\"} color={\"secondary\"}>{updatedOn.toLocaleString()}</Typography>\n {!user && updatedBy && <Chip size={\"small\"}>{updatedBy}</Chip>}\n {user && <UserChip user={user}/>}\n </div>\n <div\n className={cls(\n \"bg-white dark:bg-surface-900\",\n \"min-h-[42px]\",\n \"w-full\",\n \"items-center\",\n hover ? \"hover:bg-surface-accent-50 dark:hover:bg-surface-800 group-hover:bg-surface-accent-50 dark:group-hover:bg-surface-800\" : \"\",\n size === \"small\" ? \"p-1\" : \"px-2 py-1\",\n \"flex border rounded-lg\",\n onClick ? \"cursor-pointer\" : \"\",\n defaultBorderMixin\n )}>\n\n\n {actions}\n\n {entity &&\n <Tooltip title={\"See details for this revision\"}\n className={\"my-2 grow-0 shrink-0 self-start\"}>\n <IconButton\n color={\"inherit\"}\n className={\"\"}\n onClick={(e) => {\n\n sideEntityController.open({\n entityId: entity.id,\n path: entity.path,\n allowFullScreen: false,\n collection: {\n ...collection,\n subcollections: undefined,\n entityViews: undefined,\n permissions: {\n create: false,\n delete: false,\n edit: false,\n read: true\n }\n },\n updateUrl: true\n });\n }}>\n <KeyboardTabIcon/>\n </IconButton>\n </Tooltip>}\n\n <div className={\"flex flex-col grow w-full m-1 shrink min-w-0\"}>\n\n {previewKeys && previewKeys.map((key) => {\n const childProperty = getPropertyInPath(resolvedCollection.properties, key);\n\n const valueInPath = getValueInPath(entity.values, key);\n const previousValueInPath = previousValues ? getValueInPath(previousValues, key) : undefined;\n\n const element = childProperty ? (entity\n ? <PropertyPreview\n propertyKey={key as string}\n value={valueInPath}\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>\n : <SkeletonPropertyComponent\n property={childProperty as ResolvedProperty}\n size={\"small\"}/>) :\n <Typography variant={\"body2\"}>\n {typeof valueInPath === \"string\" ? valueInPath : JSON.stringify(valueInPath)}\n </Typography>;\n return (\n <div key={\"ref_prev_\" + key}\n className=\"flex w-full my-1 items-center\">\n <Typography variant={\"caption\"}\n color={\"secondary\"}\n className=\"min-w-[140px] md:min-w-[200px] w-1/5 pr-8 overflow-hidden text-ellipsis text-right\">\n {key}\n </Typography>\n <div className=\"w-4/5\">\n {previousValueInPath !== undefined && previousValueInPath !== valueInPath &&\n <PreviousValueView previousValueInPath={previousValueInPath}\n childProperty={childProperty as ResolvedProperty}\n key={key}/>\n }\n {element}\n </div>\n </div>\n );\n })}\n\n </div>\n\n </div>\n </div>\n}\n\n","import { useEffect, useRef, useState } from \"react\";\nimport {\n ConfirmationDialog,\n Entity,\n EntityCustomViewParams,\n EntityView,\n ErrorBoundary,\n useAuthController,\n useDataSource,\n useSnackbarController\n} from \"@firecms/core\";\nimport { cls, HistoryIcon, IconButton, Label, Tooltip, Typography } from \"@firecms/ui\";\nimport { EntityHistoryEntry } from \"./EntityHistoryEntry\";\n\nexport function EntityHistoryView({\n entity,\n collection,\n formContext\n }: EntityCustomViewParams) {\n\n const authController = useAuthController();\n const snackbarController = useSnackbarController();\n const dirty = formContext?.formex.dirty;\n\n const dataSource = useDataSource();\n const pathAndId = entity ? entity?.path + \"/\" + entity?.id : undefined;\n\n const [revertVersionDialog, setRevertVersionDialog] = useState<Entity | undefined>(undefined);\n const [revisions, setRevisions] = useState<Entity[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [hasMore, setHasMore] = useState(true);\n\n const PAGE_SIZE = 5;\n const [limit, setLimit] = useState(PAGE_SIZE);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const observerRef = useRef<IntersectionObserver | null>(null);\n const loadMoreRef = useRef<HTMLDivElement>(null);\n\n // Load revisions with the current limit\n useEffect(() => {\n if (!pathAndId) return;\n\n setIsLoading(true); // Set loading true when fetching starts\n const listener = dataSource.listenCollection?.({\n path: pathAndId + \"/__history\",\n order: \"desc\",\n orderBy: \"__metadata.updated_on\",\n limit: limit,\n startAfter: undefined,\n onUpdate: (entities) => {\n setRevisions(entities);\n setHasMore(entities.length === limit && entities.length >= PAGE_SIZE); // Ensure we fetched a full page to consider hasMore\n setIsLoading(false);\n },\n onError: (error) => {\n console.error(\"Error fetching history:\", error);\n setIsLoading(false);\n setHasMore(false); // Stop trying if there's an error\n }\n });\n return () => {\n if (typeof listener === \"function\") {\n listener();\n }\n };\n }, [pathAndId, limit, dataSource]);\n\n // Setup intersection observer for infinite scroll\n useEffect(() => {\n const currentContainer = containerRef.current;\n const currentLoadMore = loadMoreRef.current;\n\n // Conditions for active observation\n if (!currentContainer || !currentLoadMore || !hasMore || isLoading) {\n // If we shouldn't be observing, ensure any existing observer is disconnected\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n return;\n }\n\n // Options for the IntersectionObserver\n const options = {\n root: currentContainer,\n rootMargin: \"0px 0px 200px 0px\", // Trigger 200px before the sentinel is at the bottom edge\n threshold: 0.01 // Trigger if even a small part is visible within the rootMargin\n };\n\n // The callback for when the sentinel's intersection state changes\n const handleObserver = (entries: IntersectionObserverEntry[]) => {\n const target = entries[0];\n if (target.isIntersecting && hasMore && !isLoading) {\n // No need to setIsLoading(true) here, it's done in the data fetching useEffect\n setLimit(prev => prev + PAGE_SIZE);\n }\n };\n\n const observer = new IntersectionObserver(handleObserver, options);\n observer.observe(currentLoadMore);\n observerRef.current = observer; // Store the new observer\n\n // Cleanup function for this effect instance\n return () => {\n observer.disconnect(); // Disconnect the observer created in *this* effect run\n if (observerRef.current === observer) {\n observerRef.current = null;\n }\n };\n // Re-run if hasMore, isLoading changes, or if revisions.length changes (which might make loadMoreRef available/unavailable)\n }, [hasMore, isLoading, revisions.length]);\n\n if (!entity) {\n return <div className=\"flex items-center justify-center h-full\">\n <Label>History is only available for existing entities</Label>\n </div>\n }\n\n function doRevert(revertVersion: Entity) {\n if (!entity) {\n throw new Error(\"No entity to revert\");\n }\n const revertValues = {\n ...revertVersion.values,\n __metadata: {\n ...revertVersion.values?.[\"__metadata\"],\n reverted: true,\n updated_on: new Date(),\n updated_by: authController.user?.uid ?? null,\n }\n };\n const saveReverted = dataSource.saveEntity({\n path: entity.path,\n entityId: entity.id,\n values: revertValues,\n collection,\n status: \"existing\"\n });\n const saveRevertedHistory = dataSource.saveEntity({\n path: revertVersion.path,\n entityId: revertVersion.id,\n values: revertValues,\n collection,\n status: \"existing\"\n });\n return Promise.all([saveReverted, saveRevertedHistory])\n .then(() => {\n formContext.formex.resetForm({\n values: revertVersion.values\n });\n setRevertVersionDialog(undefined);\n snackbarController.open({\n message: \"Reverted version\",\n type: \"info\"\n });\n }\n ).catch((error) => {\n console.error(\"Error reverting entity:\", error);\n snackbarController.open({\n message: \"Error reverting entity\",\n type: \"error\"\n });\n });\n\n }\n\n return <div\n ref={containerRef}\n className={cls(\"relative flex-1 h-full overflow-auto w-full flex flex-col gap-4 p-8\")}>\n <div className=\"flex flex-col gap-2 max-w-6xl mx-auto w-full\">\n\n <Typography variant={\"h5\"} className={\"mt-24 ml-4\"}>\n History\n </Typography>\n\n {revisions.length === 0 && <>\n <Label className={\"ml-4 mt-8\"}>\n No history available\n </Label>\n <Typography variant={\"caption\"} className={\"ml-4\"}>\n When you save an entity, a new version is created and stored in the history.\n </Typography>\n </>}\n\n {revisions.map((revision, index) => {\n const previewKeys = revision.values?.[\"__metadata\"]?.[\"changed_fields\"];\n const previousValues: object | undefined = revision.values?.[\"__metadata\"]?.[\"previous_values\"];\n return <div key={index} className=\"flex flex-cols gap-2 w-full\">\n <EntityHistoryEntry size={\"large\"}\n entity={revision}\n collection={collection}\n previewKeys={previewKeys}\n previousValues={previousValues}\n actions={\n <Tooltip title={\"Revert to this version\"}\n className={\"m-2 grow-0 self-start\"}>\n <IconButton\n onClick={() => {\n if (dirty) {\n snackbarController.open({\n message: \"Please save or discard your changes before reverting\",\n type: \"warning\"\n });\n } else {\n setRevertVersionDialog(revision);\n }\n }}>\n <HistoryIcon/>\n </IconButton>\n </Tooltip>}\n />\n </div>\n })}\n\n {/* Load more sentinel element */}\n {revisions.length > 0 && (\n <div\n ref={loadMoreRef}\n className=\"py-4 text-center\"\n >\n {isLoading && <Label>Loading more...</Label>}\n {!hasMore && revisions.length > PAGE_SIZE && <Label>No more history available</Label>}\n </div>\n )}\n </div>\n\n <ErrorBoundary>\n <ConfirmationDialog open={Boolean(revertVersionDialog)}\n onAccept={function (): void {\n if (!revertVersionDialog) return;\n doRevert(revertVersionDialog);\n }}\n onCancel={function (): void {\n setRevertVersionDialog(undefined);\n }}\n title={<Typography variant={\"subtitle2\"}>Revert data to this version?</Typography>}\n body={revertVersionDialog ?\n <EntityView entity={revertVersionDialog}\n collection={collection}\n path={entity?.path}/> : null}/>\n </ErrorBoundary>\n </div>\n}\n","import { EntityCallbacks } from \"@firecms/core\";\nimport equal from \"react-fast-compare\"\n\nexport const entityHistoryCallbacks: EntityCallbacks = {\n onSaveSuccess: async (props) => {\n\n const changedFields = props.previousValues ? findChangedFields(props.previousValues, props.values) : null;\n const uid = props.context.authController.user?.uid;\n props.context.dataSource.saveEntity({\n path: props.path + \"/\" + props.entityId + \"/__history\",\n values: {\n ...props.values,\n __metadata: {\n previous_values: props.previousValues,\n changed_fields: changedFields,\n updated_on: new Date(),\n updated_by: uid,\n }\n },\n status: \"new\"\n }).then(() => {\n console.debug(\"History saved for\", props.path, props.entityId);\n });\n }\n}\n\nfunction findChangedFields<M extends object>(oldValues: M, newValues: M, prefix: string = \"\"): string[] {\n const changedFields: string[] = [];\n\n // Handle null/undefined cases\n if (equal(oldValues, newValues)) return changedFields;\n if (!oldValues || !newValues) return [prefix || \".\"];\n\n // Get all unique keys from both objects\n const allKeys = new Set([\n ...Object.keys(oldValues),\n ...Object.keys(newValues)\n ]);\n\n for (const key of allKeys) {\n const oldValue = oldValues[key as keyof M];\n const newValue = newValues[key as keyof M];\n const currentPath = prefix ? `${prefix}.${key}` : key;\n\n // If key exists only in one object\n if ((key in oldValues) !== (key in newValues)) {\n changedFields.push(currentPath);\n continue;\n }\n\n // If values are identical (deep equality)\n if (equal(oldValue, newValue)) continue;\n\n // Handle arrays\n if (Array.isArray(oldValue) && Array.isArray(newValue)) {\n if (oldValue.length !== newValue.length) {\n changedFields.push(currentPath);\n } else {\n // Check if any array element changed\n for (let i = 0; i < oldValue.length; i++) {\n if (\n typeof oldValue[i] === \"object\" && oldValue[i] !== null &&\n typeof newValue[i] === \"object\" && newValue[i] !== null\n ) {\n const nestedChanges = findChangedFields(\n oldValue[i] as object,\n newValue[i] as object,\n `${currentPath}[${i}]`\n );\n if (nestedChanges.length > 0) {\n changedFields.push(currentPath);\n break;\n }\n } else if (!equal(oldValue[i], newValue[i])) {\n changedFields.push(currentPath);\n break;\n }\n }\n }\n }\n // Handle nested objects\n else if (\n typeof oldValue === \"object\" && oldValue !== null &&\n typeof newValue === \"object\" && newValue !== null\n ) {\n const nestedChanges = findChangedFields(\n oldValue as object,\n newValue as object,\n currentPath\n );\n changedFields.push(...nestedChanges);\n }\n // Handle primitives\n else {\n changedFields.push(currentPath);\n }\n }\n\n return changedFields;\n}\n","import { useCallback, useMemo } from \"react\";\nimport { EntityCollection, FireCMSPlugin, mergeCallbacks, User } from \"@firecms/core\";\nimport { EntityHistoryView } from \"./components/EntityHistoryView\";\nimport { HistoryIcon } from \"@firecms/ui\";\nimport { entityHistoryCallbacks } from \"./entity_history_callbacks\";\nimport { HistoryControllerProvider } from \"./HistoryControllerProvider\";\n\n/**\n * This plugin adds a history view to the entity side panel.\n */\nexport function useEntityHistoryPlugin(props?: EntityHistoryPluginProps): FireCMSPlugin<any, any, any, EntityHistoryPluginProps> {\n\n const { defaultEnabled = false } = props ?? {};\n\n const modifyCollection = useCallback((collection: EntityCollection) => {\n if (collection.history === true || (defaultEnabled && collection.history !== false)) {\n return {\n ...collection,\n entityViews: [\n ...(collection.entityViews ?? []),\n {\n key: \"__history\",\n name: \"History\",\n tabComponent: <HistoryIcon size={\"small\"}/>,\n Builder: EntityHistoryView,\n position: \"start\"\n }\n ],\n callbacks: mergeCallbacks(collection.callbacks, entityHistoryCallbacks)\n } satisfies EntityCollection;\n }\n return collection;\n }, []);\n\n return useMemo(() => ({\n key: \"entity_history\",\n provider: {\n Component: HistoryControllerProvider,\n props: {\n getUser: props?.getUser\n }\n },\n collection: {\n modifyCollection\n }\n } satisfies FireCMSPlugin), [props]);\n}\n\nexport type EntityHistoryPluginProps = {\n /**\n * If true, the history view will be enabled to all collections by default.\n * Each collection can override this value by setting the `history` property.\n */\n defaultEnabled?: boolean;\n\n /**\n * Function to get the user object from the uid.\n * @param uid\n */\n getUser?: (uid: string) => User | null;\n}\n"],"names":["HistoryControllerContext","React","createContext","useHistoryController","useContext","HistoryControllerProvider","memo","t0","$","_c","children","getUser","t1","t2","equal","UserChip","user","email","uid","displayName","photoURL","jsx","t3","t4","t5","jsxs","Chip","t6","Tooltip","PreviousValueView","previousValueInPath","childProperty","key","Typography","Symbol","for","PropertyPreview","KeyboardBackspaceIcon","EntityHistoryEntry","actions","hover","collection","collectionProp","previewKeys","onClick","size","entity","previousValues","authController","useAuthController","customizationController","useCustomizationController","navigationController","useNavigationController","sideEntityController","useSideEntityController","getCollection","path","updatedOn","values","Error","updatedBy","resolvedCollection","useMemo","resolveCollection","propertyConfigs","toLocaleString","cls","defaultBorderMixin","IconButton","e","open","entityId","id","allowFullScreen","subcollections","undefined","entityViews","permissions","create","delete","edit","read","updateUrl","KeyboardTabIcon","map","getPropertyInPath","properties","valueInPath","getValueInPath","element","SkeletonPropertyComponent","JSON","stringify","EntityHistoryView","formContext","snackbarController","useSnackbarController","dirty","formex","dataSource","useDataSource","pathAndId","revertVersionDialog","setRevertVersionDialog","useState","revisions","setRevisions","isLoading","setIsLoading","hasMore","setHasMore","limit","setLimit","containerRef","useRef","observerRef","loadMoreRef","listener","listenCollection","order","orderBy","startAfter","onUpdate","entities","length","onError","error","useEffect","currentContainer","current","currentLoadMore","disconnect","options","root","rootMargin","threshold","handleObserver","entries","target","isIntersecting","prev","observer","IntersectionObserver","observe","Label","doRevert","revertVersion","revertValues","__metadata","reverted","updated_on","Date","updated_by","saveReverted","saveEntity","status","saveRevertedHistory","Promise","all","then","resetForm","message","type","catch","error_0","t7","t8","t9","Fragment","t10","t11","revision","index","changed_fields","previous_values","HistoryIcon","t12","t13","Boolean","t14","t15","t16","t17","EntityView","t18","ErrorBoundary","ConfirmationDialog","t19","entityHistoryCallbacks","onSaveSuccess","props","changedFields","findChangedFields","context","console","debug","oldValues","newValues","prefix","allKeys","Set","Object","keys","oldValue","newValue","currentPath","push","Array","isArray","i","nestedChanges","useEntityHistoryPlugin","defaultEnabled","modifyCollection","useCallback","history","name","tabComponent","Builder","position","callbacks","mergeCallbacks","provider","Component"],"mappings":"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"}
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@firecms/entity_history",
3
3
  "type": "module",
4
- "version": "3.0.0-canary.251",
4
+ "version": "3.0.0-canary.253",
5
5
  "access": "public",
6
6
  "main": "./dist/index.umd.js",
7
7
  "module": "./dist/index.es.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "source": "src/index.ts",
10
10
  "dependencies": {
11
- "@firecms/core": "^3.0.0-canary.251",
12
- "@firecms/formex": "^3.0.0-canary.251",
13
- "@firecms/ui": "^3.0.0-canary.251"
11
+ "@firecms/core": "^3.0.0-canary.253",
12
+ "@firecms/formex": "^3.0.0-canary.253",
13
+ "@firecms/ui": "^3.0.0-canary.253"
14
14
  },
15
15
  "peerDependencies": {
16
16
  "react": ">=18.0.0",
@@ -82,5 +82,5 @@
82
82
  "publishConfig": {
83
83
  "access": "public"
84
84
  },
85
- "gitHead": "b7b0d3730e3c3bea284f1d6f482ca038282fb554"
85
+ "gitHead": "c4dff639fcd32ba5d706f5b8cf92692af6e94893"
86
86
  }
@@ -1,12 +1,23 @@
1
1
  import * as React from "react";
2
2
 
3
- import { Chip, cls, defaultBorderMixin, IconButton, KeyboardTabIcon, Tooltip, Typography } from "@firecms/ui";
3
+ import {
4
+ Chip,
5
+ cls,
6
+ defaultBorderMixin,
7
+ DescriptionIcon,
8
+ IconButton, KeyboardBackspaceIcon,
9
+ KeyboardTabIcon,
10
+ Tooltip,
11
+ Typography
12
+ } from "@firecms/ui";
4
13
  import {
5
14
  Entity,
6
15
  EntityCollection,
16
+ EntityValues,
7
17
  getPropertyInPath,
8
18
  getValueInPath,
9
19
  PreviewSize,
20
+ Property,
10
21
  PropertyPreview,
11
22
  resolveCollection,
12
23
  ResolvedProperty,
@@ -25,24 +36,60 @@ export type EntityPreviewProps = {
25
36
  collection?: EntityCollection,
26
37
  hover?: boolean;
27
38
  previewKeys?: string[],
28
- disabled?: boolean,
29
39
  entity: Entity<any>,
40
+ previousValues?: EntityValues<any>;
30
41
  onClick?: (e: React.SyntheticEvent) => void;
31
42
  };
32
43
 
44
+ function PreviousValueView({
45
+ previousValueInPath,
46
+ childProperty,
47
+ key
48
+ }: {
49
+ previousValueInPath: any,
50
+ childProperty: Property,
51
+ key: string
52
+ }) {
53
+ if (typeof previousValueInPath === "string" || typeof previousValueInPath === "number") {
54
+ return <Typography variant={"caption"} color={"secondary"} className="line-through">
55
+ {previousValueInPath}
56
+ </Typography>;
57
+ } else if (typeof previousValueInPath === "boolean") {
58
+ return <Typography variant={"caption"} color={"secondary"} className="line-through">
59
+ {previousValueInPath ? "true" : "false"}
60
+ </Typography>;
61
+
62
+ } else {
63
+ return <Tooltip
64
+ side={"left"}
65
+ title={<div className={"flex flex-col gap-2"}>
66
+ <Typography variant={"caption"} color={"secondary"}>
67
+ Previous value
68
+ </Typography>
69
+ <PropertyPreview
70
+ propertyKey={key as string}
71
+ value={previousValueInPath}
72
+ property={childProperty as ResolvedProperty}
73
+ size={"small"}/>
74
+ </div>}>
75
+ <KeyboardBackspaceIcon size={"smallest"} color={"disabled"} className={"mb-1"}/>
76
+ </Tooltip>
77
+ }
78
+ }
79
+
33
80
  /**
34
81
  * This view is used to display a preview of an entity.
35
82
  * It is used by default in reference fields and whenever a reference is displayed.
36
83
  */
37
84
  export function EntityHistoryEntry({
38
85
  actions,
39
- disabled,
40
86
  hover,
41
87
  collection: collectionProp,
42
88
  previewKeys,
43
89
  onClick,
44
90
  size,
45
- entity
91
+ entity,
92
+ previousValues
46
93
  }: EntityPreviewProps) {
47
94
 
48
95
  const authController = useAuthController();
@@ -127,6 +174,8 @@ export function EntityHistoryEntry({
127
174
  const childProperty = getPropertyInPath(resolvedCollection.properties, key);
128
175
 
129
176
  const valueInPath = getValueInPath(entity.values, key);
177
+ const previousValueInPath = previousValues ? getValueInPath(previousValues, key) : undefined;
178
+
130
179
  const element = childProperty ? (entity
131
180
  ? <PropertyPreview
132
181
  propertyKey={key as string}
@@ -148,9 +197,12 @@ export function EntityHistoryEntry({
148
197
  {key}
149
198
  </Typography>
150
199
  <div className="w-4/5">
151
- {
152
- element
200
+ {previousValueInPath !== undefined && previousValueInPath !== valueInPath &&
201
+ <PreviousValueView previousValueInPath={previousValueInPath}
202
+ childProperty={childProperty as ResolvedProperty}
203
+ key={key}/>
153
204
  }
205
+ {element}
154
206
  </div>
155
207
  </div>
156
208
  );
@@ -3,6 +3,8 @@ import {
3
3
  ConfirmationDialog,
4
4
  Entity,
5
5
  EntityCustomViewParams,
6
+ EntityView,
7
+ ErrorBoundary,
6
8
  useAuthController,
7
9
  useDataSource,
8
10
  useSnackbarController
@@ -183,11 +185,13 @@ export function EntityHistoryView({
183
185
 
184
186
  {revisions.map((revision, index) => {
185
187
  const previewKeys = revision.values?.["__metadata"]?.["changed_fields"];
188
+ const previousValues: object | undefined = revision.values?.["__metadata"]?.["previous_values"];
186
189
  return <div key={index} className="flex flex-cols gap-2 w-full">
187
190
  <EntityHistoryEntry size={"large"}
188
191
  entity={revision}
189
192
  collection={collection}
190
193
  previewKeys={previewKeys}
194
+ previousValues={previousValues}
191
195
  actions={
192
196
  <Tooltip title={"Revert to this version"}
193
197
  className={"m-2 grow-0 self-start"}>
@@ -221,14 +225,20 @@ export function EntityHistoryView({
221
225
  )}
222
226
  </div>
223
227
 
224
- <ConfirmationDialog open={Boolean(revertVersionDialog)}
225
- onAccept={function (): void {
226
- if (!revertVersionDialog) return;
227
- doRevert(revertVersionDialog);
228
- }}
229
- onCancel={function (): void {
230
- setRevertVersionDialog(undefined);
231
- }}
232
- title={<Typography variant={"subtitle2"}>Revert data to this version?</Typography>}/>
228
+ <ErrorBoundary>
229
+ <ConfirmationDialog open={Boolean(revertVersionDialog)}
230
+ onAccept={function (): void {
231
+ if (!revertVersionDialog) return;
232
+ doRevert(revertVersionDialog);
233
+ }}
234
+ onCancel={function (): void {
235
+ setRevertVersionDialog(undefined);
236
+ }}
237
+ title={<Typography variant={"subtitle2"}>Revert data to this version?</Typography>}
238
+ body={revertVersionDialog ?
239
+ <EntityView entity={revertVersionDialog}
240
+ collection={collection}
241
+ path={entity?.path}/> : null}/>
242
+ </ErrorBoundary>
233
243
  </div>
234
244
  }
@@ -11,6 +11,7 @@ export const entityHistoryCallbacks: EntityCallbacks = {
11
11
  values: {
12
12
  ...props.values,
13
13
  __metadata: {
14
+ previous_values: props.previousValues,
14
15
  changed_fields: changedFields,
15
16
  updated_on: new Date(),
16
17
  updated_by: uid,