Merge pull request #6497 from tudi2d/entity-page-responsiveness

EntityPage responsiveness
This commit is contained in:
Tim Hansen
2021-07-20 21:01:34 -06:00
committed by GitHub
10 changed files with 132 additions and 73 deletions
+15
View File
@@ -0,0 +1,15 @@
---
'@backstage/core-components': patch
'@backstage/create-app': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-techdocs': patch
---
Improve the responsiveness of the EntityPage UI. With this the Header component should scale with the screen size & wrapping should not cause overflowing/blocking of links. Additionally enforce the Pages using the Grid Layout to use it across all screen sizes & to wrap as intended.
To benefit from the improved responsive layout, the `EntityPage` in existing Backstage applications should be updated to set the `xs` column size on each grid item in the page, as this does not default. For example:
```diff
- <Grid item md={6}>
+ <Grid item xs={12} md={6}>
```
@@ -135,6 +135,13 @@ const EntityLayoutWrapper = (props: { children?: ReactNode }) => {
);
};
/**
* NOTE: This page is designed to work on small screens such as mobile devices.
* This is based on Material UI Grid. If breakpoints are used, each grid item must set the `xs` prop to a column size or to `true`,
* since this does not default. If no breakpoints are used, the items will equitably share the asvailable space.
* https://material-ui.com/components/grid/#basic-grid.
*/
export const cicdContent = (
<EntitySwitch>
<EntitySwitch.Case if={isJenkinsAvailable}>
@@ -292,10 +299,10 @@ const serviceEntityPage = (
<EntityLayout.Route path="/api" title="API">
<Grid container spacing={3} alignItems="stretch">
<Grid item md={6}>
<Grid item xs={12} md={6}>
<EntityProvidedApisCard />
</Grid>
<Grid item md={6}>
<Grid item xs={12} md={6}>
<EntityConsumedApisCard />
</Grid>
</Grid>
@@ -303,10 +310,10 @@ const serviceEntityPage = (
<EntityLayout.Route path="/dependencies" title="Dependencies">
<Grid container spacing={3} alignItems="stretch">
<Grid item md={6}>
<Grid item xs={12} md={6}>
<EntityDependsOnComponentsCard variant="gridItem" />
</Grid>
<Grid item md={6}>
<Grid item xs={12} md={6}>
<EntityDependsOnResourcesCard variant="gridItem" />
</Grid>
</Grid>
@@ -431,15 +438,17 @@ const apiPage = (
<EntityLayoutWrapper>
<EntityLayout.Route path="/" title="Overview">
<Grid container spacing={3}>
<Grid item md={6}>
<Grid item xs={12}>
<EntityAboutCard />
</Grid>
<Grid container item md={12}>
<Grid item md={6}>
<EntityProvidingComponentsCard />
</Grid>
<Grid item md={6}>
<EntityConsumingComponentsCard />
<Grid item xs={12}>
<Grid container>
<Grid item xs={12} md={6}>
<EntityProvidingComponentsCard />
</Grid>
<Grid item xs={12} md={6}>
<EntityConsumingComponentsCard />
</Grid>
</Grid>
</Grid>
</Grid>
@@ -49,15 +49,17 @@ export const EmptyState = ({ title, description, missing, action }: Props) => {
className={classes.root}
spacing={2}
>
<Grid item container direction="column" xs={12} md={6}>
<Grid item>
<Typography variant="h5">{title}</Typography>
</Grid>
<Grid item>
<Typography variant="body1">{description}</Typography>
</Grid>
<Grid item className={classes.action}>
{action}
<Grid item xs={12} md={6}>
<Grid container direction="column">
<Grid item xs>
<Typography variant="h5">{title}</Typography>
</Grid>
<Grid item xs>
<Typography variant="body1">{description}</Typography>
</Grid>
<Grid item xs className={classes.action}>
{action}
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={6} className={classes.imageContainer}>
@@ -29,7 +29,7 @@ const useStyles = makeStyles({
generalImg: {
width: '95%',
zIndex: 2,
position: 'absolute',
position: 'relative',
left: '50%',
top: '50%',
transform: 'translate(-50%, 15%)',
@@ -16,17 +16,20 @@
import { useApi, configApiRef } from '@backstage/core-plugin-api';
import { BackstageTheme } from '@backstage/theme';
import { makeStyles, Tooltip, Typography } from '@material-ui/core';
import { Box, Grid, makeStyles, Tooltip, Typography } from '@material-ui/core';
import React, { CSSProperties, PropsWithChildren, ReactNode } from 'react';
import { Helmet } from 'react-helmet';
import { Link } from '../../components/Link';
import { Breadcrumbs } from '../Breadcrumbs';
const minHeaderHeight = 118;
const useStyles = makeStyles<BackstageTheme>(theme => ({
header: {
gridArea: 'pageHeader',
padding: theme.spacing(3),
minHeight: 118,
height: 'fit-content',
minHeight: minHeaderHeight,
width: '100%',
boxShadow: '0 0 8px 3px rgba(20, 20, 20, 0.3)',
position: 'relative',
@@ -34,26 +37,21 @@ const useStyles = makeStyles<BackstageTheme>(theme => ({
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'flex-end',
alignItems: 'center',
backgroundImage: theme.page.backgroundImage,
backgroundPosition: 'center',
backgroundSize: 'cover',
},
leftItemsBox: {
flex: '1 1 auto',
maxWidth: '100%',
flexGrow: 1,
marginBottom: theme.spacing(1),
},
rightItemsBox: {
flex: '0 1 auto',
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
marginRight: theme.spacing(1),
width: 'auto',
},
title: {
color: theme.palette.bursts.fontColor,
lineHeight: '1.0em',
wordBreak: 'break-all',
fontSize: 'calc(24px + 6 * ((100vw - 320px) / 680))',
marginBottom: theme.spacing(1),
@@ -199,7 +197,7 @@ export const Header = ({
<>
<Helmet titleTemplate={titleTemplate} defaultTitle={defaultTitle} />
<header style={style} className={classes.header}>
<div className={classes.leftItemsBox}>
<Box className={classes.leftItemsBox}>
<TypeFragment
classes={classes}
type={type}
@@ -212,8 +210,10 @@ export const Header = ({
tooltip={tooltip}
/>
<SubtitleFragment classes={classes} subtitle={subtitle} />
</div>
<div className={classes.rightItemsBox}>{children}</div>
</Box>
<Grid container className={classes.rightItemsBox} spacing={4}>
{children}
</Grid>
</header>
</>
);
@@ -14,29 +14,25 @@
* limitations under the License.
*/
import { Link, makeStyles, Typography } from '@material-ui/core';
import { Link, makeStyles, Typography, Grid } from '@material-ui/core';
import React from 'react';
const useStyles = makeStyles(theme => ({
root: {
textAlign: 'left',
margin: theme.spacing(2),
display: 'inline-block',
},
label: {
color: '#FFFFFF',
color: theme.palette.common.white,
fontWeight: 'bold',
lineHeight: '16px',
letterSpacing: 0,
fontSize: 14,
height: '16px',
marginBottom: 2,
fontSize: theme.typography.fontSize,
marginBottom: theme.spacing(1) / 2,
lineHeight: 1,
},
value: {
color: 'rgba(255, 255, 255, 0.8)',
lineHeight: '16px',
fontSize: 14,
height: '16px',
fontSize: theme.typography.fontSize,
lineHeight: 1,
},
}));
@@ -64,9 +60,11 @@ export const HeaderLabel = ({ label, value, url }: HeaderLabelProps) => {
/>
);
return (
<span className={classes.root}>
<Typography className={classes.label}>{label}</Typography>
{url ? <Link href={url}>{content}</Link> : content}
</span>
<Grid item>
<span className={classes.root}>
<Typography className={classes.label}>{label}</Typography>
{url ? <Link href={url}>{content}</Link> : content}
</span>
</Grid>
);
};
@@ -157,6 +157,13 @@ const websiteEntityPage = (
</EntityLayout>
);
/**
* NOTE: This page is designed to work on small screens such as mobile devices.
* This is based on Material UI Grid. If breakpoints are used, each grid item must set the `xs` prop to a column size or to `true`,
* since this does not default. If no breakpoints are used, the items will equitably share the asvailable space.
* https://material-ui.com/components/grid/#basic-grid.
*/
const defaultEntityPage = (
<EntityLayout>
<EntityLayout.Route path="/" title="Overview">
+9 -7
View File
@@ -59,15 +59,17 @@ const apiPage = (
<EntityLayout>
<EntityLayout.Route path="/" title="Overview">
<Grid container spacing={3}>
<Grid item md={6}>
<Grid item xs={12} md={6}>
<EntityAboutCard />
</Grid>
<Grid container item md={12}>
<Grid item md={6}>
<EntityProvidingComponentsCard />
</Grid>
<Grid item md={6}>
<EntityConsumingComponentsCard />
<Grid container>
<Grid item md={12}>
<Grid item xs={12} md={6}>
<EntityProvidingComponentsCard />
</Grid>
<Grid item xs={12} md={6}>
<EntityConsumingComponentsCard />
</Grid>
</Grid>
</Grid>
</Grid>
@@ -20,9 +20,17 @@ import {
RELATION_OWNED_BY,
} from '@backstage/catalog-model';
import {
useElementFilter,
Content,
Header,
HeaderLabel,
Page,
Progress,
RoutedTabs,
} from '@backstage/core-components';
import {
attachComponentData,
IconComponent,
useElementFilter,
} from '@backstage/core-plugin-api';
import {
EntityContext,
@@ -37,14 +45,6 @@ import { useNavigate } from 'react-router';
import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';
import { FavouriteEntity } from '../FavouriteEntity/FavouriteEntity';
import { UnregisterEntityDialog } from '../UnregisterEntityDialog/UnregisterEntityDialog';
import {
Content,
Header,
HeaderLabel,
Page,
Progress,
RoutedTabs,
} from '@backstage/core-components';
type SubRoute = {
path: string;
@@ -68,12 +68,21 @@ const EntityLayoutTitle = ({
}: {
title: string;
entity: Entity | undefined;
}) => (
<Box display="inline-flex" alignItems="center" height="1em">
{title}
{entity && <FavouriteEntity entity={entity} />}
</Box>
);
}) => {
return (
<Box display="inline-flex" alignItems="center" height="1em" maxWidth="100%">
<Box
component="span"
textOverflow="ellipsis"
whiteSpace="nowrap"
overflow="hidden"
>
{title}
</Box>
{entity && <FavouriteEntity entity={entity} />}
</Box>
);
};
const headerProps = (
paramKind: string | undefined,
@@ -19,7 +19,12 @@ import { Progress } from '@backstage/core-components';
import { useApi } from '@backstage/core-plugin-api';
import { scmIntegrationsApiRef } from '@backstage/integration-react';
import { BackstageTheme } from '@backstage/theme';
import { Button, CircularProgress, useTheme } from '@material-ui/core';
import {
Button,
CircularProgress,
makeStyles,
useTheme,
} from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
@@ -45,10 +50,20 @@ type Props = {
onReady?: () => void;
};
const useStyles = makeStyles<BackstageTheme>(() => ({
message: {
// `word-break: break-word` is deprecated, but gives legacy support to browsers not supporting `overflow-wrap` yet
// https://developer.mozilla.org/en-US/docs/Web/CSS/word-break
wordBreak: 'break-word',
overflowWrap: 'anywhere',
},
}));
export const Reader = ({ entityId, onReady }: Props) => {
const { kind, namespace, name } = entityId;
const { '*': path } = useParams();
const theme = useTheme<BackstageTheme>();
const classes = useStyles();
const {
state,
@@ -369,6 +384,7 @@ export const Reader = ({ entityId, onReady }: Props) => {
variant="outlined"
severity="error"
action={<TechDocsBuildLogs buildLog={buildLog} />}
classes={{ message: classes.message }}
>
Building a newer version of this documentation failed.{' '}
{syncErrorMessage}
@@ -381,6 +397,7 @@ export const Reader = ({ entityId, onReady }: Props) => {
variant="outlined"
severity="error"
action={<TechDocsBuildLogs buildLog={buildLog} />}
classes={{ message: classes.message }}
>
Building a newer version of this documentation failed.{' '}
{syncErrorMessage}