Added linguist frontend, backend, and common plugins
Signed-off-by: Andre Wanlin <andrewanlin@gmail.com> Removed refresh and permissions Signed-off-by: Andre Wanlin <andrewanlin@gmail.com> Small database refactor and improved naming Signed-off-by: Andre Wanlin <andrewanlin@gmail.com> Refactor stringifyEntityRef usage Signed-off-by: Andre Wanlin <andrewanlin@gmail.com> Fixed up yarn.lock Signed-off-by: Andre Wanlin <andrewanlin@gmail.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
@@ -0,0 +1,88 @@
|
||||
# Linguist
|
||||
|
||||
Welcome to the Linguist plugin!
|
||||
|
||||
## Features
|
||||
|
||||
The Linguist plugin consists of a card that will give you the breakdown of the languages used by the configured Entity in the Catalog.
|
||||
|
||||
When there is no Linguist data yet the card will be empty:
|
||||
|
||||

|
||||
|
||||
Clicking on the refresh icon will generate the language breakdown:
|
||||
|
||||

|
||||
|
||||
Here's an example where the permissions are hiding the refresh button:
|
||||
|
||||

|
||||
|
||||
## Setup
|
||||
|
||||
The following sections will help you get the Linguist plugin setup and running.
|
||||
|
||||
### Backend
|
||||
|
||||
You need to setup the [Linguist backend plugin](../linguist-backend/README.md) before you move forward with any of the following steps if you haven't already.
|
||||
|
||||
### Entity Annotation
|
||||
|
||||
To be able to use the Linguist plugin you need to add the following annotation to any entities you want to use it with:
|
||||
|
||||
```yaml
|
||||
backstage.io/linguist: https://url.to/your/srouce/code
|
||||
```
|
||||
|
||||
Linguist uses the `UrlReader` to pull down the files before it scans them to determine the languages, this means you can pull files from all the supported providers - GitHub, GitLab, Bitbucket, Azure, Google GCS, AWS S3, etc.
|
||||
|
||||
Here's what that will look like in action using the Backstage repo as an example:
|
||||
|
||||
```yaml
|
||||
# Example catalog-info.yaml entity definition file
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
# ...
|
||||
annotations:
|
||||
backstage.io/linguist: https://github.com/backstage/backstage
|
||||
spec:
|
||||
type: service
|
||||
# ...
|
||||
```
|
||||
|
||||
### Frontend
|
||||
|
||||
To setup the Linguist Card frontend you'll need to do the following steps:
|
||||
|
||||
1. First we need to add the `@backstage/plugin-linguist` package to your frontend app:
|
||||
|
||||
```sh
|
||||
# From your Backstage root directory
|
||||
yarn add --cwd packages/app @backstage/plugin-linguist
|
||||
```
|
||||
|
||||
2. Second we need to add the `EntityLinguistCard` extension to the entity page in your app:
|
||||
|
||||
```tsx
|
||||
// In packages/app/src/components/catalog/EntityPage.tsx
|
||||
import { isLinguistAvailable, EntityLinguistCard } from '@backstage/plugin-linguist';
|
||||
|
||||
// For example in the Overview section
|
||||
const overviewContent = (
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
// ...
|
||||
<EntitySwitch>
|
||||
<EntitySwitch.Case if={isLinguistAvailable}>
|
||||
<Grid item md={6}>
|
||||
<EntityLinguistCard />
|
||||
</Grid>
|
||||
</EntitySwitch.Case>
|
||||
</EntitySwitch>
|
||||
// ...
|
||||
</Grid>
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
|
||||
- The `if` prop is optional on the `EntitySwitch.Case`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation
|
||||
@@ -0,0 +1,21 @@
|
||||
## API Report File for "@backstage/plugin-linguist"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
// @public (undocumented)
|
||||
export const EntityLinguistCard: () => JSX.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export const isLinguistAvailable: (entity: Entity) => boolean;
|
||||
|
||||
// @public (undocumented)
|
||||
export const linguistPlugin: BackstagePlugin<{}, {}, {}>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 { createDevApp } from '@backstage/dev-utils';
|
||||
import { linguistPlugin, EntityLinguistCard } from '../src/plugin';
|
||||
|
||||
createDevApp()
|
||||
.registerPlugin(linguistPlugin)
|
||||
.addPage({
|
||||
element: <EntityLinguistCard />,
|
||||
title: 'Root Page',
|
||||
path: '/linguist',
|
||||
})
|
||||
.render();
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"name": "@backstage/plugin-linguist",
|
||||
"version": "0.0.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "frontend-plugin"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/linguist"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test",
|
||||
"clean": "backstage-cli package clean",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/plugin-catalog-react": "workspace:^",
|
||||
"@backstage/plugin-linguist-common": "workspace:^",
|
||||
"@backstage/theme": "workspace:^",
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||
"luxon": "^2.0.2",
|
||||
"react-use": "^17.2.4",
|
||||
"slugify": "^1.6.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/dev-utils": "workspace:^",
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@types/node": "*",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"msw": "^0.49.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 { createApiRef } from '@backstage/core-plugin-api';
|
||||
import { Languages } from '@backstage/plugin-linguist-common';
|
||||
|
||||
export const linguistApiRef = createApiRef<LinguistApi>({
|
||||
id: 'plugin.linguist.service',
|
||||
});
|
||||
|
||||
export interface LinguistApi {
|
||||
getLanguages(entityRef: string): Promise<Languages>;
|
||||
}
|
||||
@@ -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 { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import { Languages } from '@backstage/plugin-linguist-common';
|
||||
import { LinguistApi } from './LinguistApi';
|
||||
|
||||
export class LinguistClient implements LinguistApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
private readonly identityApi: IdentityApi;
|
||||
|
||||
public constructor(options: {
|
||||
discoveryApi: DiscoveryApi;
|
||||
identityApi: IdentityApi;
|
||||
}) {
|
||||
this.discoveryApi = options.discoveryApi;
|
||||
this.identityApi = options.identityApi;
|
||||
}
|
||||
|
||||
public async getLanguages(entityRef: string): Promise<Languages> {
|
||||
const queryString = new URLSearchParams();
|
||||
queryString.append('entityRef', entityRef);
|
||||
|
||||
const urlSegment = `entity-languages?${queryString}`;
|
||||
|
||||
const items = await this.get<Languages>(urlSegment);
|
||||
return items;
|
||||
}
|
||||
|
||||
private async get<T>(path: string): Promise<T> {
|
||||
const baseUrl = `${await this.discoveryApi.getBaseUrl('linguist')}/`;
|
||||
const url = new URL(path, baseUrl);
|
||||
|
||||
const { token } = await this.identityApi.getCredentials();
|
||||
const response = await fetch(url.toString(), {
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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 './LinguistApi';
|
||||
export * from './LinguistClient';
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 {
|
||||
Box,
|
||||
Chip,
|
||||
Tooltip,
|
||||
Typography,
|
||||
makeStyles,
|
||||
Grid,
|
||||
useTheme,
|
||||
} from '@material-ui/core';
|
||||
import { InfoCard, Progress } from '@backstage/core-components';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import { DateTime } from 'luxon';
|
||||
import React from 'react';
|
||||
import slugify from 'slugify';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { useLanguages } from '../../hooks';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
infoCard: {
|
||||
marginBottom: theme.spacing(3),
|
||||
},
|
||||
barContainer: {
|
||||
height: theme.spacing(2),
|
||||
marginBottom: theme.spacing(3),
|
||||
borderRadius: '4px',
|
||||
backgroundColor: 'transparent',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
bar: {
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
},
|
||||
languageDot: {
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
borderRadius: '50%',
|
||||
marginRight: theme.spacing(1),
|
||||
display: 'inline-block',
|
||||
},
|
||||
label: {
|
||||
color: 'inherit',
|
||||
},
|
||||
}));
|
||||
|
||||
export const LinguistCard = () => {
|
||||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
const { entity } = useEntity();
|
||||
const { items, loading, error } = useLanguages(entity);
|
||||
let barWidth = 0;
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (error) {
|
||||
return <Alert severity="error">{error.message}</Alert>;
|
||||
}
|
||||
|
||||
if (items && items.languageCount === 0 && items.totalBytes === 0) {
|
||||
return (
|
||||
<InfoCard title="Languages" className={classes.infoCard}>
|
||||
<Grid container spacing={3}>
|
||||
<Box p={2}>
|
||||
<Typography>
|
||||
There is currently no language data for this entity.
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
</InfoCard>
|
||||
);
|
||||
}
|
||||
|
||||
const breakdown = items?.breakdown.sort((a, b) =>
|
||||
a.percentage < b.percentage ? 1 : -1,
|
||||
);
|
||||
const processedDate = items?.processedDate;
|
||||
|
||||
return breakdown && processedDate ? (
|
||||
<InfoCard title="Languages" className={classes.infoCard}>
|
||||
<Box className={classes.barContainer}>
|
||||
{breakdown.map((language, index: number) => {
|
||||
barWidth = barWidth + language.percentage;
|
||||
return (
|
||||
<Tooltip
|
||||
title={language.name}
|
||||
placement="bottom-end"
|
||||
key={slugify(language.name, { lower: true })}
|
||||
>
|
||||
<Box
|
||||
className={classes.bar}
|
||||
key={slugify(language.name, { lower: true })}
|
||||
style={{
|
||||
marginTop: index === 0 ? '0' : `-16px`,
|
||||
zIndex: Object.keys(breakdown).length - index,
|
||||
backgroundColor:
|
||||
language.color?.toString() ||
|
||||
theme.palette.background.default,
|
||||
width: `${barWidth}%`,
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
<Tooltip
|
||||
title={`Generated ${DateTime.fromISO(processedDate).toRelative()}`}
|
||||
>
|
||||
<Box>
|
||||
{breakdown.map(languages => (
|
||||
<Chip
|
||||
classes={{
|
||||
label: classes.label,
|
||||
}}
|
||||
label={
|
||||
<Box>
|
||||
<Box
|
||||
component="span"
|
||||
className={classes.languageDot}
|
||||
style={{
|
||||
backgroundColor:
|
||||
languages?.color?.toString() ||
|
||||
theme.palette.background.default,
|
||||
}}
|
||||
/>
|
||||
{languages.name} - {languages.percentage}%
|
||||
</Box>
|
||||
}
|
||||
variant="outlined"
|
||||
key={slugify(languages.name, { lower: true })}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</InfoCard>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
@@ -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 { LinguistCard } from './LinguistCard';
|
||||
@@ -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 './useLanguages';
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 { Entity, stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { linguistApiRef } from '../api';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
||||
import { Languages } from '@backstage/plugin-linguist-common';
|
||||
|
||||
export function useLanguages(entity: Entity): {
|
||||
items?: Languages;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
} {
|
||||
const entityRef = stringifyEntityRef(entity);
|
||||
|
||||
const api = useApi(linguistApiRef);
|
||||
const { value, loading, error } = useAsync(() => {
|
||||
return api.getLanguages(entityRef);
|
||||
}, [api, entityRef]);
|
||||
|
||||
return {
|
||||
items: value,
|
||||
loading,
|
||||
error,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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 {
|
||||
linguistPlugin,
|
||||
isLinguistAvailable,
|
||||
EntityLinguistCard,
|
||||
} from './plugin';
|
||||
@@ -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 { linguistPlugin } from './plugin';
|
||||
|
||||
describe('linguist', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(linguistPlugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 {
|
||||
createApiFactory,
|
||||
createComponentExtension,
|
||||
createPlugin,
|
||||
discoveryApiRef,
|
||||
identityApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { linguistApiRef, LinguistClient } from './api';
|
||||
import { LINGUIST_ANNOTATION } from '@backstage/plugin-linguist-common';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
/** @public */
|
||||
export const isLinguistAvailable = (entity: Entity) =>
|
||||
Boolean(entity.metadata.annotations?.[LINGUIST_ANNOTATION]);
|
||||
|
||||
/** @public */
|
||||
export const linguistPlugin = createPlugin({
|
||||
id: 'linguist',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: linguistApiRef,
|
||||
deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef },
|
||||
factory: ({ discoveryApi, identityApi }) =>
|
||||
new LinguistClient({ discoveryApi, identityApi }),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
/** @public */
|
||||
export const EntityLinguistCard = linguistPlugin.provide(
|
||||
createComponentExtension({
|
||||
name: 'EntityLinguistCard',
|
||||
component: {
|
||||
lazy: () => import('./components/LinguistCard').then(m => m.LinguistCard),
|
||||
},
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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