Merge pull request #15837 from strapi/data-transfer/tracking-api-token-transfer-token

This commit is contained in:
Jean-Sébastien Herbaux 2023-02-24 15:43:30 +01:00 committed by GitHub
commit 3d6a31eb08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 16 deletions

View File

@ -5,13 +5,15 @@ import { useTracking, ConfirmDialog } from '@strapi/helper-plugin';
import { useIntl } from 'react-intl';
import PropTypes from 'prop-types';
const DeleteButton = ({ tokenName, onClickDelete }) => {
const DeleteButton = ({ tokenName, onClickDelete, tokenType }) => {
const { formatMessage } = useIntl();
const { trackUsage } = useTracking(); // TODO: Track different types of tokens
const { trackUsage } = useTracking();
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const handleClickDelete = () => {
setShowConfirmDialog(false);
trackUsage('willDeleteToken');
trackUsage('willDeleteToken', {
tokenType,
});
onClickDelete();
};
@ -44,6 +46,7 @@ const DeleteButton = ({ tokenName, onClickDelete }) => {
DeleteButton.propTypes = {
tokenName: PropTypes.string.isRequired,
onClickDelete: PropTypes.func.isRequired,
tokenType: PropTypes.string.isRequired,
};
export default DeleteButton;

View File

@ -16,7 +16,12 @@ function ComponentToTest(props) {
<IntlProvider locale="en" messages={{}}>
<ThemeProvider theme={lightTheme}>
<NotificationsProvider toggleNotification={() => {}}>
<DeleteButton tokenName="test" onClickDelete={() => {}} {...props} />
<DeleteButton
tokenType="api-token"
tokenName="test"
onClickDelete={() => {}}
{...props}
/>
</NotificationsProvider>
</ThemeProvider>
</IntlProvider>

View File

@ -14,7 +14,15 @@ import DeleteButton from './DeleteButton';
import UpdateButton from './UpdateButton';
import ReadButton from './ReadButton';
const Table = ({ permissions, headers, contentType, isLoading, tokens, onConfirmDelete }) => {
const Table = ({
permissions,
headers,
contentType,
isLoading,
tokens,
onConfirmDelete,
tokenType,
}) => {
const { canDelete, canUpdate, canRead } = permissions;
const withBulkActions = canDelete || canUpdate || canRead;
const [{ query }] = useQueryParams();
@ -47,7 +55,9 @@ const Table = ({ permissions, headers, contentType, isLoading, tokens, onConfirm
key={token.id}
{...onRowClick({
fn() {
trackUsage('willEditTokenFromList');
trackUsage('willEditTokenFromList', {
tokenType,
});
push(`${pathname}/${token.id}`);
},
condition: canUpdate,
@ -87,6 +97,7 @@ const Table = ({ permissions, headers, contentType, isLoading, tokens, onConfirm
<DeleteButton
tokenName={token.name}
onClickDelete={() => onConfirmDelete(token.id)}
tokenType={tokenType}
/>
)}
</Flex>
@ -121,6 +132,7 @@ Table.propTypes = {
contentType: PropTypes.string.isRequired,
isLoading: PropTypes.bool,
onConfirmDelete: PropTypes.func,
tokenType: PropTypes.string.isRequired,
};
Table.defaultProps = {

View File

@ -6,7 +6,7 @@ import { Duplicate, Key } from '@strapi/icons';
import PropTypes from 'prop-types';
import { CopyToClipboard } from 'react-copy-to-clipboard';
const TokenBox = ({ token }) => {
const TokenBox = ({ token, tokenType }) => {
const { formatMessage } = useIntl();
const toggleNotification = useNotification();
const { trackUsage } = useTracking(); // TODO: Track different types of tokens
@ -19,7 +19,9 @@ const TokenBox = ({ token }) => {
<span style={{ alignSelf: 'start' }}>
<CopyToClipboard
onCopy={() => {
trackUsageRef.current('didCopyTokenKey');
trackUsageRef.current('didCopyTokenKey', {
tokenType,
});
toggleNotification({
type: 'success',
message: { id: 'Settings.tokens.notification.copied' },
@ -70,6 +72,7 @@ TokenBox.defaultProps = {
TokenBox.propTypes = {
token: PropTypes.string,
tokenType: PropTypes.string.isRequired,
};
export default TokenBox;

View File

@ -0,0 +1,2 @@
export const API_TOKEN_TYPE = 'api-token';
export const TRANSFER_TOKEN_TYPE = 'transfer-token';

View File

@ -26,6 +26,7 @@ import Permissions from './components/Permissions';
import FormApiTokenContainer from './components/FormApiTokenContainer';
import TokenBox from '../../../components/Tokens/TokenBox';
import FormHead from '../../../components/Tokens/FormHead';
import { API_TOKEN_TYPE } from '../../../components/Tokens/constants';
const MSG_ERROR_NAME_TAKEN = 'Name already taken';
@ -107,7 +108,9 @@ const ApiTokenCreateView = () => {
);
useEffect(() => {
trackUsageRef.current(isCreating ? 'didAddTokenFromList' : 'didEditTokenFromList');
trackUsageRef.current(isCreating ? 'didAddTokenFromList' : 'didEditTokenFromList', {
tokenType: API_TOKEN_TYPE,
});
}, [isCreating]);
const { status } = useQuery(
@ -152,7 +155,9 @@ const ApiTokenCreateView = () => {
);
const handleSubmit = async (body, actions) => {
trackUsageRef.current(isCreating ? 'willCreateToken' : 'willEditToken');
trackUsageRef.current(isCreating ? 'willCreateToken' : 'willEditToken', {
tokenType: API_TOKEN_TYPE,
});
lockApp();
const lifespanVal =
body.lifespan && parseInt(body.lifespan, 10) && body.lifespan !== '0'
@ -199,6 +204,7 @@ const ApiTokenCreateView = () => {
trackUsageRef.current(isCreating ? 'didCreateToken' : 'didEditToken', {
type: apiToken.type,
tokenType: API_TOKEN_TYPE,
});
} catch (err) {
const errors = formatAPIErrors(err.response.data);
@ -297,7 +303,9 @@ const ApiTokenCreateView = () => {
<ContentLayout>
<Stack spacing={6}>
{Boolean(apiToken?.name) && <TokenBox token={apiToken?.accessKey} />}
{Boolean(apiToken?.name) && (
<TokenBox token={apiToken?.accessKey} tokenType={API_TOKEN_TYPE} />
)}
<FormApiTokenContainer
errors={errors}
onChange={handleChange}

View File

@ -22,6 +22,7 @@ import { Plus } from '@strapi/icons';
import adminPermissions from '../../../../../permissions';
import tableHeaders from './utils/tableHeaders';
import Table from '../../../components/Tokens/Table';
import { API_TOKEN_TYPE } from '../../../components/Tokens/constants';
const ApiTokenListView = () => {
useFocusWhenNavigate();
@ -62,12 +63,14 @@ const ApiTokenListView = () => {
} = useQuery(
['api-tokens'],
async () => {
trackUsage('willAccessTokenList');
trackUsage('willAccessTokenList', {
tokenType: API_TOKEN_TYPE,
});
const {
data: { data },
} = await get(`/admin/api-tokens`);
trackUsage('didAccessTokenList', { number: data.length });
trackUsage('didAccessTokenList', { number: data.length, tokenType: API_TOKEN_TYPE });
return data;
},
@ -127,7 +130,11 @@ const ApiTokenListView = () => {
data-testid="create-api-token-button"
startIcon={<Plus />}
size="S"
onClick={() => trackUsage('willAddTokenFromList')}
onClick={() =>
trackUsage('willAddTokenFromList', {
tokenType: API_TOKEN_TYPE,
})
}
to="/settings/api-tokens/create"
>
{formatMessage({
@ -149,6 +156,7 @@ const ApiTokenListView = () => {
isLoading={isLoading}
onConfirmDelete={(id) => deleteMutation.mutateAsync(id)}
tokens={apiTokens}
tokenType={API_TOKEN_TYPE}
/>
)}
{shouldDisplayNoContentWithCreationButton && (

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useRef, useEffect } from 'react';
import { useIntl } from 'react-intl';
import { Formik } from 'formik';
import { useRouteMatch, useHistory } from 'react-router-dom';
@ -9,6 +9,7 @@ import {
Form,
useOverlayBlocker,
useNotification,
useTracking,
useGuidedTour,
useRBAC,
useFetchClient,
@ -21,6 +22,7 @@ import adminPermissions from '../../../../../permissions';
import FormTransferTokenContainer from './components/FormTransferTokenContainer';
import TokenBox from '../../../components/Tokens/TokenBox';
import FormHead from '../../../components/Tokens/FormHead';
import { TRANSFER_TOKEN_TYPE } from '../../../components/Tokens/constants';
const MSG_ERROR_NAME_TAKEN = 'Name already taken';
@ -37,6 +39,8 @@ const TransferTokenCreateView = () => {
}
: null
);
const { trackUsage } = useTracking();
const trackUsageRef = useRef(trackUsage);
const { setCurrentStep } = useGuidedTour();
const {
allowedActions: { canCreate, canUpdate, canRegenerate },
@ -48,6 +52,12 @@ const TransferTokenCreateView = () => {
const isCreating = id === 'create';
useEffect(() => {
trackUsageRef.current(isCreating ? 'didAddTokenFromList' : 'didEditTokenFromList', {
tokenType: TRANSFER_TOKEN_TYPE,
});
}, [isCreating]);
const { status } = useQuery(
['transfer-token', id],
async () => {
@ -73,6 +83,9 @@ const TransferTokenCreateView = () => {
);
const handleSubmit = async (body, actions) => {
trackUsageRef.current(isCreating ? 'willCreateToken' : 'willEditToken', {
tokenType: TRANSFER_TOKEN_TYPE,
});
lockApp();
const lifespanVal =
body.lifespan && parseInt(body.lifespan, 10) && body.lifespan !== '0'
@ -117,6 +130,11 @@ const TransferTokenCreateView = () => {
defaultMessage: 'Transfer Token successfully edited',
}),
});
trackUsageRef.current(isCreating ? 'didCreateToken' : 'didEditToken', {
type: transferToken?.type,
tokenType: TRANSFER_TOKEN_TYPE,
});
} catch (err) {
const errors = formatAPIErrors(err.response.data);
actions.setErrors(errors);
@ -177,7 +195,9 @@ const TransferTokenCreateView = () => {
/>
<ContentLayout>
<Stack spacing={6}>
{Boolean(transferToken?.name) && <TokenBox token={transferToken?.accessKey} />}
{Boolean(transferToken?.name) && (
<TokenBox token={transferToken?.accessKey} tokenType={TRANSFER_TOKEN_TYPE} />
)}
<FormTransferTokenContainer
errors={errors}
onChange={handleChange}

View File

@ -11,6 +11,7 @@ import {
NoPermissions,
useRBAC,
NoContent,
useTracking,
useGuidedTour,
LinkButton,
useFetchClient,
@ -21,6 +22,7 @@ import { Plus } from '@strapi/icons';
import adminPermissions from '../../../../../permissions';
import tableHeaders from './utils/tableHeaders';
import Table from '../../../components/Tokens/Table';
import { TRANSFER_TOKEN_TYPE } from '../../../components/Tokens/constants';
const TransferTokenListView = () => {
useFocusWhenNavigate();
@ -31,6 +33,7 @@ const TransferTokenListView = () => {
allowedActions: { canCreate, canDelete, canUpdate, canRead },
} = useRBAC(adminPermissions.settings['transfer-tokens']);
const { push } = useHistory();
const { trackUsage } = useTracking();
const { startSection } = useGuidedTour();
const startSectionRef = useRef(startSection);
@ -61,10 +64,15 @@ const TransferTokenListView = () => {
} = useQuery(
['transfer-tokens'],
async () => {
trackUsage('willAccessTokenList', {
tokenType: TRANSFER_TOKEN_TYPE,
});
const {
data: { data },
} = await get(`/admin/transfer/tokens`);
trackUsage('didAccessTokenList', { number: data.length, tokenType: TRANSFER_TOKEN_TYPE });
return data;
},
{
@ -125,6 +133,11 @@ const TransferTokenListView = () => {
data-testid="create-transfer-token-button"
startIcon={<Plus />}
size="S"
onClick={() =>
trackUsage('willAddTokenFromList', {
tokenType: TRANSFER_TOKEN_TYPE,
})
}
to="/settings/transfer-tokens/create"
>
{formatMessage({
@ -146,6 +159,7 @@ const TransferTokenListView = () => {
isLoading={isLoading}
onConfirmDelete={(id) => deleteMutation.mutateAsync(id)}
tokens={transferTokens}
tokenType={TRANSFER_TOKEN_TYPE}
/>
)}
{shouldDisplayNoContentWithCreationButton && (