mirror of
https://github.com/strapi/strapi.git
synced 2025-11-01 18:33:55 +00:00
Merge pull request #15738 from strapi/chore/ee-seats-fe-review
This commit is contained in:
commit
0a42f13814
@ -9,7 +9,6 @@ import {
|
||||
} from '@strapi/helper-plugin';
|
||||
import { useQueries } from 'react-query';
|
||||
import get from 'lodash/get';
|
||||
import useLicenseLimitInfos from 'ee_else_ce/hooks/useLicenseLimitInfos';
|
||||
import packageJSON from '../../../../package.json';
|
||||
import { useConfigurations } from '../../hooks';
|
||||
import PluginsInitializer from '../PluginsInitializer';
|
||||
@ -73,10 +72,6 @@ const AuthenticatedApp = () => {
|
||||
}
|
||||
}, [userRoles, appInfos]);
|
||||
|
||||
// This hook fetches license allowances in 'ee' mode and stores data in redux for global access.
|
||||
// It does nothing in 'ce'.
|
||||
useLicenseLimitInfos();
|
||||
|
||||
useEffect(() => {
|
||||
const getUserId = async () => {
|
||||
const userId = await hashAdminUserEmail(userInfo);
|
||||
|
||||
@ -52,11 +52,6 @@ jest.mock('../../RBACProvider', () => {
|
||||
return Compo;
|
||||
});
|
||||
|
||||
jest.mock('ee_else_ce/hooks/useLicenseLimitInfos', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn(),
|
||||
}));
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
|
||||
@ -10,5 +10,5 @@ export { default as usePermissionsDataManager } from './usePermissionsDataManage
|
||||
export { default as useReleaseNotification } from './useReleaseNotification';
|
||||
export { default as useThemeToggle } from './useThemeToggle';
|
||||
export { default as useRegenerate } from './useRegenerate';
|
||||
export { default as useLicenseLimitInfos } from './useLicenseLimitInfos';
|
||||
export { default as useLicenseLimit } from './useLicenseLimits';
|
||||
export { default as useLicenseLimitNotification } from './useLicenseLimitNotification';
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
const useLicenseLimitInfos = () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
export default useLicenseLimitInfos;
|
||||
@ -0,0 +1,3 @@
|
||||
const useLicenseLimits = () => {};
|
||||
|
||||
export default useLicenseLimits;
|
||||
@ -101,13 +101,11 @@ const ListPage = () => {
|
||||
const isLoading =
|
||||
(status !== 'success' && status !== 'error') || (status === 'success' && isFetching);
|
||||
|
||||
const createAction = canCreate ? <CreateAction onClick={handleToggle} /> : undefined;
|
||||
|
||||
return (
|
||||
<Main aria-busy={isLoading}>
|
||||
<SettingsPageTitle name="Users" />
|
||||
<HeaderLayout
|
||||
primaryAction={createAction}
|
||||
primaryAction={canCreate && <CreateAction onClick={handleToggle} />}
|
||||
title={title}
|
||||
subtitle={formatMessage({
|
||||
id: 'Settings.permissions.users.listview.header.subtitle',
|
||||
|
||||
@ -114,8 +114,9 @@
|
||||
"Settings.application.get-help": "Get help",
|
||||
"Settings.application.link-pricing": "See all pricing plans",
|
||||
"Settings.application.link-upgrade": "Upgrade your admin panel",
|
||||
"Settings.application.ee.link-contact-sales": "Contact sales",
|
||||
"Settings.application.ee.link-add-seats": "Add seats",
|
||||
"Settings.application.ee.admin-seats.count": "{currentUserCount}/{permittedSeats}",
|
||||
"Settings.application.ee.admin-seats.at-limit-tooltip": "At limit: add seats to invite more users",
|
||||
"Settings.application.ee.admin-seats.add-seats": "{isHostedOnStrapiCloud, select, true {Add seats} false {Contact sales}}",
|
||||
"Settings.application.node-version": "node version",
|
||||
"Settings.application.strapi-version": "strapi version",
|
||||
"Settings.application.strapiVersion": "strapi version",
|
||||
@ -845,10 +846,8 @@
|
||||
"notification.version.update.message": "A new version of Strapi is available!",
|
||||
"notification.warning.title": "Warning:",
|
||||
"notification.warning.404": "404 - Not found",
|
||||
"notification.ee.warning.over-seat-limit": "Add seats to re-enable Users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app.",
|
||||
"notification.ee.warning.over-seat-limit.title": "Over seat limit ({currentUserCount}/{permittedSeats})",
|
||||
"notification.ee.warning.at-seat-limit": "Add seats to invite more Users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app.",
|
||||
"notification.ee.warning.at-seat-limit.title": "At seat limit ({currentUserCount}/{permittedSeats})",
|
||||
"notification.ee.warning.over-.message": "Add seats to {licenseLimitStatus, select, OVER_LIMIT {invite} AT_LIMIT {re-enable}} Users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app.",
|
||||
"notification.ee.warning.at-seat-limit.title": "{licenseLimitStatus, select, OVER_LIMIT {Over} AT_LIMIT {At}} seat limit ({currentUserCount}/{permittedSeats})",
|
||||
"or": "OR",
|
||||
"request.error.model.unknown": "This model doesn't exist",
|
||||
"skipToContent": "Skip to content",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export { default as useAuthProviders } from './useAuthProviders';
|
||||
export { default as useLicenseLimitNotification } from './useLicenseLimitNotification';
|
||||
export { default as useLicenseLimitInfos } from './useLicenseLimitInfos';
|
||||
export { default as useLicenseLimits } from './useLicenseLimits';
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { useFetchClient } from '@strapi/helper-plugin';
|
||||
import { useQuery } from 'react-query';
|
||||
import { produce } from 'immer';
|
||||
|
||||
import { useInjectReducer } from '../../../../admin/src/hooks/useInjectReducer';
|
||||
|
||||
const NS = 'StrapiAdmin/ee_license-info';
|
||||
const ACTION_EE_LICENSE_INFO_SET_DATA = 'StrapiAdmin/EE_LICENSE_INFO_GET_DATA';
|
||||
|
||||
const initalState = {
|
||||
serverState: {
|
||||
currentUserCount: null,
|
||||
permittedSeats: null,
|
||||
shouldNotify: false,
|
||||
licenseLimitStatus: null,
|
||||
isHostedOnStrapiCloud: false,
|
||||
licenseType: null,
|
||||
},
|
||||
};
|
||||
|
||||
const reducer = (state = initalState, action) =>
|
||||
/* eslint-disable-next-line consistent-return */
|
||||
produce(state, (draft) => {
|
||||
switch (action.type) {
|
||||
case ACTION_EE_LICENSE_INFO_SET_DATA: {
|
||||
draft.serverState = action.payload;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return draft;
|
||||
}
|
||||
});
|
||||
|
||||
const actionSetData = (payload) => {
|
||||
return {
|
||||
type: ACTION_EE_LICENSE_INFO_SET_DATA,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
const useLicenseLimitInfos = () => {
|
||||
const instance = useFetchClient();
|
||||
const fetchLicenseLimitInfo = async () => {
|
||||
const {
|
||||
data: { data },
|
||||
} = await instance.get('/admin/license-limit-information');
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const { data, status } = useQuery('license-limit-info', fetchLicenseLimitInfo);
|
||||
|
||||
const state = useSelector((state) => state?.[NS] ?? initalState);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useInjectReducer(NS, reducer);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'success' && data) {
|
||||
dispatch(actionSetData(data));
|
||||
}
|
||||
}, [data, status, dispatch]);
|
||||
|
||||
return state.serverState;
|
||||
};
|
||||
|
||||
export default useLicenseLimitInfos;
|
||||
@ -4,110 +4,76 @@
|
||||
*
|
||||
*/
|
||||
import { useEffect } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useLocation } from 'react-router';
|
||||
import { useNotification } from '@strapi/helper-plugin';
|
||||
import useLicenseLimitInfos from '../useLicenseLimitInfos';
|
||||
import useLicenseLimits from '../useLicenseLimits';
|
||||
|
||||
const notificationBody = (
|
||||
currentUserCount,
|
||||
permittedSeats,
|
||||
licenseLimitStatus,
|
||||
isHostedOnStrapiCloud
|
||||
) => {
|
||||
let notification = {};
|
||||
const linkURL = isHostedOnStrapiCloud
|
||||
? 'https://cloud.strapi.io/profile/billing'
|
||||
: 'https://strapi.chargebeeportal.com/portal/v2/login?forward=portal_main';
|
||||
const linkLabel = isHostedOnStrapiCloud ? 'ADD SEATS' : 'CONTACT SALES';
|
||||
const STORAGE_KEY_PREFIX = 'strapi-notification-seat-limit-disabled';
|
||||
|
||||
if (licenseLimitStatus === 'OVER_LIMIT') {
|
||||
notification = {
|
||||
type: 'warning',
|
||||
message: {
|
||||
id: 'notification.ee.warning.over-seat-limit',
|
||||
defaultMessage:
|
||||
"Add seats to re-enable users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app.",
|
||||
},
|
||||
// Title is translated in the Notification component
|
||||
title: {
|
||||
id: 'notification.ee.warning.over-seat-limit.title',
|
||||
defaultMessage: 'Over seat limit ({currentUserCount}/{permittedSeats})',
|
||||
values: { currentUserCount, permittedSeats },
|
||||
},
|
||||
link: {
|
||||
url: linkURL,
|
||||
label: linkLabel,
|
||||
},
|
||||
blockTransition: true,
|
||||
};
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
if (licenseLimitStatus === 'AT_LIMIT') {
|
||||
notification = {
|
||||
type: 'softWarning',
|
||||
message: {
|
||||
id: 'notification.ee.warning.at-seat-limit',
|
||||
defaultMessage:
|
||||
"Add seats to re-enable users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app.",
|
||||
},
|
||||
title: {
|
||||
id: 'notification.ee.warning.at-seat-limit.title',
|
||||
defaultMessage: 'At seat limit ({currentUserCount}/{permittedSeats})',
|
||||
values: { currentUserCount, permittedSeats },
|
||||
},
|
||||
link: {
|
||||
url: linkURL,
|
||||
label: linkLabel,
|
||||
},
|
||||
blockTransition: true,
|
||||
};
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
return notification;
|
||||
};
|
||||
|
||||
const shouldDisplayNotification = (pathname) => {
|
||||
const isLocation = (string) => pathname.includes(string);
|
||||
const shownInSession = window.sessionStorage.getItem(`notification-${pathname}`);
|
||||
|
||||
if (isLocation('/') && shownInSession) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLocation('users') && shownInSession) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
const BILLING_STRAPI_CLOUD_URL = 'https://cloud.strapi.io/profile/billing';
|
||||
const BILLING_SELF_HOSTED_URL =
|
||||
'https://strapi.chargebeeportal.com/portal/v2/login?forward=portal_main';
|
||||
|
||||
const useLicenseLimitNotification = () => {
|
||||
let licenseLimitInfos = useLicenseLimitInfos();
|
||||
const { formatMessage } = useIntl();
|
||||
let { license } = useLicenseLimits();
|
||||
const toggleNotification = useNotification();
|
||||
const location = useLocation();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
// eslint-disable-next-line consistent-return
|
||||
useEffect(() => {
|
||||
if (!licenseLimitInfos || !licenseLimitInfos.permittedSeats) return;
|
||||
|
||||
if (!shouldDisplayNotification(location.pathname)) return;
|
||||
if (!license?.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { currentUserCount, permittedSeats, licenseLimitStatus, isHostedOnStrapiCloud } =
|
||||
licenseLimitInfos;
|
||||
const notification = notificationBody(
|
||||
currentUserCount,
|
||||
permittedSeats,
|
||||
licenseLimitStatus,
|
||||
isHostedOnStrapiCloud
|
||||
);
|
||||
const onClose = () => window.sessionStorage.setItem(`notification-${location.pathname}`, true);
|
||||
toggleNotification({ ...notification, onClose });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
license?.data ?? {};
|
||||
|
||||
const shouldDisplayNotification =
|
||||
permittedSeats &&
|
||||
window.sessionStorage.getItem(`${STORAGE_KEY_PREFIX}-${pathname}`) &&
|
||||
['/', '/users'].every(pathname.includes);
|
||||
|
||||
if (shouldDisplayNotification) {
|
||||
toggleNotification({
|
||||
type: licenseLimitStatus === 'OVER_LIMIT' ? 'warning' : 'softWarning',
|
||||
message: formatMessage(
|
||||
{
|
||||
id: 'notification.ee.warning.seat-limit.message',
|
||||
defaultMessage:
|
||||
"Add seats to invite more Users. If you already did it but it's not reflected in Strapi yet, make sure to restart your app.",
|
||||
},
|
||||
{ licenseLimitStatus }
|
||||
),
|
||||
title: formatMessage(
|
||||
{
|
||||
id: 'notification.ee.warning.seat-limit.title',
|
||||
defaultMessage: 'Over seat limit ({currentUserCount}/{permittedSeats})',
|
||||
},
|
||||
{
|
||||
licenseLimitStatus,
|
||||
currentUserCount,
|
||||
permittedSeats,
|
||||
}
|
||||
),
|
||||
link: {
|
||||
url: isHostedOnStrapiCloud ? BILLING_STRAPI_CLOUD_URL : BILLING_SELF_HOSTED_URL,
|
||||
label: formatMessage(
|
||||
{
|
||||
id: 'notification.ee.warning.seat-limit.link',
|
||||
defaultMessage:
|
||||
'{isHostedOnStrapiCloud, select, true {ADD SEATS} other {CONTACT SALES}}',
|
||||
},
|
||||
{ isHostedOnStrapiCloud }
|
||||
),
|
||||
},
|
||||
blockTransition: true,
|
||||
onClose() {
|
||||
window.sessionStorage.setItem(`${STORAGE_KEY_PREFIX}-${pathname}`, true);
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [toggleNotification, license.data, pathname, formatMessage]);
|
||||
};
|
||||
|
||||
export default useLicenseLimitNotification;
|
||||
|
||||
19
packages/core/admin/ee/admin/hooks/useLicenseLimits/index.js
Normal file
19
packages/core/admin/ee/admin/hooks/useLicenseLimits/index.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { useFetchClient } from '@strapi/helper-plugin';
|
||||
import { useQuery } from 'react-query';
|
||||
|
||||
const useLicenseLimits = () => {
|
||||
const { get } = useFetchClient();
|
||||
const fetchLicenseLimitInfo = async () => {
|
||||
const {
|
||||
data: { data },
|
||||
} = await get('/admin/license-limit-information');
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
const license = useQuery(['ee', 'license-limit-info'], fetchLicenseLimitInfo);
|
||||
|
||||
return { license };
|
||||
};
|
||||
|
||||
export default useLicenseLimits;
|
||||
@ -9,19 +9,20 @@ import { Stack } from '@strapi/design-system/Stack';
|
||||
import { Link } from '@strapi/design-system/v2/Link';
|
||||
import ExternalLink from '@strapi/icons/ExternalLink';
|
||||
import ExclamationMarkCircle from '@strapi/icons/ExclamationMarkCircle';
|
||||
import { useLicenseLimitInfos } from '../../../../../../hooks';
|
||||
import { pxToRem } from '@strapi/helper-plugin';
|
||||
import { useLicenseLimits } from '../../../../../../hooks';
|
||||
|
||||
const BILLING_STRAPI_CLOUD_URL = 'https://cloud.strapi.io/profile/billing';
|
||||
const BILLING_SELF_HOSTED_URL = 'https://share.hsforms.com/1WhxtbTkJSUmfqqEuv4pwuA43qp4';
|
||||
|
||||
const AdminSeatInfo = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const licenseLimitInfos = useLicenseLimitInfos();
|
||||
const { license } = useLicenseLimits();
|
||||
const { licenseLimitStatus, currentUserCount, permittedSeats, isHostedOnStrapiCloud } =
|
||||
licenseLimitInfos;
|
||||
const linkURL = isHostedOnStrapiCloud
|
||||
? 'https://cloud.strapi.io/profile/billing'
|
||||
: 'https://share.hsforms.com/1WhxtbTkJSUmfqqEuv4pwuA43qp4';
|
||||
license?.data ?? {};
|
||||
|
||||
if (!permittedSeats) {
|
||||
return <></>;
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -39,34 +40,44 @@ const AdminSeatInfo = () => {
|
||||
textColor={licenseLimitStatus === 'OVER_LIMIT' ? 'danger500' : ''}
|
||||
fontWeight={licenseLimitStatus === 'OVER_LIMIT' ? 'bold' : ''}
|
||||
>
|
||||
{currentUserCount || 'NA'}
|
||||
{formatMessage(
|
||||
{
|
||||
id: 'Settings.application.ee.admin-seats.count',
|
||||
defaultMessage: '{currentUserCount}/{permittedSeats}',
|
||||
},
|
||||
{ permittedSeats, currentUserCount }
|
||||
)}
|
||||
</Typography>
|
||||
<Typography as="p">/</Typography>
|
||||
<Typography as="p">{permittedSeats || 'NA'}</Typography>
|
||||
</Flex>
|
||||
{licenseLimitStatus === 'AT_LIMIT' && (
|
||||
<Tooltip
|
||||
description={formatMessage({
|
||||
id: 'Settings.application.admin-seats.at-limit-tooltip',
|
||||
id: 'Settings.application.ee.admin-seats.at-limit-tooltip',
|
||||
defaultMessage: 'At limit: add seats to invite more users',
|
||||
})}
|
||||
>
|
||||
<Icon
|
||||
width={`${14 / 16}rem`}
|
||||
height={`${14 / 16}rem`}
|
||||
width={`${pxToRem(14)}rem`}
|
||||
height={`${pxToRem(14)}rem`}
|
||||
color="danger500"
|
||||
as={ExclamationMarkCircle}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Stack>
|
||||
<Link href={linkURL} isExternal endIcon={<ExternalLink />}>
|
||||
{formatMessage({
|
||||
id: isHostedOnStrapiCloud
|
||||
? 'Settings.application.ee.link-add-seats'
|
||||
: 'Settings.application.ee.link-contact-sales',
|
||||
defaultMessage: isHostedOnStrapiCloud ? 'Add seats' : 'Contact sales',
|
||||
})}
|
||||
<Link
|
||||
href={isHostedOnStrapiCloud ? BILLING_STRAPI_CLOUD_URL : BILLING_SELF_HOSTED_URL}
|
||||
isExternal
|
||||
endIcon={<ExternalLink />}
|
||||
>
|
||||
{formatMessage(
|
||||
{
|
||||
id: 'Settings.application.ee.admin-seats.add-seats',
|
||||
defaultMessage:
|
||||
'{isHostedOnStrapiCloud, select, true {Add seats} false {Contact sales}}',
|
||||
},
|
||||
{ isHostedOnStrapiCloud }
|
||||
)}
|
||||
</Link>
|
||||
</GridItem>
|
||||
);
|
||||
|
||||
@ -7,11 +7,11 @@ import { Icon } from '@strapi/design-system/Icon';
|
||||
import { Stack } from '@strapi/design-system';
|
||||
import Envelop from '@strapi/icons/Envelop';
|
||||
import ExclamationMarkCircle from '@strapi/icons/ExclamationMarkCircle';
|
||||
import { useLicenseLimitInfos } from '../../../../../../hooks';
|
||||
import { useLicenseLimits } from '../../../../../../hooks';
|
||||
|
||||
const CreateAction = ({ onClick }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const licenseLimitInfos = useLicenseLimitInfos();
|
||||
const licenseLimitInfos = useLicenseLimits();
|
||||
const { licenseLimitStatus, permittedSeats } = licenseLimitInfos;
|
||||
|
||||
return (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user