1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-26 01:17:00 +02:00

Change request event tracking (#2570)

This commit is contained in:
Mateusz Kwasniewski 2022-11-30 12:04:29 +01:00 committed by GitHub
parent d1c565735a
commit fab6fbb756
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 115 additions and 129 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 194 KiB

View File

@ -1,4 +1,4 @@
import { Alert, Button, styled } from '@mui/material';
import { Alert, Button, styled, Typography } from '@mui/material';
import { FC, useContext, useState } from 'react';
import { Box } from '@mui/material';
import { useChangeRequest } from 'hooks/api/getters/useChangeRequest/useChangeRequest';

View File

@ -41,7 +41,7 @@ export const FeatureStrategyCreate = () => {
const errors = useFormErrors();
const { addStrategyToFeature, loading } = useFeatureStrategyApi();
const { addChangeRequest } = useChangeRequestApi();
const { addChange } = useChangeRequestApi();
const { setToastData, setToastApiError } = useToast();
const { uiConfig } = useUiConfig();
const { unleashUrl } = uiConfig;
@ -98,7 +98,7 @@ export const FeatureStrategyCreate = () => {
};
const onStrategyRequestAdd = async (payload: IFeatureStrategyPayload) => {
await addChangeRequest(projectId, environmentId, {
await addChange(projectId, environmentId, {
action: 'addStrategy',
feature: featureId,
payload,

View File

@ -43,7 +43,7 @@ export const FeatureStrategyEdit = () => {
const { uiConfig } = useUiConfig();
const { unleashUrl } = uiConfig;
const navigate = useNavigate();
const { addChangeRequest } = useChangeRequestApi();
const { addChange } = useChangeRequestApi();
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
const { refetch: refetchChangeRequests } =
usePendingChangeRequests(projectId);
@ -110,7 +110,7 @@ export const FeatureStrategyEdit = () => {
};
const onStrategyRequestEdit = async (payload: IFeatureStrategyPayload) => {
await addChangeRequest(projectId, environmentId, {
await addChange(projectId, environmentId, {
action: 'updateStrategy',
feature: featureId,
payload: { ...payload, id: strategyId },

View File

@ -130,14 +130,14 @@ const useOnSuggestRemove = ({
environmentId,
strategyId,
}: IRemoveProps) => {
const { addChangeRequest } = useChangeRequestApi();
const { addChange } = useChangeRequestApi();
const { refetch: refetchChangeRequests } =
usePendingChangeRequests(projectId);
const { setToastData, setToastApiError } = useToast();
const onSuggestRemove = async (event: React.FormEvent) => {
try {
event.preventDefault();
await addChangeRequest(projectId, environmentId, {
await addChange(projectId, environmentId, {
action: 'deleteStrategy',
feature: featureId,
payload: {

View File

@ -29,6 +29,7 @@ import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
import { KeyboardArrowDownOutlined } from '@mui/icons-material';
import { useTheme } from '@mui/material/styles';
import AccessContext from 'contexts/AccessContext';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
const StyledBox = styled(Box)(({ theme }) => ({
padding: theme.spacing(1),
@ -40,6 +41,7 @@ const StyledBox = styled(Box)(({ theme }) => ({
}));
export const ChangeRequestConfiguration: VFC = () => {
const { trackEvent } = usePlausibleTracker();
const [dialogState, setDialogState] = useState<{
isOpen: boolean;
enableEnvironment: string;
@ -256,7 +258,17 @@ export const ChangeRequestConfiguration: VFC = () => {
</Table>
<Dialogue
onClick={() => onConfirm()}
onClick={() => {
trackEvent('change_request', {
props: {
eventType: `change request ${
!dialogState.isEnabled ? 'enabled' : 'disabled'
}`,
},
});
onConfirm();
}}
open={dialogState.isOpen}
onClose={() =>
setDialogState(state => ({ ...state, isOpen: false }))

View File

@ -31,8 +31,12 @@ export const ChangeRequestProcessHelp: VFC<
</Typography>
}
/>
<IconButton title="Change request process" ref={ref}>
<HelpOutline onClick={() => setIsOpen(true)} />
<IconButton
title="Change request process"
ref={ref}
onClick={() => setIsOpen(true)}
>
<HelpOutline />
</IconButton>
<Popover
open={isOpen}
@ -64,20 +68,20 @@ export const ChangeRequestProcessHelp: VFC<
<li>
These changes can be seen by everyone but only
who has <strong>Review change request</strong>{' '}
permission can Approve or Reject them
permission can Approve them
</li>
<ul>
<li>
If changes are Approved then someone who has
If changes are Approved then someone who has{' '}
<strong>Apply change request</strong>{' '}
permission needs to apply these changes to
be live on the feature toggles and request
is Closed
</li>
<li>
If changes are Rejected then these goes
automatically to Cancelled and request is
Closed.
If changes are Cancelled by the author or
admin then change request goes automatically
to Cancelled and request is Closed.
</li>
</ul>
</ol>

View File

@ -1,6 +1,7 @@
import useAPI from '../useApi/useApi';
import { usePlausibleTracker } from '../../../usePlausibleTracker';
export interface IChangeRequestsSchema {
export interface IChangeSchema {
feature: string;
action:
| 'updateEnabled'
@ -18,15 +19,22 @@ export interface IChangeRequestConfig {
}
export const useChangeRequestApi = () => {
const { trackEvent } = usePlausibleTracker();
const { makeRequest, createRequest, errors, loading } = useAPI({
propagateErrors: true,
});
const addChangeRequest = async (
const addChange = async (
project: string,
environment: string,
payload: IChangeRequestsSchema
payload: IChangeSchema
) => {
trackEvent('change_request', {
props: {
eventType: 'change added',
},
});
const path = `api/admin/projects/${project}/environments/${environment}/change-requests`;
const req = createRequest(path, {
method: 'POST',
@ -43,8 +51,14 @@ export const useChangeRequestApi = () => {
const changeState = async (
project: string,
changeRequestId: number,
payload: any
payload: { state: 'Approved' | 'Applied' | 'Cancelled' | 'In review' }
) => {
trackEvent('change_request', {
props: {
eventType: payload.state,
},
});
const path = `api/admin/projects/${project}/change-requests/${changeRequestId}/state`;
const req = createRequest(path, {
method: 'PUT',
@ -114,6 +128,12 @@ export const useChangeRequestApi = () => {
changeRequestId: string,
text: string
) => {
trackEvent('change_request', {
props: {
eventType: 'comment added',
},
});
const path = `/api/admin/projects/${projectId}/change-requests/${changeRequestId}/comments`;
const req = createRequest(path, {
method: 'POST',
@ -128,7 +148,7 @@ export const useChangeRequestApi = () => {
};
return {
addChangeRequest,
addChange,
changeState,
discardChange,
updateChangeRequestEnvironmentConfig,

View File

@ -16,7 +16,7 @@ export const useChangeRequestAddStrategy = (
action: ChangeRequestStrategyAction
) => {
const { setToastData, setToastApiError } = useToast();
const { addChangeRequest } = useChangeRequestApi();
const { addChange } = useChangeRequestApi();
const { refetch } = usePendingChangeRequests(project);
const [changeRequestDialogDetails, setChangeRequestDialogDetails] =
@ -69,15 +69,11 @@ export const useChangeRequestAddStrategy = (
const onChangeRequestAddStrategyConfirm = useCallback(async () => {
try {
await addChangeRequest(
project,
changeRequestDialogDetails.environment!,
{
await addChange(project, changeRequestDialogDetails.environment!, {
feature: changeRequestDialogDetails.featureName!,
action: action,
payload: changeRequestDialogDetails.strategy!,
}
);
});
refetch();
setChangeRequestDialogDetails({ isOpen: false });
setToastData({
@ -88,13 +84,13 @@ export const useChangeRequestAddStrategy = (
setToastApiError(formatUnknownError(error));
setChangeRequestDialogDetails({ isOpen: false });
}
}, [addChangeRequest]);
}, [addChange]);
const onChangeRequestAddStrategiesConfirm = useCallback(async () => {
try {
await Promise.all(
changeRequestDialogDetails.strategies!.map(strategy => {
return addChangeRequest(
return addChange(
project,
changeRequestDialogDetails.environment!,
{
@ -115,7 +111,7 @@ export const useChangeRequestAddStrategy = (
setToastApiError(formatUnknownError(error));
setChangeRequestDialogDetails({ isOpen: false });
}
}, [addChangeRequest]);
}, [addChange]);
return {
onChangeRequestAddStrategy,

View File

@ -6,7 +6,7 @@ import { usePendingChangeRequests } from './api/getters/usePendingChangeRequests
export const useChangeRequestToggle = (project: string) => {
const { setToastData, setToastApiError } = useToast();
const { addChangeRequest } = useChangeRequestApi();
const { addChange } = useChangeRequestApi();
const { refetch: refetchChangeRequests } =
usePendingChangeRequests(project);
@ -36,17 +36,13 @@ export const useChangeRequestToggle = (project: string) => {
const onChangeRequestToggleConfirm = useCallback(async () => {
try {
await addChangeRequest(
project,
changeRequestDialogDetails.environment!,
{
await addChange(project, changeRequestDialogDetails.environment!, {
feature: changeRequestDialogDetails.featureName!,
action: 'updateEnabled',
payload: {
enabled: Boolean(changeRequestDialogDetails.enabled),
},
}
);
});
refetchChangeRequests();
setChangeRequestDialogDetails(prev => ({ ...prev, isOpen: false }));
setToastData({
@ -57,7 +53,7 @@ export const useChangeRequestToggle = (project: string) => {
setToastApiError(formatUnknownError(error));
setChangeRequestDialogDetails(prev => ({ ...prev, isOpen: false }));
}
}, [addChangeRequest]);
}, [addChange]);
return {
onChangeRequestToggle,

View File

@ -8,7 +8,7 @@ import { EventOptions, PlausibleOptions } from 'plausible-tracker';
* @see https://plausible.io/docs/custom-event-goals#2-create-a-custom-event-goal-in-your-plausible-analytics-account
* @example `'download | 'invite' | 'signup'`
**/
type CustomEvents = 'invite' | 'upgrade_plan_clicked';
type CustomEvents = 'invite' | 'upgrade_plan_clicked' | 'change_request';
export const usePlausibleTracker = () => {
const plausible = useContext(PlausibleContext);