diff --git a/.changeset/late-news-chew.md b/.changeset/late-news-chew.md new file mode 100644 index 0000000000..cde2063ea9 --- /dev/null +++ b/.changeset/late-news-chew.md @@ -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 diff --git a/packages/core-components/src/components/InputTextFilter/InputTextFilter.test.tsx b/packages/core-components/src/components/InputTextFilter/InputTextFilter.test.tsx new file mode 100644 index 0000000000..35be191cde --- /dev/null +++ b/packages/core-components/src/components/InputTextFilter/InputTextFilter.test.tsx @@ -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('', () => { + // it('renders without exploding', async () => { + // let renderResult: RenderResult; + // await act(async () => { + // renderResult = render(wrapInTestApp()); + // }); + // await waitFor(() => + // expect(renderResult.getByTestId(SUPPORT_BUTTON_ID)).toBeInTheDocument(), + // ); + // }); + // it('supports passing a title', async () => { + // await renderInTestApp(); + // 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()); + // }); + // 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(); + // }); + // }); +}); diff --git a/packages/core-components/src/components/InputTextFilter/InputTextFilter.tsx b/packages/core-components/src/components/InputTextFilter/InputTextFilter.tsx new file mode 100644 index 0000000000..814efeccc6 --- /dev/null +++ b/packages/core-components/src/components/InputTextFilter/InputTextFilter.tsx @@ -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 ( + <> +
+
+ { + searchCategory(e); + setSearchCategoryValue(e); + }} + /> + +
+ + ); +}; diff --git a/packages/core-components/src/components/InputTextFilter/index.ts b/packages/core-components/src/components/InputTextFilter/index.ts new file mode 100644 index 0000000000..42896a9d30 --- /dev/null +++ b/packages/core-components/src/components/InputTextFilter/index.ts @@ -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'; diff --git a/packages/core-components/src/components/index.ts b/packages/core-components/src/components/index.ts index 3c9376a894..73d04dccb7 100644 --- a/packages/core-components/src/components/index.ts +++ b/packages/core-components/src/components/index.ts @@ -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'; diff --git a/packages/core-components/src/layout/Content/Content.tsx b/packages/core-components/src/layout/Content/Content.tsx index a3771dff3f..ae8259a315 100644 --- a/packages/core-components/src/layout/Content/Content.tsx +++ b/packages/core-components/src/layout/Content/Content.tsx @@ -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), diff --git a/packages/core-components/src/layout/ContentHeader/ContentHeader.tsx b/packages/core-components/src/layout/ContentHeader/ContentHeader.tsx index 76fec703a9..99260c626d 100644 --- a/packages/core-components/src/layout/ContentHeader/ContentHeader.tsx +++ b/packages/core-components/src/layout/ContentHeader/ContentHeader.tsx @@ -53,6 +53,7 @@ const useStyles = (props: ContentHeaderProps) => title: { display: 'inline-flex', marginBottom: 0, + color: '#0082C3', }, })); diff --git a/plugins/tech-radar/src/api.ts b/plugins/tech-radar/src/api.ts index 34307a1697..2497834e22 100644 --- a/plugins/tech-radar/src/api.ts +++ b/plugins/tech-radar/src/api.ts @@ -81,4 +81,5 @@ export interface TechRadarComponentProps { width: number; height: number; svgProps?: object; + searchText?: string; } diff --git a/plugins/tech-radar/src/components/RadarComponent.tsx b/plugins/tech-radar/src/components/RadarComponent.tsx index faa2763f17..88c865f999 100644 --- a/plugins/tech-radar/src/components/RadarComponent.tsx +++ b/plugins/tech-radar/src/components/RadarComponent.tsx @@ -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 => { - 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)!, diff --git a/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx b/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx index b9bc6a59a6..92fb5de9b8 100644 --- a/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx +++ b/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx @@ -32,21 +32,25 @@ export type Props = { }; const useStyles = makeStyles(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 => ({ 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" >
diff --git a/plugins/tech-radar/src/components/RadarPage.tsx b/plugins/tech-radar/src/components/RadarPage.tsx index 2393ccc9c6..a332fd63c3 100644 --- a/plugins/tech-radar/src/components/RadarPage.tsx +++ b/plugins/tech-radar/src/components/RadarPage.tsx @@ -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 ( -
+ {/*
*/} + 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 = ({ - +