From 03869109e0dcc7887da2ad4440a663c9c3ca508e Mon Sep 17 00:00:00 2001 From: RitaDias Date: Wed, 4 Sep 2024 14:10:55 +0200 Subject: [PATCH] feat(sanity): add telemetry for versions (#7460) * fix(sanity): issue where the createVersionSuccess was never resolving * feat(sanity): add telemetry when adding version * refactor(sanity): rename bundles to releases telemetry * feat(sanity): add telemetry when creating release * feat(sanity): add telemetry when updating release * feat(sanity): add telemetry when deleting release * feat(sanity): add telemetry when publishing release * feat(sanity): add telemetry when archive and unarchive release * chore(sanity): fix dependencies * feat(sanity): add telemetry when creating a draft * refactor(sanity): add telemetry for tracking drafts and include version * refactor(sanity): update telemetry request for creating release * refactor(sanity): reuse interface for OriginInfo * docs(sanity): clarify unarchive / archive telemetry track --- .../__telemetry__/releases.telemetry.ts | 84 +++++++++++++++++++ .../components/dialog/BundleDetailsDialog.tsx | 15 +++- .../components/panes/BundleActions.tsx | 22 ++++- .../BundleMenuButton/BundleMenuButton.tsx | 16 ++++ .../ReleasePublishAllButton.tsx | 6 +- .../tool/overview/ReleasesOverview.tsx | 1 + .../perspective/GlobalPerspectiveMenu.tsx | 2 +- .../panes/document/DocumentPaneProvider.tsx | 2 +- 8 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 packages/sanity/src/core/bundles/__telemetry__/releases.telemetry.ts diff --git a/packages/sanity/src/core/bundles/__telemetry__/releases.telemetry.ts b/packages/sanity/src/core/bundles/__telemetry__/releases.telemetry.ts new file mode 100644 index 00000000000..35b678ed4de --- /dev/null +++ b/packages/sanity/src/core/bundles/__telemetry__/releases.telemetry.ts @@ -0,0 +1,84 @@ +import {defineEvent} from '@sanity/telemetry' + +interface VersionInfo { + /** + * document type that was added + */ + schemaType: string + + /** + * the origin of the version created (from a draft or from a version) + */ + documentOrigin: 'draft' | 'version' +} + +export interface OriginInfo { + /** + * determines where the release was created, either from the structure view or the release plugin + */ + origin: 'structure' | 'release-plugin' +} + +/** + * When a document (version) is successfully added to a release + * @internal + */ +export const AddedVersion = defineEvent({ + name: 'Add version of document to release', + version: 1, + description: 'User added a document to a release', +}) + +/** When a release is successfully created + * @internal + */ +export const CreatedRelease = defineEvent({ + name: 'Create release', + version: 1, + description: 'User created a release', +}) + +/** When a release is successfully updated + * @internal + */ +export const UpdatedRelease = defineEvent({ + name: 'Update release', + version: 1, + description: 'User updated a release', +}) + +/** When a release is successfully deleted + * @internal + */ +export const DeletedRelease = defineEvent({ + name: 'Delete release', + version: 1, + description: 'User deleted a release', +}) + +/** When a release is successfully published + * @internal + */ +export const PublishedRelease = defineEvent({ + name: 'Publish release', + version: 1, + description: 'User published a release', +}) + +/** When a release is successfully archived + * @internal + */ +export const ArchivedRelease = defineEvent({ + name: 'Archive release', + version: 1, + description: 'User archived a release', +}) + +/** When a release is successfully unarchived + * @internal + */ +export const UnarchivedRelease = defineEvent({ + name: 'Unarchive release', + version: 1, + description: 'User unarchived a release', +}) diff --git a/packages/sanity/src/core/bundles/components/dialog/BundleDetailsDialog.tsx b/packages/sanity/src/core/bundles/components/dialog/BundleDetailsDialog.tsx index 8a350dca91f..b80964451a5 100644 --- a/packages/sanity/src/core/bundles/components/dialog/BundleDetailsDialog.tsx +++ b/packages/sanity/src/core/bundles/components/dialog/BundleDetailsDialog.tsx @@ -1,4 +1,5 @@ import {ArrowRightIcon} from '@sanity/icons' +import {useTelemetry} from '@sanity/telemetry/react' import {Box, Flex, useToast} from '@sanity/ui' import {type FormEvent, useCallback, useState} from 'react' import {type FormBundleDocument, useTranslation} from 'sanity' @@ -6,6 +7,11 @@ import {type FormBundleDocument, useTranslation} from 'sanity' import {Button, Dialog} from '../../../../ui-components' import {type BundleDocument} from '../../../store/bundles/types' import {useBundleOperations} from '../../../store/bundles/useBundleOperations' +import { + CreatedRelease, + type OriginInfo, + UpdatedRelease, +} from '../../__telemetry__/releases.telemetry' import {usePerspective} from '../../hooks/usePerspective' import {createReleaseId} from '../../util/createReleaseId' import {BundleForm} from './BundleForm' @@ -14,14 +20,16 @@ interface BundleDetailsDialogProps { onCancel: () => void onSubmit: () => void bundle?: BundleDocument + origin?: OriginInfo['origin'] } export function BundleDetailsDialog(props: BundleDetailsDialogProps): JSX.Element { - const {onCancel, onSubmit, bundle} = props + const {onCancel, onSubmit, bundle, origin} = props const toast = useToast() const {createBundle, updateBundle} = useBundleOperations() const formAction = bundle ? 'edit' : 'create' const {t} = useTranslation() + const telemetry = useTelemetry() const [value, setValue] = useState((): FormBundleDocument => { return { @@ -56,6 +64,9 @@ export function BundleDetailsDialog(props: BundleDetailsDialogProps): JSX.Elemen await submit(submitValue) if (formAction === 'create') { setPerspective(value._id) + telemetry.log(CreatedRelease, {origin}) + } else { + telemetry.log(UpdatedRelease) } } catch (err) { console.error(err) @@ -69,7 +80,7 @@ export function BundleDetailsDialog(props: BundleDetailsDialogProps): JSX.Elemen onSubmit() } }, - [value, submit, formAction, setPerspective, toast, onSubmit], + [value, submit, formAction, setPerspective, telemetry, origin, toast, onSubmit], ) const handleOnChange = useCallback((changedValue: FormBundleDocument) => { diff --git a/packages/sanity/src/core/bundles/components/panes/BundleActions.tsx b/packages/sanity/src/core/bundles/components/panes/BundleActions.tsx index 871eab3056f..280d77feb29 100644 --- a/packages/sanity/src/core/bundles/components/panes/BundleActions.tsx +++ b/packages/sanity/src/core/bundles/components/panes/BundleActions.tsx @@ -1,4 +1,5 @@ import {AddIcon, CheckmarkIcon} from '@sanity/icons' +import {useTelemetry} from '@sanity/telemetry/react' import {useToast} from '@sanity/ui' import {type ReactNode, useCallback, useState} from 'react' import {filter, firstValueFrom} from 'rxjs' @@ -6,6 +7,7 @@ import { getPublishedId, getVersionFromId, getVersionId, + isVersionId, useDocumentOperation, useDocumentStore, useTranslation, @@ -13,6 +15,7 @@ import { import {Button} from '../../../../ui-components' import {type BundleDocument} from '../../../store/bundles/types' +import {AddedVersion} from '../../__telemetry__/releases.telemetry' interface BundleActionsProps { currentGlobalBundle: BundleDocument @@ -42,6 +45,7 @@ export function BundleActions(props: BundleActionsProps): ReactNode { const toast = useToast() const {newVersion} = useDocumentOperation(publishedId, documentType, bundleId) const {t} = useTranslation() + const telemetry = useTelemetry() const handleAddVersion = useCallback(async () => { if (!documentId) { @@ -67,7 +71,7 @@ export function BundleActions(props: BundleActionsProps): ReactNode { // set up the listener before executing const createVersionSuccess = firstValueFrom( documentStore.pair - .operationEvents(versionId, documentType) + .operationEvents(getPublishedId(documentId), documentType) .pipe(filter((e) => e.op === 'newVersion' && e.type === 'success')), ) @@ -76,7 +80,21 @@ export function BundleActions(props: BundleActionsProps): ReactNode { // only change if the version was created successfully await createVersionSuccess setIsInVersion(true) - }, [documentId, globalBundleId, documentStore.pair, documentType, newVersion, toast, title]) + + telemetry.log(AddedVersion, { + schemaType: documentType, + documentOrigin: isVersionId(documentId) ? 'version' : 'draft', + }) + }, [ + documentId, + globalBundleId, + documentStore.pair, + documentType, + newVersion, + telemetry, + toast, + title, + ]) /** TODO what should happen when you add a version if we don't have the ready button */ diff --git a/packages/sanity/src/core/releases/components/BundleMenuButton/BundleMenuButton.tsx b/packages/sanity/src/core/releases/components/BundleMenuButton/BundleMenuButton.tsx index 686c9af5912..be7e62eab4b 100644 --- a/packages/sanity/src/core/releases/components/BundleMenuButton/BundleMenuButton.tsx +++ b/packages/sanity/src/core/releases/components/BundleMenuButton/BundleMenuButton.tsx @@ -5,11 +5,17 @@ import { TrashIcon, UnarchiveIcon, } from '@sanity/icons' +import {useTelemetry} from '@sanity/telemetry/react' import {Menu, Spinner, Text, useToast} from '@sanity/ui' import {useState} from 'react' import {useRouter} from 'sanity/router' import {Button, Dialog, MenuButton, MenuItem} from '../../../../ui-components' +import { + ArchivedRelease, + DeletedRelease, + UnarchivedRelease, +} from '../../../bundles/__telemetry__/releases.telemetry' import {BundleDetailsDialog} from '../../../bundles/components/dialog/BundleDetailsDialog' import {Translate, useTranslation} from '../../../i18n' import {type BundleDocument} from '../../../store/bundles/types' @@ -33,6 +39,7 @@ export const BundleMenuButton = ({disabled, bundle, documentCount}: BundleMenuBu const bundleMenuDisabled = !bundle || disabled const toast = useToast() const {t} = useTranslation(releasesLocaleNamespace) + const telemetry = useTelemetry() const resetSelectedAction = () => setSelectedAction(undefined) @@ -41,6 +48,7 @@ export const BundleMenuButton = ({disabled, bundle, documentCount}: BundleMenuBu try { setDiscardStatus('discarding') await deleteBundle(bundle) + telemetry.log(DeletedRelease) toast.push({ closable: true, status: 'success', @@ -74,6 +82,14 @@ export const BundleMenuButton = ({disabled, bundle, documentCount}: BundleMenuBu ...bundle, archivedAt: isBundleArchived ? undefined : new Date().toISOString(), }) + + if (isBundleArchived) { + // it's in the process of becoming false, so the event we want to track is unarchive + telemetry.log(UnarchivedRelease) + } else { + // it's in the process of becoming true, so the event we want to track is archive + telemetry.log(ArchivedRelease) + } setIsPerformingOperation(false) } diff --git a/packages/sanity/src/core/releases/components/ReleasePublishAllButton/ReleasePublishAllButton.tsx b/packages/sanity/src/core/releases/components/ReleasePublishAllButton/ReleasePublishAllButton.tsx index 2f37aebf6bb..b9f65f16c2f 100644 --- a/packages/sanity/src/core/releases/components/ReleasePublishAllButton/ReleasePublishAllButton.tsx +++ b/packages/sanity/src/core/releases/components/ReleasePublishAllButton/ReleasePublishAllButton.tsx @@ -1,9 +1,11 @@ import {ErrorOutlineIcon, PublishIcon} from '@sanity/icons' +import {useTelemetry} from '@sanity/telemetry/react' import {Flex, Text, useToast} from '@sanity/ui' import {useCallback, useMemo, useState} from 'react' import {type BundleDocument} from 'sanity' import {Button, Dialog} from '../../../../ui-components' +import {PublishedRelease} from '../../../bundles/__telemetry__/releases.telemetry' import {Translate, useTranslation} from '../../../i18n' import {useBundleOperations} from '../../../store/bundles/useBundleOperations' import {releasesLocaleNamespace} from '../../i18n' @@ -24,6 +26,7 @@ export const ReleasePublishAllButton = ({ const toast = useToast() const {publishBundle} = useBundleOperations() const {t} = useTranslation(releasesLocaleNamespace) + const telemetry = useTelemetry() const [publishBundleStatus, setPublishBundleStatus] = useState<'idle' | 'confirm' | 'publishing'>( 'idle', ) @@ -47,6 +50,7 @@ export const ReleasePublishAllButton = ({ bundleDocuments.map(({document}) => document), publishedDocumentsRevisions, ) + telemetry.log(PublishedRelease) toast.push({ closable: true, status: 'success', @@ -69,7 +73,7 @@ export const ReleasePublishAllButton = ({ } finally { setPublishBundleStatus('idle') } - }, [bundle, bundleDocuments, publishBundle, publishedDocumentsRevisions, t, toast]) + }, [bundle, bundleDocuments, publishBundle, publishedDocumentsRevisions, t, telemetry, toast]) const confirmPublishDialog = useMemo(() => { if (publishBundleStatus === 'idle') return null diff --git a/packages/sanity/src/core/releases/tool/overview/ReleasesOverview.tsx b/packages/sanity/src/core/releases/tool/overview/ReleasesOverview.tsx index 05a91d52344..670a7270190 100644 --- a/packages/sanity/src/core/releases/tool/overview/ReleasesOverview.tsx +++ b/packages/sanity/src/core/releases/tool/overview/ReleasesOverview.tsx @@ -147,6 +147,7 @@ export function ReleasesOverview() { setIsCreateBundleDialogOpen(false)} onSubmit={() => setIsCreateBundleDialogOpen(false)} + origin="release-plugin" /> ) } diff --git a/packages/sanity/src/core/studio/components/navbar/perspective/GlobalPerspectiveMenu.tsx b/packages/sanity/src/core/studio/components/navbar/perspective/GlobalPerspectiveMenu.tsx index 8ee36b4335b..04b1b88e138 100644 --- a/packages/sanity/src/core/studio/components/navbar/perspective/GlobalPerspectiveMenu.tsx +++ b/packages/sanity/src/core/studio/components/navbar/perspective/GlobalPerspectiveMenu.tsx @@ -60,7 +60,7 @@ export function GlobalPerspectiveMenu(): JSX.Element { /> {createBundleDialogOpen && ( - + )} ) diff --git a/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx b/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx index b33ac600a6d..a03c81b701a 100644 --- a/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx +++ b/packages/sanity/src/structure/panes/document/DocumentPaneProvider.tsx @@ -329,7 +329,7 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => { patchRef.current = (event: PatchEvent) => { // when creating a new draft - if (!editState.draft && !editState.published) { + if (!editState.draft && !editState.published && !editState.version) { telemetry.log(CreatedDraft) } patch.execute(toMutationPatches(event.patches), initialValue.value)