mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 10:55:37 +00:00
fix(cm): nested components never have permission (#20291)
* fix(cm): nested components never have permission * chore: memoize form inputs for complex forms * fix(cm): performance regression where selectFromResult was running too often due to arguments
This commit is contained in:
parent
8592bde151
commit
9381bbbca6
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { Toggle, useComposedRefs, Field } from '@strapi/design-system';
|
||||
import { useIntl } from 'react-intl';
|
||||
@ -40,4 +40,6 @@ const BooleanInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { BooleanInput };
|
||||
const MemoizedBooleanInput = memo(BooleanInput);
|
||||
|
||||
export { MemoizedBooleanInput as BooleanInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { Checkbox, useComposedRefs, Field } from '@strapi/design-system';
|
||||
|
||||
@ -31,4 +31,6 @@ const CheckboxInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { CheckboxInput };
|
||||
const MemoizedCheckboxInput = memo(CheckboxInput);
|
||||
|
||||
export { MemoizedCheckboxInput as CheckboxInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { DatePicker, useComposedRefs, Field } from '@strapi/design-system';
|
||||
import { useIntl } from 'react-intl';
|
||||
@ -37,4 +37,6 @@ const DateInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { DateInput };
|
||||
const MemoizedDateInput = memo(DateInput);
|
||||
|
||||
export { MemoizedDateInput as DateInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { DateTimePicker, useComposedRefs, Field } from '@strapi/design-system';
|
||||
import { useIntl } from 'react-intl';
|
||||
@ -37,4 +37,6 @@ const DateTimeInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { DateTimeInput };
|
||||
const MemoizedDateTimeInput = memo(DateTimeInput);
|
||||
|
||||
export { MemoizedDateTimeInput as DateTimeInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { TextInput, useComposedRefs, Field } from '@strapi/design-system';
|
||||
|
||||
@ -7,7 +7,7 @@ import { useField } from '../Form';
|
||||
|
||||
import type { StringProps } from './types';
|
||||
|
||||
export const EmailInput = forwardRef<HTMLInputElement, StringProps>(
|
||||
const EmailInput = forwardRef<HTMLInputElement, StringProps>(
|
||||
({ name, required, label, hint, labelAction, ...props }, ref) => {
|
||||
const field = useField(name);
|
||||
const fieldRef = useFocusInputField<HTMLInputElement>(name);
|
||||
@ -32,3 +32,7 @@ export const EmailInput = forwardRef<HTMLInputElement, StringProps>(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const MemoizedEmailInput = memo(EmailInput);
|
||||
|
||||
export { MemoizedEmailInput as EmailInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { SingleSelect, SingleSelectOption, useComposedRefs, Field } from '@strapi/design-system';
|
||||
|
||||
@ -7,7 +7,7 @@ import { useField } from '../Form';
|
||||
|
||||
import { EnumerationProps } from './types';
|
||||
|
||||
export const EnumerationInput = forwardRef<HTMLDivElement, EnumerationProps>(
|
||||
const EnumerationInput = forwardRef<HTMLDivElement, EnumerationProps>(
|
||||
({ name, required, label, hint, labelAction, options = [], ...props }, ref) => {
|
||||
const field = useField(name);
|
||||
const fieldRef = useFocusInputField<HTMLDivElement>(name);
|
||||
@ -39,3 +39,7 @@ export const EnumerationInput = forwardRef<HTMLDivElement, EnumerationProps>(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const MemoizedEnumerationInput = memo(EnumerationInput);
|
||||
|
||||
export { MemoizedEnumerationInput as EnumerationInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import {
|
||||
JSONInput as JSONInputImpl,
|
||||
@ -12,7 +12,7 @@ import { useField } from '../Form';
|
||||
|
||||
import { InputProps } from './types';
|
||||
|
||||
export const JsonInput = forwardRef<JSONInputRef, InputProps>(
|
||||
const JsonInput = forwardRef<JSONInputRef, InputProps>(
|
||||
({ name, required, label, hint, labelAction, ...props }, ref) => {
|
||||
const field = useField(name);
|
||||
const fieldRef = useFocusInputField(name);
|
||||
@ -40,3 +40,7 @@ export const JsonInput = forwardRef<JSONInputRef, InputProps>(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const MemoizedJsonInput = memo(JsonInput);
|
||||
|
||||
export { MemoizedJsonInput as JsonInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { NumberInput, useComposedRefs, Field } from '@strapi/design-system';
|
||||
|
||||
@ -34,4 +34,6 @@ const NumberInputImpl = forwardRef<HTMLInputElement, InputProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { NumberInputImpl as NumberInput };
|
||||
const MemoizedNumberInput = memo(NumberInputImpl);
|
||||
|
||||
export { MemoizedNumberInput as NumberInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef, useState } from 'react';
|
||||
import { forwardRef, memo, useState } from 'react';
|
||||
|
||||
import { TextInput, useComposedRefs, Field } from '@strapi/design-system';
|
||||
import { Eye, EyeStriked } from '@strapi/icons';
|
||||
@ -9,7 +9,7 @@ import { useField } from '../Form';
|
||||
|
||||
import type { StringProps } from './types';
|
||||
|
||||
export const PasswordInput = forwardRef<HTMLInputElement, StringProps>(
|
||||
const PasswordInput = forwardRef<HTMLInputElement, StringProps>(
|
||||
({ name, required, label, hint, labelAction, ...props }, ref) => {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const { formatMessage } = useIntl();
|
||||
@ -55,3 +55,7 @@ export const PasswordInput = forwardRef<HTMLInputElement, StringProps>(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const MemoizedPasswordInput = memo(PasswordInput);
|
||||
|
||||
export { MemoizedPasswordInput as PasswordInput };
|
||||
|
||||
@ -93,4 +93,6 @@ const NotSupportedField = forwardRef<any, InputProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { InputRenderer };
|
||||
const MemoizedInputRenderer = memo(InputRenderer);
|
||||
|
||||
export { MemoizedInputRenderer as InputRenderer };
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { TextInput, useComposedRefs, Field } from '@strapi/design-system';
|
||||
|
||||
import { useFocusInputField } from '../../hooks/useFocusInputField';
|
||||
import { type InputProps, useField } from '../Form';
|
||||
|
||||
export const StringInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
const StringInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
({ name, required, label, hint, labelAction, ...props }, ref) => {
|
||||
const field = useField(name);
|
||||
const fieldRef = useFocusInputField<HTMLInputElement>(name);
|
||||
@ -28,3 +28,7 @@ export const StringInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const MemoizedStringInput = memo(StringInput);
|
||||
|
||||
export { MemoizedStringInput as StringInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { Textarea, useComposedRefs, Field } from '@strapi/design-system';
|
||||
|
||||
@ -7,7 +7,7 @@ import { useField } from '../Form';
|
||||
|
||||
import type { StringProps } from './types';
|
||||
|
||||
export const TextareaInput = forwardRef<HTMLTextAreaElement, StringProps>(
|
||||
const TextareaInput = forwardRef<HTMLTextAreaElement, StringProps>(
|
||||
({ name, required, label, hint, labelAction, ...props }, ref) => {
|
||||
const field = useField(name);
|
||||
const fieldRef = useFocusInputField<HTMLTextAreaElement>(name);
|
||||
@ -30,3 +30,7 @@ export const TextareaInput = forwardRef<HTMLTextAreaElement, StringProps>(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const MemoizedTextareaInput = memo(TextareaInput);
|
||||
|
||||
export { MemoizedTextareaInput as TextareaInput };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { forwardRef } from 'react';
|
||||
import { forwardRef, memo } from 'react';
|
||||
|
||||
import { TimePicker, useComposedRefs, Field } from '@strapi/design-system';
|
||||
import { useIntl } from 'react-intl';
|
||||
@ -36,4 +36,6 @@ const TimeInput = forwardRef<HTMLInputElement, InputProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { TimeInput };
|
||||
const MemoizedTimeInput = memo(TimeInput);
|
||||
|
||||
export { MemoizedTimeInput as TimeInput };
|
||||
|
||||
@ -104,12 +104,9 @@ const DocumentRBAC = ({ children, permissions }: DocumentRBACProps) => {
|
||||
.filter((field) => field.split('.').length > 1);
|
||||
|
||||
if (fieldType === 'component') {
|
||||
const componentOrDynamicZoneFields = componentFieldNames
|
||||
// then map to give us the dot separate path as an array
|
||||
.map((field) => field.split('.'));
|
||||
// check if the field name is within any of those arrays
|
||||
return componentOrDynamicZoneFields.some((field) => {
|
||||
return field.includes(fieldName);
|
||||
return componentFieldNames.some((field) => {
|
||||
return field.includes(name.join('.'));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -26,32 +26,25 @@ const useContentTypeSchema = (model?: string) => {
|
||||
const { toggleNotification } = useNotification();
|
||||
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
||||
|
||||
const { components, contentType, contentTypes, error, isLoading, isFetching } =
|
||||
useGetInitialDataQuery(undefined, {
|
||||
selectFromResult: (res) => {
|
||||
const contentType = res.data?.contentTypes.find((ct) => ct.uid === model);
|
||||
const { data, error, isLoading, isFetching } = useGetInitialDataQuery(undefined);
|
||||
|
||||
const componentsByKey = res.data?.components.reduce<ComponentsDictionary>(
|
||||
(acc, component) => {
|
||||
acc[component.uid] = component;
|
||||
const { components, contentType, contentTypes } = React.useMemo(() => {
|
||||
const contentType = data?.contentTypes.find((ct) => ct.uid === model);
|
||||
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
const componentsByKey = data?.components.reduce<ComponentsDictionary>((acc, component) => {
|
||||
acc[component.uid] = component;
|
||||
|
||||
const components = extractContentTypeComponents(contentType?.attributes, componentsByKey);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
isLoading: res.isLoading,
|
||||
isFetching: res.isFetching,
|
||||
error: res.error,
|
||||
components: Object.keys(components).length === 0 ? undefined : components,
|
||||
contentType,
|
||||
contentTypes: res.data?.contentTypes ?? [],
|
||||
};
|
||||
},
|
||||
});
|
||||
const components = extractContentTypeComponents(contentType?.attributes, componentsByKey);
|
||||
|
||||
return {
|
||||
components: Object.keys(components).length === 0 ? undefined : components,
|
||||
contentType,
|
||||
contentTypes: data?.contentTypes ?? [],
|
||||
};
|
||||
}, [model, data]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (error) {
|
||||
|
||||
@ -38,4 +38,6 @@ const BlocksInput = React.forwardRef<{ focus: () => void }, BlocksInputProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { BlocksInput };
|
||||
const MemoizedBlocksInput = React.memo(BlocksInput);
|
||||
|
||||
export { MemoizedBlocksInput as BlocksInput };
|
||||
|
||||
@ -109,5 +109,7 @@ const ComponentInput = ({
|
||||
);
|
||||
};
|
||||
|
||||
export { ComponentInput };
|
||||
const MemoizedComponentInput = React.memo(ComponentInput);
|
||||
|
||||
export { MemoizedComponentInput as ComponentInput };
|
||||
export type { ComponentInputProps };
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { TextInput } from '@strapi/design-system';
|
||||
import { Field, TextInput } from '@strapi/design-system';
|
||||
import { EyeStriked } from '@strapi/icons';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { styled } from 'styled-components';
|
||||
|
||||
import type { InputProps } from '@strapi/admin/strapi-admin';
|
||||
import type { Schema } from '@strapi/types';
|
||||
@ -19,26 +18,18 @@ const NotAllowedInput = ({ hint, label, required, name }: NotAllowedInputProps)
|
||||
});
|
||||
|
||||
return (
|
||||
<TextInput
|
||||
disabled
|
||||
// @ts-expect-error – label _could_ be a ReactNode since it's a child, this should be fixed in the DS.
|
||||
label={label}
|
||||
id={name}
|
||||
hint={hint}
|
||||
name={name}
|
||||
placeholder={placeholder}
|
||||
required={required}
|
||||
startAction={<StyledIcon />}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<Field.Root id={name} hint={hint} name={name} required={required}>
|
||||
<Field.Label>{label}</Field.Label>
|
||||
<TextInput
|
||||
disabled
|
||||
placeholder={placeholder}
|
||||
startAction={<EyeStriked fill="neutral600" />}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<Field.Hint />
|
||||
</Field.Root>
|
||||
);
|
||||
};
|
||||
|
||||
const StyledIcon = styled(EyeStriked)`
|
||||
& > path {
|
||||
fill: ${({ theme }) => theme.colors.neutral600};
|
||||
}
|
||||
`;
|
||||
|
||||
export { NotAllowedInput };
|
||||
|
||||
@ -1032,5 +1032,7 @@ const RelationItemPlaceholder = () => (
|
||||
/>
|
||||
);
|
||||
|
||||
export { RelationsField as RelationsInput, FlexWrapper, DisconnectButton, LinkEllipsis };
|
||||
const MemoizedRelationsField = React.memo(RelationsField);
|
||||
|
||||
export { MemoizedRelationsField as RelationsInput, FlexWrapper, DisconnectButton, LinkEllipsis };
|
||||
export type { RelationsFieldProps };
|
||||
|
||||
@ -322,5 +322,7 @@ const LoadingWrapper = styled<FlexComponent>(Flex)`
|
||||
animation: ${rotation} 2s infinite linear;
|
||||
`;
|
||||
|
||||
export { UIDInput };
|
||||
const MemoizedUIDInput = React.memo(UIDInput);
|
||||
|
||||
export { MemoizedUIDInput as UIDInput };
|
||||
export type { UIDInputProps };
|
||||
|
||||
@ -150,5 +150,7 @@ const Wysiwyg = React.forwardRef<EditorApi, WysiwygProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export { Wysiwyg };
|
||||
const MemoizedWysiwyg = React.memo(Wysiwyg);
|
||||
|
||||
export { MemoizedWysiwyg as Wysiwyg };
|
||||
export type { WysiwygProps };
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { ReactNode, memo } from 'react';
|
||||
|
||||
import {
|
||||
useStrapiApp,
|
||||
@ -228,5 +228,7 @@ const getMinMax = (attribute: Schema.Attribute.AnyAttribute) => {
|
||||
}
|
||||
};
|
||||
|
||||
const MemoizedInputRenderer = memo(InputRenderer);
|
||||
|
||||
export type { InputRendererProps };
|
||||
export { InputRenderer, useFieldHint };
|
||||
export { MemoizedInputRenderer as InputRenderer, useFieldHint };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user