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:
@@ -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} />
|
||||
|
||||
Reference in New Issue
Block a user