feat: Display the plugins InfoCards on EntityPage Overwiev suitable full height (#2826)
* fix(github-actions): change RecentWorkflowRunsCard to InfoCard * feat: format entity page overview page * feat: replace InfoCard variant 'height100' with 'gridItem' * fix: deprecate usage of InfoCard variant height100
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
---
|
||||
'example-app': minor
|
||||
'@backstage/core': minor
|
||||
'@backstage/create-app': minor
|
||||
'@backstage/plugin-catalog': minor
|
||||
'@backstage/plugin-github-actions': minor
|
||||
'@backstage/plugin-jenkins': minor
|
||||
'@backstage/plugin-lighthouse': minor
|
||||
---
|
||||
|
||||
The InfoCard variant `'height100'` is deprecated. Use variant `'gridItem'` instead.
|
||||
|
||||
When the InfoCard is displayed as a grid item within a grid, you may want items to have the same height for all items.
|
||||
Set to the `'gridItem'` variant to display the InfoCard with full height suitable for Grid:
|
||||
`<InfoCard variant="gridItem">...</InfoCard>`
|
||||
|
||||
Changed the InfoCards in '@backstage/plugin-github-actions', '@backstage/plugin-jenkins', '@backstage/plugin-lighthouse'
|
||||
to pass an optional variant to the corresponding card of the plugin.
|
||||
|
||||
As a result the overview content of the EntityPage shows cards with full height suitable for Grid.
|
||||
@@ -105,10 +105,12 @@ const RecentCICDRunsSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
let content: ReactNode;
|
||||
switch (true) {
|
||||
case isJenkinsAvailable(entity):
|
||||
content = <JenkinsLatestRunCard branch="master" />;
|
||||
content = <JenkinsLatestRunCard branch="master" variant="gridItem" />;
|
||||
break;
|
||||
case isGitHubActionsAvailable(entity):
|
||||
content = <RecentWorkflowRunsCard entity={entity} />;
|
||||
content = (
|
||||
<RecentWorkflowRunsCard entity={entity} limit={4} variant="gridItem" />
|
||||
);
|
||||
break;
|
||||
case isTravisCIAvailable(entity):
|
||||
content = <RecentTravisCIBuildsWidget entity={entity} />;
|
||||
@@ -127,9 +129,9 @@ const RecentCICDRunsSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
};
|
||||
|
||||
const OverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
<Grid container spacing={3}>
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
<Grid item md={6}>
|
||||
<AboutCard entity={entity} />
|
||||
<AboutCard entity={entity} variant="gridItem" />
|
||||
</Grid>
|
||||
<RecentCICDRunsSwitcher entity={entity} />
|
||||
{isGitHubAvailable(entity) && (
|
||||
@@ -145,7 +147,7 @@ const OverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
)}
|
||||
{isLighthouseAvailable(entity) && (
|
||||
<Grid item sm={4}>
|
||||
<LastLighthouseAuditCard />
|
||||
<LastLighthouseAuditCard variant="gridItem" />
|
||||
</Grid>
|
||||
)}
|
||||
{isPullRequestsAvailable(entity) && (
|
||||
|
||||
@@ -70,6 +70,15 @@ const VARIANT_STYLES = {
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
},
|
||||
gridItem: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: 'calc(100% - 10px)', // for pages without content header
|
||||
marginBottom: '10px',
|
||||
},
|
||||
/**
|
||||
* @deprecated This variant is replaced by 'gridItem'.
|
||||
*/
|
||||
height100: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
@@ -81,9 +90,15 @@ const VARIANT_STYLES = {
|
||||
fullHeight: {
|
||||
flex: 1,
|
||||
},
|
||||
/**
|
||||
* @deprecated This variant is replaced by 'gridItem'.
|
||||
*/
|
||||
height100: {
|
||||
flex: 1,
|
||||
},
|
||||
gridItem: {
|
||||
flex: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -100,9 +115,10 @@ const VARIANT_STYLES = {
|
||||
* By default the InfoCard has no custom layout of its children, but is treated as a block element. A
|
||||
* couple common variants are provided and can be specified via the variant property:
|
||||
*
|
||||
* Display the card full height suitable for DataGrid:
|
||||
* When the InfoCard is displayed as a grid item within a grid, you may want items to have the same height for all items.
|
||||
* Set to the 'gridItem' variant to display the InfoCard with full height suitable for Grid:
|
||||
*
|
||||
* <InfoCard variant="height100">...</InfoCard>
|
||||
* <InfoCard variant="gridItem">...</InfoCard>
|
||||
*/
|
||||
type Props = {
|
||||
title?: ReactNode;
|
||||
@@ -142,17 +158,21 @@ export const InfoCard = ({
|
||||
noPadding,
|
||||
}: Props): JSX.Element => {
|
||||
const classes = useStyles();
|
||||
|
||||
/**
|
||||
* If variant is specified, we build up styles for that particular variant for both
|
||||
* the Card and the CardContent (since these need to be synced)
|
||||
*/
|
||||
let calculatedStyle = {};
|
||||
let calculatedCardStyle = {};
|
||||
|
||||
if (variant) {
|
||||
const variants = variant.split(/[\s]+/g);
|
||||
variants.forEach(name => {
|
||||
if (name === 'height100') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
"Variant 'height100' of InfoCard is deprecated. Use variant 'gridItem' instead.",
|
||||
);
|
||||
}
|
||||
calculatedStyle = {
|
||||
...calculatedStyle,
|
||||
...VARIANT_STYLES.card[name as keyof typeof VARIANT_STYLES['card']],
|
||||
|
||||
+5
-5
@@ -53,9 +53,9 @@ const CICDSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
};
|
||||
|
||||
const OverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
<Grid container spacing={3}>
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
<Grid item>
|
||||
<AboutCard entity={entity} />
|
||||
<AboutCard entity={entity} variant="gridItem" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
@@ -77,7 +77,7 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
title="API"
|
||||
element={<ApiDocsRouter entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
<EntityPageLayout.Content
|
||||
path="/docs/*"
|
||||
title="Docs"
|
||||
element={<DocsRouter entity={entity} />}
|
||||
@@ -97,7 +97,7 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
title="CI/CD"
|
||||
element={<CICDSwitcher entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
<EntityPageLayout.Content
|
||||
path="/docs/*"
|
||||
title="Docs"
|
||||
element={<DocsRouter entity={entity} />}
|
||||
@@ -112,7 +112,7 @@ const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
title="Overview"
|
||||
element={<OverviewContent entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
<EntityPageLayout.Content
|
||||
path="/docs/*"
|
||||
title="Docs"
|
||||
element={<DocsRouter entity={entity} />}
|
||||
|
||||
@@ -58,6 +58,15 @@ const useStyles = makeStyles(theme => ({
|
||||
description: {
|
||||
wordBreak: 'break-word',
|
||||
},
|
||||
gridItemCard: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: 'calc(100% - 10px)', // for pages without content header
|
||||
marginBottom: '10px',
|
||||
},
|
||||
gridItemCardContent: {
|
||||
flex: 1,
|
||||
},
|
||||
}));
|
||||
|
||||
const iconMap: Record<string, React.ReactNode> = {
|
||||
@@ -82,14 +91,15 @@ function getCodeLinkInfo(entity: Entity): CodeLinkInfo {
|
||||
|
||||
type AboutCardProps = {
|
||||
entity: Entity;
|
||||
variant?: string;
|
||||
};
|
||||
|
||||
export function AboutCard({ entity }: AboutCardProps) {
|
||||
export function AboutCard({ entity, variant }: AboutCardProps) {
|
||||
const classes = useStyles();
|
||||
const codeLink = getCodeLinkInfo(entity);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Card className={variant === 'gridItem' ? classes.gridItemCard : ''}>
|
||||
<CardHeader
|
||||
title="About"
|
||||
action={
|
||||
@@ -114,7 +124,9 @@ export function AboutCard({ entity }: AboutCardProps) {
|
||||
}
|
||||
/>
|
||||
<Divider />
|
||||
<CardContent>
|
||||
<CardContent
|
||||
className={variant === 'gridItem' ? classes.gridItemCardContent : ''}
|
||||
>
|
||||
<Grid container>
|
||||
<AboutField label="Description" gridSizes={{ xs: 12 }}>
|
||||
<Typography
|
||||
|
||||
@@ -81,10 +81,9 @@ const WidgetContent = ({
|
||||
export const LatestWorkflowRunCard = ({
|
||||
entity,
|
||||
branch = 'master',
|
||||
}: {
|
||||
entity: Entity;
|
||||
branch: string;
|
||||
}) => {
|
||||
// Display the card full height suitable for
|
||||
variant,
|
||||
}: Props) => {
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const [owner, repo] = (
|
||||
entity?.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] ?? '/'
|
||||
@@ -102,7 +101,7 @@ export const LatestWorkflowRunCard = ({
|
||||
}, [error, errorApi]);
|
||||
|
||||
return (
|
||||
<InfoCard title={`Last ${branch} build`}>
|
||||
<InfoCard title={`Last ${branch} build`} variant={variant}>
|
||||
<WidgetContent
|
||||
error={error}
|
||||
loading={loading}
|
||||
@@ -113,14 +112,18 @@ export const LatestWorkflowRunCard = ({
|
||||
);
|
||||
};
|
||||
|
||||
type Props = {
|
||||
entity: Entity;
|
||||
branch: string;
|
||||
variant?: string;
|
||||
};
|
||||
|
||||
export const LatestWorkflowsForBranchCard = ({
|
||||
entity,
|
||||
branch = 'master',
|
||||
}: {
|
||||
entity: Entity;
|
||||
branch: string;
|
||||
}) => (
|
||||
<InfoCard title={`Last ${branch} build`}>
|
||||
variant,
|
||||
}: Props) => (
|
||||
<InfoCard title={`Last ${branch} build`} variant={variant}>
|
||||
<WorkflowRunsTable branch={branch} entity={entity} />
|
||||
</InfoCard>
|
||||
);
|
||||
|
||||
@@ -18,9 +18,9 @@ import { errorApiRef, useApi } from '@backstage/core-api';
|
||||
import { GITHUB_ACTIONS_ANNOTATION } from '../useProjectName';
|
||||
import { useWorkflowRuns } from '../useWorkflowRuns';
|
||||
import React, { useEffect } from 'react';
|
||||
import { EmptyState, Table } from '@backstage/core';
|
||||
import { EmptyState, InfoCard, Table } from '@backstage/core';
|
||||
import { WorkflowRunStatus } from '../WorkflowRunStatus';
|
||||
import { Button, Card, Link, TableContainer } from '@material-ui/core';
|
||||
import { Button, Link } from '@material-ui/core';
|
||||
import { generatePath, Link as RouterLink } from 'react-router-dom';
|
||||
|
||||
const firstLine = (message: string): string => message.split('\n')[0];
|
||||
@@ -30,6 +30,7 @@ export type Props = {
|
||||
branch?: string;
|
||||
dense?: boolean;
|
||||
limit?: number;
|
||||
variant?: string;
|
||||
};
|
||||
|
||||
export const RecentWorkflowRunsCard = ({
|
||||
@@ -37,6 +38,7 @@ export const RecentWorkflowRunsCard = ({
|
||||
branch,
|
||||
dense = false,
|
||||
limit = 5,
|
||||
variant,
|
||||
}: Props) => {
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const [owner, repo] = (
|
||||
@@ -70,15 +72,19 @@ export const RecentWorkflowRunsCard = ({
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<TableContainer component={Card}>
|
||||
<InfoCard
|
||||
title="Recent Workflow Runs"
|
||||
subheader={branch ? `Branch: ${branch}` : 'All Branches'}
|
||||
noPadding
|
||||
variant={variant}
|
||||
>
|
||||
<Table
|
||||
title="Recent Workflow Runs"
|
||||
subtitle={branch ? `Branch: ${branch}` : 'All Branches'}
|
||||
isLoading={loading}
|
||||
options={{
|
||||
search: false,
|
||||
paging: false,
|
||||
padding: dense ? 'dense' : 'default',
|
||||
toolbar: false,
|
||||
}}
|
||||
columns={[
|
||||
{
|
||||
@@ -98,6 +104,6 @@ export const RecentWorkflowRunsCard = ({
|
||||
]}
|
||||
data={runs}
|
||||
/>
|
||||
</TableContainer>
|
||||
</InfoCard>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -61,12 +61,18 @@ const WidgetContent = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const LatestRunCard = ({ branch = 'master' }: { branch: string }) => {
|
||||
export const LatestRunCard = ({
|
||||
branch = 'master',
|
||||
variant,
|
||||
}: {
|
||||
branch: string;
|
||||
variant?: string;
|
||||
}) => {
|
||||
const { owner, repo } = useProjectSlugFromEntity();
|
||||
const [{ builds, loading }] = useBuilds(owner, repo, branch);
|
||||
const lastRun = builds ?? {};
|
||||
return (
|
||||
<InfoCard title={`Last ${branch} build`}>
|
||||
<InfoCard title={`Last ${branch} build`} variant={variant}>
|
||||
<WidgetContent loading={loading} branch={branch} lastRun={lastRun} />
|
||||
</InfoCard>
|
||||
);
|
||||
|
||||
@@ -88,9 +88,10 @@ const LighthouseAuditSummary: FC<{ audit: Audit; dense?: boolean }> = ({
|
||||
return <StructuredMetadataTable metadata={tableData} dense={dense} />;
|
||||
};
|
||||
|
||||
export const LastLighthouseAuditCard: FC<{ dense?: boolean }> = ({
|
||||
dense = false,
|
||||
}) => {
|
||||
export const LastLighthouseAuditCard: FC<{
|
||||
dense?: boolean;
|
||||
variant?: string;
|
||||
}> = ({ dense = false, variant }) => {
|
||||
const { value: website, loading, error } = useWebsiteForEntity();
|
||||
|
||||
let content;
|
||||
@@ -105,5 +106,9 @@ export const LastLighthouseAuditCard: FC<{ dense?: boolean }> = ({
|
||||
<LighthouseAuditSummary audit={website.lastAudit} dense={dense} />
|
||||
);
|
||||
}
|
||||
return <InfoCard title="Lighthouse Audit">{content}</InfoCard>;
|
||||
return (
|
||||
<InfoCard title="Lighthouse Audit" variant={variant}>
|
||||
{content}
|
||||
</InfoCard>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user