Merge pull request #5957 from SDA-SE/feat/scaffolder-source
Show link to template source on template card
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/integration-react': patch
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Move `ScmIntegrationIcon` from `@backstage/plugin-catalog` to
|
||||
`@backstage/integration-react` and make it customizable using
|
||||
`app.getSystemIcon()`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Provide a link to the template source on the `TemplateCard`.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': patch
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
---
|
||||
|
||||
Expose `getEntitySourceLocation`, `getEntityMetadataViewUrl`, and
|
||||
`getEntityMetadataEditUrl` from `@backstage/plugin-catalog-react`.
|
||||
@@ -8,6 +8,11 @@ import { ApiRef } from '@backstage/core';
|
||||
import { Config } from '@backstage/config';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
|
||||
// @public (undocumented)
|
||||
export const ScmIntegrationIcon: ({ type }: {
|
||||
type?: string | undefined;
|
||||
}) => JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export class ScmIntegrationsApi {
|
||||
// (undocumented)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2021 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 {
|
||||
ScmIntegrationsApi,
|
||||
scmIntegrationsApiRef,
|
||||
} from './ScmIntegrationsApi';
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 { renderInTestApp } from '@backstage/test-utils';
|
||||
import React from 'react';
|
||||
import { ScmIntegrationIcon } from './ScmIntegrationIcon';
|
||||
|
||||
describe('<ScmIntegrationIcon />', () => {
|
||||
it('renders without exploding (github)', async () => {
|
||||
const { baseElement } = await renderInTestApp(
|
||||
<ScmIntegrationIcon type="github" />,
|
||||
);
|
||||
expect(baseElement.querySelector('svg')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders without exploding (unknown)', async () => {
|
||||
const { baseElement } = await renderInTestApp(
|
||||
<ScmIntegrationIcon type="unknown" />,
|
||||
);
|
||||
expect(baseElement.querySelector('svg')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
+5
-11
@@ -13,19 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { useApp } from '@backstage/core';
|
||||
import CodeIcon from '@material-ui/icons/Code';
|
||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
||||
import React from 'react';
|
||||
|
||||
export const ScmIntegrationIcon = ({ type }: { type?: string }) => {
|
||||
// TODO: In the future we might want to support more types here as a GitLab or
|
||||
// Bitbucket icons were requested here in the past, or even use the icon
|
||||
// customization feature of the app. But material UI react doesn't provide more.
|
||||
|
||||
switch (type) {
|
||||
case 'github':
|
||||
return <GitHubIcon />;
|
||||
default:
|
||||
return <CodeIcon />;
|
||||
}
|
||||
const app = useApp();
|
||||
const DefaultIcon = CodeIcon;
|
||||
const Icon = type ? app.getSystemIcon(type) ?? DefaultIcon : DefaultIcon;
|
||||
return <Icon />;
|
||||
};
|
||||
+2
-5
@@ -13,8 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export {
|
||||
getEntityMetadataEditUrl,
|
||||
getEntityMetadataViewUrl,
|
||||
} from './getEntityMetadataUrl';
|
||||
export { getEntitySourceLocation } from './getEntitySourceLocation';
|
||||
|
||||
export { ScmIntegrationIcon } from './ScmIntegrationIcon';
|
||||
@@ -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 * from './ScmIntegrationIcon';
|
||||
@@ -14,7 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export {
|
||||
ScmIntegrationsApi,
|
||||
scmIntegrationsApiRef,
|
||||
} from './ScmIntegrationsApi';
|
||||
export * from './api';
|
||||
export * from './components';
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"@backstage/catalog-model": "^0.8.1",
|
||||
"@backstage/core": "^0.7.12",
|
||||
"@backstage/core-plugin-api": "^0.1.1",
|
||||
"@backstage/integration": "^0.5.0",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.45",
|
||||
|
||||
@@ -14,5 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './filters';
|
||||
export {
|
||||
getEntityMetadataEditUrl,
|
||||
getEntityMetadataViewUrl,
|
||||
} from './getEntityMetadataUrl';
|
||||
export { getEntityRelations } from './getEntityRelations';
|
||||
export { getEntitySourceLocation } from './getEntitySourceLocation';
|
||||
export type { EntitySourceLocation } from './getEntitySourceLocation';
|
||||
export { isOwnerOf } from './isOwnerOf';
|
||||
|
||||
@@ -26,8 +26,16 @@ import {
|
||||
InfoCardVariants,
|
||||
useApi,
|
||||
} from '@backstage/core';
|
||||
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
||||
import { getEntityRelations, useEntity } from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
ScmIntegrationIcon,
|
||||
scmIntegrationsApiRef,
|
||||
} from '@backstage/integration-react';
|
||||
import {
|
||||
getEntityMetadataEditUrl,
|
||||
getEntityRelations,
|
||||
getEntitySourceLocation,
|
||||
useEntity,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@@ -40,9 +48,7 @@ import DocsIcon from '@material-ui/icons/Description';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import ExtensionIcon from '@material-ui/icons/Extension';
|
||||
import React from 'react';
|
||||
import { getEntityMetadataEditUrl, getEntitySourceLocation } from '../../utils';
|
||||
import { AboutContent } from './AboutContent';
|
||||
import { ScmIntegrationIcon } from './ScmIntegrationIcon';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
gridItemCard: {
|
||||
|
||||
@@ -17,4 +17,3 @@
|
||||
export { AboutCard } from './AboutCard';
|
||||
export { AboutContent } from './AboutContent';
|
||||
export { AboutField } from './AboutField';
|
||||
export { ScmIntegrationIcon } from './ScmIntegrationIcon';
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
} from '@backstage/core';
|
||||
import {
|
||||
formatEntityRefTitle,
|
||||
getEntityMetadataEditUrl,
|
||||
getEntityMetadataViewUrl,
|
||||
getEntityRelations,
|
||||
useEntityListProvider,
|
||||
useStarredEntities,
|
||||
@@ -31,10 +33,6 @@ import Edit from '@material-ui/icons/Edit';
|
||||
import OpenInNew from '@material-ui/icons/OpenInNew';
|
||||
import { capitalize } from 'lodash';
|
||||
import React from 'react';
|
||||
import {
|
||||
getEntityMetadataEditUrl,
|
||||
getEntityMetadataViewUrl,
|
||||
} from '../../utils';
|
||||
import {
|
||||
favouriteEntityIcon,
|
||||
favouriteEntityTooltip,
|
||||
|
||||
@@ -14,15 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { AboutCard } from './components/AboutCard';
|
||||
export * from './components/AboutCard';
|
||||
export { CatalogResultListItem } from './components/CatalogResultListItem';
|
||||
export { EntityLayout } from './components/EntityLayout';
|
||||
export { EntityPageLayout } from './components/EntityPageLayout';
|
||||
export { CatalogTable } from './components/CatalogTable';
|
||||
export { EntityLayout } from './components/EntityLayout';
|
||||
export * from './components/EntityOrphanWarning';
|
||||
export { EntityPageLayout } from './components/EntityPageLayout';
|
||||
export * from './components/EntitySwitch';
|
||||
export { Router } from './components/Router';
|
||||
export * from './components/EntityOrphanWarning';
|
||||
export * from './components/AboutCard';
|
||||
export {
|
||||
CatalogEntityPage,
|
||||
CatalogIndexPage,
|
||||
@@ -39,4 +38,3 @@ export {
|
||||
EntityLinksCard,
|
||||
EntitySystemDiagramCard,
|
||||
} from './plugin';
|
||||
export * from './utils';
|
||||
|
||||
@@ -13,7 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Button, ItemCardHeader, useRouteRef } from '@backstage/core';
|
||||
import {
|
||||
Entity,
|
||||
RELATION_OWNED_BY,
|
||||
TemplateEntityV1alpha1,
|
||||
} from '@backstage/catalog-model';
|
||||
import { Button, ItemCardHeader, useApi, useRouteRef } from '@backstage/core';
|
||||
import {
|
||||
ScmIntegrationIcon,
|
||||
scmIntegrationsApiRef,
|
||||
} from '@backstage/integration-react';
|
||||
import {
|
||||
EntityRefLinks,
|
||||
getEntityRelations,
|
||||
getEntitySourceLocation,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { BackstageTheme, pageTheme } from '@backstage/theme';
|
||||
import {
|
||||
Box,
|
||||
@@ -22,26 +36,18 @@ import {
|
||||
CardContent,
|
||||
CardMedia,
|
||||
Chip,
|
||||
IconButton,
|
||||
Link,
|
||||
makeStyles,
|
||||
Tooltip,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import WarningIcon from '@material-ui/icons/Warning';
|
||||
import React from 'react';
|
||||
import { generatePath } from 'react-router';
|
||||
import { rootRouteRef } from '../../routes';
|
||||
import {
|
||||
TemplateEntityV1alpha1,
|
||||
Entity,
|
||||
RELATION_OWNED_BY,
|
||||
} from '@backstage/catalog-model';
|
||||
import { FavouriteTemplate } from '../FavouriteTemplate/FavouriteTemplate';
|
||||
import {
|
||||
getEntityRelations,
|
||||
EntityRefLinks,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
cardHeader: {
|
||||
@@ -67,6 +73,9 @@ const useStyles = makeStyles(theme => ({
|
||||
lineHeight: 1,
|
||||
paddingBottom: '0.2rem',
|
||||
},
|
||||
leftButton: {
|
||||
marginRight: 'auto',
|
||||
},
|
||||
}));
|
||||
|
||||
const useDeprecationStyles = makeStyles(theme => ({
|
||||
@@ -145,6 +154,9 @@ export const TemplateCard = ({ template, deprecated }: TemplateCardProps) => {
|
||||
templateName: templateProps.name,
|
||||
});
|
||||
|
||||
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
|
||||
const sourceLocation = getEntitySourceLocation(template, scmIntegrationsApi);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardMedia className={classes.cardHeader}>
|
||||
@@ -179,6 +191,14 @@ export const TemplateCard = ({ template, deprecated }: TemplateCardProps) => {
|
||||
</Box>
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
{sourceLocation && (
|
||||
<IconButton
|
||||
className={classes.leftButton}
|
||||
href={sourceLocation.locationTargetUrl}
|
||||
>
|
||||
<ScmIntegrationIcon type={sourceLocation.integrationType} />
|
||||
</IconButton>
|
||||
)}
|
||||
<Button
|
||||
color="primary"
|
||||
to={href}
|
||||
|
||||
Reference in New Issue
Block a user