1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: batch operatsion plausible events (#3367)

This commit is contained in:
Jaanus Sellin 2023-03-22 13:46:16 +02:00 committed by GitHub
parent 180c9336cc
commit 55f8d5b09e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 58 additions and 3 deletions

View File

@ -11,6 +11,7 @@ import { formatUnknownError } from 'utils/formatUnknownError';
import { useFeaturesArchive } from 'hooks/api/getters/useFeaturesArchive/useFeaturesArchive'; import { useFeaturesArchive } from 'hooks/api/getters/useFeaturesArchive/useFeaturesArchive';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import { ArchivedFeatureDeleteConfirm } from './ArchivedFeatureActionCell/ArchivedFeatureDeleteConfirm/ArchivedFeatureDeleteConfirm'; import { ArchivedFeatureDeleteConfirm } from './ArchivedFeatureActionCell/ArchivedFeatureDeleteConfirm/ArchivedFeatureDeleteConfirm';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
interface IArchiveBatchActionsProps { interface IArchiveBatchActionsProps {
selectedIds: string[]; selectedIds: string[];
@ -25,6 +26,7 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
const { refetchArchived } = useFeaturesArchive(projectId); const { refetchArchived } = useFeaturesArchive(projectId);
const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const { trackEvent } = usePlausibleTracker();
const onRevive = async () => { const onRevive = async () => {
try { try {
@ -35,6 +37,11 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({
title: "And we're back!", title: "And we're back!",
text: 'The feature toggles have been revived.', text: 'The feature toggles have been revived.',
}); });
trackEvent('batch_operations', {
props: {
eventType: 'features revived',
},
});
} catch (error: unknown) { } catch (error: unknown) {
setToastApiError(formatUnknownError(error)); setToastApiError(formatUnknownError(error));
} }
@ -76,7 +83,14 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({
projectId={projectId} projectId={projectId}
open={deleteModalOpen} open={deleteModalOpen}
setOpen={setDeleteModalOpen} setOpen={setDeleteModalOpen}
refetch={refetchArchived} refetch={() => {
refetchArchived();
trackEvent('batch_operations', {
props: {
eventType: 'features deleted',
},
});
}}
/> />
</> </>
); );

View File

@ -12,6 +12,7 @@ interface IExportDialogProps {
showExportDialog: boolean; showExportDialog: boolean;
data: Pick<FeatureSchema, 'name'>[]; data: Pick<FeatureSchema, 'name'>[];
onClose: () => void; onClose: () => void;
onConfirm?: () => void;
environments: string[]; environments: string[];
} }
@ -24,6 +25,7 @@ export const ExportDialog = ({
showExportDialog, showExportDialog,
data, data,
onClose, onClose,
onConfirm,
environments, environments,
}: IExportDialogProps) => { }: IExportDialogProps) => {
const [selected, setSelected] = useState(environments[0]); const [selected, setSelected] = useState(environments[0]);
@ -66,6 +68,7 @@ export const ExportDialog = ({
const body = await res.json(); const body = await res.json();
downloadFile(body); downloadFile(body);
onClose(); onClose();
onConfirm?.();
} catch (e: unknown) { } catch (e: unknown) {
setToastApiError(formatUnknownError(e)); setToastApiError(formatUnknownError(e));
} }

View File

@ -5,6 +5,7 @@ import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC';
import { DELETE_FEATURE } from 'component/providers/AccessProvider/permissions'; import { DELETE_FEATURE } from 'component/providers/AccessProvider/permissions';
import useProject from 'hooks/api/getters/useProject/useProject'; import useProject from 'hooks/api/getters/useProject/useProject';
import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog'; import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
interface IArchiveButtonProps { interface IArchiveButtonProps {
projectId: string; projectId: string;
@ -17,10 +18,16 @@ export const ArchiveButton: VFC<IArchiveButtonProps> = ({
}) => { }) => {
const { refetch } = useProject(projectId); const { refetch } = useProject(projectId);
const [isDialogOpen, setIsDialogOpen] = useState(false); const [isDialogOpen, setIsDialogOpen] = useState(false);
const { trackEvent } = usePlausibleTracker();
const onConfirm = async () => { const onConfirm = async () => {
setIsDialogOpen(false); setIsDialogOpen(false);
await refetch(); await refetch();
trackEvent('batch_operations', {
props: {
eventType: 'features archived',
},
});
}; };
return ( return (

View File

@ -10,6 +10,7 @@ import { formatUnknownError } from 'utils/formatUnknownError';
import useProject from 'hooks/api/getters/useProject/useProject'; import useProject from 'hooks/api/getters/useProject/useProject';
import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC'; import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC';
import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions'; import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
interface IManageTagsProps { interface IManageTagsProps {
data: FeatureSchema[]; data: FeatureSchema[];
@ -20,6 +21,7 @@ export const ManageTags: VFC<IManageTagsProps> = ({ projectId, data }) => {
const { bulkUpdateTags } = useTagApi(); const { bulkUpdateTags } = useTagApi();
const { refetch } = useProject(projectId); const { refetch } = useProject(projectId);
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
const { trackEvent } = usePlausibleTracker();
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [initialValues, indeterminateValues] = useMemo(() => { const [initialValues, indeterminateValues] = useMemo(() => {
const uniqueTags = data const uniqueTags = data
@ -77,6 +79,11 @@ export const ManageTags: VFC<IManageTagsProps> = ({ projectId, data }) => {
type: 'success', type: 'success',
autoHideDuration: 12000, autoHideDuration: 12000,
}); });
trackEvent('batch_operations', {
props: {
eventType: 'tags updated',
},
});
} catch (error: unknown) { } catch (error: unknown) {
setToastApiError(formatUnknownError(error)); setToastApiError(formatUnknownError(error));
} }

View File

@ -18,6 +18,7 @@ import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi';
import useProject from 'hooks/api/getters/useProject/useProject'; import useProject from 'hooks/api/getters/useProject/useProject';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError'; import { formatUnknownError } from 'utils/formatUnknownError';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
interface IMoreActionsProps { interface IMoreActionsProps {
projectId: string; projectId: string;
@ -31,6 +32,7 @@ export const MoreActions: VFC<IMoreActionsProps> = ({ projectId, data }) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const { staleFeatures } = useProjectApi(); const { staleFeatures } = useProjectApi();
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
const { trackEvent } = usePlausibleTracker();
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const selectedIds = data.map(({ name }) => name); const selectedIds = data.map(({ name }) => name);
@ -55,6 +57,11 @@ export const MoreActions: VFC<IMoreActionsProps> = ({ projectId, data }) => {
text: 'Feature toggles marked as stale', text: 'Feature toggles marked as stale',
type: 'success', type: 'success',
}); });
trackEvent('batch_operations', {
props: {
eventType: 'features staled',
},
});
} catch (error: unknown) { } catch (error: unknown) {
setToastApiError(formatUnknownError(error)); setToastApiError(formatUnknownError(error));
} }
@ -70,6 +77,11 @@ export const MoreActions: VFC<IMoreActionsProps> = ({ projectId, data }) => {
text: 'Feature toggles unmarked as stale', text: 'Feature toggles unmarked as stale',
type: 'success', type: 'success',
}); });
trackEvent('batch_operations', {
props: {
eventType: 'features unstaled',
},
});
} catch (error: unknown) { } catch (error: unknown) {
setToastApiError(formatUnknownError(error)); setToastApiError(formatUnknownError(error));
} }

View File

@ -1,6 +1,6 @@
import { FC, useMemo, useState } from 'react'; import { FC, useMemo, useState } from 'react';
import { Button } from '@mui/material'; import { Button } from '@mui/material';
import { FileDownload, Label } from '@mui/icons-material'; import { FileDownload } from '@mui/icons-material';
import type { FeatureSchema } from 'openapi'; import type { FeatureSchema } from 'openapi';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ExportDialog } from 'component/feature/FeatureToggleList/ExportDialog'; import { ExportDialog } from 'component/feature/FeatureToggleList/ExportDialog';
@ -8,6 +8,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { ArchiveButton } from './ArchiveButton'; import { ArchiveButton } from './ArchiveButton';
import { MoreActions } from './MoreActions'; import { MoreActions } from './MoreActions';
import { ManageTags } from './ManageTags'; import { ManageTags } from './ManageTags';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
interface IProjectFeaturesBatchActionsProps { interface IProjectFeaturesBatchActionsProps {
selectedIds: string[]; selectedIds: string[];
@ -20,6 +21,7 @@ export const ProjectFeaturesBatchActions: FC<
> = ({ selectedIds, data, projectId }) => { > = ({ selectedIds, data, projectId }) => {
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
const [showExportDialog, setShowExportDialog] = useState(false); const [showExportDialog, setShowExportDialog] = useState(false);
const { trackEvent } = usePlausibleTracker();
const selectedData = useMemo( const selectedData = useMemo(
() => data.filter(d => selectedIds.includes(d.name)), () => data.filter(d => selectedIds.includes(d.name)),
[data, selectedIds] [data, selectedIds]
@ -33,6 +35,14 @@ export const ProjectFeaturesBatchActions: FC<
return Array.from(new Set(envs)); return Array.from(new Set(envs));
}, [selectedData]); }, [selectedData]);
const trackExport = () => {
trackEvent('batch_operations', {
props: {
eventType: 'features exported',
},
});
};
return ( return (
<> <>
<ArchiveButton projectId={projectId} features={selectedIds} /> <ArchiveButton projectId={projectId} features={selectedIds} />
@ -54,6 +64,7 @@ export const ProjectFeaturesBatchActions: FC<
data={selectedData} data={selectedData}
onClose={() => setShowExportDialog(false)} onClose={() => setShowExportDialog(false)}
environments={environments} environments={environments}
onConfirm={trackExport}
/> />
} }
/> />

View File

@ -22,7 +22,8 @@ export type CustomEvents =
| 'export_import' | 'export_import'
| 'project_api_tokens' | 'project_api_tokens'
| 'project_stickiness_set' | 'project_stickiness_set'
| 'notifications'; | 'notifications'
| 'batch_operations';
export const usePlausibleTracker = () => { export const usePlausibleTracker = () => {
const plausible = useContext(PlausibleContext); const plausible = useContext(PlausibleContext);