Merge branch 'master' into rugvip/moreports
This commit is contained in:
@@ -1,5 +1,36 @@
|
||||
# @backstage/plugin-api-docs
|
||||
|
||||
## 0.4.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7fc89bae2: Display owner and system as entity page links in the tables of the `api-docs`
|
||||
plugin.
|
||||
|
||||
Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to
|
||||
`@backstage/plugin-catalog-react` and export it from there to use it by other
|
||||
plugins.
|
||||
|
||||
- bc5082a00: Migrate to new composability API, exporting the plugin as `apiDocsPlugin`, index page as `ApiExplorerPage`, and entity page cards as `EntityApiDefinitionCard`, `EntityConsumedApisCard`, `EntityConsumingComponentsCard`, `EntityProvidedApisCard`, and `EntityProvidingComponentsCard`.
|
||||
- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-api-docs",
|
||||
"version": "0.4.3",
|
||||
"version": "0.4.4",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,10 +30,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@asyncapi/react-component": "^0.18.2",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.1",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@backstage/theme": "^0.2.3",
|
||||
"@material-icons/font": "^1.0.2",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
@@ -49,8 +49,8 @@
|
||||
"swagger-ui-react": "^3.37.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -75,8 +75,8 @@ paths:
|
||||
type: 'openapi',
|
||||
title: 'OpenAPI',
|
||||
rawLanguage: 'yaml',
|
||||
component: definition => (
|
||||
<OpenApiDefinitionWidget definition={definition} />
|
||||
component: definitionString => (
|
||||
<OpenApiDefinitionWidget definition={definitionString} />
|
||||
),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/plugin-app-backend
|
||||
|
||||
## 0.3.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e9aab60c7: Failures to load the frontend configuration schema now throws an error that includes more context and instructions for how to fix the issue.
|
||||
- Updated dependencies [2430ee7c2]
|
||||
- Updated dependencies [062df71db]
|
||||
- Updated dependencies [e9aab60c7]
|
||||
- @backstage/backend-common@0.5.2
|
||||
- @backstage/config-loader@0.5.1
|
||||
|
||||
## 0.3.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-app-backend",
|
||||
"version": "0.3.5",
|
||||
"version": "0.3.6",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,8 +29,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/config-loader": "^0.5.0",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/config-loader": "^0.5.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@types/express": "^4.17.6",
|
||||
"express": "^4.17.1",
|
||||
@@ -40,7 +40,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"msw": "^0.20.5",
|
||||
"supertest": "^4.0.2"
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/catalog-client": "^0.3.5",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@types/express": "^4.17.6",
|
||||
"compression": "^1.7.4",
|
||||
@@ -65,7 +65,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@types/body-parser": "^1.19.0",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express-session": "^1.17.2",
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# @backstage/plugin-catalog-backend
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 3149bfe63: Make use of the `resolveUrl` facility of the `integration` package.
|
||||
|
||||
Also rename the `LocationRefProcessor` to `LocationEntityProcessor`, to match the file name. This constitutes an interface change since the class is exported, but it is unlikely to be consumed outside of the package since it sits comfortably with the other default processors inside the catalog builder.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 24e47ef1e: Throw `NotAllowedError` when registering locations with entities of disallowed kinds
|
||||
- Updated dependencies [c4abcdb60]
|
||||
- Updated dependencies [2430ee7c2]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [064c513e1]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [3149bfe63]
|
||||
- Updated dependencies [2e62aea6f]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/integration@0.3.2
|
||||
- @backstage/backend-common@0.5.2
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.5.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-backend",
|
||||
"version": "0.5.5",
|
||||
"version": "0.6.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,9 +31,10 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-organizations": "^3.2.0",
|
||||
"@azure/msal-node": "^1.0.0-beta.3",
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/integration": "^0.3.2",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/ldapjs": "^1.0.9",
|
||||
@@ -57,7 +58,7 @@
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@types/core-js": "^2.5.4",
|
||||
"@types/git-url-parse": "^9.0.0",
|
||||
|
||||
@@ -124,7 +124,7 @@ export class DatabaseEntitiesCatalog implements EntitiesCatalog {
|
||||
// produce tens of thousands of entities, and those are too large batch
|
||||
// sizes to reasonably send to the database.
|
||||
const batches = Object.values(requestsByKindAndNamespace)
|
||||
.map(requests => chunk(requests, BATCH_SIZE))
|
||||
.map(request => chunk(request, BATCH_SIZE))
|
||||
.flat();
|
||||
|
||||
// Bound the number of concurrent batches. We want a bit of concurrency for
|
||||
|
||||
+6
-3
@@ -65,7 +65,10 @@ describe('AwsOrganizationCloudAccountProcessor', () => {
|
||||
});
|
||||
|
||||
it('filters out accounts not in specified location target', async () => {
|
||||
const location = { type: 'aws-cloud-accounts', target: 'o-1vl18kc5a3' };
|
||||
const locationTest = {
|
||||
type: 'aws-cloud-accounts',
|
||||
target: 'o-1vl18kc5a3',
|
||||
};
|
||||
listAccounts.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
Accounts: [
|
||||
@@ -83,11 +86,11 @@ describe('AwsOrganizationCloudAccountProcessor', () => {
|
||||
NextToken: undefined,
|
||||
}),
|
||||
);
|
||||
await processor.readLocation(location, false, emit);
|
||||
await processor.readLocation(locationTest, false, emit);
|
||||
expect(emit).toBeCalledTimes(1);
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'entity',
|
||||
location,
|
||||
location: locationTest,
|
||||
entity: {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Resource',
|
||||
|
||||
@@ -66,8 +66,8 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
|
||||
async validateEntityKind(entity: Entity): Promise<boolean> {
|
||||
for (const validator of this.validators) {
|
||||
const result = await validator.check(entity);
|
||||
if (result) {
|
||||
const results = await validator.check(entity);
|
||||
if (results) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,30 +15,73 @@
|
||||
*/
|
||||
|
||||
import { LocationSpec } from '@backstage/catalog-model';
|
||||
import { toAbsoluteUrl } from './LocationEntityProcessor';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import {
|
||||
ScmIntegrations,
|
||||
ScmIntegrationRegistry,
|
||||
} from '@backstage/integration';
|
||||
import path from 'path';
|
||||
import { toAbsoluteUrl } from './LocationEntityProcessor';
|
||||
|
||||
describe('LocationEntityProcessor', () => {
|
||||
describe('toAbsoluteUrl', () => {
|
||||
it('handles files', () => {
|
||||
const integrations = ({} as unknown) as ScmIntegrationRegistry;
|
||||
const base: LocationSpec = {
|
||||
type: 'file',
|
||||
target: `some${path.sep}path${path.sep}catalog-info.yaml`,
|
||||
};
|
||||
expect(toAbsoluteUrl(base, `.${path.sep}c`)).toBe(
|
||||
expect(toAbsoluteUrl(integrations, base, `.${path.sep}c`)).toBe(
|
||||
`some${path.sep}path${path.sep}c`,
|
||||
);
|
||||
expect(toAbsoluteUrl(base, `${path.sep}c`)).toBe(`${path.sep}c`);
|
||||
expect(toAbsoluteUrl(integrations, base, `${path.sep}c`)).toBe(
|
||||
`${path.sep}c`,
|
||||
);
|
||||
});
|
||||
|
||||
it('handles urls', () => {
|
||||
const integrations = ScmIntegrations.fromConfig(new ConfigReader({}));
|
||||
const base: LocationSpec = {
|
||||
type: 'url',
|
||||
target: 'http://a.com/b/catalog-info.yaml',
|
||||
};
|
||||
expect(toAbsoluteUrl(base, './c/d')).toBe('http://a.com/b/c/d');
|
||||
expect(toAbsoluteUrl(base, 'c/d')).toBe('http://a.com/b/c/d');
|
||||
expect(toAbsoluteUrl(base, 'http://b.com/z')).toBe('http://b.com/z');
|
||||
jest.spyOn(integrations, 'resolveUrl');
|
||||
|
||||
expect(toAbsoluteUrl(integrations, base, './c/d')).toBe(
|
||||
'http://a.com/b/c/d',
|
||||
);
|
||||
expect(toAbsoluteUrl(integrations, base, 'c/d')).toBe(
|
||||
'http://a.com/b/c/d',
|
||||
);
|
||||
expect(toAbsoluteUrl(integrations, base, 'http://b.com/z')).toBe(
|
||||
'http://b.com/z',
|
||||
);
|
||||
|
||||
expect(integrations.resolveUrl).toBeCalledTimes(3);
|
||||
});
|
||||
|
||||
it('handles azure urls specifically', () => {
|
||||
const integrations = ScmIntegrations.fromConfig(
|
||||
new ConfigReader({
|
||||
integrations: {
|
||||
azure: [{ host: 'dev.azure.com' }],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(
|
||||
toAbsoluteUrl(
|
||||
integrations,
|
||||
{
|
||||
type: 'url',
|
||||
target:
|
||||
'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml',
|
||||
},
|
||||
'./a.yaml',
|
||||
),
|
||||
).toBe(
|
||||
'https://dev.azure.com/organization/project/_git/repository?path=%2Fa.yaml',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,11 +15,16 @@
|
||||
*/
|
||||
|
||||
import { Entity, LocationEntity, LocationSpec } from '@backstage/catalog-model';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import path from 'path';
|
||||
import * as result from './results';
|
||||
import { CatalogProcessor, CatalogProcessorEmit } from './types';
|
||||
import path from 'path';
|
||||
|
||||
export function toAbsoluteUrl(base: LocationSpec, target: string): string {
|
||||
export function toAbsoluteUrl(
|
||||
integrations: ScmIntegrationRegistry,
|
||||
base: LocationSpec,
|
||||
target: string,
|
||||
): string {
|
||||
try {
|
||||
if (base.type === 'file') {
|
||||
if (target.startsWith('.')) {
|
||||
@@ -27,13 +32,19 @@ export function toAbsoluteUrl(base: LocationSpec, target: string): string {
|
||||
}
|
||||
return target;
|
||||
}
|
||||
return new URL(target, base.target).toString();
|
||||
return integrations.resolveUrl({ url: target, base: base.target });
|
||||
} catch (e) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
export class LocationRefProcessor implements CatalogProcessor {
|
||||
type Options = {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
};
|
||||
|
||||
export class LocationEntityProcessor implements CatalogProcessor {
|
||||
constructor(private readonly options: Options) {}
|
||||
|
||||
async postProcessEntity(
|
||||
entity: Entity,
|
||||
location: LocationSpec,
|
||||
@@ -47,7 +58,7 @@ export class LocationRefProcessor implements CatalogProcessor {
|
||||
emit(
|
||||
result.inputError(
|
||||
location,
|
||||
`LocationRefProcessor cannot handle ${type} type location with target ${location.target} that ends with a path separator`,
|
||||
`LocationEntityProcessor cannot handle ${type} type location with target ${location.target} that ends with a path separator`,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -61,7 +72,11 @@ export class LocationRefProcessor implements CatalogProcessor {
|
||||
}
|
||||
|
||||
for (const maybeRelativeTarget of targets) {
|
||||
const target = toAbsoluteUrl(location, maybeRelativeTarget);
|
||||
const target = toAbsoluteUrl(
|
||||
this.options.integrations,
|
||||
location,
|
||||
maybeRelativeTarget,
|
||||
);
|
||||
emit(result.location({ type, target }, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export { CodeOwnersProcessor } from './CodeOwnersProcessor';
|
||||
export { FileReaderProcessor } from './FileReaderProcessor';
|
||||
export { GithubOrgReaderProcessor } from './GithubOrgReaderProcessor';
|
||||
export { LdapOrgReaderProcessor } from './LdapOrgReaderProcessor';
|
||||
export { LocationRefProcessor } from './LocationEntityProcessor';
|
||||
export { LocationEntityProcessor } from './LocationEntityProcessor';
|
||||
export { MicrosoftGraphOrgReaderProcessor } from './MicrosoftGraphOrgReaderProcessor';
|
||||
export { PlaceholderProcessor } from './PlaceholderProcessor';
|
||||
export type { PlaceholderResolver } from './PlaceholderProcessor';
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
Validators,
|
||||
} from '@backstage/catalog-model';
|
||||
import { Config } from '@backstage/config';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import lodash from 'lodash';
|
||||
import { Logger } from 'winston';
|
||||
import {
|
||||
@@ -46,8 +47,8 @@ import {
|
||||
HigherOrderOperation,
|
||||
HigherOrderOperations,
|
||||
LdapOrgReaderProcessor,
|
||||
LocationEntityProcessor,
|
||||
LocationReaders,
|
||||
LocationRefProcessor,
|
||||
MicrosoftGraphOrgReaderProcessor,
|
||||
PlaceholderProcessor,
|
||||
PlaceholderResolver,
|
||||
@@ -280,6 +281,7 @@ export class CatalogBuilder {
|
||||
|
||||
private buildProcessors(): CatalogProcessor[] {
|
||||
const { config, logger, reader } = this.env;
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
|
||||
this.checkDeprecatedReaderProcessors();
|
||||
|
||||
@@ -306,7 +308,7 @@ export class CatalogBuilder {
|
||||
MicrosoftGraphOrgReaderProcessor.fromConfig(config, { logger }),
|
||||
new UrlReaderProcessor({ reader, logger }),
|
||||
new CodeOwnersProcessor({ reader, logger }),
|
||||
new LocationRefProcessor(),
|
||||
new LocationEntityProcessor({ integrations }),
|
||||
new AnnotateLocationEntityProcessor(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@graphql-modules/core": "^0.7.17",
|
||||
"apollo-server": "^2.16.1",
|
||||
@@ -42,7 +42,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/test-utils": "^0.1.5",
|
||||
"@graphql-codegen/cli": "^1.17.7",
|
||||
"@graphql-codegen/typescript": "^1.17.7",
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# @backstage/plugin-catalog-import
|
||||
|
||||
## 0.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ceef4dd89: Export _api_ (Client, API, ref) from the catalog import plugin.
|
||||
- b712841d6: Migrated to new composability API, exporting the plugin instance as `catalogImportPlugin`, and the page as `CatalogImportPage`.
|
||||
- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [c4abcdb60]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [064c513e1]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [3149bfe63]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [2e62aea6f]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/integration@0.3.2
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.3.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-import",
|
||||
"version": "0.3.6",
|
||||
"version": "0.3.7",
|
||||
"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.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/integration": "^0.3.1",
|
||||
"@backstage/plugin-catalog-react": "^0.0.1",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/integration": "^0.3.2",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@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",
|
||||
@@ -50,8 +50,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/catalog-client": "^0.3.5",
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -71,8 +71,8 @@ export const RegisterComponentForm = ({
|
||||
|
||||
const onSubmit = async (formData: Record<string, string>) => {
|
||||
const { componentLocation: target } = formData;
|
||||
async function saveCatalogFileConfig(target: string) {
|
||||
const data = await catalogApi.addLocation({ target });
|
||||
async function saveCatalogFileConfig(targetString: string) {
|
||||
const data = await catalogApi.addLocation({ target: targetString });
|
||||
saveConfig({
|
||||
type: 'file',
|
||||
location: data.location.target,
|
||||
@@ -80,12 +80,12 @@ export const RegisterComponentForm = ({
|
||||
});
|
||||
}
|
||||
|
||||
async function trySaveRepositoryConfig(target: string) {
|
||||
const existingCatalog = await checkForExistingCatalogInfo(target);
|
||||
async function trySaveRepositoryConfig(targetString: string) {
|
||||
const existingCatalog = await checkForExistingCatalogInfo(targetString);
|
||||
if (existingCatalog.exists) {
|
||||
const targetUrl = target.endsWith('/')
|
||||
? `${target}${existingCatalog.url}`
|
||||
: `${target}/${existingCatalog.url}`;
|
||||
const targetUrl = targetString.endsWith('/')
|
||||
? `${targetString}${existingCatalog.url}`
|
||||
: `${targetString}/${existingCatalog.url}`;
|
||||
await saveCatalogFileConfig(targetUrl);
|
||||
} else {
|
||||
saveConfig({
|
||||
|
||||
@@ -46,20 +46,20 @@ function manifestGenerationAvailable(configApi: ConfigApi): boolean {
|
||||
|
||||
function repositories(configApi: ConfigApi): string[] {
|
||||
const integrations = configApi.getConfig('integrations');
|
||||
const repositories = [];
|
||||
const repos = [];
|
||||
if (integrations.has('github')) {
|
||||
repositories.push('GitHub');
|
||||
repos.push('GitHub');
|
||||
}
|
||||
if (integrations.has('bitbucket')) {
|
||||
repositories.push('Bitbucket');
|
||||
repos.push('Bitbucket');
|
||||
}
|
||||
if (integrations.has('gitlab')) {
|
||||
repositories.push('GitLab');
|
||||
repos.push('GitLab');
|
||||
}
|
||||
if (integrations.has('azure')) {
|
||||
repositories.push('Azure');
|
||||
repos.push('Azure');
|
||||
}
|
||||
return repositories;
|
||||
return repos;
|
||||
}
|
||||
|
||||
export const ImportComponentPage = ({
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# @backstage/plugin-catalog-react
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7fc89bae2: Display owner and system as entity page links in the tables of the `api-docs`
|
||||
plugin.
|
||||
|
||||
Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to
|
||||
`@backstage/plugin-catalog-react` and export it from there to use it by other
|
||||
plugins.
|
||||
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/catalog-model@0.7.1
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-react",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -29,8 +29,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-client": "^0.3.5",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@types/react": "^16.9",
|
||||
"react": "^16.13.1",
|
||||
@@ -39,8 +39,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -34,13 +34,13 @@ export function isOwnerOf(owner: Entity, owned: Entity) {
|
||||
|
||||
const owners = getEntityRelations(owned, RELATION_OWNED_BY);
|
||||
|
||||
for (const owner of owners) {
|
||||
for (const ownerItem of owners) {
|
||||
if (
|
||||
possibleOwners.find(
|
||||
o =>
|
||||
owner.kind.toLowerCase() === o.kind.toLowerCase() &&
|
||||
owner.namespace.toLowerCase() === o.namespace.toLowerCase() &&
|
||||
owner.name.toLowerCase() === o.name.toLowerCase(),
|
||||
ownerItem.kind.toLowerCase() === o.kind.toLowerCase() &&
|
||||
ownerItem.namespace.toLowerCase() === o.namespace.toLowerCase() &&
|
||||
ownerItem.name.toLowerCase() === o.name.toLowerCase(),
|
||||
) !== undefined
|
||||
) {
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,55 @@
|
||||
# @backstage/plugin-catalog
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 019fe39a0: `@backstage/plugin-catalog` stopped exporting hooks and helpers for other
|
||||
plugins. They are migrated to `@backstage/plugin-catalog-react`.
|
||||
Change both your dependencies and imports to the new package.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 7fc89bae2: Display owner and system as entity page links in the tables of the `api-docs`
|
||||
plugin.
|
||||
|
||||
Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to
|
||||
`@backstage/plugin-catalog-react` and export it from there to use it by other
|
||||
plugins.
|
||||
|
||||
- b37501a3d: Add `children` option to `addPage`, which will be rendered as the children of the `Route`.
|
||||
- b37501a3d: Finalize migration to new composability API, with the plugin instance now exported `catalogPlugin`.
|
||||
- 54c7d02f7: Introduce `TabbedLayout` for creating tabs that are routed.
|
||||
|
||||
```typescript
|
||||
<TabbedLayout>
|
||||
<TabbedLayout.Route path="/example" title="Example tab">
|
||||
<div>This is rendered under /example/anything-here route</div>
|
||||
</TabbedLayout.Route>
|
||||
</TabbedLayout>
|
||||
```
|
||||
|
||||
- Updated dependencies [720149854]
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [019fe39a0]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/plugin-scaffolder@0.4.2
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.2.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog",
|
||||
"version": "0.2.14",
|
||||
"version": "0.3.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,11 +31,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-client": "^0.3.5",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.1",
|
||||
"@backstage/plugin-scaffolder": "^0.4.1",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@backstage/plugin-scaffolder": "^0.4.2",
|
||||
"@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",
|
||||
@@ -52,8 +52,8 @@
|
||||
"swr": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@microsoft/microsoft-graph-types": "^1.25.0",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
ApiRegistry,
|
||||
} from '@backstage/core';
|
||||
import { catalogApiRef, EntityContext } from '@backstage/plugin-catalog-react';
|
||||
import { renderInTestApp, withLogCollector } from '@backstage/test-utils';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
@@ -59,34 +59,11 @@ describe('EntityLayout', () => {
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(rendered.getByText('my-entity')).toBeInTheDocument();
|
||||
expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument();
|
||||
expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('throws if any other component is a child of TabbedLayout', async () => {
|
||||
const { error } = await withLogCollector(async () => {
|
||||
await expect(
|
||||
renderInTestApp(
|
||||
<EntityLayout>
|
||||
<EntityLayout.Route path="/" title="tabbed-test-title">
|
||||
<div>tabbed-test-content</div>
|
||||
</EntityLayout.Route>
|
||||
<div>This will cause app to throw</div>
|
||||
</EntityLayout>,
|
||||
),
|
||||
).rejects.toThrow(/Child of EntityLayout must be an EntityLayout.Route/);
|
||||
});
|
||||
|
||||
expect(error).toEqual([
|
||||
expect.stringMatching(
|
||||
/Child of EntityLayout must be an EntityLayout.Route/,
|
||||
),
|
||||
expect.stringMatching(
|
||||
/The above error occurred in the <EntityLayout> component/,
|
||||
),
|
||||
]);
|
||||
});
|
||||
|
||||
it('navigates when user clicks different tab', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<Routes>
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';
|
||||
import {
|
||||
attachComponentData,
|
||||
Content,
|
||||
Header,
|
||||
HeaderLabel,
|
||||
Page,
|
||||
Progress,
|
||||
TabbedLayout,
|
||||
} from '@backstage/core';
|
||||
import {
|
||||
EntityContext,
|
||||
@@ -29,12 +29,9 @@ import {
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { Box } from '@material-ui/core';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import React, {
|
||||
Children,
|
||||
Fragment,
|
||||
isValidElement,
|
||||
import {
|
||||
default as React,
|
||||
PropsWithChildren,
|
||||
ReactNode,
|
||||
useContext,
|
||||
useState,
|
||||
} from 'react';
|
||||
@@ -42,37 +39,6 @@ import { useNavigate } from 'react-router';
|
||||
import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';
|
||||
import { FavouriteEntity } from '../FavouriteEntity/FavouriteEntity';
|
||||
import { UnregisterEntityDialog } from '../UnregisterEntityDialog/UnregisterEntityDialog';
|
||||
import { TabbedLayout } from './TabbedLayout';
|
||||
|
||||
type SubRoute = {
|
||||
path: string;
|
||||
title: string;
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
const Route: (props: SubRoute) => null = () => null;
|
||||
|
||||
// This causes all mount points that are discovered within this route to use the path of the route itself
|
||||
attachComponentData(Route, 'core.gatherMountPoints', true);
|
||||
|
||||
export function createSubRoutesFromChildren(children: ReactNode): SubRoute[] {
|
||||
return Children.toArray(children).flatMap(child => {
|
||||
if (!isValidElement(child)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (child.type === Fragment) {
|
||||
return createSubRoutesFromChildren(child.props.children);
|
||||
}
|
||||
|
||||
if (child.type !== Route) {
|
||||
throw new Error('Child of EntityLayout must be an EntityLayout.Route');
|
||||
}
|
||||
|
||||
const { path, title, children } = child.props;
|
||||
return [{ path, title, children }];
|
||||
});
|
||||
}
|
||||
|
||||
const EntityLayoutTitle = ({
|
||||
entity,
|
||||
@@ -132,7 +98,6 @@ export const EntityLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { kind, namespace, name } = useEntityCompoundName();
|
||||
const { entity, loading, error } = useContext(EntityContext);
|
||||
|
||||
const routes = createSubRoutesFromChildren(children);
|
||||
const { headerTitle, headerType } = headerProps(
|
||||
kind,
|
||||
namespace,
|
||||
@@ -174,7 +139,7 @@ export const EntityLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
|
||||
{loading && <Progress />}
|
||||
|
||||
{entity && <TabbedLayout routes={routes} />}
|
||||
{entity && <TabbedLayout>{children}</TabbedLayout>}
|
||||
|
||||
{error && (
|
||||
<Content>
|
||||
@@ -191,4 +156,4 @@ export const EntityLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
);
|
||||
};
|
||||
|
||||
EntityLayout.Route = Route;
|
||||
EntityLayout.Route = TabbedLayout.Route;
|
||||
|
||||
@@ -1,150 +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 from 'react';
|
||||
import { TabbedLayout } from './TabbedLayout';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { Routes, Route } from 'react-router';
|
||||
|
||||
const testRoute1 = {
|
||||
path: '',
|
||||
title: 'tabbed-test-title',
|
||||
children: <div>tabbed-test-content</div>,
|
||||
};
|
||||
const testRoute2 = {
|
||||
title: 'tabbed-test-title-2',
|
||||
path: '/some-other-path',
|
||||
children: <div>tabbed-test-content-2</div>,
|
||||
};
|
||||
|
||||
describe('TabbedLayout', () => {
|
||||
it('renders simplest case', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<TabbedLayout routes={[testRoute1]} />,
|
||||
);
|
||||
|
||||
expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument();
|
||||
expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('navigates when user clicks different tab', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<Routes>
|
||||
<Route
|
||||
path="/*"
|
||||
element={<TabbedLayout routes={[testRoute1, testRoute2]} />}
|
||||
/>
|
||||
</Routes>,
|
||||
);
|
||||
|
||||
const secondTab = rendered.queryAllByRole('tab')[1];
|
||||
act(() => {
|
||||
fireEvent.click(secondTab);
|
||||
});
|
||||
|
||||
expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument();
|
||||
expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument();
|
||||
|
||||
expect(rendered.getByText('tabbed-test-title-2')).toBeInTheDocument();
|
||||
expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe('correctly delegates nested links', () => {
|
||||
const renderRoute = (route: string) =>
|
||||
renderInTestApp(
|
||||
<Routes>
|
||||
<Route
|
||||
path="/*"
|
||||
element={
|
||||
<TabbedLayout
|
||||
routes={[
|
||||
testRoute1,
|
||||
{
|
||||
...testRoute2,
|
||||
children: (
|
||||
<div>
|
||||
tabbed-test-content-2
|
||||
<Routes>
|
||||
<Route
|
||||
path="/nested"
|
||||
element={<div>tabbed-test-nested-content-2</div>}
|
||||
/>
|
||||
</Routes>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>,
|
||||
{ routeEntries: [route] },
|
||||
);
|
||||
|
||||
it('works for nested content', async () => {
|
||||
const rendered = await renderRoute('/some-other-path/nested');
|
||||
|
||||
expect(
|
||||
rendered.queryByText('tabbed-test-content'),
|
||||
).not.toBeInTheDocument();
|
||||
expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument();
|
||||
expect(
|
||||
rendered.queryByText('tabbed-test-nested-content-2'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('works for non-nested content', async () => {
|
||||
const rendered = await renderRoute('/some-other-path/');
|
||||
|
||||
expect(
|
||||
rendered.queryByText('tabbed-test-content'),
|
||||
).not.toBeInTheDocument();
|
||||
expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument();
|
||||
expect(
|
||||
rendered.queryByText('tabbed-test-nested-content-2'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows only one tab contents at a time', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<TabbedLayout routes={[testRoute1, testRoute2]} />,
|
||||
{ routeEntries: ['/some-other-path'] },
|
||||
);
|
||||
|
||||
expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument();
|
||||
expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument();
|
||||
|
||||
expect(rendered.getByText('tabbed-test-title-2')).toBeInTheDocument();
|
||||
expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('redirects to the top level when no route is matching the url', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<TabbedLayout routes={[testRoute1, testRoute2]} />,
|
||||
{ routeEntries: ['/non-existing-path'] },
|
||||
);
|
||||
|
||||
expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument();
|
||||
expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument();
|
||||
expect(rendered.getByText('tabbed-test-title-2')).toBeInTheDocument();
|
||||
|
||||
expect(
|
||||
rendered.queryByText('tabbed-test-content-2'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,75 +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, { useMemo } from 'react';
|
||||
import { useParams, useNavigate, matchRoutes, useRoutes } from 'react-router';
|
||||
import { HeaderTabs, Content as LayoutContent } from '@backstage/core';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { SubRoute } from './types';
|
||||
|
||||
export function useSelectedSubRoute(
|
||||
subRoutes: SubRoute[],
|
||||
): { index: number; route: SubRoute; element: JSX.Element } {
|
||||
const params = useParams();
|
||||
|
||||
const routes = subRoutes.map(({ path, children }) => ({
|
||||
caseSensitive: false,
|
||||
path: `${path}/*`,
|
||||
element: children,
|
||||
}));
|
||||
|
||||
const element = useRoutes(routes) ?? subRoutes[0].children;
|
||||
|
||||
const [matchedRoute] = matchRoutes(routes, `/${params['*']}`) ?? [];
|
||||
const foundIndex = matchedRoute
|
||||
? subRoutes.findIndex(t => `${t.path}/*` === matchedRoute.route.path)
|
||||
: 0;
|
||||
|
||||
return {
|
||||
index: foundIndex === -1 ? 0 : foundIndex,
|
||||
element,
|
||||
route: subRoutes[foundIndex] ?? subRoutes[0],
|
||||
};
|
||||
}
|
||||
|
||||
export const TabbedLayout = ({ routes }: { routes: SubRoute[] }) => {
|
||||
const navigate = useNavigate();
|
||||
const { index, route, element } = useSelectedSubRoute(routes);
|
||||
const headerTabs = useMemo(
|
||||
() => routes.map(t => ({ id: t.path, label: t.title })),
|
||||
[routes],
|
||||
);
|
||||
|
||||
const onTabChange = (index: number) =>
|
||||
// Remove trailing /*
|
||||
// And remove leading / for relative navigation
|
||||
// Note! route resolves relative to the position in the React tree,
|
||||
// not relative to current location
|
||||
navigate(routes[index].path.replace(/\/\*$/, '').replace(/^\//, ''));
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeaderTabs
|
||||
tabs={headerTabs}
|
||||
selectedIndex={index}
|
||||
onChange={onTabChange}
|
||||
/>
|
||||
<LayoutContent>
|
||||
<Helmet title={route.title} />
|
||||
{element}
|
||||
</LayoutContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -35,8 +35,8 @@ type SwitchCase = {
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
function createSwitchCasesFromChildren(children: ReactNode): SwitchCase[] {
|
||||
return Children.toArray(children).flatMap(child => {
|
||||
function createSwitchCasesFromChildren(childrenNode: ReactNode): SwitchCase[] {
|
||||
return Children.toArray(childrenNode).flatMap(child => {
|
||||
if (!isValidElement(child)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @backstage/plugin-circleci
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-circleci",
|
||||
"version": "0.2.6",
|
||||
"version": "0.2.7",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,10 +31,10 @@
|
||||
"postpack": "backstage-cli postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.1",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@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",
|
||||
@@ -50,8 +50,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# @backstage/plugin-cloudbuild
|
||||
|
||||
## 0.2.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-cloudbuild",
|
||||
"version": "0.2.7",
|
||||
"version": "0.2.8",
|
||||
"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.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@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",
|
||||
@@ -46,8 +46,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @backstage/plugin-cost-insights
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 19172f5a9: add alert hooks
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4c6a6dddd: Fixed date calculations incorrectly converting to UTC in some cases. This should be a transparent change.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/theme@0.2.3
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-cost-insights",
|
||||
"version": "0.7.0",
|
||||
"version": "0.8.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,8 +31,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@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",
|
||||
@@ -55,8 +55,8 @@
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -124,18 +124,18 @@ export const AlertInsights = ({
|
||||
setSnackbarOpen(!!error);
|
||||
}, [error]);
|
||||
|
||||
function onSnooze(alert: Alert) {
|
||||
setAlert(alert);
|
||||
function onSnooze(alertToSnooze: Alert) {
|
||||
setAlert(alertToSnooze);
|
||||
setStatus(AlertStatus.Snoozed);
|
||||
}
|
||||
|
||||
function onAccept(alert: Alert) {
|
||||
setAlert(alert);
|
||||
function onAccept(alertToAccept: Alert) {
|
||||
setAlert(alertToAccept);
|
||||
setStatus(AlertStatus.Accepted);
|
||||
}
|
||||
|
||||
function onDismiss(alert: Alert) {
|
||||
setAlert(alert);
|
||||
function onDismiss(alertToDismiss: Alert) {
|
||||
setAlert(alertToDismiss);
|
||||
setStatus(AlertStatus.Dismissed);
|
||||
}
|
||||
|
||||
@@ -148,8 +148,8 @@ export const AlertInsights = ({
|
||||
setStatus(null);
|
||||
}
|
||||
|
||||
function onDialogFormSubmit(data: any) {
|
||||
setData(data);
|
||||
function onDialogFormSubmit(formData: any) {
|
||||
setData(formData);
|
||||
}
|
||||
|
||||
function onSummaryButtonClick() {
|
||||
@@ -175,10 +175,10 @@ export const AlertInsights = ({
|
||||
</Grid>
|
||||
{isAlertInsightSectionDisplayed && (
|
||||
<Grid item container direction="column" spacing={4}>
|
||||
{active.map((alert, index) => (
|
||||
{active.map((activeAlert, index) => (
|
||||
<Grid item key={`alert-insights-section-${index}`}>
|
||||
<AlertInsightsSection
|
||||
alert={alert}
|
||||
alert={activeAlert}
|
||||
number={index + 1}
|
||||
onSnooze={onSnooze}
|
||||
onAccept={onAccept}
|
||||
|
||||
@@ -18,7 +18,7 @@ import React, { PropsWithChildren } from 'react';
|
||||
import { Box, Typography } from '@material-ui/core';
|
||||
import { useBarChartLabelStyles } from '../../utils/styles';
|
||||
|
||||
type BarChartLabel = {
|
||||
type BarChartLabelProps = {
|
||||
x: number;
|
||||
y: number;
|
||||
height: number;
|
||||
@@ -33,7 +33,7 @@ export const BarChartLabel = ({
|
||||
width,
|
||||
details,
|
||||
children,
|
||||
}: PropsWithChildren<BarChartLabel>) => {
|
||||
}: PropsWithChildren<BarChartLabelProps>) => {
|
||||
const classes = useBarChartLabelStyles();
|
||||
const translateX = width * -0.5;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import React from 'react';
|
||||
import { ButtonBase } from '@material-ui/core';
|
||||
import { useBarChartStepperStyles as useStyles } from '../../utils/styles';
|
||||
|
||||
export type BarChartSteps = {
|
||||
export type BarChartStepsProps = {
|
||||
steps: number;
|
||||
activeStep: number;
|
||||
onClick: (index: number) => void;
|
||||
@@ -28,7 +28,7 @@ export const BarChartSteps = ({
|
||||
steps,
|
||||
activeStep,
|
||||
onClick,
|
||||
}: BarChartSteps) => {
|
||||
}: BarChartStepsProps) => {
|
||||
const classes = useStyles();
|
||||
const handleOnClick = (index: number) => (
|
||||
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
||||
|
||||
@@ -82,12 +82,7 @@ export const ProductInsights = ({
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
async function getAllProductInsights(
|
||||
group: string,
|
||||
project: Maybe<string>,
|
||||
products: Product[],
|
||||
lastCompleteBillingDate: string,
|
||||
) {
|
||||
async function getAllProductInsights() {
|
||||
try {
|
||||
dispatchLoadingProducts(true);
|
||||
const responses = await Promise.allSettled(
|
||||
@@ -101,10 +96,10 @@ export const ProductInsights = ({
|
||||
),
|
||||
).then(settledResponseOf);
|
||||
|
||||
const initialStates = initialStatesOf(products, responses).sort(
|
||||
const updatedInitialStates = initialStatesOf(products, responses).sort(
|
||||
totalAggregationSort,
|
||||
);
|
||||
setStates(initialStates);
|
||||
setStates(updatedInitialStates);
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
} finally {
|
||||
@@ -112,7 +107,7 @@ export const ProductInsights = ({
|
||||
}
|
||||
}
|
||||
|
||||
getAllProductInsights(group, project, products, lastCompleteBillingDate);
|
||||
getAllProductInsights();
|
||||
}, [
|
||||
client,
|
||||
group,
|
||||
@@ -125,8 +120,8 @@ export const ProductInsights = ({
|
||||
useEffect(
|
||||
function handleOnLoaded() {
|
||||
if (onceRef.current) {
|
||||
const products = initialStates.map(state => state.product);
|
||||
onLoaded(products);
|
||||
const initialProducts = initialStates.map(state => state.product);
|
||||
onLoaded(initialProducts);
|
||||
} else {
|
||||
onceRef.current = true;
|
||||
}
|
||||
|
||||
@@ -76,13 +76,13 @@ describe('getPreviousPeriodTotalCost', () => {
|
||||
change: changeOf(MockAggregatedDailyCosts),
|
||||
trendline: trendlineOf(MockAggregatedDailyCosts),
|
||||
};
|
||||
const exclusiveEndDate = '2020-09-30';
|
||||
const inclusiveEndDate = '2020-09-30';
|
||||
expect(
|
||||
getPreviousPeriodTotalCost(
|
||||
mockGroupDailyCost.aggregation,
|
||||
Duration.P30D,
|
||||
exclusiveEndDate,
|
||||
inclusiveEndDate,
|
||||
),
|
||||
).toEqual(100_000);
|
||||
).toEqual(96_600);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,14 +22,13 @@ import {
|
||||
GrowthType,
|
||||
MetricData,
|
||||
Duration,
|
||||
DEFAULT_DATE_FORMAT,
|
||||
DateAggregation,
|
||||
} from '../types';
|
||||
import dayjs, { OpUnitType } from 'dayjs';
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import durationPlugin from 'dayjs/plugin/duration';
|
||||
import { inclusiveStartDateOf } from './duration';
|
||||
|
||||
dayjs.extend(duration);
|
||||
dayjs.extend(durationPlugin);
|
||||
|
||||
// Used for displaying status colors
|
||||
export function growthOf(ratio: number, amount?: number) {
|
||||
@@ -73,10 +72,7 @@ export function getPreviousPeriodTotalCost(
|
||||
inclusiveEndDate: string,
|
||||
): number {
|
||||
const dayjsDuration = dayjs.duration(duration);
|
||||
const startDate = inclusiveStartDateOf(
|
||||
duration,
|
||||
dayjs(inclusiveEndDate).add(1, 'day').format(DEFAULT_DATE_FORMAT),
|
||||
);
|
||||
const startDate = inclusiveStartDateOf(duration, inclusiveEndDate);
|
||||
// dayjs doesn't allow adding an ISO 8601 period to dates.
|
||||
const [amount, type]: [number, OpUnitType] = dayjsDuration.days()
|
||||
? [dayjsDuration.days(), 'day']
|
||||
|
||||
@@ -24,23 +24,21 @@ export const DEFAULT_DURATION = Duration.P30D;
|
||||
* Derive the start date of a given period, assuming two repeating intervals.
|
||||
*
|
||||
* @param duration see comment on Duration enum
|
||||
* @param exclusiveEndDate from CostInsightsApi.getLastCompleteBillingDate + 1 day
|
||||
* @param inclusiveEndDate from CostInsightsApi.getLastCompleteBillingDate
|
||||
*/
|
||||
export function inclusiveStartDateOf(
|
||||
duration: Duration,
|
||||
exclusiveEndDate: string,
|
||||
inclusiveEndDate: string,
|
||||
): string {
|
||||
switch (duration) {
|
||||
case Duration.P7D:
|
||||
case Duration.P30D:
|
||||
case Duration.P90D:
|
||||
return moment(exclusiveEndDate)
|
||||
.utc()
|
||||
return moment(inclusiveEndDate)
|
||||
.subtract(moment.duration(duration).add(moment.duration(duration)))
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
case Duration.P3M:
|
||||
return moment(exclusiveEndDate)
|
||||
.utc()
|
||||
return moment(inclusiveEndDate)
|
||||
.startOf('quarter')
|
||||
.subtract(moment.duration(duration).add(moment.duration(duration)))
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
@@ -57,13 +55,9 @@ export function exclusiveEndDateOf(
|
||||
case Duration.P7D:
|
||||
case Duration.P30D:
|
||||
case Duration.P90D:
|
||||
return moment(inclusiveEndDate)
|
||||
.utc()
|
||||
.add(1, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
return moment(inclusiveEndDate).add(1, 'day').format(DEFAULT_DATE_FORMAT);
|
||||
case Duration.P3M:
|
||||
return moment(quarterEndDate(inclusiveEndDate))
|
||||
.utc()
|
||||
.add(1, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
default:
|
||||
@@ -76,7 +70,6 @@ export function inclusiveEndDateOf(
|
||||
inclusiveEndDate: string,
|
||||
): string {
|
||||
return moment(exclusiveEndDateOf(duration, inclusiveEndDate))
|
||||
.utc()
|
||||
.subtract(1, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
}
|
||||
@@ -94,7 +87,7 @@ export function intervalsOf(
|
||||
}
|
||||
|
||||
export function quarterEndDate(inclusiveEndDate: string): string {
|
||||
const endDate = moment(inclusiveEndDate).utc();
|
||||
const endDate = moment(inclusiveEndDate);
|
||||
const endOfQuarter = endDate.endOf('quarter').format(DEFAULT_DATE_FORMAT);
|
||||
if (endOfQuarter === inclusiveEndDate) {
|
||||
return endDate.format(DEFAULT_DATE_FORMAT);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import moment from 'moment';
|
||||
import pluralize from 'pluralize';
|
||||
import { Duration, DEFAULT_DATE_FORMAT } from '../types';
|
||||
import { Duration } from '../types';
|
||||
import { inclusiveEndDateOf, inclusiveStartDateOf } from '../utils/duration';
|
||||
|
||||
export type Period = {
|
||||
@@ -92,11 +92,8 @@ export function formatPercent(n: number): string {
|
||||
}
|
||||
|
||||
export function formatLastTwoLookaheadQuarters(inclusiveEndDate: string) {
|
||||
const exclusiveEndDate = moment(inclusiveEndDate)
|
||||
.add(1, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
const start = moment(
|
||||
inclusiveStartDateOf(Duration.P3M, exclusiveEndDate),
|
||||
inclusiveStartDateOf(Duration.P3M, inclusiveEndDate),
|
||||
).format('[Q]Q YYYY');
|
||||
const end = moment(inclusiveEndDateOf(Duration.P3M, inclusiveEndDate)).format(
|
||||
'[Q]Q YYYY',
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
getDefaultState as getDefaultLoadingState,
|
||||
} from '../utils/loading';
|
||||
import { findAlways } from '../utils/assert';
|
||||
import { inclusiveStartDateOf } from './duration';
|
||||
import { inclusiveEndDateOf, inclusiveStartDateOf } from './duration';
|
||||
|
||||
type mockAlertRenderer<T> = (alert: T) => T;
|
||||
type mockEntityRenderer<T> = (entity: T) => T;
|
||||
@@ -228,8 +228,9 @@ export function aggregationFor(
|
||||
baseline: number,
|
||||
): DateAggregation[] {
|
||||
const { duration, endDate } = parseIntervals(intervals);
|
||||
const inclusiveEndDate = inclusiveEndDateOf(duration, endDate);
|
||||
const days = dayjs(endDate).diff(
|
||||
inclusiveStartDateOf(duration, endDate),
|
||||
inclusiveStartDateOf(duration, inclusiveEndDate),
|
||||
'day',
|
||||
);
|
||||
|
||||
@@ -244,7 +245,7 @@ export function aggregationFor(
|
||||
return [...Array(days).keys()].reduce(
|
||||
(values: DateAggregation[], i: number): DateAggregation[] => {
|
||||
const last = values.length ? values[values.length - 1].amount : baseline;
|
||||
const date = dayjs(inclusiveStartDateOf(duration, endDate))
|
||||
const date = dayjs(inclusiveStartDateOf(duration, inclusiveEndDate))
|
||||
.add(i, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
const amount = Math.max(0, last + nextDelta());
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint')],
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
# @backstage/plugin-explore-react
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- @backstage/core@0.6.0
|
||||
@@ -0,0 +1,4 @@
|
||||
# explore-react
|
||||
|
||||
This package provides helpers to the `explore` plugin that can be imported by
|
||||
any other plugin or app.
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "@backstage/plugin-explore-react",
|
||||
"version": "0.0.2",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/explore-react"
|
||||
},
|
||||
"keywords": [
|
||||
"backstage"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli plugin:build",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test",
|
||||
"clean": "backstage-cli clean",
|
||||
"prepack": "backstage-cli prepack",
|
||||
"postpack": "backstage-cli postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/node": "^12.0.0",
|
||||
"cross-fetch": "^3.0.6",
|
||||
"msw": "^0.21.2"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
+1
-5
@@ -14,8 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type SubRoute = {
|
||||
path: string;
|
||||
title: string;
|
||||
children: JSX.Element;
|
||||
};
|
||||
export * from './tools';
|
||||
+1
-10
@@ -14,13 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Route, Routes } from 'react-router';
|
||||
import { ExplorePluginPage } from './ExplorePluginPage';
|
||||
import { rootRouteRef } from '../plugin';
|
||||
|
||||
export const Router = () => (
|
||||
<Routes>
|
||||
<Route path={`/${rootRouteRef.path}`} element={<ExplorePluginPage />} />
|
||||
</Routes>
|
||||
);
|
||||
import '@testing-library/jest-dom';
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 { exploreToolsConfigRef } from './api';
|
||||
|
||||
describe('api', () => {
|
||||
// This is a dummy test to have at least one test in the package.
|
||||
it('api ref exists', () => {
|
||||
expect(exploreToolsConfigRef.id).toBe('plugin.explore.toolsconfig');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 { createApiRef } from '@backstage/core';
|
||||
|
||||
export const exploreToolsConfigRef = createApiRef<ExploreToolsConfig>({
|
||||
id: 'plugin.explore.toolsconfig',
|
||||
description: 'Used to configure tools displayed in the explore plugin',
|
||||
});
|
||||
|
||||
export type ExploreTool = {
|
||||
title: string;
|
||||
description?: string;
|
||||
url: string;
|
||||
image: string;
|
||||
tags?: string[];
|
||||
lifecycle?: string;
|
||||
newsTag?: string;
|
||||
};
|
||||
|
||||
export interface ExploreToolsConfig {
|
||||
getTools: () => Promise<ExploreTool[]>;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { exploreToolsConfigRef } from './api';
|
||||
export type { ExploreTool, ExploreToolsConfig } from './api';
|
||||
@@ -1,5 +1,40 @@
|
||||
# @backstage/plugin-explore
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 54c7d02f7: Introduce `TabbedLayout` for creating tabs that are routed.
|
||||
|
||||
```typescript
|
||||
<TabbedLayout>
|
||||
<TabbedLayout.Route path="/example" title="Example tab">
|
||||
<div>This is rendered under /example/anything-here route</div>
|
||||
</TabbedLayout.Route>
|
||||
</TabbedLayout>
|
||||
```
|
||||
|
||||
- 806929fe2: Rework the explore plugin to allow the user to explore things in the ecosystem,
|
||||
including tools and domains.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
- @backstage/plugin-explore-react@0.0.2
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,32 @@
|
||||
# Title
|
||||
# explore
|
||||
|
||||
Welcome to the explore plugin!
|
||||
This plugin helps to visualize the domains and tools in your ecosystem.
|
||||
|
||||
## Sub-section 1
|
||||
## Getting started
|
||||
|
||||
## Sub-section 2
|
||||
To install the plugin, include the following import your `plugins.ts`:
|
||||
|
||||
```typescript
|
||||
export { explorePlugin } from '@backstage/plugin-explore';
|
||||
```
|
||||
|
||||
Register the route in `App.tsx`:
|
||||
|
||||
```typescript
|
||||
import { ExplorePage } from '@backstage/plugin-explore';
|
||||
|
||||
...
|
||||
|
||||
<Route path="/explore" element={<ExplorePage />} />
|
||||
```
|
||||
|
||||
Add a link to the sidebar in `Root.tsx`:
|
||||
|
||||
```typescript
|
||||
import LayersIcon from '@material-ui/icons/Layers';
|
||||
|
||||
...
|
||||
|
||||
<SidebarItem icon={LayersIcon} to="explore" text="Explore" />
|
||||
```
|
||||
|
||||
@@ -14,7 +14,59 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { createDevApp } from '@backstage/dev-utils';
|
||||
import { plugin } from '../src/plugin';
|
||||
import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { exploreToolsConfigRef } from '@backstage/plugin-explore-react';
|
||||
import React from 'react';
|
||||
import { ExplorePage, explorePlugin } from '../src';
|
||||
import { exampleTools } from '../src/util/examples';
|
||||
|
||||
createDevApp().registerPlugin(plugin).render();
|
||||
createDevApp()
|
||||
.registerPlugin(explorePlugin)
|
||||
.registerApi({
|
||||
api: exploreToolsConfigRef,
|
||||
deps: {},
|
||||
factory: () => ({
|
||||
async getTools() {
|
||||
return exampleTools;
|
||||
},
|
||||
}),
|
||||
})
|
||||
.registerApi({
|
||||
api: catalogApiRef,
|
||||
deps: {},
|
||||
factory: () =>
|
||||
({
|
||||
async getEntities() {
|
||||
const domainNames = [
|
||||
'playback',
|
||||
'artists',
|
||||
'payments',
|
||||
'analytics',
|
||||
'songs',
|
||||
'devops',
|
||||
];
|
||||
|
||||
return {
|
||||
items: domainNames.map(
|
||||
(n, i) =>
|
||||
({
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Domain',
|
||||
metadata: {
|
||||
name: n,
|
||||
description: `Everything about ${n}`,
|
||||
tags: i % 2 === 0 ? [n] : undefined,
|
||||
},
|
||||
spec: {
|
||||
owner: `${n}@example.com`,
|
||||
},
|
||||
} as Entity),
|
||||
),
|
||||
};
|
||||
},
|
||||
} as CatalogApi),
|
||||
})
|
||||
.addPage({ element: <ExplorePage />, title: 'Explore' })
|
||||
.render();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-explore",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,20 +30,23 @@
|
||||
"start": "backstage-cli plugin:serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@backstage/plugin-explore-react": "^0.0.2",
|
||||
"@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",
|
||||
"classnames": "^2.2.6",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-router": "6.0.0-beta.0",
|
||||
"react-router-dom": "6.0.0-beta.0",
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 { DomainEntity } from '@backstage/catalog-model';
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { DomainCard } from './DomainCard';
|
||||
|
||||
describe('<DomainCard />', () => {
|
||||
it('renders a domain card', () => {
|
||||
const entity: DomainEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Domain',
|
||||
metadata: {
|
||||
name: 'artists',
|
||||
description: 'Everything about artists',
|
||||
tags: ['a-tag'],
|
||||
},
|
||||
spec: {
|
||||
owner: 'guest',
|
||||
},
|
||||
};
|
||||
const { getByText } = render(<DomainCard entity={entity} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
expect(getByText('artists')).toBeInTheDocument();
|
||||
expect(getByText('Everything about artists')).toBeInTheDocument();
|
||||
expect(getByText('a-tag')).toBeInTheDocument();
|
||||
expect(getByText('Explore').parentElement).toHaveAttribute(
|
||||
'href',
|
||||
'/catalog/default/domain/artists',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 { DomainEntity } from '@backstage/catalog-model';
|
||||
import { ItemCard } from '@backstage/core';
|
||||
import {
|
||||
entityRoute,
|
||||
entityRouteParams,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import React from 'react';
|
||||
import { generatePath } from 'react-router-dom';
|
||||
|
||||
type DomainCardProps = {
|
||||
entity: DomainEntity;
|
||||
};
|
||||
|
||||
export const DomainCard = ({ entity }: DomainCardProps) => (
|
||||
<ItemCard
|
||||
title={entity.metadata.name}
|
||||
description={entity.metadata.description}
|
||||
tags={entity.metadata.tags}
|
||||
label="Explore"
|
||||
// TODO: Use useRouteRef here to generate the path
|
||||
href={generatePath(
|
||||
`/catalog/${entityRoute.path}`,
|
||||
entityRouteParams(entity),
|
||||
)}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 { DomainEntity } from '@backstage/catalog-model';
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { DomainCardGrid } from './DomainCardGrid';
|
||||
|
||||
describe('<DomainCardGrid />', () => {
|
||||
it('renders a grid of domain cards', () => {
|
||||
const entities: DomainEntity[] = [
|
||||
{
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Domain',
|
||||
metadata: {
|
||||
name: 'playback',
|
||||
},
|
||||
spec: {
|
||||
owner: 'guest',
|
||||
},
|
||||
},
|
||||
{
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Domain',
|
||||
metadata: {
|
||||
name: 'artists',
|
||||
},
|
||||
spec: {
|
||||
owner: 'guest',
|
||||
},
|
||||
},
|
||||
];
|
||||
const { getByText } = render(<DomainCardGrid entities={entities} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
expect(getByText('artists')).toBeInTheDocument();
|
||||
expect(getByText('playback')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 { DomainEntity } from '@backstage/catalog-model';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { DomainCard } from '.';
|
||||
|
||||
type DomainCardGridProps = {
|
||||
entities: DomainEntity[];
|
||||
};
|
||||
|
||||
export const DomainCardGrid = ({ entities }: DomainCardGridProps) => (
|
||||
<Grid container spacing={4}>
|
||||
{entities.map((e, i) => (
|
||||
<Grid item xs={12} md={3} key={i}>
|
||||
<DomainCard entity={e} />
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { DomainCard } from './DomainCard';
|
||||
export { DomainCardGrid } from './DomainCardGrid';
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 { DomainEntity } from '@backstage/catalog-model';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { DomainExplorerContent } from './DomainExplorerContent';
|
||||
|
||||
describe('<DomainExplorerContent />', () => {
|
||||
const catalogApi: jest.Mocked<typeof catalogApiRef.T> = {
|
||||
addLocation: jest.fn(_a => new Promise(() => {})),
|
||||
getEntities: jest.fn(),
|
||||
getLocationByEntity: jest.fn(),
|
||||
getLocationById: jest.fn(),
|
||||
removeEntityByUid: jest.fn(),
|
||||
getEntityByName: jest.fn(),
|
||||
};
|
||||
|
||||
const Wrapper = ({ children }: { children?: React.ReactNode }) => (
|
||||
<MemoryRouter>
|
||||
<ApiProvider apis={ApiRegistry.with(catalogApiRef, catalogApi)}>
|
||||
{children}
|
||||
</ApiProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('renders a grid of domains', async () => {
|
||||
const entities: DomainEntity[] = [
|
||||
{
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Domain',
|
||||
metadata: {
|
||||
name: 'playback',
|
||||
},
|
||||
spec: {
|
||||
owner: 'guest',
|
||||
},
|
||||
},
|
||||
{
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Domain',
|
||||
metadata: {
|
||||
name: 'artists',
|
||||
},
|
||||
spec: {
|
||||
owner: 'guest',
|
||||
},
|
||||
},
|
||||
];
|
||||
catalogApi.getEntities.mockResolvedValue({ items: entities });
|
||||
|
||||
const { getByText } = render(<DomainExplorerContent />, {
|
||||
wrapper: Wrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('artists')).toBeInTheDocument();
|
||||
expect(getByText('playback')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders empty state', async () => {
|
||||
catalogApi.getEntities.mockResolvedValue({ items: [] });
|
||||
|
||||
const { getByText } = render(<DomainExplorerContent />, {
|
||||
wrapper: Wrapper,
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(getByText('No domains to display')).toBeInTheDocument(),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 { DomainEntity } from '@backstage/catalog-model';
|
||||
import {
|
||||
Content,
|
||||
ContentHeader,
|
||||
EmptyState,
|
||||
Progress,
|
||||
SupportButton,
|
||||
useApi,
|
||||
} from '@backstage/core';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { Button } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import { DomainCardGrid } from '../DomainCard';
|
||||
|
||||
export const DomainExplorerContent = () => {
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const { value: entities, loading } = useAsync(async () => {
|
||||
const response = await catalogApi.getEntities({
|
||||
filter: { kind: 'domain' },
|
||||
});
|
||||
|
||||
return response.items as DomainEntity[];
|
||||
}, [catalogApi]);
|
||||
|
||||
return (
|
||||
<Content noPadding>
|
||||
<ContentHeader title="Domains">
|
||||
<SupportButton>Discover the domains in your ecosystem.</SupportButton>
|
||||
</ContentHeader>
|
||||
|
||||
{loading && <Progress />}
|
||||
{!loading && (!entities || entities.length === 0) && (
|
||||
<EmptyState
|
||||
missing="info"
|
||||
title="No domains to display"
|
||||
description={`You haven't added any domains yet.`}
|
||||
action={
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
href="https://backstage.io/docs/features/software-catalog/descriptor-format#kind-domain"
|
||||
>
|
||||
Read more
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{!loading && entities && <DomainCardGrid entities={entities} />}
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { DomainExplorerContent } from './DomainExplorerContent';
|
||||
+12
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
* 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.
|
||||
@@ -13,28 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { configApiRef, Header, Page, useApi } from '@backstage/core';
|
||||
import React from 'react';
|
||||
import { Content, Header, Page } from '@backstage/core';
|
||||
import { RollbarProjectTable } from '../RollbarProjectTable/RollbarProjectTable';
|
||||
import { useRollbarEntities } from '../../hooks/useRollbarEntities';
|
||||
|
||||
export const RollbarHome = () => {
|
||||
const { entities, loading, error } = useRollbarEntities();
|
||||
import { ExploreTabs } from './ExploreTabs';
|
||||
|
||||
export const ExplorePage = () => {
|
||||
const configApi = useApi(configApiRef);
|
||||
const organizationName =
|
||||
configApi.getOptionalString('organization.name') ?? 'Backstage';
|
||||
return (
|
||||
<Page themeId="tool">
|
||||
<Page themeId="home">
|
||||
<Header
|
||||
title="Rollbar"
|
||||
subtitle="Real-time error tracking & debugging tools for developers"
|
||||
title={`Explore the ${organizationName} ecosystem`}
|
||||
subtitle="Discover solutions available in your ecosystem"
|
||||
/>
|
||||
<Content>
|
||||
<RollbarProjectTable
|
||||
entities={entities || []}
|
||||
loading={loading}
|
||||
error={error}
|
||||
/>
|
||||
</Content>
|
||||
|
||||
<ExploreTabs />
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 { TabbedLayout } from '@backstage/core';
|
||||
import React from 'react';
|
||||
import { DomainExplorerContent } from '../DomainExplorerContent';
|
||||
import { ToolExplorerContent } from '../ToolExplorerContent';
|
||||
|
||||
export const ExploreTabs = () => (
|
||||
<TabbedLayout>
|
||||
<TabbedLayout.Route path="domains" title="Domains">
|
||||
<DomainExplorerContent />
|
||||
</TabbedLayout.Route>
|
||||
<TabbedLayout.Route path="tools" title="Tools">
|
||||
<ToolExplorerContent />
|
||||
</TabbedLayout.Route>
|
||||
</TabbedLayout>
|
||||
);
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { ExplorePage } from './ExplorePage';
|
||||
+15
-22
@@ -14,11 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
|
||||
import ExploreCard from './ExploreCard';
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { ToolCard } from './ToolCard';
|
||||
|
||||
const minProps = {
|
||||
card: {
|
||||
@@ -30,37 +29,31 @@ const minProps = {
|
||||
},
|
||||
};
|
||||
|
||||
describe('<ExploreCard />', () => {
|
||||
describe('<ToolCard />', () => {
|
||||
it('renders without exploding', () => {
|
||||
const { getByText } = render(wrapInTestApp(<ExploreCard {...minProps} />));
|
||||
const { getByText } = render(wrapInTestApp(<ToolCard {...minProps} />));
|
||||
expect(getByText('Explore')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders props correctly', () => {
|
||||
const { getByText } = render(wrapInTestApp(<ExploreCard {...minProps} />));
|
||||
const { getByText } = render(wrapInTestApp(<ToolCard {...minProps} />));
|
||||
expect(getByText(minProps.card.title)).toBeInTheDocument();
|
||||
expect(getByText(minProps.card.description)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should link out', () => {
|
||||
const rendered = render(wrapInTestApp(<ExploreCard {...minProps} />));
|
||||
const rendered = render(wrapInTestApp(<ToolCard {...minProps} />));
|
||||
const anchor = rendered.container.querySelector('a');
|
||||
expect(anchor.href).toBe(minProps.card.url);
|
||||
expect(anchor).toHaveAttribute('href', minProps.card.url);
|
||||
});
|
||||
|
||||
it('renders default description when missing', () => {
|
||||
const propsWithoutDescription = {
|
||||
card: {
|
||||
card: {
|
||||
title: 'Title',
|
||||
url: 'http://spotify.com/',
|
||||
image: 'https://developer.spotify.com/assets/WebAPI_intro.png',
|
||||
},
|
||||
},
|
||||
const card = {
|
||||
title: 'Title',
|
||||
url: 'http://spotify.com/',
|
||||
image: 'https://developer.spotify.com/assets/WebAPI_intro.png',
|
||||
};
|
||||
const { getByText } = render(
|
||||
wrapInTestApp(<ExploreCard {...propsWithoutDescription} />),
|
||||
);
|
||||
const { getByText } = render(wrapInTestApp(<ToolCard card={card} />));
|
||||
expect(getByText('Description missing')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -74,13 +67,13 @@ describe('<ExploreCard />', () => {
|
||||
},
|
||||
};
|
||||
const { queryByText } = render(
|
||||
wrapInTestApp(<ExploreCard {...propsWithLifecycle} />),
|
||||
wrapInTestApp(<ToolCard {...propsWithLifecycle} />),
|
||||
);
|
||||
expect(queryByText('GA')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders tags correctly', () => {
|
||||
const { getByText } = render(wrapInTestApp(<ExploreCard {...minProps} />));
|
||||
const { getByText } = render(wrapInTestApp(<ToolCard {...minProps} />));
|
||||
expect(getByText(minProps.card.tags[0])).toBeInTheDocument();
|
||||
expect(getByText(minProps.card.tags[1])).toBeInTheDocument();
|
||||
});
|
||||
+9
-18
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { ExploreTool } from '@backstage/plugin-explore-react';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@@ -23,10 +23,13 @@ import {
|
||||
CardContent,
|
||||
CardMedia,
|
||||
Chip,
|
||||
Typography,
|
||||
makeStyles,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
// TODO: Align styling between Domain and ToolCard
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
card: {
|
||||
@@ -65,22 +68,12 @@ const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
},
|
||||
}));
|
||||
|
||||
export type CardData = {
|
||||
title: string;
|
||||
description: string;
|
||||
url: string;
|
||||
image: string;
|
||||
tags?: string[];
|
||||
lifecycle?: string;
|
||||
newsTag?: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
card: CardData;
|
||||
card: ExploreTool;
|
||||
objectFit?: 'cover' | 'contain';
|
||||
};
|
||||
|
||||
const ExploreCard = ({ card, objectFit }: Props) => {
|
||||
export const ToolCard = ({ card, objectFit }: Props) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const { title, description, url, image, lifecycle, newsTag, tags } = card;
|
||||
@@ -130,5 +123,3 @@ const ExploreCard = ({ card, objectFit }: Props) => {
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExploreCard;
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 { ExploreTool } from '@backstage/plugin-explore-react';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { ToolCard } from './ToolCard';
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
container: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fill, 296px)',
|
||||
gridGap: theme.spacing(3),
|
||||
marginBottom: theme.spacing(6),
|
||||
},
|
||||
}));
|
||||
|
||||
type ToolCardGridProps = {
|
||||
tools: ExploreTool[];
|
||||
};
|
||||
|
||||
export const ToolCardGrid = ({ tools }: ToolCardGridProps) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
{tools.map((card: ExploreTool, ix: any) => (
|
||||
<ToolCard card={card} key={ix} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { ToolCard } from './ToolCard';
|
||||
export { ToolCardGrid } from './ToolCardGrid';
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 { ApiProvider, ApiRegistry } from '@backstage/core';
|
||||
import {
|
||||
ExploreTool,
|
||||
exploreToolsConfigRef,
|
||||
} from '@backstage/plugin-explore-react';
|
||||
import { lightTheme } from '@backstage/theme';
|
||||
import { ThemeProvider } from '@material-ui/core';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { ToolExplorerContent } from './ToolExplorerContent';
|
||||
|
||||
describe('<ToolExplorerContent />', () => {
|
||||
const exploreToolsConfigApi: jest.Mocked<typeof exploreToolsConfigRef.T> = {
|
||||
getTools: jest.fn(),
|
||||
};
|
||||
|
||||
const Wrapper = ({ children }: { children?: React.ReactNode }) => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<MemoryRouter>
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(exploreToolsConfigRef, exploreToolsConfigApi)}
|
||||
>
|
||||
{children}
|
||||
</ApiProvider>
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('renders a grid of tools', async () => {
|
||||
const tools: ExploreTool[] = [
|
||||
{
|
||||
title: 'Lighthouse',
|
||||
description:
|
||||
"Google's Lighthouse tool is a great resource for benchmarking and improving the accessibility, performance, SEO, and best practices of your website.",
|
||||
url: '/lighthouse',
|
||||
image:
|
||||
'https://raw.githubusercontent.com/GoogleChrome/lighthouse/8b3d7f052b2e64dd857e741d7395647f487697e7/assets/lighthouse-logo.png',
|
||||
tags: ['web', 'seo', 'accessibility', 'performance'],
|
||||
},
|
||||
{
|
||||
title: 'Tech Radar',
|
||||
description:
|
||||
'Tech Radar is a list of technologies, complemented by an assessment result, called ring assignment.',
|
||||
url: '/tech-radar',
|
||||
image:
|
||||
'https://storage.googleapis.com/wf-blogs-engineering-media/2018/09/fe13bb32-wf-tech-radar-hero-1024x597.png',
|
||||
tags: ['standards', 'landscape'],
|
||||
},
|
||||
];
|
||||
exploreToolsConfigApi.getTools.mockResolvedValue(tools);
|
||||
|
||||
const { getByText } = render(<ToolExplorerContent />, {
|
||||
wrapper: Wrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Lighthouse')).toBeInTheDocument();
|
||||
expect(getByText('Tech Radar')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders empty state', async () => {
|
||||
exploreToolsConfigApi.getTools.mockResolvedValue([]);
|
||||
|
||||
const { getByText } = render(<ToolExplorerContent />, {
|
||||
wrapper: Wrapper,
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(getByText('No tools to display')).toBeInTheDocument(),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 {
|
||||
Content,
|
||||
ContentHeader,
|
||||
EmptyState,
|
||||
Progress,
|
||||
SupportButton,
|
||||
useApi,
|
||||
} from '@backstage/core';
|
||||
import { exploreToolsConfigRef } from '@backstage/plugin-explore-react';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import { ToolCardGrid } from '../ToolCard';
|
||||
|
||||
export const ToolExplorerContent = () => {
|
||||
const exploreToolsConfigApi = useApi(exploreToolsConfigRef);
|
||||
const { value: tools, loading } = useAsync(async () => {
|
||||
return await exploreToolsConfigApi.getTools();
|
||||
}, [exploreToolsConfigApi]);
|
||||
|
||||
return (
|
||||
<Content noPadding>
|
||||
<ContentHeader title="Tools">
|
||||
<SupportButton>Discover the tools in your ecosystem.</SupportButton>
|
||||
</ContentHeader>
|
||||
|
||||
{loading && <Progress />}
|
||||
{!loading && (!tools || tools.length === 0) && (
|
||||
<EmptyState
|
||||
missing="info"
|
||||
title="No tools to display"
|
||||
description={`You haven't added any tools yet.`}
|
||||
/>
|
||||
)}
|
||||
{!loading && tools && <ToolCardGrid tools={tools} />}
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { ToolExplorerContent } from './ToolExplorerContent';
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 { createRoutableExtension } from '@backstage/core';
|
||||
import { explorePlugin } from './plugin';
|
||||
import { exploreRouteRef } from './routes';
|
||||
|
||||
export const ExplorePage = explorePlugin.provide(
|
||||
createRoutableExtension({
|
||||
component: () =>
|
||||
import('./components/ExplorePage').then(m => m.ExplorePage),
|
||||
mountPoint: exploreRouteRef,
|
||||
}),
|
||||
);
|
||||
@@ -14,5 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { plugin } from './plugin';
|
||||
export { Router } from './components/Router';
|
||||
export * from './extensions';
|
||||
export { explorePlugin } from './plugin';
|
||||
export * from './routes';
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { plugin } from './plugin';
|
||||
import { explorePlugin } from './plugin';
|
||||
|
||||
describe('explore', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(plugin).toBeDefined();
|
||||
expect(explorePlugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,9 +14,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createPlugin, createRouteRef } from '@backstage/core';
|
||||
import { createApiFactory, createPlugin } from '@backstage/core';
|
||||
import { exploreToolsConfigRef } from '@backstage/plugin-explore-react';
|
||||
import { exploreRouteRef } from './routes';
|
||||
import { exampleTools } from './util/examples';
|
||||
|
||||
export const rootRouteRef = createRouteRef({ path: '', title: 'Explore' });
|
||||
export const plugin = createPlugin({
|
||||
export const explorePlugin = createPlugin({
|
||||
id: 'explore',
|
||||
apis: [
|
||||
// Register a default for exploreToolsConfigRef, you may want to override
|
||||
// the API locally in your app.
|
||||
createApiFactory({
|
||||
api: exploreToolsConfigRef,
|
||||
deps: {},
|
||||
factory: () => ({
|
||||
async getTools() {
|
||||
return exampleTools;
|
||||
},
|
||||
}),
|
||||
}),
|
||||
],
|
||||
routes: {
|
||||
explore: exploreRouteRef,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -18,19 +18,7 @@ import { createRouteRef } from '@backstage/core';
|
||||
|
||||
const NoIcon = () => null;
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
export const exploreRouteRef = createRouteRef({
|
||||
icon: NoIcon,
|
||||
path: '/rollbar',
|
||||
title: 'Rollbar Home',
|
||||
});
|
||||
|
||||
export const entityRouteRef = createRouteRef({
|
||||
path: '/rollbar/:optionalNamespaceAndName',
|
||||
title: 'Rollbar',
|
||||
});
|
||||
|
||||
export const catalogRouteRef = createRouteRef({
|
||||
icon: NoIcon,
|
||||
path: '',
|
||||
title: 'Rollbar',
|
||||
title: 'Explore',
|
||||
});
|
||||
+1
-47
@@ -14,28 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { makeStyles, Typography } from '@material-ui/core';
|
||||
import {
|
||||
Content,
|
||||
ContentHeader,
|
||||
Header,
|
||||
Page,
|
||||
SupportButton,
|
||||
} from '@backstage/core';
|
||||
import ExploreCard, { CardData } from './ExploreCard';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
container: {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fill, 296px)',
|
||||
gridGap: theme.spacing(3),
|
||||
marginBottom: theme.spacing(6),
|
||||
},
|
||||
}));
|
||||
|
||||
const toolsCards = [
|
||||
export const exampleTools = [
|
||||
{
|
||||
title: 'New Relic',
|
||||
description:
|
||||
@@ -112,28 +91,3 @@ const toolsCards = [
|
||||
tags: ['rollbar', 'monitoring', 'errors'],
|
||||
},
|
||||
];
|
||||
|
||||
export const ExplorePluginPage = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Page themeId="home">
|
||||
<Header
|
||||
title="Explore"
|
||||
subtitle="Tools and services available in Backstage"
|
||||
/>
|
||||
<Content>
|
||||
<ContentHeader title="Tools">
|
||||
<SupportButton>
|
||||
<Typography>Explore tools available in Backstage</Typography>
|
||||
</SupportButton>
|
||||
</ContentHeader>
|
||||
<div className={classes.container}>
|
||||
{toolsCards.map((card: CardData, ix: any) => (
|
||||
<ExploreCard card={card} key={ix} />
|
||||
))}
|
||||
</div>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,34 @@
|
||||
# @backstage/plugin-fossa
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 5ac9df899: Port FOSSA plugin to new extension model.
|
||||
|
||||
If you are using the FOSSA plugin adjust the plugin import from `plugin` to
|
||||
`fossaPlugin` and replace `<FossaCard entity={...} ...>` with `<EntityFossaCard />`.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-fossa",
|
||||
"version": "0.1.2",
|
||||
"version": "0.2.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,10 +31,10 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.1",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@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",
|
||||
@@ -44,8 +44,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @backstage/plugin-gcp-projects
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- bc5082a00: Migrate to new composability API, exporting the plugin as `gcpProjectsPlugin` and page as `GcpProjectsPage`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/theme@0.2.3
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-gcp-projects",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -30,8 +30,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@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",
|
||||
@@ -41,8 +41,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# @backstage/plugin-github-actions
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [c4abcdb60]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [064c513e1]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [3149bfe63]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [2e62aea6f]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/integration@0.3.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-github-actions",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -32,10 +32,10 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/integration": "^0.3.1",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/integration": "^0.3.2",
|
||||
"@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",
|
||||
@@ -49,8 +49,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @backstage/plugin-gitops-profiles
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/theme@0.2.3
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-gitops-profiles",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,8 +31,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@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",
|
||||
@@ -42,8 +42,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @backstage/plugin-graphiql
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 87b189d00: Finalized composability API migration, now exporting the plugin as `graphiqlPlugin`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/theme@0.2.3
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-graphiql",
|
||||
"description": "Backstage plugin for browsing GraphQL APIs",
|
||||
"version": "0.2.6",
|
||||
"version": "0.2.7",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
@@ -31,8 +31,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@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",
|
||||
@@ -43,8 +43,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@backstage/plugin-catalog-graphql": "^0.2.6",
|
||||
"@graphql-modules/core": "^0.7.17",
|
||||
@@ -45,7 +45,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"eslint-plugin-graphql": "^4.0.0",
|
||||
"msw": "^0.20.5",
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @backstage/plugin-jenkins
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-jenkins",
|
||||
"version": "0.3.7",
|
||||
"version": "0.3.8",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,10 +31,10 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.1",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@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",
|
||||
@@ -47,8 +47,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -36,17 +36,17 @@ export function useBuilds(owner: string, repo: string, branch?: string) {
|
||||
|
||||
const { loading, value: builds, retry } = useAsyncRetry(async () => {
|
||||
try {
|
||||
let builds;
|
||||
let build;
|
||||
if (branch) {
|
||||
builds = await api.getLastBuild(`${owner}/${repo}/${branch}`);
|
||||
build = await api.getLastBuild(`${owner}/${repo}/${branch}`);
|
||||
} else {
|
||||
builds = await api.getFolder(`${owner}/${repo}`);
|
||||
build = await api.getFolder(`${owner}/${repo}`);
|
||||
}
|
||||
|
||||
const size = Array.isArray(builds) ? builds?.[0].build_num! : 1;
|
||||
const size = Array.isArray(build) ? build?.[0].build_num! : 1;
|
||||
setTotal(size);
|
||||
|
||||
return builds || [];
|
||||
return build || [];
|
||||
} catch (e) {
|
||||
errorApi.post(e);
|
||||
throw e;
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@types/express": "^4.17.6",
|
||||
"express": "^4.17.1",
|
||||
@@ -42,7 +42,7 @@
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@types/jest-when": "^2.7.2",
|
||||
"@types/lodash": "^4.14.151",
|
||||
"jest-when": "^3.1.0",
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @backstage/plugin-kafka
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`.
|
||||
- Updated dependencies [12ece98cd]
|
||||
- Updated dependencies [d82246867]
|
||||
- Updated dependencies [7fc89bae2]
|
||||
- Updated dependencies [c810082ae]
|
||||
- Updated dependencies [5fa3bdb55]
|
||||
- Updated dependencies [6e612ce25]
|
||||
- Updated dependencies [025e122c3]
|
||||
- Updated dependencies [21e624ba9]
|
||||
- Updated dependencies [da9f53c60]
|
||||
- Updated dependencies [32c95605f]
|
||||
- Updated dependencies [7881f2117]
|
||||
- Updated dependencies [54c7d02f7]
|
||||
- Updated dependencies [11cb5ef94]
|
||||
- @backstage/core@0.6.0
|
||||
- @backstage/plugin-catalog-react@0.0.2
|
||||
- @backstage/theme@0.2.3
|
||||
- @backstage/catalog-model@0.7.1
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-kafka",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"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.0",
|
||||
"@backstage/core": "^0.5.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.1",
|
||||
"@backstage/theme": "^0.2.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/core": "^0.6.0",
|
||||
"@backstage/plugin-catalog-react": "^0.0.2",
|
||||
"@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",
|
||||
@@ -33,8 +33,8 @@
|
||||
"react-use": "^15.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/dev-utils": "^0.1.8",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@backstage/dev-utils": "^0.1.9",
|
||||
"@backstage/test-utils": "^0.1.6",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^10.4.1",
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/credential-provider-node": "^3.3.0",
|
||||
"@backstage/backend-common": "^0.5.1",
|
||||
"@backstage/catalog-model": "^0.7.0",
|
||||
"@backstage/backend-common": "^0.5.2",
|
||||
"@backstage/catalog-model": "^0.7.1",
|
||||
"@backstage/config": "^0.1.2",
|
||||
"@kubernetes/client-node": "^0.13.2",
|
||||
"@types/express": "^4.17.6",
|
||||
@@ -51,7 +51,7 @@
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.5.0",
|
||||
"@backstage/cli": "^0.6.0",
|
||||
"@types/aws4": "^1.5.1",
|
||||
"supertest": "^4.0.2"
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user