Clean up code according to review

Signed-off-by: Philipp Hugenroth <philipph@spotify.com>
This commit is contained in:
Philipp Hugenroth
2021-07-16 13:19:27 +02:00
parent 3ee8e75892
commit b044fa6f7c
19 changed files with 136 additions and 247 deletions
+3 -1
View File
@@ -5,4 +5,6 @@
'@backstage/plugin-catalog': patch
---
Build a general TablePage component to enforce a more responsive layout for the Catalog & API page. Filters are now wrapped in an accordion on smaller screens, enabling the user to see & interact better with the table. Additionally, a test was added, to check that the responsive wrapping is working for the Catalog page.
Changing the layout of the Catalog & API page to use responsive wrappers for table & filters. The goal is to enforce a responsive layout & that the Catalog & API page are better useable on smaller screens by showing more of the main content. To apply this changes to your custom catalog page, you can add the wrappers following the updated documentation on catalog customization.
Additionally, the tests for Material UI breakpoints were adjusted & used to test the responsive wrappers.
@@ -29,25 +29,27 @@ default catalog page and create a component in a
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx
export const CustomCatalogPage = () => {
return (
<CatalogLayout>
<PageWithHeader title={`${orgName} Catalog`} themeId="home">
<Content>
<ContentHeader title="Components">
<CreateComponentButton />
<SupportButton>All your software catalog entities</SupportButton>
</ContentHeader>
<div className={styles.contentWrapper}>
<EntityListProvider>
<div>
<EntityListProvider>
<FilteredEntityLayout>
<FilterContainer>
<EntityKindPicker initialFilter="component" hidden />
<EntityTypePicker />
<UserListPicker />
<UserListPicker initialFilter={initiallySelectedFilter} />
<EntityTagPicker />
</div>
<CatalogTable />
</EntityListProvider>
</div>
</FilterContainer>
<EntityListContainer>
<CatalogTable columns={columns} actions={actions} />
</EntityListContainer>
</FilteredEntityLayout>
</EntityListProvider>
</Content>
</CatalogLayout>
</PageWithHeader>
);
};
```
@@ -141,14 +143,18 @@ export const CustomCatalogPage = () => {
return (
...
<EntityListProvider>
<div>
<EntityKindPicker initialFilter="component" hidden />
<EntityTypePicker />
<UserListPicker />
+ <EntitySecurityTierPicker />
<EntityTagPicker />
</div>
<CatalogTable />
<FilteredEntityLayout>
<FilterContainer>
<EntityKindPicker initialFilter="component" hidden />
<EntityTypePicker />
<UserListPicker />
+ <EntitySecurityTierPicker />
<EntityTagPicker />
<FilterContainer>
<EntityListContainer>
<CatalogTable />
</EntityListContainer>
</FilteredEntityLayout>
</EntityListProvider>
...
};
@@ -100,8 +100,9 @@ export const SupportButton = ({ title, children }: SupportButtonProps) => {
color="primary"
onClick={onClickHandler}
>
<HelpIcon />
<Box mr={1} />
<Box mr={1} height={24}>
<HelpIcon />
</Box>
Support
</Button>
<Popover
@@ -57,7 +57,7 @@ const useStyles = (props: ContentHeaderProps) =>
},
}));
type DefaultTitleProps = {
type ContentHeaderTitleProps = {
title?: string;
className?: string;
};
@@ -65,7 +65,7 @@ type DefaultTitleProps = {
const ContentHeaderTitle = ({
title = 'Unknown page',
className,
}: DefaultTitleProps) => (
}: ContentHeaderTitleProps) => (
<Typography
variant="h4"
component="h2"
@@ -77,7 +77,7 @@ const ContentHeaderTitle = ({
);
type ContentHeaderProps = {
title?: DefaultTitleProps['title'];
title?: ContentHeaderTitleProps['title'];
titleComponent?: ComponentType;
description?: string;
textAlign?: 'left' | 'right' | 'center';
@@ -14,20 +14,20 @@
* limitations under the License.
*/
import React from 'react';
import React, { ComponentProps } from 'react';
import { Header } from '../Header';
import { Page } from './';
import { Page } from './Page';
interface IProps extends React.ComponentProps<typeof Header> {
type ThemedHeaderProps = ComponentProps<typeof Header> & {
themeId: string;
}
};
export const PageWithHeader = ({
themeId,
children,
...props
}: React.PropsWithChildren<IProps>) => (
}: React.PropsWithChildren<ThemedHeaderProps>) => (
<Page themeId={themeId}>
<Header {...props} />
{children}
@@ -25,8 +25,8 @@ import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';
import {
CatalogTable,
CatalogTableRow,
FilteredTableLayout,
TableContainer,
FilteredEntityLayout,
EntityListContainer,
FilterContainer,
} from '@backstage/plugin-catalog';
import {
@@ -54,11 +54,8 @@ const defaultColumns: TableColumn<CatalogTableRow>[] = [
CatalogTable.columns.createTagsColumn(),
];
interface IApiExplorerePageFilterProps {
type ApiExplorerPageProps = {
initiallySelectedFilter?: UserListFilterKind;
}
export type ApiExplorerPageProps = IApiExplorerePageFilterProps & {
columns?: TableColumn<CatalogTableRow>[];
};
@@ -94,7 +91,7 @@ export const ApiExplorerPage = ({
<SupportButton>All your APIs</SupportButton>
</ContentHeader>
<EntityListProvider>
<FilteredTableLayout>
<FilteredEntityLayout>
<FilterContainer>
<EntityKindPicker initialFilter="api" hidden />
<EntityTypePicker />
@@ -103,10 +100,10 @@ export const ApiExplorerPage = ({
<EntityLifecyclePicker />
<EntityTagPicker />
</FilterContainer>
<TableContainer>
<EntityListContainer>
<CatalogTable columns={columns || defaultColumns} />
</TableContainer>
</FilteredTableLayout>
</EntityListContainer>
</FilteredEntityLayout>
</EntityListProvider>
</Content>
</PageWithHeader>
@@ -84,9 +84,6 @@ export type EntityListContextProps<
*/
queryParameters: Partial<Record<keyof EntityFilters, string | string[]>>;
showFiltersDrawer: boolean;
toggleFiltersDrawer: (showFiltersDrawer: boolean) => void;
loading: boolean;
error?: Error;
};
@@ -111,8 +108,6 @@ export const EntityListProvider = <EntityFilters extends DefaultEntityFilters>({
const [requestedFilters, setRequestedFilters] = useState<EntityFilters>(
{} as EntityFilters,
);
// Show
const [showFiltersDrawer, toggleFiltersDrawer] = useState<boolean>(false);
const [outputState, setOutputState] = useState<OutputState<EntityFilters>>({
appliedFilters: {} as EntityFilters,
entities: [],
@@ -208,8 +203,6 @@ export const EntityListProvider = <EntityFilters extends DefaultEntityFilters>({
updateFilters,
queryParameters: outputState.queryParameters,
loading,
showFiltersDrawer,
toggleFiltersDrawer,
error,
}}
>
@@ -32,7 +32,6 @@ export const MockEntityListContextProvider = ({
const [filters, setFilters] = useState<DefaultEntityFilters>(
value.filters ?? {},
);
const [showFiltersDrawer, toggleFiltersDrawer] = useState(false);
const updateFilters = useCallback(
(
update:
@@ -57,8 +56,6 @@ export const MockEntityListContextProvider = ({
filters,
loading: false,
queryParameters: {},
showFiltersDrawer,
toggleFiltersDrawer,
};
// Extract value.filters to avoid overwriting it; some tests exercise filter updates. The value
@@ -1,78 +0,0 @@
/*
* Copyright 2020 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 {
EntityKindPicker,
EntityLifecyclePicker,
EntityOwnerPicker,
EntityTagPicker,
EntityTypePicker,
UserListFilterKind,
UserListPicker,
} from '@backstage/plugin-catalog-react';
import {
Accordion,
AccordionDetails,
AccordionSummary,
Grid,
isWidthDown,
Typography,
withWidth,
} from '@material-ui/core';
import { Breakpoint } from '@material-ui/core/styles/createBreakpoints';
import ExpandMore from '@material-ui/icons/ExpandMore';
import React, { PropsWithChildren } from 'react';
interface IProps {
initiallySelectedFilter?: UserListFilterKind;
initialFilter?: 'component' | 'api';
}
const CatalogFilterWrapper = withWidth()(
({ width, children }: PropsWithChildren<{ width: Breakpoint }>) =>
isWidthDown('md', width) ? (
<Accordion>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography>Filters</Typography>
</AccordionSummary>
<AccordionDetails>{children}</AccordionDetails>
</Accordion>
) : (
<React.Fragment>{children}</React.Fragment>
),
);
export const CatalogFilter = ({
initiallySelectedFilter = 'owned',
initialFilter = 'component',
}: IProps) => (
<CatalogFilterWrapper>
<Grid container alignContent="flex-start">
<Grid item xs={12} sm={4} lg={12}>
<EntityKindPicker initialFilter={initialFilter} hidden />
<EntityTypePicker />
</Grid>
<Grid item xs={12} sm={4} lg={12}>
<UserListPicker initialFilter={initiallySelectedFilter} />
</Grid>
<Grid item xs={12} sm={4} lg={12}>
<EntityOwnerPicker />
<EntityLifecyclePicker />
<EntityTagPicker />
</Grid>
</Grid>
</CatalogFilterWrapper>
);
@@ -38,10 +38,10 @@ import { CatalogTable } from '../CatalogTable';
import { EntityRow } from '../CatalogTable/types';
import { CreateComponentButton } from '../CreateComponentButton/CreateComponentButton';
import {
FilteredTableLayout,
TableContainer,
FilteredEntityLayout,
EntityListContainer,
FilterContainer,
} from '../FilteredTableLayout';
} from '../FilteredEntityLayout';
export type CatalogPageProps = {
initiallySelectedFilter?: UserListFilterKind;
@@ -65,7 +65,7 @@ export const CatalogPage = ({
<SupportButton>All your software catalog entities</SupportButton>
</ContentHeader>
<EntityListProvider>
<FilteredTableLayout>
<FilteredEntityLayout>
<FilterContainer>
<EntityKindPicker initialFilter="component" hidden />
<EntityTypePicker />
@@ -74,10 +74,10 @@ export const CatalogPage = ({
<EntityLifecyclePicker />
<EntityTagPicker />
</FilterContainer>
<TableContainer>
<EntityListContainer>
<CatalogTable columns={columns} actions={actions} />
</TableContainer>
</FilteredTableLayout>
</EntityListContainer>
</FilteredEntityLayout>
</EntityListProvider>
</Content>
</PageWithHeader>
@@ -23,7 +23,7 @@ import { useRouteRef } from '@backstage/core-plugin-api';
export const CreateComponentButton = () => {
const createComponentLink = useRouteRef(createComponentRouteRef);
return !createComponentLink ? null : (
return createComponentLink ? (
<Button
component={RouterLink}
variant="contained"
@@ -32,5 +32,5 @@ export const CreateComponentButton = () => {
>
Create Component
</Button>
);
) : null;
};
@@ -15,9 +15,9 @@
*/
import { Grid } from '@material-ui/core';
import React from 'react';
import React, { PropsWithChildren } from 'react';
export const TableContainer = ({ children }: React.PropsWithChildren<{}>) => (
export const EntityListContainer = ({ children }: PropsWithChildren<{}>) => (
<Grid item xs={12} lg={10}>
{children}
</Grid>
@@ -0,0 +1,68 @@
/*
* Copyright 2021 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 { BackstageTheme } from '@backstage/theme';
import {
Box,
Button,
Drawer,
Grid,
useMediaQuery,
useTheme,
} from '@material-ui/core';
import FilterListIcon from '@material-ui/icons/FilterList';
import React, { useState } from 'react';
export const FilterContainer = ({ children }: React.PropsWithChildren<{}>) => {
const isMidSizeScreen = useMediaQuery<BackstageTheme>(theme =>
theme.breakpoints.down('md'),
);
const theme = useTheme<BackstageTheme>();
const [showFiltersDrawer, toggleFiltersDrawer] = useState<boolean>(false);
return isMidSizeScreen ? (
<>
<Button
style={{ marginTop: theme.spacing(1), marginLeft: theme.spacing(1) }}
onClick={() => toggleFiltersDrawer(!showFiltersDrawer)}
>
<Box display="flex" alignItems="center">
<FilterListIcon style={{ marginRight: theme.spacing(1) }} />
Filters
</Box>
</Button>
<Drawer
title="Filters"
data-testid="entity-filters-drawer"
open={showFiltersDrawer}
onClose={() => {
toggleFiltersDrawer(false);
}}
elevation={0}
anchor="left"
disableAutoFocus
keepMounted
variant="temporary"
>
<Box m={2}>{children}</Box>
</Drawer>
</>
) : (
<Grid data-testid="entity-filters-grid" item lg={2}>
{children}
</Grid>
);
};
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* Copyright 2021 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.
@@ -14,4 +14,11 @@
* limitations under the License.
*/
export { CatalogFilter } from './CatalogFilter';
import { Grid } from '@material-ui/core';
import React, { PropsWithChildren } from 'react';
export const FilteredEntityLayout = ({ children }: PropsWithChildren<{}>) => (
<Grid container style={{ position: 'relative' }}>
{children}
</Grid>
);
@@ -14,6 +14,6 @@
* limitations under the License.
*/
export { FilteredTableLayout } from './FilteredTableLayout';
export { FilteredEntityLayout } from './FilteredEntityLayout';
export { FilterContainer } from './FilterContainer';
export { TableContainer } from './TableContainer';
export { EntityListContainer } from './EntityListContainer';
@@ -1,51 +0,0 @@
/*
* Copyright 2021 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 { Box, Drawer, Grid, useMediaQuery } from '@material-ui/core';
import { useEntityListProvider } from '@backstage/plugin-catalog-react';
import { BackstageTheme } from '@backstage/theme';
import React from 'react';
export const FilterContainer = ({ children }: React.PropsWithChildren<{}>) => {
const isMidSizeScreen = useMediaQuery<BackstageTheme>(theme =>
theme.breakpoints.down('md'),
);
const { showFiltersDrawer, toggleFiltersDrawer } = useEntityListProvider();
return isMidSizeScreen ? (
<Drawer
data-testid="entity-filters-drawer"
open={showFiltersDrawer}
onClose={() => {
toggleFiltersDrawer(false);
}}
PaperProps={{
style: { width: '300px' },
}}
elevation={0}
anchor="left"
disableAutoFocus
keepMounted
variant="temporary"
>
<Box m={2}>{children}</Box>
</Drawer>
) : (
<Grid data-testid="entity-filters-grid" item lg={2}>
{children}
</Grid>
);
};
@@ -1,52 +0,0 @@
/*
* Copyright 2021 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 { useEntityListProvider } from '@backstage/plugin-catalog-react';
import { BackstageTheme } from '@backstage/theme';
import { Box, Button, Grid, useMediaQuery, useTheme } from '@material-ui/core';
import FilterListIcon from '@material-ui/icons/FilterList';
import React, { Fragment } from 'react';
interface IProps {}
export const FilteredTableLayout = ({
children,
}: React.PropsWithChildren<IProps>) => {
const isMidSizeScreen = useMediaQuery<BackstageTheme>(theme =>
theme.breakpoints.down('md'),
);
const { showFiltersDrawer, toggleFiltersDrawer } = useEntityListProvider();
const theme = useTheme<BackstageTheme>();
return (
<Fragment>
{isMidSizeScreen && (
<Button
style={{ paddingLeft: 0, marginBottom: theme.spacing(1) }}
onClick={() => toggleFiltersDrawer(!showFiltersDrawer)}
>
<Box display="flex" alignItems="center">
<FilterListIcon style={{ marginRight: theme.spacing(1) }} />
Filters
</Box>
</Button>
)}
<Grid container style={{ position: 'relative' }}>
{children}
</Grid>
</Fragment>
);
};
+1 -2
View File
@@ -40,5 +40,4 @@ export {
EntitySystemDiagramCard,
} from './plugin';
export * from './components/CatalogTable/columns';
export * from './components/CatalogFilter';
export * from './components/FilteredTableLayout';
export * from './components/FilteredEntityLayout';