feat: show hidden fields in history frontend (#20201)

* chore: add configuration to history context

* feat: show fields that aren't in the layout in history

* chore: add renderLayout prop to ComponentInput

* feat: render remaining fields in components

* fix: types

* chore: refactor to composition api

* chore: move renderInput to children

* fix: repeatable components index

* fix: repeatable components toggling together

* chore: move ComponentLayout

* fix: generate temp keys for history values

* chore: delete ComponentLayout

* fix: components with no hidden fields

* fix: add comments

* chore: add comment
This commit is contained in:
Rémi de Juvigny 2024-04-30 17:53:27 +02:00 committed by GitHub
parent 4a26739ee0
commit 9d4475b11a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 245 additions and 99 deletions

View File

@ -10,15 +10,102 @@ import {
GridItem,
Typography,
} from '@strapi/design-system';
import { Schema } from '@strapi/types';
import pipe from 'lodash/fp/pipe';
import { useIntl } from 'react-intl';
import { useDoc } from '../../hooks/useDocument';
import { useTypedSelector } from '../../modules/hooks';
import { useHistoryContext } from '../pages/History';
import {
prepareTempKeys,
removeFieldsThatDontExistOnSchema,
} from '../../pages/EditView/utils/data';
import { HistoryContextValue, useHistoryContext } from '../pages/History';
import { VersionInputRenderer } from './VersionInputRenderer';
import type { Metadatas } from '../../../../shared/contracts/content-types';
import type { GetInitData } from '../../../../shared/contracts/init';
import type { ComponentsDictionary, Document } from '../../hooks/useDocument';
import type { EditFieldLayout } from '../../hooks/useDocumentLayout';
const createLayoutFromFields = <T extends EditFieldLayout | UnknownField>(fields: T[]) => {
return (
fields
.reduce<Array<T[]>>((rows, field) => {
if (field.type === 'dynamiczone') {
// Dynamic zones take up all the columns in a row
rows.push([field]);
return rows;
}
if (!rows[rows.length - 1]) {
// Create a new row if there isn't one available
rows.push([]);
}
// Push fields to the current row, they wrap and handle their own column size
rows[rows.length - 1].push(field);
return rows;
}, [])
// Map the rows to panels
.map((row) => [row])
);
};
/* -------------------------------------------------------------------------------------------------
* getRemainingFieldsLayout
* -----------------------------------------------------------------------------------------------*/
interface GetRemainingFieldsLayoutOptions
extends Pick<HistoryContextValue, 'layout'>,
Pick<GetInitData.Response['data'], 'fieldSizes'> {
schemaAttributes: HistoryContextValue['schema']['attributes'];
metadatas: Metadatas;
}
/**
* Build a layout for the fields that are were deleted from the edit view layout
* via the configure the view page. This layout will be merged with the main one.
* Those fields would be restored if the user restores the history version, which is why it's
* important to show them, even if they're not in the normal layout.
*/
function getRemaingFieldsLayout({
layout,
metadatas,
schemaAttributes,
fieldSizes,
}: GetRemainingFieldsLayoutOptions) {
const fieldsInLayout = layout.flatMap((panel) =>
panel.flatMap((row) => row.flatMap((field) => field.name))
);
const remainingFields = Object.entries(metadatas).reduce<EditFieldLayout[]>(
(currentRemainingFields, [name, field]) => {
// Make sure we do not fields that are not visible, e.g. "id"
if (!fieldsInLayout.includes(name) && field.edit.visible === true) {
const attribute = schemaAttributes[name];
// @ts-expect-error not sure why attribute causes type error
currentRemainingFields.push({
attribute,
type: attribute.type,
visible: true,
disabled: true,
label: field.edit.label || name,
name: name,
size: fieldSizes[attribute.type].default ?? 12,
});
}
return currentRemainingFields;
},
[]
);
return createLayoutFromFields(remainingFields);
}
/* -------------------------------------------------------------------------------------------------
* FormPanel
* -----------------------------------------------------------------------------------------------*/
@ -70,14 +157,16 @@ const FormPanel = ({ panel }: { panel: EditFieldLayout[][] }) => {
* -----------------------------------------------------------------------------------------------*/
type UnknownField = EditFieldLayout & { shouldIgnoreRBAC: boolean };
const VersionContent = () => {
const { formatMessage } = useIntl();
const { fieldSizes } = useTypedSelector((state) => state['content-manager'].app);
const { version, layout } = useHistoryContext('VersionContent', (state) => ({
version: state.selectedVersion,
layout: state.layout,
}));
const version = useHistoryContext('VersionContent', (state) => state.selectedVersion);
const layout = useHistoryContext('VersionContent', (state) => state.layout);
const configuration = useHistoryContext('VersionContent', (state) => state.configuration);
const schema = useHistoryContext('VersionContent', (state) => state.schema);
// Build a layout for the unknown fields section
const removedAttributes = version.meta.unknownAttributes.removed;
const removedAttributesAsFields = Object.entries(removedAttributes).map(
([attributeName, attribute]) => {
@ -95,34 +184,43 @@ const VersionContent = () => {
return field;
}
);
const unknownFieldsLayout = removedAttributesAsFields
.reduce<Array<UnknownField[]>>((rows, field) => {
if (field.type === 'dynamiczone') {
// Dynamic zones take up all the columns in a row
rows.push([field]);
const unknownFieldsLayout = createLayoutFromFields(removedAttributesAsFields);
return rows;
}
// Build a layout for the fields that are were deleted from the layout
const remainingFieldsLayout = getRemaingFieldsLayout({
metadatas: configuration.contentType.metadatas,
layout,
schemaAttributes: schema.attributes,
fieldSizes,
});
if (!rows[rows.length - 1]) {
// Create a new row if there isn't one available
rows.push([]);
}
const { components } = useDoc();
// Push fields to the current row, they wrap and handle their own column size
rows[rows.length - 1].push(field);
/**
* Transform the data before passing it to the form so that each field
* has a uniquely generated key
*/
const transformedData = React.useMemo(() => {
const transform =
(schemaAttributes: Schema.Attributes, components: ComponentsDictionary = {}) =>
(document: Omit<Document, 'id'>) => {
const schema = { attributes: schemaAttributes };
const transformations = pipe(
removeFieldsThatDontExistOnSchema(schema),
prepareTempKeys(schema, components)
);
return transformations(document);
};
return rows;
}, [])
// Map the rows to panels
.map((row) => [row]);
return transform(version.schema, components)(version.data);
}, [components, version.data, version.schema]);
return (
<ContentLayout>
<Box paddingBottom={8}>
<Form disabled={true} method="PUT" initialValues={version.data}>
<Form disabled={true} method="PUT" initialValues={transformedData}>
<Flex direction="column" alignItems="stretch" gap={6} position="relative">
{layout.map((panel, index) => {
{[...layout, ...remainingFieldsLayout].map((panel, index) => {
return <FormPanel key={index} panel={panel} />;
})}
</Flex>
@ -170,4 +268,4 @@ const VersionContent = () => {
);
};
export { VersionContent };
export { VersionContent, getRemaingFieldsLayout };

View File

@ -15,7 +15,9 @@ import styled from 'styled-components';
import { COLLECTION_TYPES } from '../../constants/collections';
import { useDocumentRBAC } from '../../features/DocumentRBAC';
import { useDoc } from '../../hooks/useDocument';
import { useDocLayout } from '../../hooks/useDocumentLayout';
import { useLazyComponents } from '../../hooks/useLazyComponents';
import { useTypedSelector } from '../../modules/hooks';
import { DocumentStatus } from '../../pages/EditView/components/DocumentStatus';
import { BlocksInput } from '../../pages/EditView/components/FormInputs/BlocksInput/BlocksInput';
import { ComponentInput } from '../../pages/EditView/components/FormInputs/Component/Input';
@ -30,6 +32,8 @@ import { useFieldHint } from '../../pages/EditView/components/InputRenderer';
import { getRelationLabel } from '../../utils/relations';
import { useHistoryContext } from '../pages/History';
import { getRemaingFieldsLayout } from './VersionContent';
import type { EditFieldLayout } from '../../hooks/useDocumentLayout';
import type { RelationsFieldProps } from '../../pages/EditView/components/FormInputs/Relations';
import type { RelationResult } from '../../services/relations';
@ -233,10 +237,11 @@ const VersionInputRenderer = ({
...props
}: VersionInputRendererProps) => {
const { formatMessage } = useIntl();
const { version } = useHistoryContext('VersionContent', (state) => ({
version: state.selectedVersion,
}));
const { id } = useDoc();
const version = useHistoryContext('VersionContent', (state) => state.selectedVersion);
const configuration = useHistoryContext('VersionContent', (state) => state.configuration);
const fieldSizes = useTypedSelector((state) => state['content-manager'].app.fieldSizes);
const { id, components } = useDoc();
const isFormDisabled = useForm('InputRenderer', (state) => state.disabled);
const isInDynamicZone = useDynamicZone('isInDynamicZone', (state) => state.isInDynamicZone);
@ -261,6 +266,9 @@ const VersionInputRenderer = ({
);
const hint = useFieldHint(providedHint, props.attribute);
const {
edit: { components: componentsLayout },
} = useDocLayout();
if (!visible) {
return null;
@ -353,13 +361,24 @@ const VersionInputRenderer = ({
case 'blocks':
return <BlocksInput {...props} hint={hint} type={props.type} disabled={fieldIsDisabled} />;
case 'component':
const { layout } = componentsLayout[props.attribute.component];
// Components can only have one panel, so only save the first layout item
const [remainingFieldsLayout] = getRemaingFieldsLayout({
layout: [layout],
metadatas: configuration.components[props.attribute.component].metadatas,
fieldSizes,
schemaAttributes: components[props.attribute.component].attributes,
});
return (
<ComponentInput
{...props}
layout={[...layout, ...(remainingFieldsLayout || [])]}
hint={hint}
disabled={fieldIsDisabled}
renderInput={(props) => <VersionInputRenderer {...props} shouldIgnoreRBAC={true} />}
/>
>
{(inputProps) => <VersionInputRenderer {...inputProps} shouldIgnoreRBAC={true} />}
</ComponentInput>
);
case 'dynamiczone':
return <DynamicZone {...props} hint={hint} disabled={fieldIsDisabled} />;

View File

@ -11,13 +11,17 @@ import { PERMISSIONS } from '../../constants/plugin';
import { DocumentRBAC } from '../../features/DocumentRBAC';
import { useDocument } from '../../hooks/useDocument';
import { type EditLayout, useDocumentLayout } from '../../hooks/useDocumentLayout';
import { useGetContentTypeConfigurationQuery } from '../../services/contentTypes';
import { buildValidParams } from '../../utils/api';
import { VersionContent } from '../components/VersionContent';
import { VersionHeader } from '../components/VersionHeader';
import { VersionsList } from '../components/VersionsList';
import { useGetHistoryVersionsQuery } from '../services/historyVersion';
import type { ContentType } from '../../../../shared/contracts/content-types';
import type {
ContentType,
FindContentTypeConfiguration,
} from '../../../../shared/contracts/content-types';
import type {
HistoryVersionDataResponse,
GetHistoryVersions,
@ -32,6 +36,7 @@ interface HistoryContextValue {
contentType: UID.ContentType;
id?: string; // null for single types
layout: EditLayout['layout'];
configuration: FindContentTypeConfiguration.Response['data'];
selectedVersion: HistoryVersionDataResponse;
// Errors are handled outside of the provider, so we exclude errors from the response type
versions: Extract<GetHistoryVersions.Response, { data: Array<HistoryVersionDataResponse> }>;
@ -71,6 +76,8 @@ const HistoryPage = () => {
settings: { displayName, mainField },
},
} = useDocumentLayout(slug!);
const { data: configuration, isLoading: isLoadingConfiguration } =
useGetContentTypeConfigurationQuery(slug!);
// Parse state from query params
const [{ query }] = useQueryParams<{
@ -114,7 +121,13 @@ const HistoryPage = () => {
return <Navigate to="/content-manager" />;
}
if (isLoadingDocument || isLoadingLayout || versionsResponse.isFetching || isStaleRequest) {
if (
isLoadingDocument ||
isLoadingLayout ||
versionsResponse.isFetching ||
isStaleRequest ||
isLoadingConfiguration
) {
return <Page.Loading />;
}
@ -141,6 +154,7 @@ const HistoryPage = () => {
!layout ||
!schema ||
!selectedVersion ||
!configuration ||
// This should not happen as it's covered by versionsResponse.isError, but we need it for TS
versionsResponse.data.error
) {
@ -165,6 +179,7 @@ const HistoryPage = () => {
id={documentId}
schema={schema}
layout={layout}
configuration={configuration}
selectedVersion={selectedVersion}
versions={versionsResponse.data}
page={page}

View File

@ -224,7 +224,7 @@ type LayoutData = FindContentTypeConfiguration.Response['data'];
/**
* @internal
* @description takes the configuration data, the schema & the components used in the schema and formats the edit view
* vesions of the schema & components. This is then used to redner the edit view of the content-type.
* versions of the schema & components. This is then used to render the edit view of the content-type.
*/
const formatEditLayout = (
data: LayoutData,

View File

@ -10,7 +10,7 @@ import { EditFieldLayout } from '../../../../../hooks/useDocumentLayout';
import { getTranslation } from '../../../../../utils/translations';
import { transformDocument } from '../../../utils/data';
import { createDefaultForm } from '../../../utils/forms';
import { InputRendererProps } from '../../InputRenderer';
import { type InputRendererProps } from '../../InputRenderer';
import { Initializer } from './Initializer';
import { NonRepeatableComponent } from './NonRepeatable';
@ -20,7 +20,12 @@ interface ComponentInputProps
extends Omit<Extract<EditFieldLayout, { type: 'component' }>, 'size' | 'hint'>,
Pick<InputProps, 'hint'> {
labelAction?: React.ReactNode;
renderInput?: (props: InputRendererProps) => React.ReactNode;
children: (props: InputRendererProps) => React.ReactNode;
/**
* We need layout to come from the props, and not via a hook, because Content History needs
* a way to modify the normal component layout to add hidden fields.
*/
layout: EditFieldLayout[][];
}
const ComponentInput = ({
@ -90,15 +95,14 @@ const ComponentInput = ({
<Initializer disabled={disabled} name={name} onClick={handleInitialisationClick} />
)}
{!attribute.repeatable && field.value ? (
<NonRepeatableComponent
attribute={attribute}
name={name}
disabled={disabled}
{...props}
/>
<NonRepeatableComponent attribute={attribute} name={name} disabled={disabled} {...props}>
{props.children}
</NonRepeatableComponent>
) : null}
{attribute.repeatable && (
<RepeatableComponent attribute={attribute} name={name} disabled={disabled} {...props} />
<RepeatableComponent attribute={attribute} name={name} disabled={disabled} {...props}>
{props.children}
</RepeatableComponent>
)}
</Flex>
</Box>

View File

@ -1,28 +1,20 @@
import { useField } from '@strapi/admin/strapi-admin';
import { Box, Flex, Grid, GridItem } from '@strapi/design-system';
import { useDocLayout } from '../../../../../hooks/useDocumentLayout';
import { InputRenderer } from '../../InputRenderer';
import { ComponentProvider, useComponent } from '../ComponentContext';
import type { ComponentInputProps } from './Input';
interface NonRepeatableComponentProps extends Omit<ComponentInputProps, 'required' | 'label'> {}
type NonRepeatableComponentProps = Omit<ComponentInputProps, 'required' | 'label'>;
const NonRepeatableComponent = ({
attribute,
name,
renderInput = InputRenderer,
children,
layout,
}: NonRepeatableComponentProps) => {
const {
edit: { components },
} = useDocLayout();
const { value } = useField(name);
const level = useComponent('NonRepeatableComponent', (state) => state.level);
const { layout } = components[attribute.component];
const isNested = level > 0;
return (
@ -51,7 +43,7 @@ const NonRepeatableComponent = ({
return (
<GridItem col={size} key={completeFieldName} s={12} xs={12}>
{renderInput({ ...field, name: completeFieldName })}
{children({ ...field, name: completeFieldName })}
</GridItem>
);
})}

View File

@ -9,12 +9,12 @@ import {
Accordion,
AccordionContent as DSAccordionContent,
AccordionToggle,
Grid,
GridItem,
IconButton,
Typography,
KeyboardNavigable,
useComposedRefs,
GridItem,
Grid,
} from '@strapi/design-system';
import { Plus, Drag, Trash } from '@strapi/icons';
import { getEmptyImage } from 'react-dnd-html5-backend';
@ -24,13 +24,11 @@ import styled from 'styled-components';
import { ItemTypes } from '../../../../../constants/dragAndDrop';
import { useDoc } from '../../../../../hooks/useDocument';
import { useDocLayout } from '../../../../../hooks/useDocumentLayout';
import { useDragAndDrop, type UseDragAndDropOptions } from '../../../../../hooks/useDragAndDrop';
import { getIn } from '../../../../../utils/objects';
import { getTranslation } from '../../../../../utils/translations';
import { transformDocument } from '../../../utils/data';
import { createDefaultForm } from '../../../utils/forms';
import { InputRenderer } from '../../InputRenderer';
import { ComponentProvider, useComponent } from '../ComponentContext';
import { Initializer } from './Initializer';
@ -42,14 +40,15 @@ import type { Schema } from '@strapi/types';
* RepeatableComponent
* -----------------------------------------------------------------------------------------------*/
interface RepeatableComponentProps extends Omit<ComponentInputProps, 'label' | 'required'> {}
type RepeatableComponentProps = Omit<ComponentInputProps, 'required' | 'label'>;
const RepeatableComponent = ({
attribute,
disabled,
name,
mainField,
renderInput,
children,
layout,
}: RepeatableComponentProps) => {
const { toggleNotification } = useNotification();
const { formatMessage } = useIntl();
@ -211,6 +210,7 @@ const RepeatableComponent = ({
<AccordionGroup error={error}>
<AccordionContent aria-describedby={ariaDescriptionId}>
{value.map(({ __temp_key__: key, id }, index) => {
const nameWithIndex = `${name}.${index}`;
return (
<ComponentProvider
key={key}
@ -222,12 +222,11 @@ const RepeatableComponent = ({
>
<Component
disabled={disabled}
name={`${name}.${index}`}
name={nameWithIndex}
attribute={attribute}
index={index}
isOpen={collapseToOpen === key}
mainField={mainField}
renderInput={renderInput}
onMoveItem={handleMoveComponentField}
onClickToggle={handleToggle(key)}
onDeleteComponent={() => {
@ -238,7 +237,29 @@ const RepeatableComponent = ({
onCancel={handleCancel}
onDropItem={handleDropItem}
onGrabItem={handleGrabItem}
/>
>
{layout.map((row, index) => {
return (
<Grid gap={4} key={index}>
{row.map(({ size, ...field }) => {
/**
* Layouts are built from schemas so they don't understand the complete
* schema tree, for components we append the parent name to the field name
* because this is the structure for the data & permissions also understand
* the nesting involved.
*/
const completeFieldName = `${nameWithIndex}.${field.name}`;
return (
<GridItem col={size} key={completeFieldName} s={12} xs={12}>
{children({ ...field, name: completeFieldName })}
</GridItem>
);
})}
</Grid>
);
})}
</Component>
</ComponentProvider>
);
})}
@ -379,7 +400,7 @@ const ActionsFlex = styled(Flex)<{ expanded?: boolean }>`
interface ComponentProps
extends Pick<UseDragAndDropOptions, 'onGrabItem' | 'onDropItem' | 'onCancel' | 'onMoveItem'>,
Pick<RepeatableComponentProps, 'mainField' | 'renderInput'> {
Pick<RepeatableComponentProps, 'mainField'> {
attribute: Schema.Attribute.Component<`${string}.${string}`, boolean>;
disabled?: boolean;
index: number;
@ -388,10 +409,10 @@ interface ComponentProps
onClickToggle: () => void;
onDeleteComponent?: React.MouseEventHandler<HTMLButtonElement>;
toggleCollapses: () => void;
children: React.ReactNode;
}
const Component = ({
attribute,
disabled,
index,
isOpen,
@ -400,18 +421,13 @@ const Component = ({
name: 'id',
type: 'integer',
},
children,
onClickToggle,
onDeleteComponent,
toggleCollapses,
renderInput = InputRenderer,
...dragProps
}: ComponentProps) => {
const { formatMessage } = useIntl();
const {
edit: { components },
} = useDocLayout();
const { layout } = components[attribute.component];
const displayValue = useForm('RepeatableComponent', (state) => {
return getIn(state.values, [...name.split('.'), mainField.name]);
@ -500,27 +516,7 @@ const Component = ({
padding={6}
gap={6}
>
{layout.map((row, index) => {
return (
<Grid gap={4} key={index}>
{row.map(({ size, ...field }) => {
/**
* Layouts are built from schemas so they don't understand the complete
* schema tree, for components we append the parent name to the field name
* because this is the structure for the data & permissions also understand
* the nesting involved.
*/
const completeFieldName = `${name}.${field.name}`;
return (
<GridItem col={size} key={completeFieldName} s={12} xs={12}>
{renderInput({ ...field, name: completeFieldName })}
</GridItem>
);
})}
</Grid>
);
})}
{children}
</Flex>
</DSAccordionContent>
</Accordion>

View File

@ -9,6 +9,7 @@ import { useIntl } from 'react-intl';
import { useDocumentRBAC } from '../../../features/DocumentRBAC';
import { useDoc } from '../../../hooks/useDocument';
import { useDocLayout } from '../../../hooks/useDocumentLayout';
import { useLazyComponents } from '../../../hooks/useLazyComponents';
import { BlocksInput } from './FormInputs/BlocksInput/BlocksInput';
@ -58,6 +59,9 @@ const InputRenderer = ({ visible, hint: providedHint, ...props }: InputRendererP
);
const hint = useFieldHint(providedHint, props.attribute);
const {
edit: { components },
} = useDocLayout();
if (!visible) {
return null;
@ -114,7 +118,16 @@ const InputRenderer = ({ visible, hint: providedHint, ...props }: InputRendererP
case 'blocks':
return <BlocksInput {...props} hint={hint} type={props.type} disabled={fieldIsDisabled} />;
case 'component':
return <ComponentInput {...props} hint={hint} disabled={fieldIsDisabled} />;
return (
<ComponentInput
{...props}
hint={hint}
layout={components[props.attribute.component].layout}
disabled={fieldIsDisabled}
>
{(inputProps) => <InputRenderer {...inputProps} />}
</ComponentInput>
);
case 'dynamiczone':
return <DynamicZone {...props} hint={hint} disabled={fieldIsDisabled} />;
case 'relation':

View File

@ -10,6 +10,9 @@ import type { Schema, UID } from '@strapi/types';
* traverseData
* -----------------------------------------------------------------------------------------------*/
// Make only attributes required since it's the only one Content History has
type PartialSchema = Partial<Schema.Schema> & Pick<Schema.Schema, 'attributes'>;
type Predicate = <TAttribute extends Schema.Attribute.AnyAttribute>(
attribute: TAttribute,
value: Schema.Attribute.Value<TAttribute>
@ -35,7 +38,7 @@ const BLOCK_LIST_ATTRIBUTE_KEYS = ['__component', '__temp_key__'];
*/
const traverseData =
(predicate: Predicate, transform: Transform) =>
(schema: Schema.Schema, components: ComponentsDictionary = {}) =>
(schema: PartialSchema, components: ComponentsDictionary = {}) =>
(data: AnyData = {}) => {
const traverse = (datum: AnyData, attributes: Schema.Schema['attributes']) => {
return Object.entries(datum).reduce<AnyData>((acc, [key, value]) => {
@ -122,7 +125,7 @@ const prepareRelations = traverseData(
/**
* @internal
* @description Adds a `__temp_key__` to each component and dynamiczone item. This gives us
* a stable identifier regardless of it's ids etc. that we can then use for drag and drop.
* a stable identifier regardless of its ids etc. that we can then use for drag and drop.
*/
const prepareTempKeys = traverseData(
(attribute) =>
@ -150,7 +153,7 @@ const prepareTempKeys = traverseData(
* @description Fields that don't exist in the schema like createdAt etc. are only on the first level (not nested),
* as such we don't need to traverse the components to remove them.
*/
const removeFieldsThatDontExistOnSchema = (schema: Schema.Schema) => (data: AnyData) => {
const removeFieldsThatDontExistOnSchema = (schema: PartialSchema) => (data: AnyData) => {
const schemaKeys = Object.keys(schema.attributes);
const dataKeys = Object.keys(data);
@ -194,7 +197,7 @@ const removeNullValues = (data: AnyData) => {
* form to ensure the data is correctly prepared from their default state e.g. relations are set to an empty array.
*/
const transformDocument =
(schema: Schema.Schema, components: ComponentsDictionary = {}) =>
(schema: PartialSchema, components: ComponentsDictionary = {}) =>
(document: AnyData) => {
const transformations = pipe(
removeFieldsThatDontExistOnSchema(schema),
@ -207,4 +210,10 @@ const transformDocument =
return transformations(document);
};
export { removeProhibitedFields, prepareRelations, transformDocument };
export {
removeProhibitedFields,
prepareRelations,
prepareTempKeys,
removeFieldsThatDontExistOnSchema,
transformDocument,
};