From 2e2b1f94e0094a64710760420bab2cdd4b02c5f1 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 9 Oct 2023 17:41:26 +0200 Subject: [PATCH 01/12] Make it possible to configure certain tings per template Signed-off-by: Bogdan Nechyporenko --- plugins/scaffolder-backend/src/service/router.ts | 1 + plugins/scaffolder-common/src/TemplateEntityV1beta3.ts | 8 ++++++++ plugins/scaffolder-common/src/index.ts | 1 + .../src/next/components/Stepper/Stepper.tsx | 4 ++-- .../scaffolder-react/src/next/hooks/useTemplateSchema.ts | 7 ++++++- plugins/scaffolder-react/src/types.ts | 3 +++ 6 files changed, 21 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 15f7c11eba..2bf44cdfc6 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -365,6 +365,7 @@ export async function createRouter( const parameters = [template.spec.parameters ?? []].flat(); res.json({ title: template.metadata.title ?? template.metadata.name, + configurations: template.spec.configurations ?? {}, description: template.metadata.description, 'ui:options': template.metadata['ui:options'], steps: parameters.map(schema => ({ diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index ebabb5cad4..ffd50eab79 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -45,6 +45,9 @@ export interface TemplateEntityV1beta3 extends Entity { * The type that the Template will create. For example service, website or library. */ type: string; + + configurations?: TemplateConfigurationsV1beta3; + /** * This is a JSONSchema or an array of JSONSchema's which is used to render a form in the frontend * to collect user input and validate it against that schema. This can then be used in the `steps` part below to template @@ -67,6 +70,11 @@ export interface TemplateEntityV1beta3 extends Entity { }; } +export interface TemplateConfigurationsV1beta3 { + kickOffButtonText?: string; + reviewButtonText?: string; +} + /** * Step that is part of a Template Entity. * diff --git a/plugins/scaffolder-common/src/index.ts b/plugins/scaffolder-common/src/index.ts index fd34fe6f41..851c6ac7e5 100644 --- a/plugins/scaffolder-common/src/index.ts +++ b/plugins/scaffolder-common/src/index.ts @@ -27,6 +27,7 @@ export { isTemplateEntityV1beta3, } from './TemplateEntityV1beta3'; export type { + TemplateConfigurationsV1beta3, TemplateEntityV1beta3, TemplateEntityStepV1beta3, TemplateParametersV1beta3, diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index e15953bf1f..8240fca9e0 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -91,7 +91,7 @@ export const Stepper = (stepperProps: StepperProps) => { reviewButtonText = 'Review', } = components; const analytics = useAnalytics(); - const { steps } = useTemplateSchema(props.manifest); + const { configurations, steps } = useTemplateSchema(props.manifest); const apiHolder = useApiHolder(); const [activeStep, setActiveStep] = useState(0); const [isValidating, setIsValidating] = useState(false); @@ -229,7 +229,7 @@ export const Stepper = (stepperProps: StepperProps) => { ); }} > - {createButtonText} + {configurations.kickOffButtonText ?? createButtonText} diff --git a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts index df70df965c..5fbac20db7 100644 --- a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts +++ b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { featureFlagsApiRef, useApi } from '@backstage/core-plugin-api'; +import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; import { JsonObject } from '@backstage/types'; import { UiSchema } from '@rjsf/utils'; import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; @@ -39,7 +40,10 @@ export interface ParsedTemplateSchema { */ export const useTemplateSchema = ( manifest: TemplateParameterSchema, -): { steps: ParsedTemplateSchema[] } => { +): { + steps: ParsedTemplateSchema[]; + configurations: TemplateConfigurationsV1beta3; +} => { const featureFlags = useApi(featureFlagsApiRef); const steps = manifest.steps.map(({ title, description, schema }) => ({ title, @@ -76,6 +80,7 @@ export const useTemplateSchema = ( })); return { + configurations: manifest.configurations, steps: returningSteps, }; }; diff --git a/plugins/scaffolder-react/src/types.ts b/plugins/scaffolder-react/src/types.ts index f644fbeb64..f5c4cabc04 100644 --- a/plugins/scaffolder-react/src/types.ts +++ b/plugins/scaffolder-react/src/types.ts @@ -16,6 +16,8 @@ import { JsonObject } from '@backstage/types'; +import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; + /** * The shape of each entry of parameters which gets rendered * as a separate step in the wizard input @@ -25,6 +27,7 @@ import { JsonObject } from '@backstage/types'; export type TemplateParameterSchema = { title: string; description?: string; + configurations?: TemplateConfigurationsV1beta3; steps: Array<{ title: string; description?: string; From 7d653f58b1d1ec8236f4d8d3219267b6bc599f66 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 16 Oct 2023 13:38:10 +0200 Subject: [PATCH 02/12] Preserve time execution for a non-running task. Signed-off-by: Bogdan Nechyporenko --- .changeset/hungry-coats-judge.md | 5 ++ plugins/scaffolder-backend/api-report.md | 4 +- plugins/scaffolder-node/api-report.md | 4 +- plugins/scaffolder/package.json | 1 + plugins/scaffolder/src/api.test.ts | 97 ++++++++++++++++++++++++ plugins/scaffolder/src/api.ts | 61 +++++++++++++-- yarn.lock | 1 + 7 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 .changeset/hungry-coats-judge.md diff --git a/.changeset/hungry-coats-judge.md b/.changeset/hungry-coats-judge.md new file mode 100644 index 0000000000..7e5b634237 --- /dev/null +++ b/.changeset/hungry-coats-judge.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Preserve time execution for a non-running task diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index ba7576b1bb..1b0930eaee 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -741,8 +741,8 @@ export function createRouter(options: RouterOptions): Promise; export const createTemplateAction: < TInputParams extends JsonObject = JsonObject, TOutputParams extends JsonObject = JsonObject, - TInputSchema extends ZodType | Schema = {}, - TOutputSchema extends ZodType | Schema = {}, + TInputSchema extends Schema | ZodType = {}, + TOutputSchema extends Schema | ZodType = {}, TActionInput extends JsonObject = TInputSchema extends ZodType< any, any, diff --git a/plugins/scaffolder-node/api-report.md b/plugins/scaffolder-node/api-report.md index 52ce3c8d13..0c97fb2e40 100644 --- a/plugins/scaffolder-node/api-report.md +++ b/plugins/scaffolder-node/api-report.md @@ -53,8 +53,8 @@ export type ActionContext< export const createTemplateAction: < TInputParams extends JsonObject = JsonObject, TOutputParams extends JsonObject = JsonObject, - TInputSchema extends z.ZodType | Schema = {}, - TOutputSchema extends z.ZodType | Schema = {}, + TInputSchema extends Schema | z.ZodType = {}, + TOutputSchema extends Schema | z.ZodType = {}, TActionInput extends JsonObject = TInputSchema extends z.ZodType< any, any, diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 68066a5a79..7766669411 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -58,6 +58,7 @@ "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", + "@backstage/plugin-scaffolder-node": "workspace:^", "@backstage/plugin-scaffolder-react": "workspace:^", "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", diff --git a/plugins/scaffolder/src/api.test.ts b/plugins/scaffolder/src/api.test.ts index b9b1881066..e10363b61f 100644 --- a/plugins/scaffolder/src/api.test.ts +++ b/plugins/scaffolder/src/api.test.ts @@ -21,6 +21,11 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ScaffolderClient } from './api'; import { EventSourcePolyfill } from 'event-source-polyfill'; +import { + SerializedTask, + SerializedTaskEvent, +} from '@backstage/plugin-scaffolder-node'; +import { ScaffolderStep } from '@backstage/plugin-scaffolder-react'; const MockedEventSource = EventSourcePolyfill as jest.MockedClass< typeof EventSourcePolyfill @@ -327,6 +332,98 @@ describe('api', () => { }); }); + describe('getTask', () => { + it('should return the task enriched with timestamps', async () => { + const taskId = 'e4e4cb25-e743-4b79-8572-87e9d35aa998'; + server.use( + rest.get(`${mockBaseUrl}/v2/tasks/:taskId`, (_req, res, ctx) => { + return res( + ctx.json({ + createdAt: '2023-10-16T08:21:32.038Z', + id: taskId, + lastHeartbeatAt: '2023-10-16T08:21:54.304Z', + spec: { + apiVersion: 'scaffolder.backstage.io/v1beta3', + steps: [ + { + action: 'fetch:template', + id: 'fetch', + }, + { + action: 'debug:wait', + id: 'mock-step-1', + }, + { + action: 'debug:wait', + id: 'mock-step-2', + }, + ], + templateInfo: { + entityRef: 'template:default/docs-long-running-template', + }, + }, + } as SerializedTask), + ); + }), + rest.get(`${mockBaseUrl}/v2/tasks/:taskId/events`, (_req, res, ctx) => { + return res( + ctx.json([ + { + createdAt: '2023-10-16T08:21:32.062Z', + body: {}, + id: 109, + taskId, + type: 'log', + }, + { + body: { stepId: 'fetch' }, + createdAt: '2023-10-16T08:21:32.062Z', + id: 110, + taskId, + type: 'log', + }, + { + body: { stepId: 'fetch' }, + createdAt: '2023-10-16T08:21:33.062Z', + id: 111, + taskId, + type: 'log', + }, + { + body: { stepId: 'fetch' }, + createdAt: '2023-10-16T08:21:34.062Z', + id: 112, + taskId, + type: 'log', + }, + { + body: { stepId: 'mock-step-1' }, + createdAt: '2023-10-16T08:21:37.062Z', + id: 120, + taskId, + type: 'log', + }, + ] as SerializedTaskEvent[]), + ); + }), + ); + + const task = await apiClient.getTask(taskId); + + const getStep = (stepId: string) => + task.spec.steps.find( + step => step.id === stepId, + ) as unknown as ScaffolderStep; + + expect(getStep('fetch').startedAt).toBe('2023-10-16T08:21:32.062Z'); + expect(getStep('fetch').endedAt).toBe('2023-10-16T08:21:34.062Z'); + expect(getStep('mock-step-1').startedAt).toBe('2023-10-16T08:21:37.062Z'); + expect(getStep('mock-step-1').endedAt).toBe('2023-10-16T08:21:37.062Z'); + expect(getStep('mock-step-2').startedAt).toBeUndefined(); + expect(getStep('mock-step-2').endedAt).toBeUndefined(); + }); + }); + describe('listTasks', () => { it('should list all tasks', async () => { server.use( diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index c67a5c944e..6aa7fac780 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -38,10 +38,13 @@ import { ScaffolderDryRunOptions, ScaffolderDryRunResponse, TemplateParameterSchema, + ScaffolderStep, } from '@backstage/plugin-scaffolder-react'; +import { TaskStep } from '@backstage/plugin-scaffolder-common'; import queryString from 'qs'; import { EventSourcePolyfill } from 'event-source-polyfill'; +import { SerializedTaskEvent } from '@backstage/plugin-scaffolder-node'; /** * An API to interact with the scaffolder backend. @@ -170,14 +173,62 @@ export class ScaffolderClient implements ScaffolderApi { async getTask(taskId: string): Promise { const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`; + const taskUrl = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`; - const response = await this.fetchApi.fetch(url); - if (!response.ok) { - throw await ResponseError.fromResponse(response); + const taskEventsUrl = `${baseUrl}/v2/tasks/${encodeURIComponent( + taskId, + )}/events`; + + const taskResponse = await this.fetchApi.fetch(taskUrl); + if (!taskResponse.ok) { + throw await ResponseError.fromResponse(taskResponse); } - return await response.json(); + const taskEventsResponse = await this.fetchApi.fetch(taskEventsUrl); + if (!taskEventsResponse.ok) { + throw await ResponseError.fromResponse(taskEventsResponse); + } + + const task = (await taskResponse.json()) as ScaffolderTask; + const taskEvents = + (await taskEventsResponse.json()) as SerializedTaskEvent[]; + + const stepIdToTimestamps = taskEvents + .filter(event => event.type === 'log') + .reduce((acc, event) => { + const stepId = event.body.stepId as string; + if (stepId) { + acc.set(stepId, [...(acc.get(stepId) ?? []), event.createdAt]); + } + return acc; + }, new Map()); + + const toStartedAt = (stepId: string) => { + const timestamps = stepIdToTimestamps.get(stepId); + return timestamps ? timestamps[0] : undefined; + }; + + const toEndedAt = (stepId: string) => { + const timestamps = stepIdToTimestamps.get(stepId); + return timestamps ? timestamps[timestamps.length - 1] : undefined; + }; + + const enrichedTask = { + ...task, + spec: { + ...task.spec, + steps: task.spec.steps.map( + step => + ({ + ...step, + startedAt: toStartedAt(step.id), + endedAt: toEndedAt(step.id), + } as TaskStep & ScaffolderStep), + ), + }, + }; + + return enrichedTask as ScaffolderTask; } streamLogs(options: ScaffolderStreamLogsOptions): Observable { diff --git a/yarn.lock b/yarn.lock index 2533a51f32..e7cd435d9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8975,6 +8975,7 @@ __metadata: "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/plugin-scaffolder-common": "workspace:^" + "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-react": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" From b5dcf6b1205093523f65a6d8417133e25164e7ce Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 16 Oct 2023 14:18:37 +0200 Subject: [PATCH 03/12] Make it possible to define control buttons text (Back, Create, Review) per template Signed-off-by: Bogdan Nechyporenko --- .../src/TemplateEntityV1beta3.ts | 7 ++++-- .../src/next/components/Stepper/Stepper.tsx | 22 +++++++++++++------ .../src/next/hooks/useTemplateSchema.ts | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index ffd50eab79..96edd44595 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -71,8 +71,11 @@ export interface TemplateEntityV1beta3 extends Entity { } export interface TemplateConfigurationsV1beta3 { - kickOffButtonText?: string; - reviewButtonText?: string; + buttonLabels?: { + backButtonText?: string; + createButtonText?: string; + reviewButtonText?: string; + }; } /** diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 8240fca9e0..9c800b7605 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -32,9 +32,8 @@ import { type FormValidation, } from './createAsyncValidators'; import { ReviewState, type ReviewStateProps } from '../ReviewState'; -import { useTemplateSchema } from '../../hooks/useTemplateSchema'; +import { useTemplateSchema, useFormDataFromQuery } from '../../hooks'; import validator from '@rjsf/validator-ajv8'; -import { useFormDataFromQuery } from '../../hooks'; import { FormProps } from '../../types'; import { useTransformSchemaToProps } from '../../hooks/useTransformSchemaToProps'; import { hasErrors } from './utils'; @@ -73,6 +72,7 @@ export type StepperProps = { onCreate: (values: Record) => Promise; components?: { ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element; + backButtonText?: ReactNode; createButtonText?: ReactNode; reviewButtonText?: ReactNode; }; @@ -87,6 +87,7 @@ export const Stepper = (stepperProps: StepperProps) => { const { layouts = [], components = {}, ...props } = stepperProps; const { ReviewStateComponent = ReviewState, + backButtonText = 'Back', createButtonText = 'Create', reviewButtonText = 'Review', } = components; @@ -157,6 +158,13 @@ export const Stepper = (stepperProps: StepperProps) => { setFormState(current => ({ ...current, ...formData })); }; + const backLabel = + configurations?.buttonLabels?.backButtonText ?? backButtonText; + const createLabel = + configurations?.buttonLabels?.createButtonText ?? createButtonText; + const reviewLabel = + configurations?.buttonLabels?.reviewButtonText ?? reviewButtonText; + return ( <> {isValidating && } @@ -167,7 +175,7 @@ export const Stepper = (stepperProps: StepperProps) => { ))} - Review + ${reviewLabel}
@@ -191,7 +199,7 @@ export const Stepper = (stepperProps: StepperProps) => { className={styles.backButton} disabled={activeStep < 1 || isValidating} > - Back + {backLabel}
@@ -212,7 +220,7 @@ export const Stepper = (stepperProps: StepperProps) => { className={styles.backButton} disabled={activeStep < 1} > - Back + {configurations?.buttonLabels?.backButtonText ?? backButtonText} diff --git a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts index 5fbac20db7..738be10279 100644 --- a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts +++ b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts @@ -42,7 +42,7 @@ export const useTemplateSchema = ( manifest: TemplateParameterSchema, ): { steps: ParsedTemplateSchema[]; - configurations: TemplateConfigurationsV1beta3; + configurations?: TemplateConfigurationsV1beta3; } => { const featureFlags = useApi(featureFlagsApiRef); const steps = manifest.steps.map(({ title, description, schema }) => ({ From 4db0d9903c659967f9b4503003ec4ef8e293d28f Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 16 Oct 2023 14:47:46 +0200 Subject: [PATCH 04/12] Make it possible to define control buttons text (Back, Create, Review) per template Signed-off-by: Bogdan Nechyporenko --- plugins/scaffolder-common/api-report.md | 10 +++++++++ .../src/TemplateEntityV1beta3.ts | 22 ++++++++++++++++++- plugins/scaffolder-react/alpha-api-report.md | 3 +++ plugins/scaffolder-react/api-report.md | 2 ++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/plugins/scaffolder-common/api-report.md b/plugins/scaffolder-common/api-report.md index 6113c72659..73289bcc47 100644 --- a/plugins/scaffolder-common/api-report.md +++ b/plugins/scaffolder-common/api-report.md @@ -44,6 +44,15 @@ export interface TaskStep { name: string; } +// @public +export interface TemplateConfigurationsV1beta3 extends JsonObject { + buttonLabels?: { + backButtonText?: string; + createButtonText?: string; + reviewButtonText?: string; + }; +} + // @public export interface TemplateEntityStepV1beta3 extends JsonObject { // (undocumented) @@ -66,6 +75,7 @@ export interface TemplateEntityV1beta3 extends Entity { kind: 'Template'; spec: { type: string; + configurations?: TemplateConfigurationsV1beta3; parameters?: TemplateParametersV1beta3 | TemplateParametersV1beta3[]; steps: Array; output?: { diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index 96edd44595..c610886ac1 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -46,6 +46,9 @@ export interface TemplateEntityV1beta3 extends Entity { */ type: string; + /** + * Template specific configurations. + */ configurations?: TemplateConfigurationsV1beta3; /** @@ -70,10 +73,27 @@ export interface TemplateEntityV1beta3 extends Entity { }; } -export interface TemplateConfigurationsV1beta3 { +/** + * The configuration of the template. + * + * @public + */ +export interface TemplateConfigurationsV1beta3 extends JsonObject { + /** + * Overrides default buttons' text + */ buttonLabels?: { + /** + * The text for the button which leads to the previous template page + */ backButtonText?: string; + /** + * The text for the button which starts the execution of the template + */ createButtonText?: string; + /** + * The text for the button which opens template's review/summary + */ reviewButtonText?: string; }; } diff --git a/plugins/scaffolder-react/alpha-api-report.md b/plugins/scaffolder-react/alpha-api-report.md index 11bb2c10c4..3c9a4df26b 100644 --- a/plugins/scaffolder-react/alpha-api-report.md +++ b/plugins/scaffolder-react/alpha-api-report.md @@ -25,6 +25,7 @@ import { ScaffolderStep } from '@backstage/plugin-scaffolder-react'; import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react'; import { SetStateAction } from 'react'; import { TaskStep } from '@backstage/plugin-scaffolder-common'; +import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; import { UIOptionsType } from '@rjsf/utils'; @@ -183,6 +184,7 @@ export type StepperProps = { onCreate: (values: Record) => Promise; components?: { ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element; + backButtonText?: ReactNode; createButtonText?: ReactNode; reviewButtonText?: ReactNode; }; @@ -303,6 +305,7 @@ export const useTemplateParameterSchema: (templateRef: string) => { // @alpha export const useTemplateSchema: (manifest: TemplateParameterSchema) => { steps: ParsedTemplateSchema[]; + configurations?: TemplateConfigurationsV1beta3 | undefined; }; // @alpha (undocumented) diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index da95e6746e..5df7aa3b85 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -19,6 +19,7 @@ import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { TaskStep } from '@backstage/plugin-scaffolder-common'; +import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; // @public export type Action = { @@ -317,6 +318,7 @@ export type TaskStream = { export type TemplateParameterSchema = { title: string; description?: string; + configurations?: TemplateConfigurationsV1beta3; steps: Array<{ title: string; description?: string; From 6bb8457bd20ee98f23e4c2a484de90c7c0c37fe8 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 16 Oct 2023 14:55:48 +0200 Subject: [PATCH 05/12] wip Signed-off-by: Bogdan Nechyporenko --- plugins/scaffolder/src/api.test.ts | 92 ------------------------------ 1 file changed, 92 deletions(-) diff --git a/plugins/scaffolder/src/api.test.ts b/plugins/scaffolder/src/api.test.ts index e10363b61f..edd27ba8f0 100644 --- a/plugins/scaffolder/src/api.test.ts +++ b/plugins/scaffolder/src/api.test.ts @@ -332,98 +332,6 @@ describe('api', () => { }); }); - describe('getTask', () => { - it('should return the task enriched with timestamps', async () => { - const taskId = 'e4e4cb25-e743-4b79-8572-87e9d35aa998'; - server.use( - rest.get(`${mockBaseUrl}/v2/tasks/:taskId`, (_req, res, ctx) => { - return res( - ctx.json({ - createdAt: '2023-10-16T08:21:32.038Z', - id: taskId, - lastHeartbeatAt: '2023-10-16T08:21:54.304Z', - spec: { - apiVersion: 'scaffolder.backstage.io/v1beta3', - steps: [ - { - action: 'fetch:template', - id: 'fetch', - }, - { - action: 'debug:wait', - id: 'mock-step-1', - }, - { - action: 'debug:wait', - id: 'mock-step-2', - }, - ], - templateInfo: { - entityRef: 'template:default/docs-long-running-template', - }, - }, - } as SerializedTask), - ); - }), - rest.get(`${mockBaseUrl}/v2/tasks/:taskId/events`, (_req, res, ctx) => { - return res( - ctx.json([ - { - createdAt: '2023-10-16T08:21:32.062Z', - body: {}, - id: 109, - taskId, - type: 'log', - }, - { - body: { stepId: 'fetch' }, - createdAt: '2023-10-16T08:21:32.062Z', - id: 110, - taskId, - type: 'log', - }, - { - body: { stepId: 'fetch' }, - createdAt: '2023-10-16T08:21:33.062Z', - id: 111, - taskId, - type: 'log', - }, - { - body: { stepId: 'fetch' }, - createdAt: '2023-10-16T08:21:34.062Z', - id: 112, - taskId, - type: 'log', - }, - { - body: { stepId: 'mock-step-1' }, - createdAt: '2023-10-16T08:21:37.062Z', - id: 120, - taskId, - type: 'log', - }, - ] as SerializedTaskEvent[]), - ); - }), - ); - - const task = await apiClient.getTask(taskId); - - const getStep = (stepId: string) => - task.spec.steps.find( - step => step.id === stepId, - ) as unknown as ScaffolderStep; - - expect(getStep('fetch').startedAt).toBe('2023-10-16T08:21:32.062Z'); - expect(getStep('fetch').endedAt).toBe('2023-10-16T08:21:34.062Z'); - expect(getStep('mock-step-1').startedAt).toBe('2023-10-16T08:21:37.062Z'); - expect(getStep('mock-step-1').endedAt).toBe('2023-10-16T08:21:37.062Z'); - expect(getStep('mock-step-2').startedAt).toBeUndefined(); - expect(getStep('mock-step-2').endedAt).toBeUndefined(); - }); - }); - describe('listTasks', () => { it('should list all tasks', async () => { server.use( From 76d07da66a930593c336f74c1b9a2e4e36f9a3c2 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 16 Oct 2023 15:00:46 +0200 Subject: [PATCH 06/12] wip Signed-off-by: Bogdan Nechyporenko --- .changeset/hungry-coats-judge.md | 5 --- .changeset/tidy-planets-trade.md | 6 +++ plugins/scaffolder/src/api.test.ts | 5 --- plugins/scaffolder/src/api.ts | 61 +++--------------------------- 4 files changed, 11 insertions(+), 66 deletions(-) delete mode 100644 .changeset/hungry-coats-judge.md create mode 100644 .changeset/tidy-planets-trade.md diff --git a/.changeset/hungry-coats-judge.md b/.changeset/hungry-coats-judge.md deleted file mode 100644 index 7e5b634237..0000000000 --- a/.changeset/hungry-coats-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Preserve time execution for a non-running task diff --git a/.changeset/tidy-planets-trade.md b/.changeset/tidy-planets-trade.md new file mode 100644 index 0000000000..a25179b222 --- /dev/null +++ b/.changeset/tidy-planets-trade.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-common': patch +'@backstage/plugin-scaffolder-react': patch +--- + +Make it possible to define control buttons text (Back, Create, Review) per template diff --git a/plugins/scaffolder/src/api.test.ts b/plugins/scaffolder/src/api.test.ts index edd27ba8f0..b9b1881066 100644 --- a/plugins/scaffolder/src/api.test.ts +++ b/plugins/scaffolder/src/api.test.ts @@ -21,11 +21,6 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ScaffolderClient } from './api'; import { EventSourcePolyfill } from 'event-source-polyfill'; -import { - SerializedTask, - SerializedTaskEvent, -} from '@backstage/plugin-scaffolder-node'; -import { ScaffolderStep } from '@backstage/plugin-scaffolder-react'; const MockedEventSource = EventSourcePolyfill as jest.MockedClass< typeof EventSourcePolyfill diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index 6aa7fac780..c67a5c944e 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -38,13 +38,10 @@ import { ScaffolderDryRunOptions, ScaffolderDryRunResponse, TemplateParameterSchema, - ScaffolderStep, } from '@backstage/plugin-scaffolder-react'; -import { TaskStep } from '@backstage/plugin-scaffolder-common'; import queryString from 'qs'; import { EventSourcePolyfill } from 'event-source-polyfill'; -import { SerializedTaskEvent } from '@backstage/plugin-scaffolder-node'; /** * An API to interact with the scaffolder backend. @@ -173,62 +170,14 @@ export class ScaffolderClient implements ScaffolderApi { async getTask(taskId: string): Promise { const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); - const taskUrl = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`; + const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`; - const taskEventsUrl = `${baseUrl}/v2/tasks/${encodeURIComponent( - taskId, - )}/events`; - - const taskResponse = await this.fetchApi.fetch(taskUrl); - if (!taskResponse.ok) { - throw await ResponseError.fromResponse(taskResponse); + const response = await this.fetchApi.fetch(url); + if (!response.ok) { + throw await ResponseError.fromResponse(response); } - const taskEventsResponse = await this.fetchApi.fetch(taskEventsUrl); - if (!taskEventsResponse.ok) { - throw await ResponseError.fromResponse(taskEventsResponse); - } - - const task = (await taskResponse.json()) as ScaffolderTask; - const taskEvents = - (await taskEventsResponse.json()) as SerializedTaskEvent[]; - - const stepIdToTimestamps = taskEvents - .filter(event => event.type === 'log') - .reduce((acc, event) => { - const stepId = event.body.stepId as string; - if (stepId) { - acc.set(stepId, [...(acc.get(stepId) ?? []), event.createdAt]); - } - return acc; - }, new Map()); - - const toStartedAt = (stepId: string) => { - const timestamps = stepIdToTimestamps.get(stepId); - return timestamps ? timestamps[0] : undefined; - }; - - const toEndedAt = (stepId: string) => { - const timestamps = stepIdToTimestamps.get(stepId); - return timestamps ? timestamps[timestamps.length - 1] : undefined; - }; - - const enrichedTask = { - ...task, - spec: { - ...task.spec, - steps: task.spec.steps.map( - step => - ({ - ...step, - startedAt: toStartedAt(step.id), - endedAt: toEndedAt(step.id), - } as TaskStep & ScaffolderStep), - ), - }, - }; - - return enrichedTask as ScaffolderTask; + return await response.json(); } streamLogs(options: ScaffolderStreamLogsOptions): Observable { From e694775034ee47f07343f64d7f2bba81a0991093 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 16 Oct 2023 15:04:29 +0200 Subject: [PATCH 07/12] wip Signed-off-by: Bogdan Nechyporenko --- .changeset/tidy-planets-trade.md | 1 + plugins/scaffolder/package.json | 1 - yarn.lock | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.changeset/tidy-planets-trade.md b/.changeset/tidy-planets-trade.md index a25179b222..49c1643e55 100644 --- a/.changeset/tidy-planets-trade.md +++ b/.changeset/tidy-planets-trade.md @@ -1,4 +1,5 @@ --- +'@backstage/plugin-scaffolder-backend': patch '@backstage/plugin-scaffolder-common': patch '@backstage/plugin-scaffolder-react': patch --- diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 7766669411..68066a5a79 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -58,7 +58,6 @@ "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-permission-react": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", - "@backstage/plugin-scaffolder-node": "workspace:^", "@backstage/plugin-scaffolder-react": "workspace:^", "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", diff --git a/yarn.lock b/yarn.lock index e7cd435d9b..2533a51f32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8975,7 +8975,6 @@ __metadata: "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/plugin-scaffolder-common": "workspace:^" - "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-react": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" From 84e61831a9647a924b5032394daf2e5dc21da2a4 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 16 Oct 2023 15:30:11 +0200 Subject: [PATCH 08/12] wip Signed-off-by: Bogdan Nechyporenko --- plugins/scaffolder-backend/api-report.md | 4 ++-- plugins/scaffolder-node/api-report.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 1b0930eaee..ba7576b1bb 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -741,8 +741,8 @@ export function createRouter(options: RouterOptions): Promise; export const createTemplateAction: < TInputParams extends JsonObject = JsonObject, TOutputParams extends JsonObject = JsonObject, - TInputSchema extends Schema | ZodType = {}, - TOutputSchema extends Schema | ZodType = {}, + TInputSchema extends ZodType | Schema = {}, + TOutputSchema extends ZodType | Schema = {}, TActionInput extends JsonObject = TInputSchema extends ZodType< any, any, diff --git a/plugins/scaffolder-node/api-report.md b/plugins/scaffolder-node/api-report.md index 0c97fb2e40..52ce3c8d13 100644 --- a/plugins/scaffolder-node/api-report.md +++ b/plugins/scaffolder-node/api-report.md @@ -53,8 +53,8 @@ export type ActionContext< export const createTemplateAction: < TInputParams extends JsonObject = JsonObject, TOutputParams extends JsonObject = JsonObject, - TInputSchema extends Schema | z.ZodType = {}, - TOutputSchema extends Schema | z.ZodType = {}, + TInputSchema extends z.ZodType | Schema = {}, + TOutputSchema extends z.ZodType | Schema = {}, TActionInput extends JsonObject = TInputSchema extends z.ZodType< any, any, From 5cdcf77a45119419286422a2c2339220db50d9ff Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 23 Oct 2023 11:05:30 +0200 Subject: [PATCH 09/12] Updated to a presentation Signed-off-by: Bogdan Nechyporenko --- .../scaffolder-backend/src/service/router.ts | 2 +- .../src/TemplateEntityV1beta3.ts | 8 ++++---- plugins/scaffolder-common/src/index.ts | 2 +- .../src/next/components/Stepper/Stepper.tsx | 17 +++++++++++++---- .../src/next/hooks/useTemplateSchema.ts | 6 +++--- plugins/scaffolder-react/src/types.ts | 4 ++-- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 2bf44cdfc6..f8bdb48e2b 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -365,7 +365,7 @@ export async function createRouter( const parameters = [template.spec.parameters ?? []].flat(); res.json({ title: template.metadata.title ?? template.metadata.name, - configurations: template.spec.configurations ?? {}, + presentation: template.spec.presentation ?? {}, description: template.metadata.description, 'ui:options': template.metadata['ui:options'], steps: parameters.map(schema => ({ diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index c610886ac1..23cc3ca3d8 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -47,9 +47,9 @@ export interface TemplateEntityV1beta3 extends Entity { type: string; /** - * Template specific configurations. + * Template specific configuration of the presentation layer. */ - configurations?: TemplateConfigurationsV1beta3; + presentation?: TemplatePresentationV1beta3; /** * This is a JSONSchema or an array of JSONSchema's which is used to render a form in the frontend @@ -74,11 +74,11 @@ export interface TemplateEntityV1beta3 extends Entity { } /** - * The configuration of the template. + * The presentation of the template. * * @public */ -export interface TemplateConfigurationsV1beta3 extends JsonObject { +export interface TemplatePresentationV1beta3 extends JsonObject { /** * Overrides default buttons' text */ diff --git a/plugins/scaffolder-common/src/index.ts b/plugins/scaffolder-common/src/index.ts index 851c6ac7e5..3300aebf46 100644 --- a/plugins/scaffolder-common/src/index.ts +++ b/plugins/scaffolder-common/src/index.ts @@ -27,7 +27,7 @@ export { isTemplateEntityV1beta3, } from './TemplateEntityV1beta3'; export type { - TemplateConfigurationsV1beta3, + TemplatePresentationV1beta3, TemplateEntityV1beta3, TemplateEntityStepV1beta3, TemplateParametersV1beta3, diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 1e43eba770..e52560e2a5 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -81,6 +81,7 @@ export type StepperProps = { components?: { ReviewStepComponent?: ComponentType; ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element; + backButtonText?: ReactNode; createButtonText?: ReactNode; reviewButtonText?: ReactNode; }; @@ -96,11 +97,12 @@ export const Stepper = (stepperProps: StepperProps) => { const { ReviewStateComponent = ReviewState, ReviewStepComponent, + backButtonText = 'Back', createButtonText = 'Create', reviewButtonText = 'Review', } = components; const analytics = useAnalytics(); - const { steps } = useTemplateSchema(props.manifest); + const { presentation, steps } = useTemplateSchema(props.manifest); const apiHolder = useApiHolder(); const [activeStep, setActiveStep] = useState(0); const [isValidating, setIsValidating] = useState(false); @@ -173,6 +175,13 @@ export const Stepper = (stepperProps: StepperProps) => { setFormState(current => ({ ...current, ...formData })); }; + const backLabel = + presentation?.buttonLabels?.backButtonText ?? backButtonText; + const createLabel = + presentation?.buttonLabels?.createButtonText ?? createButtonText; + const reviewLabel = + presentation?.buttonLabels?.reviewButtonText ?? reviewButtonText; + return ( <> {isValidating && } @@ -208,7 +217,7 @@ export const Stepper = (stepperProps: StepperProps) => { className={styles.backButton} disabled={activeStep < 1 || isValidating} > - Back + {backLabel} @@ -246,7 +255,7 @@ export const Stepper = (stepperProps: StepperProps) => { color="primary" onClick={handleCreate} > - {createButtonText} + {createLabel} diff --git a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts index 738be10279..838f8b1c30 100644 --- a/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts +++ b/plugins/scaffolder-react/src/next/hooks/useTemplateSchema.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { featureFlagsApiRef, useApi } from '@backstage/core-plugin-api'; -import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; import { JsonObject } from '@backstage/types'; import { UiSchema } from '@rjsf/utils'; import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; @@ -42,7 +42,7 @@ export const useTemplateSchema = ( manifest: TemplateParameterSchema, ): { steps: ParsedTemplateSchema[]; - configurations?: TemplateConfigurationsV1beta3; + presentation?: TemplatePresentationV1beta3; } => { const featureFlags = useApi(featureFlagsApiRef); const steps = manifest.steps.map(({ title, description, schema }) => ({ @@ -80,7 +80,7 @@ export const useTemplateSchema = ( })); return { - configurations: manifest.configurations, + presentation: manifest.presentation, steps: returningSteps, }; }; diff --git a/plugins/scaffolder-react/src/types.ts b/plugins/scaffolder-react/src/types.ts index f5c4cabc04..c1c26f32bb 100644 --- a/plugins/scaffolder-react/src/types.ts +++ b/plugins/scaffolder-react/src/types.ts @@ -16,7 +16,7 @@ import { JsonObject } from '@backstage/types'; -import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; /** * The shape of each entry of parameters which gets rendered @@ -27,7 +27,7 @@ import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-comm export type TemplateParameterSchema = { title: string; description?: string; - configurations?: TemplateConfigurationsV1beta3; + presentation?: TemplatePresentationV1beta3; steps: Array<{ title: string; description?: string; From d8d05f613c42c881e375881ee3dfddb91137d66e Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 23 Oct 2023 11:47:27 +0200 Subject: [PATCH 10/12] Updated to a presentation Signed-off-by: Bogdan Nechyporenko --- plugins/scaffolder-backend/src/service/router.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index f8bdb48e2b..194120f0f9 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -363,9 +363,12 @@ export async function createRouter( const template = await authorizeTemplate(req.params, token); const parameters = [template.spec.parameters ?? []].flat(); + + const presentation = template.spec.presentation; + res.json({ title: template.metadata.title ?? template.metadata.name, - presentation: template.spec.presentation ?? {}, + ...(presentation ? { presentation } : {}), description: template.metadata.description, 'ui:options': template.metadata['ui:options'], steps: parameters.map(schema => ({ From 27b3963e03cb87073af18a3f74a71df2038da04d Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 24 Oct 2023 12:57:06 +0200 Subject: [PATCH 11/12] Fix for flaky SearchContext.test.tsx Signed-off-by: Bogdan Nechyporenko --- plugins/search-react/src/context/SearchContext.test.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/search-react/src/context/SearchContext.test.tsx b/plugins/search-react/src/context/SearchContext.test.tsx index 5aa217553f..f962bc1620 100644 --- a/plugins/search-react/src/context/SearchContext.test.tsx +++ b/plugins/search-react/src/context/SearchContext.test.tsx @@ -405,11 +405,10 @@ describe('SearchContext', () => { await waitFor(() => { expect(result.current).toEqual(expect.objectContaining(initialState)); + expect(result.current.fetchNextPage).toBeUndefined(); + expect(result.current.fetchPreviousPage).toBeDefined(); }); - expect(result.current.fetchNextPage).toBeUndefined(); - expect(result.current.fetchPreviousPage).toBeDefined(); - await act(async () => { result.current.fetchPreviousPage!(); }); From f1257394dacd2b56cd29af9fc78274ba4d562ed6 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 24 Oct 2023 12:57:39 +0200 Subject: [PATCH 12/12] Updated api reports Signed-off-by: Bogdan Nechyporenko --- plugins/scaffolder-common/api-report.md | 20 ++++++++++---------- plugins/scaffolder-react/alpha-api-report.md | 4 ++-- plugins/scaffolder-react/api-report.md | 2 ++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/plugins/scaffolder-common/api-report.md b/plugins/scaffolder-common/api-report.md index 73289bcc47..8cfbd2aaac 100644 --- a/plugins/scaffolder-common/api-report.md +++ b/plugins/scaffolder-common/api-report.md @@ -44,15 +44,6 @@ export interface TaskStep { name: string; } -// @public -export interface TemplateConfigurationsV1beta3 extends JsonObject { - buttonLabels?: { - backButtonText?: string; - createButtonText?: string; - reviewButtonText?: string; - }; -} - // @public export interface TemplateEntityStepV1beta3 extends JsonObject { // (undocumented) @@ -75,7 +66,7 @@ export interface TemplateEntityV1beta3 extends Entity { kind: 'Template'; spec: { type: string; - configurations?: TemplateConfigurationsV1beta3; + presentation?: TemplatePresentationV1beta3; parameters?: TemplateParametersV1beta3 | TemplateParametersV1beta3[]; steps: Array; output?: { @@ -108,4 +99,13 @@ export interface TemplatePermissionsV1beta3 extends JsonObject { // (undocumented) tags?: string[]; } + +// @public +export interface TemplatePresentationV1beta3 extends JsonObject { + buttonLabels?: { + backButtonText?: string; + createButtonText?: string; + reviewButtonText?: string; + }; +} ``` diff --git a/plugins/scaffolder-react/alpha-api-report.md b/plugins/scaffolder-react/alpha-api-report.md index 282edf6457..3d9361bf18 100644 --- a/plugins/scaffolder-react/alpha-api-report.md +++ b/plugins/scaffolder-react/alpha-api-report.md @@ -30,10 +30,10 @@ import { ScaffolderStep } from '@backstage/plugin-scaffolder-react'; import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react'; import { SetStateAction } from 'react'; import { TaskStep } from '@backstage/plugin-scaffolder-common'; -import { TemplateConfigurationsV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; +import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; import { UiSchema } from '@rjsf/utils'; // @alpha (undocumented) @@ -305,7 +305,7 @@ export const useTemplateParameterSchema: (templateRef: string) => { // @alpha export const useTemplateSchema: (manifest: TemplateParameterSchema) => { steps: ParsedTemplateSchema[]; - configurations?: TemplateConfigurationsV1beta3 | undefined; + presentation?: TemplatePresentationV1beta3 | undefined; }; // @alpha (undocumented) diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index 6acc2f9812..8589078f1e 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -39,6 +39,7 @@ import { StrictRJSFSchema } from '@rjsf/utils'; import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { TaskStep } from '@backstage/plugin-scaffolder-common'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplatesType } from '@rjsf/utils'; import { UIOptionsType } from '@rjsf/utils'; import { UiSchema } from '@rjsf/utils'; @@ -482,6 +483,7 @@ export type TemplateGroupFilter = { export type TemplateParameterSchema = { title: string; description?: string; + presentation?: TemplatePresentationV1beta3; steps: Array<{ title: string; description?: string;