Merge pull request #16611 from backstage/blam/move-alpha

scaffolder/next: simplify the exported components
This commit is contained in:
Ben Lambert
2023-02-28 10:54:53 +01:00
committed by GitHub
25 changed files with 164 additions and 189 deletions
@@ -22,8 +22,10 @@ import { PropsWithChildren } from 'react';
import { default as React_2 } from 'react';
import { ReactNode } from 'react';
import { RJSFSchema } from '@rjsf/utils';
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 { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react';
import { UIOptionsType } from '@rjsf/utils';
@@ -140,6 +142,28 @@ export type StepperProps = {
layouts?: LayoutOptions[];
};
// @alpha
export const TaskLogStream: (props: {
logs: {
[k: string]: string[];
};
}) => JSX.Element;
// @alpha
export const TaskSteps: (props: TaskStepsProps) => JSX.Element;
// @alpha
export interface TaskStepsProps {
// (undocumented)
activeStep?: number;
// (undocumented)
isComplete?: boolean;
// (undocumented)
isError?: boolean;
// (undocumented)
steps: (TaskStep & ScaffolderStep)[];
}
// @alpha
export const TemplateCard: (props: TemplateCardProps) => JSX.Element;
+11 -39
View File
@@ -17,10 +17,6 @@ import { JsonValue } from '@backstage/types';
import { Observable } from '@backstage/types';
import { PropsWithChildren } from 'react';
import { default as React_2 } from 'react';
import { ScaffolderTask as ScaffolderTask_2 } from '@backstage/plugin-scaffolder-react';
import { ScaffolderTaskOutput as ScaffolderTaskOutput_2 } from '@backstage/plugin-scaffolder-react';
import { ScaffolderTaskStatus as ScaffolderTaskStatus_2 } from '@backstage/plugin-scaffolder-react';
import { Step as Step_2 } from '@backstage/plugin-scaffolder-react';
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
import { TaskStep } from '@backstage/plugin-scaffolder-common';
@@ -236,6 +232,14 @@ export interface ScaffolderScaffoldResponse {
taskId: string;
}
// @public
export type ScaffolderStep = {
id: string;
status: ScaffolderTaskStatus;
endedAt?: string;
startedAt?: string;
};
// @public
export interface ScaffolderStreamLogsOptions {
// (undocumented)
@@ -281,38 +285,6 @@ export const SecretsContextProvider: ({
children,
}: PropsWithChildren<{}>) => JSX.Element;
// @public
export type Step = {
id: string;
status: ScaffolderTaskStatus_2;
endedAt?: string;
startedAt?: string;
};
// @public (undocumented)
export interface StepperProps {
// (undocumented)
activeStep?: number;
// (undocumented)
steps: (TaskStep & Step_2)[];
}
// @public
export const TaskBorder: (props: {
isComplete: boolean;
isError: boolean;
}) => JSX.Element;
// @public
export const TaskLogStream: (props: {
logs: {
[k: string]: string[];
};
}) => JSX.Element;
// @public
export const TaskSteps: (props: StepperProps) => JSX.Element;
// @public
export type TaskStream = {
loading: boolean;
@@ -321,11 +293,11 @@ export type TaskStream = {
[stepId in string]: string[];
};
completed: boolean;
task?: ScaffolderTask_2;
task?: ScaffolderTask;
steps: {
[stepId in string]: Step;
[stepId in string]: ScaffolderStep;
};
output?: ScaffolderTaskOutput_2;
output?: ScaffolderTaskOutput;
};
// @public
@@ -1,79 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import {
Stepper as MuiStepper,
Step as MuiStep,
StepButton as MuiStepButton,
StepLabel as MuiStepLabel,
StepIconProps,
Box,
} from '@material-ui/core';
import { TaskStep } from '@backstage/plugin-scaffolder-common';
import { type Step } from '@backstage/plugin-scaffolder-react';
import { StepIcon } from './StepIcon';
import { StepTime } from './StepTime';
/**
*
* @public
*/
export interface StepperProps {
steps: (TaskStep & Step)[];
activeStep?: number;
}
/**
* The visual stepper of the task event stream
*
* @public
*/
export const TaskSteps = (props: StepperProps) => {
return (
<MuiStepper
activeStep={props.activeStep}
alternativeLabel
variant="elevation"
>
{props.steps.map((step, index) => {
const isCompleted = step.status === 'completed';
const isFailed = step.status === 'failed';
const isActive = step.status === 'processing';
const isSkipped = step.status === 'skipped';
const stepIconProps: Partial<StepIconProps & { skipped: boolean }> = {
completed: isCompleted,
error: isFailed,
active: isActive,
skipped: isSkipped,
};
return (
<MuiStep key={index}>
<MuiStepButton>
<MuiStepLabel
StepIconProps={stepIconProps}
StepIconComponent={StepIcon}
>
<Box>{step.name}</Box>
<StepTime step={step} />
</MuiStepLabel>
</MuiStepButton>
</MuiStep>
);
})}
</MuiStepper>
);
};
@@ -1,16 +0,0 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { TaskSteps, type StepperProps } from './TaskSteps';
@@ -1,18 +0,0 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { TaskSteps, type StepperProps } from './TaskSteps';
export { TaskBorder } from './TaskBorder';
export { TaskLogStream } from './TaskLogStream';
+1 -1
View File
@@ -19,5 +19,5 @@ export { useCustomLayouts } from './useCustomLayouts';
export {
useTaskEventStream,
type TaskStream,
type Step,
type ScaffolderStep,
} from './useEventStream';
@@ -15,22 +15,23 @@
*/
import { useImmerReducer } from 'use-immer';
import { useEffect } from 'react';
import {
ScaffolderTask,
ScaffolderTaskStatus,
ScaffolderTaskOutput,
LogEvent,
scaffolderApiRef,
} from '@backstage/plugin-scaffolder-react';
import { useApi } from '@backstage/core-plugin-api';
import { Subscription } from '@backstage/types';
import {
LogEvent,
scaffolderApiRef,
ScaffolderTask,
ScaffolderTaskOutput,
ScaffolderTaskStatus,
} from '../api';
/**
* The status of the step being processed
*
* @public
*/
export type Step = {
export type ScaffolderStep = {
id: string;
status: ScaffolderTaskStatus;
endedAt?: string;
@@ -48,7 +49,7 @@ export type TaskStream = {
stepLogs: { [stepId in string]: string[] };
completed: boolean;
task?: ScaffolderTask;
steps: { [stepId in string]: Step };
steps: { [stepId in string]: ScaffolderStep };
output?: ScaffolderTaskOutput;
};
@@ -75,7 +76,7 @@ function reducer(draft: TaskStream, action: ReducerAction) {
draft.steps = action.data.spec.steps.reduce((current, next) => {
current[next.id] = { status: 'open', id: next.id };
return current;
}, {} as { [stepId in string]: Step });
}, {} as { [stepId in string]: ScaffolderStep });
draft.stepLogs = action.data.spec.steps.reduce((current, next) => {
current[next.id] = [];
return current;
@@ -153,7 +154,7 @@ export const useTaskEventStream = (taskId: string): TaskStream => {
loading: true,
completed: false,
stepLogs: {} as { [stepId in string]: string[] },
steps: {} as { [stepId in string]: Step },
steps: {} as { [stepId in string]: ScaffolderStep },
});
useEffect(() => {
-1
View File
@@ -20,4 +20,3 @@ export * from './secrets';
export * from './api';
export * from './hooks';
export * from './layouts';
export * from './components';
@@ -26,7 +26,6 @@ import { type IChangeEvent } from '@rjsf/core-v5';
import { ErrorSchema } from '@rjsf/utils';
import React, { useCallback, useMemo, useState, type ReactNode } from 'react';
import { NextFieldExtensionOptions } from '../../extensions';
import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react';
import {
createAsyncValidators,
type FormValidation,
@@ -36,11 +35,14 @@ import { useTemplateSchema } from '../../hooks/useTemplateSchema';
import validator from '@rjsf/validator-ajv8';
import { useFormDataFromQuery } from '../../hooks';
import { FormProps } from '../../types';
import { LayoutOptions } from '@backstage/plugin-scaffolder-react';
import { useTransformSchemaToProps } from '../../hooks/useTransformSchemaToProps';
import { hasErrors } from './utils';
import * as FieldOverrides from './FieldOverrides';
import { Form } from '../Form';
import {
TemplateParameterSchema,
LayoutOptions,
} from '@backstage/plugin-scaffolder-react';
const useStyles = makeStyles(theme => ({
backButton: {
@@ -28,7 +28,7 @@ const useStyles = makeStyles({
/**
* The text of the event stream
*
* @public
* @alpha
*/
export const TaskLogStream = (props: { logs: { [k: string]: string[] } }) => {
const styles = useStyles();
@@ -28,8 +28,6 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({
/**
* The visual progress of the task event stream
*
* @public
*/
export const TaskBorder = (props: {
isComplete: boolean;
@@ -15,8 +15,8 @@
*/
import React from 'react';
import { TaskSteps } from './TaskSteps';
import { ScaffolderTaskStatus } from '@backstage/plugin-scaffolder-react';
import { renderInTestApp } from '@backstage/test-utils';
import { ScaffolderTaskStatus } from '../../../api';
describe('TaskSteps', () => {
it('should render each of the steps', async () => {
@@ -0,0 +1,93 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import {
Stepper as MuiStepper,
Step as MuiStep,
StepButton as MuiStepButton,
StepLabel as MuiStepLabel,
StepIconProps,
Box,
Paper,
} from '@material-ui/core';
import { TaskStep } from '@backstage/plugin-scaffolder-common';
import { StepIcon } from './StepIcon';
import { StepTime } from './StepTime';
import { TaskBorder } from './TaskBorder';
import { ScaffolderStep } from '@backstage/plugin-scaffolder-react';
/**
* Props for the TaskSteps component
*
* @alpha
*/
export interface TaskStepsProps {
steps: (TaskStep & ScaffolderStep)[];
activeStep?: number;
isComplete?: boolean;
isError?: boolean;
}
/**
* The visual stepper of the task event stream
*
* @alpha
*/
export const TaskSteps = (props: TaskStepsProps) => {
return (
<Paper style={{ position: 'relative', overflow: 'hidden' }}>
<TaskBorder
isComplete={props.isComplete ?? false}
isError={props.isError ?? false}
/>
<Box padding={2}>
<MuiStepper
activeStep={props.activeStep}
alternativeLabel
variant="elevation"
>
{props.steps.map((step, index) => {
const isCompleted = step.status === 'completed';
const isFailed = step.status === 'failed';
const isActive = step.status === 'processing';
const isSkipped = step.status === 'skipped';
const stepIconProps: Partial<StepIconProps & { skipped: boolean }> =
{
completed: isCompleted,
error: isFailed,
active: isActive,
skipped: isSkipped,
};
return (
<MuiStep key={index}>
<MuiStepButton>
<MuiStepLabel
StepIconProps={stepIconProps}
StepIconComponent={StepIcon}
>
<Box>{step.name}</Box>
<StepTime step={step} />
</MuiStepLabel>
</MuiStepButton>
</MuiStep>
);
})}
</MuiStepper>
</Box>
</Paper>
);
};
@@ -13,4 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { TaskBorder } from './TaskBorder';
export { TaskSteps, type TaskStepsProps } from './TaskSteps';
@@ -20,3 +20,5 @@ export * from './TemplateGroup';
export * from './Workflow';
export * from './TemplateOutputs';
export * from './Form';
export * from './TaskSteps';
export * from './TaskLogStream';
@@ -21,9 +21,8 @@ import {
} from './types';
import { Extension, attachComponentData } from '@backstage/core-plugin-api';
import { UIOptionsType } from '@rjsf/utils';
// eslint-disable-next-line import/no-extraneous-dependencies
import { FieldExtensionComponent } from '@backstage/plugin-scaffolder-react';
import { FIELD_EXTENSION_KEY } from '../../extensions/keys';
import { FieldExtensionComponent } from '@backstage/plugin-scaffolder-react';
/**
* Method for creating field extensions that can be used in the scaffolder
@@ -18,7 +18,7 @@ import { renderHook } from '@testing-library/react-hooks';
import { TestApiProvider } from '@backstage/test-utils';
import React from 'react';
import { featureFlagsApiRef } from '@backstage/core-plugin-api';
import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react';
import { TemplateParameterSchema } from '../../types';
describe('useTemplateSchema', () => {
it('should generate the correct schema', () => {
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { LayoutOptions } from '../../layouts';
import { type ParsedTemplateSchema } from './useTemplateSchema';
import { type LayoutOptions } from '@backstage/plugin-scaffolder-react';
interface Options {
layouts?: LayoutOptions[];
@@ -18,9 +18,6 @@ import { Page, Header, Content, ErrorPanel } from '@backstage/core-components';
import { useNavigate, useParams } from 'react-router-dom';
import { Box, makeStyles, Paper } from '@material-ui/core';
import {
TaskSteps,
TaskBorder,
TaskLogStream,
ScaffolderTaskOutput,
useTaskEventStream,
} from '@backstage/plugin-scaffolder-react';
@@ -28,7 +25,11 @@ import { nextSelectedTemplateRouteRef } from '../routes';
import { useRouteRef } from '@backstage/core-plugin-api';
import qs from 'qs';
import { ContextMenu } from './ContextMenu';
import { DefaultTemplateOutputs } from '@backstage/plugin-scaffolder-react/alpha';
import {
DefaultTemplateOutputs,
TaskLogStream,
TaskSteps,
} from '@backstage/plugin-scaffolder-react/alpha';
const useStyles = makeStyles({
contentWrapper: {
@@ -132,15 +133,12 @@ export const OngoingTask = (props: {
) : null}
<Box paddingBottom={2}>
<Paper style={{ position: 'relative', overflow: 'hidden' }}>
<TaskBorder
isComplete={taskStream.completed}
isError={Boolean(taskStream.error)}
/>
<Box padding={2}>
<TaskSteps steps={steps} activeStep={activeStep} />
</Box>
</Paper>
<TaskSteps
steps={steps}
activeStep={activeStep}
isComplete={taskStream.completed}
isError={Boolean(taskStream.error)}
/>
</Box>
<Outputs output={taskStream.output} />