Add component for multiple links
Signed-off-by: James Turley <james.turley@signalmedia.co> Signed-off-by: James Turley <jamesturley1905@googlemail.com>
This commit is contained in:
committed by
James Turley
parent
b96d9c5677
commit
baee14e5d6
@@ -22,28 +22,24 @@ import Step from '@material-ui/core/Step';
|
||||
import StepLabel from '@material-ui/core/StepLabel';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { generatePath, useParams } from 'react-router';
|
||||
import { useParams } from 'react-router';
|
||||
import { useTaskEventStream } from '../hooks/useEventStream';
|
||||
import LazyLog from 'react-lazylog/build/LazyLog';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
Paper,
|
||||
StepButton,
|
||||
StepIconProps,
|
||||
} from '@material-ui/core';
|
||||
import { Status } from '../../types';
|
||||
import { Status, TaskOutput } from '../../types';
|
||||
import { DateTime, Interval } from 'luxon';
|
||||
import { useInterval } from 'react-use';
|
||||
import Check from '@material-ui/icons/Check';
|
||||
import Cancel from '@material-ui/icons/Cancel';
|
||||
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
|
||||
import { entityRoute } from '@backstage/plugin-catalog-react';
|
||||
import { parseEntityName } from '@backstage/catalog-model';
|
||||
import classNames from 'classnames';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { TaskPageLinks } from './TaskPageLinks';
|
||||
|
||||
// typings are wrong for this library, so fallback to not parsing types.
|
||||
const humanizeDuration = require('humanize-duration');
|
||||
@@ -211,6 +207,9 @@ const TaskLogger = memo(({ log }: { log: string }) => {
|
||||
);
|
||||
});
|
||||
|
||||
const hasLinks = ({ entityRef, remoteUrl, links = [] }: TaskOutput): boolean =>
|
||||
!!(entityRef || remoteUrl || links.length > 0);
|
||||
|
||||
export const TaskPage = () => {
|
||||
const [userSelectedStepId, setUserSelectedStepId] = useState<
|
||||
string | undefined
|
||||
@@ -261,8 +260,8 @@ export const TaskPage = () => {
|
||||
taskStream.loading === false &&
|
||||
!taskStream.task;
|
||||
|
||||
const entityRef = taskStream.output?.entityRef;
|
||||
const remoteUrl = taskStream.output?.remoteUrl;
|
||||
const { output } = taskStream;
|
||||
|
||||
return (
|
||||
<Page themeId="home">
|
||||
<Header
|
||||
@@ -291,38 +290,8 @@ export const TaskPage = () => {
|
||||
currentStepId={currentStepId}
|
||||
onUserStepChange={setUserSelectedStepId}
|
||||
/>
|
||||
{(entityRef || remoteUrl) && (
|
||||
<Box
|
||||
px={3}
|
||||
pb={3}
|
||||
display="flex"
|
||||
flex={1}
|
||||
justifyContent="space-between"
|
||||
flexDirection="row"
|
||||
>
|
||||
{entityRef && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
component={Link}
|
||||
to={generatePath(
|
||||
`/catalog/${entityRoute.path}`,
|
||||
parseEntityName(entityRef),
|
||||
)}
|
||||
>
|
||||
Open in catalog
|
||||
</Button>
|
||||
)}
|
||||
{remoteUrl && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
href={remoteUrl}
|
||||
>
|
||||
Repo
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
{output && hasLinks(output) && (
|
||||
<TaskPageLinks output={output} />
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 { parseEntityName } from '@backstage/catalog-model';
|
||||
import { IconComponent, IconKey, IconLink, useApp } from '@backstage/core';
|
||||
import { entityRoute } from '@backstage/plugin-catalog-react';
|
||||
import { Box } from '@material-ui/core';
|
||||
import LanguageIcon from '@material-ui/icons/Language';
|
||||
import { generatePath } from 'react-router';
|
||||
import { TaskOutput } from '../../types';
|
||||
|
||||
type TaskPageLinksProps = {
|
||||
output: TaskOutput;
|
||||
};
|
||||
|
||||
export const TaskPageLinks = ({ output }: TaskPageLinksProps) => {
|
||||
const { entityRef, remoteUrl } = output;
|
||||
let { links = [] } = output;
|
||||
const app = useApp();
|
||||
|
||||
const iconResolver = (key: IconKey | undefined): IconComponent =>
|
||||
key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon;
|
||||
|
||||
if (remoteUrl) {
|
||||
links = [{ url: remoteUrl, title: 'Repo' }, ...links];
|
||||
}
|
||||
|
||||
if (entityRef) {
|
||||
links = [
|
||||
{
|
||||
url: generatePath(
|
||||
`/catalog/${entityRoute.path}`,
|
||||
parseEntityName(entityRef),
|
||||
),
|
||||
title: 'Open in catalog',
|
||||
icon: 'catalog',
|
||||
},
|
||||
...links,
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<Box px={3} pb={3}>
|
||||
{links.map(({ url, title, icon }, i) => (
|
||||
<IconLink
|
||||
key={`output-link-${i}`}
|
||||
href={url}
|
||||
text={title ?? url}
|
||||
Icon={iconResolver(icon)}
|
||||
target="_blank"
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -16,14 +16,9 @@
|
||||
import { useImmerReducer } from 'use-immer';
|
||||
import { useEffect } from 'react';
|
||||
import { scaffolderApiRef, LogEvent } from '../../api';
|
||||
import { ScaffolderTask, Status } from '../../types';
|
||||
import { ScaffolderTask, Status, TaskOutput } from '../../types';
|
||||
import { Subscription, useApi } from '@backstage/core';
|
||||
|
||||
type OutputLink = {
|
||||
title: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
type Step = {
|
||||
id: string;
|
||||
status: Status;
|
||||
@@ -31,11 +26,6 @@ type Step = {
|
||||
startedAt?: string;
|
||||
};
|
||||
|
||||
type TaskOutput = {
|
||||
entityRef?: string;
|
||||
links?: OutputLink[];
|
||||
} & { [key in string]: string };
|
||||
|
||||
export type TaskStream = {
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
|
||||
@@ -64,3 +64,16 @@ export type ListActionsResponse = Array<{
|
||||
output?: JSONSchema;
|
||||
};
|
||||
}>;
|
||||
|
||||
type OutputLink = {
|
||||
url: string;
|
||||
title?: string;
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
export type TaskOutput = {
|
||||
entityRef?: string;
|
||||
remoteUrl?: string;
|
||||
links?: OutputLink[];
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user