diff --git a/packages/core/content-type-builder/admin/src/components/AttributeOptions/AttributeOption/index.js b/packages/core/content-type-builder/admin/src/components/AttributeOptions/AttributeOption/index.js
index ab767fe443..c5a8f64f31 100644
--- a/packages/core/content-type-builder/admin/src/components/AttributeOptions/AttributeOption/index.js
+++ b/packages/core/content-type-builder/admin/src/components/AttributeOptions/AttributeOption/index.js
@@ -42,7 +42,10 @@ const AttributeOption = ({ type }) => {
- {formatMessage({ id: getTrad(`attribute.${type}.description`) })}
+ {formatMessage({
+ id: getTrad(`attribute.${type}.description`),
+ defaultMessage: 'A type for modeling data',
+ })}
diff --git a/packages/core/content-type-builder/admin/src/components/AttributeOptions/index.js b/packages/core/content-type-builder/admin/src/components/AttributeOptions/index.js
index db130b6eb0..37030fd8d0 100644
--- a/packages/core/content-type-builder/admin/src/components/AttributeOptions/index.js
+++ b/packages/core/content-type-builder/admin/src/components/AttributeOptions/index.js
@@ -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 (
-
-
-
- {formatMessage({ id: titleId, defaultMessage: 'Select a field' })}
-
-
-
-
-
-
- {attributes.map((attributeRow, index) => {
- const key = index;
+
+
+
+
+ {formatMessage({ id: titleId, defaultMessage: 'Select a field' })}
+
+
+ {formatMessage({ id: defaultTabId, defaultMessage: 'Default' })}
+ {formatMessage({ id: customTabId, defaultMessage: 'Custom' })}
+
+
+
+
+
+
+
+
+
+ {attributes.map((attributeRow, index) => {
+ const key = index;
- return (
-
- {attributeRow.map((attribute, index) => {
- const isOdd = index % 2 === 1;
- const paddingLeft = isOdd ? 2 : 0;
- const paddingRight = isOdd ? 0 : 2;
+ return (
+
+ {attributeRow.map((attribute, index) => {
+ const isOdd = index % 2 === 1;
+ const paddingLeft = isOdd ? 2 : 0;
+ const paddingRight = isOdd ? 0 : 2;
- return (
-
-
-
-
-
- );
- })}
-
- );
- })}
-
-
-
+ return (
+
+
+
+
+
+ );
+ })}
+
+ );
+ })}
+
+
+
+
+ Coming soon
+
+
+
);
};
diff --git a/packages/core/content-type-builder/admin/src/components/AttributeOptions/tests/__snapshots__/index.test.js.snap b/packages/core/content-type-builder/admin/src/components/AttributeOptions/tests/__snapshots__/index.test.js.snap
new file mode 100644
index 0000000000..a1fe23434d
--- /dev/null
+++ b/packages/core/content-type-builder/admin/src/components/AttributeOptions/tests/__snapshots__/index.test.js.snap
@@ -0,0 +1,1264 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` renders and matches the snapshot 1`] = `
+.c26 {
+ border: 0;
+ -webkit-clip: rect(0 0 0 0);
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+.c10 {
+ padding-bottom: 24px;
+}
+
+.c17 {
+ padding-right: 8px;
+ padding-bottom: 4px;
+ padding-left: 0px;
+}
+
+.c18 {
+ padding: 16px;
+ border-radius: 4px;
+}
+
+.c22 {
+ padding-left: 16px;
+}
+
+.c25 {
+ padding-right: 0px;
+ padding-bottom: 4px;
+ padding-left: 8px;
+}
+
+.c2 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+}
+
+.c20 {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-direction: row;
+ -ms-flex-direction: row;
+ flex-direction: row;
+}
+
+.c13 {
+ -webkit-align-items: stretch;
+ -webkit-box-align: stretch;
+ -ms-flex-align: stretch;
+ align-items: stretch;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+}
+
+.c14 > * {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.c14 > * + * {
+ margin-top: 40px;
+}
+
+.c3 {
+ color: #32324d;
+ font-weight: 600;
+ font-size: 1.125rem;
+ line-height: 1.22;
+}
+
+.c23 {
+ font-weight: 600;
+ color: #32324d;
+ font-size: 0.875rem;
+ line-height: 1.43;
+}
+
+.c24 {
+ color: #666687;
+ font-size: 0.75rem;
+ line-height: 1.33;
+}
+
+.c11 {
+ background: #eaeaef;
+}
+
+.c12 {
+ height: 1px;
+ border: none;
+ margin: 0;
+}
+
+.c15 {
+ display: grid;
+ grid-template-columns: repeat(12,1fr);
+ gap: 0px;
+}
+
+.c16 {
+ grid-column: span 6;
+ max-width: 100%;
+}
+
+.c0 {
+ padding: 24px;
+}
+
+.c1 {
+ overflow: auto;
+ max-height: 60vh;
+}
+
+.c7 {
+ color: #4945ff;
+ font-weight: 600;
+ font-size: 0.6875rem;
+ line-height: 1.45;
+ text-transform: uppercase;
+}
+
+.c9 {
+ color: #666687;
+ font-weight: 600;
+ font-size: 0.6875rem;
+ line-height: 1.45;
+ text-transform: uppercase;
+}
+
+.c5 {
+ padding: 16px;
+}
+
+.c6 {
+ border-bottom: 2px solid #4945ff;
+}
+
+.c8 {
+ border-bottom: 2px solid transparent;
+}
+
+.c4[aria-disabled='true'] {
+ cursor: not-allowed;
+}
+
+.c21 {
+ width: 2rem;
+ height: 1.5rem;
+ box-sizing: content-box;
+}
+
+.c19 {
+ width: 100%;
+ height: 100%;
+ border: 1px solid #dcdce4;
+ text-align: left;
+}
+
+.c19:hover {
+ background: #f0f0ff;
+ border: 1px solid #d9d8ff;
+}
+
+@media (max-width:68.75rem) {
+ .c16 {
+ grid-column: span;
+ }
+}
+
+@media (max-width:34.375rem) {
+ .c16 {
+ grid-column: span;
+ }
+}
+
+
+
+
+
+
+ Select a field
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/packages/core/content-type-builder/admin/src/components/AttributeOptions/tests/index.test.js b/packages/core/content-type-builder/admin/src/components/AttributeOptions/tests/index.test.js
new file mode 100644
index 0000000000..8b927ce234
--- /dev/null
+++ b/packages/core/content-type-builder/admin/src/components/AttributeOptions/tests/index.test.js
@@ -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 = (
+
+
+
+
+
+
+
+);
+
+describe('', () => {
+ 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();
+ });
+});
diff --git a/packages/core/content-type-builder/admin/src/translations/en.json b/packages/core/content-type-builder/admin/src/translations/en.json
index 77d02a63f2..bd855aa955 100644
--- a/packages/core/content-type-builder/admin/src/translations/en.json
+++ b/packages/core/content-type-builder/admin/src/translations/en.json
@@ -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",