mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 08:19:07 +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 { formatMessage } = useIntl();
|
||||
let { license } = useLicenseLimits();
|
||||
let { license, isError, isLoading } = useLicenseLimits();
|
||||
const toggleNotification = useNotification();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const { enforcementUserCount, permittedSeats, licenseLimitStatus, isHostedOnStrapiCloud } =
|
||||
license;
|
||||
|
||||
useEffect(() => {
|
||||
if (!license?.data) {
|
||||
if (isError || isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { enforcementUserCount, permittedSeats, licenseLimitStatus, isHostedOnStrapiCloud } =
|
||||
license?.data ?? {};
|
||||
|
||||
const shouldDisplayNotification =
|
||||
!isNil(permittedSeats) &&
|
||||
!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;
|
||||
|
@ -54,9 +54,7 @@ describe('useLicenseLimitNotification', () => {
|
||||
|
||||
it('should return if no license info is available', () => {
|
||||
useLicenseLimits.mockImplementationOnce(() => ({
|
||||
license: {
|
||||
data: {},
|
||||
},
|
||||
license: {},
|
||||
}));
|
||||
|
||||
renderHook(() => useLicenseLimitNotification());
|
||||
@ -66,10 +64,8 @@ describe('useLicenseLimitNotification', () => {
|
||||
it('should not display notification if permittedSeat info is missing', () => {
|
||||
useLicenseLimits.mockImplementationOnce(() => ({
|
||||
license: {
|
||||
data: {
|
||||
...baseLicenseInfo,
|
||||
permittedSeats: undefined,
|
||||
},
|
||||
...baseLicenseInfo,
|
||||
permittedSeats: undefined,
|
||||
},
|
||||
}));
|
||||
|
||||
@ -80,10 +76,8 @@ describe('useLicenseLimitNotification', () => {
|
||||
it('should not display notification if status is not AT_LIMIT or OVER_LIMIT', () => {
|
||||
useLicenseLimits.mockImplementationOnce(() => ({
|
||||
license: {
|
||||
data: {
|
||||
...baseLicenseInfo,
|
||||
licenseLimitStatus: 'SOME_STRING',
|
||||
},
|
||||
...baseLicenseInfo,
|
||||
licenseLimitStatus: 'SOME_STRING',
|
||||
},
|
||||
}));
|
||||
|
||||
@ -117,10 +111,8 @@ describe('useLicenseLimitNotification', () => {
|
||||
it('should display a warning notification when license limit is at limit', () => {
|
||||
useLicenseLimits.mockImplementationOnce(() => ({
|
||||
license: {
|
||||
data: {
|
||||
...baseLicenseInfo,
|
||||
licenseLimitStatus: 'OVER_LIMIT',
|
||||
},
|
||||
...baseLicenseInfo,
|
||||
licenseLimitStatus: 'OVER_LIMIT',
|
||||
},
|
||||
}));
|
||||
|
||||
@ -144,10 +136,8 @@ describe('useLicenseLimitNotification', () => {
|
||||
it('should have cloud billing url if is hosted on strapi cloud', () => {
|
||||
useLicenseLimits.mockImplementationOnce(() => ({
|
||||
license: {
|
||||
data: {
|
||||
...baseLicenseInfo,
|
||||
isHostedOnStrapiCloud: true,
|
||||
},
|
||||
...baseLicenseInfo,
|
||||
isHostedOnStrapiCloud: true,
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -1,34 +1,3 @@
|
||||
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';
|
||||
|
||||
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 };
|
||||
};
|
||||
import { useLicenseLimits } from './useLicenseLimits';
|
||||
|
||||
export default useLicenseLimits;
|
||||
|
@ -1,19 +1,32 @@
|
||||
import React from 'react';
|
||||
|
||||
import { fixtures } from '@strapi/admin-test-utils';
|
||||
import { useFetchClient } from '@strapi/helper-plugin';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useRBAC } from '@strapi/helper-plugin';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||
import { Provider } from 'react-redux';
|
||||
import { createStore } from 'redux';
|
||||
|
||||
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', () => ({
|
||||
// TODO: Replace with msw
|
||||
useFetchClient: jest.fn(() => ({
|
||||
get: jest.fn(),
|
||||
})),
|
||||
...jest.requireActual('@strapi/helper-plugin'),
|
||||
useRBAC: jest.fn(() => ({
|
||||
isLoading: false,
|
||||
allowedActions: {
|
||||
@ -25,55 +38,71 @@ jest.mock('@strapi/helper-plugin', () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
// TODO: Replace with msw
|
||||
jest.mock('react-query', () => ({
|
||||
useQuery: jest.fn(),
|
||||
}));
|
||||
|
||||
const setup = (...args) =>
|
||||
renderHook(() => useLicenseLimits(...args), {
|
||||
wrapper({ children }) {
|
||||
const client = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Provider
|
||||
store={createStore((state) => state, {
|
||||
admin_app: { permissions: fixtures.permissions.app },
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
<QueryClientProvider client={client}>{children}</QueryClientProvider>
|
||||
</Provider>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
describe('useLicenseLimits', () => {
|
||||
beforeAll(() => server.listen());
|
||||
|
||||
afterEach(() => {
|
||||
server.resetHandlers();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
expect(useFetchClient).toHaveBeenCalled();
|
||||
expect(useQuery).toHaveBeenCalledWith(['ee', 'license-limit-info'], expect.any(Function), {
|
||||
enabled: true,
|
||||
expect(result.current.license).toEqual({});
|
||||
|
||||
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 () => {
|
||||
// const data = { data: { id: 1, name: 'Test License' } };
|
||||
useQuery.mockReturnValue({
|
||||
isError: true,
|
||||
});
|
||||
it.each(['canRead', 'canCreate', 'canUpdate', 'canDelete'])(
|
||||
'should not fetch the license limit information, when the user does not have the %s permissions',
|
||||
async (permission) => {
|
||||
const allowedActions = {
|
||||
canRead: true,
|
||||
canCreate: true,
|
||||
canUpdate: true,
|
||||
canDelete: true,
|
||||
};
|
||||
|
||||
const { result } = setup();
|
||||
allowedActions[permission] = false;
|
||||
|
||||
expect(useFetchClient).toHaveBeenCalled();
|
||||
expect(useQuery).toHaveBeenCalledWith(['ee', 'license-limit-info'], expect.any(Function), {
|
||||
enabled: true,
|
||||
});
|
||||
expect(result.current.license.data).toEqual(undefined);
|
||||
});
|
||||
useRBAC.mockReturnValue({
|
||||
isLoading: false,
|
||||
allowedActions,
|
||||
});
|
||||
|
||||
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 { formatMessage } = useIntl();
|
||||
const { license } = useLicenseLimits();
|
||||
const { licenseLimitStatus, enforcementUserCount, permittedSeats, isHostedOnStrapiCloud } =
|
||||
license?.data ?? {};
|
||||
const {
|
||||
license: { licenseLimitStatus, enforcementUserCount, permittedSeats, isHostedOnStrapiCloud },
|
||||
isError,
|
||||
isLoading,
|
||||
} = useLicenseLimits();
|
||||
|
||||
if (!permittedSeats) {
|
||||
if (isError || isLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,15 @@ import { useLicenseLimits } from '../../../../../../hooks';
|
||||
|
||||
const CreateAction = ({ onClick }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { license } = useLicenseLimits();
|
||||
const { permittedSeats, shouldStopCreate } = license?.data ?? {};
|
||||
const {
|
||||
license: { permittedSeats, shouldStopCreate },
|
||||
isError,
|
||||
isLoading,
|
||||
} = useLicenseLimits();
|
||||
|
||||
if (isError || isLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex gap={2}>
|
||||
|
Loading…
x
Reference in New Issue
Block a user