From 77aa3a4d47ee8c3e4d272b51ca8442a7689c9c45 Mon Sep 17 00:00:00 2001 From: Andy Ladjadj Date: Fri, 17 Feb 2023 16:43:12 +0100 Subject: [PATCH 1/8] fix(plugins/adr): use path attribute to fetch file instead of name Signed-off-by: Andy Ladjadj --- .changeset/odd-plums-bake.md | 5 ++++ .../EntityAdrContent/EntityAdrContent.tsx | 27 +++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) create mode 100644 .changeset/odd-plums-bake.md diff --git a/.changeset/odd-plums-bake.md b/.changeset/odd-plums-bake.md new file mode 100644 index 0000000000..f06bf4d61d --- /dev/null +++ b/.changeset/odd-plums-bake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-adr': patch +--- + +use path attribute to fetch files instead of name diff --git a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx index eb5b4aed21..58183b5230 100644 --- a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx +++ b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx @@ -47,7 +47,7 @@ import { import { rootRouteRef } from '../../routes'; import { AdrContentDecorator, AdrReader } from '../AdrReader'; -import { adrApiRef } from '../../api'; +import { adrApiRef, AdrFileInfo } from '../../api'; import useAsync from 'react-use/lib/useAsync'; const useStyles = makeStyles((theme: Theme) => ({ @@ -68,9 +68,7 @@ export const EntityAdrContent = (props: { const classes = useStyles(); const { entity } = useEntity(); const rootLink = useRouteRef(rootRouteRef); - const [adrList, setAdrList] = useState< - { name: string; title?: string; status?: string; date?: string }[] - >([]); + const [adrList, setAdrList] = useState([]); const [searchParams, setSearchParams] = useSearchParams(); const scmIntegrations = useApi(scmIntegrationsApiRef); const adrApi = useApi(adrApiRef); @@ -82,7 +80,8 @@ export const EntityAdrContent = (props: { }, [entity, scmIntegrations]); const selectedAdr = - adrList.find(adr => adr.name === searchParams.get('record'))?.name ?? ''; + adrList.find(adr => adr.name === searchParams.get('record'))?.path ?? ''; + useEffect(() => { if (adrList.length && !selectedAdr) { searchParams.set('record', adrList[0].name); @@ -95,15 +94,13 @@ export const EntityAdrContent = (props: { return; } - const adrs = value.data - .filter( - (item: { type: string; name: string }) => - item.type === 'file' && - (filePathFilterFn - ? filePathFilterFn(item.name) - : madrFilePathFilter(item.name)), - ) - .map(({ name, title, status, date }) => ({ name, title, status, date })); + const adrs: AdrFileInfo[] = value.data.filter( + (item: AdrFileInfo) => + item.type === 'file' && + (filePathFilterFn + ? filePathFilterFn(item.name) + : madrFilePathFilter(item.name)), + ); setAdrList(adrs); }, [filePathFilterFn, value]); @@ -148,7 +145,7 @@ export const EntityAdrContent = (props: { button component={Link} to={`${rootLink()}?record=${adr.name}`} - selected={selectedAdr === adr.name} + selected={selectedAdr === adr.path} > Date: Tue, 14 Mar 2023 17:54:20 +0100 Subject: [PATCH 2/8] feat(plugins/adr): render subdirectories in list Signed-off-by: Andy Ladjadj --- plugins/adr/package.json | 1 + .../EntityAdrContent/EntityAdrContent.tsx | 155 +++++++++++++----- yarn.lock | 1 + 3 files changed, 118 insertions(+), 39 deletions(-) diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 453ff62792..55bcc21d62 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -34,6 +34,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", + "lodash": "^4.17.21", "react-markdown": "^8.0.0", "react-use": "^17.2.4", "remark-gfm": "^3.0.1" diff --git a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx index 58183b5230..846678f718 100644 --- a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx +++ b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx @@ -16,9 +16,14 @@ import React, { useEffect, useState } from 'react'; import { Link, useSearchParams } from 'react-router-dom'; +import useAsync from 'react-use/lib/useAsync'; + +import groupBy from 'lodash/groupBy'; + import { Content, ContentHeader, + InfoCard, MissingAnnotationEmptyState, Progress, SupportButton, @@ -35,27 +40,118 @@ import { } from '@backstage/plugin-adr-common'; import { useEntity } from '@backstage/plugin-catalog-react'; import { + Box, Chip, + Collapse, Grid, List, ListItem, + ListItemIcon, ListItemText, makeStyles, Theme, Typography, } from '@material-ui/core'; +import ExpandLess from '@material-ui/icons/ExpandLess'; +import ExpandMore from '@material-ui/icons/ExpandMore'; +import FolderIcon from '@material-ui/icons/Folder'; +import { adrApiRef, AdrFileInfo } from '../../api'; import { rootRouteRef } from '../../routes'; import { AdrContentDecorator, AdrReader } from '../AdrReader'; -import { adrApiRef, AdrFileInfo } from '../../api'; -import useAsync from 'react-use/lib/useAsync'; const useStyles = makeStyles((theme: Theme) => ({ adrMenu: { backgroundColor: theme.palette.background.paper, }, + adrContainerTitle: { + color: theme.palette.grey[700], + marginBottom: theme.spacing(1), + }, + adrChip: { + position: 'absolute', + right: 0, + }, })); +const AdrListContainer = (props: { + adrs: AdrFileInfo[]; + selectedAdr: string; + title: string; +}) => { + const { adrs, selectedAdr, title } = props; + const classes = useStyles(); + const rootLink = useRouteRef(rootRouteRef); + const [open, setOpen] = React.useState(true); + + const getChipColor = (status: string) => { + switch (status) { + case 'accepted': + return 'primary'; + case 'rejected' || 'deprecated': + return 'secondary'; + default: + return 'default'; + } + }; + + const handleClick = () => { + setOpen(!open); + }; + + return ( + <> + {title && ( + + + + + + {open ? : } + + )} + + + {adrs.map((adr, idx) => ( + + + {adr.date} + {adr.status && ( + + )} + + } + /> + + ))} + + + + ); +}; + /** * Component for browsing ADRs on an entity page. * @public @@ -67,7 +163,6 @@ export const EntityAdrContent = (props: { const { contentDecorators, filePathFilterFn } = props; const classes = useStyles(); const { entity } = useEntity(); - const rootLink = useRouteRef(rootRouteRef); const [adrList, setAdrList] = useState([]); const [searchParams, setSearchParams] = useSearchParams(); const scmIntegrations = useApi(scmIntegrationsApiRef); @@ -82,6 +177,10 @@ export const EntityAdrContent = (props: { const selectedAdr = adrList.find(adr => adr.name === searchParams.get('record'))?.path ?? ''; + const adrSubDirectoryFunc = (adr: AdrFileInfo) => { + return adr.path.split('/').slice(0, -1).join('/'); + }; + useEffect(() => { if (adrList.length && !selectedAdr) { searchParams.set('record', adrList[0].name); @@ -105,16 +204,9 @@ export const EntityAdrContent = (props: { setAdrList(adrs); }, [filePathFilterFn, value]); - const getChipColor = (status: string) => { - switch (status) { - case 'accepted': - return 'primary'; - case 'rejected' || 'deprecated': - return 'secondary'; - default: - return 'default'; - } - }; + const adrListGrouped = Object.entries( + groupBy(adrList, adrSubDirectoryFunc), + ).sort(); return ( @@ -138,33 +230,18 @@ export const EntityAdrContent = (props: { (adrList.length ? ( - - {adrList.map((adr, idx) => ( - - + + {adrListGrouped.map(([title, adrs], idx) => ( + - {adr.status && ( - - )} - - ))} - + ))} + + diff --git a/yarn.lock b/yarn.lock index 3f5fbf684b..0c16c829a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4316,6 +4316,7 @@ __metadata: "@types/git-url-parse": ^9.0.0 "@types/node": "*" cross-fetch: ^3.1.5 + lodash: ^4.17.21 msw: ^1.0.0 react-markdown: ^8.0.0 react-use: ^17.2.4 From 668b5733b15715fdfc030d501be7a5f4d9b56655 Mon Sep 17 00:00:00 2001 From: Andy Ladjadj Date: Wed, 15 Mar 2023 09:46:09 +0100 Subject: [PATCH 3/8] fix(plugins/adr): replace url record by the path Signed-off-by: Andy Ladjadj --- plugins/adr-common/src/index.ts | 2 +- .../components/EntityAdrContent/EntityAdrContent.tsx | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/adr-common/src/index.ts b/plugins/adr-common/src/index.ts index c3a048d9d1..25b61d5aa4 100644 --- a/plugins/adr-common/src/index.ts +++ b/plugins/adr-common/src/index.ts @@ -77,7 +77,7 @@ export type AdrFilePathFilterFn = (path: string) => boolean; * @public */ export const madrFilePathFilter: AdrFilePathFilterFn = (path: string) => - /^\d{4}-.+\.md$/.test(path); + /^(?>.+\/)?\d{4}-.+\.md$/.test(path); /** * ADR indexable document interface diff --git a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx index 846678f718..1567306f12 100644 --- a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx +++ b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx @@ -122,7 +122,7 @@ const AdrListContainer = (props: { component={Link} key={idx} selected={selectedAdr === adr.path} - to={`${rootLink()}?record=${adr.name}`} + to={`${rootLink()}?record=${adr.path}`} > adr.name === searchParams.get('record'))?.path ?? ''; + adrList.find(adr => adr.path === searchParams.get('record'))?.path ?? ''; const adrSubDirectoryFunc = (adr: AdrFileInfo) => { return adr.path.split('/').slice(0, -1).join('/'); @@ -183,7 +183,7 @@ export const EntityAdrContent = (props: { useEffect(() => { if (adrList.length && !selectedAdr) { - searchParams.set('record', adrList[0].name); + searchParams.set('record', adrList[0].path); setSearchParams(searchParams, { replace: true }); } }); @@ -197,8 +197,8 @@ export const EntityAdrContent = (props: { (item: AdrFileInfo) => item.type === 'file' && (filePathFilterFn - ? filePathFilterFn(item.name) - : madrFilePathFilter(item.name)), + ? filePathFilterFn(item.path) + : madrFilePathFilter(item.path)), ); setAdrList(adrs); From b012dcefba7cf17ca3b9d290d856f6f1644a9741 Mon Sep 17 00:00:00 2001 From: Andy Ladjadj Date: Wed, 15 Mar 2023 10:05:09 +0100 Subject: [PATCH 4/8] ci: update changeset Signed-off-by: Andy Ladjadj --- .changeset/odd-plums-bake.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/odd-plums-bake.md b/.changeset/odd-plums-bake.md index f06bf4d61d..d2d66e67e2 100644 --- a/.changeset/odd-plums-bake.md +++ b/.changeset/odd-plums-bake.md @@ -2,4 +2,4 @@ '@backstage/plugin-adr': patch --- -use path attribute to fetch files instead of name +use path attribute to fetch files instead of name and update the UI to navigate over subdirectories From 059e14136cdb1b004eb0f3ce69276ff1a3fd7fac Mon Sep 17 00:00:00 2001 From: Andy Ladjadj Date: Wed, 15 Mar 2023 11:03:46 +0100 Subject: [PATCH 5/8] fix(plugins/adr): use javascript regex compliant Signed-off-by: Andy Ladjadj --- plugins/adr-common/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/adr-common/src/index.ts b/plugins/adr-common/src/index.ts index 25b61d5aa4..ffdd9b349a 100644 --- a/plugins/adr-common/src/index.ts +++ b/plugins/adr-common/src/index.ts @@ -77,7 +77,7 @@ export type AdrFilePathFilterFn = (path: string) => boolean; * @public */ export const madrFilePathFilter: AdrFilePathFilterFn = (path: string) => - /^(?>.+\/)?\d{4}-.+\.md$/.test(path); + /^(?:.+\/)?\d{4}-.+\.md$/.test(path); /** * ADR indexable document interface From d07e48212018e2dbd959b0b3136dc6249bddac6d Mon Sep 17 00:00:00 2001 From: Andy Ladjadj Date: Fri, 24 Mar 2023 13:42:11 +0100 Subject: [PATCH 6/8] ci: update changeset to include plugin-adr-common Signed-off-by: Andy Ladjadj --- .changeset/odd-plums-bake.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.changeset/odd-plums-bake.md b/.changeset/odd-plums-bake.md index d2d66e67e2..427ab776b5 100644 --- a/.changeset/odd-plums-bake.md +++ b/.changeset/odd-plums-bake.md @@ -1,4 +1,5 @@ --- +'@backstage/plugin-adr-common': patch '@backstage/plugin-adr': patch --- From 0701dfc4b46abfe15e7ef078a069c7407dfc1ffb Mon Sep 17 00:00:00 2001 From: Andy Ladjadj Date: Fri, 24 Mar 2023 13:42:56 +0100 Subject: [PATCH 7/8] fix: update regex to keep retro compatibility Signed-off-by: Andy Ladjadj --- plugins/adr-common/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/adr-common/src/index.ts b/plugins/adr-common/src/index.ts index ffdd9b349a..cf71367cba 100644 --- a/plugins/adr-common/src/index.ts +++ b/plugins/adr-common/src/index.ts @@ -77,7 +77,7 @@ export type AdrFilePathFilterFn = (path: string) => boolean; * @public */ export const madrFilePathFilter: AdrFilePathFilterFn = (path: string) => - /^(?:.+\/)?\d{4}-.+\.md$/.test(path); + /^(?:.*\/)?\d{4}-.+\.md$/.test(path); /** * ADR indexable document interface From 79c2dd6d54331433736ebee106102d1c67c874a4 Mon Sep 17 00:00:00 2001 From: Andy Ladjadj Date: Fri, 24 Mar 2023 16:52:53 +0100 Subject: [PATCH 8/8] Update plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx Co-authored-by: Ben Lambert Signed-off-by: Andy Ladjadj --- .../adr/src/components/EntityAdrContent/EntityAdrContent.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx index 1567306f12..d136de4717 100644 --- a/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx +++ b/plugins/adr/src/components/EntityAdrContent/EntityAdrContent.tsx @@ -88,7 +88,8 @@ const AdrListContainer = (props: { switch (status) { case 'accepted': return 'primary'; - case 'rejected' || 'deprecated': + case 'rejected': + case 'deprecated': return 'secondary'; default: return 'default';