From 862595ce5014412f5c79de66ee33d66d8febaafb Mon Sep 17 00:00:00 2001 From: Jeff Durand Date: Thu, 18 Feb 2021 13:52:39 +0000 Subject: [PATCH] tech-radar: add description dialog box --- .../src/components/RadarComponent.tsx | 1 + .../RadarDescription.test.tsx | 43 +++++++++++++ .../RadarDescription/RadarDescription.tsx | 62 ++++++++++++++++++ .../src/components/RadarDescription/index.ts | 17 +++++ .../components/RadarEntry/RadarEntry.test.tsx | 36 +++++++++-- .../src/components/RadarEntry/RadarEntry.tsx | 47 +++++++++++++- .../components/RadarLegend/RadarLegend.tsx | 63 ++++++++++++++++++- .../src/components/RadarPlot/RadarPlot.tsx | 2 + plugins/tech-radar/src/utils/types.ts | 2 + 9 files changed, 262 insertions(+), 11 deletions(-) create mode 100644 plugins/tech-radar/src/components/RadarDescription/RadarDescription.test.tsx create mode 100644 plugins/tech-radar/src/components/RadarDescription/RadarDescription.tsx create mode 100644 plugins/tech-radar/src/components/RadarDescription/index.ts diff --git a/plugins/tech-radar/src/components/RadarComponent.tsx b/plugins/tech-radar/src/components/RadarComponent.tsx index 759fec62c3..bed45e63fc 100644 --- a/plugins/tech-radar/src/components/RadarComponent.tsx +++ b/plugins/tech-radar/src/components/RadarComponent.tsx @@ -68,6 +68,7 @@ const RadarComponent = (props: TechRadarComponentProps): JSX.Element => { }; }), moved: entry.timeline[0].moved, + description: entry.timeline[0].description, url: entry.url, }; }); diff --git a/plugins/tech-radar/src/components/RadarDescription/RadarDescription.test.tsx b/plugins/tech-radar/src/components/RadarDescription/RadarDescription.test.tsx new file mode 100644 index 0000000000..54b8ef0892 --- /dev/null +++ b/plugins/tech-radar/src/components/RadarDescription/RadarDescription.test.tsx @@ -0,0 +1,43 @@ +/* + * 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 { render, screen } from '@testing-library/react'; +import { ThemeProvider } from '@material-ui/core'; +import { lightTheme } from '@backstage/theme'; + +import RadarDescription, { Props } from './RadarDescription'; + +const minProps: Props = { + open: true, + title: 'example-title', + description: 'example-description', + onClose: () => {}, +}; + +describe('RadarDescription', () => { + it('should render', () => { + render( + + + , + ); + + const radarDescription = screen.getByTestId('radar-description'); + expect(radarDescription).toBeInTheDocument(); + expect(screen.getByText(String(minProps.description))).toBeInTheDocument(); + }); +}); diff --git a/plugins/tech-radar/src/components/RadarDescription/RadarDescription.tsx b/plugins/tech-radar/src/components/RadarDescription/RadarDescription.tsx new file mode 100644 index 0000000000..ecef4900fb --- /dev/null +++ b/plugins/tech-radar/src/components/RadarDescription/RadarDescription.tsx @@ -0,0 +1,62 @@ +/* + * 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 Dialog from '@material-ui/core/Dialog'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import { Button, DialogActions, DialogContent } from '@material-ui/core'; +import LinkIcon from '@material-ui/icons/Link'; + +export type Props = { + open: boolean; + onClose: () => void; + title: string; + description: string; + url?: string; +}; + +const RadarDescription = (props: Props): JSX.Element => { + // const classes = useStyles(props); + const { open, onClose, title, description, url } = props; + + const handleClick = () => { + onClose(); + if (url) { + window.location.href = url; + } + }; + + return ( + + {title} + {description} + {url && ( + + + + )} + + ); +}; + +export default RadarDescription; diff --git a/plugins/tech-radar/src/components/RadarDescription/index.ts b/plugins/tech-radar/src/components/RadarDescription/index.ts new file mode 100644 index 0000000000..908e97701e --- /dev/null +++ b/plugins/tech-radar/src/components/RadarDescription/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { default } from './RadarDescription'; diff --git a/plugins/tech-radar/src/components/RadarEntry/RadarEntry.test.tsx b/plugins/tech-radar/src/components/RadarEntry/RadarEntry.test.tsx index 2d24f301d1..0424624007 100644 --- a/plugins/tech-radar/src/components/RadarEntry/RadarEntry.test.tsx +++ b/plugins/tech-radar/src/components/RadarEntry/RadarEntry.test.tsx @@ -15,7 +15,8 @@ */ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; import GetBBoxPolyfill from '../../utils/polyfills/getBBox'; @@ -29,6 +30,12 @@ const minProps: Props = { color: 'red', }; +const optionalProps: Props = { + ...minProps, + title: 'example-title', + description: 'example-description', +}; + describe('RadarEntry', () => { beforeAll(() => { GetBBoxPolyfill.create(0, 0, 1000, 500); @@ -38,8 +45,8 @@ describe('RadarEntry', () => { GetBBoxPolyfill.remove(); }); - it('should render', () => { - const rendered = render( + it('should render link only', () => { + render( @@ -47,10 +54,29 @@ describe('RadarEntry', () => { , ); - const radarEntry = rendered.getByTestId('radar-entry'); + const radarEntry = screen.getByTestId('radar-entry'); const { x, y } = minProps; expect(radarEntry).toBeInTheDocument(); expect(radarEntry.getAttribute('transform')).toBe(`translate(${x}, ${y})`); - expect(rendered.getByText(String(minProps.value))).toBeInTheDocument(); + expect(screen.getByText(String(minProps.value))).toBeInTheDocument(); + }); + + it('should render with description', () => { + render( + + + + + , + ); + + userEvent.click(screen.getByRole('button')); + + const radarEntry = screen.getByTestId('radar-entry'); + expect(radarEntry).toBeInTheDocument(); + + const radarDescription = screen.getByTestId('radar-description'); + expect(radarDescription).toBeInTheDocument(); + expect(screen.getByText(String(minProps.value))).toBeInTheDocument(); }); }); diff --git a/plugins/tech-radar/src/components/RadarEntry/RadarEntry.tsx b/plugins/tech-radar/src/components/RadarEntry/RadarEntry.tsx index 29d35e01e2..f146eb5fa8 100644 --- a/plugins/tech-radar/src/components/RadarEntry/RadarEntry.tsx +++ b/plugins/tech-radar/src/components/RadarEntry/RadarEntry.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { makeStyles, Theme } from '@material-ui/core'; import { WithLink } from '../../utils/components'; +import RadarDescription from '../RadarDescription'; export type Props = { x: number; @@ -25,6 +26,8 @@ export type Props = { color: string; url?: string; moved?: number; + description?: string; + title?: string; onMouseEnter?: (event: React.MouseEvent) => void; onMouseLeave?: (event: React.MouseEvent) => void; onClick?: (event: React.MouseEvent) => void; @@ -59,9 +62,12 @@ const makeBlip = (color: string, moved?: number) => { const RadarEntry = (props: Props): JSX.Element => { const classes = useStyles(props); + const [open, setOpen] = React.useState(false); const { moved, + description, + title, color, url, value, @@ -74,6 +80,18 @@ const RadarEntry = (props: Props): JSX.Element => { const blip = makeBlip(color, moved); + const handleClickOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + const toggle = () => { + setOpen(!open); + }; + return ( { onClick={onClick} data-testid="radar-entry" > - - {blip} - + {' '} + {description ? ( + <> + + {blip} + + + + ) : ( + + {blip} + + )} {value} diff --git a/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx b/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx index e10993b010..998a3370c1 100644 --- a/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx +++ b/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { makeStyles, Theme } from '@material-ui/core'; import type { Quadrant, Ring, Entry } from '../../utils/types'; import { WithLink } from '../../utils/components'; +import RadarDescription from '../RadarDescription'; type Segments = { [k: number]: { [k: number]: Entry[] }; @@ -105,6 +106,60 @@ const RadarLegend = (props: Props): JSX.Element => { onEntryMouseLeave?: Props['onEntryMouseEnter']; }; + type RadarLegendLinkProps = { + url?: string; + description?: string; + title?: string; + }; + + const RadarLegendLink = ({ + url, + description, + title, + }: RadarLegendLinkProps) => { + const [open, setOpen] = React.useState(false); + + const handleClickOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + const toggle = () => { + setOpen(!open); + }; + + if (description && url) { + return ( + <> + + {title} + + + + ); + } + return ( + + {title} + + ); + }; + const RadarLegendRing = ({ ring, entries, @@ -129,9 +184,11 @@ const RadarLegend = (props: Props): JSX.Element => { onEntryMouseLeave && (() => onEntryMouseLeave(entry)) } > - - {entry.title} - + ))} diff --git a/plugins/tech-radar/src/components/RadarPlot/RadarPlot.tsx b/plugins/tech-radar/src/components/RadarPlot/RadarPlot.tsx index 7f68ffe021..4dd11c6ccf 100644 --- a/plugins/tech-radar/src/components/RadarPlot/RadarPlot.tsx +++ b/plugins/tech-radar/src/components/RadarPlot/RadarPlot.tsx @@ -73,7 +73,9 @@ const RadarPlot = (props: Props): JSX.Element => { color={entry.color || ''} value={(entry?.index || 0) + 1} url={entry.url} + description={entry.description} moved={entry.moved} + title={entry.title} onMouseEnter={onEntryMouseEnter && (() => onEntryMouseEnter(entry))} onMouseLeave={onEntryMouseLeave && (() => onEntryMouseLeave(entry))} /> diff --git a/plugins/tech-radar/src/utils/types.ts b/plugins/tech-radar/src/utils/types.ts index 3322a67dcb..e4b2ef6fbe 100644 --- a/plugins/tech-radar/src/utils/types.ts +++ b/plugins/tech-radar/src/utils/types.ts @@ -68,6 +68,8 @@ export type Entry = { url?: string; // How this entry has recently moved; -1 for "down", +1 for "up", 0 for not moved moved?: MovedState; + // Most recent description to display in the UI + description?: string; active?: boolean; timeline?: Array; };