feat: renders diffs

This commit is contained in:
James
2021-12-13 16:10:25 -05:00
parent f57223024a
commit 245e12e8b6
13 changed files with 260 additions and 15 deletions

View File

@@ -0,0 +1,5 @@
@import '../../../../../scss/styles.scss';
.field-diff-label {
margin-bottom: base(.25);
}

View File

@@ -0,0 +1,13 @@
import React from 'react';
import './index.scss';
const baseClass = 'field-diff-label';
const Label: React.FC = ({ children }) => (
<div className={baseClass}>
{children}
</div>
);
export default Label;

View File

@@ -0,0 +1,21 @@
import React from 'react';
const baseClass = 'iterable-diff';
type Props = {
revision: string
comparison: string
}
const Iterable: React.FC<Props> = ({ revision, comparison }) => (
<div className={baseClass}>
<div className={`${baseClass}__revision`}>
{revision}
</div>
<div className={`${baseClass}__comparison`}>
{comparison}
</div>
</div>
);
export default Iterable;

View File

@@ -0,0 +1,21 @@
import React from 'react';
const baseClass = 'nested-diff';
type Props = {
revision: string
comparison: string
}
const Nested: React.FC<Props> = ({ revision, comparison }) => (
<div className={baseClass}>
<div className={`${baseClass}__revision`}>
{revision}
</div>
<div className={`${baseClass}__comparison`}>
{comparison}
</div>
</div>
);
export default Nested;

View File

@@ -0,0 +1,10 @@
@import '../../../../../../scss/styles.scss';
.text-diff {
&__locale-label {
margin-right: base(.25);
background: $color-background-gray;
padding: base(.25);
border-radius: $style-radius-m;
}
}

View File

@@ -0,0 +1,32 @@
import React from 'react';
import ReactDiffViewer from 'react-diff-viewer';
import { Props } from '../types';
import Label from '../../Label';
import './index.scss';
const baseClass = 'text-diff';
const Text: React.FC<Props> = ({ field, locale, revision, comparison }) => {
return (
<div className={baseClass}>
<Label>
{locale && (
<span className={`${baseClass}__locale-label`}>{locale}</span>
)}
{field.label}
</Label>
<ReactDiffViewer
oldValue={String(revision)}
newValue={String(comparison)}
splitView
hideLineNumbers
showDiffOnly={false}
/>
</div>
);
return null;
};
export default Text;

View File

@@ -0,0 +1,22 @@
import Text from './Text';
import Iterable from './Iterable';
import Nested from './Nested';
export default {
text: Text,
textarea: Text,
number: Text,
email: Text,
code: Text,
// group: Nested,
// row: Nested,
// array: Iterable,
blocks: Iterable,
checkbox: Text,
date: Text,
radio: Text,
select: Text,
relationship: Text,
upload: Text,
point: Text,
};

View File

@@ -0,0 +1,8 @@
import { Field } from '../../../../../../fields/config/types';
export type Props = {
revision: string
comparison: string
field: Field
locale?: string
}

View File

@@ -0,0 +1,11 @@
@import '../../../../scss/styles.scss';
.render-field-diffs {
&__field {
margin-bottom: $baseline;
}
&__locale {
margin-bottom: base(.5);
}
}

View File

@@ -0,0 +1,72 @@
import React from 'react';
import { Props } from './types';
import fieldComponents from './fields';
import { fieldAffectsData } from '../../../../../fields/config/types';
import Label from './Label';
import './index.scss';
const baseClass = 'render-field-diffs';
const RenderFieldsToDiff: React.FC<Props> = ({ fields, fieldPermissions, revision, comparison, locales }) => (
<div className={baseClass}>
{fields.map((field, i) => {
const Component = fieldComponents[field.type];
if (Component) {
if (fieldAffectsData(field)) {
const revisionValue = revision[field.name];
const comparisonValue = comparison?.[field.name];
const hasPermission = fieldPermissions?.[field.name]?.read?.permission;
if (!hasPermission) return null;
if (field.localized) {
return (
<div
className={`${baseClass}__field`}
key={i}
>
{locales.map((locale) => {
const revisionLocaleValue = revisionValue?.[locale];
const comparisonLocaleValue = comparisonValue?.[locale];
return (
<div
className={`${baseClass}__locale`}
key={locale}
>
<div className={`${baseClass}__locale-value`}>
<Component
locale={locale}
field={field}
revision={revisionLocaleValue}
comparison={comparisonLocaleValue}
/>
</div>
</div>
);
})}
</div>
);
}
return (
<div
className={`${baseClass}__field`}
key={i}
>
<Component
field={field}
revision={revisionValue}
comparison={comparisonValue}
/>
</div>
);
}
}
return null;
})}
</div>
);
export default RenderFieldsToDiff;

View File

@@ -0,0 +1,10 @@
import { FieldPermissions } from '../../../../../auth';
import { Field } from '../../../../../fields/config/types';
export type Props = {
fields: Field[]
fieldPermissions: Record<string, FieldPermissions>
revision: Record<string, any>
comparison: Record<string, any>
locales: string[]
}

View File

@@ -30,7 +30,7 @@
> * {
margin-left: base(.5);
margin-right: base(.5);
width: 50%;
flex-basis: 100%;
}
}
@@ -53,7 +53,11 @@
&__controls {
display: block;
margin: 0 $baseline;
margin: 0 base(.5);
> * {
margin-bottom: base(.5);
}
}
&__restore {

View File

@@ -1,4 +1,4 @@
import { useConfig } from '@payloadcms/config-provider';
import { useAuth, useConfig } from '@payloadcms/config-provider';
import React, { useEffect, useState } from 'react';
import { useRouteMatch } from 'react-router-dom';
import format from 'date-fns/format';
@@ -12,9 +12,12 @@ import { LocaleOption, CompareOption, Props } from './types';
import CompareRevision from './Compare';
import { publishedVersionOption } from './shared';
import Restore from './Restore';
import SelectLocales from './SelectLocales';
import RenderFieldsToDiff from './RenderFieldsToDiff';
import './index.scss';
import SelectLocales from './SelectLocales';
import { Field } from '../../../../fields/config/types';
import { FieldPermissions } from '../../../../auth';
const baseClass = 'view-revision';
@@ -25,10 +28,13 @@ const ViewRevision: React.FC<Props> = ({ collection, global }) => {
const [compareValue, setCompareValue] = useState<CompareOption>(publishedVersionOption);
const [localeOptions] = useState<LocaleOption[]>(() => (localization?.locales ? localization.locales.map((locale) => ({ label: locale, value: locale })) : []));
const [locales, setLocales] = useState<LocaleOption[]>(localeOptions);
const { permissions } = useAuth();
let originalDocFetchURL: string;
let revisionFetchURL: string;
let entityLabel: string;
let fields: Field[];
let fieldPermissions: Record<string, FieldPermissions>;
let compareBaseURL: string;
let slug: string;
let parentID: string;
@@ -40,6 +46,8 @@ const ViewRevision: React.FC<Props> = ({ collection, global }) => {
compareBaseURL = `${serverURL}${api}/${slug}/revisions`;
entityLabel = collection.labels.singular;
parentID = id;
fields = collection.fields;
fieldPermissions = permissions.collections[collection.slug].fields;
}
if (global) {
@@ -48,14 +56,16 @@ const ViewRevision: React.FC<Props> = ({ collection, global }) => {
revisionFetchURL = `${serverURL}${api}/globals/${slug}/revisions/${revisionID}`;
compareBaseURL = `${serverURL}${api}/globals/${slug}/revisions`;
entityLabel = global.label;
fields = global.fields;
fieldPermissions = permissions.globals[global.slug].fields;
}
const useAsTitle = collection?.admin?.useAsTitle || 'id';
const compareFetchURL = compareValue?.value && compareValue?.value !== 'published' ? `${compareBaseURL}/${compareValue.value}` : '';
const compareFetchURL = compareValue?.value === 'published' ? originalDocFetchURL : `${compareBaseURL}/${compareValue.value}`;
const [{ data: doc, isLoading }] = usePayloadAPI(revisionFetchURL);
const [{ data: doc, isLoading }] = usePayloadAPI(revisionFetchURL, { initialParams: { locale: '*' } });
const [{ data: originalDoc }] = usePayloadAPI(originalDocFetchURL);
const [{ data: compareDoc }] = usePayloadAPI(compareFetchURL);
const [{ data: compareDoc }] = usePayloadAPI(compareFetchURL, { initialParams: { locale: '*' } });
useEffect(() => {
let nav: StepNavItem[] = [];
@@ -133,25 +143,31 @@ const ViewRevision: React.FC<Props> = ({ collection, global }) => {
/>
</header>
<div className={`${baseClass}__controls`}>
{localization && (
<SelectLocales
onChange={setLocales}
options={localeOptions}
value={locales}
/>
)}
<CompareRevision
baseURL={compareBaseURL}
parentID={parentID}
value={compareValue}
onChange={setCompareValue}
/>
<SelectLocales
onChange={setLocales}
options={localeOptions}
value={locales}
/>
</div>
{isLoading && (
<Loading />
)}
{doc?.revision && (
<React.Fragment>
hello
</React.Fragment>
<RenderFieldsToDiff
locales={locales.map((locale) => locale.value)}
fields={fields}
fieldPermissions={fieldPermissions}
revision={doc?.revision}
comparison={compareValue?.value === 'published' ? compareDoc : compareDoc?.revision}
/>
)}
</div>
</div>