mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 16:29:34 +00:00
Chore: Refactor useLicenseLimits() hook
This commit is contained in:
parent
dda5eeebad
commit
e3324379db
@ -19,18 +19,18 @@ const BILLING_SELF_HOSTED_URL = 'https://strapi.io/billing/request-seats';
|
|||||||
|
|
||||||
const useLicenseLimitNotification = () => {
|
const useLicenseLimitNotification = () => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
let { license } = useLicenseLimits();
|
let { license, isError, isLoading } = useLicenseLimits();
|
||||||
const toggleNotification = useNotification();
|
const toggleNotification = useNotification();
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
|
|
||||||
|
const { enforcementUserCount, permittedSeats, licenseLimitStatus, isHostedOnStrapiCloud } =
|
||||||
|
license;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!license?.data) {
|
if (isError || isLoading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { enforcementUserCount, permittedSeats, licenseLimitStatus, isHostedOnStrapiCloud } =
|
|
||||||
license?.data ?? {};
|
|
||||||
|
|
||||||
const shouldDisplayNotification =
|
const shouldDisplayNotification =
|
||||||
!isNil(permittedSeats) &&
|
!isNil(permittedSeats) &&
|
||||||
!window.sessionStorage.getItem(`${STORAGE_KEY_PREFIX}-${pathname}`) &&
|
!window.sessionStorage.getItem(`${STORAGE_KEY_PREFIX}-${pathname}`) &&
|
||||||
@ -84,7 +84,18 @@ const useLicenseLimitNotification = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [toggleNotification, license.data, pathname, formatMessage]);
|
}, [
|
||||||
|
toggleNotification,
|
||||||
|
license,
|
||||||
|
pathname,
|
||||||
|
formatMessage,
|
||||||
|
isLoading,
|
||||||
|
permittedSeats,
|
||||||
|
licenseLimitStatus,
|
||||||
|
enforcementUserCount,
|
||||||
|
isHostedOnStrapiCloud,
|
||||||
|
isError,
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useLicenseLimitNotification;
|
export default useLicenseLimitNotification;
|
||||||
|
@ -54,9 +54,7 @@ describe('useLicenseLimitNotification', () => {
|
|||||||
|
|
||||||
it('should return if no license info is available', () => {
|
it('should return if no license info is available', () => {
|
||||||
useLicenseLimits.mockImplementationOnce(() => ({
|
useLicenseLimits.mockImplementationOnce(() => ({
|
||||||
license: {
|
license: {},
|
||||||
data: {},
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
renderHook(() => useLicenseLimitNotification());
|
renderHook(() => useLicenseLimitNotification());
|
||||||
@ -66,10 +64,8 @@ describe('useLicenseLimitNotification', () => {
|
|||||||
it('should not display notification if permittedSeat info is missing', () => {
|
it('should not display notification if permittedSeat info is missing', () => {
|
||||||
useLicenseLimits.mockImplementationOnce(() => ({
|
useLicenseLimits.mockImplementationOnce(() => ({
|
||||||
license: {
|
license: {
|
||||||
data: {
|
...baseLicenseInfo,
|
||||||
...baseLicenseInfo,
|
permittedSeats: undefined,
|
||||||
permittedSeats: undefined,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -80,10 +76,8 @@ describe('useLicenseLimitNotification', () => {
|
|||||||
it('should not display notification if status is not AT_LIMIT or OVER_LIMIT', () => {
|
it('should not display notification if status is not AT_LIMIT or OVER_LIMIT', () => {
|
||||||
useLicenseLimits.mockImplementationOnce(() => ({
|
useLicenseLimits.mockImplementationOnce(() => ({
|
||||||
license: {
|
license: {
|
||||||
data: {
|
...baseLicenseInfo,
|
||||||
...baseLicenseInfo,
|
licenseLimitStatus: 'SOME_STRING',
|
||||||
licenseLimitStatus: 'SOME_STRING',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -117,10 +111,8 @@ describe('useLicenseLimitNotification', () => {
|
|||||||
it('should display a warning notification when license limit is at limit', () => {
|
it('should display a warning notification when license limit is at limit', () => {
|
||||||
useLicenseLimits.mockImplementationOnce(() => ({
|
useLicenseLimits.mockImplementationOnce(() => ({
|
||||||
license: {
|
license: {
|
||||||
data: {
|
...baseLicenseInfo,
|
||||||
...baseLicenseInfo,
|
licenseLimitStatus: 'OVER_LIMIT',
|
||||||
licenseLimitStatus: 'OVER_LIMIT',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -144,10 +136,8 @@ describe('useLicenseLimitNotification', () => {
|
|||||||
it('should have cloud billing url if is hosted on strapi cloud', () => {
|
it('should have cloud billing url if is hosted on strapi cloud', () => {
|
||||||
useLicenseLimits.mockImplementationOnce(() => ({
|
useLicenseLimits.mockImplementationOnce(() => ({
|
||||||
license: {
|
license: {
|
||||||
data: {
|
...baseLicenseInfo,
|
||||||
...baseLicenseInfo,
|
isHostedOnStrapiCloud: true,
|
||||||
isHostedOnStrapiCloud: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -1,34 +1,3 @@
|
|||||||
import { useFetchClient, useRBAC } from '@strapi/helper-plugin';
|
import { useLicenseLimits } from './useLicenseLimits';
|
||||||
import { useQuery } from 'react-query';
|
|
||||||
import { useSelector } from 'react-redux';
|
|
||||||
|
|
||||||
import { selectAdminPermissions } from '../../../../admin/src/pages/App/selectors';
|
|
||||||
|
|
||||||
const useLicenseLimits = () => {
|
|
||||||
const permissions = useSelector(selectAdminPermissions);
|
|
||||||
const rbac = useRBAC(permissions.settings.users);
|
|
||||||
|
|
||||||
const {
|
|
||||||
isLoading: isRBACLoading,
|
|
||||||
allowedActions: { canRead, canCreate, canUpdate, canDelete },
|
|
||||||
} = rbac;
|
|
||||||
|
|
||||||
const isRBACAllowed = canRead && canCreate && canUpdate && canDelete;
|
|
||||||
|
|
||||||
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, {
|
|
||||||
enabled: !isRBACLoading && isRBACAllowed,
|
|
||||||
});
|
|
||||||
|
|
||||||
return { license };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useLicenseLimits;
|
export default useLicenseLimits;
|
||||||
|
@ -1,19 +1,32 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { fixtures } from '@strapi/admin-test-utils';
|
import { fixtures } from '@strapi/admin-test-utils';
|
||||||
import { useFetchClient } from '@strapi/helper-plugin';
|
import { useRBAC } from '@strapi/helper-plugin';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook, waitFor } from '@testing-library/react';
|
||||||
import { useQuery } from 'react-query';
|
import { rest } from 'msw';
|
||||||
|
import { setupServer } from 'msw/node';
|
||||||
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { createStore } from 'redux';
|
import { createStore } from 'redux';
|
||||||
|
|
||||||
import useLicenseLimits from '..';
|
import useLicenseLimits from '..';
|
||||||
|
|
||||||
|
const server = setupServer(
|
||||||
|
...[
|
||||||
|
rest.get('*/license-limit-information', (req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.json({
|
||||||
|
data: {
|
||||||
|
attribute: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
jest.mock('@strapi/helper-plugin', () => ({
|
jest.mock('@strapi/helper-plugin', () => ({
|
||||||
// TODO: Replace with msw
|
...jest.requireActual('@strapi/helper-plugin'),
|
||||||
useFetchClient: jest.fn(() => ({
|
|
||||||
get: jest.fn(),
|
|
||||||
})),
|
|
||||||
useRBAC: jest.fn(() => ({
|
useRBAC: jest.fn(() => ({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
allowedActions: {
|
allowedActions: {
|
||||||
@ -25,55 +38,71 @@ jest.mock('@strapi/helper-plugin', () => ({
|
|||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// TODO: Replace with msw
|
|
||||||
jest.mock('react-query', () => ({
|
|
||||||
useQuery: jest.fn(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const setup = (...args) =>
|
const setup = (...args) =>
|
||||||
renderHook(() => useLicenseLimits(...args), {
|
renderHook(() => useLicenseLimits(...args), {
|
||||||
wrapper({ children }) {
|
wrapper({ children }) {
|
||||||
|
const client = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Provider
|
<Provider
|
||||||
store={createStore((state) => state, {
|
store={createStore((state) => state, {
|
||||||
admin_app: { permissions: fixtures.permissions.app },
|
admin_app: { permissions: fixtures.permissions.app },
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{children}
|
<QueryClientProvider client={client}>{children}</QueryClientProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('useLicenseLimits', () => {
|
describe('useLicenseLimits', () => {
|
||||||
|
beforeAll(() => server.listen());
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
server.resetHandlers();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
it('should fetch the license limit information', async () => {
|
it('should fetch the license limit information', async () => {
|
||||||
const data = { data: { id: 1, name: 'Test License' } };
|
|
||||||
useQuery.mockReturnValue({
|
|
||||||
data: { id: 1, name: 'Test License' },
|
|
||||||
isLoading: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { result } = setup();
|
const { result } = setup();
|
||||||
|
|
||||||
expect(useFetchClient).toHaveBeenCalled();
|
expect(result.current.license).toEqual({});
|
||||||
expect(useQuery).toHaveBeenCalledWith(['ee', 'license-limit-info'], expect.any(Function), {
|
|
||||||
enabled: true,
|
await waitFor(() => expect(result.current.isLoading).toBeFalsy());
|
||||||
|
|
||||||
|
expect(result.current.license).toEqual({
|
||||||
|
attribute: 1,
|
||||||
});
|
});
|
||||||
expect(result.current.license.data).toEqual(data.data);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('data should be undefined if there is an API error', async () => {
|
it.each(['canRead', 'canCreate', 'canUpdate', 'canDelete'])(
|
||||||
// const data = { data: { id: 1, name: 'Test License' } };
|
'should not fetch the license limit information, when the user does not have the %s permissions',
|
||||||
useQuery.mockReturnValue({
|
async (permission) => {
|
||||||
isError: true,
|
const allowedActions = {
|
||||||
});
|
canRead: true,
|
||||||
|
canCreate: true,
|
||||||
|
canUpdate: true,
|
||||||
|
canDelete: true,
|
||||||
|
};
|
||||||
|
|
||||||
const { result } = setup();
|
allowedActions[permission] = false;
|
||||||
|
|
||||||
expect(useFetchClient).toHaveBeenCalled();
|
useRBAC.mockReturnValue({
|
||||||
expect(useQuery).toHaveBeenCalledWith(['ee', 'license-limit-info'], expect.any(Function), {
|
isLoading: false,
|
||||||
enabled: true,
|
allowedActions,
|
||||||
});
|
});
|
||||||
expect(result.current.license.data).toEqual(undefined);
|
|
||||||
});
|
const { result } = setup();
|
||||||
|
|
||||||
|
await waitFor(() => expect(result.current.isLoading).toBeFalsy());
|
||||||
|
|
||||||
|
expect(result.current.license).toEqual({});
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
import { useFetchClient, useRBAC } from '@strapi/helper-plugin';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { selectAdminPermissions } from '../../../../admin/src/pages/App/selectors';
|
||||||
|
|
||||||
|
export function useLicenseLimits() {
|
||||||
|
const permissions = useSelector(selectAdminPermissions);
|
||||||
|
const { get } = useFetchClient();
|
||||||
|
const {
|
||||||
|
isLoading: isRBACLoading,
|
||||||
|
allowedActions: { canRead, canCreate, canUpdate, canDelete },
|
||||||
|
} = useRBAC(permissions.settings.users);
|
||||||
|
const hasPermissions = canRead && canCreate && canUpdate && canDelete;
|
||||||
|
|
||||||
|
const { data, isError, isLoading } = useQuery(
|
||||||
|
['ee', 'license-limit-info'],
|
||||||
|
async () => {
|
||||||
|
const {
|
||||||
|
data: { data },
|
||||||
|
} = await get('/admin/license-limit-information');
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: !isRBACLoading && hasPermissions,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return { license: data ?? {}, isError, isLoading };
|
||||||
|
}
|
@ -13,11 +13,13 @@ const BILLING_SELF_HOSTED_URL = 'https://strapi.io/billing/request-seats';
|
|||||||
|
|
||||||
const AdminSeatInfo = () => {
|
const AdminSeatInfo = () => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const { license } = useLicenseLimits();
|
const {
|
||||||
const { licenseLimitStatus, enforcementUserCount, permittedSeats, isHostedOnStrapiCloud } =
|
license: { licenseLimitStatus, enforcementUserCount, permittedSeats, isHostedOnStrapiCloud },
|
||||||
license?.data ?? {};
|
isError,
|
||||||
|
isLoading,
|
||||||
|
} = useLicenseLimits();
|
||||||
|
|
||||||
if (!permittedSeats) {
|
if (isError || isLoading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,15 @@ import { useLicenseLimits } from '../../../../../../hooks';
|
|||||||
|
|
||||||
const CreateAction = ({ onClick }) => {
|
const CreateAction = ({ onClick }) => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const { license } = useLicenseLimits();
|
const {
|
||||||
const { permittedSeats, shouldStopCreate } = license?.data ?? {};
|
license: { permittedSeats, shouldStopCreate },
|
||||||
|
isError,
|
||||||
|
isLoading,
|
||||||
|
} = useLicenseLimits();
|
||||||
|
|
||||||
|
if (isError || isLoading) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap={2}>
|
<Flex gap={2}>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user