Merge branch 'master' of https://github.com/spotify/backstage into k8s-load-with-only-queryselector
This commit is contained in:
@@ -1,5 +1,29 @@
|
||||
# @backstage/plugin-api-docs
|
||||
|
||||
## 0.4.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d6593abe6: Remove domain column from `HasSystemsCard` and system from `HasComponentsCard`,
|
||||
`HasSubcomponentsCard`, and `HasApisCard`.
|
||||
- 437bac549: Make the description column in the catalog table and api-docs table use up as
|
||||
much space as possible before hiding overflowing text.
|
||||
- 5469a9761: Changes made in CatalogTable and ApiExplorerTable for using the OverflowTooltip component for truncating large description and showing tooltip on hover-over.
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.4.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-api-docs",
|
||||
"version": "0.4.6",
|
||||
"version": "0.4.7",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,9 +30,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@asyncapi/react-component": "^0.18.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-icons/font": "^1.0.2",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
@@ -49,9 +49,9 @@
|
||||
"swagger-ui-react": "^3.37.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -99,6 +99,7 @@ const columns: TableColumn<EntityRow>[] = [
|
||||
placement="bottom-start"
|
||||
/>
|
||||
),
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
title: 'Tags',
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
InfoCard,
|
||||
Link,
|
||||
Progress,
|
||||
TableColumn,
|
||||
WarningPanel,
|
||||
} from '@backstage/core';
|
||||
import {
|
||||
@@ -28,12 +29,20 @@ import {
|
||||
useRelatedEntities,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import React from 'react';
|
||||
import { apiEntityColumns } from './presets';
|
||||
import { createSpecApiTypeColumn } from './presets';
|
||||
|
||||
type Props = {
|
||||
variant?: 'gridItem';
|
||||
};
|
||||
|
||||
const columns: TableColumn<ApiEntity>[] = [
|
||||
EntityTable.columns.createEntityRefColumn({ defaultKind: 'API' }),
|
||||
EntityTable.columns.createOwnerColumn(),
|
||||
EntityTable.columns.createSpecLifecycleColumn(),
|
||||
createSpecApiTypeColumn(),
|
||||
EntityTable.columns.createMetadataDescriptionColumn(),
|
||||
];
|
||||
|
||||
export const HasApisCard = ({ variant = 'gridItem' }: Props) => {
|
||||
const { entity } = useEntity();
|
||||
const { entities, loading, error } = useRelatedEntities(entity, {
|
||||
@@ -73,7 +82,7 @@ export const HasApisCard = ({ variant = 'gridItem' }: Props) => {
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
columns={apiEntityColumns}
|
||||
columns={columns}
|
||||
entities={entities as ApiEntity[]}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/plugin-app-backend
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1c06cb312: Clarify troubleshooting steps for schema serialization issues.
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-app-backend",
|
||||
"version": "0.3.7",
|
||||
"version": "0.3.8",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.3",
|
||||
"@backstage/config-loader": "^0.5.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@types/express": "^4.17.6",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^3.0.3",
|
||||
@@ -40,7 +40,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"msw": "^0.20.5",
|
||||
"supertest": "^4.0.2"
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/plugin-auth-backend
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ec504e7b4: Fix for refresh token being lost during Microsoft login.
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- @backstage/catalog-model@0.7.2
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-auth-backend",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,8 +31,8 @@
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.4",
|
||||
"@backstage/catalog-client": "^0.3.6",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/passport": "^1.0.3",
|
||||
"compression": "^1.7.4",
|
||||
@@ -66,7 +66,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@types/body-parser": "^1.19.0",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express-session": "^1.17.2",
|
||||
|
||||
@@ -54,12 +54,12 @@ export class GithubAuthProvider implements OAuthHandlers {
|
||||
},
|
||||
(
|
||||
accessToken: any,
|
||||
refreshToken: any,
|
||||
_refreshToken: any,
|
||||
params: any,
|
||||
fullProfile: any,
|
||||
done: PassportDoneCallback<OAuthResult>,
|
||||
) => {
|
||||
done(undefined, { fullProfile, params, accessToken, refreshToken });
|
||||
done(undefined, { fullProfile, params, accessToken });
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,12 +51,12 @@ export class GitlabAuthProvider implements OAuthHandlers {
|
||||
},
|
||||
(
|
||||
accessToken: any,
|
||||
refreshToken: any,
|
||||
_refreshToken: any,
|
||||
params: any,
|
||||
fullProfile: any,
|
||||
done: PassportDoneCallback<OAuthResult>,
|
||||
) => {
|
||||
done(undefined, { fullProfile, params, accessToken, refreshToken });
|
||||
done(undefined, { fullProfile, params, accessToken });
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export class MicrosoftAuthProvider implements OAuthHandlers {
|
||||
fullProfile: passport.Profile,
|
||||
done: PassportDoneCallback<OAuthResult, PrivateInfo>,
|
||||
) => {
|
||||
done(undefined, { fullProfile, accessToken, refreshToken, params });
|
||||
done(undefined, { fullProfile, accessToken, params }, { refreshToken });
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/plugin-catalog-backend
|
||||
|
||||
## 0.6.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2499f6cde: Add support for assuming role in AWS integrations
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- @backstage/catalog-model@0.7.2
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
Vendored
+13
@@ -334,6 +334,19 @@ export interface Config {
|
||||
}>;
|
||||
};
|
||||
|
||||
/**
|
||||
* AwsOrganizationCloudAccountProcessor configuration
|
||||
*/
|
||||
awsOrganization?: {
|
||||
provider: {
|
||||
/**
|
||||
* The role to be assumed by this processor
|
||||
*
|
||||
*/
|
||||
roleArn?: string;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* MicrosoftGraphOrgReaderProcessor configuration
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-backend",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,8 +31,8 @@
|
||||
"dependencies": {
|
||||
"@azure/msal-node": "^1.0.0-beta.3",
|
||||
"@backstage/backend-common": "^0.5.4",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/integration": "^0.5.0",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@types/express": "^4.17.6",
|
||||
@@ -59,8 +59,8 @@
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@types/core-js": "^2.5.4",
|
||||
"@types/git-url-parse": "^9.0.0",
|
||||
"@types/lodash": "^4.14.151",
|
||||
|
||||
+5
-1
@@ -15,10 +15,14 @@
|
||||
*/
|
||||
|
||||
import { AwsOrganizationCloudAccountProcessor } from './AwsOrganizationCloudAccountProcessor';
|
||||
import * as winston from 'winston';
|
||||
|
||||
describe('AwsOrganizationCloudAccountProcessor', () => {
|
||||
describe('readLocation', () => {
|
||||
const processor = new AwsOrganizationCloudAccountProcessor();
|
||||
const processor = new AwsOrganizationCloudAccountProcessor({
|
||||
provider: {},
|
||||
logger: winston.createLogger(),
|
||||
});
|
||||
const location = { type: 'aws-cloud-accounts', target: '' };
|
||||
const emit = jest.fn();
|
||||
const listAccounts = jest.fn();
|
||||
|
||||
+38
-2
@@ -14,11 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { LocationSpec, ResourceEntityV1alpha1 } from '@backstage/catalog-model';
|
||||
import AWS, { Organizations } from 'aws-sdk';
|
||||
import AWS, { Credentials, Organizations } from 'aws-sdk';
|
||||
import { Account, ListAccountsResponse } from 'aws-sdk/clients/organizations';
|
||||
|
||||
import * as results from './results';
|
||||
import { CatalogProcessor, CatalogProcessorEmit } from './types';
|
||||
import { Config } from '@backstage/config';
|
||||
import { Logger } from 'winston';
|
||||
import {
|
||||
AwsOrganizationProviderConfig,
|
||||
readAwsOrganizationConfig,
|
||||
} from './awsOrganization/config';
|
||||
|
||||
const AWS_ORGANIZATION_REGION = 'us-east-1';
|
||||
const LOCATION_TYPE = 'aws-cloud-accounts';
|
||||
@@ -33,9 +39,39 @@ const ORGANIZATION_ANNOTATION: string = 'amazonaws.com/organization-id';
|
||||
* If custom authentication is needed, it can be achieved by configuring the global AWS.credentials object.
|
||||
*/
|
||||
export class AwsOrganizationCloudAccountProcessor implements CatalogProcessor {
|
||||
logger: Logger;
|
||||
organizations: Organizations;
|
||||
constructor() {
|
||||
provider: AwsOrganizationProviderConfig;
|
||||
|
||||
static fromConfig(config: Config, options: { logger: Logger }) {
|
||||
const c = config.getOptionalConfig('catalog.processors.awsOrganization');
|
||||
return new AwsOrganizationCloudAccountProcessor({
|
||||
...options,
|
||||
provider: c ? readAwsOrganizationConfig(c) : {},
|
||||
});
|
||||
}
|
||||
|
||||
constructor(options: {
|
||||
provider: AwsOrganizationProviderConfig;
|
||||
logger: Logger;
|
||||
}) {
|
||||
this.provider = options.provider;
|
||||
this.logger = options.logger;
|
||||
let credentials = undefined;
|
||||
if (
|
||||
this.provider.roleArn !== undefined &&
|
||||
AWS.config.credentials instanceof Credentials
|
||||
) {
|
||||
credentials = new AWS.ChainableTemporaryCredentials({
|
||||
masterCredentials: AWS.config.credentials as Credentials,
|
||||
params: {
|
||||
RoleSessionName: 'backstage-aws-organization-processor',
|
||||
RoleArn: this.provider.roleArn,
|
||||
},
|
||||
});
|
||||
}
|
||||
this.organizations = new AWS.Organizations({
|
||||
credentials,
|
||||
region: AWS_ORGANIZATION_REGION,
|
||||
}); // Only available in us-east-1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 { ConfigReader } from '@backstage/config';
|
||||
import { readAwsOrganizationConfig } from './config';
|
||||
|
||||
describe('readAwsOrganizationConfig', () => {
|
||||
it('applies all of the defaults', () => {
|
||||
const config = {
|
||||
provider: {
|
||||
roleArn: 'aws::arn::foo',
|
||||
},
|
||||
};
|
||||
const actual = readAwsOrganizationConfig(new ConfigReader(config));
|
||||
const expected = {
|
||||
roleArn: 'aws::arn::foo',
|
||||
};
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
+20
-15
@@ -14,20 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useApi } from '@backstage/core';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { CircularProgress, useTheme } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
export const AllServicesCount = () => {
|
||||
const theme = useTheme();
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const { value, loading } = useAsync(() => catalogApi.getEntities());
|
||||
|
||||
if (loading) {
|
||||
return <CircularProgress size={theme.spacing(2)} />;
|
||||
}
|
||||
|
||||
return <span>{value ?? length ?? '-'}</span>;
|
||||
/**
|
||||
* The configuration parameters for a single AWS Organization Processor
|
||||
*/
|
||||
export type AwsOrganizationProviderConfig = {
|
||||
/**
|
||||
* The role to assume for the processor.
|
||||
*/
|
||||
roleArn?: string;
|
||||
};
|
||||
|
||||
export function readAwsOrganizationConfig(
|
||||
config: Config,
|
||||
): AwsOrganizationProviderConfig {
|
||||
const providerConfig = config.getOptionalConfig('provider');
|
||||
|
||||
const roleArn = providerConfig?.getOptionalString('roleArn');
|
||||
return {
|
||||
roleArn,
|
||||
};
|
||||
}
|
||||
@@ -60,6 +60,16 @@ export async function createRouter(
|
||||
res.status(200).json(entities.map(fieldMapper));
|
||||
})
|
||||
.post('/entities', async (req, res) => {
|
||||
/*
|
||||
* NOTE: THIS METHOD IS DEPRECATED AND NOT RECOMMENDED TO USE
|
||||
*
|
||||
* Posting entities to this method has unclear semantics and will not
|
||||
* properly subject them to limitations, processing, or resolution of
|
||||
* relations.
|
||||
*
|
||||
* It stays around in the service for the time being, but may be
|
||||
* removed or change semantics at any time without prior notice.
|
||||
*/
|
||||
const body = await requireRequestBody(req);
|
||||
const [result] = await entitiesCatalog.batchAddOrUpdateEntities([
|
||||
{ entity: body as Entity, relations: [] },
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# @backstage/plugin-catalog-import
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a8953a9c9: This updates the `catalog-import` plugin to omit the default metadata namespace
|
||||
field and also use the short form entity reference format for selected group owners.
|
||||
- 968b588f7: Allows the CodeOwnersProcessor to set the owner automatically within the catalog-import plugin. This adds an additional checkbox that overrides the group selector and will omit the owner option in the generated catalog file yaml.
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-import",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,11 +30,11 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/catalog-client": "^0.3.6",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/integration": "^0.5.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -51,9 +51,9 @@
|
||||
"yaml": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/react-hooks": "^3.3.0",
|
||||
|
||||
@@ -15,7 +15,15 @@
|
||||
*/
|
||||
|
||||
import { ConfigApi } from '@backstage/core';
|
||||
import { Box, StepLabel, TextField, Typography } from '@material-ui/core';
|
||||
import {
|
||||
Box,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
FormHelperText,
|
||||
StepLabel,
|
||||
TextField,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { BackButton } from '../Buttons';
|
||||
import { StepFinishImportLocation } from '../StepFinishImportLocation';
|
||||
@@ -167,6 +175,7 @@ export function defaultGenerateStepper(
|
||||
defaultTitle={title}
|
||||
defaultBody={body}
|
||||
renderFormFields={({
|
||||
values,
|
||||
control,
|
||||
errors,
|
||||
groupsLoading,
|
||||
@@ -219,22 +228,47 @@ export function defaultGenerateStepper(
|
||||
required
|
||||
/>
|
||||
|
||||
<AutocompleteTextField
|
||||
name="owner"
|
||||
control={control}
|
||||
errors={errors}
|
||||
options={groups || []}
|
||||
loading={groupsLoading}
|
||||
loadingText="Loading groups…"
|
||||
helperText="Select an owner from the list or enter a reference to a Group or a User"
|
||||
errorHelperText="required value"
|
||||
textFieldProps={{
|
||||
label: 'Entity Owner',
|
||||
placeholder: 'Group:default/my-group',
|
||||
}}
|
||||
rules={{ required: true }}
|
||||
required
|
||||
{!values.useCodeowners && (
|
||||
<AutocompleteTextField
|
||||
name="owner"
|
||||
control={control}
|
||||
errors={errors}
|
||||
options={groups || []}
|
||||
loading={groupsLoading}
|
||||
loadingText="Loading groups…"
|
||||
helperText="Select an owner from the list or enter a reference to a Group or a User"
|
||||
errorHelperText="required value"
|
||||
textFieldProps={{
|
||||
label: 'Entity Owner',
|
||||
placeholder: 'my-group',
|
||||
}}
|
||||
rules={{ required: true }}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
name="useCodeowners"
|
||||
inputRef={register}
|
||||
onChange={(_, value) => {
|
||||
if (value) {
|
||||
control.setValue('owner', '');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<>
|
||||
Use <em>CODEOWNERS</em> file as Entity Owner
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<FormHelperText>
|
||||
WARNING: This may fail is no CODEOWNERS file is found at
|
||||
the target location.
|
||||
</FormHelperText>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
|
||||
+46
-2
@@ -21,7 +21,10 @@ import { act, render, RenderResult } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { AnalyzeResult, catalogImportApiRef } from '../../api';
|
||||
import { StepPrepareCreatePullRequest } from './StepPrepareCreatePullRequest';
|
||||
import {
|
||||
generateEntities,
|
||||
StepPrepareCreatePullRequest,
|
||||
} from './StepPrepareCreatePullRequest';
|
||||
|
||||
describe('<StepPrepareCreatePullRequest />', () => {
|
||||
const catalogImportApi: jest.Mocked<typeof catalogImportApiRef.T> = {
|
||||
@@ -60,6 +63,7 @@ describe('<StepPrepareCreatePullRequest />', () => {
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'my-component',
|
||||
namespace: 'default',
|
||||
},
|
||||
spec: {
|
||||
owner: 'my-owner',
|
||||
@@ -282,6 +286,46 @@ spec:
|
||||
renderFormFieldsFn.mock.calls[
|
||||
renderFormFieldsFn.mock.calls.length - 1
|
||||
][0],
|
||||
).toMatchObject({ groups: ['Group:my-group'], groupsLoading: false });
|
||||
).toMatchObject({ groups: ['my-group'], groupsLoading: false });
|
||||
});
|
||||
|
||||
describe('generateEntities', () => {
|
||||
it.each([[undefined], [null]])(
|
||||
'should not include blank namespace for %s',
|
||||
namespace => {
|
||||
expect(
|
||||
generateEntities(
|
||||
[{ metadata: { namespace: namespace as any } }],
|
||||
'my-component',
|
||||
'group-1',
|
||||
),
|
||||
).toEqual([
|
||||
expect.objectContaining({
|
||||
metadata: expect.not.objectContaining({
|
||||
namespace: 'default',
|
||||
}),
|
||||
}),
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([['default'], ['my-namespace']])(
|
||||
'should include explicit namespace %s',
|
||||
namespace => {
|
||||
expect(
|
||||
generateEntities(
|
||||
[{ metadata: { namespace } }],
|
||||
'my-component',
|
||||
'group-1',
|
||||
),
|
||||
).toEqual([
|
||||
expect.objectContaining({
|
||||
metadata: expect.objectContaining({
|
||||
namespace,
|
||||
}),
|
||||
}),
|
||||
]);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+16
-9
@@ -14,13 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity, serializeEntityRef } from '@backstage/catalog-model';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { useApi } from '@backstage/core';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
catalogApiRef,
|
||||
formatEntityRefTitle,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { Box, FormHelperText, Grid, Typography } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { UseFormMethods } from 'react-hook-form';
|
||||
import { UnpackNestedValue, UseFormMethods } from 'react-hook-form';
|
||||
import { useAsync } from 'react-use';
|
||||
import YAML from 'yaml';
|
||||
import { AnalyzeResult, catalogImportApiRef } from '../../api';
|
||||
@@ -45,6 +48,7 @@ type FormData = {
|
||||
body: string;
|
||||
componentName: string;
|
||||
owner: string;
|
||||
useCodeowners: boolean;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -60,16 +64,17 @@ type Props = {
|
||||
|
||||
renderFormFields: (
|
||||
props: Pick<UseFormMethods<FormData>, 'errors' | 'register' | 'control'> & {
|
||||
values: UnpackNestedValue<FormData>;
|
||||
groups: string[];
|
||||
groupsLoading: boolean;
|
||||
},
|
||||
) => React.ReactNode;
|
||||
};
|
||||
|
||||
function generateEntities(
|
||||
export function generateEntities(
|
||||
entities: PartialEntity[],
|
||||
componentName: string,
|
||||
owner: string,
|
||||
owner?: string,
|
||||
): Entity[] {
|
||||
return entities.map(e => ({
|
||||
...e,
|
||||
@@ -78,11 +83,10 @@ function generateEntities(
|
||||
metadata: {
|
||||
...e.metadata,
|
||||
name: componentName,
|
||||
namespace: e.metadata?.namespace ?? 'default',
|
||||
},
|
||||
spec: {
|
||||
...e.spec,
|
||||
owner,
|
||||
...(owner ? { owner } : {}),
|
||||
},
|
||||
}));
|
||||
}
|
||||
@@ -107,8 +111,9 @@ export const StepPrepareCreatePullRequest = ({
|
||||
filter: { kind: 'group' },
|
||||
});
|
||||
|
||||
// TODO: defaultKind (=group), defaultNamespace (=same as entity)
|
||||
return groupEntities.items.map(e => serializeEntityRef(e) as string).sort();
|
||||
return groupEntities.items
|
||||
.map(e => formatEntityRefTitle(e, { defaultKind: 'group' }))
|
||||
.sort();
|
||||
});
|
||||
|
||||
const handleResult = useCallback(
|
||||
@@ -186,10 +191,12 @@ export const StepPrepareCreatePullRequest = ({
|
||||
(analyzeResult.generatedEntities[0]?.spec?.owner as string) || '',
|
||||
componentName:
|
||||
analyzeResult.generatedEntities[0]?.metadata?.name || '',
|
||||
useCodeowners: false,
|
||||
}}
|
||||
render={({ values, errors, control, register }) => (
|
||||
<>
|
||||
{renderFormFields({
|
||||
values,
|
||||
errors,
|
||||
register,
|
||||
control,
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# @backstage/plugin-catalog-react
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- d0760ecdf: Moved common useStarredEntities hook to plugin-catalog-react
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 88f1f1b60: Truncate and show ellipsis with tooltip if content of
|
||||
`createMetadataDescriptionColumn` is too wide.
|
||||
- 9615e68fb: Forward link styling of `EntityRefLink` and `EnriryRefLinks` into the underling
|
||||
`Link`.
|
||||
- 5c2e2863f: Added the proper type parameters to entityRouteRef.
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-react",
|
||||
"version": "0.0.4",
|
||||
"version": "0.1.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,8 +29,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-client": "^0.3.6",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@types/react": "^16.9",
|
||||
"react": "^16.13.1",
|
||||
@@ -39,9 +39,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/react-hooks": "^3.3.0",
|
||||
|
||||
@@ -26,7 +26,7 @@ export const EntityProvider = ({ entity, children }: EntityProviderProps) => (
|
||||
<EntityContext.Provider
|
||||
value={{
|
||||
entity,
|
||||
loading: Boolean(entity),
|
||||
loading: !Boolean(entity),
|
||||
error: undefined,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
RELATION_OWNED_BY,
|
||||
RELATION_PART_OF,
|
||||
} from '@backstage/catalog-model';
|
||||
import { TableColumn } from '@backstage/core';
|
||||
import { OverflowTooltip, TableColumn } from '@backstage/core';
|
||||
import React from 'react';
|
||||
import { getEntityRelations } from '../../utils';
|
||||
import {
|
||||
@@ -139,6 +139,12 @@ export function createMetadataDescriptionColumn<
|
||||
return {
|
||||
title: 'Description',
|
||||
field: 'metadata.description',
|
||||
render: entity => (
|
||||
<OverflowTooltip
|
||||
text={entity.metadata.description}
|
||||
placement="bottom-start"
|
||||
/>
|
||||
),
|
||||
width: 'auto',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ describe('systemEntityColumns', () => {
|
||||
expect(getByText('my-namespace/my-system')).toBeInTheDocument();
|
||||
expect(getByText('my-namespace/my-domain')).toBeInTheDocument();
|
||||
expect(getByText('Test')).toBeInTheDocument();
|
||||
expect(getByText('Some description')).toBeInTheDocument();
|
||||
expect(getByText(/Some/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -131,7 +131,7 @@ describe('componentEntityColumns', () => {
|
||||
expect(getByText('Test')).toBeInTheDocument();
|
||||
expect(getByText('production')).toBeInTheDocument();
|
||||
expect(getByText('service')).toBeInTheDocument();
|
||||
expect(getByText('Some description')).toBeInTheDocument();
|
||||
expect(getByText(/Some/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,3 +16,4 @@
|
||||
export { EntityContext, useEntity, useEntityFromUrl } from './useEntity';
|
||||
export { useEntityCompoundName } from './useEntityCompoundName';
|
||||
export { useRelatedEntities } from './useRelatedEntities';
|
||||
export { useStarredEntities } from './useStarredEntities';
|
||||
|
||||
@@ -31,6 +31,7 @@ export const entityRoute = createRouteRef({
|
||||
icon: NoIcon,
|
||||
path: ':namespace/:kind/:name/*',
|
||||
title: 'Entity',
|
||||
params: ['namespace', 'kind', 'name'],
|
||||
});
|
||||
export const entityRouteRef = entityRoute;
|
||||
|
||||
|
||||
@@ -1,5 +1,70 @@
|
||||
# @backstage/plugin-catalog
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- a5f42cf66: The Scaffolder and Catalog plugins have been migrated to partially require use of the [new composability API](https://backstage.io/docs/plugins/composability). The Scaffolder used to register its pages using the deprecated route registration plugin API, but those registrations have been removed. This means you now need to add the Scaffolder plugin page to the app directly.
|
||||
|
||||
The page is imported from the Scaffolder plugin and added to the `<FlatRoutes>` component:
|
||||
|
||||
```tsx
|
||||
<Route path="/create" element={<ScaffolderPage />} />
|
||||
```
|
||||
|
||||
The Catalog plugin has also been migrated to use an [external route reference](https://backstage.io/docs/plugins/composability#binding-external-routes-in-the-app) to dynamically link to the create component page. This means you need to migrate the catalog plugin to use the new extension components, as well as bind the external route.
|
||||
|
||||
To use the new extension components, replace existing usage of the `CatalogRouter` with the following:
|
||||
|
||||
```tsx
|
||||
<Route path="/catalog" element={<CatalogIndexPage />} />
|
||||
<Route path="/catalog/:namespace/:kind/:name" element={<CatalogEntityPage />}>
|
||||
<EntityPage />
|
||||
</Route>
|
||||
```
|
||||
|
||||
And to bind the external route from the catalog plugin to the scaffolder template index page, make sure you have the appropriate imports and add the following to the `createApp` call:
|
||||
|
||||
```ts
|
||||
import { catalogPlugin } from '@backstage/plugin-catalog';
|
||||
import { scaffolderPlugin } from '@backstage/plugin-scaffolder';
|
||||
|
||||
const app = createApp({
|
||||
// ...
|
||||
bindRoutes({ bind }) {
|
||||
bind(catalogPlugin.externalRoutes, {
|
||||
createComponent: scaffolderPlugin.routes.root,
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
- d0760ecdf: Moved common useStarredEntities hook to plugin-catalog-react
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d6593abe6: Remove domain column from `HasSystemsCard` and system from `HasComponentsCard`,
|
||||
`HasSubcomponentsCard`, and `HasApisCard`.
|
||||
- bad21a085: Implement annotations for customising Entity URLs in the Catalog pages.
|
||||
- 437bac549: Make the description column in the catalog table and api-docs table use up as
|
||||
much space as possible before hiding overflowing text.
|
||||
- 5469a9761: Changes made in CatalogTable and ApiExplorerTable for using the OverflowTooltip component for truncating large description and showing tooltip on hover-over.
|
||||
- 60d1bc3e7: Fix Japanese Good Morning
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog",
|
||||
"version": "0.3.2",
|
||||
"version": "0.4.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,9 +31,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-client": "^0.3.6",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -50,9 +50,9 @@
|
||||
"swr": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@microsoft/microsoft-graph-types": "^1.25.0",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
SOURCE_LOCATION_ANNOTATION,
|
||||
EDIT_URL_ANNOTATION,
|
||||
} from '@backstage/catalog-model';
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { AboutCard } from './AboutCard';
|
||||
@@ -123,3 +127,41 @@ describe('<AboutCard /> BitBucket', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('<AboutCard /> custom links', () => {
|
||||
it('renders info and "view source" link', () => {
|
||||
const entity = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'software',
|
||||
annotations: {
|
||||
'backstage.io/managed-by-location':
|
||||
'bitbucket:https://bitbucket.org/backstage/backstage/src/master/software.yaml',
|
||||
[EDIT_URL_ANNOTATION]: 'https://another.place',
|
||||
[SOURCE_LOCATION_ANNOTATION]:
|
||||
'url:https://another.place/backstage.git',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
owner: 'guest',
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
},
|
||||
};
|
||||
const { getByText } = render(
|
||||
<EntityProvider entity={entity}>
|
||||
<AboutCard />
|
||||
</EntityProvider>,
|
||||
);
|
||||
expect(getByText('service')).toBeInTheDocument();
|
||||
expect(getByText('View Source').closest('a')).toHaveAttribute(
|
||||
'href',
|
||||
'https://another.place/backstage.git',
|
||||
);
|
||||
expect(getByText('View Source').closest('a')).toHaveAttribute(
|
||||
'edithref',
|
||||
'https://another.place',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
import {
|
||||
Entity,
|
||||
LocationSpec,
|
||||
ENTITY_DEFAULT_NAMESPACE,
|
||||
SOURCE_LOCATION_ANNOTATION,
|
||||
RELATION_PROVIDES_API,
|
||||
} from '@backstage/catalog-model';
|
||||
import { HeaderIconLinkRow } from '@backstage/core';
|
||||
@@ -34,8 +36,8 @@ import EditIcon from '@material-ui/icons/Edit';
|
||||
import ExtensionIcon from '@material-ui/icons/Extension';
|
||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
||||
import React from 'react';
|
||||
import { findLocationForEntityMeta } from '../../data/utils';
|
||||
import { createEditLink, determineUrlType } from '../createEditLink';
|
||||
import { findLocationForEntityMeta, parseLocation } from '../../data/utils';
|
||||
import { findEditUrl, determineUrlType } from '../actions';
|
||||
import { AboutContent } from './AboutContent';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
@@ -60,20 +62,35 @@ type CodeLinkInfo = {
|
||||
href?: string;
|
||||
};
|
||||
|
||||
function getSourceLocationForEntity(
|
||||
entity: Entity,
|
||||
location?: LocationSpec,
|
||||
): LocationSpec | undefined {
|
||||
const annotation = entity.metadata?.annotations?.[SOURCE_LOCATION_ANNOTATION];
|
||||
const parsed = annotation && parseLocation(annotation);
|
||||
|
||||
return parsed || location;
|
||||
}
|
||||
|
||||
function getCodeLinkInfo(entity: Entity): CodeLinkInfo {
|
||||
const location = findLocationForEntityMeta(entity?.metadata);
|
||||
const editUrl = findEditUrl(entity);
|
||||
let sourceLocation = getSourceLocationForEntity(entity, location);
|
||||
|
||||
if (location) {
|
||||
sourceLocation = sourceLocation || location;
|
||||
const type =
|
||||
location.type === 'url'
|
||||
? determineUrlType(location.target)
|
||||
: location.type;
|
||||
sourceLocation.type === 'url'
|
||||
? determineUrlType(sourceLocation.target)
|
||||
: sourceLocation.type;
|
||||
return {
|
||||
edithref: editUrl,
|
||||
icon: iconMap[type],
|
||||
edithref: createEditLink(location),
|
||||
href: location.target,
|
||||
href: sourceLocation.target,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
|
||||
return { edithref: editUrl, href: sourceLocation?.target };
|
||||
}
|
||||
|
||||
type AboutCardProps = {
|
||||
|
||||
@@ -23,14 +23,18 @@ import {
|
||||
useApi,
|
||||
useRouteRef,
|
||||
} from '@backstage/core';
|
||||
import { catalogApiRef, isOwnerOf } from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
catalogApiRef,
|
||||
isOwnerOf,
|
||||
useStarredEntities,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
|
||||
import { Button, makeStyles } from '@material-ui/core';
|
||||
import SettingsIcon from '@material-ui/icons/Settings';
|
||||
import StarIcon from '@material-ui/icons/Star';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { EntityFilterGroupsProvider, useFilteredEntities } from '../../filter';
|
||||
import { useStarredEntities } from '../../hooks/useStarredEntities';
|
||||
import { createComponentRouteRef } from '../../routes';
|
||||
import {
|
||||
ButtonGroup,
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"Indonesian": "Selamat pagi",
|
||||
"Irish": "Dia dhuit",
|
||||
"Italian": "Buongiorno",
|
||||
"Japanese": "お早う",
|
||||
"Japanese": "おはよう",
|
||||
"Korean": "안녕하세요",
|
||||
"Kazakh": "Kayırlı tan",
|
||||
"Kurdish": "Beyanî baş",
|
||||
|
||||
@@ -14,7 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import {
|
||||
Entity,
|
||||
VIEW_URL_ANNOTATION,
|
||||
EDIT_URL_ANNOTATION,
|
||||
} from '@backstage/catalog-model';
|
||||
import { act, fireEvent } from '@testing-library/react';
|
||||
import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils';
|
||||
import * as React from 'react';
|
||||
import { CatalogTable } from './CatalogTable';
|
||||
@@ -38,6 +43,14 @@ const entities: Entity[] = [
|
||||
];
|
||||
|
||||
describe('CatalogTable component', () => {
|
||||
beforeEach(() => {
|
||||
window.open = jest.fn();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should render error message when error is passed in props', async () => {
|
||||
const rendered = await renderWithEffects(
|
||||
wrapInTestApp(
|
||||
@@ -70,4 +83,62 @@ describe('CatalogTable component', () => {
|
||||
expect(rendered.getByText(/component2/)).toBeInTheDocument();
|
||||
expect(rendered.getByText(/component3/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should use specified edit URL if in annotation', async () => {
|
||||
const entity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'component1',
|
||||
annotations: { [EDIT_URL_ANNOTATION]: 'https://other.place' },
|
||||
},
|
||||
};
|
||||
|
||||
const { getByTitle } = await renderWithEffects(
|
||||
wrapInTestApp(
|
||||
<CatalogTable
|
||||
titlePreamble="Owned"
|
||||
entities={[entity]}
|
||||
loading={false}
|
||||
/>,
|
||||
),
|
||||
);
|
||||
|
||||
const editButton = getByTitle('Edit');
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(editButton);
|
||||
});
|
||||
|
||||
expect(window.open).toHaveBeenCalledWith('https://other.place', '_blank');
|
||||
});
|
||||
|
||||
it('should use specified view URL if in annotation', async () => {
|
||||
const entity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'component1',
|
||||
annotations: { [VIEW_URL_ANNOTATION]: 'https://other.place' },
|
||||
},
|
||||
};
|
||||
|
||||
const { getByTitle } = await renderWithEffects(
|
||||
wrapInTestApp(
|
||||
<CatalogTable
|
||||
titlePreamble="Owned"
|
||||
entities={[entity]}
|
||||
loading={false}
|
||||
/>,
|
||||
),
|
||||
);
|
||||
|
||||
const viewButton = getByTitle('View');
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(viewButton);
|
||||
});
|
||||
|
||||
expect(window.open).toHaveBeenCalledWith('https://other.place', '_blank');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,14 +32,13 @@ import {
|
||||
EntityRefLinks,
|
||||
formatEntityRefTitle,
|
||||
getEntityRelations,
|
||||
useStarredEntities,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { Chip } from '@material-ui/core';
|
||||
import Edit from '@material-ui/icons/Edit';
|
||||
import OpenInNew from '@material-ui/icons/OpenInNew';
|
||||
import React from 'react';
|
||||
import { findLocationForEntityMeta } from '../../data/utils';
|
||||
import { useStarredEntities } from '../../hooks/useStarredEntities';
|
||||
import { createEditLink } from '../createEditLink';
|
||||
import { findViewUrl, findEditUrl } from '../actions';
|
||||
import {
|
||||
favouriteEntityIcon,
|
||||
favouriteEntityTooltip,
|
||||
@@ -98,6 +97,7 @@ const columns: TableColumn<EntityRow>[] = [
|
||||
placement="bottom-start"
|
||||
/>
|
||||
),
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
title: 'Tags',
|
||||
@@ -152,24 +152,24 @@ export const CatalogTable = ({
|
||||
|
||||
const actions: TableProps<EntityRow>['actions'] = [
|
||||
({ entity }) => {
|
||||
const location = findLocationForEntityMeta(entity.metadata);
|
||||
const url = findViewUrl(entity);
|
||||
return {
|
||||
icon: () => <OpenInNew fontSize="small" />,
|
||||
tooltip: 'View',
|
||||
onClick: () => {
|
||||
if (!location) return;
|
||||
window.open(location.target, '_blank');
|
||||
if (!url) return;
|
||||
window.open(url, '_blank');
|
||||
},
|
||||
};
|
||||
},
|
||||
({ entity }) => {
|
||||
const location = findLocationForEntityMeta(entity.metadata);
|
||||
const url = findEditUrl(entity);
|
||||
return {
|
||||
icon: () => <Edit fontSize="small" />,
|
||||
tooltip: 'Edit',
|
||||
onClick: () => {
|
||||
if (!location) return;
|
||||
window.open(createEditLink(location), '_blank');
|
||||
if (!url) return;
|
||||
window.open(url, '_blank');
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
|
||||
import React, { ComponentProps } from 'react';
|
||||
import { useStarredEntities } from '@backstage/plugin-catalog-react';
|
||||
import { IconButton, Tooltip, withStyles } from '@material-ui/core';
|
||||
import StarBorder from '@material-ui/icons/StarBorder';
|
||||
import Star from '@material-ui/icons/Star';
|
||||
import { useStarredEntities } from '../../hooks/useStarredEntities';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
type Props = ComponentProps<typeof IconButton> & { entity: Entity };
|
||||
|
||||
@@ -33,6 +33,14 @@ type Props = {
|
||||
variant?: 'gridItem';
|
||||
};
|
||||
|
||||
const columns = [
|
||||
EntityTable.columns.createEntityRefColumn({ defaultKind: 'component' }),
|
||||
EntityTable.columns.createOwnerColumn(),
|
||||
EntityTable.columns.createSpecTypeColumn(),
|
||||
EntityTable.columns.createSpecLifecycleColumn(),
|
||||
EntityTable.columns.createMetadataDescriptionColumn(),
|
||||
];
|
||||
|
||||
export const HasComponentsCard = ({ variant = 'gridItem' }: Props) => {
|
||||
const { entity } = useEntity();
|
||||
const { entities, loading, error } = useRelatedEntities(entity, {
|
||||
@@ -72,7 +80,7 @@ export const HasComponentsCard = ({ variant = 'gridItem' }: Props) => {
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
columns={EntityTable.componentEntityColumns}
|
||||
columns={columns}
|
||||
entities={entities as ComponentEntity[]}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -33,6 +33,14 @@ type Props = {
|
||||
variant?: 'gridItem';
|
||||
};
|
||||
|
||||
const columns = [
|
||||
EntityTable.columns.createEntityRefColumn({ defaultKind: 'component' }),
|
||||
EntityTable.columns.createOwnerColumn(),
|
||||
EntityTable.columns.createSpecTypeColumn(),
|
||||
EntityTable.columns.createSpecLifecycleColumn(),
|
||||
EntityTable.columns.createMetadataDescriptionColumn(),
|
||||
];
|
||||
|
||||
export const HasSubcomponentsCard = ({ variant = 'gridItem' }: Props) => {
|
||||
const { entity } = useEntity();
|
||||
const { entities, loading, error } = useRelatedEntities(entity, {
|
||||
@@ -72,7 +80,7 @@ export const HasSubcomponentsCard = ({ variant = 'gridItem' }: Props) => {
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
columns={EntityTable.componentEntityColumns}
|
||||
columns={columns}
|
||||
entities={entities as ComponentEntity[]}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -33,6 +33,12 @@ type Props = {
|
||||
variant?: 'gridItem';
|
||||
};
|
||||
|
||||
const columns = [
|
||||
EntityTable.columns.createEntityRefColumn({ defaultKind: 'system' }),
|
||||
EntityTable.columns.createOwnerColumn(),
|
||||
EntityTable.columns.createMetadataDescriptionColumn(),
|
||||
];
|
||||
|
||||
export const HasSystemsCard = ({ variant = 'gridItem' }: Props) => {
|
||||
const { entity } = useEntity();
|
||||
const { entities, loading, error } = useRelatedEntities(entity, {
|
||||
@@ -71,7 +77,7 @@ export const HasSystemsCard = ({ variant = 'gridItem' }: Props) => {
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
columns={EntityTable.systemEntityColumns}
|
||||
columns={columns}
|
||||
entities={entities as SystemEntity[]}
|
||||
/>
|
||||
);
|
||||
|
||||
+26
-1
@@ -14,7 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { LocationSpec } from '@backstage/catalog-model';
|
||||
import {
|
||||
LocationSpec,
|
||||
Entity,
|
||||
EDIT_URL_ANNOTATION,
|
||||
VIEW_URL_ANNOTATION,
|
||||
} from '@backstage/catalog-model';
|
||||
import { findLocationForEntityMeta } from '../data/utils';
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
|
||||
/**
|
||||
@@ -75,3 +81,22 @@ export const determineUrlType = (url: string): string => {
|
||||
}
|
||||
return 'url';
|
||||
};
|
||||
|
||||
export const findEditUrl = ({ metadata }: Entity): string | undefined => {
|
||||
const annotations = metadata.annotations || {};
|
||||
|
||||
const editUrl = annotations[EDIT_URL_ANNOTATION];
|
||||
|
||||
if (editUrl) return editUrl;
|
||||
|
||||
const location = findLocationForEntityMeta(metadata);
|
||||
|
||||
return location && createEditLink(location);
|
||||
};
|
||||
|
||||
export const findViewUrl = ({ metadata }: Entity): string | undefined => {
|
||||
const annotations = metadata.annotations || {};
|
||||
const location = findLocationForEntityMeta(metadata);
|
||||
|
||||
return annotations[VIEW_URL_ANNOTATION] || location?.target;
|
||||
};
|
||||
@@ -32,13 +32,17 @@ export function findLocationForEntityMeta(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const separatorIndex = annotation.indexOf(':');
|
||||
return parseLocation(annotation);
|
||||
}
|
||||
|
||||
export function parseLocation(reference: string): LocationSpec | undefined {
|
||||
const separatorIndex = reference.indexOf(':');
|
||||
if (separatorIndex === -1) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
type: annotation.substring(0, separatorIndex),
|
||||
target: annotation.substring(separatorIndex + 1),
|
||||
type: reference.substring(0, separatorIndex),
|
||||
target: reference.substring(separatorIndex + 1),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* 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 React, { PropsWithChildren } from 'react';
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import { useStarredEntities } from './useStarredEntities';
|
||||
import {
|
||||
ApiProvider,
|
||||
ApiRegistry,
|
||||
storageApiRef,
|
||||
WebStorage,
|
||||
StorageApi,
|
||||
} from '@backstage/core';
|
||||
import { MockErrorApi } from '@backstage/test-utils';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
describe('useStarredEntities', () => {
|
||||
let mockStorage: StorageApi | undefined;
|
||||
|
||||
const mockEntity: Entity = {
|
||||
apiVersion: '1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'mock',
|
||||
},
|
||||
};
|
||||
|
||||
const secondMockEntity: Entity = {
|
||||
apiVersion: '1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
namespace: 'test',
|
||||
name: 'mock2',
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
return (
|
||||
<ApiProvider apis={ApiRegistry.with(storageApiRef, mockStorage)}>
|
||||
{children}
|
||||
</ApiProvider>
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockStorage = new WebStorage('@backstage', new MockErrorApi()).forBucket(
|
||||
Date.now().toString(), // TODO(blam): need something that changes every test run for now until the MockStorage is implemented
|
||||
);
|
||||
});
|
||||
it('should return an empty set for when there is no items in storage', async () => {
|
||||
const { result } = renderHook(() => useStarredEntities(), { wrapper });
|
||||
|
||||
expect(result.current.starredEntities.size).toBe(0);
|
||||
});
|
||||
it('should return a set with the current items when there is items in storage', async () => {
|
||||
const expectedIds = ['i', 'am', 'some', 'test', 'ids'];
|
||||
const store = mockStorage?.forBucket('settings');
|
||||
await store?.set('starredEntities', expectedIds);
|
||||
|
||||
const { result } = renderHook(() => useStarredEntities(), { wrapper });
|
||||
|
||||
for (const item of expectedIds) {
|
||||
expect(result.current.starredEntities.has(item)).toBeTruthy();
|
||||
}
|
||||
});
|
||||
it('should listen to changes when the storage is set elsewhere', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(
|
||||
() => useStarredEntities(),
|
||||
{ wrapper },
|
||||
);
|
||||
|
||||
expect(result.current.starredEntities.size).toBe(0);
|
||||
expect(result.current.isStarredEntity(mockEntity)).toBeFalsy();
|
||||
|
||||
// Make this happen after awaiting for the next update so we can
|
||||
// catch when the hook re-renders with the latest data
|
||||
setTimeout(() => result.current.toggleStarredEntity(mockEntity), 1);
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.starredEntities.size).toBe(1);
|
||||
expect(result.current.isStarredEntity(mockEntity)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should write new entries to the local store when adding a togglging entity', async () => {
|
||||
const { result } = renderHook(() => useStarredEntities(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current.toggleStarredEntity(mockEntity);
|
||||
});
|
||||
|
||||
expect(result.current.isStarredEntity(mockEntity)).toBeTruthy();
|
||||
expect(result.current.isStarredEntity(secondMockEntity)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should remove an existing entity when toggling entries', async () => {
|
||||
const { result } = renderHook(() => useStarredEntities(), { wrapper });
|
||||
|
||||
act(() => {
|
||||
result.current.toggleStarredEntity(mockEntity);
|
||||
result.current.toggleStarredEntity(secondMockEntity);
|
||||
result.current.toggleStarredEntity(mockEntity);
|
||||
});
|
||||
|
||||
expect(result.current.isStarredEntity(mockEntity)).toBeFalsy();
|
||||
expect(result.current.isStarredEntity(secondMockEntity)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-circleci
|
||||
|
||||
## 0.2.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.2.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-circleci",
|
||||
"version": "0.2.9",
|
||||
"version": "0.2.10",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,9 +31,9 @@
|
||||
"postpack": "backstage-cli postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -50,9 +50,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-cloudbuild
|
||||
|
||||
## 0.2.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.2.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-cloudbuild",
|
||||
"version": "0.2.10",
|
||||
"version": "0.2.11",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,9 +30,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -47,9 +47,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @backstage/plugin-cost-insights
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 38205492a: Default alert properties can be overridden using accessors
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-cost-insights",
|
||||
"version": "0.8.1",
|
||||
"version": "0.8.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,8 +30,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -55,9 +55,9 @@
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import pluralize from 'pluralize';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ProjectGrowthAlert } from './ProjectGrowthAlert';
|
||||
import { ProjectGrowthData } from '../types';
|
||||
import {
|
||||
MockCurrencyProvider,
|
||||
MockConfigProvider,
|
||||
MockBillingDateProvider,
|
||||
} from '../utils/tests';
|
||||
|
||||
const mockData: ProjectGrowthData = {
|
||||
project: 'test-project',
|
||||
periodStart: '2021-01-01',
|
||||
periodEnd: '2021-02-01',
|
||||
aggregation: [0, 0],
|
||||
change: {
|
||||
ratio: 0,
|
||||
amount: 0,
|
||||
},
|
||||
products: [
|
||||
{
|
||||
id: 'product-a',
|
||||
aggregation: [0, 0],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// suppress recharts componentDidUpdate deprecation warnings
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
|
||||
async function renderInContext(children: JSX.Element) {
|
||||
return renderInTestApp(
|
||||
<MockConfigProvider>
|
||||
<MockBillingDateProvider>
|
||||
<MockCurrencyProvider>{children}</MockCurrencyProvider>
|
||||
</MockBillingDateProvider>
|
||||
</MockConfigProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
class CustomProjectGrowthAlert extends ProjectGrowthAlert {
|
||||
get url() {
|
||||
return 'path/to/resource';
|
||||
}
|
||||
get title() {
|
||||
return `Investigate cost growth in ${pluralize(
|
||||
'project',
|
||||
this.data.products.length,
|
||||
true,
|
||||
)}`;
|
||||
}
|
||||
}
|
||||
|
||||
describe('ProjectGrowthAlert', () => {
|
||||
describe('constructor', () => {
|
||||
it('should create a project growth alert', async () => {
|
||||
const alert = new ProjectGrowthAlert(mockData);
|
||||
const { getByText, queryByText } = await renderInContext(alert.element);
|
||||
|
||||
expect(alert.url).toBe('/cost-insights/investigating-growth');
|
||||
expect(alert.title).toBe(
|
||||
'Investigate cost growth in project test-project',
|
||||
);
|
||||
expect(alert.subtitle).toBe(
|
||||
'Cost growth outpacing business growth is unsustainable long-term.',
|
||||
);
|
||||
expect(getByText('1 product')).toBeInTheDocument();
|
||||
expect(queryByText('sorted by cost')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('a subclass can inherit and override defaults using accessors', async () => {
|
||||
const alert = new CustomProjectGrowthAlert(mockData);
|
||||
const { getByText, queryByText } = await renderInContext(alert.element);
|
||||
|
||||
expect(alert.url).toBe('path/to/resource');
|
||||
expect(alert.title).toBe('Investigate cost growth in 1 project');
|
||||
expect(alert.subtitle).toBe(
|
||||
'Cost growth outpacing business growth is unsustainable long-term.',
|
||||
);
|
||||
expect(getByText('1 product')).toBeInTheDocument();
|
||||
expect(queryByText('sorted by cost')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -27,18 +27,22 @@ import { Alert, ProjectGrowthData } from '../types';
|
||||
export class ProjectGrowthAlert implements Alert {
|
||||
data: ProjectGrowthData;
|
||||
|
||||
url = '/cost-insights/investigating-growth';
|
||||
subtitle =
|
||||
'Cost growth outpacing business growth is unsustainable long-term.';
|
||||
|
||||
constructor(data: ProjectGrowthData) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
get url() {
|
||||
return '/cost-insights/investigating-growth';
|
||||
}
|
||||
|
||||
get title() {
|
||||
return `Investigate cost growth in project ${this.data.project}`;
|
||||
}
|
||||
|
||||
get subtitle() {
|
||||
return 'Cost growth outpacing business growth is unsustainable long-term.';
|
||||
}
|
||||
|
||||
get element() {
|
||||
return <ProjectGrowthAlertCard alert={this.data} />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import pluralize from 'pluralize';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { UnlabeledDataflowAlert } from './UnlabeledDataflowAlert';
|
||||
import { UnlabeledDataflowData } from '../types';
|
||||
import {
|
||||
MockCurrencyProvider,
|
||||
MockConfigProvider,
|
||||
MockBillingDateProvider,
|
||||
} from '../utils/tests';
|
||||
|
||||
const mockData: UnlabeledDataflowData = {
|
||||
periodStart: '2021-02-01',
|
||||
periodEnd: '2021-03-31',
|
||||
unlabeledCost: 0,
|
||||
labeledCost: 0,
|
||||
projects: [
|
||||
{
|
||||
id: 'project-a',
|
||||
labeledCost: 0,
|
||||
unlabeledCost: 0,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// suppress recharts componentDidUpdate deprecation warnings
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
|
||||
async function renderInContext(children: JSX.Element) {
|
||||
return renderInTestApp(
|
||||
<MockConfigProvider>
|
||||
<MockBillingDateProvider>
|
||||
<MockCurrencyProvider>{children}</MockCurrencyProvider>
|
||||
</MockBillingDateProvider>
|
||||
</MockConfigProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
class CustomUnlabeledDataflowAlert extends UnlabeledDataflowAlert {
|
||||
get url() {
|
||||
return 'path/to/resource';
|
||||
}
|
||||
get title() {
|
||||
return `Add labels to ${pluralize(
|
||||
'workflow',
|
||||
this.data.projects.length,
|
||||
true,
|
||||
)}`;
|
||||
}
|
||||
}
|
||||
|
||||
describe('UnlabeledDataflowAlert', () => {
|
||||
describe('constructor', () => {
|
||||
it('should create an unlabeled dataflow alert', async () => {
|
||||
const alert = new UnlabeledDataflowAlert(mockData);
|
||||
const { getByText } = await renderInContext(alert.element);
|
||||
|
||||
expect(alert.url).toBe('/cost-insights/labeling-jobs');
|
||||
expect(alert.title).toBe('Add labels to workflows');
|
||||
expect(alert.subtitle).toBe(
|
||||
'Labels show in billing data, enabling cost insights for each workflow.',
|
||||
);
|
||||
expect(
|
||||
getByText(
|
||||
'Showing costs from 1 project with unlabeled Dataflow jobs in the last 30 days.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('a subclass can inherit and override defaults using accessors', async () => {
|
||||
const alert = new CustomUnlabeledDataflowAlert(mockData);
|
||||
const { getByText } = await renderInContext(alert.element);
|
||||
|
||||
expect(alert.url).toBe('path/to/resource');
|
||||
expect(alert.title).toBe('Add labels to 1 workflow');
|
||||
expect(alert.subtitle).toBe(
|
||||
'Labels show in billing data, enabling cost insights for each workflow.',
|
||||
);
|
||||
expect(
|
||||
getByText(
|
||||
'Showing costs from 1 project with unlabeled Dataflow jobs in the last 30 days.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -28,15 +28,22 @@ export class UnlabeledDataflowAlert implements Alert {
|
||||
data: UnlabeledDataflowData;
|
||||
status?: AlertStatus;
|
||||
|
||||
url = '/cost-insights/labeling-jobs';
|
||||
title = 'Add labels to workflows';
|
||||
subtitle =
|
||||
'Labels show in billing data, enabling cost insights for each workflow.';
|
||||
|
||||
constructor(data: UnlabeledDataflowData) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
get url() {
|
||||
return '/cost-insights/labeling-jobs';
|
||||
}
|
||||
|
||||
get title() {
|
||||
return 'Add labels to workflows';
|
||||
}
|
||||
|
||||
get subtitle() {
|
||||
return 'Labels show in billing data, enabling cost insights for each workflow.';
|
||||
}
|
||||
|
||||
get element() {
|
||||
return <UnlabeledDataflowAlertCard alert={this.data} />;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @backstage/plugin-explore
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 347137ccf: Display the owner of a domain on the domain card.
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-explore",
|
||||
"version": "0.2.6",
|
||||
"version": "0.2.7",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,9 +30,9 @@
|
||||
"start": "backstage-cli plugin:serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/plugin-explore-react": "^0.0.2",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
@@ -45,9 +45,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-fossa
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-fossa",
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.3",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,9 +31,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -44,9 +44,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -41,9 +41,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-github-actions
|
||||
|
||||
## 0.3.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-github-actions",
|
||||
"version": "0.3.3",
|
||||
"version": "0.3.4",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -32,9 +32,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/integration": "^0.5.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
@@ -50,9 +50,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -42,9 +42,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -31,21 +31,21 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.45",
|
||||
"graphiql": "^1.0.0-alpha.10",
|
||||
"graphql": "15.4.0",
|
||||
"graphql": "15.5.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-jenkins
|
||||
|
||||
## 0.3.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.3.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -50,7 +50,7 @@ metadata:
|
||||
name: 'your-component'
|
||||
description: 'a description'
|
||||
annotations:
|
||||
jenkins.io/github-folder: 'folder-name/job-name'
|
||||
jenkins.io/github-folder: 'folder-name/project-name'
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
@@ -84,5 +84,5 @@ YWRtaW46MTFlYzI1NmU0Mzg1MDFjM2Y1Yzc2Yjc1MWE3ZTQ3YWY4Mw== is the base64 of user a
|
||||
|
||||
## Limitations
|
||||
|
||||
- Only works with organization folder jobs backed by GitHub
|
||||
- No pagination support currently, limited to 50 jobs - don't run this on a Jenkins with lots of builds
|
||||
- Only works with organization folder projects backed by GitHub
|
||||
- No pagination support currently, limited to 50 projects - don't run this on a Jenkins with lots of builds
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-jenkins",
|
||||
"version": "0.3.10",
|
||||
"version": "0.3.11",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,9 +31,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -47,9 +47,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 29 KiB |
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Content, Link } from '@backstage/core';
|
||||
import { Breadcrumbs, Content, Link } from '@backstage/core';
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Breadcrumbs,
|
||||
Paper,
|
||||
TableContainer,
|
||||
Table,
|
||||
@@ -36,7 +36,6 @@ import ExternalLinkIcon from '@material-ui/icons/Launch';
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
maxWidth: 720,
|
||||
margin: theme.spacing(2),
|
||||
},
|
||||
table: {
|
||||
padding: theme.spacing(1),
|
||||
@@ -57,9 +56,10 @@ const BuildWithStepsView = () => {
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Breadcrumbs aria-label="breadcrumb">
|
||||
<Link to="../../..">Jobs</Link>
|
||||
<Link to="../../..">Projects</Link>
|
||||
<Typography>Run</Typography>
|
||||
</Breadcrumbs>
|
||||
<Box m={2} />
|
||||
<TableContainer component={Paper} className={classes.table}>
|
||||
<Table>
|
||||
<TableBody>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import React from 'react';
|
||||
import { Box, IconButton, Link, Typography, Tooltip } from '@material-ui/core';
|
||||
import RetryIcon from '@material-ui/icons/Replay';
|
||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
||||
import JenkinsLogo from '../../../../assets/JenkinsLogo.svg';
|
||||
import { generatePath, Link as RouterLink } from 'react-router-dom';
|
||||
import { Table, TableColumn } from '@backstage/core';
|
||||
import { JenkinsRunStatus } from '../Status';
|
||||
@@ -231,9 +231,9 @@ export const CITableView = ({
|
||||
onChangeRowsPerPage={onChangePageSize}
|
||||
title={
|
||||
<Box display="flex" alignItems="center">
|
||||
<GitHubIcon />
|
||||
<Box mr={1} />
|
||||
<Typography variant="h6">{projectName}</Typography>
|
||||
<img src={JenkinsLogo} alt="Jenkins logo" height="50px" />
|
||||
<Box mr={2} />
|
||||
<Typography variant="h6">Project: {projectName}</Typography>
|
||||
</Box>
|
||||
}
|
||||
columns={generatedColumns}
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-kafka
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-kafka",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -20,9 +20,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -33,9 +33,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/react-hooks": "^3.4.2",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/plugin-kubernetes-backend
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a70af22a2: update kubernetes plugin backend function to use classes
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- @backstage/catalog-model@0.7.2
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-kubernetes-backend",
|
||||
"version": "0.2.6",
|
||||
"version": "0.2.7",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -33,8 +33,8 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/credential-provider-node": "^3.3.0",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@kubernetes/client-node": "^0.13.2",
|
||||
"@types/express": "^4.17.6",
|
||||
"aws4": "^1.11.0",
|
||||
@@ -51,7 +51,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@types/aws4": "^1.5.1",
|
||||
"supertest": "^4.0.2"
|
||||
},
|
||||
|
||||
+53
-55
@@ -14,11 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { handleGetKubernetesObjectsForService } from './getKubernetesObjectsForServiceHandler';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { ObjectFetchParams } from '..';
|
||||
|
||||
const TEST_SERVICE_ID = 'my-service';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
|
||||
const fetchObjectsForService = jest.fn();
|
||||
|
||||
@@ -81,34 +79,34 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
|
||||
mockFetch(fetchObjectsForService);
|
||||
|
||||
const result = await handleGetKubernetesObjectsForService(
|
||||
TEST_SERVICE_ID,
|
||||
const sut = new KubernetesFanOutHandler(
|
||||
getVoidLogger(),
|
||||
{
|
||||
fetchObjectsForService: fetchObjectsForService,
|
||||
fetchObjectsForService,
|
||||
},
|
||||
{
|
||||
getClustersByServiceId,
|
||||
},
|
||||
getVoidLogger(),
|
||||
{
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
);
|
||||
|
||||
const result = await sut.getKubernetesObjectsByEntity({
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
expect(getClustersByServiceId.mock.calls.length).toBe(1);
|
||||
expect(fetchObjectsForService.mock.calls.length).toBe(1);
|
||||
@@ -124,7 +122,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-my-service-test-cluster',
|
||||
name: 'my-pods-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -134,7 +132,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-my-service-test-cluster',
|
||||
name: 'my-configmaps-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -144,7 +142,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-my-service-test-cluster',
|
||||
name: 'my-services-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -172,37 +170,37 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
|
||||
mockFetch(fetchObjectsForService);
|
||||
|
||||
const result = await handleGetKubernetesObjectsForService(
|
||||
TEST_SERVICE_ID,
|
||||
const sut = new KubernetesFanOutHandler(
|
||||
getVoidLogger(),
|
||||
{
|
||||
fetchObjectsForService: fetchObjectsForService,
|
||||
fetchObjectsForService,
|
||||
},
|
||||
{
|
||||
getClustersByServiceId,
|
||||
},
|
||||
getVoidLogger(),
|
||||
{
|
||||
auth: {
|
||||
google: 'google_token_123',
|
||||
);
|
||||
|
||||
const result = await sut.getKubernetesObjectsByEntity({
|
||||
auth: {
|
||||
google: 'google_token_123',
|
||||
},
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test-component',
|
||||
annotations: {
|
||||
'backstage.io/kubernetes-labels-selector':
|
||||
'backstage.io/test-label=test-component',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
spec: {
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
owner: 'joe',
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
expect(getClustersByServiceId.mock.calls.length).toBe(1);
|
||||
expect(fetchObjectsForService.mock.calls.length).toBe(2);
|
||||
@@ -218,7 +216,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-my-service-test-cluster',
|
||||
name: 'my-pods-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -228,7 +226,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-my-service-test-cluster',
|
||||
name: 'my-configmaps-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -238,7 +236,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-my-service-test-cluster',
|
||||
name: 'my-services-test-component-test-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -256,7 +254,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-pods-my-service-other-cluster',
|
||||
name: 'my-pods-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -266,7 +264,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-configmaps-my-service-other-cluster',
|
||||
name: 'my-configmaps-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -276,7 +274,7 @@ describe('handleGetKubernetesObjectsForService', () => {
|
||||
resources: [
|
||||
{
|
||||
metadata: {
|
||||
name: 'my-services-my-service-other-cluster',
|
||||
name: 'my-services-test-component-other-cluster',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Logger } from 'winston';
|
||||
import {
|
||||
ClusterDetails,
|
||||
KubernetesFetcher,
|
||||
KubernetesObjectTypes,
|
||||
KubernetesRequestBody,
|
||||
KubernetesServiceLocator,
|
||||
} from '../types/types';
|
||||
import { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types';
|
||||
import { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator';
|
||||
|
||||
const DEFAULT_OBJECTS = new Set<KubernetesObjectTypes>([
|
||||
'pods',
|
||||
'services',
|
||||
'configmaps',
|
||||
'deployments',
|
||||
'replicasets',
|
||||
'horizontalpodautoscalers',
|
||||
'ingresses',
|
||||
]);
|
||||
|
||||
export class KubernetesFanOutHandler {
|
||||
private readonly logger: Logger;
|
||||
private readonly fetcher: KubernetesFetcher;
|
||||
private readonly serviceLocator: KubernetesServiceLocator;
|
||||
|
||||
constructor(
|
||||
logger: Logger,
|
||||
fetcher: KubernetesFetcher,
|
||||
serviceLocator: KubernetesServiceLocator,
|
||||
) {
|
||||
this.logger = logger;
|
||||
this.fetcher = fetcher;
|
||||
this.serviceLocator = serviceLocator;
|
||||
}
|
||||
|
||||
async getKubernetesObjectsByEntity(
|
||||
requestBody: KubernetesRequestBody,
|
||||
objectTypesToFetch: Set<KubernetesObjectTypes> = DEFAULT_OBJECTS,
|
||||
) {
|
||||
const entityName = requestBody.entity.metadata.name;
|
||||
|
||||
const clusterDetails: ClusterDetails[] = await this.serviceLocator.getClustersByServiceId(
|
||||
entityName,
|
||||
);
|
||||
|
||||
// Execute all of these async actions simultaneously/without blocking sequentially as no common object is modified by them
|
||||
const promises: Promise<ClusterDetails>[] = clusterDetails.map(cd => {
|
||||
const kubernetesAuthTranslator: KubernetesAuthTranslator = KubernetesAuthTranslatorGenerator.getKubernetesAuthTranslatorInstance(
|
||||
cd.authProvider,
|
||||
);
|
||||
return kubernetesAuthTranslator.decorateClusterDetailsWithAuth(
|
||||
cd,
|
||||
requestBody,
|
||||
);
|
||||
});
|
||||
const clusterDetailsDecoratedForAuth: ClusterDetails[] = await Promise.all(
|
||||
promises,
|
||||
);
|
||||
|
||||
this.logger.info(
|
||||
`entity.metadata.name=${entityName} clusterDetails=[${clusterDetailsDecoratedForAuth
|
||||
.map(c => c.name)
|
||||
.join(', ')}]`,
|
||||
);
|
||||
|
||||
const labelSelector: string =
|
||||
requestBody.entity?.metadata?.annotations?.[
|
||||
'backstage.io/kubernetes-label-selector'
|
||||
] || `backstage.io/kubernetes-id=${entityName}`;
|
||||
|
||||
return Promise.all(
|
||||
clusterDetailsDecoratedForAuth.map(clusterDetailsItem => {
|
||||
return this.fetcher
|
||||
.fetchObjectsForService({
|
||||
serviceId: entityName,
|
||||
clusterDetails: clusterDetailsItem,
|
||||
objectTypesToFetch,
|
||||
labelSelector,
|
||||
})
|
||||
.then(result => {
|
||||
return {
|
||||
cluster: {
|
||||
name: clusterDetailsItem.name,
|
||||
},
|
||||
resources: result.responses,
|
||||
errors: result.errors,
|
||||
};
|
||||
});
|
||||
}),
|
||||
).then(r => ({ items: r }));
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* 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 { Logger } from 'winston';
|
||||
import {
|
||||
KubernetesRequestBody,
|
||||
ClusterDetails,
|
||||
KubernetesServiceLocator,
|
||||
KubernetesFetcher,
|
||||
KubernetesObjectTypes,
|
||||
ObjectsByEntityResponse,
|
||||
ObjectFetchParams,
|
||||
} from '../types/types';
|
||||
import { KubernetesAuthTranslator } from '../kubernetes-auth-translator/types';
|
||||
import { KubernetesAuthTranslatorGenerator } from '../kubernetes-auth-translator/KubernetesAuthTranslatorGenerator';
|
||||
|
||||
export type GetKubernetesObjectsForServiceHandler = (
|
||||
serviceId: string,
|
||||
fetcher: KubernetesFetcher,
|
||||
serviceLocator: KubernetesServiceLocator,
|
||||
logger: Logger,
|
||||
requestBody: KubernetesRequestBody,
|
||||
objectTypesToFetch?: Set<KubernetesObjectTypes>,
|
||||
) => Promise<ObjectsByEntityResponse>;
|
||||
|
||||
const DEFAULT_OBJECTS = new Set<KubernetesObjectTypes>([
|
||||
'pods',
|
||||
'services',
|
||||
'configmaps',
|
||||
'deployments',
|
||||
'replicasets',
|
||||
'horizontalpodautoscalers',
|
||||
'ingresses',
|
||||
]);
|
||||
|
||||
// Fans out the request to all clusters that the service lives in, aggregates their responses together
|
||||
export const handleGetKubernetesObjectsForService: GetKubernetesObjectsForServiceHandler = async (
|
||||
serviceId,
|
||||
fetcher,
|
||||
serviceLocator,
|
||||
logger,
|
||||
requestBody,
|
||||
objectTypesToFetch = DEFAULT_OBJECTS,
|
||||
) => {
|
||||
const clusterDetails: ClusterDetails[] = await serviceLocator.getClustersByServiceId(
|
||||
serviceId,
|
||||
);
|
||||
|
||||
// Execute all of these async actions simultaneously/without blocking sequentially as no common object is modified by them
|
||||
const promises: Promise<ClusterDetails>[] = clusterDetails.map(cd => {
|
||||
const kubernetesAuthTranslator: KubernetesAuthTranslator = KubernetesAuthTranslatorGenerator.getKubernetesAuthTranslatorInstance(
|
||||
cd.authProvider,
|
||||
);
|
||||
return kubernetesAuthTranslator.decorateClusterDetailsWithAuth(
|
||||
cd,
|
||||
requestBody,
|
||||
);
|
||||
});
|
||||
const clusterDetailsDecoratedForAuth: ClusterDetails[] = await Promise.all(
|
||||
promises,
|
||||
);
|
||||
|
||||
logger.info(
|
||||
`serviceId=${serviceId} clusterDetails=[${clusterDetailsDecoratedForAuth
|
||||
.map(c => c.name)
|
||||
.join(', ')}]`,
|
||||
);
|
||||
|
||||
const labelSelector: string =
|
||||
requestBody.entity?.metadata?.annotations?.[
|
||||
'backstage.io/kubernetes-label-selector'
|
||||
] || `backstage.io/kubernetes-id=${requestBody.entity.metadata.name}`;
|
||||
|
||||
return Promise.all(
|
||||
clusterDetailsDecoratedForAuth.map(clusterDetailsItem => {
|
||||
return fetcher
|
||||
.fetchObjectsForService({
|
||||
serviceId,
|
||||
clusterDetails: clusterDetailsItem,
|
||||
objectTypesToFetch,
|
||||
labelSelector,
|
||||
} as ObjectFetchParams)
|
||||
.then(result => {
|
||||
return {
|
||||
cluster: {
|
||||
name: clusterDetailsItem.name,
|
||||
},
|
||||
resources: result.responses,
|
||||
errors: result.errors,
|
||||
};
|
||||
});
|
||||
}),
|
||||
).then(r => ({ items: r }));
|
||||
};
|
||||
@@ -18,35 +18,18 @@ import { getVoidLogger } from '@backstage/backend-common';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { makeRouter } from './router';
|
||||
import {
|
||||
KubernetesServiceLocator,
|
||||
KubernetesFetcher,
|
||||
ObjectsByEntityResponse,
|
||||
} from '..';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
|
||||
describe('router', () => {
|
||||
let app: express.Express;
|
||||
let kubernetesFetcher: jest.Mocked<KubernetesFetcher>;
|
||||
let kubernetesServiceLocator: jest.Mocked<KubernetesServiceLocator>;
|
||||
let handleGetByServiceId: jest.Mock<Promise<ObjectsByEntityResponse>>;
|
||||
let kubernetesFanOutHandler: jest.Mocked<KubernetesFanOutHandler>;
|
||||
|
||||
beforeAll(async () => {
|
||||
kubernetesFetcher = {
|
||||
fetchObjectsForService: jest.fn(),
|
||||
};
|
||||
kubernetesFanOutHandler = {
|
||||
getKubernetesObjectsByEntity: jest.fn(),
|
||||
} as any;
|
||||
|
||||
kubernetesServiceLocator = {
|
||||
getClustersByServiceId: jest.fn(),
|
||||
};
|
||||
|
||||
handleGetByServiceId = jest.fn();
|
||||
|
||||
const router = makeRouter(
|
||||
getVoidLogger(),
|
||||
kubernetesFetcher,
|
||||
kubernetesServiceLocator,
|
||||
handleGetByServiceId as any,
|
||||
);
|
||||
const router = makeRouter(getVoidLogger(), kubernetesFanOutHandler);
|
||||
app = express().use(router);
|
||||
});
|
||||
|
||||
@@ -67,7 +50,9 @@ describe('router', () => {
|
||||
],
|
||||
},
|
||||
} as any;
|
||||
handleGetByServiceId.mockReturnValueOnce(Promise.resolve(result));
|
||||
kubernetesFanOutHandler.getKubernetesObjectsByEntity.mockReturnValueOnce(
|
||||
Promise.resolve(result),
|
||||
);
|
||||
|
||||
const response = await request(app).post('/services/test-service');
|
||||
|
||||
@@ -87,7 +72,9 @@ describe('router', () => {
|
||||
],
|
||||
},
|
||||
} as any;
|
||||
handleGetByServiceId.mockReturnValueOnce(Promise.resolve(result));
|
||||
kubernetesFanOutHandler.getKubernetesObjectsByEntity.mockReturnValueOnce(
|
||||
Promise.resolve(result),
|
||||
);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/services/test-service')
|
||||
@@ -103,7 +90,9 @@ describe('router', () => {
|
||||
});
|
||||
|
||||
it('internal error: lists kubernetes objects', async () => {
|
||||
handleGetByServiceId.mockRejectedValue(Error('some internal error'));
|
||||
kubernetesFanOutHandler.getKubernetesObjectsByEntity.mockRejectedValue(
|
||||
Error('some internal error'),
|
||||
);
|
||||
|
||||
const response = await request(app).post('/services/test-service');
|
||||
|
||||
|
||||
@@ -21,19 +21,15 @@ import { Config } from '@backstage/config';
|
||||
import { MultiTenantServiceLocator } from '../service-locator/MultiTenantServiceLocator';
|
||||
import { KubernetesClientBasedFetcher } from './KubernetesFetcher';
|
||||
import { KubernetesClientProvider } from './KubernetesClientProvider';
|
||||
import {
|
||||
GetKubernetesObjectsForServiceHandler,
|
||||
handleGetKubernetesObjectsForService,
|
||||
} from './getKubernetesObjectsForServiceHandler';
|
||||
import {
|
||||
KubernetesRequestBody,
|
||||
KubernetesServiceLocator,
|
||||
KubernetesFetcher,
|
||||
ServiceLocatorMethod,
|
||||
ClusterLocatorMethod,
|
||||
ClusterDetails,
|
||||
} from '..';
|
||||
import { getCombinedClusterDetails } from '../cluster-locator';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
|
||||
export interface RouterOptions {
|
||||
logger: Logger;
|
||||
@@ -62,9 +58,7 @@ const getServiceLocator = (
|
||||
|
||||
export const makeRouter = (
|
||||
logger: Logger,
|
||||
fetcher: KubernetesFetcher,
|
||||
serviceLocator: KubernetesServiceLocator,
|
||||
handleGetByEntity: GetKubernetesObjectsForServiceHandler,
|
||||
kubernetesFanOutHandler: KubernetesFanOutHandler,
|
||||
): express.Router => {
|
||||
const router = Router();
|
||||
router.use(express.json());
|
||||
@@ -73,11 +67,7 @@ export const makeRouter = (
|
||||
const serviceId = req.params.serviceId;
|
||||
const requestBody: KubernetesRequestBody = req.body;
|
||||
try {
|
||||
const response = await handleGetByEntity(
|
||||
serviceId,
|
||||
fetcher,
|
||||
serviceLocator,
|
||||
logger,
|
||||
const response = await kubernetesFanOutHandler.getKubernetesObjectsByEntity(
|
||||
requestBody,
|
||||
);
|
||||
res.send(response);
|
||||
@@ -115,10 +105,11 @@ export async function createRouter(
|
||||
|
||||
const serviceLocator = getServiceLocator(options.config, clusterDetails);
|
||||
|
||||
return makeRouter(
|
||||
const kubernetesFanOutHandler = new KubernetesFanOutHandler(
|
||||
logger,
|
||||
fetcher,
|
||||
serviceLocator,
|
||||
handleGetKubernetesObjectsForService,
|
||||
);
|
||||
|
||||
return makeRouter(logger, kubernetesFanOutHandler);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @backstage/plugin-kubernetes
|
||||
|
||||
## 0.3.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a70af22a2]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/plugin-kubernetes-backend@0.2.7
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.3.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-kubernetes",
|
||||
"version": "0.3.10",
|
||||
"version": "0.3.11",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,11 +31,11 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.2.6",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-kubernetes-backend": "^0.2.7",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@kubernetes/client-node": "^0.13.2",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
@@ -48,9 +48,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# @backstage/plugin-lighthouse
|
||||
|
||||
## 0.2.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.2.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-lighthouse",
|
||||
"version": "0.2.11",
|
||||
"version": "0.2.12",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,10 +31,10 @@
|
||||
"start": "backstage-cli plugin:serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -46,9 +46,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -41,9 +41,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# @backstage/plugin-org
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e3bc5aad7: Use the `pageTheme` to colour the OwnershipCard boxes with their respective theme colours.
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [b6c4f485d]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core-api@0.2.11
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-org",
|
||||
"version": "0.3.7",
|
||||
"version": "0.3.8",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -20,10 +20,10 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/core-api": "^0.2.10",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/core-api": "^0.2.11",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -35,9 +35,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-pagerduty
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-pagerduty",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,9 +30,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -46,9 +46,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-register-component
|
||||
|
||||
## 0.2.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.2.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-register-component",
|
||||
"version": "0.2.10",
|
||||
"version": "0.2.11",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,9 +30,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -45,9 +45,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# @backstage/plugin-rollbar
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-rollbar",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,9 +31,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -47,9 +47,9 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/react-hooks": "^3.3.0",
|
||||
|
||||
@@ -1,5 +1,65 @@
|
||||
# @backstage/plugin-scaffolder-backend
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- a5f42cf66: # Stateless scaffolding
|
||||
|
||||
The scaffolder has been redesigned to be horizontally scalable and to persistently store task state and execution logs in the database.
|
||||
|
||||
Each scaffolder task is given a unique task ID which is persisted in the database.
|
||||
Tasks are then picked up by a `TaskWorker` which performs the scaffolding steps.
|
||||
Execution logs are also persisted in the database meaning you can now refresh the scaffolder task status page without losing information.
|
||||
|
||||
The task status page is now dynamically created based on the step information stored in the database.
|
||||
This allows for custom steps to be displayed once the next version of the scaffolder template schema is available.
|
||||
|
||||
The task page is updated to display links to both the git repository and to the newly created catalog entity.
|
||||
|
||||
Component registration has moved from the frontend into a separate registration step executed by the `TaskWorker`. This requires that a `CatalogClient` is passed to the scaffolder backend instead of the old `CatalogEntityClient`.
|
||||
|
||||
Make sure to update `plugins/scaffolder.ts`
|
||||
|
||||
```diff
|
||||
import {
|
||||
CookieCutter,
|
||||
createRouter,
|
||||
Preparers,
|
||||
Publishers,
|
||||
CreateReactAppTemplater,
|
||||
Templaters,
|
||||
- CatalogEntityClient,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
|
||||
+import { CatalogClient } from '@backstage/catalog-client';
|
||||
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
-const entityClient = new CatalogEntityClient({ discovery });
|
||||
+const catalogClient = new CatalogClient({ discoveryApi: discovery })
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
templaters,
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
- entityClient,
|
||||
database,
|
||||
+ catalogClient,
|
||||
});
|
||||
```
|
||||
|
||||
As well as adding the `@backstage/catalog-client` packages as a dependency of your backend package.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- @backstage/catalog-model@0.7.2
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.7.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-scaffolder-backend",
|
||||
"version": "0.7.1",
|
||||
"version": "0.8.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,8 +31,8 @@
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.4",
|
||||
"@backstage/catalog-client": "^0.3.6",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/integration": "^0.5.0",
|
||||
"@gitbeaker/core": "^28.0.2",
|
||||
"@gitbeaker/node": "^28.0.2",
|
||||
@@ -63,8 +63,8 @@
|
||||
"yaml": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
"@types/mock-fs": "^4.13.0",
|
||||
"@types/supertest": "^2.0.8",
|
||||
|
||||
@@ -1,5 +1,117 @@
|
||||
# @backstage/plugin-scaffolder
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- a5f42cf66: The Scaffolder and Catalog plugins have been migrated to partially require use of the [new composability API](https://backstage.io/docs/plugins/composability). The Scaffolder used to register its pages using the deprecated route registration plugin API, but those registrations have been removed. This means you now need to add the Scaffolder plugin page to the app directly.
|
||||
|
||||
The page is imported from the Scaffolder plugin and added to the `<FlatRoutes>` component:
|
||||
|
||||
```tsx
|
||||
<Route path="/create" element={<ScaffolderPage />} />
|
||||
```
|
||||
|
||||
The Catalog plugin has also been migrated to use an [external route reference](https://backstage.io/docs/plugins/composability#binding-external-routes-in-the-app) to dynamically link to the create component page. This means you need to migrate the catalog plugin to use the new extension components, as well as bind the external route.
|
||||
|
||||
To use the new extension components, replace existing usage of the `CatalogRouter` with the following:
|
||||
|
||||
```tsx
|
||||
<Route path="/catalog" element={<CatalogIndexPage />} />
|
||||
<Route path="/catalog/:namespace/:kind/:name" element={<CatalogEntityPage />}>
|
||||
<EntityPage />
|
||||
</Route>
|
||||
```
|
||||
|
||||
And to bind the external route from the catalog plugin to the scaffolder template index page, make sure you have the appropriate imports and add the following to the `createApp` call:
|
||||
|
||||
```ts
|
||||
import { catalogPlugin } from '@backstage/plugin-catalog';
|
||||
import { scaffolderPlugin } from '@backstage/plugin-scaffolder';
|
||||
|
||||
const app = createApp({
|
||||
// ...
|
||||
bindRoutes({ bind }) {
|
||||
bind(catalogPlugin.externalRoutes, {
|
||||
createComponent: scaffolderPlugin.routes.root,
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
- d0760ecdf: Moved common useStarredEntities hook to plugin-catalog-react
|
||||
- e8e35fb5f: Adding Search and Filter features to Scaffolder/Templates Grid
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a5f42cf66: # Stateless scaffolding
|
||||
|
||||
The scaffolder has been redesigned to be horizontally scalable and to persistently store task state and execution logs in the database.
|
||||
|
||||
Each scaffolder task is given a unique task ID which is persisted in the database.
|
||||
Tasks are then picked up by a `TaskWorker` which performs the scaffolding steps.
|
||||
Execution logs are also persisted in the database meaning you can now refresh the scaffolder task status page without losing information.
|
||||
|
||||
The task status page is now dynamically created based on the step information stored in the database.
|
||||
This allows for custom steps to be displayed once the next version of the scaffolder template schema is available.
|
||||
|
||||
The task page is updated to display links to both the git repository and to the newly created catalog entity.
|
||||
|
||||
Component registration has moved from the frontend into a separate registration step executed by the `TaskWorker`. This requires that a `CatalogClient` is passed to the scaffolder backend instead of the old `CatalogEntityClient`.
|
||||
|
||||
Make sure to update `plugins/scaffolder.ts`
|
||||
|
||||
```diff
|
||||
import {
|
||||
CookieCutter,
|
||||
createRouter,
|
||||
Preparers,
|
||||
Publishers,
|
||||
CreateReactAppTemplater,
|
||||
Templaters,
|
||||
- CatalogEntityClient,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
|
||||
+import { CatalogClient } from '@backstage/catalog-client';
|
||||
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
-const entityClient = new CatalogEntityClient({ discovery });
|
||||
+const catalogClient = new CatalogClient({ discoveryApi: discovery })
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
templaters,
|
||||
publishers,
|
||||
logger,
|
||||
config,
|
||||
dockerClient,
|
||||
- entityClient,
|
||||
database,
|
||||
+ catalogClient,
|
||||
});
|
||||
```
|
||||
|
||||
As well as adding the `@backstage/catalog-client` packages as a dependency of your backend package.
|
||||
|
||||
- e488f0502: Update messages that process during loading, error, and no templates found.
|
||||
Remove unused dependencies.
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [e799e74d4]
|
||||
- Updated dependencies [d0760ecdf]
|
||||
- Updated dependencies [1407b34c6]
|
||||
- Updated dependencies [88f1f1b60]
|
||||
- Updated dependencies [bad21a085]
|
||||
- Updated dependencies [9615e68fb]
|
||||
- Updated dependencies [49f9b7346]
|
||||
- Updated dependencies [5c2e2863f]
|
||||
- Updated dependencies [3a58084b6]
|
||||
- Updated dependencies [a1f5e6545]
|
||||
- Updated dependencies [2c1f2a7c2]
|
||||
- @backstage/core@0.6.3
|
||||
- @backstage/plugin-catalog-react@0.1.0
|
||||
- @backstage/catalog-model@0.7.2
|
||||
- @backstage/config@0.1.3
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-scaffolder",
|
||||
"version": "0.5.1",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,10 +31,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-client": "^0.3.6",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core": "^0.6.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.4",
|
||||
"@backstage/catalog-model": "^0.7.2",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/core": "^0.6.3",
|
||||
"@backstage/plugin-catalog-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -56,9 +56,9 @@
|
||||
"zen-observable": "^0.8.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.1",
|
||||
"@backstage/dev-utils": "^0.1.11",
|
||||
"@backstage/test-utils": "^0.1.7",
|
||||
"@backstage/cli": "^0.6.2",
|
||||
"@backstage/dev-utils": "^0.1.12",
|
||||
"@backstage/test-utils": "^0.1.8",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
Theme,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import React, { useCallback, useContext, useState } from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { filterGroupsContext } from '../../filter/context';
|
||||
|
||||
const useStyles = makeStyles<Theme>(theme => ({
|
||||
@@ -59,20 +59,12 @@ type Props = {
|
||||
export const ResultsFilter = ({ availableCategories }: Props) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
|
||||
const context = useContext(filterGroupsContext);
|
||||
if (!context) {
|
||||
throw new Error(`Must be used inside an EntityFilterGroupsProvider`);
|
||||
}
|
||||
const setSelectedCatgoriesFilter = context?.setSelectedCategories;
|
||||
|
||||
const updateSelectedCategories = useCallback(
|
||||
(categories: string[]) => {
|
||||
setSelectedCategories(categories);
|
||||
setSelectedCatgoriesFilter(categories);
|
||||
},
|
||||
[setSelectedCategories, setSelectedCatgoriesFilter],
|
||||
);
|
||||
const { selectedCategories, setSelectedCategories } = context;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -80,7 +72,7 @@ export const ResultsFilter = ({ availableCategories }: Props) => {
|
||||
<Typography variant="subtitle2" className={classes.filterBoxTitle}>
|
||||
Refine Results
|
||||
</Typography>{' '}
|
||||
<Button onClick={() => updateSelectedCategories([])}>Clear</Button>
|
||||
<Button onClick={() => setSelectedCategories([])}>Clear</Button>
|
||||
</div>
|
||||
<Divider />
|
||||
<Typography variant="subtitle2" className={classes.title}>
|
||||
@@ -95,7 +87,7 @@ export const ResultsFilter = ({ availableCategories }: Props) => {
|
||||
dense
|
||||
button
|
||||
onClick={() =>
|
||||
updateSelectedCategories(
|
||||
setSelectedCategories(
|
||||
selectedCategories.includes(category)
|
||||
? selectedCategories.filter(
|
||||
selectedCategory => selectedCategory !== category,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user