mirror of
				https://github.com/strapi/strapi.git
				synced 2025-10-31 01:47:13 +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> |           <Flex> | ||||||
|             <Typography variant="pi" textColor="neutral600"> |             <Typography variant="pi" textColor="neutral600"> | ||||||
|               {formatMessage({ id: getTrad(`attribute.${type}.description`) })} |               {formatMessage({ | ||||||
|  |                 id: getTrad(`attribute.${type}.description`), | ||||||
|  |                 defaultMessage: 'A type for modeling data', | ||||||
|  |               })} | ||||||
|             </Typography> |             </Typography> | ||||||
|           </Flex> |           </Flex> | ||||||
|         </Box> |         </Box> | ||||||
|  | |||||||
| @ -12,58 +12,82 @@ import { Divider } from '@strapi/design-system/Divider'; | |||||||
| import { Grid, GridItem } from '@strapi/design-system/Grid'; | import { Grid, GridItem } from '@strapi/design-system/Grid'; | ||||||
| import { KeyboardNavigable } from '@strapi/design-system/KeyboardNavigable'; | import { KeyboardNavigable } from '@strapi/design-system/KeyboardNavigable'; | ||||||
| import { ModalBody } from '@strapi/design-system/ModalLayout'; | import { ModalBody } from '@strapi/design-system/ModalLayout'; | ||||||
| import { Flex } from '@strapi/design-system/Flex'; |  | ||||||
| import { Stack } from '@strapi/design-system/Stack'; | import { Stack } from '@strapi/design-system/Stack'; | ||||||
|  | import { Flex } from '@strapi/design-system/Flex'; | ||||||
| import { Typography } from '@strapi/design-system/Typography'; | import { Typography } from '@strapi/design-system/Typography'; | ||||||
|  | import { Tabs, Tab, TabGroup, TabPanels, TabPanel } from '@strapi/design-system/Tabs'; | ||||||
| import { getTrad } from '../../utils'; | import { getTrad } from '../../utils'; | ||||||
| import AttributeOption from './AttributeOption'; | import AttributeOption from './AttributeOption'; | ||||||
| 
 | 
 | ||||||
| const AttributeOptions = ({ attributes, forTarget, kind }) => { | const AttributeOptions = ({ attributes, forTarget, kind }) => { | ||||||
|   const { formatMessage } = useIntl(); |   const { formatMessage } = useIntl(); | ||||||
| 
 | 
 | ||||||
|  |   const defaultTabId = getTrad('modalForm.tabs.default'); | ||||||
|  |   const customTabId = getTrad('modalForm.tabs.custom'); | ||||||
|  | 
 | ||||||
|   const titleIdSuffix = forTarget.includes('component') ? 'component' : kind; |   const titleIdSuffix = forTarget.includes('component') ? 'component' : kind; | ||||||
|   const titleId = getTrad(`modalForm.sub-header.chooseAttribute.${titleIdSuffix}`); |   const titleId = getTrad(`modalForm.sub-header.chooseAttribute.${titleIdSuffix}`); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <ModalBody> |     <ModalBody padding={6}> | ||||||
|       <Flex paddingBottom={4}> |       <TabGroup | ||||||
|         <Typography variant="beta" as="h2"> |         label={formatMessage({ | ||||||
|           {formatMessage({ id: titleId, defaultMessage: 'Select a field' })} |           id: 'modalForm.tab-group.label', | ||||||
|         </Typography> |           defaultMessage: 'Default and Custom types tabs', | ||||||
|       </Flex> |         })} | ||||||
|       <Divider /> |         id="attribute-type-tabs" | ||||||
|       <Box paddingTop={6} paddingBottom={4}> |         variant="simple" | ||||||
|         <KeyboardNavigable tagName="button"> |       > | ||||||
|           <Stack spacing={8}> |         <Flex justifyContent="space-between"> | ||||||
|             {attributes.map((attributeRow, index) => { |           <Typography variant="beta" as="h2"> | ||||||
|               const key = index; |             {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 ( |                   return ( | ||||||
|                 <Grid key={key} gap={0}> |                     <Grid key={key} gap={0}> | ||||||
|                   {attributeRow.map((attribute, index) => { |                       {attributeRow.map((attribute, index) => { | ||||||
|                     const isOdd = index % 2 === 1; |                         const isOdd = index % 2 === 1; | ||||||
|                     const paddingLeft = isOdd ? 2 : 0; |                         const paddingLeft = isOdd ? 2 : 0; | ||||||
|                     const paddingRight = isOdd ? 0 : 2; |                         const paddingRight = isOdd ? 0 : 2; | ||||||
| 
 | 
 | ||||||
|                     return ( |                         return ( | ||||||
|                       <GridItem key={attribute} col={6} style={{ height: '100%' }}> |                           <GridItem key={attribute} col={6} style={{ height: '100%' }}> | ||||||
|                         <Box |                             <Box | ||||||
|                           paddingLeft={paddingLeft} |                               paddingLeft={paddingLeft} | ||||||
|                           paddingRight={paddingRight} |                               paddingRight={paddingRight} | ||||||
|                           paddingBottom={1} |                               paddingBottom={1} | ||||||
|                           style={{ height: '100%' }} |                               style={{ height: '100%' }} | ||||||
|                         > |                             > | ||||||
|                           <AttributeOption type={attribute} /> |                               <AttributeOption type={attribute} /> | ||||||
|                         </Box> |                             </Box> | ||||||
|                       </GridItem> |                           </GridItem> | ||||||
|                     ); |                         ); | ||||||
|                   })} |                       })} | ||||||
|                 </Grid> |                     </Grid> | ||||||
|               ); |                   ); | ||||||
|             })} |                 })} | ||||||
|           </Stack> |               </Stack> | ||||||
|         </KeyboardNavigable> |             </KeyboardNavigable> | ||||||
|       </Box> |           </TabPanel> | ||||||
|  |           <TabPanel> | ||||||
|  |             <Typography>Coming soon</Typography> | ||||||
|  |           </TabPanel> | ||||||
|  |         </TabPanels> | ||||||
|  |       </TabGroup> | ||||||
|     </ModalBody> |     </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.collectionType": "Select a field for your collection type", | ||||||
|   "modalForm.sub-header.chooseAttribute.component": "Select a field for your component", |   "modalForm.sub-header.chooseAttribute.component": "Select a field for your component", | ||||||
|   "modalForm.sub-header.chooseAttribute.singleType": "Select a field for your single type", |   "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.relation-polymorphic": "Relation (polymorphic)", | ||||||
|   "modelPage.attribute.relationWith": "Relation with", |   "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", |   "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
	 Rémi de Juvigny
						Rémi de Juvigny