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:
parent
d1c565735a
commit
fab6fbb756
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 194 KiB |
@ -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';
|
||||
|
@ -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,
|
||||
|
@ -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 },
|
||||
|
@ -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: {
|
||||
|
@ -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 }))
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user