feat(content-releases): added a purchase content releases page (#19455)

* feat(content-releases): first draft implementation PurchaseContentReleases

* feat(content-releases): remove useless custom icon

* feat(content-releases): fix typo and remove useless destructuring

* feat(content-releases): add Icon as children and ignore the ts error

* feat(content-releases): use badgeContent to show lock icon

* feat(content-releases): change the typescript comment to avoid type errors
This commit is contained in:
Simone 2024-02-13 10:14:53 +01:00 committed by GitHub
parent aa7c7ec672
commit 9bfbb6d4ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 98 additions and 14 deletions

View File

@ -1,6 +1,6 @@
import * as React from 'react';
import { Box, Divider, Flex, FocusTrap, Typography } from '@strapi/design-system';
import { Box, Divider, Flex, FocusTrap, Icon, Typography } from '@strapi/design-system';
import {
MainNav,
NavBrand,
@ -12,7 +12,7 @@ import {
NavUser,
} from '@strapi/design-system/v2';
import { useAppInfo, usePersistentState, useTracking } from '@strapi/helper-plugin';
import { Exit, Write } from '@strapi/icons';
import { Exit, Write, Lock } from '@strapi/icons';
import { useIntl } from 'react-intl';
import { NavLink as RouterNavLink, useLocation } from 'react-router-dom';
import styled from 'styled-components';
@ -49,6 +49,13 @@ const LinkUser = styled(RouterNavLink)<{ logout?: boolean }>`
}
`;
const NavLinkWrapper = styled(Box)`
div:nth-child(2) {
/* remove badge background color */
background: transparent;
}
`;
interface LeftMenuProps extends Pick<Menu, 'generalSectionLinks' | 'pluginsSectionLinks'> {}
const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }: LeftMenuProps) => {
@ -134,19 +141,24 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }: LeftMenuProps) =
})}
>
{pluginsSectionLinks.map((link) => {
const Icon = link.icon;
const LinkIcon = link.icon;
return (
<NavLink
as={RouterNavLink}
// @ts-expect-error the props from the passed as prop are not inferred // joined together
to={link.to}
key={link.to}
icon={<Icon />}
onClick={() => handleClickOnLink(link.to)}
>
{formatMessage(link.intlLabel)}
</NavLink>
<NavLinkWrapper key={link.to}>
<NavLink
as={RouterNavLink}
to={link.to}
icon={<LinkIcon />}
onClick={() => handleClickOnLink(link.to)}
// @ts-expect-error: badgeContent in the DS accept only strings
badgeContent={
link?.lockIcon ? (
<Icon width={`${15 / 16}rem`} height={`${15 / 16}rem`} as={Lock} />
) : undefined
}
>
{formatMessage(link.intlLabel)}
</NavLink>
</NavLinkWrapper>
);
})}
</NavSection>

View File

@ -16,6 +16,7 @@ declare global {
};
flags: {
nps?: boolean;
promoteEE?: boolean;
};
projectType: 'Community' | 'Enterprise';
telemetryDisabled: boolean;

View File

@ -42,6 +42,23 @@ const admin: Plugin.Config.AdminInput = {
name: `${pluginId}-link`,
Component: CMReleasesContainer,
});
} else if (
!window.strapi.features.isEnabled('cms-content-releases') &&
window.strapi?.flags?.promoteEE
) {
app.addMenuLink({
to: `/plugins/purchase-content-releases`,
icon: PaperPlane,
intlLabel: {
id: `${pluginId}.plugin.name`,
defaultMessage: 'Releases',
},
async Component() {
const { PurchaseContentReleases } = await import('./pages/PurchaseContentReleases');
return PurchaseContentReleases;
},
lockIcon: true,
});
}
},
async registerTrads({ locales }: { locales: string[] }) {

View File

@ -0,0 +1,51 @@
import { Box, Layout, Main, HeaderLayout, EmptyStateLayout } from '@strapi/design-system';
import { LinkButton } from '@strapi/design-system/v2';
import { ExternalLink, EmptyPermissions } from '@strapi/icons';
import { useIntl } from 'react-intl';
const PurchaseContentReleases = () => {
const { formatMessage } = useIntl();
return (
<Layout>
<Main>
<HeaderLayout
title={formatMessage({
id: 'content-releases.pages.Releases.title',
defaultMessage: 'Releases',
})}
subtitle={formatMessage({
id: 'content-releases.pages.PurchaseRelease.subTitle',
defaultMessage: 'Manage content updates and releases.',
})}
/>
<Box paddingLeft={10} paddingRight={10}>
<EmptyStateLayout
icon={<EmptyPermissions width="10rem" />}
content={formatMessage({
id: 'content-releases.pages.PurchaseRelease.not-available',
defaultMessage:
'Releases is only available as part of the Enterprise Edition. Upgrade to create and manage releases.',
})}
action={
<LinkButton
variant="default"
endIcon={<ExternalLink />}
href="https://strapi.io/pricing-self-hosted?utm_campaign=Growth-Experiments&utm_source=In-Product&utm_medium=Releases"
isExternal
target="_blank"
>
{formatMessage({
id: 'global.learn-more',
defaultMessage: 'Learn more',
})}
</LinkButton>
}
/>
</Box>
</Main>
</Layout>
);
};
export { PurchaseContentReleases };

View File

@ -20,6 +20,8 @@
"pages.Releases.max-limit-reached.title": "You have reached the {number} pending {number, plural, one {release} other {releases}} limit.",
"pages.Releases.max-limit-reached.message": "Upgrade to manage an unlimited number of releases.",
"pages.Releases.max-limit-reached.action": "Explore plans",
"pages.PurchaseRelease.subTitle": "Manage content updates and releases.",
"pages.PurchaseRelease.not-available": "Releases is only available as part of the Enterprise Edition. Upgrade to create and manage releases.",
"header.actions.add-release": "New Release",
"header.actions.refresh": "Refresh",
"header.actions.publish": "Publish",

View File

@ -23,6 +23,7 @@ interface MenuItem extends Pick<LinkProps, 'to'> {
notificationsCount?: number;
Component?: ComponentModule;
exact?: boolean;
lockIcon?: boolean;
}
/* -------------------------------------------------------------------------------------------------