mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 18:33:55 +00:00
Merge branch 'releases/v4' of github.com:strapi/strapi into v4/media-library-cm
This commit is contained in:
commit
4d907c873c
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_basic_simples",
|
||||
"info": {
|
||||
"name": "simple",
|
||||
"displayName": "simple",
|
||||
"icon": "ambulance",
|
||||
"description": ""
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_blog_test_comos",
|
||||
"info": {
|
||||
"name": "test comp",
|
||||
"displayName": "test comp",
|
||||
"icon": "air-freshener",
|
||||
"description": ""
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_default_apples",
|
||||
"info": {
|
||||
"name": "apple",
|
||||
"displayName": "apple",
|
||||
"icon": "apple-alt",
|
||||
"description": ""
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_default_cars",
|
||||
"info": {
|
||||
"name": "car",
|
||||
"displayName": "car",
|
||||
"icon": "align-right"
|
||||
},
|
||||
"options": {},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_closingperiods",
|
||||
"info": {
|
||||
"name": "closingperiod",
|
||||
"displayName": "closingperiod",
|
||||
"description": "",
|
||||
"icon": "angry"
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_dishes",
|
||||
"info": {
|
||||
"name": "dish",
|
||||
"displayName": "dish",
|
||||
"description": "",
|
||||
"icon": "address-book"
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_openingtimes",
|
||||
"info": {
|
||||
"name": "openingtimes",
|
||||
"displayName": "openingtimes",
|
||||
"description": "",
|
||||
"icon": "calendar"
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_restaurantservices",
|
||||
"info": {
|
||||
"name": "restaurantservice",
|
||||
"displayName": "restaurantservice",
|
||||
"description": "",
|
||||
"icon": "cannabis"
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"collectionName": "components_default_temps",
|
||||
"info": {
|
||||
"name": "temp",
|
||||
"displayName": "temp",
|
||||
"icon": "adjust",
|
||||
"description": ""
|
||||
},
|
||||
|
||||
@ -1,3 +1,14 @@
|
||||
module.exports = () => {
|
||||
return (ctx, next) => next();
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* `test-middleware` middleware.
|
||||
*/
|
||||
|
||||
module.exports = (config, { strapi }) => {
|
||||
// Add your own logic here.
|
||||
return async (ctx, next) => {
|
||||
strapi.log.info('In test-middleware middleware.');
|
||||
|
||||
await next();
|
||||
};
|
||||
};
|
||||
|
||||
@ -57,11 +57,11 @@ async function getTemplateQuestion() {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string|null} projectName - The name of the project
|
||||
* @param {string|null} template - The template the project should use
|
||||
* @returns Array of prompt question objects
|
||||
*/
|
||||
// TODO: re-enabled once the template have been migrated to V4
|
||||
async function getPromptQuestions(projectName /*, template */) {
|
||||
async function getPromptQuestions(projectName /*, template*/) {
|
||||
return [
|
||||
{
|
||||
type: 'input',
|
||||
@ -85,7 +85,7 @@ async function getPromptQuestions(projectName /*, template */) {
|
||||
},
|
||||
],
|
||||
},
|
||||
// TODO: re-enabled once the template have been migrated to V4
|
||||
// TODO: re-enable once we know where to list the official compatible templates
|
||||
// {
|
||||
// type: 'confirm',
|
||||
// name: 'useTemplate',
|
||||
|
||||
@ -4,23 +4,18 @@ import styled from 'styled-components';
|
||||
import { useIntl } from 'react-intl';
|
||||
import PlusCircle from '@strapi/icons/PlusCircle';
|
||||
import { Box } from '@strapi/design-system/Box';
|
||||
import { BaseButton } from '@strapi/design-system/BaseButton';
|
||||
import { Stack } from '@strapi/design-system/Stack';
|
||||
import { Flex } from '@strapi/design-system/Flex';
|
||||
import { Text } from '@strapi/design-system/Text';
|
||||
import { pxToRem } from '@strapi/helper-plugin';
|
||||
import { getTrad } from '../../utils';
|
||||
|
||||
const IconButton = styled(BaseButton)`
|
||||
border: none;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
|
||||
const IconWrapper = styled.span`
|
||||
> svg {
|
||||
width: ${pxToRem(24)};
|
||||
height: ${pxToRem(24)};
|
||||
> circle {
|
||||
fill: ${({ theme }) => theme.colors.primary200}!important;
|
||||
fill: ${({ theme }) => theme.colors.primary200};
|
||||
}
|
||||
> path {
|
||||
fill: ${({ theme }) => theme.colors.primary600};
|
||||
@ -33,17 +28,21 @@ const ComponentInitializer = ({ isReadOnly, onClick }) => {
|
||||
|
||||
return (
|
||||
<Box
|
||||
as="button"
|
||||
background="neutral100"
|
||||
hasRadius
|
||||
borderColor="neutral200"
|
||||
disabled={isReadOnly}
|
||||
hasRadius
|
||||
onClick={onClick}
|
||||
paddingTop={9}
|
||||
paddingBottom={9}
|
||||
type="button"
|
||||
>
|
||||
<Stack size={2}>
|
||||
<Flex justifyContent="center" style={{ cursor: isReadOnly ? 'not-allowed' : 'inherit' }}>
|
||||
<IconButton disabled={isReadOnly} onClick={onClick}>
|
||||
<IconWrapper>
|
||||
<PlusCircle />
|
||||
</IconButton>
|
||||
</IconWrapper>
|
||||
</Flex>
|
||||
<Flex justifyContent="center">
|
||||
<Text textColor="primary600" small bold>
|
||||
|
||||
@ -26,12 +26,12 @@ const Category = ({ category, components, isOdd, isOpen, onAddComponent, onToggl
|
||||
<AccordionContent>
|
||||
<Box paddingTop={4} paddingBottom={4} paddingLeft={3} paddingRight={3}>
|
||||
<Grid>
|
||||
{components.map(({ componentUid, info: { label, icon, name } }) => {
|
||||
{components.map(({ componentUid, info: { displayName, icon } }) => {
|
||||
return (
|
||||
<ComponentCard
|
||||
key={componentUid}
|
||||
componentUid={componentUid}
|
||||
intlLabel={{ id: label || name, defaultMessage: label || name }}
|
||||
intlLabel={{ id: displayName, defaultMessage: displayName }}
|
||||
icon={icon}
|
||||
onClick={onAddComponent}
|
||||
/>
|
||||
|
||||
@ -18,7 +18,13 @@ import Image from '@strapi/icons/Picture';
|
||||
import Link from '@strapi/icons/Link';
|
||||
import Quote from '@strapi/icons/Quote';
|
||||
import More from '@strapi/icons/More';
|
||||
import { MainButtons, CustomIconButton, MoreButton, IconButtonGroupMargin } from './WysiwygStyles';
|
||||
import {
|
||||
MainButtons,
|
||||
CustomIconButton,
|
||||
MoreButton,
|
||||
IconButtonGroupMargin,
|
||||
CustomLinkIconButton,
|
||||
} from './WysiwygStyles';
|
||||
|
||||
const WysiwygNav = ({
|
||||
editorRef,
|
||||
@ -75,7 +81,7 @@ const WysiwygNav = ({
|
||||
/>
|
||||
</MainButtons>
|
||||
|
||||
<MoreButton disabled ref={buttonMoreRef} id="more" label="more" icon={<More />} />
|
||||
<MoreButton disabled ref={buttonMoreRef} id="more" label="More" icon={<More />} />
|
||||
</Flex>
|
||||
|
||||
<Button onClick={onTogglePreviewMode} variant="tertiary" size="L" id="preview">
|
||||
@ -135,7 +141,7 @@ const WysiwygNav = ({
|
||||
ref={buttonMoreRef}
|
||||
onClick={onTogglePopover}
|
||||
id="more"
|
||||
label="more"
|
||||
label="More"
|
||||
icon={<More />}
|
||||
/>
|
||||
{visiblePopover && (
|
||||
@ -179,7 +185,7 @@ const WysiwygNav = ({
|
||||
name="Image"
|
||||
icon={<Image />}
|
||||
/>
|
||||
<CustomIconButton
|
||||
<CustomLinkIconButton
|
||||
onClick={() => onActionClick('Link', editorRef, onTogglePopover)}
|
||||
id="Link"
|
||||
label="Link"
|
||||
|
||||
@ -21,6 +21,13 @@ export const CustomIconButton = styled(IconButton)`
|
||||
}
|
||||
`;
|
||||
|
||||
export const CustomLinkIconButton = styled(CustomIconButton)`
|
||||
svg {
|
||||
width: ${8 / 16}rem;
|
||||
height: ${8 / 16}rem;
|
||||
}
|
||||
`;
|
||||
|
||||
export const MainButtons = styled(IconButtonGroup)`
|
||||
margin-left: ${({ theme }) => theme.spaces[4]};
|
||||
`;
|
||||
|
||||
@ -73,7 +73,7 @@ const DynamicZoneList = ({ components }) => {
|
||||
</CustomFlex>
|
||||
<Box paddingTop={1}>
|
||||
<Typography fontSize={1} textColor="neutral600" fontWeight="bold">
|
||||
{get(componentLayouts, [componentUid, 'info', 'name'], '')}
|
||||
{get(componentLayouts, [componentUid, 'info', 'displayName'], '')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</CustomLink>
|
||||
|
||||
@ -45,7 +45,7 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
|
||||
const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(false);
|
||||
const { componentLayouts, initialData, modifiedData, metaToEdit, metaForm } = reducerState;
|
||||
const { formatMessage } = useIntl();
|
||||
const modelName = get(mainLayout, ['info', isContentTypeView ? 'displayName' : 'name'], '');
|
||||
const modelName = get(mainLayout, ['info', 'displayName'], '');
|
||||
const attributes = get(modifiedData, ['attributes'], {});
|
||||
|
||||
const entryTitleOptions = Object.keys(attributes).filter(attr => {
|
||||
|
||||
@ -3,9 +3,9 @@ import PropTypes from 'prop-types';
|
||||
import { Box } from '@strapi/design-system/Box';
|
||||
import { Flex } from '@strapi/design-system/Flex';
|
||||
import { Td, Tr } from '@strapi/design-system/Table';
|
||||
import { Text } from '@strapi/design-system/Text';
|
||||
import { Text, EllipsisText } from '@strapi/design-system/Text';
|
||||
import { IconButton } from '@strapi/design-system/IconButton';
|
||||
import { stopPropagation, onRowClick } from '@strapi/helper-plugin';
|
||||
import { stopPropagation, onRowClick, pxToRem } from '@strapi/helper-plugin';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
const RoleRow = ({ id, name, description, usersCount, icons }) => {
|
||||
@ -26,11 +26,11 @@ const RoleRow = ({ id, name, description, usersCount, icons }) => {
|
||||
fn: icons[1].onClick,
|
||||
})}
|
||||
>
|
||||
<Td>
|
||||
<Text textColor="neutral800">{name}</Text>
|
||||
<Td maxWidth={pxToRem(130)}>
|
||||
<EllipsisText textColor="neutral800">{name}</EllipsisText>
|
||||
</Td>
|
||||
<Td>
|
||||
<Text textColor="neutral800">{description}</Text>
|
||||
<Td maxWidth={pxToRem(250)}>
|
||||
<EllipsisText textColor="neutral800">{description}</EllipsisText>
|
||||
</Td>
|
||||
<Td>
|
||||
<Text textColor="neutral800">{usersCountText}</Text>
|
||||
|
||||
@ -331,7 +331,7 @@ const ListView = () => {
|
||||
onValueChange={handleSelectAllCheckbox}
|
||||
/>
|
||||
</Th>
|
||||
<Th>
|
||||
<Th width="20%">
|
||||
<TableLabel textColor="neutral600">
|
||||
{formatMessage({
|
||||
id: 'Settings.webhooks.form.name',
|
||||
@ -339,7 +339,7 @@ const ListView = () => {
|
||||
})}
|
||||
</TableLabel>
|
||||
</Th>
|
||||
<Th>
|
||||
<Th width="60%">
|
||||
<TableLabel textColor="neutral600">
|
||||
{formatMessage({
|
||||
id: 'Settings.webhooks.form.url',
|
||||
@ -347,7 +347,7 @@ const ListView = () => {
|
||||
})}
|
||||
</TableLabel>
|
||||
</Th>
|
||||
<Th width="30%">
|
||||
<Th width="20%">
|
||||
<TableLabel textColor="neutral600">
|
||||
{formatMessage({
|
||||
id: 'Settings.webhooks.list.th.status',
|
||||
|
||||
@ -14,7 +14,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -14,7 +14,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -16,7 +16,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -16,7 +16,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -16,7 +16,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -34,7 +34,7 @@ const productWithDP = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -14,7 +14,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -38,7 +38,7 @@ const models = {
|
||||
},
|
||||
},
|
||||
simpleCompo: {
|
||||
name: 'simple-compo',
|
||||
displayName: 'simple-compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
@ -46,7 +46,7 @@ const models = {
|
||||
},
|
||||
},
|
||||
otherCompo: {
|
||||
name: 'compo-with-other-compo',
|
||||
displayName: 'compo-with-other-compo',
|
||||
attributes: {
|
||||
compo: {
|
||||
type: 'component',
|
||||
|
||||
@ -23,7 +23,7 @@ const uploadImg = () => {
|
||||
|
||||
const components = {
|
||||
singleMedia: {
|
||||
name: 'single-media',
|
||||
displayName: 'single-media',
|
||||
attributes: {
|
||||
media: {
|
||||
type: 'media',
|
||||
@ -31,7 +31,7 @@ const components = {
|
||||
},
|
||||
},
|
||||
multipleMedia: {
|
||||
name: 'multiple-media',
|
||||
displayName: 'multiple-media',
|
||||
attributes: {
|
||||
media: {
|
||||
type: 'media',
|
||||
@ -40,7 +40,7 @@ const components = {
|
||||
},
|
||||
},
|
||||
withNested: {
|
||||
name: 'with-nested',
|
||||
displayName: 'with-nested',
|
||||
attributes: {
|
||||
singleMedia: {
|
||||
type: 'component',
|
||||
|
||||
@ -83,7 +83,7 @@ const ComponentBox = styled(Box)`
|
||||
function ComponentCard({ component, dzName, index, isActive, isInDevelopmentMode, onClick }) {
|
||||
const { modifiedData, removeComponentFromDynamicZone } = useDataManager();
|
||||
const {
|
||||
schema: { icon, name },
|
||||
schema: { icon, displayName },
|
||||
} = get(modifiedData, ['components', component], {
|
||||
schema: { icon: null },
|
||||
});
|
||||
@ -95,11 +95,16 @@ function ComponentCard({ component, dzName, index, isActive, isInDevelopmentMode
|
||||
|
||||
return (
|
||||
<button type="button" onClick={onClick}>
|
||||
<ComponentBox className={isActive ? 'active' : ''} borderRadius="borderRadius">
|
||||
<ComponentBox
|
||||
className={isActive ? 'active' : ''}
|
||||
borderRadius="borderRadius"
|
||||
paddingLeft={4}
|
||||
paddingRight={4}
|
||||
>
|
||||
<Stack size={1} style={{ justifyContent: 'center', alignItems: 'center' }}>
|
||||
<StyledFontAwesomeIcon icon={icon} />
|
||||
<Text small bold>
|
||||
{name}
|
||||
<Text small bold ellipsis style={{ width: `calc(${pxToRem(140)} - 32px)` }}>
|
||||
{displayName}
|
||||
</Text>
|
||||
</Stack>
|
||||
{isInDevelopmentMode && (
|
||||
|
||||
@ -44,7 +44,7 @@ const ContentTypeBuilderNav = () => {
|
||||
return (
|
||||
<React.Fragment key={section.name}>
|
||||
<SubNavSection
|
||||
label={formatMessage({ id: title, defaultMessage: title.defaultMessage })}
|
||||
label={formatMessage({ id: title, defaultMessage: title })}
|
||||
collapsable
|
||||
badgeLabel={section.links.length.toString()}
|
||||
>
|
||||
|
||||
@ -1152,7 +1152,9 @@ exports[`<ContentTypeBuilderNav /> renders and matches the snapshot 1`] = `
|
||||
</nav>
|
||||
<div
|
||||
class="c41 c42"
|
||||
/>
|
||||
>
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="c43"
|
||||
|
||||
@ -32,7 +32,9 @@ const makeApp = () => {
|
||||
<LanguageProvider messages={messages} localeNames={localeNames}>
|
||||
<Theme>
|
||||
<Router history={history}>
|
||||
<Layout sideNav={<ContentTypeBuilderNav />} />
|
||||
<Layout sideNav={<ContentTypeBuilderNav />}>
|
||||
<div />
|
||||
</Layout>
|
||||
</Router>
|
||||
</Theme>
|
||||
</LanguageProvider>
|
||||
|
||||
@ -43,7 +43,7 @@ const useContentTypeBuilderMenu = () => {
|
||||
componentsGroupedByCategory[category].map(compo => ({
|
||||
name: compo.uid,
|
||||
to: `/plugins/${pluginId}/component-categories/${category}/${compo.uid}`,
|
||||
title: compo.schema.name,
|
||||
title: compo.schema.displayName,
|
||||
})),
|
||||
obj => obj.title
|
||||
),
|
||||
|
||||
@ -545,13 +545,12 @@ const reducer = (state = initialState, action) =>
|
||||
}
|
||||
case actions.UPDATE_SCHEMA: {
|
||||
const {
|
||||
data: { name, collectionName, category, icon, kind },
|
||||
data: { displayName, category, icon, kind },
|
||||
schemaType,
|
||||
uid,
|
||||
} = action;
|
||||
|
||||
draftState.modifiedData[schemaType].schema.collectionName = collectionName;
|
||||
draftState.modifiedData[schemaType].schema.name = name;
|
||||
draftState.modifiedData[schemaType].schema.displayName = displayName;
|
||||
|
||||
if (action.schemaType === 'component') {
|
||||
draftState.modifiedData.component.category = category;
|
||||
|
||||
@ -715,8 +715,7 @@ describe('CTB | components | DataManagerProvider | reducer | basics actions ', (
|
||||
describe('UPDATE_SCHEMA', () => {
|
||||
it('Should update the modified data correctly if the schemaType is a content type', () => {
|
||||
const data = {
|
||||
name: 'test1',
|
||||
collectionName: 'newTest',
|
||||
displayName: 'test1',
|
||||
};
|
||||
|
||||
const state = {
|
||||
@ -726,8 +725,7 @@ describe('CTB | components | DataManagerProvider | reducer | basics actions ', (
|
||||
contentType: {
|
||||
uid: 'test',
|
||||
schema: {
|
||||
name: 'test',
|
||||
collectionName: 'test',
|
||||
displayName: 'test',
|
||||
attributes: [
|
||||
{
|
||||
name: 'something',
|
||||
@ -751,8 +749,7 @@ describe('CTB | components | DataManagerProvider | reducer | basics actions ', (
|
||||
contentType: {
|
||||
uid: 'test',
|
||||
schema: {
|
||||
name: 'test1',
|
||||
collectionName: 'newTest',
|
||||
displayName: 'test1',
|
||||
attributes: [
|
||||
{
|
||||
name: 'something',
|
||||
@ -769,8 +766,7 @@ describe('CTB | components | DataManagerProvider | reducer | basics actions ', (
|
||||
|
||||
it('Should update the modified data correctly if the schemaType is a component', () => {
|
||||
const data = {
|
||||
name: 'newTest',
|
||||
collectionName: 'newTest',
|
||||
displayName: 'newTest',
|
||||
category: 'test',
|
||||
icon: 'test',
|
||||
};
|
||||
@ -782,9 +778,8 @@ describe('CTB | components | DataManagerProvider | reducer | basics actions ', (
|
||||
uid: 'test',
|
||||
category: 'default',
|
||||
schema: {
|
||||
name: 'test',
|
||||
displayName: 'test',
|
||||
icon: 'book',
|
||||
collectionName: 'components_tests',
|
||||
attributes: [
|
||||
{
|
||||
name: 'something',
|
||||
@ -800,9 +795,8 @@ describe('CTB | components | DataManagerProvider | reducer | basics actions ', (
|
||||
uid: 'test',
|
||||
category: 'default',
|
||||
schema: {
|
||||
name: 'test',
|
||||
displayName: 'test',
|
||||
icon: 'book',
|
||||
collectionName: 'components_tests',
|
||||
attributes: [
|
||||
{
|
||||
name: 'something',
|
||||
@ -827,9 +821,8 @@ describe('CTB | components | DataManagerProvider | reducer | basics actions ', (
|
||||
uid: 'test',
|
||||
category: 'test',
|
||||
schema: {
|
||||
name: 'newTest',
|
||||
displayName: 'newTest',
|
||||
icon: 'test',
|
||||
collectionName: 'newTest',
|
||||
attributes: [
|
||||
{
|
||||
name: 'something',
|
||||
@ -845,9 +838,8 @@ describe('CTB | components | DataManagerProvider | reducer | basics actions ', (
|
||||
uid: 'test',
|
||||
category: 'test',
|
||||
schema: {
|
||||
name: 'newTest',
|
||||
displayName: 'newTest',
|
||||
icon: 'test',
|
||||
collectionName: 'newTest',
|
||||
attributes: [
|
||||
{
|
||||
name: 'something',
|
||||
|
||||
@ -7,7 +7,7 @@ import { CATEGORY_NAME_REGEX } from '../category';
|
||||
|
||||
const createComponentSchema = (usedComponentNames, reservedNames, category) => {
|
||||
const shape = {
|
||||
name: yup
|
||||
displayName: yup
|
||||
.string()
|
||||
.test({
|
||||
name: 'nameAlreadyUsed',
|
||||
|
||||
@ -7,11 +7,11 @@ const componentForm = {
|
||||
sectionTitle: null,
|
||||
items: [
|
||||
{
|
||||
name: `${prefix}name`,
|
||||
name: `${prefix}displayName`,
|
||||
type: 'text',
|
||||
intlLabel: {
|
||||
id: getTrad('modalForm.attribute.form.base.name'),
|
||||
defaultMessage: 'Name',
|
||||
id: getTrad('contentType.displayName.label'),
|
||||
defaultMessage: 'Display Name',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@ -221,10 +221,9 @@ const FormModal = () => {
|
||||
actionType,
|
||||
modalType,
|
||||
data: {
|
||||
name: data.schema.name,
|
||||
displayName: data.schema.displayName,
|
||||
category: data.category,
|
||||
icon: data.schema.icon,
|
||||
collectionName: data.schema.collectionName,
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -496,10 +495,11 @@ const FormModal = () => {
|
||||
|
||||
return;
|
||||
}
|
||||
} else if (isCreatingComponent) {
|
||||
// We are creating a component using the component modal from the left menu
|
||||
} else if (modalType === 'component') {
|
||||
if (isCreating) {
|
||||
// Create the component schema
|
||||
const componentUid = createComponentUid(modifiedData.name, modifiedData.category);
|
||||
const componentUid = createComponentUid(modifiedData.displayName, modifiedData.category);
|
||||
const { category, ...rest } = modifiedData;
|
||||
|
||||
createSchema(rest, 'component', componentUid, category);
|
||||
@ -652,7 +652,7 @@ const FormModal = () => {
|
||||
const { category, type, ...rest } = componentToCreate;
|
||||
// Create a the component temp UID
|
||||
// This could be refactored but I think it's more understandable to separate the logic
|
||||
const componentUid = createComponentUid(componentToCreate.name, category);
|
||||
const componentUid = createComponentUid(componentToCreate.displayName, category);
|
||||
// Create the component first and add it to the components data
|
||||
createSchema(
|
||||
// Component data
|
||||
@ -686,7 +686,10 @@ const FormModal = () => {
|
||||
if (isInFirstComponentStep) {
|
||||
if (isCreatingComponentFromAView) {
|
||||
const { category, type, ...rest } = modifiedData.componentToCreate;
|
||||
const componentUid = createComponentUid(modifiedData.componentToCreate.name, category);
|
||||
const componentUid = createComponentUid(
|
||||
modifiedData.componentToCreate.displayName,
|
||||
category
|
||||
);
|
||||
// Create the component first and add it to the components data
|
||||
createSchema(
|
||||
// Component data
|
||||
|
||||
@ -189,11 +189,11 @@ const reducer = (state = initialState, action) =>
|
||||
// This is run when the user has created a new component
|
||||
const componentToCreate = state.modifiedData.componentToCreate;
|
||||
const modifiedData = {
|
||||
name: componentToCreate.name,
|
||||
displayName: componentToCreate.displayName,
|
||||
type: 'component',
|
||||
repeatable: false,
|
||||
...action.options,
|
||||
component: createComponentUid(componentToCreate.name, componentToCreate.category),
|
||||
component: createComponentUid(componentToCreate.displayName, componentToCreate.category),
|
||||
};
|
||||
|
||||
const nextState = {
|
||||
|
||||
@ -362,7 +362,7 @@ describe('CTB | components | FormModal | reducer | actions', () => {
|
||||
createComponent: true,
|
||||
componentToCreate: {
|
||||
type: 'component',
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
icon: 'air-freshener',
|
||||
category: 'default',
|
||||
},
|
||||
@ -373,12 +373,12 @@ describe('CTB | components | FormModal | reducer | actions', () => {
|
||||
...initialState,
|
||||
componentToCreate: {
|
||||
type: 'component',
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
icon: 'air-freshener',
|
||||
category: 'default',
|
||||
},
|
||||
modifiedData: {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
type: 'component',
|
||||
repeatable: false,
|
||||
component: 'default.compo',
|
||||
|
||||
@ -36,7 +36,7 @@ const FormModalHeader = ({
|
||||
let headers = [];
|
||||
|
||||
const schema = modifiedData?.[forTarget]?.[targetUid] || modifiedData?.[forTarget] || null;
|
||||
let displayName = forTarget === 'contentType' ? schema?.schema.displayName : schema?.schema.name;
|
||||
let displayName = schema?.schema.displayName;
|
||||
|
||||
if (modalType === 'contentType') {
|
||||
icon = contentTypeKind;
|
||||
@ -78,7 +78,7 @@ const FormModalHeader = ({
|
||||
headers = [
|
||||
{
|
||||
label: displayName,
|
||||
info: { category: schema?.category || null, name: schema?.schema.name },
|
||||
info: { category: schema?.category || null, name: schema?.schema.displayName },
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ const SelectComponent = ({
|
||||
const compos = components.map(component => {
|
||||
return {
|
||||
uid: component.uid,
|
||||
label: component.schema.name,
|
||||
label: component.schema.displayName,
|
||||
categoryName,
|
||||
};
|
||||
});
|
||||
@ -61,7 +61,11 @@ const SelectComponent = ({
|
||||
|
||||
if (isCreatingComponentWhileAddingAField) {
|
||||
options = [
|
||||
{ uid: value, label: componentToCreate.name, categoryName: componentToCreate.category },
|
||||
{
|
||||
uid: value,
|
||||
label: componentToCreate.displayName,
|
||||
categoryName: componentToCreate.category,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -36,8 +36,8 @@ const SelectComponents = ({ dynamicZoneTarget, intlLabel, name, onChange, value
|
||||
const [categoryName, components] = current;
|
||||
const section = {
|
||||
label: categoryName,
|
||||
children: components.map(({ uid, schema: { name } }) => {
|
||||
return { label: name, value: uid };
|
||||
children: components.map(({ uid, schema: { displayName } }) => {
|
||||
return { label: displayName, value: uid };
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
@ -53,7 +53,6 @@ const ListView = () => {
|
||||
const contentTypeKind = get(modifiedData, [firstMainDataPath, 'schema', 'kind'], null);
|
||||
|
||||
const attributes = get(modifiedData, mainDataTypeAttributesPath, []);
|
||||
const currentDataName = get(initialData, [firstMainDataPath, 'schema', 'name'], '');
|
||||
const isFromPlugin = has(initialData, [firstMainDataPath, 'plugin']);
|
||||
const hasModelBeenModified = !isEqual(modifiedData, initialData);
|
||||
|
||||
@ -76,10 +75,7 @@ const ListView = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: fixme
|
||||
let label = isInContentTypeView
|
||||
? get(modifiedData, [firstMainDataPath, 'schema', 'displayName'], '')
|
||||
: get(modifiedData, [firstMainDataPath, 'schema', 'name'], '');
|
||||
let label = get(modifiedData, [firstMainDataPath, 'schema', 'displayName'], '');
|
||||
const kind = get(modifiedData, [firstMainDataPath, 'schema', 'kind'], '');
|
||||
|
||||
const isCreatingFirstContentType = match?.params.currentUID === 'create-content-type';
|
||||
@ -192,9 +188,6 @@ const ListView = () => {
|
||||
customRowComponent={props => <ListRow {...props} onClick={handleClickEditField} />}
|
||||
addComponentToDZ={handleClickAddComponentToDZ}
|
||||
targetUid={targetUid}
|
||||
dataType={forTarget}
|
||||
dataTypeName={currentDataName}
|
||||
mainTypeName={currentDataName}
|
||||
editTarget={forTarget}
|
||||
isMain
|
||||
/>
|
||||
|
||||
@ -47,6 +47,8 @@ exports[`<ListView /> renders and matches the snapshot 1`] = `
|
||||
}
|
||||
|
||||
.c63 {
|
||||
padding-right: 16px;
|
||||
padding-left: 16px;
|
||||
border-radius: borderRadius;
|
||||
}
|
||||
|
||||
@ -678,6 +680,10 @@ exports[`<ListView /> renders and matches the snapshot 1`] = `
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.33;
|
||||
color: #32324d;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.c33 {
|
||||
@ -3418,9 +3424,8 @@ exports[`<ListView /> renders and matches the snapshot 1`] = `
|
||||
</svg>
|
||||
<span
|
||||
class="c31 c67"
|
||||
>
|
||||
Compo
|
||||
</span>
|
||||
style="width: calc(8.75rem - 32px);"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="c68 c69"
|
||||
@ -3469,9 +3474,8 @@ exports[`<ListView /> renders and matches the snapshot 1`] = `
|
||||
</svg>
|
||||
<span
|
||||
class="c31 c67"
|
||||
>
|
||||
dish
|
||||
</span>
|
||||
style="width: calc(8.75rem - 32px);"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="c68 c69"
|
||||
@ -3520,9 +3524,8 @@ exports[`<ListView /> renders and matches the snapshot 1`] = `
|
||||
</svg>
|
||||
<span
|
||||
class="c31 c67"
|
||||
>
|
||||
openingtimes
|
||||
</span>
|
||||
style="width: calc(8.75rem - 32px);"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="c68 c69"
|
||||
@ -3571,9 +3574,8 @@ exports[`<ListView /> renders and matches the snapshot 1`] = `
|
||||
</svg>
|
||||
<span
|
||||
class="c31 c67"
|
||||
>
|
||||
restaurantservice
|
||||
</span>
|
||||
style="width: calc(8.75rem - 32px);"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="c68 c69"
|
||||
|
||||
@ -27,7 +27,7 @@ describe('Component validator', () => {
|
||||
components: [],
|
||||
component: {
|
||||
category: 'default',
|
||||
name: 'mycompo',
|
||||
displayName: 'mycompo',
|
||||
icon: 'american-sign-language-interpreting',
|
||||
attributes: {
|
||||
title: {
|
||||
@ -49,7 +49,7 @@ describe('Component validator', () => {
|
||||
components: [],
|
||||
component: {
|
||||
category: 'default',
|
||||
name: 'mycompo',
|
||||
displayName: 'mycompo',
|
||||
icon: 'american-sign-language-interpreting',
|
||||
attributes: {
|
||||
title: {
|
||||
@ -73,7 +73,7 @@ describe('Component validator', () => {
|
||||
components: [],
|
||||
component: {
|
||||
category: 'default',
|
||||
name: 'mycompo',
|
||||
displayName: 'mycompo',
|
||||
icon: 'american-sign-language-interpreting',
|
||||
attributes: {
|
||||
title: {
|
||||
|
||||
@ -44,7 +44,7 @@ describe('Content type validator', () => {
|
||||
test('Throws when reserved names are used', async () => {
|
||||
const data = {
|
||||
contentType: {
|
||||
name: 'test',
|
||||
displayName: 'test',
|
||||
attributes: {
|
||||
thisIsReserved: {
|
||||
type: 'string',
|
||||
@ -133,7 +133,7 @@ describe('Content type validator', () => {
|
||||
{
|
||||
uid: 'edit',
|
||||
icon: 'star',
|
||||
name: 'test',
|
||||
displayName: 'test',
|
||||
category: 'test',
|
||||
attributes: {
|
||||
title: {
|
||||
@ -145,7 +145,7 @@ describe('Content type validator', () => {
|
||||
{
|
||||
tmpUID: 'random',
|
||||
icon: 'star',
|
||||
name: 'test2',
|
||||
displayName: 'test2',
|
||||
category: 'test',
|
||||
attributes: {
|
||||
title: {
|
||||
|
||||
@ -16,10 +16,10 @@ const componentSchema = createSchema(VALID_TYPES, VALID_RELATIONS, {
|
||||
modelType: modelTypes.COMPONENT,
|
||||
})
|
||||
.shape({
|
||||
name: yup
|
||||
displayName: yup
|
||||
.string()
|
||||
.min(1)
|
||||
.required('name.required'),
|
||||
.required('displayName.required'),
|
||||
icon: yup
|
||||
.string()
|
||||
.nullable()
|
||||
|
||||
@ -1,11 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = () => ({
|
||||
// TODO: Implement
|
||||
getReservedNames() {
|
||||
return {
|
||||
models: [],
|
||||
attributes: [],
|
||||
models: ['boolean', 'date', 'date-time', 'dateTime', 'time', 'upload'],
|
||||
attributes: [
|
||||
'id',
|
||||
'created_at',
|
||||
'createdAt',
|
||||
'updated_at',
|
||||
'updatedAt',
|
||||
'created_by',
|
||||
'createdBy',
|
||||
'updated_by',
|
||||
'updatedBy',
|
||||
'published_at',
|
||||
'publishedAt',
|
||||
],
|
||||
};
|
||||
// strapi.db.getReservedNames();
|
||||
},
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const pluralize = require('pluralize');
|
||||
|
||||
const { formatAttributes, replaceTemporaryUIDs } = require('../utils/attributes');
|
||||
const createBuilder = require('./schema-builder');
|
||||
@ -20,7 +19,7 @@ const formatComponent = component => {
|
||||
apiId: modelName,
|
||||
schema: {
|
||||
icon: _.get(info, 'icon'),
|
||||
name: _.get(info, 'name') || _.upperFirst(pluralize(uid)),
|
||||
displayName: _.get(info, 'displayName'),
|
||||
description: _.get(info, 'description', ''),
|
||||
connection,
|
||||
collectionName,
|
||||
|
||||
@ -14,10 +14,10 @@ module.exports = function createComponentBuilder() {
|
||||
* Returns a uid from a component infos
|
||||
* @param {Object} options options
|
||||
* @param {string} options.category component category
|
||||
* @param {string} options.name component name
|
||||
* @param {string} options.displayName component displayName
|
||||
*/
|
||||
createComponentUID({ category, name }) {
|
||||
return `${nameToSlug(category)}.${nameToSlug(name)}`;
|
||||
createComponentUID({ category, displayName }) {
|
||||
return `${nameToSlug(category)}.${nameToSlug(displayName)}`;
|
||||
},
|
||||
|
||||
createNewComponentUIDMap(components) {
|
||||
@ -39,17 +39,17 @@ module.exports = function createComponentBuilder() {
|
||||
|
||||
const handler = createSchemaHandler({
|
||||
dir: path.join(strapi.dirs.components, nameToSlug(infos.category)),
|
||||
filename: `${nameToSlug(infos.name)}.json`,
|
||||
filename: `${nameToSlug(infos.displayName)}.json`,
|
||||
});
|
||||
|
||||
const collectionName = `components_${nameToCollectionName(
|
||||
infos.category
|
||||
)}_${nameToCollectionName(pluralize(infos.name))}`;
|
||||
)}_${nameToCollectionName(pluralize(infos.displayName))}`;
|
||||
|
||||
handler
|
||||
.setUID(uid)
|
||||
.set('collectionName', collectionName)
|
||||
.set(['info', 'name'], infos.name)
|
||||
.set(['info', 'displayName'], infos.displayName)
|
||||
.set(['info', 'icon'], infos.icon)
|
||||
.set(['info', 'description'], infos.description)
|
||||
.set('pluginOptions', infos.pluginOptions)
|
||||
@ -98,7 +98,7 @@ module.exports = function createComponentBuilder() {
|
||||
component
|
||||
.setUID(newUID)
|
||||
.setDir(newDir)
|
||||
.set(['info', 'name'], infos.name)
|
||||
.set(['info', 'displayName'], infos.displayName)
|
||||
.set(['info', 'icon'], infos.icon)
|
||||
.set(['info', 'description'], infos.description)
|
||||
.set('pluginOptions', infos.pluginOptions)
|
||||
|
||||
@ -38,7 +38,7 @@ describe('Content Type Builder - Components', () => {
|
||||
'component.category': ['category.required'],
|
||||
'component.icon': ['icon.required'],
|
||||
'component.attributes': ['attributes.required'],
|
||||
'component.name': ['name.required'],
|
||||
'component.displayName': ['displayName.required'],
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -51,7 +51,7 @@ describe('Content Type Builder - Components', () => {
|
||||
component: {
|
||||
category: 'default',
|
||||
icon: 'default',
|
||||
name: 'Some Component',
|
||||
displayName: 'Some Component',
|
||||
pluginOptions: {
|
||||
pluginName: {
|
||||
option: true,
|
||||
@ -92,7 +92,7 @@ describe('Content Type Builder - Components', () => {
|
||||
component: {
|
||||
category: 'default',
|
||||
icon: 'default',
|
||||
name: 'someComponent',
|
||||
displayName: 'someComponent',
|
||||
attributes: {},
|
||||
},
|
||||
},
|
||||
@ -121,7 +121,7 @@ describe('Content Type Builder - Components', () => {
|
||||
expect(el).toMatchObject({
|
||||
uid: expect.any(String),
|
||||
schema: expect.objectContaining({
|
||||
name: expect.any(String),
|
||||
displayName: expect.any(String),
|
||||
description: expect.any(String),
|
||||
collectionName: expect.any(String),
|
||||
attributes: expect.objectContaining({}),
|
||||
@ -157,7 +157,7 @@ describe('Content Type Builder - Components', () => {
|
||||
category: 'default',
|
||||
schema: {
|
||||
icon: 'default',
|
||||
name: 'Some Component',
|
||||
displayName: 'Some Component',
|
||||
description: '',
|
||||
collectionName: 'components_default_some_components',
|
||||
pluginOptions: {
|
||||
@ -215,7 +215,7 @@ describe('Content Type Builder - Components', () => {
|
||||
error: {
|
||||
'component.category': ['category.required'],
|
||||
'component.icon': ['icon.required'],
|
||||
'component.name': ['name.required'],
|
||||
'component.displayName': ['displayName.required'],
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -228,7 +228,7 @@ describe('Content Type Builder - Components', () => {
|
||||
component: {
|
||||
category: 'default',
|
||||
icon: 'default',
|
||||
name: 'New Component',
|
||||
displayName: 'New Component',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
@ -262,7 +262,7 @@ describe('Content Type Builder - Components', () => {
|
||||
data: {
|
||||
uid: 'default.some-component',
|
||||
schema: {
|
||||
name: 'New Component',
|
||||
displayName: 'New Component',
|
||||
pluginOptions: {
|
||||
pluginName: {
|
||||
option: false,
|
||||
|
||||
@ -127,7 +127,7 @@ program
|
||||
|
||||
// `$ strapi generate:template <directory>`
|
||||
program
|
||||
.command('generate:template <directory>')
|
||||
.command('templates:generate <directory>')
|
||||
.description('Generate template from Strapi project')
|
||||
.action(getLocalScript('generate-template'));
|
||||
|
||||
|
||||
@ -30,23 +30,20 @@ describe('generate:template command', () => {
|
||||
expect(fse.ensureDir).toHaveBeenCalledWith(templatePath);
|
||||
});
|
||||
|
||||
it.each(['api', 'components', 'config/functions/bootstrap.js', 'data'])(
|
||||
'copies folder %s',
|
||||
async item => {
|
||||
// Mock the empty directory arg
|
||||
fse.pathExists.mockReturnValueOnce(false);
|
||||
// Mock the folder exists
|
||||
fse.pathExists.mockReturnValue(true);
|
||||
const directory = '../test-dir';
|
||||
const rootPath = resolve(directory);
|
||||
const templatePath = join(rootPath, 'template');
|
||||
it.each(['src', 'data'])('copies folder %s', async item => {
|
||||
// Mock the empty directory arg
|
||||
fse.pathExists.mockReturnValueOnce(false);
|
||||
// Mock the folder exists
|
||||
fse.pathExists.mockReturnValue(true);
|
||||
const directory = '../test-dir';
|
||||
const rootPath = resolve(directory);
|
||||
const templatePath = join(rootPath, 'template');
|
||||
|
||||
await exportTemplate(directory);
|
||||
await exportTemplate(directory);
|
||||
|
||||
expect(fse.pathExists).toHaveBeenCalledWith(join(process.cwd(), item));
|
||||
expect(fse.copy).toHaveBeenCalledWith(join(process.cwd(), item), join(templatePath, item));
|
||||
}
|
||||
);
|
||||
expect(fse.pathExists).toHaveBeenCalledWith(join(process.cwd(), item));
|
||||
expect(fse.copy).toHaveBeenCalledWith(join(process.cwd(), item), join(templatePath, item));
|
||||
});
|
||||
|
||||
it('creates a json config file', async () => {
|
||||
fse.pathExists.mockReturnValue(false);
|
||||
|
||||
@ -6,7 +6,7 @@ const chalk = require('chalk');
|
||||
const inquirer = require('inquirer');
|
||||
|
||||
// All directories that a template could need
|
||||
const TEMPLATE_CONTENT = ['api', 'components', 'config/functions/bootstrap.js', 'data'];
|
||||
const TEMPLATE_CONTENT = ['src', 'data'];
|
||||
|
||||
/**
|
||||
*
|
||||
@ -54,10 +54,9 @@ async function writeTemplateJson(rootPath) {
|
||||
* @returns boolean
|
||||
*/
|
||||
async function templateConfigExists(rootPath) {
|
||||
const jsonConfig = await fse.pathExists(join(rootPath, 'template.json'));
|
||||
const functionConfig = await fse.pathExists(join(rootPath, 'template.js'));
|
||||
|
||||
return jsonConfig || functionConfig;
|
||||
const configExists = await fse.pathExists(join(rootPath, 'template.json'));
|
||||
console.log(`checking: ${join(rootPath, 'template.json')}. result ${configExists}`);
|
||||
return configExists;
|
||||
}
|
||||
|
||||
module.exports = async function generateTemplate(directory) {
|
||||
|
||||
@ -14,7 +14,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -14,7 +14,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -14,7 +14,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -14,7 +14,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -14,7 +14,7 @@ let data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -14,7 +14,7 @@ const data = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -28,7 +28,7 @@ const product = {
|
||||
};
|
||||
|
||||
const compo = {
|
||||
name: 'compo',
|
||||
displayName: 'compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -8,7 +8,7 @@ let strapi;
|
||||
let rq;
|
||||
|
||||
const component = {
|
||||
name: 'somecomponent',
|
||||
displayName: 'somecomponent',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
|
||||
@ -38,7 +38,7 @@ const models = {
|
||||
},
|
||||
},
|
||||
simpleCompo: {
|
||||
name: 'simple-compo',
|
||||
displayName: 'simple-compo',
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
@ -46,7 +46,7 @@ const models = {
|
||||
},
|
||||
},
|
||||
otherCompo: {
|
||||
name: 'compo-with-other-compo',
|
||||
displayName: 'compo-with-other-compo',
|
||||
attributes: {
|
||||
compo: {
|
||||
type: 'component',
|
||||
|
||||
@ -23,7 +23,7 @@ const uploadImg = () => {
|
||||
|
||||
const components = {
|
||||
singleMedia: {
|
||||
name: 'one-media',
|
||||
displayName: 'one-media',
|
||||
attributes: {
|
||||
media: {
|
||||
type: 'media',
|
||||
@ -31,7 +31,7 @@ const components = {
|
||||
},
|
||||
},
|
||||
multipleMedia: {
|
||||
name: 'many-media',
|
||||
displayName: 'many-media',
|
||||
attributes: {
|
||||
media: {
|
||||
type: 'media',
|
||||
@ -40,7 +40,7 @@ const components = {
|
||||
},
|
||||
},
|
||||
withNested: {
|
||||
name: 'with-nested',
|
||||
displayName: 'with-nested',
|
||||
attributes: {
|
||||
singleMedia: {
|
||||
type: 'component',
|
||||
|
||||
@ -97,7 +97,7 @@ const contentTypes = {
|
||||
|
||||
const components = {
|
||||
comp: {
|
||||
name: 'comp',
|
||||
displayName: 'comp',
|
||||
attributes: {
|
||||
countries: {
|
||||
type: 'relation',
|
||||
|
||||
@ -18,19 +18,7 @@ sentry.init({
|
||||
dsn: 'https://841d2b2c9b4d4b43a4cde92794cb705a@sentry.io/1762059',
|
||||
});
|
||||
|
||||
// TODO: to remove after the templates are updated for V4
|
||||
const warnTemplatesAreDisabled = cliArguments => {
|
||||
if (cliArguments.template) {
|
||||
console.log(
|
||||
'❌ Templates have been disabled for the Beta version of V4 and will be re-enabled soon!'
|
||||
);
|
||||
process.exit();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = (projectDirectory, cliArguments) => {
|
||||
warnTemplatesAreDisabled(cliArguments);
|
||||
|
||||
checkRequirements();
|
||||
|
||||
const rootPath = resolve(projectDirectory);
|
||||
|
||||
@ -1,94 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const fetch = require('node-fetch');
|
||||
const tar = require('tar');
|
||||
const parseGitUrl = require('git-url-parse');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const stopProcess = require('./stop-process');
|
||||
|
||||
function parseShorthand(template) {
|
||||
// Determine if it is comes from another owner
|
||||
if (template.includes('/')) {
|
||||
const [owner, partialName] = template.split('/');
|
||||
const name = `strapi-template-${partialName}`;
|
||||
return {
|
||||
name,
|
||||
fullName: `${owner}/${name}`,
|
||||
};
|
||||
}
|
||||
|
||||
const name = `strapi-template-${template}`;
|
||||
return {
|
||||
name,
|
||||
fullName: `strapi/${name}`,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} repo The full name of the repository.
|
||||
*/
|
||||
async function getDefaultBranch(repo) {
|
||||
const response = await fetch(`https://api.github.com/repos/${repo}`);
|
||||
if (!response.ok) {
|
||||
stopProcess(
|
||||
`Could not find the information for ${chalk.yellow(
|
||||
repo
|
||||
)}. Make sure it is publicly accessible on github.`
|
||||
);
|
||||
}
|
||||
|
||||
const { default_branch } = await response.json();
|
||||
return default_branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} template GitHub URL or shorthand to a template project.
|
||||
*/
|
||||
async function getRepoInfo(template) {
|
||||
const { name, full_name: fullName, ref, filepath, protocols, source } = parseGitUrl(template);
|
||||
|
||||
if (protocols.length === 0) {
|
||||
const repoInfo = parseShorthand(template);
|
||||
return {
|
||||
...repoInfo,
|
||||
branch: await getDefaultBranch(repoInfo.fullName),
|
||||
usedShorthand: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (source !== 'github.com') {
|
||||
stopProcess(`GitHub URL not found for: ${chalk.yellow(template)}.`);
|
||||
}
|
||||
|
||||
let branch;
|
||||
if (ref) {
|
||||
// Append the filepath to the parsed ref since a branch name could contain '/'
|
||||
// If so, the rest of the branch name will be considered 'filepath' by 'parseGitUrl'
|
||||
branch = filepath ? `${ref}/${filepath}` : ref;
|
||||
} else {
|
||||
branch = await getDefaultBranch(fullName);
|
||||
}
|
||||
|
||||
return { name, fullName, branch };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} repoInfo GitHub repository information (full name, branch...).
|
||||
* @param {string} tmpDir Path to the destination temporary directory.
|
||||
*/
|
||||
async function downloadGitHubRepo(repoInfo, tmpDir) {
|
||||
// Download from GitHub
|
||||
const { fullName, branch } = repoInfo;
|
||||
const codeload = `https://codeload.github.com/${fullName}/tar.gz/${branch}`;
|
||||
const response = await fetch(codeload);
|
||||
if (!response.ok) {
|
||||
throw Error(`Could not download the ${chalk.yellow(fullName)} repository.`);
|
||||
}
|
||||
|
||||
await new Promise(resolve => {
|
||||
response.body.pipe(tar.extract({ strip: 1, cwd: tmpDir })).on('close', resolve);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { getRepoInfo, downloadGitHubRepo };
|
||||
61
packages/generators/app/lib/utils/fetch-npm-template.js
Normal file
61
packages/generators/app/lib/utils/fetch-npm-template.js
Normal file
@ -0,0 +1,61 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const execa = require('execa');
|
||||
const chalk = require('chalk');
|
||||
|
||||
/**
|
||||
* Gets the package version on npm. Will fail if the package does not exist
|
||||
* @param {string} packageName - Name to look up on npm, may include a specific version
|
||||
* @returns {Object}
|
||||
*/
|
||||
async function getPackageInfo(packageName) {
|
||||
const { stdout } = await execa.shell(`npm view ${packageName} name version --silent`);
|
||||
// Use regex to parse name and version from CLI result
|
||||
const [name, version] = stdout.match(/(?<=')(.*?)(?=')/gm);
|
||||
return { name, version };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} template - The name of the template as provided by the user.
|
||||
* @returns {Object} - The full name of the template package's name on npm
|
||||
*/
|
||||
async function getTemplatePackageInfo(template) {
|
||||
// Check if template is a shorthand
|
||||
try {
|
||||
const longhand = `@strapi/template-${template}`;
|
||||
const packageInfo = await getPackageInfo(longhand);
|
||||
// Hasn't crashed so it is indeed a shorthand
|
||||
return packageInfo;
|
||||
} catch (error) {
|
||||
// Ignore error, we now know it's not a shorthand
|
||||
}
|
||||
// Fetch version of the non-shorthand package
|
||||
try {
|
||||
return getPackageInfo(template);
|
||||
} catch (error) {
|
||||
throw new Error(`Could not find package ${chalk.green('template.json')} on npm`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} packageInfo - Template's npm package information
|
||||
* @param {string} packageInfo.name
|
||||
* @param {string} packageInfo.version
|
||||
* @param {string} parentDir - Path inside of which we install the template.
|
||||
*/
|
||||
async function downloadNpmTemplate({ name, version }, parentDir) {
|
||||
// Download from npm
|
||||
await execa.shell(`npm install ${name}@${version} --no-save --silent`, {
|
||||
cwd: parentDir,
|
||||
});
|
||||
|
||||
// Return the path of the actual template
|
||||
const exactTemplatePath = require.resolve(path.join('node_modules', name), {
|
||||
paths: [parentDir],
|
||||
});
|
||||
// const exactTemplatePath = path.resolve(parentDir, 'node_modules', name);
|
||||
return exactTemplatePath;
|
||||
}
|
||||
|
||||
module.exports = { getTemplatePackageInfo, downloadNpmTemplate };
|
||||
@ -3,99 +3,83 @@
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const fse = require('fs-extra');
|
||||
const _ = require('lodash');
|
||||
const _ = require('lodash/fp');
|
||||
const chalk = require('chalk');
|
||||
|
||||
const { getRepoInfo, downloadGitHubRepo } = require('./fetch-github');
|
||||
const { getTemplatePackageInfo, downloadNpmTemplate } = require('./fetch-npm-template');
|
||||
|
||||
// Specify all the files and directories a template can have
|
||||
const allowChildren = '*';
|
||||
const allowFile = Symbol();
|
||||
const allowChildren = Symbol();
|
||||
const allowedTemplateContents = {
|
||||
'README.md': true,
|
||||
'.env.example': true,
|
||||
src: {
|
||||
api: allowChildren,
|
||||
components: allowChildren,
|
||||
plugins: allowChildren,
|
||||
},
|
||||
config: {
|
||||
functions: allowChildren,
|
||||
},
|
||||
'README.md': allowFile,
|
||||
'.env.example': allowFile,
|
||||
'package.json': allowFile,
|
||||
src: allowChildren,
|
||||
data: allowChildren,
|
||||
database: allowChildren,
|
||||
public: allowChildren,
|
||||
scripts: allowChildren,
|
||||
};
|
||||
|
||||
/**
|
||||
* merge template with new project being created
|
||||
* Merge template with new project being created
|
||||
* @param {string} scope project creation params
|
||||
* @param {string} rootPath project path
|
||||
*/
|
||||
module.exports = async function mergeTemplate(scope, rootPath) {
|
||||
// Parse template info
|
||||
const repoInfo = await getRepoInfo(scope.template);
|
||||
const { fullName } = repoInfo;
|
||||
console.log(`Installing ${chalk.yellow(fullName)} template.`);
|
||||
let templatePath;
|
||||
let templateParentPath;
|
||||
let templatePackageInfo = {};
|
||||
const isLocalTemplate = ['./', '../', '/'].some(filePrefix =>
|
||||
scope.template.startsWith(filePrefix)
|
||||
);
|
||||
|
||||
// Download template repository to a temporary directory
|
||||
const templatePath = await fse.mkdtemp(path.join(os.tmpdir(), 'strapi-'));
|
||||
await downloadGitHubRepo(repoInfo, templatePath);
|
||||
if (isLocalTemplate) {
|
||||
// Template is a local directory
|
||||
console.log('Installing local template.');
|
||||
templatePath = path.resolve(rootPath, '..', scope.template);
|
||||
} else {
|
||||
// Template should be an npm package. Fetch template info
|
||||
templatePackageInfo = await getTemplatePackageInfo(scope.template);
|
||||
console.log(`Installing ${chalk.yellow(templatePackageInfo.name)} template.`);
|
||||
|
||||
// Download template repository to a temporary directory
|
||||
templateParentPath = await fse.mkdtemp(path.join(os.tmpdir(), 'strapi-'));
|
||||
templatePath = await downloadNpmTemplate(templatePackageInfo, templateParentPath);
|
||||
}
|
||||
|
||||
// Make sure the downloaded template matches the required format
|
||||
const { templateConfig } = await checkTemplateRootStructure(templatePath, scope);
|
||||
const templateConfig = await checkTemplateRootStructure(templatePath, scope);
|
||||
await checkTemplateContentsStructure(path.resolve(templatePath, 'template'));
|
||||
|
||||
// Merge contents of the template in the project
|
||||
const fullTemplateUrl = `https://github.com/${fullName}`;
|
||||
await mergePackageJSON(rootPath, templateConfig, fullTemplateUrl);
|
||||
await mergePackageJSON({ rootPath, templateConfig, templatePackageInfo });
|
||||
await mergeFilesAndDirectories(rootPath, templatePath);
|
||||
|
||||
// Delete the downloaded template repo
|
||||
await fse.remove(templatePath);
|
||||
// Delete the template directory if it was downloaded
|
||||
if (!isLocalTemplate) {
|
||||
await fse.remove(templateParentPath);
|
||||
}
|
||||
};
|
||||
|
||||
// Make sure the template has the required top-level structure
|
||||
async function checkTemplateRootStructure(templatePath, scope) {
|
||||
// Make sure the root of the repo has a template.json or a template.js file
|
||||
/**
|
||||
* Make sure the template has the required top-level structure
|
||||
* @param {string} templatePath - Path of the locally downloaded template
|
||||
* @returns {Object} - The template config object
|
||||
*/
|
||||
async function checkTemplateRootStructure(templatePath) {
|
||||
// Make sure the root of the repo has a template.json file
|
||||
const templateJsonPath = path.join(templatePath, 'template.json');
|
||||
const templateFunctionPath = path.join(templatePath, 'template.js');
|
||||
|
||||
// Store the template config, whether it comes from a JSON or a function
|
||||
let templateConfig = {};
|
||||
|
||||
const hasJsonConfig = fse.existsSync(templateJsonPath);
|
||||
if (hasJsonConfig) {
|
||||
const jsonStat = await fse.stat(templateJsonPath);
|
||||
if (!jsonStat.isFile()) {
|
||||
throw new Error(`A template's ${chalk.green('template.json')} must be a file`);
|
||||
}
|
||||
templateConfig = require(templateJsonPath);
|
||||
const templateJsonExists = await fse.exists(templateJsonPath);
|
||||
if (!templateJsonExists) {
|
||||
throw new Error(`A template must have a ${chalk.green('template.json')} root file`);
|
||||
}
|
||||
const templateJsonStat = await fse.stat(templateJsonPath);
|
||||
if (!templateJsonStat.isFile()) {
|
||||
throw new Error(`A template's ${chalk.green('template.json')} must be a file`);
|
||||
}
|
||||
|
||||
const hasFunctionConfig = fse.existsSync(templateFunctionPath);
|
||||
if (hasFunctionConfig) {
|
||||
const functionStat = await fse.stat(templateFunctionPath);
|
||||
if (!functionStat.isFile()) {
|
||||
throw new Error(`A template's ${chalk.green('template.js')} must be a file`);
|
||||
}
|
||||
// Get the config by passing the scope to the function
|
||||
templateConfig = require(templateFunctionPath)(scope);
|
||||
}
|
||||
|
||||
// Make sure there's exactly one template config file
|
||||
if (!hasJsonConfig && !hasFunctionConfig) {
|
||||
throw new Error(
|
||||
`A template must have either a ${chalk.green('template.json')} or a ${chalk.green(
|
||||
'template.js'
|
||||
)} root file`
|
||||
);
|
||||
} else if (hasJsonConfig && hasFunctionConfig) {
|
||||
throw new Error(
|
||||
`A template cannot have both ${chalk.green('template.json')} and ${chalk.green(
|
||||
'template.js'
|
||||
)} root files`
|
||||
);
|
||||
}
|
||||
const templateConfig = require(templateJsonPath);
|
||||
|
||||
// Make sure the root of the repo has a template folder
|
||||
const templateDirPath = path.join(templatePath, 'template');
|
||||
@ -112,21 +96,24 @@ async function checkTemplateRootStructure(templatePath, scope) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return { templateConfig };
|
||||
return templateConfig;
|
||||
}
|
||||
|
||||
// Traverse template tree to make sure each file and folder is allowed
|
||||
/**
|
||||
* Traverse template tree to make sure each file and folder is allowed
|
||||
* @param {string} templateContentsPath
|
||||
*/
|
||||
async function checkTemplateContentsStructure(templateContentsPath) {
|
||||
// Recursively check if each item in a directory is allowed
|
||||
const checkPathContents = (pathToCheck, parents) => {
|
||||
const contents = fse.readdirSync(pathToCheck);
|
||||
contents.forEach(item => {
|
||||
const checkPathContents = async (pathToCheck, parents) => {
|
||||
const contents = await fse.readdir(pathToCheck);
|
||||
for (const item of contents) {
|
||||
const nextParents = [...parents, item];
|
||||
const matchingTreeValue = _.get(allowedTemplateContents, nextParents);
|
||||
const matchingTreeValue = _.get(nextParents, allowedTemplateContents);
|
||||
|
||||
// Treat files and directories separately
|
||||
const itemPath = path.resolve(pathToCheck, item);
|
||||
const isDirectory = fse.statSync(itemPath).isDirectory();
|
||||
const isDirectory = (await fse.stat(itemPath)).isDirectory();
|
||||
|
||||
if (matchingTreeValue === undefined) {
|
||||
// Unknown paths are forbidden
|
||||
@ -135,7 +122,7 @@ async function checkTemplateContentsStructure(templateContentsPath) {
|
||||
);
|
||||
}
|
||||
|
||||
if (matchingTreeValue === true) {
|
||||
if (matchingTreeValue === allowFile) {
|
||||
if (!isDirectory) {
|
||||
// All good, the file is allowed
|
||||
return;
|
||||
@ -153,20 +140,28 @@ async function checkTemplateContentsStructure(templateContentsPath) {
|
||||
return;
|
||||
}
|
||||
// Check if the contents of the directory are allowed
|
||||
checkPathContents(itemPath, nextParents);
|
||||
await checkPathContents(itemPath, nextParents);
|
||||
} else {
|
||||
throw Error(
|
||||
`Illegal template structure, unknow file ${chalk.green(nextParents.join('/'))}`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
checkPathContents(templateContentsPath, []);
|
||||
await checkPathContents(templateContentsPath, []);
|
||||
}
|
||||
|
||||
// Merge the template's template.json into the Strapi project's package.json
|
||||
async function mergePackageJSON(rootPath, templateConfig, templateUrl) {
|
||||
/**
|
||||
* Merge the template's template.json into the Strapi project's package.json
|
||||
* @param {Object} config
|
||||
* @param {string} config.rootPath
|
||||
* @param {string} config.templateConfig
|
||||
* @param {Object} config.templatePackageInfo - Info about the template's package on npm
|
||||
* @param {Object} config.templatePackageInfo.name - The name of the template's package on npm
|
||||
* @param {Object} config.templatePackageInfo.version - The name of the template's package on npm
|
||||
*/
|
||||
async function mergePackageJSON({ rootPath, templateConfig, templatePackageInfo }) {
|
||||
// Import the package.json as an object
|
||||
const packageJSON = require(path.resolve(rootPath, 'package.json'));
|
||||
|
||||
@ -181,10 +176,12 @@ async function mergePackageJSON(rootPath, templateConfig, templateUrl) {
|
||||
}
|
||||
|
||||
// Use lodash to deeply merge them
|
||||
const mergedConfig = _.merge(packageJSON, templateConfig.package);
|
||||
const mergedConfig = _.merge(templateConfig.package, packageJSON);
|
||||
|
||||
// Add starter info to package.json
|
||||
_.set(mergedConfig, 'strapi.template', templateUrl);
|
||||
// Add template info to package.json
|
||||
if (templatePackageInfo.name) {
|
||||
_.set('strapi.template', templatePackageInfo.name, mergedConfig);
|
||||
}
|
||||
|
||||
// Save the merged config as the new package.json
|
||||
const packageJSONPath = path.join(rootPath, 'package.json');
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
"chalk": "^4.1.1",
|
||||
"execa": "^1.0.0",
|
||||
"fs-extra": "^9.1.0",
|
||||
"git-url-parse": "^11.4.4",
|
||||
"inquirer": "^6.3.1",
|
||||
"lodash": "4.17.21",
|
||||
"node-fetch": "^2.6.1",
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* `{{ name }}` middleware.
|
||||
*/
|
||||
|
||||
module.exports = async (config, { strapi }) => {
|
||||
module.exports = (config, { strapi }) => {
|
||||
// Add your own logic here.
|
||||
return async (ctx, next) => {
|
||||
strapi.log.info('In {{ name }} middleware.');
|
||||
|
||||
@ -29,7 +29,7 @@ const rgbColorComponent = {
|
||||
type: 'integer',
|
||||
},
|
||||
},
|
||||
name: 'rgbColor',
|
||||
displayName: 'rgbColor',
|
||||
};
|
||||
|
||||
const documentModel = {
|
||||
|
||||
@ -11883,7 +11883,7 @@ git-url-parse@11.4.4:
|
||||
dependencies:
|
||||
git-up "^4.0.0"
|
||||
|
||||
git-url-parse@^11.1.2, git-url-parse@^11.4.4:
|
||||
git-url-parse@^11.1.2:
|
||||
version "11.6.0"
|
||||
resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-11.6.0.tgz#c634b8de7faa66498a2b88932df31702c67df605"
|
||||
integrity sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user