Merge pull request #2623 from BA1RY/feat/entity-404-page-2266
feat: 404 page for entity not found in catalog
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2020 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 { Grid, Button, Typography } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
import { Illo } from './Illo';
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
container: {
|
||||
paddingTop: theme.spacing(24),
|
||||
paddingLeft: theme.spacing(8),
|
||||
},
|
||||
title: {
|
||||
paddingBottom: theme.spacing(2),
|
||||
},
|
||||
body: {
|
||||
paddingBottom: theme.spacing(6),
|
||||
},
|
||||
}));
|
||||
|
||||
export const EntityNotFound = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Grid container className={classes.container}>
|
||||
<Illo />
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Typography variant="h2" className={classes.title}>
|
||||
Entity was not found
|
||||
</Typography>
|
||||
<Typography variant="body1" className={classes.body}>
|
||||
Want to help us build this? Check out our Getting Started
|
||||
documentation.
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
href="https://backstage.io/docs"
|
||||
>
|
||||
DOCS
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2020 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 { makeStyles } from '@material-ui/core';
|
||||
import IlloSvgUrl from './illo.svg';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
illo: {
|
||||
maxWidth: '60%',
|
||||
top: 100,
|
||||
right: 20,
|
||||
position: 'absolute',
|
||||
},
|
||||
});
|
||||
|
||||
export const Illo = () => {
|
||||
const classes = useStyles();
|
||||
return <img src={IlloSvgUrl} className={classes.illo} alt="" />;
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<svg width="687" height="421" viewBox="0 0 687 421" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="16.231" y="114.353" width="407.223" height="48.4618" rx="24.2309" transform="rotate(-10.5556 16.231 114.353)" fill="#D9D9D9"/>
|
||||
<rect x="56.5332" y="151.306" width="337.679" height="48.4618" rx="24.2309" transform="rotate(-10.5556 56.5332 151.306)" fill="#D9D9D9"/>
|
||||
<rect x="54.707" y="274.403" width="441.061" height="48.4618" rx="24.2309" transform="rotate(-10.5556 54.707 274.403)" fill="#D9D9D9"/>
|
||||
<rect x="38.1221" y="321.956" width="440.421" height="48.4618" rx="24.2309" transform="rotate(-10.5556 38.1221 321.956)" fill="#D9D9D9"/>
|
||||
<rect x="213.923" y="147.109" width="435.885" height="48.4618" rx="24.2309" transform="rotate(-10.5556 213.923 147.109)" fill="#D9D9D9"/>
|
||||
<rect x="199.842" y="194.196" width="431.054" height="48.4618" rx="24.2309" transform="rotate(-10.5556 199.842 194.196)" fill="#D9D9D9"/>
|
||||
<rect x="235.299" y="292.946" width="394.936" height="48.4618" rx="24.2309" transform="rotate(-10.5556 235.299 292.946)" fill="#D9D9D9"/>
|
||||
<rect x="199.862" y="344.013" width="456.282" height="48.4618" rx="24.2309" transform="rotate(-10.5556 199.862 344.013)" fill="#D9D9D9"/>
|
||||
<g filter="url(#filter0_d)">
|
||||
<rect x="126" y="67" width="461" height="286" rx="10" fill="#F8F8F8"/>
|
||||
<rect x="154" y="91" width="90" height="67.2827" fill="#D9D9D9"/>
|
||||
<rect x="154" y="175.354" width="90" height="69.2911" fill="#D9D9D9"/>
|
||||
<rect x="154" y="261.717" width="90" height="67.2827" fill="#D9D9D9"/>
|
||||
<rect x="259" y="91" width="90" height="67.2827" fill="#D9D9D9"/>
|
||||
<rect x="364" y="91" width="90" height="67.2827" fill="#D9D9D9"/>
|
||||
<rect x="364" y="175.354" width="90" height="69.2911" fill="#EEEEEE"/>
|
||||
<rect x="364" y="261.717" width="90" height="67.2827" fill="#D9D9D9"/>
|
||||
<rect x="259" y="175.354" width="90" height="69.2911" fill="#D9D9D9"/>
|
||||
<rect x="259" y="261.717" width="90" height="67.2827" fill="#D9D9D9"/>
|
||||
<rect x="469" y="91" width="90" height="67.2827" fill="#D9D9D9"/>
|
||||
<rect x="469" y="175.354" width="90" height="69.2911" fill="#D9D9D9"/>
|
||||
<rect x="469" y="261.717" width="90" height="67.2827" fill="#D9D9D9"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_d" x="116" y="59" width="485" height="310" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
|
||||
<feOffset dx="2" dy="4"/>
|
||||
<feGaussianBlur stdDeviation="6"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
export { EntityNotFound } from './EntityNotFound';
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
import React, { ComponentType } from 'react';
|
||||
import { CatalogPage } from './CatalogPage';
|
||||
import { EntityNotFound } from './EntityNotFound';
|
||||
import { EntityPageLayout } from './EntityPageLayout';
|
||||
import { Route, Routes } from 'react-router';
|
||||
import { entityRoute, rootRoute } from '../routes';
|
||||
@@ -45,9 +46,10 @@ const DefaultEntityPage = () => (
|
||||
);
|
||||
|
||||
const EntityPageSwitch = ({ EntityPage }: { EntityPage: ComponentType }) => {
|
||||
const { entity } = useEntity();
|
||||
const { entity, loading, error } = useEntity();
|
||||
// Loading and error states
|
||||
if (!entity) return <EntityPageLayout />;
|
||||
if (loading) return <EntityPageLayout />;
|
||||
if (error || (!loading && !entity)) return <EntityNotFound />;
|
||||
|
||||
// Otherwise EntityPage provided from the App
|
||||
// Note that EntityPage will include EntityPageLayout already
|
||||
|
||||
@@ -20,8 +20,6 @@ import { catalogApiRef } from '../api/types';
|
||||
import { useAsync } from 'react-use';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
const REDIRECT_DELAY = 2000;
|
||||
|
||||
type EntityLoadingStatus = {
|
||||
entity?: Entity;
|
||||
loading: boolean;
|
||||
@@ -47,13 +45,6 @@ export const useEntityFromUrl = (): EntityLoadingStatus => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (error || (!loading && !entity)) {
|
||||
errorApi.post(new Error('Entity not found!'));
|
||||
setTimeout(() => {
|
||||
navigate('/');
|
||||
}, REDIRECT_DELAY);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
errorApi.post(new Error('No name provided!'));
|
||||
navigate('/');
|
||||
@@ -67,6 +58,10 @@ export const useEntityFromUrl = (): EntityLoadingStatus => {
|
||||
* Always going to return an entity, or throw an error if not a descendant of a EntityProvider.
|
||||
*/
|
||||
export const useEntity = () => {
|
||||
const { entity } = useContext<{ entity: Entity }>(EntityContext as any);
|
||||
return { entity };
|
||||
const { entity, loading, error } = useContext<{
|
||||
entity: Entity;
|
||||
loading: boolean;
|
||||
error: Error;
|
||||
}>(EntityContext as any);
|
||||
return { entity, loading, error };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user