diff --git a/.changeset/late-news-chew.md b/.changeset/late-news-chew.md new file mode 100644 index 0000000000..5552caf8fb --- /dev/null +++ b/.changeset/late-news-chew.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-radar': patch +--- + +Added `SearchBar` to allow filtering and a scroll bar to display hidden tech diff --git a/plugins/tech-radar/api-report.md b/plugins/tech-radar/api-report.md index c02c7ee519..452b241937 100644 --- a/plugins/tech-radar/api-report.md +++ b/plugins/tech-radar/api-report.md @@ -107,6 +107,8 @@ export interface TechRadarComponentProps { // (undocumented) id?: string; // (undocumented) + searchText?: string; + // (undocumented) svgProps?: object; // (undocumented) width: number; 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..9abb200792 100644 --- a/plugins/tech-radar/src/components/RadarComponent.tsx +++ b/plugins/tech-radar/src/components/RadarComponent.tsx @@ -14,19 +14,19 @@ * limitations under the License. */ +import { Progress } from '@backstage/core-components'; +import { errorApiRef, useApi } from '@backstage/core-plugin-api'; import React, { useEffect } from 'react'; import { useAsync } from 'react-use'; -import Radar from '../components/Radar'; import { + RadarEntry, techRadarApiRef, TechRadarComponentProps, TechRadarLoaderResponse, } from '../api'; +import Radar from '../components/Radar'; import { Entry } from '../utils/types'; -import { Progress } from '@backstage/core-components'; -import { useApi, errorApiRef } from '@backstage/core-plugin-api'; - const useTechRadarLoader = (id: string | undefined) => { const errorApi = useApi(errorApiRef); const techRadarApi = useApi(techRadarApiRef); @@ -45,24 +45,44 @@ const useTechRadarLoader = (id: string | undefined) => { return { loading, value, error }; }; +function matchFilter(filter?: string): (entry: RadarEntry) => boolean { + const terms = filter + ?.toLocaleLowerCase('en-US') + .split(/\s/) + .map(e => e.trim()) + .filter(Boolean); + + if (!terms?.length) { + return () => true; + } + + return entry => { + const text = `${entry.title} ${ + entry.timeline[0]?.description || '' + }`.toLocaleLowerCase('en-US'); + return terms.every(term => text.includes(term)); + }; +} + const RadarComponent = (props: TechRadarComponentProps): JSX.Element => { const { loading, error, value: data } = useTechRadarLoader(props.id); const mapToEntries = ( - loaderResponse: TechRadarLoaderResponse | undefined, + loaderResponse: TechRadarLoaderResponse, ): Array => { - return loaderResponse!.entries.map(entry => { - return { + return loaderResponse.entries + .filter(matchFilter(props.searchText)) + .map(entry => ({ id: entry.key, - quadrant: loaderResponse!.quadrants.find(q => q.id === entry.quadrant)!, + quadrant: loaderResponse.quadrants.find(q => q.id === entry.quadrant)!, title: entry.title, - ring: loaderResponse!.rings.find( + ring: loaderResponse.rings.find( r => r.id === entry.timeline[0].ringId, )!, timeline: entry.timeline.map(e => { return { date: e.date, - ring: loaderResponse!.rings.find(a => a.id === e.ringId)!, + ring: loaderResponse.rings.find(a => a.id === e.ringId)!, description: e.description, moved: e.moved, }; @@ -70,18 +90,17 @@ const RadarComponent = (props: TechRadarComponentProps): JSX.Element => { moved: entry.timeline[0].moved, description: entry.description || entry.timeline[0].description, url: entry.url, - }; - }); + })); }; return ( <> {loading && } - {!loading && !error && ( + {!loading && !error && data && ( )} diff --git a/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx b/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx index b9bc6a59a6..705dc9f47b 100644 --- a/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx +++ b/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; import { makeStyles, Theme } from '@material-ui/core'; -import type { Quadrant, Ring, Entry } from '../../utils/types'; +import React from 'react'; import { WithLink } from '../../utils/components'; +import type { Entry, Quadrant, Ring } from '../../utils/types'; import { RadarDescription } from '../RadarDescription'; type Segments = { @@ -32,17 +32,21 @@ export type Props = { }; const useStyles = makeStyles(theme => ({ + quadrantLegend: { + overflowY: 'auto', + scrollbarWidth: 'thin', + }, quadrant: { height: '100%', width: '100%', - overflow: 'hidden', + scrollbarWidth: 'thin', pointerEvents: 'none', }, quadrantHeading: { pointerEvents: 'none', userSelect: 'none', marginTop: 0, - marginBottom: theme.spacing(8 / (18 * 0.375)), + marginBottom: theme.spacing(2), fontSize: '18px', }, rings: { @@ -53,12 +57,16 @@ const useStyles = makeStyles(theme => ({ pageBreakInside: 'avoid', '-webkit-column-break-inside': 'avoid', fontSize: '12px', + marginBottom: theme.spacing(2), + }, + ringEmpty: { + color: theme.palette.text.secondary, }, ringHeading: { pointerEvents: 'none', userSelect: 'none', marginTop: 0, - marginBottom: theme.spacing(8 / (12 * 0.375)), + marginBottom: theme.spacing(1), fontSize: '12px', fontWeight: 800, }, @@ -172,7 +180,7 @@ const RadarLegend = (props: Props): JSX.Element => {

{ring.name}

{entries.length === 0 ? ( -

(empty)

+

(empty)

) : (
    {entries.map(entry => ( @@ -221,6 +229,7 @@ const RadarLegend = (props: Props): JSX.Element => { y={quadrant.legendY} width={quadrant.legendWidth} height={quadrant.legendHeight} + className={classes.quadrantLegend} data-testid="radar-quadrant" >
    diff --git a/plugins/tech-radar/src/components/RadarPage.tsx b/plugins/tech-radar/src/components/RadarPage.tsx index 2393ccc9c6..8ae7d17fd0 100644 --- a/plugins/tech-radar/src/components/RadarPage.tsx +++ b/plugins/tech-radar/src/components/RadarPage.tsx @@ -14,17 +14,17 @@ * limitations under the License. */ -import React from 'react'; -import { Grid, makeStyles } from '@material-ui/core'; -import RadarComponent from '../components/RadarComponent'; -import { TechRadarComponentProps } from '../api'; import { Content, ContentHeader, - Page, Header, + Page, SupportButton, } from '@backstage/core-components'; +import { Grid, Input, makeStyles } from '@material-ui/core'; +import React from 'react'; +import { TechRadarComponentProps } from '../api'; +import RadarComponent from '../components/RadarComponent'; const useStyles = makeStyles(() => ({ overflowXScroll: { @@ -45,11 +45,19 @@ export const RadarPage = ({ ...props }: TechRadarPageProps): JSX.Element => { const classes = useStyles(); + const [searchText, setSearchText] = React.useState(''); + return (
    + setSearchText(e.target.value)} + /> 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 = ({ - +