From 2da89d12895d39a44002051d45f2abfb1c757ff2 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 13 Jun 2025 10:00:42 +0200 Subject: [PATCH] scaffolder: refine analytics events data Signed-off-by: Vincenzo Scamporlino --- .../TemplateGroup/TemplateGroup.tsx | 18 ++++--- .../src/next/components/Workflow/Workflow.tsx | 6 +-- .../components/OngoingTask/ContextMenu.tsx | 28 ++-------- .../components/OngoingTask/OngoingTask.tsx | 51 ++++++++++++++++--- 4 files changed, 63 insertions(+), 40 deletions(-) diff --git a/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx b/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx index a70b822d13..74ade33344 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx @@ -22,7 +22,7 @@ import { } from '@backstage/core-components'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { TemplateCardProps, TemplateCard } from '../TemplateCard'; -import { IconComponent } from '@backstage/core-plugin-api'; +import { AnalyticsContext, IconComponent } from '@backstage/core-plugin-api'; /** * The props for the {@link TemplateGroup} component. @@ -69,12 +69,18 @@ export const TemplateGroup = (props: TemplateGroupProps) => { {titleComponent} {templates.map(({ template, additionalLinks }) => ( - + > + + ))} diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index 2aa4ee9b2d..95e2647b5a 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -97,13 +97,11 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { async (formState: Record) => { await onCreate(formState); - const name = - typeof formState.name === 'string' ? formState.name : undefined; - analytics.captureEvent('create', name ?? templateName ?? 'unknown', { + analytics.captureEvent('create', 'Task has been created', { value: minutesSaved, }); }, - [onCreate, analytics, templateName, minutesSaved], + [onCreate, analytics, minutesSaved], ); useEffect(() => { diff --git a/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx index 704d39a8fd..e4ca230c36 100644 --- a/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/ContextMenu.tsx @@ -29,11 +29,8 @@ import Toc from '@material-ui/icons/Toc'; import ControlPointIcon from '@material-ui/icons/ControlPoint'; import MoreVert from '@material-ui/icons/MoreVert'; import { SyntheticEvent, useState } from 'react'; -import { useAnalytics, useApi } from '@backstage/core-plugin-api'; -import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import { usePermission } from '@backstage/plugin-permission-react'; import { - taskCancelPermission, taskReadPermission, taskCreatePermission, } from '@backstage/plugin-scaffolder-common/alpha'; @@ -50,7 +47,8 @@ type ContextMenuProps = { onStartOver?: () => void; onToggleLogs?: (state: boolean) => void; onToggleButtonBar?: (state: boolean) => void; - taskId?: string; + isCancelButtonDisabled: boolean; + onCancel: () => void; }; const useStyles = makeStyles(() => ({ @@ -70,27 +68,13 @@ export const ContextMenu = (props: ContextMenuProps) => { onStartOver, onToggleLogs, onToggleButtonBar, - taskId, } = props; const { getPageTheme } = useTheme(); const pageTheme = getPageTheme({ themeId: 'website' }); const classes = useStyles({ fontColor: pageTheme.fontColor }); - const scaffolderApi = useApi(scaffolderApiRef); - const analytics = useAnalytics(); const [anchorEl, setAnchorEl] = useState(); const { t } = useTranslationRef(scaffolderTranslationRef); - const [{ status: cancelStatus }, { execute: cancel }] = useAsync(async () => { - if (taskId) { - analytics.captureEvent('cancelled', 'Template has been cancelled'); - await scaffolderApi.cancelTask(taskId); - } - }); - - const { allowed: canCancelTask } = usePermission({ - permission: taskCancelPermission, - }); - const { allowed: canReadTask } = usePermission({ permission: taskReadPermission, }); @@ -171,12 +155,8 @@ export const ContextMenu = (props: ContextMenuProps) => { )} diff --git a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx index b718a257b6..c9a119e4a1 100644 --- a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx +++ b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx @@ -32,7 +32,12 @@ import { useTaskEventStream, } from '@backstage/plugin-scaffolder-react'; import { selectedTemplateRouteRef } from '../../routes'; -import { useAnalytics, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { + AnalyticsContext, + useAnalytics, + useApi, + useRouteRef, +} from '@backstage/core-plugin-api'; import qs from 'qs'; import { ContextMenu } from './ContextMenu'; import { @@ -51,6 +56,7 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { scaffolderTranslationRef } from '../../translation'; import { entityPresentationApiRef } from '@backstage/plugin-catalog-react'; import { default as reactUseAsync } from 'react-use/esm/useAsync'; +import { stringifyEntityRef } from '@backstage/catalog-model'; const useStyles = makeStyles(theme => ({ contentWrapper: { @@ -82,6 +88,36 @@ export const OngoingTask = (props: { }>; }) => { // todo(blam): check that task Id actually exists, and that it's valid. otherwise redirect to something more useful. + const { taskId } = useParams(); + const taskStream = useTaskEventStream(taskId!); + const { namespace, name } = + taskStream.task?.spec.templateInfo?.entity?.metadata ?? {}; + + return ( + + + + + + ); +}; + +function OngoingTaskContent(props: { + TemplateOutputsComponent?: ComponentType<{ + output?: ScaffolderTaskOutput; + }>; +}) { const { taskId } = useParams(); const templateRouteRef = useRouteRef(selectedTemplateRouteRef); const navigate = useNavigate(); @@ -183,7 +219,7 @@ export const OngoingTask = (props: { templateRouteRef, ]); - const [{ status: _ }, { execute: triggerRetry }] = useAsync(async () => { + const [, { execute: triggerRetry }] = useAsync(async () => { if (taskId) { analytics.captureEvent('retried', 'Template has been retried'); await scaffolderApi.retry?.(taskId); @@ -202,9 +238,11 @@ export const OngoingTask = (props: { const Outputs = props.TemplateOutputsComponent ?? DefaultTemplateOutputs; const cancelEnabled = !(taskStream.cancelled || taskStream.completed); + const isCancelButtonDisabled = + !cancelEnabled || cancelStatus !== 'not-executed' || !canCancelTask; return ( - + <>
@@ -316,6 +355,6 @@ export const OngoingTask = (props: { ) : null} -
+ ); -}; +}