feat(scaffolder): support text outputs from templates

Signed-off-by: Zander Franks <zander@zanderf.net>
This commit is contained in:
Zander Franks
2023-05-03 17:35:16 -05:00
parent 021cfbb515
commit 906dc9223c
4 changed files with 135 additions and 10 deletions
@@ -84,9 +84,17 @@ export type ScaffolderOutputLink = {
entityRef?: string;
};
/** @public */
export type ScaffolderOutputText = {
title?: string;
icon?: string;
data?: string;
};
/** @public */
export type ScaffolderTaskOutput = {
links?: ScaffolderOutputLink[];
text?: ScaffolderOutputText[];
} & {
[key: string]: unknown;
};
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Box, Paper } from '@material-ui/core';
import { LinkOutputs } from './LinkOutputs';
import { InfoCard, MarkdownContent } from '@backstage/core-components';
import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react';
import { Box, Paper } from '@material-ui/core';
import React, { useMemo, useState } from 'react';
import { LinkOutputs } from './LinkOutputs';
import { TextOutputs } from './TextOutputs';
/**
* The DefaultOutputs renderer for the scaffolder task output
@@ -26,17 +28,47 @@ import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react';
export const DefaultTemplateOutputs = (props: {
output?: ScaffolderTaskOutput;
}) => {
if (!props.output?.links) {
const [textOutputIndex, setTextOutputIndex] = useState<number | undefined>();
const textOutput = useMemo(
() =>
textOutputIndex !== undefined
? props.output?.text?.[textOutputIndex]
: null,
[props.output, textOutputIndex],
);
if (!props.output) {
return null;
}
return (
<Box paddingBottom={2}>
<Paper>
<Box padding={2} justifyContent="center" display="flex" gridGap={16}>
<LinkOutputs output={props.output} />
<>
<Box paddingBottom={2}>
<Paper>
<Box padding={2} justifyContent="center" display="flex" gridGap={16}>
<TextOutputs
output={props.output}
index={textOutputIndex}
setIndex={setTextOutputIndex}
/>
<LinkOutputs output={props.output} />
</Box>
</Paper>
</Box>
{textOutput ? (
<Box paddingBottom={2}>
<InfoCard
title={textOutput.title ?? 'Text Output'}
noPadding
titleTypographyProps={{ component: 'h2' }}
>
<Box padding={2} height="100%">
<MarkdownContent content={textOutput.data ?? ''} />
</Box>
</InfoCard>
</Box>
</Paper>
</Box>
) : null}
</>
);
};
@@ -0,0 +1,58 @@
/*
* 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.
*/
import { IconComponent, useApp } from '@backstage/core-plugin-api';
import { Button } from '@material-ui/core';
import WebIcon from '@material-ui/icons/Web';
import React from 'react';
import { ScaffolderTaskOutput } from '../../../api';
export const TextOutputs = (props: {
output: ScaffolderTaskOutput;
index?: number;
setIndex?: (index: number | undefined) => void;
}) => {
const {
output: { text = [] },
index,
setIndex,
} = props;
const app = useApp();
const iconResolver = (key?: string): IconComponent =>
app.getSystemIcon(key!) ?? WebIcon;
return (
<>
{text
.filter(({ data }) => data)
.map(({ title, icon }, i) => {
const Icon = iconResolver(icon);
return (
<Button
startIcon={<Icon />}
component="div"
color="primary"
onClick={() => setIndex?.(index !== i ? i : undefined)}
variant={index === i ? 'outlined' : undefined}
>
{title}
</Button>
);
})}
</>
);
};