Merge pull request #16430 from aladjadj/fix/adr-fetch-subdirectory

feat(plugins/adr): use path attribute to fetch file instead of name
This commit is contained in:
Phil Kuang
2023-04-04 11:41:27 -04:00
committed by GitHub
5 changed files with 137 additions and 54 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-adr-common': patch
'@backstage/plugin-adr': patch
---
use path attribute to fetch files instead of name and update the UI to navigate over subdirectories
+1 -1
View File
@@ -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
+1
View File
@@ -35,6 +35,7 @@
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.61",
"@types/react": "^16.13.1 || ^17.0.0",
"lodash": "^4.17.21",
"react-markdown": "^8.0.0",
"react-use": "^17.2.4",
"remark-gfm": "^3.0.1"
@@ -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,119 @@ 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 } 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':
case 'deprecated':
return 'secondary';
default:
return 'default';
}
};
const handleClick = () => {
setOpen(!open);
};
return (
<>
{title && (
<ListItem
button
className={classes.adrContainerTitle}
onClick={handleClick}
>
<ListItemIcon>
<FolderIcon />
</ListItemIcon>
<ListItemText primary={title} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
)}
<Collapse in={open} timeout="auto" unmountOnExit>
<List dense>
{adrs.map((adr, idx) => (
<ListItem
button
component={Link}
key={idx}
selected={selectedAdr === adr.path}
to={`${rootLink()}?record=${adr.path}`}
>
<ListItemText
primary={adr.title ?? adr?.name.replace(/\.md$/, '')}
primaryTypographyProps={{
style: { whiteSpace: 'normal' },
}}
secondary={
<Box>
{adr.date}
{adr.status && (
<Chip
color={getChipColor(adr.status)}
label={adr.status}
size="small"
variant="outlined"
className={classes.adrChip}
/>
)}
</Box>
}
/>
</ListItem>
))}
</List>
</Collapse>
</>
);
};
/**
* Component for browsing ADRs on an entity page.
* @public
@@ -67,10 +164,7 @@ export const EntityAdrContent = (props: {
const { contentDecorators, filePathFilterFn } = 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<AdrFileInfo[]>([]);
const [searchParams, setSearchParams] = useSearchParams();
const scmIntegrations = useApi(scmIntegrationsApiRef);
const adrApi = useApi(adrApiRef);
@@ -82,10 +176,15 @@ export const EntityAdrContent = (props: {
}, [entity, scmIntegrations]);
const selectedAdr =
adrList.find(adr => adr.name === searchParams.get('record'))?.name ?? '';
adrList.find(adr => adr.path === 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);
searchParams.set('record', adrList[0].path);
setSearchParams(searchParams, { replace: true });
}
});
@@ -95,29 +194,20 @@ 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.path)
: madrFilePathFilter(item.path)),
);
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 (
<Content>
@@ -141,33 +231,18 @@ export const EntityAdrContent = (props: {
(adrList.length ? (
<Grid container direction="row">
<Grid item xs={3}>
<List className={classes.adrMenu} dense>
{adrList.map((adr, idx) => (
<ListItem
key={idx}
button
component={Link}
to={`${rootLink()}?record=${adr.name}`}
selected={selectedAdr === adr.name}
>
<ListItemText
primaryTypographyProps={{
style: { whiteSpace: 'normal' },
}}
primary={adr.title ?? adr?.name.replace(/\.md$/, '')}
secondary={adr.date}
<InfoCard>
<List className={classes.adrMenu} dense>
{adrListGrouped.map(([title, adrs], idx) => (
<AdrListContainer
adrs={adrs}
key={idx}
selectedAdr={selectedAdr}
title={title}
/>
{adr.status && (
<Chip
label={adr.status}
size="small"
variant="outlined"
color={getChipColor(adr.status)}
/>
)}
</ListItem>
))}
</List>
))}
</List>
</InfoCard>
</Grid>
<Grid item xs={9}>
<AdrReader adr={selectedAdr} decorators={contentDecorators} />
+1
View File
@@ -4356,6 +4356,7 @@ __metadata:
"@types/node": "*"
"@types/react": ^16.13.1 || ^17.0.0
cross-fetch: ^3.1.5
lodash: ^4.17.21
msw: ^1.0.0
react-markdown: ^8.0.0
react-use: ^17.2.4