diff --git a/frontend/src/component/archive/ArchiveTable/ArchiveBatchActions.tsx b/frontend/src/component/archive/ArchiveTable/ArchiveBatchActions.tsx index f58ef75995..65983dbf3b 100644 --- a/frontend/src/component/archive/ArchiveTable/ArchiveBatchActions.tsx +++ b/frontend/src/component/archive/ArchiveTable/ArchiveBatchActions.tsx @@ -11,6 +11,7 @@ import { formatUnknownError } from 'utils/formatUnknownError'; import { useFeaturesArchive } from 'hooks/api/getters/useFeaturesArchive/useFeaturesArchive'; import useToast from 'hooks/useToast'; import { ArchivedFeatureDeleteConfirm } from './ArchivedFeatureActionCell/ArchivedFeatureDeleteConfirm/ArchivedFeatureDeleteConfirm'; +import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; interface IArchiveBatchActionsProps { selectedIds: string[]; @@ -25,6 +26,7 @@ export const ArchiveBatchActions: FC = ({ const { setToastData, setToastApiError } = useToast(); const { refetchArchived } = useFeaturesArchive(projectId); const [deleteModalOpen, setDeleteModalOpen] = useState(false); + const { trackEvent } = usePlausibleTracker(); const onRevive = async () => { try { @@ -35,6 +37,11 @@ export const ArchiveBatchActions: FC = ({ title: "And we're back!", text: 'The feature toggles have been revived.', }); + trackEvent('batch_operations', { + props: { + eventType: 'features revived', + }, + }); } catch (error: unknown) { setToastApiError(formatUnknownError(error)); } @@ -76,7 +83,14 @@ export const ArchiveBatchActions: FC = ({ projectId={projectId} open={deleteModalOpen} setOpen={setDeleteModalOpen} - refetch={refetchArchived} + refetch={() => { + refetchArchived(); + trackEvent('batch_operations', { + props: { + eventType: 'features deleted', + }, + }); + }} /> ); diff --git a/frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx b/frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx index 2d8a2a5902..aecac9470f 100644 --- a/frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx +++ b/frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx @@ -12,6 +12,7 @@ interface IExportDialogProps { showExportDialog: boolean; data: Pick[]; onClose: () => void; + onConfirm?: () => void; environments: string[]; } @@ -24,6 +25,7 @@ export const ExportDialog = ({ showExportDialog, data, onClose, + onConfirm, environments, }: IExportDialogProps) => { const [selected, setSelected] = useState(environments[0]); @@ -66,6 +68,7 @@ export const ExportDialog = ({ const body = await res.json(); downloadFile(body); onClose(); + onConfirm?.(); } catch (e: unknown) { setToastApiError(formatUnknownError(e)); } diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ArchiveButton.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ArchiveButton.tsx index e313e084be..82aba301b1 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ArchiveButton.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ArchiveButton.tsx @@ -5,6 +5,7 @@ import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC'; import { DELETE_FEATURE } from 'component/providers/AccessProvider/permissions'; import useProject from 'hooks/api/getters/useProject/useProject'; import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog'; +import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; interface IArchiveButtonProps { projectId: string; @@ -17,10 +18,16 @@ export const ArchiveButton: VFC = ({ }) => { const { refetch } = useProject(projectId); const [isDialogOpen, setIsDialogOpen] = useState(false); + const { trackEvent } = usePlausibleTracker(); const onConfirm = async () => { setIsDialogOpen(false); await refetch(); + trackEvent('batch_operations', { + props: { + eventType: 'features archived', + }, + }); }; return ( diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ManageTags.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ManageTags.tsx index 15c5312e8d..d59ffa7a4f 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ManageTags.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ManageTags.tsx @@ -10,6 +10,7 @@ import { formatUnknownError } from 'utils/formatUnknownError'; import useProject from 'hooks/api/getters/useProject/useProject'; import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC'; import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions'; +import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; interface IManageTagsProps { data: FeatureSchema[]; @@ -20,6 +21,7 @@ export const ManageTags: VFC = ({ projectId, data }) => { const { bulkUpdateTags } = useTagApi(); const { refetch } = useProject(projectId); const { setToastData, setToastApiError } = useToast(); + const { trackEvent } = usePlausibleTracker(); const [isOpen, setIsOpen] = useState(false); const [initialValues, indeterminateValues] = useMemo(() => { const uniqueTags = data @@ -77,6 +79,11 @@ export const ManageTags: VFC = ({ projectId, data }) => { type: 'success', autoHideDuration: 12000, }); + trackEvent('batch_operations', { + props: { + eventType: 'tags updated', + }, + }); } catch (error: unknown) { setToastApiError(formatUnknownError(error)); } diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/MoreActions.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/MoreActions.tsx index 259cff1253..8a1fbc445b 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/MoreActions.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/MoreActions.tsx @@ -18,6 +18,7 @@ import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; import useProject from 'hooks/api/getters/useProject/useProject'; import useToast from 'hooks/useToast'; import { formatUnknownError } from 'utils/formatUnknownError'; +import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; interface IMoreActionsProps { projectId: string; @@ -31,6 +32,7 @@ export const MoreActions: VFC = ({ projectId, data }) => { const [anchorEl, setAnchorEl] = useState(null); const { staleFeatures } = useProjectApi(); const { setToastData, setToastApiError } = useToast(); + const { trackEvent } = usePlausibleTracker(); const open = Boolean(anchorEl); const selectedIds = data.map(({ name }) => name); @@ -55,6 +57,11 @@ export const MoreActions: VFC = ({ projectId, data }) => { text: 'Feature toggles marked as stale', type: 'success', }); + trackEvent('batch_operations', { + props: { + eventType: 'features staled', + }, + }); } catch (error: unknown) { setToastApiError(formatUnknownError(error)); } @@ -70,6 +77,11 @@ export const MoreActions: VFC = ({ projectId, data }) => { text: 'Feature toggles unmarked as stale', type: 'success', }); + trackEvent('batch_operations', { + props: { + eventType: 'features unstaled', + }, + }); } catch (error: unknown) { setToastApiError(formatUnknownError(error)); } diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ProjectFeaturesBatchActions.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ProjectFeaturesBatchActions.tsx index 2390aabe3a..b8902f4280 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ProjectFeaturesBatchActions.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeaturesBatchActions/ProjectFeaturesBatchActions.tsx @@ -1,6 +1,6 @@ import { FC, useMemo, useState } from 'react'; import { Button } from '@mui/material'; -import { FileDownload, Label } from '@mui/icons-material'; +import { FileDownload } from '@mui/icons-material'; import type { FeatureSchema } from 'openapi'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { ExportDialog } from 'component/feature/FeatureToggleList/ExportDialog'; @@ -8,6 +8,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit import { ArchiveButton } from './ArchiveButton'; import { MoreActions } from './MoreActions'; import { ManageTags } from './ManageTags'; +import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; interface IProjectFeaturesBatchActionsProps { selectedIds: string[]; @@ -20,6 +21,7 @@ export const ProjectFeaturesBatchActions: FC< > = ({ selectedIds, data, projectId }) => { const { uiConfig } = useUiConfig(); const [showExportDialog, setShowExportDialog] = useState(false); + const { trackEvent } = usePlausibleTracker(); const selectedData = useMemo( () => data.filter(d => selectedIds.includes(d.name)), [data, selectedIds] @@ -33,6 +35,14 @@ export const ProjectFeaturesBatchActions: FC< return Array.from(new Set(envs)); }, [selectedData]); + const trackExport = () => { + trackEvent('batch_operations', { + props: { + eventType: 'features exported', + }, + }); + }; + return ( <> @@ -54,6 +64,7 @@ export const ProjectFeaturesBatchActions: FC< data={selectedData} onClose={() => setShowExportDialog(false)} environments={environments} + onConfirm={trackExport} /> } /> diff --git a/frontend/src/hooks/usePlausibleTracker.ts b/frontend/src/hooks/usePlausibleTracker.ts index 32c90b5420..63a1c92c88 100644 --- a/frontend/src/hooks/usePlausibleTracker.ts +++ b/frontend/src/hooks/usePlausibleTracker.ts @@ -22,7 +22,8 @@ export type CustomEvents = | 'export_import' | 'project_api_tokens' | 'project_stickiness_set' - | 'notifications'; + | 'notifications' + | 'batch_operations'; export const usePlausibleTracker = () => { const plausible = useContext(PlausibleContext);