Added SearchBar and ScrollBar on Techradar

Signed-off-by: lmejbar <42239917+lmejbar@users.noreply.github.com>
This commit is contained in:
lmejbar
2021-08-20 15:45:01 +02:00
committed by Fredrik Adelöw
parent da407a0b1f
commit c1ef701395
11 changed files with 189 additions and 7 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/core-components': minor
'@backstage/plugin-tech-radar': minor
---
Added SearchBar to allow filtering and a scrollbar to display hidden tech
@@ -0,0 +1,64 @@
/*
* 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 React from 'react';
import {
render,
act,
RenderResult,
waitFor,
fireEvent,
screen,
} from '@testing-library/react';
import { wrapInTestApp, renderInTestApp } from '@backstage/test-utils';
import { InputTextFilter } from './InputTextFilter';
const SUPPORT_BUTTON_ID = 'support-button';
const POPOVER_ID = 'support-button-popover';
describe('<InputTextFilter />', () => {
// it('renders without exploding', async () => {
// let renderResult: RenderResult;
// await act(async () => {
// renderResult = render(wrapInTestApp(<InputTextFilter />));
// });
// await waitFor(() =>
// expect(renderResult.getByTestId(SUPPORT_BUTTON_ID)).toBeInTheDocument(),
// );
// });
// it('supports passing a title', async () => {
// await renderInTestApp(<InputTextFilter title="Custom title" />);
// fireEvent.click(screen.getByTestId(SUPPORT_BUTTON_ID));
// expect(screen.getByText('Custom title')).toBeInTheDocument();
// });
// it('shows popover on click', async () => {
// let renderResult: RenderResult;
// await act(async () => {
// renderResult = render(wrapInTestApp(<InputTextFilter />));
// });
// let button: HTMLElement;
// await waitFor(() => {
// expect(renderResult.getByTestId(SUPPORT_BUTTON_ID)).toBeInTheDocument();
// button = renderResult.getByTestId(SUPPORT_BUTTON_ID);
// });
// await act(async () => {
// fireEvent.click(button);
// });
// await waitFor(() => {
// expect(renderResult.getByTestId(POPOVER_ID)).toBeInTheDocument();
// });
// });
});
@@ -0,0 +1,60 @@
/*
* 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 React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
const useStyles = makeStyles(theme => ({
root: {
'& > *': {
width: '50ch',
'margin-right': '40ch',
'margin-bottom': '1ch',
},
},
}));
export const InputTextFilter = ({
searchCategory,
}: {
searchCategory: any;
}) => {
const classes = useStyles();
const [, setSearchCategory] = React.useState('');
const setSearchCategoryValue = event => {
setSearchCategory(event.target.value);
};
return (
<>
<div>
<form className={classes.root} noValidate autoComplete="off">
<TextField
id="standard-basic"
label="Search"
onChange={e => {
searchCategory(e);
setSearchCategoryValue(e);
}}
/>
</form>
</div>
</>
);
};
@@ -0,0 +1,17 @@
/*
* 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.
*/
export { InputTextFilter } from './InputTextFilter';
@@ -28,6 +28,7 @@ export * from './ResponseErrorPanel';
export * from './FeatureDiscovery';
export * from './HeaderIconLinkRow';
export * from './HorizontalScrollGrid';
export * from './InputTextFilter';
export * from './Lifecycle';
export * from './Link';
export * from './MarkdownContent';
@@ -22,7 +22,7 @@ const useStyles = makeStyles((theme: Theme) => ({
root: {
gridArea: 'pageContent',
minWidth: 0,
paddingTop: theme.spacing(3),
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(3),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
@@ -53,6 +53,7 @@ const useStyles = (props: ContentHeaderProps) =>
title: {
display: 'inline-flex',
marginBottom: 0,
color: '#0082C3',
},
}));
+1
View File
@@ -81,4 +81,5 @@ export interface TechRadarComponentProps {
width: number;
height: number;
svgProps?: object;
searchText?: string;
}
@@ -45,13 +45,29 @@ const useTechRadarLoader = (id: string | undefined) => {
return { loading, value, error };
};
const RadarComponent = (props: TechRadarComponentProps): JSX.Element => {
const RadarComponent = (
props: TechRadarComponentProps,
searchText: string,
): JSX.Element => {
const { loading, error, value: data } = useTechRadarLoader(props.id);
const mapToEntries = (
loaderResponse: TechRadarLoaderResponse | undefined,
): Array<Entry> => {
return loaderResponse!.entries.map(entry => {
let filteredArray = loaderResponse!.entries;
if (!(props.searchText === '')) {
// Compare the name or the description with the search input text
filteredArray = loaderResponse!.entries.filter(
element =>
element.title
.toLowerCase()
.includes(props.searchText.toLowerCase()) ||
element.timeline[0].description
?.toLowerCase()
.includes(props.searchText.toLowerCase()),
);
}
return filteredArray.map(entry => {
return {
id: entry.key,
quadrant: loaderResponse!.quadrants.find(q => q.id === entry.quadrant)!,
@@ -32,21 +32,25 @@ export type Props = {
};
const useStyles = makeStyles<Theme>(theme => ({
foreignObject: {
overflowY: 'visible',
},
quadrant: {
height: '100%',
width: '100%',
overflow: 'hidden',
overflowY: 'visible',
pointerEvents: 'none',
},
quadrantHeading: {
pointerEvents: 'none',
userSelect: 'none',
color: '#0082C3',
marginTop: 0,
marginBottom: theme.spacing(8 / (18 * 0.375)),
fontSize: '18px',
},
rings: {
columns: 3,
columns: 2,
},
ring: {
breakInside: 'avoid-column',
@@ -66,6 +70,9 @@ const useStyles = makeStyles<Theme>(theme => ({
listStylePosition: 'inside',
marginTop: 0,
paddingLeft: 0,
height: '100%',
width: '100%',
overflow: 'scroll',
fontVariantNumeric: 'proportional-nums',
'-moz-font-feature-settings': 'pnum',
'-webkit-font-feature-settings': 'pnum',
@@ -221,6 +228,7 @@ const RadarLegend = (props: Props): JSX.Element => {
y={quadrant.legendY}
width={quadrant.legendWidth}
height={quadrant.legendHeight}
className={classes.foreignObject}
data-testid="radar-quadrant"
>
<div className={classes.quadrant}>
@@ -24,6 +24,7 @@ import {
Page,
Header,
SupportButton,
InputTextFilter,
} from '@backstage/core-components';
const useStyles = makeStyles(() => ({
@@ -45,11 +46,18 @@ export const RadarPage = ({
...props
}: TechRadarPageProps): JSX.Element => {
const classes = useStyles();
const [searchText, setSearchText] = React.useState('');
const searchInput = event => {
setSearchText(event.target.value);
};
return (
<Page themeId="tool">
<Header title={title} subtitle={subtitle} />
{/* <Header title={title} subtitle={subtitle} /> */}
<Content className={classes.overflowXScroll}>
<ContentHeader title={pageTitle}>
<InputTextFilter searchCategory={searchInput} />
<SupportButton>
This is used for visualizing the official guidelines of different
areas of software development such as languages, frameworks,
@@ -58,7 +66,7 @@ export const RadarPage = ({
</ContentHeader>
<Grid container spacing={3} direction="row">
<Grid item xs={12} sm={6} md={4}>
<RadarComponent {...props} />
<RadarComponent {...props} searchText={searchText} />
</Grid>
</Grid>
</Content>