Wizard: Use useChrome hook to set beta feature flag
The use of chrome.isBeta is deprecated, the useChrome hook should be used instead to obtain an isBeta() function. Using the deprecrated chrome.isBeta pollutes the browser console with warning messages. This commit replaces the isBeta() helper function with a new custom hook, useGetEnvironment(). We still sometimes need to know which environment is running outside of React components, where we cannot call the useChrome() or useGetEnvironment() hooks. For instance, in the json used to define a wizard step. Therefore a new isBeta variable has been added to the form's initialState for use in these cases.
This commit is contained in:
parent
c9081259a6
commit
b2e6e3cf04
15 changed files with 95 additions and 85 deletions
|
|
@ -32,9 +32,9 @@ import { UNIT_GIB, UNIT_KIB, UNIT_MIB, MODAL_ANCHOR } from '../../constants';
|
||||||
import { useGetArchitecturesByDistributionQuery } from '../../store/apiSlice';
|
import { useGetArchitecturesByDistributionQuery } from '../../store/apiSlice';
|
||||||
import { composeAdded } from '../../store/composesSlice';
|
import { composeAdded } from '../../store/composesSlice';
|
||||||
import { fetchRepositories } from '../../store/repositoriesSlice';
|
import { fetchRepositories } from '../../store/repositoriesSlice';
|
||||||
import isBeta from '../../Utilities/isBeta';
|
|
||||||
import isRhel from '../../Utilities/isRhel';
|
import isRhel from '../../Utilities/isRhel';
|
||||||
import { resolveRelPath } from '../../Utilities/path';
|
import { resolveRelPath } from '../../Utilities/path';
|
||||||
|
import { useGetEnvironment } from '../../Utilities/useGetEnvironment';
|
||||||
import DocumentationButton from '../sharedComponents/DocumentationButton';
|
import DocumentationButton from '../sharedComponents/DocumentationButton';
|
||||||
|
|
||||||
const handleKeyDown = (e, handleClose) => {
|
const handleKeyDown = (e, handleClose) => {
|
||||||
|
|
@ -266,11 +266,17 @@ const getDistributionRepoUrls = (distributionInformation) => {
|
||||||
return mapped;
|
return mapped;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPackageDescription = async (release, arch, repoUrls, packageName) => {
|
const getPackageDescription = async (
|
||||||
|
release,
|
||||||
|
arch,
|
||||||
|
repoUrls,
|
||||||
|
packageName,
|
||||||
|
isBeta
|
||||||
|
) => {
|
||||||
let pack;
|
let pack;
|
||||||
// if the env is stage beta then use content-sources api
|
// if the env is stage beta then use content-sources api
|
||||||
// else use image-builder api
|
// else use image-builder api
|
||||||
if (isBeta()) {
|
if (isBeta) {
|
||||||
const data = await api.getPackagesContentSources(repoUrls, packageName);
|
const data = await api.getPackagesContentSources(repoUrls, packageName);
|
||||||
pack = data.find((pack) => packageName === pack.name);
|
pack = data.find((pack) => packageName === pack.name);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -296,7 +302,7 @@ const getPackageDescription = async (release, arch, repoUrls, packageName) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// map the compose request object to the expected form state
|
// map the compose request object to the expected form state
|
||||||
const requestToState = (composeRequest, distroInfo) => {
|
const requestToState = (composeRequest, distroInfo, isBeta) => {
|
||||||
if (composeRequest) {
|
if (composeRequest) {
|
||||||
const imageRequest = composeRequest.image_requests[0];
|
const imageRequest = composeRequest.image_requests[0];
|
||||||
const uploadRequest = imageRequest.upload_request;
|
const uploadRequest = imageRequest.upload_request;
|
||||||
|
|
@ -396,7 +402,8 @@ const requestToState = (composeRequest, distroInfo) => {
|
||||||
distro,
|
distro,
|
||||||
imageRequest?.architecture,
|
imageRequest?.architecture,
|
||||||
repoUrls,
|
repoUrls,
|
||||||
packName
|
packName,
|
||||||
|
isBeta
|
||||||
);
|
);
|
||||||
const pack = {
|
const pack = {
|
||||||
name: packName,
|
name: packName,
|
||||||
|
|
@ -472,7 +479,7 @@ const requestToState = (composeRequest, distroInfo) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const formStepHistory = (composeRequest) => {
|
const formStepHistory = (composeRequest, isBeta) => {
|
||||||
if (composeRequest) {
|
if (composeRequest) {
|
||||||
const imageRequest = composeRequest.image_requests[0];
|
const imageRequest = composeRequest.image_requests[0];
|
||||||
const uploadRequest = imageRequest.upload_request;
|
const uploadRequest = imageRequest.upload_request;
|
||||||
|
|
@ -491,7 +498,7 @@ const formStepHistory = (composeRequest) => {
|
||||||
steps.push('registration');
|
steps.push('registration');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBeta()) {
|
if (isBeta) {
|
||||||
steps.push('File system configuration', 'packages', 'repositories');
|
steps.push('File system configuration', 'packages', 'repositories');
|
||||||
|
|
||||||
const customRepositories =
|
const customRepositories =
|
||||||
|
|
@ -537,10 +544,16 @@ const CreateImageWizard = () => {
|
||||||
// This will occur if 'Recreate image' is clicked
|
// This will occur if 'Recreate image' is clicked
|
||||||
const initialStep = compose?.request ? 'review' : undefined;
|
const initialStep = compose?.request ? 'review' : undefined;
|
||||||
|
|
||||||
|
const { isBeta } = useGetEnvironment();
|
||||||
|
|
||||||
const awsTarget = isBeta() ? awsTargetBeta : awsTargetStable;
|
const awsTarget = isBeta() ? awsTargetBeta : awsTargetStable;
|
||||||
const msAzureTarget = isBeta() ? msAzureTargetBeta : msAzureTargetStable;
|
const msAzureTarget = isBeta() ? msAzureTargetBeta : msAzureTargetStable;
|
||||||
const initialState = requestToState(composeRequest, distroInfo);
|
let initialState = requestToState(composeRequest, distroInfo, isBeta());
|
||||||
const stepHistory = formStepHistory(composeRequest);
|
const stepHistory = formStepHistory(composeRequest, isBeta());
|
||||||
|
|
||||||
|
initialState
|
||||||
|
? (initialState.isBeta = isBeta())
|
||||||
|
: (initialState = { isBeta: isBeta() });
|
||||||
|
|
||||||
const handleClose = () => navigate(resolveRelPath(''));
|
const handleClose = () => navigate(resolveRelPath(''));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import api from '../../../api';
|
import api from '../../../api';
|
||||||
import { useGetArchitecturesByDistributionQuery } from '../../../store/apiSlice';
|
import { useGetArchitecturesByDistributionQuery } from '../../../store/apiSlice';
|
||||||
import isBeta from '../../../Utilities/isBeta';
|
|
||||||
|
|
||||||
const ExactMatch = ({
|
const ExactMatch = ({
|
||||||
pkgList,
|
pkgList,
|
||||||
|
|
@ -67,7 +66,7 @@ export const RedHatPackages = ({ defaultArch }) => {
|
||||||
const getAllPackages = async (packagesSearchName) => {
|
const getAllPackages = async (packagesSearchName) => {
|
||||||
// if the env is stage beta then use content-sources api
|
// if the env is stage beta then use content-sources api
|
||||||
// else use image-builder api
|
// else use image-builder api
|
||||||
if (isBeta()) {
|
if (getState()?.values?.isBeta) {
|
||||||
const filteredArchx86_64 = distributionInformation.find(
|
const filteredArchx86_64 = distributionInformation.find(
|
||||||
(info) => info.arch === 'x86_64'
|
(info) => info.arch === 'x86_64'
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import PropTypes from 'prop-types';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { selectValidRepositories } from '../../../store/repositoriesSlice';
|
import { selectValidRepositories } from '../../../store/repositoriesSlice';
|
||||||
import isBeta from '../../../Utilities/isBeta';
|
|
||||||
|
|
||||||
const BulkSelect = ({
|
const BulkSelect = ({
|
||||||
selected,
|
selected,
|
||||||
|
|
@ -276,7 +275,11 @@ const Repositories = (props) => {
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
component="a"
|
component="a"
|
||||||
href={isBeta() ? '/beta/settings/content' : '/settings/content'}
|
href={
|
||||||
|
getState()?.values?.isBeta
|
||||||
|
? '/beta/settings/content'
|
||||||
|
: '/settings/content'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Repositories
|
Repositories
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { Text } from '@patternfly/react-core';
|
||||||
|
|
||||||
import StepTemplate from './stepTemplate';
|
import StepTemplate from './stepTemplate';
|
||||||
|
|
||||||
import isBeta from '../../../Utilities/isBeta';
|
|
||||||
import CustomButtons from '../formComponents/CustomButtons';
|
import CustomButtons from '../formComponents/CustomButtons';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -14,8 +13,8 @@ export default {
|
||||||
title: 'Additional Red Hat packages',
|
title: 'Additional Red Hat packages',
|
||||||
name: 'packages',
|
name: 'packages',
|
||||||
substepOf: 'Content',
|
substepOf: 'Content',
|
||||||
nextStep: () => {
|
nextStep: ({ values }) => {
|
||||||
if (isBeta()) {
|
if (values.isBeta) {
|
||||||
return 'repositories';
|
return 'repositories';
|
||||||
} else {
|
} else {
|
||||||
return 'image-name';
|
return 'image-name';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Suspense, useState, useMemo } from 'react';
|
import React, { Suspense, useState, useMemo } from 'react';
|
||||||
|
|
||||||
import { Button, Modal, ModalVariant } from '@patternfly/react-core';
|
import { Button, Modal, ModalVariant } from '@patternfly/react-core';
|
||||||
import useChrome from '@redhat-cloud-services/frontend-components/useChrome';
|
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
|
||||||
import { useLoadModule, useScalprum } from '@scalprum/react-core';
|
import { useLoadModule, useScalprum } from '@scalprum/react-core';
|
||||||
import { useFlag } from '@unleash/proxy-client-react';
|
import { useFlag } from '@unleash/proxy-client-react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
@ -11,6 +11,7 @@ import ImageLinkDirect from './ImageLinkDirect';
|
||||||
|
|
||||||
import { MODAL_ANCHOR } from '../../constants';
|
import { MODAL_ANCHOR } from '../../constants';
|
||||||
import { selectImageById } from '../../store/composesSlice';
|
import { selectImageById } from '../../store/composesSlice';
|
||||||
|
import { useGetEnvironment } from '../../Utilities/useGetEnvironment';
|
||||||
|
|
||||||
const getImageProvider = ({ imageType }) => {
|
const getImageProvider = ({ imageType }) => {
|
||||||
switch (imageType) {
|
switch (imageType) {
|
||||||
|
|
@ -91,18 +92,13 @@ const ProvisioningLink = ({ imageId, isExpired, isInClonesTable }) => {
|
||||||
const ImageLink = ({ imageId, isExpired, isInClonesTable }) => {
|
const ImageLink = ({ imageId, isExpired, isInClonesTable }) => {
|
||||||
const image = useSelector((state) => selectImageById(state, imageId));
|
const image = useSelector((state) => selectImageById(state, imageId));
|
||||||
const uploadStatus = image.uploadStatus;
|
const uploadStatus = image.uploadStatus;
|
||||||
const {
|
const { initialized: chromeInitialized } = useChrome();
|
||||||
initialized: chromeInitialized,
|
const { isBeta } = useGetEnvironment();
|
||||||
isBeta,
|
|
||||||
getEnvironment,
|
|
||||||
} = useChrome();
|
|
||||||
const azureFeatureFlag = useFlag('provisioning.azure');
|
const azureFeatureFlag = useFlag('provisioning.azure');
|
||||||
|
|
||||||
const scalprum = useScalprum();
|
const scalprum = useScalprum();
|
||||||
const hasProvisioning =
|
const hasProvisioning =
|
||||||
chromeInitialized &&
|
chromeInitialized && scalprum.config?.provisioning && isBeta();
|
||||||
scalprum.config?.provisioning &&
|
|
||||||
(isBeta() || getEnvironment() === 'qa');
|
|
||||||
|
|
||||||
if (!uploadStatus || image.status !== 'success') return null;
|
if (!uploadStatus || image.status !== 'success') return null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { selectComposeById, selectImagesById } from '../../store/composesSlice';
|
import { selectComposeById, selectImagesById } from '../../store/composesSlice';
|
||||||
import isBeta from '../../Utilities/isBeta';
|
import { useGetEnvironment } from '../../Utilities/useGetEnvironment';
|
||||||
import BetaLabel from '../sharedComponents/BetaLabel';
|
import BetaLabel from '../sharedComponents/BetaLabel';
|
||||||
|
|
||||||
export const selectRegions = createSelector(
|
export const selectRegions = createSelector(
|
||||||
|
|
@ -57,6 +57,7 @@ const ImageLinkRegion = ({ region, ami }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RegionsPopover = ({ composeId }) => {
|
export const RegionsPopover = ({ composeId }) => {
|
||||||
|
const { isBeta } = useGetEnvironment();
|
||||||
const regions = useSelector((state) => selectRegions(state, composeId));
|
const regions = useSelector((state) => selectRegions(state, composeId));
|
||||||
|
|
||||||
const listItems = useMemo(() => {
|
const listItems = useMemo(() => {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import azureQuickStart from './azurequickstart.json';
|
||||||
import contentQuickStart from './contentquickstart.json';
|
import contentQuickStart from './contentquickstart.json';
|
||||||
import './LandingPage.scss';
|
import './LandingPage.scss';
|
||||||
|
|
||||||
import isBeta from '../../Utilities/isBeta';
|
import { useGetEnvironment } from '../../Utilities/useGetEnvironment';
|
||||||
import ImagesTable from '../ImagesTable/ImagesTable';
|
import ImagesTable from '../ImagesTable/ImagesTable';
|
||||||
import DocumentationButton from '../sharedComponents/DocumentationButton';
|
import DocumentationButton from '../sharedComponents/DocumentationButton';
|
||||||
|
|
||||||
|
|
@ -37,6 +37,7 @@ export const LandingPage = () => {
|
||||||
const [showHint, setShowHint] = useState(true);
|
const [showHint, setShowHint] = useState(true);
|
||||||
|
|
||||||
const { quickStarts } = useChrome();
|
const { quickStarts } = useChrome();
|
||||||
|
const { isBeta } = useGetEnvironment();
|
||||||
const activateQuickstart = (qs) => quickStarts.toggle(qs.metadata.name);
|
const activateQuickstart = (qs) => quickStarts.toggle(qs.metadata.name);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
function isBeta() {
|
|
||||||
return insights.chrome.isBeta() || insights.chrome.getEnvironment() === 'qa'
|
|
||||||
? true
|
|
||||||
: false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default isBeta;
|
|
||||||
10
src/Utilities/useGetEnvironment.js
Normal file
10
src/Utilities/useGetEnvironment.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
|
||||||
|
|
||||||
|
export const useGetEnvironment = () => {
|
||||||
|
const { isBeta, getEnvironment } = useChrome();
|
||||||
|
// Expose beta features in the ephemeral environment
|
||||||
|
if (isBeta() || getEnvironment() === 'qa') {
|
||||||
|
return { isBeta: () => true };
|
||||||
|
}
|
||||||
|
return { isBeta: () => false };
|
||||||
|
};
|
||||||
|
|
@ -10,6 +10,14 @@ import { mockRepositoryResults } from '../../fixtures/repositories';
|
||||||
import { server } from '../../mocks/server.js';
|
import { server } from '../../mocks/server.js';
|
||||||
import { renderWithReduxRouter } from '../../testUtils';
|
import { renderWithReduxRouter } from '../../testUtils';
|
||||||
|
|
||||||
|
jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
|
||||||
|
useChrome: () => ({
|
||||||
|
isBeta: () => true,
|
||||||
|
isProd: () => true,
|
||||||
|
getEnvironment: () => 'prod',
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('Step Upload to Azure', () => {
|
describe('Step Upload to Azure', () => {
|
||||||
const getNextButton = () => {
|
const getNextButton = () => {
|
||||||
const next = screen.getByRole('button', { name: /Next/ });
|
const next = screen.getByRole('button', { name: /Next/ });
|
||||||
|
|
@ -47,15 +55,6 @@ describe('Step Upload to Azure', () => {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isBeta: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
isProd: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
getEnvironment: () => {
|
|
||||||
return 'prod';
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,14 @@ const mockComposes = {
|
||||||
data: [],
|
data: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
|
||||||
|
useChrome: () => ({
|
||||||
|
isBeta: () => true,
|
||||||
|
isProd: () => true,
|
||||||
|
getEnvironment: () => 'prod',
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
// Mocking getComposes is necessary because in many tests we call navigate()
|
// Mocking getComposes is necessary because in many tests we call navigate()
|
||||||
// to navigate to the images table (via useNavigate hook), which will in turn
|
// to navigate to the images table (via useNavigate hook), which will in turn
|
||||||
// result in a call to getComposes. If it is not mocked, tests fail due to MSW
|
// result in a call to getComposes. If it is not mocked, tests fail due to MSW
|
||||||
|
|
@ -169,15 +177,9 @@ beforeAll(() => {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isBeta: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
isProd: () => {
|
isProd: () => {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
getEnvironment: () => {
|
|
||||||
return 'prod';
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,14 @@ jest
|
||||||
.spyOn(api, 'getComposes')
|
.spyOn(api, 'getComposes')
|
||||||
.mockImplementation(() => Promise.resolve(mockComposes));
|
.mockImplementation(() => Promise.resolve(mockComposes));
|
||||||
|
|
||||||
|
jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
|
||||||
|
useChrome: () => ({
|
||||||
|
isBeta: () => false,
|
||||||
|
isProd: () => true,
|
||||||
|
getEnvironment: () => 'prod',
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
function getBackButton() {
|
function getBackButton() {
|
||||||
const back = screen.getByRole('button', { name: /Back/ });
|
const back = screen.getByRole('button', { name: /Back/ });
|
||||||
return back;
|
return back;
|
||||||
|
|
|
||||||
|
|
@ -425,21 +425,13 @@ const mockCloneStatus = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeAll(() => {
|
jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
|
||||||
global.insights = {
|
useChrome: () => ({
|
||||||
chrome: {
|
isBeta: () => false,
|
||||||
isBeta: () => {
|
isProd: () => true,
|
||||||
return false;
|
getEnvironment: () => 'prod',
|
||||||
},
|
}),
|
||||||
isProd: () => {
|
}));
|
||||||
return true;
|
|
||||||
},
|
|
||||||
getEnvironment: () => {
|
|
||||||
return 'prod';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(api, 'getComposes')
|
.spyOn(api, 'getComposes')
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,20 @@ jest.mock('../../../store/actions/actions', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
|
||||||
|
useChrome: () => ({
|
||||||
|
isBeta: () => false,
|
||||||
|
isProd: () => true,
|
||||||
|
getEnvironment: () => 'prod',
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
global.insights = {
|
global.insights = {
|
||||||
chrome: {
|
chrome: {
|
||||||
isBeta: () => {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
isProd: () => {
|
isProd: () => {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
getEnvironment: () => {
|
|
||||||
return 'prod';
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,13 @@ import api from '../../../api.js';
|
||||||
import { RHEL_8 } from '../../../constants.js';
|
import { RHEL_8 } from '../../../constants.js';
|
||||||
import { renderWithReduxRouter } from '../../testUtils';
|
import { renderWithReduxRouter } from '../../testUtils';
|
||||||
|
|
||||||
beforeAll(() => {
|
jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
|
||||||
global.insights = {
|
useChrome: () => ({
|
||||||
chrome: {
|
isBeta: () => false,
|
||||||
isBeta: () => {
|
isProd: () => true,
|
||||||
return false;
|
getEnvironment: () => 'prod',
|
||||||
},
|
}),
|
||||||
isProd: () => {
|
}));
|
||||||
return true;
|
|
||||||
},
|
|
||||||
getEnvironment: () => {
|
|
||||||
return 'prod';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const mockComposes = {
|
const mockComposes = {
|
||||||
count: 1,
|
count: 1,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue