mirror of
https://github.com/strapi/strapi.git
synced 2025-09-27 01:09:49 +00:00
Merge pull request #15837 from strapi/data-transfer/tracking-api-token-transfer-token
This commit is contained in:
commit
3d6a31eb08
@ -5,13 +5,15 @@ import { useTracking, ConfirmDialog } from '@strapi/helper-plugin';
|
|||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const DeleteButton = ({ tokenName, onClickDelete }) => {
|
const DeleteButton = ({ tokenName, onClickDelete, tokenType }) => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const { trackUsage } = useTracking(); // TODO: Track different types of tokens
|
const { trackUsage } = useTracking();
|
||||||
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
||||||
const handleClickDelete = () => {
|
const handleClickDelete = () => {
|
||||||
setShowConfirmDialog(false);
|
setShowConfirmDialog(false);
|
||||||
trackUsage('willDeleteToken');
|
trackUsage('willDeleteToken', {
|
||||||
|
tokenType,
|
||||||
|
});
|
||||||
onClickDelete();
|
onClickDelete();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ const DeleteButton = ({ tokenName, onClickDelete }) => {
|
|||||||
DeleteButton.propTypes = {
|
DeleteButton.propTypes = {
|
||||||
tokenName: PropTypes.string.isRequired,
|
tokenName: PropTypes.string.isRequired,
|
||||||
onClickDelete: PropTypes.func.isRequired,
|
onClickDelete: PropTypes.func.isRequired,
|
||||||
|
tokenType: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DeleteButton;
|
export default DeleteButton;
|
||||||
|
@ -16,7 +16,12 @@ function ComponentToTest(props) {
|
|||||||
<IntlProvider locale="en" messages={{}}>
|
<IntlProvider locale="en" messages={{}}>
|
||||||
<ThemeProvider theme={lightTheme}>
|
<ThemeProvider theme={lightTheme}>
|
||||||
<NotificationsProvider toggleNotification={() => {}}>
|
<NotificationsProvider toggleNotification={() => {}}>
|
||||||
<DeleteButton tokenName="test" onClickDelete={() => {}} {...props} />
|
<DeleteButton
|
||||||
|
tokenType="api-token"
|
||||||
|
tokenName="test"
|
||||||
|
onClickDelete={() => {}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
</NotificationsProvider>
|
</NotificationsProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
|
@ -14,7 +14,15 @@ import DeleteButton from './DeleteButton';
|
|||||||
import UpdateButton from './UpdateButton';
|
import UpdateButton from './UpdateButton';
|
||||||
import ReadButton from './ReadButton';
|
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 { canDelete, canUpdate, canRead } = permissions;
|
||||||
const withBulkActions = canDelete || canUpdate || canRead;
|
const withBulkActions = canDelete || canUpdate || canRead;
|
||||||
const [{ query }] = useQueryParams();
|
const [{ query }] = useQueryParams();
|
||||||
@ -47,7 +55,9 @@ const Table = ({ permissions, headers, contentType, isLoading, tokens, onConfirm
|
|||||||
key={token.id}
|
key={token.id}
|
||||||
{...onRowClick({
|
{...onRowClick({
|
||||||
fn() {
|
fn() {
|
||||||
trackUsage('willEditTokenFromList');
|
trackUsage('willEditTokenFromList', {
|
||||||
|
tokenType,
|
||||||
|
});
|
||||||
push(`${pathname}/${token.id}`);
|
push(`${pathname}/${token.id}`);
|
||||||
},
|
},
|
||||||
condition: canUpdate,
|
condition: canUpdate,
|
||||||
@ -87,6 +97,7 @@ const Table = ({ permissions, headers, contentType, isLoading, tokens, onConfirm
|
|||||||
<DeleteButton
|
<DeleteButton
|
||||||
tokenName={token.name}
|
tokenName={token.name}
|
||||||
onClickDelete={() => onConfirmDelete(token.id)}
|
onClickDelete={() => onConfirmDelete(token.id)}
|
||||||
|
tokenType={tokenType}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -121,6 +132,7 @@ Table.propTypes = {
|
|||||||
contentType: PropTypes.string.isRequired,
|
contentType: PropTypes.string.isRequired,
|
||||||
isLoading: PropTypes.bool,
|
isLoading: PropTypes.bool,
|
||||||
onConfirmDelete: PropTypes.func,
|
onConfirmDelete: PropTypes.func,
|
||||||
|
tokenType: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
Table.defaultProps = {
|
Table.defaultProps = {
|
||||||
|
@ -6,7 +6,7 @@ import { Duplicate, Key } from '@strapi/icons';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||||
|
|
||||||
const TokenBox = ({ token }) => {
|
const TokenBox = ({ token, tokenType }) => {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const toggleNotification = useNotification();
|
const toggleNotification = useNotification();
|
||||||
const { trackUsage } = useTracking(); // TODO: Track different types of tokens
|
const { trackUsage } = useTracking(); // TODO: Track different types of tokens
|
||||||
@ -19,7 +19,9 @@ const TokenBox = ({ token }) => {
|
|||||||
<span style={{ alignSelf: 'start' }}>
|
<span style={{ alignSelf: 'start' }}>
|
||||||
<CopyToClipboard
|
<CopyToClipboard
|
||||||
onCopy={() => {
|
onCopy={() => {
|
||||||
trackUsageRef.current('didCopyTokenKey');
|
trackUsageRef.current('didCopyTokenKey', {
|
||||||
|
tokenType,
|
||||||
|
});
|
||||||
toggleNotification({
|
toggleNotification({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: { id: 'Settings.tokens.notification.copied' },
|
message: { id: 'Settings.tokens.notification.copied' },
|
||||||
@ -70,6 +72,7 @@ TokenBox.defaultProps = {
|
|||||||
|
|
||||||
TokenBox.propTypes = {
|
TokenBox.propTypes = {
|
||||||
token: PropTypes.string,
|
token: PropTypes.string,
|
||||||
|
tokenType: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TokenBox;
|
export default TokenBox;
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
export const API_TOKEN_TYPE = 'api-token';
|
||||||
|
export const TRANSFER_TOKEN_TYPE = 'transfer-token';
|
@ -26,6 +26,7 @@ import Permissions from './components/Permissions';
|
|||||||
import FormApiTokenContainer from './components/FormApiTokenContainer';
|
import FormApiTokenContainer from './components/FormApiTokenContainer';
|
||||||
import TokenBox from '../../../components/Tokens/TokenBox';
|
import TokenBox from '../../../components/Tokens/TokenBox';
|
||||||
import FormHead from '../../../components/Tokens/FormHead';
|
import FormHead from '../../../components/Tokens/FormHead';
|
||||||
|
import { API_TOKEN_TYPE } from '../../../components/Tokens/constants';
|
||||||
|
|
||||||
const MSG_ERROR_NAME_TAKEN = 'Name already taken';
|
const MSG_ERROR_NAME_TAKEN = 'Name already taken';
|
||||||
|
|
||||||
@ -107,7 +108,9 @@ const ApiTokenCreateView = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
trackUsageRef.current(isCreating ? 'didAddTokenFromList' : 'didEditTokenFromList');
|
trackUsageRef.current(isCreating ? 'didAddTokenFromList' : 'didEditTokenFromList', {
|
||||||
|
tokenType: API_TOKEN_TYPE,
|
||||||
|
});
|
||||||
}, [isCreating]);
|
}, [isCreating]);
|
||||||
|
|
||||||
const { status } = useQuery(
|
const { status } = useQuery(
|
||||||
@ -152,7 +155,9 @@ const ApiTokenCreateView = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleSubmit = async (body, actions) => {
|
const handleSubmit = async (body, actions) => {
|
||||||
trackUsageRef.current(isCreating ? 'willCreateToken' : 'willEditToken');
|
trackUsageRef.current(isCreating ? 'willCreateToken' : 'willEditToken', {
|
||||||
|
tokenType: API_TOKEN_TYPE,
|
||||||
|
});
|
||||||
lockApp();
|
lockApp();
|
||||||
const lifespanVal =
|
const lifespanVal =
|
||||||
body.lifespan && parseInt(body.lifespan, 10) && body.lifespan !== '0'
|
body.lifespan && parseInt(body.lifespan, 10) && body.lifespan !== '0'
|
||||||
@ -199,6 +204,7 @@ const ApiTokenCreateView = () => {
|
|||||||
|
|
||||||
trackUsageRef.current(isCreating ? 'didCreateToken' : 'didEditToken', {
|
trackUsageRef.current(isCreating ? 'didCreateToken' : 'didEditToken', {
|
||||||
type: apiToken.type,
|
type: apiToken.type,
|
||||||
|
tokenType: API_TOKEN_TYPE,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errors = formatAPIErrors(err.response.data);
|
const errors = formatAPIErrors(err.response.data);
|
||||||
@ -297,7 +303,9 @@ const ApiTokenCreateView = () => {
|
|||||||
|
|
||||||
<ContentLayout>
|
<ContentLayout>
|
||||||
<Stack spacing={6}>
|
<Stack spacing={6}>
|
||||||
{Boolean(apiToken?.name) && <TokenBox token={apiToken?.accessKey} />}
|
{Boolean(apiToken?.name) && (
|
||||||
|
<TokenBox token={apiToken?.accessKey} tokenType={API_TOKEN_TYPE} />
|
||||||
|
)}
|
||||||
<FormApiTokenContainer
|
<FormApiTokenContainer
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
@ -22,6 +22,7 @@ import { Plus } from '@strapi/icons';
|
|||||||
import adminPermissions from '../../../../../permissions';
|
import adminPermissions from '../../../../../permissions';
|
||||||
import tableHeaders from './utils/tableHeaders';
|
import tableHeaders from './utils/tableHeaders';
|
||||||
import Table from '../../../components/Tokens/Table';
|
import Table from '../../../components/Tokens/Table';
|
||||||
|
import { API_TOKEN_TYPE } from '../../../components/Tokens/constants';
|
||||||
|
|
||||||
const ApiTokenListView = () => {
|
const ApiTokenListView = () => {
|
||||||
useFocusWhenNavigate();
|
useFocusWhenNavigate();
|
||||||
@ -62,12 +63,14 @@ const ApiTokenListView = () => {
|
|||||||
} = useQuery(
|
} = useQuery(
|
||||||
['api-tokens'],
|
['api-tokens'],
|
||||||
async () => {
|
async () => {
|
||||||
trackUsage('willAccessTokenList');
|
trackUsage('willAccessTokenList', {
|
||||||
|
tokenType: API_TOKEN_TYPE,
|
||||||
|
});
|
||||||
const {
|
const {
|
||||||
data: { data },
|
data: { data },
|
||||||
} = await get(`/admin/api-tokens`);
|
} = await get(`/admin/api-tokens`);
|
||||||
|
|
||||||
trackUsage('didAccessTokenList', { number: data.length });
|
trackUsage('didAccessTokenList', { number: data.length, tokenType: API_TOKEN_TYPE });
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
@ -127,7 +130,11 @@ const ApiTokenListView = () => {
|
|||||||
data-testid="create-api-token-button"
|
data-testid="create-api-token-button"
|
||||||
startIcon={<Plus />}
|
startIcon={<Plus />}
|
||||||
size="S"
|
size="S"
|
||||||
onClick={() => trackUsage('willAddTokenFromList')}
|
onClick={() =>
|
||||||
|
trackUsage('willAddTokenFromList', {
|
||||||
|
tokenType: API_TOKEN_TYPE,
|
||||||
|
})
|
||||||
|
}
|
||||||
to="/settings/api-tokens/create"
|
to="/settings/api-tokens/create"
|
||||||
>
|
>
|
||||||
{formatMessage({
|
{formatMessage({
|
||||||
@ -149,6 +156,7 @@ const ApiTokenListView = () => {
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onConfirmDelete={(id) => deleteMutation.mutateAsync(id)}
|
onConfirmDelete={(id) => deleteMutation.mutateAsync(id)}
|
||||||
tokens={apiTokens}
|
tokens={apiTokens}
|
||||||
|
tokenType={API_TOKEN_TYPE}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{shouldDisplayNoContentWithCreationButton && (
|
{shouldDisplayNoContentWithCreationButton && (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
import { useRouteMatch, useHistory } from 'react-router-dom';
|
import { useRouteMatch, useHistory } from 'react-router-dom';
|
||||||
@ -9,6 +9,7 @@ import {
|
|||||||
Form,
|
Form,
|
||||||
useOverlayBlocker,
|
useOverlayBlocker,
|
||||||
useNotification,
|
useNotification,
|
||||||
|
useTracking,
|
||||||
useGuidedTour,
|
useGuidedTour,
|
||||||
useRBAC,
|
useRBAC,
|
||||||
useFetchClient,
|
useFetchClient,
|
||||||
@ -21,6 +22,7 @@ import adminPermissions from '../../../../../permissions';
|
|||||||
import FormTransferTokenContainer from './components/FormTransferTokenContainer';
|
import FormTransferTokenContainer from './components/FormTransferTokenContainer';
|
||||||
import TokenBox from '../../../components/Tokens/TokenBox';
|
import TokenBox from '../../../components/Tokens/TokenBox';
|
||||||
import FormHead from '../../../components/Tokens/FormHead';
|
import FormHead from '../../../components/Tokens/FormHead';
|
||||||
|
import { TRANSFER_TOKEN_TYPE } from '../../../components/Tokens/constants';
|
||||||
|
|
||||||
const MSG_ERROR_NAME_TAKEN = 'Name already taken';
|
const MSG_ERROR_NAME_TAKEN = 'Name already taken';
|
||||||
|
|
||||||
@ -37,6 +39,8 @@ const TransferTokenCreateView = () => {
|
|||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
const { trackUsage } = useTracking();
|
||||||
|
const trackUsageRef = useRef(trackUsage);
|
||||||
const { setCurrentStep } = useGuidedTour();
|
const { setCurrentStep } = useGuidedTour();
|
||||||
const {
|
const {
|
||||||
allowedActions: { canCreate, canUpdate, canRegenerate },
|
allowedActions: { canCreate, canUpdate, canRegenerate },
|
||||||
@ -48,6 +52,12 @@ const TransferTokenCreateView = () => {
|
|||||||
|
|
||||||
const isCreating = id === 'create';
|
const isCreating = id === 'create';
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
trackUsageRef.current(isCreating ? 'didAddTokenFromList' : 'didEditTokenFromList', {
|
||||||
|
tokenType: TRANSFER_TOKEN_TYPE,
|
||||||
|
});
|
||||||
|
}, [isCreating]);
|
||||||
|
|
||||||
const { status } = useQuery(
|
const { status } = useQuery(
|
||||||
['transfer-token', id],
|
['transfer-token', id],
|
||||||
async () => {
|
async () => {
|
||||||
@ -73,6 +83,9 @@ const TransferTokenCreateView = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleSubmit = async (body, actions) => {
|
const handleSubmit = async (body, actions) => {
|
||||||
|
trackUsageRef.current(isCreating ? 'willCreateToken' : 'willEditToken', {
|
||||||
|
tokenType: TRANSFER_TOKEN_TYPE,
|
||||||
|
});
|
||||||
lockApp();
|
lockApp();
|
||||||
const lifespanVal =
|
const lifespanVal =
|
||||||
body.lifespan && parseInt(body.lifespan, 10) && body.lifespan !== '0'
|
body.lifespan && parseInt(body.lifespan, 10) && body.lifespan !== '0'
|
||||||
@ -117,6 +130,11 @@ const TransferTokenCreateView = () => {
|
|||||||
defaultMessage: 'Transfer Token successfully edited',
|
defaultMessage: 'Transfer Token successfully edited',
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
trackUsageRef.current(isCreating ? 'didCreateToken' : 'didEditToken', {
|
||||||
|
type: transferToken?.type,
|
||||||
|
tokenType: TRANSFER_TOKEN_TYPE,
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errors = formatAPIErrors(err.response.data);
|
const errors = formatAPIErrors(err.response.data);
|
||||||
actions.setErrors(errors);
|
actions.setErrors(errors);
|
||||||
@ -177,7 +195,9 @@ const TransferTokenCreateView = () => {
|
|||||||
/>
|
/>
|
||||||
<ContentLayout>
|
<ContentLayout>
|
||||||
<Stack spacing={6}>
|
<Stack spacing={6}>
|
||||||
{Boolean(transferToken?.name) && <TokenBox token={transferToken?.accessKey} />}
|
{Boolean(transferToken?.name) && (
|
||||||
|
<TokenBox token={transferToken?.accessKey} tokenType={TRANSFER_TOKEN_TYPE} />
|
||||||
|
)}
|
||||||
<FormTransferTokenContainer
|
<FormTransferTokenContainer
|
||||||
errors={errors}
|
errors={errors}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
NoPermissions,
|
NoPermissions,
|
||||||
useRBAC,
|
useRBAC,
|
||||||
NoContent,
|
NoContent,
|
||||||
|
useTracking,
|
||||||
useGuidedTour,
|
useGuidedTour,
|
||||||
LinkButton,
|
LinkButton,
|
||||||
useFetchClient,
|
useFetchClient,
|
||||||
@ -21,6 +22,7 @@ import { Plus } from '@strapi/icons';
|
|||||||
import adminPermissions from '../../../../../permissions';
|
import adminPermissions from '../../../../../permissions';
|
||||||
import tableHeaders from './utils/tableHeaders';
|
import tableHeaders from './utils/tableHeaders';
|
||||||
import Table from '../../../components/Tokens/Table';
|
import Table from '../../../components/Tokens/Table';
|
||||||
|
import { TRANSFER_TOKEN_TYPE } from '../../../components/Tokens/constants';
|
||||||
|
|
||||||
const TransferTokenListView = () => {
|
const TransferTokenListView = () => {
|
||||||
useFocusWhenNavigate();
|
useFocusWhenNavigate();
|
||||||
@ -31,6 +33,7 @@ const TransferTokenListView = () => {
|
|||||||
allowedActions: { canCreate, canDelete, canUpdate, canRead },
|
allowedActions: { canCreate, canDelete, canUpdate, canRead },
|
||||||
} = useRBAC(adminPermissions.settings['transfer-tokens']);
|
} = useRBAC(adminPermissions.settings['transfer-tokens']);
|
||||||
const { push } = useHistory();
|
const { push } = useHistory();
|
||||||
|
const { trackUsage } = useTracking();
|
||||||
|
|
||||||
const { startSection } = useGuidedTour();
|
const { startSection } = useGuidedTour();
|
||||||
const startSectionRef = useRef(startSection);
|
const startSectionRef = useRef(startSection);
|
||||||
@ -61,10 +64,15 @@ const TransferTokenListView = () => {
|
|||||||
} = useQuery(
|
} = useQuery(
|
||||||
['transfer-tokens'],
|
['transfer-tokens'],
|
||||||
async () => {
|
async () => {
|
||||||
|
trackUsage('willAccessTokenList', {
|
||||||
|
tokenType: TRANSFER_TOKEN_TYPE,
|
||||||
|
});
|
||||||
const {
|
const {
|
||||||
data: { data },
|
data: { data },
|
||||||
} = await get(`/admin/transfer/tokens`);
|
} = await get(`/admin/transfer/tokens`);
|
||||||
|
|
||||||
|
trackUsage('didAccessTokenList', { number: data.length, tokenType: TRANSFER_TOKEN_TYPE });
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -125,6 +133,11 @@ const TransferTokenListView = () => {
|
|||||||
data-testid="create-transfer-token-button"
|
data-testid="create-transfer-token-button"
|
||||||
startIcon={<Plus />}
|
startIcon={<Plus />}
|
||||||
size="S"
|
size="S"
|
||||||
|
onClick={() =>
|
||||||
|
trackUsage('willAddTokenFromList', {
|
||||||
|
tokenType: TRANSFER_TOKEN_TYPE,
|
||||||
|
})
|
||||||
|
}
|
||||||
to="/settings/transfer-tokens/create"
|
to="/settings/transfer-tokens/create"
|
||||||
>
|
>
|
||||||
{formatMessage({
|
{formatMessage({
|
||||||
@ -146,6 +159,7 @@ const TransferTokenListView = () => {
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onConfirmDelete={(id) => deleteMutation.mutateAsync(id)}
|
onConfirmDelete={(id) => deleteMutation.mutateAsync(id)}
|
||||||
tokens={transferTokens}
|
tokens={transferTokens}
|
||||||
|
tokenType={TRANSFER_TOKEN_TYPE}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{shouldDisplayNoContentWithCreationButton && (
|
{shouldDisplayNoContentWithCreationButton && (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user