diff --git a/.changeset/yellow-rules-vanish.md b/.changeset/yellow-rules-vanish.md
new file mode 100644
index 0000000000..23fff893f6
--- /dev/null
+++ b/.changeset/yellow-rules-vanish.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder': patch
+---
+
+Use template title for ongoing task page header
diff --git a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx
index d62ef6f95e..7a04854c6f 100644
--- a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx
+++ b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.test.tsx
@@ -17,9 +17,9 @@
import { OngoingTask } from './OngoingTask';
import React from 'react';
import {
+ mockApis,
renderInTestApp,
TestApiProvider,
- mockApis,
} from '@backstage/test-utils';
import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';
import { act, fireEvent, waitFor, within } from '@testing-library/react';
@@ -30,6 +30,7 @@ import {
import { rootRouteRef } from '../../routes';
import { AuthorizeResult } from '@backstage/plugin-permission-common';
import { SWRConfig } from 'swr';
+import { entityPresentationApiRef } from '@backstage/plugin-catalog-react';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
@@ -47,7 +48,10 @@ jest.mock('@backstage/plugin-scaffolder-react', () => ({
task: {
spec: {
steps: [],
- templateInfo: { entity: { metadata: { name: 'my-template' } } },
+ templateInfo: {
+ entityRef: 'template:default/my-template',
+ entity: { metadata: { name: 'my-template' } },
+ },
},
},
}),
@@ -59,6 +63,12 @@ describe('OngoingTask', () => {
getTask: jest.fn().mockImplementation(async () => {}),
};
+ const mockEntityPresentationApi = {
+ forEntity: jest.fn().mockReturnValue({
+ promise: new Promise(resolve => resolve({ primaryTitle: 'My template' })),
+ }),
+ };
+
beforeEach(async () => {
jest.clearAllMocks();
});
@@ -71,6 +81,7 @@ describe('OngoingTask', () => {
apis={[
[scaffolderApiRef, mockScaffolderApi],
[permissionApiRef, permissionApi || mockApis.permission()],
+ [entityPresentationApiRef, mockEntityPresentationApi],
]}
>
@@ -79,6 +90,12 @@ describe('OngoingTask', () => {
{ mountedRoutes: { '/': rootRouteRef } },
);
};
+
+ it('should render title', async () => {
+ const rendered = await render();
+ expect(rendered.getByText('My template')).toBeInTheDocument();
+ });
+
it('should trigger cancel api on "Cancel" click in context menu', async () => {
const rendered = await render();
const cancelOptionLabel = 'Cancel';
diff --git a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx
index 97047d00c9..06620e7280 100644
--- a/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx
+++ b/plugins/scaffolder/src/components/OngoingTask/OngoingTask.tsx
@@ -21,8 +21,8 @@ import Button from '@material-ui/core/Button';
import Paper from '@material-ui/core/Paper';
import { makeStyles } from '@material-ui/core/styles';
import {
- ScaffolderTaskOutput,
scaffolderApiRef,
+ ScaffolderTaskOutput,
useTaskEventStream,
} from '@backstage/plugin-scaffolder-react';
import { selectedTemplateRouteRef } from '../../routes';
@@ -38,11 +38,13 @@ import { useAsync } from '@react-hookz/web';
import { usePermission } from '@backstage/plugin-permission-react';
import {
taskCancelPermission,
- taskReadPermission,
taskCreatePermission,
+ taskReadPermission,
} from '@backstage/plugin-scaffolder-common/alpha';
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';
const useStyles = makeStyles(theme => ({
contentWrapper: {
@@ -79,6 +81,7 @@ export const OngoingTask = (props: {
const navigate = useNavigate();
const analytics = useAnalytics();
const scaffolderApi = useApi(scaffolderApiRef);
+ const entityPresentationApi = useApi(entityPresentationApiRef);
const taskStream = useTaskEventStream(taskId!);
const classes = useStyles();
const steps = useMemo(
@@ -123,6 +126,14 @@ export const OngoingTask = (props: {
}
}, [taskStream.error, taskStream.completed]);
+ const { value: presentation } = reactUseAsync(async () => {
+ const templateEntityRef = taskStream.task?.spec.templateInfo?.entityRef;
+ if (!templateEntityRef) {
+ return undefined;
+ }
+ return entityPresentationApi.forEntity(templateEntityRef).promise;
+ }, [entityPresentationApi, taskStream.task?.spec.templateInfo?.entityRef]);
+
const activeStep = useMemo(() => {
for (let i = steps.length - 1; i >= 0; i--) {
if (steps[i].status !== 'open') {
@@ -184,22 +195,22 @@ export const OngoingTask = (props: {
const Outputs = props.TemplateOutputsComponent ?? DefaultTemplateOutputs;
- const templateName =
- taskStream.task?.spec.templateInfo?.entity?.metadata.name || '';
-
const cancelEnabled = !(taskStream.cancelled || taskStream.completed);
return (
- {t('ongoingTask.title')} {templateName}
+ {t('ongoingTask.title')}{' '}
+ {presentation ? presentation.primaryTitle : ''}
}
subtitle={t('ongoingTask.subtitle', { taskId: taskId as string })}