feat(ADR): implement ADR plugin
Signed-off-by: Phil Kuang <pkuang@factset.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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, { useMemo } from 'react';
|
||||
import {
|
||||
InfoCard,
|
||||
MarkdownContent,
|
||||
Progress,
|
||||
WarningPanel,
|
||||
} from '@backstage/core-components';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
||||
import { getAdrLocationUrl } from '@backstage/plugin-adr-common';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
|
||||
import { useOctokitRequest } from '../../hooks';
|
||||
import { adrDecoratorFactories } from './decorators';
|
||||
import { AdrContentDecorator } from './types';
|
||||
|
||||
/**
|
||||
* Component to fetch and render an ADR.
|
||||
* @public
|
||||
*/
|
||||
export const AdrReader = ({
|
||||
adr,
|
||||
decorators,
|
||||
}: {
|
||||
adr: string;
|
||||
decorators?: AdrContentDecorator[];
|
||||
}) => {
|
||||
const { entity } = useEntity();
|
||||
const scmIntegrations = useApi(scmIntegrationsApiRef);
|
||||
const adrLocationUrl = getAdrLocationUrl(entity, scmIntegrations);
|
||||
|
||||
const { value, loading, error } = useOctokitRequest(
|
||||
`${adrLocationUrl}/${adr}`,
|
||||
);
|
||||
|
||||
const adrContent = useMemo(() => {
|
||||
if (!value?.data) {
|
||||
return '';
|
||||
}
|
||||
const adrDecorators = decorators ?? [
|
||||
adrDecoratorFactories.createRewriteRelativeLinksDecorator(),
|
||||
adrDecoratorFactories.createRewriteRelativeEmbedsDecorator(),
|
||||
];
|
||||
|
||||
return adrDecorators.reduce(
|
||||
(content, decorator) =>
|
||||
decorator({ baseUrl: adrLocationUrl, content }).content,
|
||||
value.data,
|
||||
);
|
||||
}, [adrLocationUrl, decorators, value]);
|
||||
|
||||
return (
|
||||
<InfoCard>
|
||||
{loading && <Progress />}
|
||||
|
||||
{!loading && error && (
|
||||
<WarningPanel title="Failed to fetch ADR" message={error?.message} />
|
||||
)}
|
||||
|
||||
{!loading && !error && value?.data && (
|
||||
<MarkdownContent content={adrContent} linkTarget="_blank" />
|
||||
)}
|
||||
</InfoCard>
|
||||
);
|
||||
};
|
||||
|
||||
AdrReader.decorators = adrDecoratorFactories;
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 { AdrContentDecorator } from './types';
|
||||
|
||||
/**
|
||||
*
|
||||
* Factory for creating default ADR content decorators. The adrDecoratorFactories
|
||||
* symbol is not directly exported, but through the AdrReader.decorators field.
|
||||
* @public
|
||||
*/
|
||||
export const adrDecoratorFactories = Object.freeze({
|
||||
/**
|
||||
* Rewrites relative Markdown links as absolute links.
|
||||
*/
|
||||
createRewriteRelativeLinksDecorator(): AdrContentDecorator {
|
||||
return ({ baseUrl, content }) => ({
|
||||
content: content.replace(
|
||||
/\[([^\[\]]*)\]\((?!https?:\/\/)(.*?)(\.md)\)/gim,
|
||||
`[$1](${baseUrl}/$2$3)`,
|
||||
),
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Rewrites relative Markdown embeds using absolute URLs.
|
||||
*/
|
||||
createRewriteRelativeEmbedsDecorator(): AdrContentDecorator {
|
||||
return ({ baseUrl, content }) => ({
|
||||
content: content.replace(
|
||||
/!\[([^\[\]]*)\]\((?!https?:\/\/)(.*?)(\.png|\.jpg|\.jpeg|\.gif|\.webp)(.*)\)/gim,
|
||||
``,
|
||||
),
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 * from './AdrReader';
|
||||
export * from './types';
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ADR content decorator function type. Decorators are responsible for
|
||||
* performing any necessary transformations on the ADR content before rendering.
|
||||
* @public
|
||||
*/
|
||||
export type AdrContentDecorator = (adrInfo: {
|
||||
baseUrl: string;
|
||||
content: string;
|
||||
}) => { content: string };
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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, { useEffect, useState } from 'react';
|
||||
import { Link, useSearchParams } from 'react-router-dom';
|
||||
import {
|
||||
Content,
|
||||
ContentHeader,
|
||||
MissingAnnotationEmptyState,
|
||||
Progress,
|
||||
SupportButton,
|
||||
WarningPanel,
|
||||
} from '@backstage/core-components';
|
||||
import { useApi, useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
||||
import {
|
||||
AdrFilePathFilterFn,
|
||||
ANNOTATION_ADR_LOCATION,
|
||||
getAdrLocationUrl,
|
||||
isAdrAvailable,
|
||||
madrFilePathFilter,
|
||||
} from '@backstage/plugin-adr-common';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
Grid,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
makeStyles,
|
||||
Theme,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
|
||||
import { useOctokitRequest } from '../../hooks';
|
||||
import { rootRouteRef } from '../../routes';
|
||||
import { AdrContentDecorator, AdrReader } from '../AdrReader';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
adrMenu: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
}));
|
||||
|
||||
/**
|
||||
* Component for browsing ADRs on an entity page.
|
||||
* @public
|
||||
*/
|
||||
export const EntityAdrContent = ({
|
||||
contentDecorators,
|
||||
filePathFilterFn,
|
||||
}: {
|
||||
contentDecorators?: AdrContentDecorator[];
|
||||
filePathFilterFn?: AdrFilePathFilterFn;
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
const { entity } = useEntity();
|
||||
const rootLink = useRouteRef(rootRouteRef);
|
||||
const [adrList, setAdrList] = useState<string[]>([]);
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const scmIntegrations = useApi(scmIntegrationsApiRef);
|
||||
const entityHasAdrs = isAdrAvailable(entity);
|
||||
|
||||
const { value, loading, error } = useOctokitRequest(
|
||||
getAdrLocationUrl(entity, scmIntegrations),
|
||||
);
|
||||
|
||||
const selectedAdr =
|
||||
adrList.find(adr => adr === searchParams.get('record')) ?? '';
|
||||
useEffect(() => {
|
||||
if (adrList.length && !selectedAdr) {
|
||||
searchParams.set('record', adrList[0]);
|
||||
setSearchParams(searchParams, { replace: true });
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!value?.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const adrs = value.data
|
||||
.filter(
|
||||
(item: { type: string; name: string }) =>
|
||||
item.type === 'file' &&
|
||||
(filePathFilterFn
|
||||
? filePathFilterFn(item.name)
|
||||
: madrFilePathFilter(item.name)),
|
||||
)
|
||||
.map(({ name }: { name: string }) => name);
|
||||
|
||||
setAdrList(adrs);
|
||||
}, [filePathFilterFn, value]);
|
||||
|
||||
return (
|
||||
<Content>
|
||||
<ContentHeader title="Architecture Decision Records">
|
||||
<SupportButton />
|
||||
</ContentHeader>
|
||||
|
||||
{!entityHasAdrs && (
|
||||
<MissingAnnotationEmptyState annotation={ANNOTATION_ADR_LOCATION} />
|
||||
)}
|
||||
|
||||
{loading && <Progress />}
|
||||
|
||||
{entityHasAdrs && !loading && error && (
|
||||
<WarningPanel title="Failed to fetch ADRs" message={error?.message} />
|
||||
)}
|
||||
|
||||
{entityHasAdrs &&
|
||||
!loading &&
|
||||
!error &&
|
||||
(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}`}
|
||||
selected={selectedAdr === adr}
|
||||
>
|
||||
<ListItemText
|
||||
secondaryTypographyProps={{ noWrap: true }}
|
||||
secondary={adr.replace(/\.md$/, '')}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<AdrReader adr={selectedAdr} decorators={contentDecorators} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : (
|
||||
<Typography>No ADRs found</Typography>
|
||||
))}
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 { EntityAdrContent } from './EntityAdrContent';
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 * from './useOctokitRequest';
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 parseGitUrl from 'git-url-parse';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { Octokit } from 'octokit';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
scmAuthApiRef,
|
||||
scmIntegrationsApiRef,
|
||||
} from '@backstage/integration-react';
|
||||
|
||||
/**
|
||||
* Hook for triggering authenticated Octokit requests against the GitHub Content API
|
||||
* @public
|
||||
*/
|
||||
export const useOctokitRequest = (request: string): any => {
|
||||
const authApi = useApi(scmAuthApiRef);
|
||||
const scmIntegrations = useApi(scmIntegrationsApiRef);
|
||||
|
||||
const { owner, name, ref, filepath } = parseGitUrl(request);
|
||||
const path = filepath.replace(/^\//, '');
|
||||
const baseUrl = scmIntegrations.github.byUrl(request)?.config.apiBaseUrl;
|
||||
|
||||
return useAsync<any>(async () => {
|
||||
const { token } = await authApi.getCredentials({
|
||||
url: request,
|
||||
additionalScope: {
|
||||
customScopes: {
|
||||
github: ['repo'],
|
||||
},
|
||||
},
|
||||
});
|
||||
const octokit = new Octokit({
|
||||
auth: token,
|
||||
baseUrl,
|
||||
});
|
||||
|
||||
return octokit.request(
|
||||
`GET /repos/${owner}/${name}/contents/${path}?ref=${ref}`,
|
||||
{
|
||||
headers: { Accept: 'application/vnd.github.v3.raw' },
|
||||
},
|
||||
);
|
||||
}, [request]);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/**
|
||||
* ADR frontend plugin
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
export { isAdrAvailable } from '@backstage/plugin-adr-common';
|
||||
export * from './components/AdrReader';
|
||||
export { adrPlugin, EntityAdrContent } from './plugin';
|
||||
export * from './search';
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 { adrPlugin } from './plugin';
|
||||
|
||||
describe('adr', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(adrPlugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 {
|
||||
createPlugin,
|
||||
createRoutableExtension,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
import { rootRouteRef } from './routes';
|
||||
|
||||
/**
|
||||
* The Backstage plugin that holds ADR specific components
|
||||
* @public
|
||||
*/
|
||||
export const adrPlugin = createPlugin({
|
||||
id: 'adr',
|
||||
routes: {
|
||||
root: rootRouteRef,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* An extension for browsing ADRs on an entity page.
|
||||
* @public
|
||||
*/
|
||||
export const EntityAdrContent = adrPlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'EntityAdrContent',
|
||||
component: () =>
|
||||
import('./components/EntityAdrContent').then(m => m.EntityAdrContent),
|
||||
mountPoint: rootRouteRef,
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 { createRouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
* Root route ref for the ADR plugin
|
||||
* @public
|
||||
*/
|
||||
export const rootRouteRef = createRouteRef({
|
||||
id: 'adr',
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 TextTruncate from 'react-text-truncate';
|
||||
import {
|
||||
Box,
|
||||
Chip,
|
||||
Divider,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
makeStyles,
|
||||
} from '@material-ui/core';
|
||||
import { Link } from '@backstage/core-components';
|
||||
import { AdrDocument } from '@backstage/plugin-adr-common';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
flexContainer: {
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
itemText: {
|
||||
width: '100%',
|
||||
wordBreak: 'break-all',
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* A component to display a ADR search result
|
||||
* @public
|
||||
*/
|
||||
export const AdrSearchResultListItem = ({
|
||||
lineClamp = 5,
|
||||
result,
|
||||
}: {
|
||||
lineClamp?: number;
|
||||
result: AdrDocument;
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Link to={result.location}>
|
||||
<ListItem alignItems="flex-start" className={classes.flexContainer}>
|
||||
<ListItemText
|
||||
className={classes.itemText}
|
||||
primaryTypographyProps={{ variant: 'h6' }}
|
||||
primary={result.title}
|
||||
secondary={
|
||||
<TextTruncate
|
||||
line={lineClamp}
|
||||
truncateText="…"
|
||||
text={result.text}
|
||||
element="span"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Box>
|
||||
{result.status && (
|
||||
<Chip label={`Status: ${result.status}`} size="small" />
|
||||
)}
|
||||
{result.date && <Chip label={`Date: ${result.date}`} size="small" />}
|
||||
</Box>
|
||||
</ListItem>
|
||||
<Divider component="li" />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 * from './AdrSearchResultListItem';
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* 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 '@testing-library/jest-dom';
|
||||
import 'cross-fetch/polyfill';
|
||||
Reference in New Issue
Block a user