mirror of
https://github.com/strapi/strapi.git
synced 2025-08-31 04:03:50 +00:00
Merge remote-tracking branch 'origin/features/custom-fields' into custom-fields/attributes-list
This commit is contained in:
commit
c97ebd192a
@ -42,7 +42,10 @@ const AttributeOption = ({ type }) => {
|
||||
|
||||
<Flex>
|
||||
<Typography variant="pi" textColor="neutral600">
|
||||
{formatMessage({ id: getTrad(`attribute.${type}.description`) })}
|
||||
{formatMessage({
|
||||
id: getTrad(`attribute.${type}.description`),
|
||||
defaultMessage: 'A type for modeling data',
|
||||
})}
|
||||
</Typography>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
@ -12,58 +12,82 @@ import { Divider } from '@strapi/design-system/Divider';
|
||||
import { Grid, GridItem } from '@strapi/design-system/Grid';
|
||||
import { KeyboardNavigable } from '@strapi/design-system/KeyboardNavigable';
|
||||
import { ModalBody } from '@strapi/design-system/ModalLayout';
|
||||
import { Flex } from '@strapi/design-system/Flex';
|
||||
import { Stack } from '@strapi/design-system/Stack';
|
||||
import { Flex } from '@strapi/design-system/Flex';
|
||||
import { Typography } from '@strapi/design-system/Typography';
|
||||
import { Tabs, Tab, TabGroup, TabPanels, TabPanel } from '@strapi/design-system/Tabs';
|
||||
import { getTrad } from '../../utils';
|
||||
import AttributeOption from './AttributeOption';
|
||||
|
||||
const AttributeOptions = ({ attributes, forTarget, kind }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const defaultTabId = getTrad('modalForm.tabs.default');
|
||||
const customTabId = getTrad('modalForm.tabs.custom');
|
||||
|
||||
const titleIdSuffix = forTarget.includes('component') ? 'component' : kind;
|
||||
const titleId = getTrad(`modalForm.sub-header.chooseAttribute.${titleIdSuffix}`);
|
||||
|
||||
return (
|
||||
<ModalBody>
|
||||
<Flex paddingBottom={4}>
|
||||
<Typography variant="beta" as="h2">
|
||||
{formatMessage({ id: titleId, defaultMessage: 'Select a field' })}
|
||||
</Typography>
|
||||
</Flex>
|
||||
<Divider />
|
||||
<Box paddingTop={6} paddingBottom={4}>
|
||||
<KeyboardNavigable tagName="button">
|
||||
<Stack spacing={8}>
|
||||
{attributes.map((attributeRow, index) => {
|
||||
const key = index;
|
||||
<ModalBody padding={6}>
|
||||
<TabGroup
|
||||
label={formatMessage({
|
||||
id: 'modalForm.tab-group.label',
|
||||
defaultMessage: 'Default and Custom types tabs',
|
||||
})}
|
||||
id="attribute-type-tabs"
|
||||
variant="simple"
|
||||
>
|
||||
<Flex justifyContent="space-between">
|
||||
<Typography variant="beta" as="h2">
|
||||
{formatMessage({ id: titleId, defaultMessage: 'Select a field' })}
|
||||
</Typography>
|
||||
<Tabs>
|
||||
<Tab>{formatMessage({ id: defaultTabId, defaultMessage: 'Default' })}</Tab>
|
||||
<Tab>{formatMessage({ id: customTabId, defaultMessage: 'Custom' })}</Tab>
|
||||
</Tabs>
|
||||
</Flex>
|
||||
<Box paddingBottom={6}>
|
||||
<Divider />
|
||||
</Box>
|
||||
<TabPanels>
|
||||
<TabPanel>
|
||||
<KeyboardNavigable tagName="button">
|
||||
<Stack spacing={8}>
|
||||
{attributes.map((attributeRow, index) => {
|
||||
const key = index;
|
||||
|
||||
return (
|
||||
<Grid key={key} gap={0}>
|
||||
{attributeRow.map((attribute, index) => {
|
||||
const isOdd = index % 2 === 1;
|
||||
const paddingLeft = isOdd ? 2 : 0;
|
||||
const paddingRight = isOdd ? 0 : 2;
|
||||
return (
|
||||
<Grid key={key} gap={0}>
|
||||
{attributeRow.map((attribute, index) => {
|
||||
const isOdd = index % 2 === 1;
|
||||
const paddingLeft = isOdd ? 2 : 0;
|
||||
const paddingRight = isOdd ? 0 : 2;
|
||||
|
||||
return (
|
||||
<GridItem key={attribute} col={6} style={{ height: '100%' }}>
|
||||
<Box
|
||||
paddingLeft={paddingLeft}
|
||||
paddingRight={paddingRight}
|
||||
paddingBottom={1}
|
||||
style={{ height: '100%' }}
|
||||
>
|
||||
<AttributeOption type={attribute} />
|
||||
</Box>
|
||||
</GridItem>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</KeyboardNavigable>
|
||||
</Box>
|
||||
return (
|
||||
<GridItem key={attribute} col={6} style={{ height: '100%' }}>
|
||||
<Box
|
||||
paddingLeft={paddingLeft}
|
||||
paddingRight={paddingRight}
|
||||
paddingBottom={1}
|
||||
style={{ height: '100%' }}
|
||||
>
|
||||
<AttributeOption type={attribute} />
|
||||
</Box>
|
||||
</GridItem>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</KeyboardNavigable>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Typography>Coming soon</Typography>
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</TabGroup>
|
||||
</ModalBody>
|
||||
);
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import { render, screen, getByText, fireEvent } from '@testing-library/react';
|
||||
import { lightTheme, ThemeProvider } from '@strapi/design-system';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import FormModalNavigationProvider from '../../FormModalNavigationProvider';
|
||||
import AttributeOptions from '../index';
|
||||
|
||||
const mockAttributes = [
|
||||
[
|
||||
'text',
|
||||
'email',
|
||||
'richtext',
|
||||
'password',
|
||||
'number',
|
||||
'enumeration',
|
||||
'date',
|
||||
'media',
|
||||
'boolean',
|
||||
'json',
|
||||
'relation',
|
||||
'uid',
|
||||
],
|
||||
['component', 'dynamiczone'],
|
||||
];
|
||||
|
||||
const App = (
|
||||
<IntlProvider locale="en" messages={{}} textComponent="span">
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<FormModalNavigationProvider>
|
||||
<AttributeOptions
|
||||
attributes={mockAttributes}
|
||||
forTarget="contentType"
|
||||
kind="collectionType"
|
||||
/>
|
||||
</FormModalNavigationProvider>
|
||||
</ThemeProvider>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
describe('<AttributeOptions />', () => {
|
||||
it('renders and matches the snapshot', () => {
|
||||
const { container } = render(App);
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('shows the simple tabs', () => {
|
||||
render(App);
|
||||
|
||||
const defaultTab = screen.getByRole('tab', { selected: true });
|
||||
const customTab = screen.getByRole('tab', { selected: false });
|
||||
|
||||
expect(defaultTab).toBeVisible();
|
||||
expect(customTab).toBeVisible();
|
||||
});
|
||||
|
||||
it('defaults to the default tab', () => {
|
||||
render(App);
|
||||
|
||||
const comingSoonText = screen.queryByText('Coming soon');
|
||||
|
||||
expect(comingSoonText).toEqual(null);
|
||||
});
|
||||
|
||||
it('switches to the custom tab', () => {
|
||||
render(App);
|
||||
|
||||
const customTab = screen.getByRole('tab', { selected: false });
|
||||
fireEvent.click(customTab);
|
||||
const customTabSelected = screen.getByRole('tab', { selected: true });
|
||||
const customTabText = getByText(customTabSelected, 'Custom');
|
||||
const comingSoonText = screen.getByText('Coming soon');
|
||||
|
||||
expect(customTabText).not.toBe(null);
|
||||
expect(comingSoonText).toBeVisible();
|
||||
});
|
||||
});
|
@ -155,6 +155,9 @@
|
||||
"modalForm.sub-header.chooseAttribute.collectionType": "Select a field for your collection type",
|
||||
"modalForm.sub-header.chooseAttribute.component": "Select a field for your component",
|
||||
"modalForm.sub-header.chooseAttribute.singleType": "Select a field for your single type",
|
||||
"modalForm.tabs.custom": "Custom",
|
||||
"modalForm.tabs.default": "Default",
|
||||
"modalForm.tabs.label": "Default and Custom types tabs",
|
||||
"modelPage.attribute.relation-polymorphic": "Relation (polymorphic)",
|
||||
"modelPage.attribute.relationWith": "Relation with",
|
||||
"notification.error.dynamiczone-min.validation": "At least one component is required in a dynamic zone to be able to save a content type",
|
||||
|
Loading…
x
Reference in New Issue
Block a user