Merge branch 'master' of https://github.com/backstage/backstage into marley/7678-pull-request-dashboard
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@backstage/plugin-azure-devops': patch
|
||||
'@backstage/plugin-azure-devops-backend': minor
|
||||
'@backstage/plugin-azure-devops-common': patch
|
||||
---
|
||||
|
||||
refactor(`@backstage/plugin-azure-devops`): Consume types from `@backstage/plugin-azure-devops-common`.
|
||||
Stop re-exporting types from `@backstage/plugin-azure-devops-backend`.
|
||||
Added new types to `@backstage/plugin-azure-devops-common`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/catalog-client': patch
|
||||
---
|
||||
|
||||
Improved API documentation for catalog-client.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Only use settings that have a value when creating a new FirestoreKeyStore instance
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Updated the app template to no longer include the `--no-private` flag for the `create-plugin` command.
|
||||
|
||||
To apply this change to an existing application, remove the `--no-private` flag from the `create-plugin` command in the root `package.json`:
|
||||
|
||||
```diff
|
||||
"prettier:check": "prettier --check .",
|
||||
- "create-plugin": "backstage-cli create-plugin --scope internal --no-private",
|
||||
+ "create-plugin": "backstage-cli create-plugin --scope internal",
|
||||
"remove-plugin": "backstage-cli remove-plugin"
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-code-coverage': patch
|
||||
---
|
||||
|
||||
Make dates in X-Axis sort in ascending order
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Removed the version pinning of the packages `graphql-language-service-interface` and `graphql-language-service-parser`. This should no longer be necessary.
|
||||
|
||||
You can apply the same change in your repository by ensuring that the following does _NOT_ appear in your root `package.json`.
|
||||
|
||||
```json
|
||||
"resolutions": {
|
||||
"graphql-language-service-interface": "2.8.2",
|
||||
"graphql-language-service-parser": "1.9.0"
|
||||
},
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
'@backstage/core-plugin-api': patch
|
||||
---
|
||||
|
||||
Improve API documentation for @backstage/core-plugin-api
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
Fix a bug where only file mode 775 is considered an executable
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-plugin-api': patch
|
||||
---
|
||||
|
||||
Deprecate unused ApiRef types
|
||||
@@ -6,10 +6,12 @@ on:
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Create Snyk report
|
||||
uses: snyk/actions/node@master
|
||||
continue-on-error: true # Snyk CLI exits with error when vulnerabilities are found
|
||||
with:
|
||||
args: >
|
||||
--yarn-workspaces
|
||||
|
||||
@@ -64,3 +64,4 @@
|
||||
| [SoundCloud](https://www.soundcloud.com) | [Julio Zynger](https://github.com/julioz) | Developer portal as a [humane registry](https://martinfowler.com/bliki/HumaneRegistry.html) for the organization: catalog of people, services, documentation, feature toggles, escalation policies, etc. |
|
||||
| [Volvofinans Bank](https://www.volvofinans.se) | [Johan Hammar](https://github.com/johanhammar) | Developer portal enabling engineers to manage and explore software and documentation. |
|
||||
| [Palo Alto Networks](https://www.paloaltonetworks.com) | [Jeremy Guarini](https://github.com/jeremyguarini), [Brian Lomeland](https://github.com/bbbmmmlll), [Palo Alto Networks](https://github.com/PaloAltoNetworks) | Developer portal, service catalog, documentation and tooling |
|
||||
| [Signal Iduna Group](https://www.signal-iduna.de/) | [Jonas Thomsen](https://github.com/JoThomsen) | Developer Portal, documentation, monitoring, service catalog for our insurance ecosystem
|
||||
|
||||
@@ -125,8 +125,8 @@ input schema.
|
||||
input:
|
||||
- address: '{{ json parameters.address }}'
|
||||
+ address: ${{ parameters.address }}
|
||||
- number: '{{ parameters.number }}'
|
||||
+ number: ${{ parameters.number }} # this will now make sure that the type of number is a number 🙏
|
||||
- test: '{{ parameters.test }}'
|
||||
+ test: ${{ parameters.test }} # this will now make sure that the type of test is a number 🙏
|
||||
```
|
||||
|
||||
## `parseRepoUrl` is now a `filter`
|
||||
|
||||
+1
-3
@@ -46,9 +46,7 @@
|
||||
"resolutions": {
|
||||
"**/@graphql-codegen/cli/**/ws": "^7.4.6",
|
||||
"**/@roadiehq/**/@backstage/plugin-catalog": "*",
|
||||
"**/@roadiehq/**/@backstage/catalog-model": "*",
|
||||
"graphql-language-service-interface": "2.8.2",
|
||||
"graphql-language-service-parser": "1.9.0"
|
||||
"**/@roadiehq/**/@backstage/catalog-model": "*"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Entity } from '@backstage/catalog-model';
|
||||
import { EntityName } from '@backstage/catalog-model';
|
||||
import { Location as Location_2 } from '@backstage/catalog-model';
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type AddLocationRequest = {
|
||||
type?: string;
|
||||
target: string;
|
||||
@@ -15,126 +15,106 @@ export type AddLocationRequest = {
|
||||
presence?: 'optional' | 'required';
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type AddLocationResponse = {
|
||||
location: Location_2;
|
||||
entities: Entity[];
|
||||
exists?: boolean;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export const CATALOG_FILTER_EXISTS: unique symbol;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export interface CatalogApi {
|
||||
// (undocumented)
|
||||
addLocation(
|
||||
location: AddLocationRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<AddLocationResponse>;
|
||||
// (undocumented)
|
||||
getEntities(
|
||||
request?: CatalogEntitiesRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<CatalogListResponse<Entity>>;
|
||||
// (undocumented)
|
||||
getEntityAncestors(
|
||||
request: CatalogEntityAncestorsRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<CatalogEntityAncestorsResponse>;
|
||||
// (undocumented)
|
||||
getEntityByName(
|
||||
name: EntityName,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Entity | undefined>;
|
||||
// (undocumented)
|
||||
getLocationByEntity(
|
||||
entity: Entity,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location_2 | undefined>;
|
||||
// (undocumented)
|
||||
getLocationById(
|
||||
id: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location_2 | undefined>;
|
||||
// (undocumented)
|
||||
getOriginLocationByEntity(
|
||||
entity: Entity,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location_2 | undefined>;
|
||||
// (undocumented)
|
||||
refreshEntity(
|
||||
entityRef: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
// (undocumented)
|
||||
removeEntityByUid(
|
||||
uid: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
// (undocumented)
|
||||
removeLocationById(
|
||||
id: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class CatalogClient implements CatalogApi {
|
||||
constructor(options: { discoveryApi: DiscoveryApi });
|
||||
// (undocumented)
|
||||
addLocation(
|
||||
{ type, target, dryRun, presence }: AddLocationRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<AddLocationResponse>;
|
||||
// (undocumented)
|
||||
getEntities(
|
||||
request?: CatalogEntitiesRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<CatalogListResponse<Entity>>;
|
||||
// (undocumented)
|
||||
getEntityAncestors(
|
||||
request: CatalogEntityAncestorsRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<CatalogEntityAncestorsResponse>;
|
||||
// (undocumented)
|
||||
getEntityByName(
|
||||
compoundName: EntityName,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Entity | undefined>;
|
||||
// (undocumented)
|
||||
getLocationByEntity(
|
||||
entity: Entity,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location_2 | undefined>;
|
||||
// (undocumented)
|
||||
getLocationById(
|
||||
id: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location_2 | undefined>;
|
||||
// (undocumented)
|
||||
getOriginLocationByEntity(
|
||||
entity: Entity,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location_2 | undefined>;
|
||||
// (undocumented)
|
||||
refreshEntity(
|
||||
entityRef: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
// (undocumented)
|
||||
removeEntityByUid(
|
||||
uid: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
// (undocumented)
|
||||
removeLocationById(
|
||||
id: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type CatalogEntitiesRequest = {
|
||||
filter?:
|
||||
| Record<string, string | symbol | (string | symbol)[]>[]
|
||||
@@ -143,12 +123,12 @@ export type CatalogEntitiesRequest = {
|
||||
fields?: string[] | undefined;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type CatalogEntityAncestorsRequest = {
|
||||
entityRef: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type CatalogEntityAncestorsResponse = {
|
||||
root: EntityName;
|
||||
items: {
|
||||
@@ -157,12 +137,12 @@ export type CatalogEntityAncestorsResponse = {
|
||||
}[];
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type CatalogListResponse<T> = {
|
||||
items: T[];
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export type CatalogRequestOptions = {
|
||||
token?: string;
|
||||
};
|
||||
|
||||
@@ -39,7 +39,11 @@ import {
|
||||
} from './types/api';
|
||||
import { DiscoveryApi } from './types/discovery';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A frontend and backend compatible client for communicating with the Backstage Catalog.
|
||||
*
|
||||
* @public
|
||||
* */
|
||||
export class CatalogClient implements CatalogApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
|
||||
@@ -47,6 +51,16 @@ export class CatalogClient implements CatalogApi {
|
||||
this.discoveryApi = options.discoveryApi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Ancestors of an Entity.
|
||||
*
|
||||
* @param request - A request type for retrieving Entity ancestors.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A CatalogEntityAncestorsResponse.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async getEntityAncestors(
|
||||
request: CatalogEntityAncestorsRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
@@ -61,6 +75,16 @@ export class CatalogClient implements CatalogApi {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Location by Id.
|
||||
*
|
||||
* @param id - A string containing the Id.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A {@link catalog-model#Location_2}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async getLocationById(
|
||||
id: string,
|
||||
options?: CatalogRequestOptions,
|
||||
@@ -72,6 +96,16 @@ export class CatalogClient implements CatalogApi {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of Entities.
|
||||
*
|
||||
* @param request - A request type for retrieving an Entity.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A CatalogListResponse.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async getEntities(
|
||||
request?: CatalogEntitiesRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
@@ -139,6 +173,16 @@ export class CatalogClient implements CatalogApi {
|
||||
return { items: entities.sort(refCompare) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a given Entity based on a provided name.
|
||||
*
|
||||
* @param compoundName - A string containing the name.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns An {@link catalog-model#Entity}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async getEntityByName(
|
||||
compoundName: EntityName,
|
||||
options?: CatalogRequestOptions,
|
||||
@@ -153,6 +197,14 @@ export class CatalogClient implements CatalogApi {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes an Entity.
|
||||
*
|
||||
* @param entityRef - A string containing the entityREf
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async refreshEntity(entityRef: string, options?: CatalogRequestOptions) {
|
||||
const response = await fetch(
|
||||
`${await this.discoveryApi.getBaseUrl('catalog')}/refresh`,
|
||||
@@ -171,6 +223,16 @@ export class CatalogClient implements CatalogApi {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a location.
|
||||
*
|
||||
* @param options - An object with your preferred options.
|
||||
* @param AddLocationRequest - A request object for adding locations.
|
||||
*
|
||||
* @returns An AddLocationResponse
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async addLocation(
|
||||
{ type = 'url', target, dryRun, presence }: AddLocationRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
@@ -206,6 +268,16 @@ export class CatalogClient implements CatalogApi {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an origin Location By Entity.
|
||||
*
|
||||
* @param entity - An Entity
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A {@link catalog-model#Location_2}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async getOriginLocationByEntity(
|
||||
entity: Entity,
|
||||
options?: CatalogRequestOptions,
|
||||
@@ -225,6 +297,16 @@ export class CatalogClient implements CatalogApi {
|
||||
.find(l => locationCompound === stringifyLocationReference(l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Location by Entity.
|
||||
*
|
||||
* @param entity - An Entity
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A {@link catalog-model#Location_2}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async getLocationByEntity(
|
||||
entity: Entity,
|
||||
options?: CatalogRequestOptions,
|
||||
@@ -243,6 +325,14 @@ export class CatalogClient implements CatalogApi {
|
||||
.find(l => locationCompound === stringifyLocationReference(l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a location as identified by Id.
|
||||
*
|
||||
* @param id - A string containing the Id
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async removeLocationById(
|
||||
id: string,
|
||||
options?: CatalogRequestOptions,
|
||||
@@ -254,6 +344,14 @@ export class CatalogClient implements CatalogApi {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an Entity as identified by Uid.
|
||||
*
|
||||
* @param uid - A string containing the Uid
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async removeEntityByUid(
|
||||
uid: string,
|
||||
options?: CatalogRequestOptions,
|
||||
|
||||
@@ -16,10 +16,18 @@
|
||||
|
||||
import { Entity, EntityName, Location } from '@backstage/catalog-model';
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A Symbol to define if a catalog filter exists or not.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS');
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A request type for retrieving catalog Entities.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CatalogEntitiesRequest = {
|
||||
filter?:
|
||||
| Record<string, string | symbol | (string | symbol)[]>[]
|
||||
@@ -28,75 +36,176 @@ export type CatalogEntitiesRequest = {
|
||||
fields?: string[] | undefined;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A request type for Catalog Entity Ancestor information.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CatalogEntityAncestorsRequest = {
|
||||
entityRef: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A response type for Catalog Entity Ancestor information.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CatalogEntityAncestorsResponse = {
|
||||
root: EntityName;
|
||||
items: { entity: Entity; parents: EntityName[] }[];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A response type for the result of a catalog operation in list form.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CatalogListResponse<T> = {
|
||||
items: T[];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Options you can pass into a catalog request for additional information.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CatalogRequestOptions = {
|
||||
token?: string;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* Public functions for interacting with the Catalog API.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface CatalogApi {
|
||||
// Entities
|
||||
/**
|
||||
* Gets the Entities from the catalog based on your request and options.
|
||||
*
|
||||
* @param request - An object with your filters and fields.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A CatalogListResponse with items typed Catalog Model Entity.
|
||||
*
|
||||
*/
|
||||
getEntities(
|
||||
request?: CatalogEntitiesRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<CatalogListResponse<Entity>>;
|
||||
/**
|
||||
* Gets the Entity ancestor information from the catalog based on your request and options.
|
||||
*
|
||||
* @param request - An object with your filters and fields.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A CatalogEntityAncestorsResponse.
|
||||
*/
|
||||
getEntityAncestors(
|
||||
request: CatalogEntityAncestorsRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<CatalogEntityAncestorsResponse>;
|
||||
/**
|
||||
* Gets a single Entity from the catalog by Entity name.
|
||||
*
|
||||
* @param name - A complete Entity name, with the full kind-namespace-name triplet.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A {@link catalog-model#Entity}.
|
||||
*/
|
||||
getEntityByName(
|
||||
name: EntityName,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Entity | undefined>;
|
||||
/**
|
||||
* Removes a single Entity from the catalog by Entity UID.
|
||||
*
|
||||
* @param uid - A string of the Entity UID.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
*/
|
||||
removeEntityByUid(
|
||||
uid: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Refreshes an Entity in the catalog.
|
||||
*
|
||||
* @param entityRef - A string in the form of 'Kind/default:foo'.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
*/
|
||||
refreshEntity(
|
||||
entityRef: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
|
||||
// Locations
|
||||
/**
|
||||
* Gets a Location object by ID from the catalog.
|
||||
*
|
||||
* @param id - A string in of the Location Id.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A {@link catalog-model#Location_2}.
|
||||
*/
|
||||
getLocationById(
|
||||
id: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location | undefined>;
|
||||
/**
|
||||
* Gets origin location by Entity.
|
||||
*
|
||||
* @param entity - An {@link catalog-model#Entity}.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A {@link catalog-model#Location_2}.
|
||||
*/
|
||||
getOriginLocationByEntity(
|
||||
entity: Entity,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location | undefined>;
|
||||
/**
|
||||
* Gets Location by Entity.
|
||||
*
|
||||
* @param entity - An {@link catalog-model#Entity}.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A {@link catalog-model#Location_2}.
|
||||
*/
|
||||
getLocationByEntity(
|
||||
entity: Entity,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<Location | undefined>;
|
||||
/**
|
||||
* Adds a Location.
|
||||
*
|
||||
* @param location - A request type for adding a Location to the catalog.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
* @returns A AddLocationResponse.
|
||||
*/
|
||||
addLocation(
|
||||
location: AddLocationRequest,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<AddLocationResponse>;
|
||||
/**
|
||||
* Removes a Location by Id.
|
||||
*
|
||||
* @param id - A string in of the Location Id.
|
||||
* @param options - An object with your preferred options.
|
||||
*
|
||||
*/
|
||||
removeLocationById(
|
||||
id: string,
|
||||
options?: CatalogRequestOptions,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A request type for adding a Location to the catalog.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AddLocationRequest = {
|
||||
type?: string;
|
||||
target: string;
|
||||
@@ -104,7 +213,11 @@ export type AddLocationRequest = {
|
||||
presence?: 'optional' | 'required';
|
||||
};
|
||||
|
||||
/** @public */
|
||||
/**
|
||||
* A response type for adding a Location to the catalog.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AddLocationResponse = {
|
||||
location: Location;
|
||||
entities: Entity[];
|
||||
|
||||
@@ -28,6 +28,7 @@ import { bitbucketAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { Error as Error_2 } from '@backstage/core-plugin-api';
|
||||
import { ErrorApi } from '@backstage/core-plugin-api';
|
||||
import { ErrorContext } from '@backstage/core-plugin-api';
|
||||
import { ExternalRouteRef } from '@backstage/core-plugin-api';
|
||||
@@ -298,11 +299,7 @@ export class ErrorAlerter implements ErrorApi {
|
||||
constructor(alertApi: AlertApi, errorApi: ErrorApi);
|
||||
// (undocumented)
|
||||
error$(): Observable<{
|
||||
error: {
|
||||
name: string;
|
||||
message: string;
|
||||
stack?: string | undefined;
|
||||
};
|
||||
error: Error_2;
|
||||
context?: ErrorContext | undefined;
|
||||
}>;
|
||||
// (undocumented)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,8 @@ const AnalyticsReactContext =
|
||||
/**
|
||||
* A "private" (to this package) hook that enables context inheritance and a
|
||||
* way to read Analytics Context values at event capture-time.
|
||||
* @private
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export const useAnalyticsContext = (): AnalyticsContextValue => {
|
||||
const theContext = useContext(AnalyticsReactContext);
|
||||
@@ -54,8 +55,12 @@ export const useAnalyticsContext = (): AnalyticsContextValue => {
|
||||
* Provides components in the child react tree an Analytics Context, ensuring
|
||||
* all analytics events captured within the context have relevant attributes.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Analytics contexts are additive, meaning the context ultimately emitted with
|
||||
* an event is the combination of all contexts in the parent tree.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const AnalyticsContext = ({
|
||||
attributes,
|
||||
@@ -84,6 +89,7 @@ export const AnalyticsContext = ({
|
||||
*
|
||||
* @param Component - Component to be wrapped with analytics context attributes
|
||||
* @param values - Analytics context key/value pairs.
|
||||
* @internal
|
||||
*/
|
||||
export function withAnalyticsContext<P>(
|
||||
Component: React.ComponentType<P>,
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
/**
|
||||
* Common analytics context attributes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type CommonAnalyticsContext = {
|
||||
/**
|
||||
@@ -35,7 +37,9 @@ export type CommonAnalyticsContext = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Allow arbitrary scalar values as context attributes too.
|
||||
* Allows arbitrary scalar values as context attributes too.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnyAnalyticsContext = {
|
||||
[param in string]: string | boolean | number | undefined;
|
||||
@@ -43,6 +47,8 @@ export type AnyAnalyticsContext = {
|
||||
|
||||
/**
|
||||
* Analytics context envelope.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnalyticsContextValue = CommonAnalyticsContext &
|
||||
AnyAnalyticsContext;
|
||||
|
||||
@@ -33,7 +33,9 @@ function useAnalyticsApi(): AnalyticsApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pre-configured analytics tracker.
|
||||
* Gets a pre-configured analytics tracker.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useAnalytics(): AnalyticsTracker {
|
||||
const trackerRef = useRef<Tracker | null>(null);
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
import { createApiRef, ApiRef } from '../system';
|
||||
import { Observable } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* Message handled by the {@link AlertApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AlertMessage = {
|
||||
message: string;
|
||||
// Severity will default to success since that is what material ui defaults the value to.
|
||||
@@ -25,8 +30,9 @@ export type AlertMessage = {
|
||||
|
||||
/**
|
||||
* The alert API is used to report alerts to the app, and display them to the user.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
export type AlertApi = {
|
||||
/**
|
||||
* Post an alert for handling by the application.
|
||||
@@ -39,6 +45,11 @@ export type AlertApi = {
|
||||
alert$(): Observable<AlertMessage>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link AlertApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const alertApiRef: ApiRef<AlertApi> = createApiRef({
|
||||
id: 'core.alert',
|
||||
});
|
||||
|
||||
@@ -20,6 +20,8 @@ import { AnalyticsContextValue } from '../../analytics/types';
|
||||
/**
|
||||
* Represents an event worth tracking in an analytics system that could inform
|
||||
* how users of a Backstage instance are using its features.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnalyticsEvent = {
|
||||
/**
|
||||
@@ -76,6 +78,8 @@ export type AnalyticsEvent = {
|
||||
/**
|
||||
* A structure allowing other arbitrary metadata to be provided by analytics
|
||||
* event emitters.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnalyticsEventAttributes = {
|
||||
[attribute in string]: string | boolean | number;
|
||||
@@ -84,6 +88,8 @@ export type AnalyticsEventAttributes = {
|
||||
/**
|
||||
* Represents a tracker with methods that can be called to track events in a
|
||||
* configured analytics service.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnalyticsTracker = {
|
||||
captureEvent: (
|
||||
@@ -99,9 +105,13 @@ export type AnalyticsTracker = {
|
||||
/**
|
||||
* The Analytics API is used to track user behavior in a Backstage instance.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* To instrument your App or Plugin, retrieve an analytics tracker using the
|
||||
* useAnalytics() hook. This will return a pre-configured AnalyticsTracker
|
||||
* with relevant methods for instrumentation.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnalyticsApi = {
|
||||
/**
|
||||
@@ -111,6 +121,11 @@ export type AnalyticsApi = {
|
||||
captureEvent(event: AnalyticsEvent): void;
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link AnalyticsApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const analyticsApiRef: ApiRef<AnalyticsApi> = createApiRef({
|
||||
id: 'core.analytics',
|
||||
});
|
||||
|
||||
@@ -20,6 +20,8 @@ import { Observable } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* Describes a theme provided by the app.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AppTheme = {
|
||||
/**
|
||||
@@ -51,6 +53,8 @@ export type AppTheme = {
|
||||
/**
|
||||
* The AppThemeApi gives access to the current app theme, and allows switching
|
||||
* to other options that have been registered as a part of the App.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AppThemeApi = {
|
||||
/**
|
||||
@@ -76,6 +80,11 @@ export type AppThemeApi = {
|
||||
setActiveThemeId(themeId?: string): void;
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link AppThemeApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const appThemeApiRef: ApiRef<AppThemeApi> = createApiRef({
|
||||
id: 'core.apptheme',
|
||||
});
|
||||
|
||||
@@ -19,9 +19,16 @@ import { Config } from '@backstage/config';
|
||||
/**
|
||||
* The Config API is used to provide a mechanism to access the
|
||||
* runtime configuration of the system.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ConfigApi = Config;
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link ConfigApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const configApiRef: ApiRef<ConfigApi> = createApiRef({
|
||||
id: 'core.config',
|
||||
});
|
||||
|
||||
@@ -19,6 +19,8 @@ import { ApiRef, createApiRef } from '../system';
|
||||
* The discovery API is used to provide a mechanism for plugins to
|
||||
* discover the endpoint to use to talk to their backend counterpart.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The purpose of the discovery API is to allow for many different deployment
|
||||
* setups and routing methods through a central configuration, instead
|
||||
* of letting each individual plugin manage that configuration.
|
||||
@@ -26,6 +28,8 @@ import { ApiRef, createApiRef } from '../system';
|
||||
* Implementations of the discovery API can be a simple as a URL pattern
|
||||
* using the pluginId, but could also have overrides for individual plugins,
|
||||
* or query a separate discovery service.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type DiscoveryApi = {
|
||||
/**
|
||||
@@ -41,6 +45,11 @@ export type DiscoveryApi = {
|
||||
getBaseUrl(pluginId: string): Promise<string>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link DiscoveryApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const discoveryApiRef: ApiRef<DiscoveryApi> = createApiRef({
|
||||
id: 'core.discovery',
|
||||
});
|
||||
|
||||
@@ -20,8 +20,10 @@ import { Observable } from '@backstage/types';
|
||||
/**
|
||||
* Mirrors the JavaScript Error class, for the purpose of
|
||||
* providing documentation and optional fields.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
type Error = {
|
||||
export type Error = {
|
||||
name: string;
|
||||
message: string;
|
||||
stack?: string;
|
||||
@@ -29,6 +31,8 @@ type Error = {
|
||||
|
||||
/**
|
||||
* Provides additional information about an error that was posted to the application.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ErrorContext = {
|
||||
// If set to true, this error should not be displayed to the user. Defaults to false.
|
||||
@@ -38,6 +42,8 @@ export type ErrorContext = {
|
||||
/**
|
||||
* The error API is used to report errors to the app, and display them to the user.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Plugins can use this API as a method of displaying errors to the user, but also
|
||||
* to report errors for collection by error reporting services.
|
||||
*
|
||||
@@ -49,6 +55,8 @@ export type ErrorContext = {
|
||||
* if it would be useful to collect or log it for debugging purposes, but with
|
||||
* the hidden flag set. For example, an error arising from form field validation
|
||||
* should probably not be reported, while a failed REST call would be useful to report.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ErrorApi = {
|
||||
/**
|
||||
@@ -62,6 +70,11 @@ export type ErrorApi = {
|
||||
error$(): Observable<{ error: Error; context?: ErrorContext }>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link ErrorApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const errorApiRef: ApiRef<ErrorApi> = createApiRef({
|
||||
id: 'core.error',
|
||||
});
|
||||
|
||||
@@ -17,29 +17,35 @@
|
||||
import { ApiRef, createApiRef } from '../system';
|
||||
|
||||
/**
|
||||
* The feature flags API is used to toggle functionality to users across plugins and Backstage.
|
||||
* Fetaure flag descriptor.
|
||||
*
|
||||
* Plugins can use this API to register feature flags that they have available
|
||||
* for users to enable/disable, and this API will centralize the current user's
|
||||
* state of which feature flags they would like to enable.
|
||||
*
|
||||
* This is ideal for Backstage plugins, as well as your own App, to trial incomplete
|
||||
* or unstable upcoming features. Although there will be a common interface for users
|
||||
* to enable and disable feature flags, this API acts as another way to enable/disable.
|
||||
* @public
|
||||
*/
|
||||
|
||||
export type FeatureFlag = {
|
||||
name: string;
|
||||
pluginId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum representing the state of a feature flag (inactive/active).
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export enum FeatureFlagState {
|
||||
/**
|
||||
* Feature flag inactive (disabled).
|
||||
*/
|
||||
None = 0,
|
||||
/**
|
||||
* Feature flag active (enabled).
|
||||
*/
|
||||
Active = 1,
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to use when saving feature flags.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type FeatureFlagsSaveOptions = {
|
||||
/**
|
||||
@@ -55,8 +61,28 @@ export type FeatureFlagsSaveOptions = {
|
||||
merge?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* User flags alias.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type UserFlags = {};
|
||||
|
||||
/**
|
||||
* The feature flags API is used to toggle functionality to users across plugins and Backstage.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Plugins can use this API to register feature flags that they have available
|
||||
* for users to enable/disable, and this API will centralize the current user's
|
||||
* state of which feature flags they would like to enable.
|
||||
*
|
||||
* This is ideal for Backstage plugins, as well as your own App, to trial incomplete
|
||||
* or unstable upcoming features. Although there will be a common interface for users
|
||||
* to enable and disable feature flags, this API acts as another way to enable/disable.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface FeatureFlagsApi {
|
||||
/**
|
||||
* Registers a new feature flag. Once a feature flag has been registered it
|
||||
@@ -80,6 +106,11 @@ export interface FeatureFlagsApi {
|
||||
save(options: FeatureFlagsSaveOptions): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link FeatureFlagsApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const featureFlagsApiRef: ApiRef<FeatureFlagsApi> = createApiRef({
|
||||
id: 'core.featureflags',
|
||||
});
|
||||
|
||||
@@ -18,6 +18,8 @@ import { ProfileInfo } from './auth';
|
||||
|
||||
/**
|
||||
* The Identity API used to identify and get information about the signed in user.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type IdentityApi = {
|
||||
/**
|
||||
@@ -49,6 +51,11 @@ export type IdentityApi = {
|
||||
signOut(): Promise<void>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link IdentityApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const identityApiRef: ApiRef<IdentityApi> = createApiRef({
|
||||
id: 'core.identity',
|
||||
});
|
||||
|
||||
@@ -21,8 +21,12 @@ import { ApiRef, createApiRef } from '../system';
|
||||
/**
|
||||
* Information about the auth provider that we're requesting a login towards.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This should be shown to the user so that they can be informed about what login is being requested
|
||||
* before a popup is shown.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AuthProvider = {
|
||||
/**
|
||||
@@ -39,6 +43,8 @@ export type AuthProvider = {
|
||||
/**
|
||||
* Describes how to handle auth requests. Both how to show them to the user, and what to do when
|
||||
* the user accesses the auth request.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AuthRequesterOptions<AuthResponse> = {
|
||||
/**
|
||||
@@ -56,12 +62,16 @@ export type AuthRequesterOptions<AuthResponse> = {
|
||||
/**
|
||||
* Function used to trigger new auth requests for a set of scopes.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The returned promise will resolve to the same value returned by the onAuthRequest in the
|
||||
* AuthRequesterOptions. Or rejected, if the request is rejected.
|
||||
* {@link AuthRequesterOptions}. Or rejected, if the request is rejected.
|
||||
*
|
||||
* This function can be called multiple times before the promise resolves. All calls
|
||||
* will be merged into one request, and the scopes forwarded to the onAuthRequest will be the
|
||||
* union of all requested scopes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AuthRequester<AuthResponse> = (
|
||||
scopes: Set<string>,
|
||||
@@ -71,8 +81,12 @@ export type AuthRequester<AuthResponse> = (
|
||||
* An pending auth request for a single auth provider. The request will remain in this pending
|
||||
* state until either reject() or trigger() is called.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Any new requests for the same provider are merged into the existing pending request, meaning
|
||||
* there will only ever be a single pending request for a given provider.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PendingAuthRequest = {
|
||||
/**
|
||||
@@ -95,6 +109,8 @@ export type PendingAuthRequest = {
|
||||
|
||||
/**
|
||||
* Provides helpers for implemented OAuth login flows within Backstage.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type OAuthRequestApi = {
|
||||
/**
|
||||
@@ -127,6 +143,11 @@ export type OAuthRequestApi = {
|
||||
authRequest$(): Observable<PendingAuthRequest[]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link OAuthRequestApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const oauthRequestApiRef: ApiRef<OAuthRequestApi> = createApiRef({
|
||||
id: 'core.oauthrequest',
|
||||
});
|
||||
|
||||
@@ -17,48 +17,60 @@
|
||||
import { ApiRef, createApiRef } from '../system';
|
||||
import { Observable } from '@backstage/types';
|
||||
|
||||
/**
|
||||
* Describes a value change event.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type StorageValueChange<T = any> = {
|
||||
key: string;
|
||||
newValue?: T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides key-value persistence API.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface StorageApi {
|
||||
/**
|
||||
* Create a bucket to store data in.
|
||||
* @param {String} name Namespace for the storage to be stored under,
|
||||
* @param name - Namespace for the storage to be stored under,
|
||||
* will inherit previous namespaces too
|
||||
*/
|
||||
forBucket(name: string): StorageApi;
|
||||
|
||||
/**
|
||||
* Get the current value for persistent data, use observe$ to be notified of updates.
|
||||
*
|
||||
* @param {String} key Unique key associated with the data.
|
||||
* @return {Object} data The data that should is stored.
|
||||
* @param key - Unique key associated with the data.
|
||||
*/
|
||||
get<T>(key: string): T | undefined;
|
||||
|
||||
/**
|
||||
* Remove persistent data.
|
||||
*
|
||||
* @param {String} key Unique key associated with the data.
|
||||
* @param key - Unique key associated with the data.
|
||||
*/
|
||||
remove(key: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Save persistent data, and emit messages to anyone that is using observe$ for this key
|
||||
*
|
||||
* @param {String} key Unique key associated with the data.
|
||||
* @param key - Unique key associated with the data.
|
||||
* @param data - The data to be stored under the key.
|
||||
*/
|
||||
set(key: string, data: any): Promise<void>;
|
||||
|
||||
/**
|
||||
* Observe changes on a particular key in the bucket
|
||||
* @param {String} key Unique key associated with the data
|
||||
* @param key - Unique key associated with the data
|
||||
*/
|
||||
observe$<T>(key: string): Observable<StorageValueChange<T>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link ApiRef} of {@link StorageApi}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const storageApiRef: ApiRef<StorageApi> = createApiRef({
|
||||
id: 'core.storage',
|
||||
});
|
||||
|
||||
@@ -32,11 +32,20 @@ import { Observable } from '@backstage/types';
|
||||
* An array of scopes, or a scope string formatted according to the
|
||||
* auth provider, which is typically a space separated list.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See the documentation for each auth provider for the list of scopes
|
||||
* supported by each provider.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type OAuthScope = string | string[];
|
||||
|
||||
/**
|
||||
* Configuration of an authentication request.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AuthRequestOptions = {
|
||||
/**
|
||||
* If this is set to true, the user will not be prompted to log in,
|
||||
@@ -45,7 +54,7 @@ export type AuthRequestOptions = {
|
||||
* This can be used to perform a check whether the user is logged in, or if you don't
|
||||
* want to force a user to be logged in, but provide functionality if they already are.
|
||||
*
|
||||
* @default false
|
||||
* @defaultValue false
|
||||
*/
|
||||
optional?: boolean;
|
||||
|
||||
@@ -55,7 +64,7 @@ export type AuthRequestOptions = {
|
||||
*
|
||||
* The method must be called synchronously from a user action for this to work in all browsers.
|
||||
*
|
||||
* @default false
|
||||
* @defaultValue false
|
||||
*/
|
||||
instantPopup?: boolean;
|
||||
};
|
||||
@@ -63,6 +72,8 @@ export type AuthRequestOptions = {
|
||||
/**
|
||||
* This API provides access to OAuth 2 credentials. It lets you request access tokens,
|
||||
* which can be used to act on behalf of the user when talking to APIs.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type OAuthApi = {
|
||||
/**
|
||||
@@ -95,6 +106,8 @@ export type OAuthApi = {
|
||||
/**
|
||||
* This API provides access to OpenID Connect credentials. It lets you request ID tokens,
|
||||
* which can be passed to backend services to prove the user's identity.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type OpenIdConnectApi = {
|
||||
/**
|
||||
@@ -113,13 +126,15 @@ export type OpenIdConnectApi = {
|
||||
|
||||
/**
|
||||
* This API provides access to profile information of the user from an auth provider.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ProfileInfoApi = {
|
||||
/**
|
||||
* Get profile information for the user as supplied by this auth provider.
|
||||
*
|
||||
* If the optional flag is not set, a session is guaranteed to be returned, while if
|
||||
* the optional flag is set, the session may be undefined. See @AuthRequestOptions for more details.
|
||||
* the optional flag is set, the session may be undefined. See {@link AuthRequestOptions} for more details.
|
||||
*/
|
||||
getProfile(options?: AuthRequestOptions): Promise<ProfileInfo | undefined>;
|
||||
};
|
||||
@@ -127,23 +142,32 @@ export type ProfileInfoApi = {
|
||||
/**
|
||||
* This API provides access to the user's identity within Backstage.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* An auth provider that implements this interface can be used to sign-in to backstage. It is
|
||||
* not intended to be used directly from a plugin, but instead serves as a connection between
|
||||
* this authentication method and the app's @IdentityApi
|
||||
* this authentication method and the app's {@link IdentityApi}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type BackstageIdentityApi = {
|
||||
/**
|
||||
* Get the user's identity within Backstage. This should normally not be called directly,
|
||||
* use the @IdentityApi instead.
|
||||
* use the {@link IdentityApi} instead.
|
||||
*
|
||||
* If the optional flag is not set, a session is guaranteed to be returned, while if
|
||||
* the optional flag is set, the session may be undefined. See @AuthRequestOptions for more details.
|
||||
* the optional flag is set, the session may be undefined. See {@link AuthRequestOptions} for more details.
|
||||
*/
|
||||
getBackstageIdentity(
|
||||
options?: AuthRequestOptions,
|
||||
): Promise<BackstageIdentity | undefined>;
|
||||
};
|
||||
|
||||
/**
|
||||
* A (user id, token) pair.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type BackstageIdentity = {
|
||||
/**
|
||||
* The backstage user ID.
|
||||
@@ -163,6 +187,8 @@ export type BackstageIdentity = {
|
||||
|
||||
/**
|
||||
* Profile information of the user.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ProfileInfo = {
|
||||
/**
|
||||
@@ -183,14 +209,24 @@ export type ProfileInfo = {
|
||||
|
||||
/**
|
||||
* Session state values passed to subscribers of the SessionApi.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export enum SessionState {
|
||||
/**
|
||||
* User signed in.
|
||||
*/
|
||||
SignedIn = 'SignedIn',
|
||||
/**
|
||||
* User not signed in.
|
||||
*/
|
||||
SignedOut = 'SignedOut',
|
||||
}
|
||||
|
||||
/**
|
||||
* The SessionApi provides basic controls for any auth provider that is tied to a persistent session.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SessionApi = {
|
||||
/**
|
||||
@@ -212,10 +248,14 @@ export type SessionApi = {
|
||||
/**
|
||||
* Provides authentication towards Google APIs and identities.
|
||||
*
|
||||
* See https://developers.google.com/identity/protocols/googlescopes for a full list of supported scopes.
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://developers.google.com/identity/protocols/googlescopes} for a full list of supported scopes.
|
||||
*
|
||||
* Note that the ID token payload is only guaranteed to contain the user's numerical Google ID,
|
||||
* email and expiration information. Do not rely on any other fields, as they might not be present.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const googleAuthApiRef: ApiRef<
|
||||
OAuthApi &
|
||||
@@ -230,8 +270,12 @@ export const googleAuthApiRef: ApiRef<
|
||||
/**
|
||||
* Provides authentication towards GitHub APIs.
|
||||
*
|
||||
* See https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/}
|
||||
* for a full list of supported scopes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const githubAuthApiRef: ApiRef<
|
||||
OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
@@ -242,8 +286,12 @@ export const githubAuthApiRef: ApiRef<
|
||||
/**
|
||||
* Provides authentication towards Okta APIs.
|
||||
*
|
||||
* See https://developer.okta.com/docs/guides/implement-oauth-for-okta/scopes/
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://developer.okta.com/docs/guides/implement-oauth-for-okta/scopes/}
|
||||
* for a full list of supported scopes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const oktaAuthApiRef: ApiRef<
|
||||
OAuthApi &
|
||||
@@ -258,8 +306,12 @@ export const oktaAuthApiRef: ApiRef<
|
||||
/**
|
||||
* Provides authentication towards GitLab APIs.
|
||||
*
|
||||
* See https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#limiting-scopes-of-a-personal-access-token
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#limiting-scopes-of-a-personal-access-token}
|
||||
* for a full list of supported scopes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const gitlabAuthApiRef: ApiRef<
|
||||
OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
@@ -270,8 +322,12 @@ export const gitlabAuthApiRef: ApiRef<
|
||||
/**
|
||||
* Provides authentication towards Auth0 APIs.
|
||||
*
|
||||
* See https://auth0.com/docs/scopes/current/oidc-scopes
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://auth0.com/docs/scopes/current/oidc-scopes}
|
||||
* for a full list of supported scopes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const auth0AuthApiRef: ApiRef<
|
||||
OpenIdConnectApi & ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
@@ -282,9 +338,13 @@ export const auth0AuthApiRef: ApiRef<
|
||||
/**
|
||||
* Provides authentication towards Microsoft APIs and identities.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* For more info and a full list of supported scopes, see:
|
||||
* - https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent
|
||||
* - https://docs.microsoft.com/en-us/graph/permissions-reference
|
||||
* - {@link https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent}
|
||||
* - {@link https://docs.microsoft.com/en-us/graph/permissions-reference}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const microsoftAuthApiRef: ApiRef<
|
||||
OAuthApi &
|
||||
@@ -298,6 +358,8 @@ export const microsoftAuthApiRef: ApiRef<
|
||||
|
||||
/**
|
||||
* Provides authentication for custom identity providers.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const oauth2ApiRef: ApiRef<
|
||||
OAuthApi &
|
||||
@@ -311,6 +373,8 @@ export const oauth2ApiRef: ApiRef<
|
||||
|
||||
/**
|
||||
* Provides authentication for custom OpenID Connect identity providers.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const oidcAuthApiRef: ApiRef<
|
||||
OAuthApi &
|
||||
@@ -323,7 +387,9 @@ export const oidcAuthApiRef: ApiRef<
|
||||
});
|
||||
|
||||
/**
|
||||
* Provides authentication for saml based identity providers
|
||||
* Provides authentication for SAML-based identity providers.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const samlAuthApiRef: ApiRef<
|
||||
ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
@@ -331,6 +397,11 @@ export const samlAuthApiRef: ApiRef<
|
||||
id: 'core.auth.saml',
|
||||
});
|
||||
|
||||
/**
|
||||
* Provides authentication towards OneLogin APIs.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const oneloginAuthApiRef: ApiRef<
|
||||
OAuthApi &
|
||||
OpenIdConnectApi &
|
||||
@@ -344,8 +415,12 @@ export const oneloginAuthApiRef: ApiRef<
|
||||
/**
|
||||
* Provides authentication towards Bitbucket APIs.
|
||||
*
|
||||
* See https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/}
|
||||
* for a full list of supported scopes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const bitbucketAuthApiRef: ApiRef<
|
||||
OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
@@ -356,8 +431,12 @@ export const bitbucketAuthApiRef: ApiRef<
|
||||
/**
|
||||
* Provides authentication towards Atlassian APIs.
|
||||
*
|
||||
* See https://developer.atlassian.com/cloud/jira/platform/scopes-for-connect-and-oauth-2-3LO-apps/
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://developer.atlassian.com/cloud/jira/platform/scopes-for-connect-and-oauth-2-3LO-apps/}
|
||||
* for a full list of supported scopes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const atlassianAuthApiRef: ApiRef<
|
||||
OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
import type { ApiRef } from './types';
|
||||
|
||||
/**
|
||||
* API reference configuration - holds an ID of the referenced API.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ApiRefConfig = {
|
||||
id: string;
|
||||
/**
|
||||
@@ -57,6 +62,13 @@ class ApiRefImpl<T> implements ApiRef<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reference to an API.
|
||||
*
|
||||
* @param config - The descriptor of the API to reference.
|
||||
* @returns An API reference.
|
||||
* @public
|
||||
*/
|
||||
export function createApiRef<T>(config: ApiRefConfig): ApiRef<T> {
|
||||
return new ApiRefImpl<T>(config);
|
||||
}
|
||||
|
||||
@@ -17,19 +17,44 @@
|
||||
import { ApiRef, ApiFactory, TypesToApiRefs } from './types';
|
||||
|
||||
/**
|
||||
* Used to infer types for a standalone ApiFactory that isn't immediately passed
|
||||
* Used to infer types for a standalone {@link ApiFactory} that isn't immediately passed
|
||||
* to another function.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This function doesn't actually do anything, it's only used to infer types.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createApiFactory<
|
||||
Api,
|
||||
Impl extends Api,
|
||||
Deps extends { [name in string]: unknown },
|
||||
>(factory: ApiFactory<Api, Impl, Deps>): ApiFactory<Api, Impl, Deps>;
|
||||
/**
|
||||
* Used to infer types for a standalone {@link ApiFactory} that isn't immediately passed
|
||||
* to another function.
|
||||
*
|
||||
* @param api - Ref of the API that will be produced by the factory.
|
||||
* @param instance - Implementation of the API to use.
|
||||
* @public
|
||||
*/
|
||||
export function createApiFactory<Api, Impl extends Api>(
|
||||
api: ApiRef<Api>,
|
||||
instance: Impl,
|
||||
): ApiFactory<Api, Impl, {}>;
|
||||
/**
|
||||
* Used to infer types for a standalone {@link ApiFactory} that isn't immediately passed
|
||||
* to another function.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Creates factory from {@link ApiRef} or returns the factory itself if provided.
|
||||
*
|
||||
* @param factory - Existing factory or {@link ApiRef}.
|
||||
* @param instance - The instance to be returned by the factory.
|
||||
* @public
|
||||
*/
|
||||
export function createApiFactory<
|
||||
Api,
|
||||
Impl extends Api,
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
|
||||
export { useApi, useApiHolder, withApis } from './useApi';
|
||||
export { createApiRef } from './ApiRef';
|
||||
export type { ApiRefConfig } from './ApiRef';
|
||||
export * from './types';
|
||||
export * from './helpers';
|
||||
|
||||
@@ -14,25 +14,64 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* API reference.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ApiRef<T> = {
|
||||
id: string;
|
||||
T: T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Catch-all {@link ApiRef} type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnyApiRef = ApiRef<unknown>;
|
||||
|
||||
/**
|
||||
* Transforms ApiRef type into its inner API type.
|
||||
*
|
||||
* @public
|
||||
* @deprecated unused type.
|
||||
*/
|
||||
export type ApiRefType<T> = T extends ApiRef<infer U> ? U : never;
|
||||
|
||||
/**
|
||||
* Wraps a type with API properties into a type holding their respective {@link ApiRef}s.
|
||||
* Reverse type transform of {@link ApiRefsToTypes}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type TypesToApiRefs<T> = { [key in keyof T]: ApiRef<T[key]> };
|
||||
|
||||
/**
|
||||
* Unwraps type with {@link ApiRef} properties into a type holding their respective API types.
|
||||
* Reverse type transform of {@link TypesToApiRefs}.
|
||||
*
|
||||
* @public
|
||||
* @deprecated unused type.
|
||||
*/
|
||||
export type ApiRefsToTypes<T extends { [key in string]: ApiRef<unknown> }> = {
|
||||
[key in keyof T]: ApiRefType<T[key]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides lookup of APIs through their {@link ApiRef}s.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ApiHolder = {
|
||||
get<T>(api: ApiRef<T>): T | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes type returning API implementations.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ApiFactory<
|
||||
Api,
|
||||
Impl extends Api,
|
||||
@@ -43,6 +82,11 @@ export type ApiFactory<
|
||||
factory(deps: Deps): Impl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Catch-all {@link ApiFactory} type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnyApiFactory = ApiFactory<
|
||||
unknown,
|
||||
unknown,
|
||||
|
||||
@@ -18,6 +18,11 @@ import React, { PropsWithChildren } from 'react';
|
||||
import { ApiRef, ApiHolder, TypesToApiRefs } from './types';
|
||||
import { useVersionedContext } from '@backstage/version-bridge';
|
||||
|
||||
/**
|
||||
* React hook for retrieving {@link ApiHolder}, an API catalog.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useApiHolder(): ApiHolder {
|
||||
const versionedHolder = useVersionedContext<{ 1: ApiHolder }>('api-context');
|
||||
if (!versionedHolder) {
|
||||
@@ -31,6 +36,12 @@ export function useApiHolder(): ApiHolder {
|
||||
return apiHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* React hook for retrieving APIs.
|
||||
*
|
||||
* @param apiRef - Reference of the API to use.
|
||||
* @public
|
||||
*/
|
||||
export function useApi<T>(apiRef: ApiRef<T>): T {
|
||||
const apiHolder = useApiHolder();
|
||||
|
||||
@@ -41,6 +52,12 @@ export function useApi<T>(apiRef: ApiRef<T>): T {
|
||||
return api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for giving component an API context.
|
||||
*
|
||||
* @param apis - APIs for the context.
|
||||
* @public
|
||||
*/
|
||||
export function withApis<T>(apis: TypesToApiRefs<T>) {
|
||||
return function withApisWrapper<P extends T>(
|
||||
WrappedComponent: React.ComponentType<P>,
|
||||
|
||||
@@ -19,11 +19,21 @@ import { ProfileInfo } from '../apis/definitions';
|
||||
import { IconComponent } from '../icons';
|
||||
import { BackstagePlugin } from '../plugin/types';
|
||||
|
||||
/**
|
||||
* Props for the BootErrorPage.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type BootErrorPageProps = {
|
||||
step: 'load-config' | 'load-chunk';
|
||||
error: Error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Data and handlers associated with the user sign in event.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SignInResult = {
|
||||
/**
|
||||
* User ID that will be returned by the IdentityApi
|
||||
@@ -43,6 +53,11 @@ export type SignInResult = {
|
||||
signOut?: () => Promise<void>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Props for the SignInPage.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SignInPageProps = {
|
||||
/**
|
||||
* Set the sign-in result for the app. This should only be called once.
|
||||
@@ -50,12 +65,22 @@ export type SignInPageProps = {
|
||||
onResult(result: SignInResult): void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Props for the ErrorBoundaryFallback.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ErrorBoundaryFallbackProps = {
|
||||
plugin?: BackstagePlugin;
|
||||
error: Error;
|
||||
resetError: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic app components.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AppComponents = {
|
||||
NotFoundErrorPage: ComponentType<{}>;
|
||||
BootErrorPage: ComponentType<BootErrorPageProps>;
|
||||
@@ -75,6 +100,11 @@ export type AppComponents = {
|
||||
SignInPage?: ComponentType<SignInPageProps>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides plugins and components registered in the app.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AppContext = {
|
||||
/**
|
||||
* Get a list of all plugins that are installed in the app.
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
import { useVersionedContext } from '@backstage/version-bridge';
|
||||
import { AppContext as AppContextV1 } from './types';
|
||||
|
||||
/**
|
||||
* React hook providing {@link AppContext}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const useApp = (): AppContextV1 => {
|
||||
const versionedContext =
|
||||
useVersionedContext<{ 1: AppContextV1 }>('app-context');
|
||||
|
||||
@@ -39,8 +39,9 @@ export type Subscription = CoreSubscription;
|
||||
/**
|
||||
* Observable sequence of values and errors, see TC39.
|
||||
*
|
||||
* https://github.com/tc39/proposal-observable
|
||||
* @remarks
|
||||
*
|
||||
* {@link https://github.com/tc39/proposal-observable}
|
||||
* This is used as a common return type for observable values and can be created
|
||||
* using many different observable implementations, such as zen-observable or RxJS 5.
|
||||
*
|
||||
|
||||
@@ -41,6 +41,18 @@ type MaybeComponentNode = ReactNode & {
|
||||
type?: ComponentWithData;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores data related to a component in a global store.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#component-data}.
|
||||
*
|
||||
* @param component - The component to attach the data to.
|
||||
* @param type - The key under which the data will be stored.
|
||||
* @param data - Arbitrary value.
|
||||
* @public
|
||||
*/
|
||||
export function attachComponentData<P>(
|
||||
component: ComponentType<P>,
|
||||
type: string,
|
||||
@@ -70,6 +82,18 @@ export function attachComponentData<P>(
|
||||
container.map.set(type, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves data attached to a component.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#component-data}.
|
||||
*
|
||||
* @param node - React component to look up.
|
||||
* @param type - Key of the data to retrieve.
|
||||
* @returns Data stored using {@link attachComponentData}.
|
||||
* @public
|
||||
*/
|
||||
export function getComponentData<T>(
|
||||
node: ReactNode,
|
||||
type: string,
|
||||
|
||||
@@ -22,7 +22,12 @@ import { attachComponentData } from './componentData';
|
||||
import { Extension, BackstagePlugin } from '../plugin/types';
|
||||
import { PluginErrorBoundary } from './PluginErrorBoundary';
|
||||
|
||||
type ComponentLoader<T> =
|
||||
/**
|
||||
* Lazy or synchronous retrieving of extension components.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ComponentLoader<T> =
|
||||
| {
|
||||
lazy: () => Promise<T>;
|
||||
}
|
||||
@@ -30,9 +35,19 @@ type ComponentLoader<T> =
|
||||
sync: T;
|
||||
};
|
||||
|
||||
// We do not use ComponentType as the return type, since it doesn't let us convey the children prop.
|
||||
// ComponentType inserts children as an optional prop whether the inner component accepts it or not,
|
||||
// making it impossible to make the usage of children type safe.
|
||||
/**
|
||||
* Extension for components that can have its own URL route (top-level pages, tabs etc.).
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* We do not use ComponentType as the return type, since it doesn't let us convey the children prop.
|
||||
* ComponentType inserts children as an optional prop whether the inner component accepts it or not,
|
||||
* making it impossible to make the usage of children type safe.
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#extensions}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createRoutableExtension<
|
||||
T extends (props: any) => JSX.Element | null,
|
||||
>(options: {
|
||||
@@ -97,9 +112,19 @@ export function createRoutableExtension<
|
||||
});
|
||||
}
|
||||
|
||||
// We do not use ComponentType as the return type, since it doesn't let us convey the children prop.
|
||||
// ComponentType inserts children as an optional prop whether the inner component accepts it or not,
|
||||
// making it impossible to make the usage of children type safe.
|
||||
/**
|
||||
* Plain React component extension.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* We do not use ComponentType as the return type, since it doesn't let us convey the children prop.
|
||||
* ComponentType inserts children as an optional prop whether the inner component accepts it or not,
|
||||
* making it impossible to make the usage of children type safe.
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#extensions}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createComponentExtension<
|
||||
T extends (props: any) => JSX.Element | null,
|
||||
>(options: { component: ComponentLoader<T>; name?: string }): Extension<T> {
|
||||
@@ -107,9 +132,19 @@ export function createComponentExtension<
|
||||
return createReactExtension({ component, name });
|
||||
}
|
||||
|
||||
// We do not use ComponentType as the return type, since it doesn't let us convey the children prop.
|
||||
// ComponentType inserts children as an optional prop whether the inner component accepts it or not,
|
||||
// making it impossible to make the usage of children type safe.
|
||||
/**
|
||||
* Used by {@link createComponentExtension} and {@link createRoutableExtension}.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* We do not use ComponentType as the return type, since it doesn't let us convey the children prop.
|
||||
* ComponentType inserts children as an optional prop whether the inner component accepts it or not,
|
||||
* making it impossible to make the usage of children type safe.
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#extensions}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function createReactExtension<
|
||||
T extends (props: any) => JSX.Element | null,
|
||||
>(options: {
|
||||
|
||||
@@ -20,5 +20,6 @@ export {
|
||||
createRoutableExtension,
|
||||
createComponentExtension,
|
||||
} from './extensions';
|
||||
export type { ComponentLoader } from './extensions';
|
||||
export { useElementFilter } from './useElementFilter';
|
||||
export type { ElementCollection } from './useElementFilter';
|
||||
|
||||
@@ -82,17 +82,23 @@ function selectChildren(
|
||||
* A querying interface tailored to traversing a set of selected React elements
|
||||
* and extracting data.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Methods prefixed with `selectBy` are used to narrow the set of selected elements.
|
||||
*
|
||||
* Methods prefixed with `find` return concrete data using a deep traversal of the set.
|
||||
*
|
||||
* Methods prefixed with `get` return concrete data using a shallow traversal of the set.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ElementCollection {
|
||||
/**
|
||||
* Narrows the set of selected components by doing a deep traversal and
|
||||
* only including those that have defined component data for the given `key`.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Whether an element in the tree has component data set for the given key
|
||||
* is determined by whether `getComponentData` returns undefined.
|
||||
*
|
||||
@@ -104,6 +110,8 @@ export interface ElementCollection {
|
||||
* If `withStrictError` is set, the resulting selection must be a full match, meaning
|
||||
* there may be no elements that were excluded in the selection. If the selection
|
||||
* is not a clean match, an error will be throw with `withStrictError` as the message.
|
||||
*
|
||||
* @param query - Filtering query.
|
||||
*/
|
||||
selectByComponentData(query: {
|
||||
key: string;
|
||||
@@ -113,6 +121,8 @@ export interface ElementCollection {
|
||||
/**
|
||||
* Finds all elements using the same criteria as `selectByComponentData`, but
|
||||
* returns the actual component data of each of those elements instead.
|
||||
*
|
||||
* @param query - Lookup query.
|
||||
*/
|
||||
findComponentData<T>(query: { key: string }): T[];
|
||||
|
||||
@@ -163,7 +173,11 @@ class Collection implements ElementCollection {
|
||||
/**
|
||||
* useElementFilter is a utility that helps you narrow down and retrieve data
|
||||
* from a React element tree, typically operating on the `children` property
|
||||
* passed in to a component. A common use-case is to construct declarative APIs
|
||||
* passed in to a component.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* A common use-case is to construct declarative APIs
|
||||
* where a React component defines its behavior based on its children, such as
|
||||
* the relationship between `Routes` and `Route` in `react-router`.
|
||||
*
|
||||
@@ -175,6 +189,8 @@ class Collection implements ElementCollection {
|
||||
* with added memoization based on the input `node`. If further memoization
|
||||
* dependencies are used in the filter function, they should be added to the
|
||||
* third `dependencies` argument, just like `useMemo`, `useEffect`, etc.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useElementFilter<T>(
|
||||
node: ReactNode,
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type { IconComponent } from './types';
|
||||
export type { IconComponent, OldIconComponent } from './types';
|
||||
|
||||
@@ -21,6 +21,8 @@ import { SvgIconProps } from '@material-ui/core';
|
||||
* IconComponent is the common icon type used throughout Backstage when
|
||||
* working with and rendering generic icons, including the app system icons.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The type is based on SvgIcon from MUI, but both do not what the plugin-api
|
||||
* package to have a dependency on MUI, nor do we want the props to be as broad
|
||||
* as the SvgIconProps interface.
|
||||
@@ -28,6 +30,8 @@ import { SvgIconProps } from '@material-ui/core';
|
||||
* If you have the need to forward additional props from SvgIconProps, you can
|
||||
* open an issue or submit a PR to the main Backstage repo. When doing so please
|
||||
* also describe your use-case and reasoning of the addition.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type IconComponent = ComponentType<{
|
||||
fontSize?: 'default' | 'small' | 'large';
|
||||
@@ -37,5 +41,7 @@ export type IconComponent = ComponentType<{
|
||||
* This exists for backwards compatibility with the old core package.
|
||||
* It's used in some parts of this package in order to smooth out the
|
||||
* migration, but it is not exported.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type OldIconComponent = ComponentType<SvgIconProps>;
|
||||
|
||||
@@ -24,6 +24,9 @@ import {
|
||||
} from './types';
|
||||
import { AnyApiFactory } from '../apis';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class PluginImpl<
|
||||
Routes extends AnyRoutes,
|
||||
ExternalRoutes extends AnyExternalRoutes,
|
||||
@@ -80,6 +83,12 @@ export class PluginImpl<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Backstage Plugin from config.
|
||||
*
|
||||
* @param config - Plugin configuration.
|
||||
* @public
|
||||
*/
|
||||
export function createPlugin<
|
||||
Routes extends AnyRoutes = {},
|
||||
ExternalRoutes extends AnyExternalRoutes = {},
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
export { createPlugin } from './Plugin';
|
||||
export type {
|
||||
AnyExternalRoutes,
|
||||
AnyRoutes,
|
||||
BackstagePlugin,
|
||||
Extension,
|
||||
FeatureFlagOutput,
|
||||
|
||||
@@ -17,29 +17,72 @@
|
||||
import { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing';
|
||||
import { AnyApiFactory } from '../apis/system';
|
||||
|
||||
/**
|
||||
* Route configuration.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type RouteOptions = {
|
||||
// Whether the route path must match exactly, defaults to true.
|
||||
exact?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Type alias for paths.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type RoutePath = string;
|
||||
|
||||
// Replace with using RouteRefs
|
||||
/**
|
||||
* Replace with using {@link RouteRef}s.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type FeatureFlagOutput = {
|
||||
type: 'feature-flag';
|
||||
name: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* {@link FeatureFlagOutput} type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PluginOutput = FeatureFlagOutput;
|
||||
|
||||
/**
|
||||
* Plugin extension type.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#extensions}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type Extension<T> = {
|
||||
expose(plugin: BackstagePlugin<any, any>): T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Catch-all route type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnyRoutes = { [name: string]: RouteRef | SubRouteRef };
|
||||
|
||||
/**
|
||||
* Catch-all type for {@link ExternalRouteRef}s.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnyExternalRoutes = { [name: string]: ExternalRouteRef };
|
||||
|
||||
/**
|
||||
* Plugin type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type BackstagePlugin<
|
||||
Routes extends AnyRoutes = {},
|
||||
ExternalRoutes extends AnyExternalRoutes = {},
|
||||
@@ -52,6 +95,11 @@ export type BackstagePlugin<
|
||||
externalRoutes: ExternalRoutes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plugin descriptor type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PluginConfig<
|
||||
Routes extends AnyRoutes,
|
||||
ExternalRoutes extends AnyExternalRoutes,
|
||||
@@ -63,10 +111,20 @@ export type PluginConfig<
|
||||
externalRoutes?: ExternalRoutes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds hooks registered by the plugin.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type PluginHooks = {
|
||||
featureFlags: FeatureFlagsHooks;
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for registering feature flags hooks.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type FeatureFlagsHooks = {
|
||||
register(name: string): void;
|
||||
};
|
||||
|
||||
@@ -22,6 +22,9 @@ import {
|
||||
OptionalParams,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class ExternalRouteRefImpl<
|
||||
Params extends AnyParams,
|
||||
Optional extends boolean,
|
||||
@@ -42,6 +45,16 @@ export class ExternalRouteRefImpl<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#routing-system}.
|
||||
*
|
||||
* @param options - Description of the route reference to be created.
|
||||
* @public
|
||||
*/
|
||||
export function createExternalRouteRef<
|
||||
Params extends { [param in ParamKey]: string },
|
||||
Optional extends boolean = false,
|
||||
|
||||
@@ -24,6 +24,10 @@ import {
|
||||
import { OldIconComponent } from '../icons/types';
|
||||
|
||||
// TODO(Rugvip): Remove this in the next breaking release, it's exported but unused
|
||||
/**
|
||||
* @deprecated
|
||||
* @internal
|
||||
*/
|
||||
export type RouteRefConfig<Params extends AnyParams> = {
|
||||
params?: ParamKeys<Params>;
|
||||
path?: string;
|
||||
@@ -31,6 +35,9 @@ export type RouteRefConfig<Params extends AnyParams> = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class RouteRefImpl<Params extends AnyParams>
|
||||
implements RouteRef<Params>
|
||||
{
|
||||
@@ -66,6 +73,12 @@ export class RouteRefImpl<Params extends AnyParams>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link RouteRef} from a route descriptor.
|
||||
*
|
||||
* @param config - Description of the route reference to be created.
|
||||
* @public
|
||||
*/
|
||||
export function createRouteRef<
|
||||
// Params is the type that we care about and the one to be embedded in the route ref.
|
||||
// For example, given the params ['name', 'kind'], Params will be {name: string, kind: string}
|
||||
|
||||
@@ -26,6 +26,9 @@ import {
|
||||
// Should match the pattern in react-router
|
||||
const PARAM_PATTERN = /^\w+$/;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class SubRouteRefImpl<Params extends AnyParams>
|
||||
implements SubRouteRef<Params>
|
||||
{
|
||||
@@ -45,18 +48,34 @@ export class SubRouteRefImpl<Params extends AnyParams>
|
||||
}
|
||||
}
|
||||
|
||||
// These utility types help us infer a Param object type from a string path
|
||||
// For example, `/foo/:bar/:baz` inferred to `{ bar: string, baz: string }`
|
||||
type ParamPart<S extends string> = S extends `:${infer Param}` ? Param : never;
|
||||
type ParamNames<S extends string> = S extends `${infer Part}/${infer Rest}`
|
||||
? ParamPart<Part> | ParamNames<Rest>
|
||||
: ParamPart<S>;
|
||||
type PathParams<S extends string> = { [name in ParamNames<S>]: string };
|
||||
/**
|
||||
* Used in {@link PathParams} type declaration.
|
||||
* @public
|
||||
*/
|
||||
export type ParamPart<S extends string> = S extends `:${infer Param}`
|
||||
? Param
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Merges a param object type with with an optional params type into a params object
|
||||
* Used in {@link PathParams} type declaration.
|
||||
* @public
|
||||
*/
|
||||
type MergeParams<
|
||||
export type ParamNames<S extends string> =
|
||||
S extends `${infer Part}/${infer Rest}`
|
||||
? ParamPart<Part> | ParamNames<Rest>
|
||||
: ParamPart<S>;
|
||||
/**
|
||||
* This utility type helps us infer a Param object type from a string path
|
||||
* For example, `/foo/:bar/:baz` inferred to `{ bar: string, baz: string }`
|
||||
* @public
|
||||
*/
|
||||
export type PathParams<S extends string> = { [name in ParamNames<S>]: string };
|
||||
|
||||
/**
|
||||
* Merges a param object type with with an optional params type into a params object.
|
||||
* @public
|
||||
*/
|
||||
export type MergeParams<
|
||||
P1 extends { [param in string]: string },
|
||||
P2 extends AnyParams,
|
||||
> = (P1[keyof P1] extends never ? {} : P1) & (P2 extends undefined ? {} : P2);
|
||||
@@ -64,14 +83,22 @@ type MergeParams<
|
||||
/**
|
||||
* Creates a SubRouteRef type given the desired parameters and parent route parameters.
|
||||
* The parameters types are merged together while ensuring that there is no overlap between the two.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
type MakeSubRouteRef<
|
||||
export type MakeSubRouteRef<
|
||||
Params extends { [param in string]: string },
|
||||
ParentParams extends AnyParams,
|
||||
> = keyof Params & keyof ParentParams extends never
|
||||
? SubRouteRef<OptionalParams<MergeParams<Params, ParentParams>>>
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Create a {@link SubRouteRef} from a route descriptor.
|
||||
*
|
||||
* @param config - Description of the route reference to be created.
|
||||
* @public
|
||||
*/
|
||||
export function createSubRouteRef<
|
||||
Path extends string,
|
||||
ParentParams extends AnyParams = never,
|
||||
|
||||
@@ -14,9 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type { RouteRef, SubRouteRef, ExternalRouteRef } from './types';
|
||||
export type {
|
||||
AnyParams,
|
||||
RouteRef,
|
||||
SubRouteRef,
|
||||
ExternalRouteRef,
|
||||
OptionalParams,
|
||||
ParamKeys,
|
||||
RouteFunc,
|
||||
} from './types';
|
||||
export { createRouteRef } from './RouteRef';
|
||||
export { createSubRouteRef } from './SubRouteRef';
|
||||
export type {
|
||||
MakeSubRouteRef,
|
||||
MergeParams,
|
||||
ParamNames,
|
||||
ParamPart,
|
||||
PathParams,
|
||||
} from './SubRouteRef';
|
||||
export { createExternalRouteRef } from './ExternalRouteRef';
|
||||
export { useRouteRef } from './useRouteRef';
|
||||
export { useRouteRefParams } from './useRouteRefParams';
|
||||
|
||||
@@ -17,32 +17,70 @@
|
||||
import { OldIconComponent } from '../icons/types';
|
||||
import { getOrCreateGlobalSingleton } from '@backstage/version-bridge';
|
||||
|
||||
/**
|
||||
* Catch-all type for route params.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AnyParams = { [param in string]: string } | undefined;
|
||||
|
||||
/**
|
||||
* Type describing the key type of a route parameter mapping.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ParamKeys<Params extends AnyParams> = keyof Params extends never
|
||||
? []
|
||||
: (keyof Params)[];
|
||||
|
||||
/**
|
||||
* Optional route params.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type OptionalParams<Params extends { [param in string]: string }> =
|
||||
Params[keyof Params] extends never ? undefined : Params;
|
||||
|
||||
// The extra TS magic here is to require a single params argument if the RouteRef
|
||||
// had at least one param defined, but require 0 arguments if there are no params defined.
|
||||
// Without this we'd have to pass in empty object to all parameter-less RouteRefs
|
||||
// just to make TypeScript happy, or we would have to make the argument optional in
|
||||
// which case you might forget to pass it in when it is actually required.
|
||||
/**
|
||||
* TS magic for handling route parameters.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* The extra TS magic here is to require a single params argument if the RouteRef
|
||||
* had at least one param defined, but require 0 arguments if there are no params defined.
|
||||
* Without this we'd have to pass in empty object to all parameter-less RouteRefs
|
||||
* just to make TypeScript happy, or we would have to make the argument optional in
|
||||
* which case you might forget to pass it in when it is actually required.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type RouteFunc<Params extends AnyParams> = (
|
||||
...[params]: Params extends undefined ? readonly [] : readonly [Params]
|
||||
) => string;
|
||||
|
||||
// This symbol is what we use at runtime to determine whether a given object
|
||||
// is a type of RouteRef or not. It doesn't work well in TypeScript though since
|
||||
// the `unique symbol` will refer to different values between package versions.
|
||||
// For that reason we use the marker $$routeRefType to represent the symbol at
|
||||
// compile-time instead of using the symbol directly.
|
||||
/**
|
||||
* This symbol is what we use at runtime to determine whether a given object
|
||||
* is a type of RouteRef or not. It doesn't work well in TypeScript though since
|
||||
* the `unique symbol` will refer to different values between package versions.
|
||||
* For that reason we use the marker $$routeRefType to represent the symbol at
|
||||
* compile-time instead of using the symbol directly.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export const routeRefType: unique symbol = getOrCreateGlobalSingleton<any>(
|
||||
'route-ref-type',
|
||||
() => Symbol('route-ref-type'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Absolute route reference.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#routing-system}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type RouteRef<Params extends AnyParams = any> = {
|
||||
$$routeRefType: 'absolute'; // See routeRefType above
|
||||
|
||||
@@ -57,6 +95,15 @@ export type RouteRef<Params extends AnyParams = any> = {
|
||||
title?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Descriptor of a route relative to an absolute {@link RouteRef}.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#routing-system}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type SubRouteRef<Params extends AnyParams = any> = {
|
||||
$$routeRefType: 'sub'; // See routeRefType above
|
||||
|
||||
@@ -67,6 +114,15 @@ export type SubRouteRef<Params extends AnyParams = any> = {
|
||||
params: ParamKeys<Params>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#routing-system}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ExternalRouteRef<
|
||||
Params extends AnyParams = any,
|
||||
Optional extends boolean = any,
|
||||
@@ -78,20 +134,35 @@ export type ExternalRouteRef<
|
||||
optional?: Optional;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type AnyRouteRef =
|
||||
| RouteRef<any>
|
||||
| SubRouteRef<any>
|
||||
| ExternalRouteRef<any, any>;
|
||||
|
||||
// TODO(Rugvip): None of these should be found in the wild anymore, remove in next minor release
|
||||
/** @deprecated */
|
||||
/**
|
||||
* @deprecated
|
||||
* @internal
|
||||
*/
|
||||
export type ConcreteRoute = {};
|
||||
/** @deprecated */
|
||||
/**
|
||||
* @deprecated
|
||||
* @internal
|
||||
*/
|
||||
export type AbsoluteRouteRef = RouteRef<{}>;
|
||||
/** @deprecated */
|
||||
/**
|
||||
* @deprecated
|
||||
* @internal
|
||||
*/
|
||||
export type MutableRouteRef = RouteRef<{}>;
|
||||
|
||||
// A duplicate of the react-router RouteObject, but with routeRef added
|
||||
/**
|
||||
* A duplicate of the react-router RouteObject, but with routeRef added
|
||||
* @internal
|
||||
*/
|
||||
export interface BackstageRouteObject {
|
||||
caseSensitive: boolean;
|
||||
children?: BackstageRouteObject[];
|
||||
|
||||
@@ -25,6 +25,9 @@ import {
|
||||
SubRouteRef,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface RouteResolver {
|
||||
resolve<Params extends AnyParams>(
|
||||
anyRouteRef:
|
||||
@@ -35,12 +38,47 @@ export interface RouteResolver {
|
||||
): RouteFunc<Params> | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* React hook for constructing URLs to routes.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#routing-system}
|
||||
*
|
||||
* @param routeRef - The ref to route that should be converted to URL.
|
||||
* @returns A function that will in turn return the concrete URL of the `routeRef`.
|
||||
* @public
|
||||
*/
|
||||
export function useRouteRef<Optional extends boolean, Params extends AnyParams>(
|
||||
routeRef: ExternalRouteRef<Params, Optional>,
|
||||
): Optional extends true ? RouteFunc<Params> | undefined : RouteFunc<Params>;
|
||||
|
||||
/**
|
||||
* React hook for constructing URLs to routes.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#routing-system}
|
||||
*
|
||||
* @param routeRef - The ref to route that should be converted to URL.
|
||||
* @returns A function that will in turn return the concrete URL of the `routeRef`.
|
||||
* @public
|
||||
*/
|
||||
export function useRouteRef<Params extends AnyParams>(
|
||||
routeRef: RouteRef<Params> | SubRouteRef<Params>,
|
||||
): RouteFunc<Params>;
|
||||
|
||||
/**
|
||||
* React hook for constructing URLs to routes.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* See {@link https://backstage.io/docs/plugins/composability#routing-system}
|
||||
*
|
||||
* @param routeRef - The ref to route that should be converted to URL.
|
||||
* @returns A function that will in turn return the concrete URL of the `routeRef`.
|
||||
* @public
|
||||
*/
|
||||
export function useRouteRef<Params extends AnyParams>(
|
||||
routeRef:
|
||||
| RouteRef<Params>
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { RouteRef, AnyParams, SubRouteRef } from './types';
|
||||
|
||||
/**
|
||||
* React hook for retrieving dynamic params from the current URL.
|
||||
* @param _routeRef - Ref of the current route.
|
||||
* @public
|
||||
*/
|
||||
export function useRouteRefParams<Params extends AnyParams>(
|
||||
_routeRef: RouteRef<Params> | SubRouteRef<Params>,
|
||||
): Params {
|
||||
|
||||
@@ -20,13 +20,9 @@
|
||||
"lint": "lerna run lint --since origin/master --",
|
||||
"lint:all": "lerna run lint --",
|
||||
"prettier:check": "prettier --check .",
|
||||
"create-plugin": "backstage-cli create-plugin --scope internal --no-private",
|
||||
"create-plugin": "backstage-cli create-plugin --scope internal",
|
||||
"remove-plugin": "backstage-cli remove-plugin"
|
||||
},
|
||||
"resolutions": {
|
||||
"graphql-language-service-interface": "2.8.2",
|
||||
"graphql-language-service-parser": "1.9.0"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { Logger } from 'winston';
|
||||
import { pickBy } from 'lodash';
|
||||
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
import { Config } from '@backstage/config';
|
||||
@@ -64,16 +65,20 @@ export class KeyStores {
|
||||
if (provider === 'firestore') {
|
||||
const settings = ks?.getConfig(provider);
|
||||
|
||||
const keyStore = await FirestoreKeyStore.create({
|
||||
projectId: settings?.getOptionalString('projectId'),
|
||||
keyFilename: settings?.getOptionalString('keyFilename'),
|
||||
host: settings?.getOptionalString('host'),
|
||||
port: settings?.getOptionalNumber('port'),
|
||||
ssl: settings?.getOptionalBoolean('ssl'),
|
||||
path: settings?.getOptionalString('path'),
|
||||
timeout: settings?.getOptionalNumber('timeout'),
|
||||
});
|
||||
|
||||
const keyStore = await FirestoreKeyStore.create(
|
||||
pickBy(
|
||||
{
|
||||
projectId: settings?.getOptionalString('projectId'),
|
||||
keyFilename: settings?.getOptionalString('keyFilename'),
|
||||
host: settings?.getOptionalString('host'),
|
||||
port: settings?.getOptionalNumber('port'),
|
||||
ssl: settings?.getOptionalBoolean('ssl'),
|
||||
path: settings?.getOptionalString('path'),
|
||||
timeout: settings?.getOptionalNumber('timeout'),
|
||||
},
|
||||
value => value !== undefined,
|
||||
),
|
||||
);
|
||||
await FirestoreKeyStore.verifyConnection(keyStore, logger);
|
||||
|
||||
return keyStore;
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
```ts
|
||||
import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { BuildResult } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { BuildStatus } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { Config } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { Logger as Logger_2 } from 'winston';
|
||||
import { PullRequestStatus } from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { PullRequest } from '@backstage/plugin-azure-devops-common';
|
||||
import { PullRequestOptions } from '@backstage/plugin-azure-devops-common';
|
||||
import { RepoBuild } from '@backstage/plugin-azure-devops-common';
|
||||
import { WebApi } from 'azure-devops-node-api';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AzureDevOpsApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
@@ -29,8 +29,6 @@ export class AzureDevOpsApi {
|
||||
projectName: string,
|
||||
repoName: string,
|
||||
): Promise<GitRepository>;
|
||||
// Warning: (ae-forgotten-export) The symbol "PullRequestOptions" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
getPullRequests(
|
||||
projectName: string,
|
||||
@@ -45,48 +43,11 @@ export class AzureDevOpsApi {
|
||||
): Promise<RepoBuild[]>;
|
||||
}
|
||||
|
||||
export { BuildResult };
|
||||
|
||||
export { BuildStatus };
|
||||
|
||||
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function createRouter(options: RouterOptions): Promise<express.Router>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PullRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type PullRequest = {
|
||||
pullRequestId?: number;
|
||||
repoName?: string;
|
||||
title?: string;
|
||||
uniqueName?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: Date;
|
||||
sourceRefName?: string;
|
||||
targetRefName?: string;
|
||||
status?: PullRequestStatus;
|
||||
isDraft?: boolean;
|
||||
link: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RepoBuild" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type RepoBuild = {
|
||||
id?: number;
|
||||
title: string;
|
||||
link?: string;
|
||||
status?: BuildStatus;
|
||||
result?: BuildResult;
|
||||
queueTime?: Date;
|
||||
startTime?: Date;
|
||||
finishTime?: Date;
|
||||
source: string;
|
||||
uniqueName?: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RouterOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.9.8",
|
||||
"@backstage/config": "^0.1.11",
|
||||
"@backstage/plugin-azure-devops-common": "^0.0.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"azure-devops-node-api": "^11.0.1",
|
||||
"express": "^4.17.1",
|
||||
|
||||
@@ -16,17 +16,21 @@
|
||||
|
||||
import {
|
||||
Build,
|
||||
DefinitionReference,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import {
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
GitPullRequest,
|
||||
GitRepository,
|
||||
PullRequest,
|
||||
PullRequestStatus,
|
||||
RepoBuild,
|
||||
} from './types';
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import {
|
||||
GitPullRequest,
|
||||
GitRepository,
|
||||
} from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { mappedPullRequest, mappedRepoBuild } from './AzureDevOpsApi';
|
||||
|
||||
import { DefinitionReference } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { IdentityRef } from 'azure-devops-node-api/interfaces/common/VSSInterfaces';
|
||||
|
||||
describe('AzureDevOpsApi', () => {
|
||||
|
||||
@@ -15,17 +15,19 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
Build,
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
GitPullRequest,
|
||||
GitPullRequestSearchCriteria,
|
||||
GitRepository,
|
||||
PullRequest,
|
||||
PullRequestOptions,
|
||||
RepoBuild,
|
||||
} from './types';
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import {
|
||||
GitPullRequest,
|
||||
GitPullRequestSearchCriteria,
|
||||
GitRepository,
|
||||
} from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
|
||||
import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { Logger } from 'winston';
|
||||
import { WebApi } from 'azure-devops-node-api';
|
||||
|
||||
|
||||
@@ -15,5 +15,3 @@
|
||||
*/
|
||||
|
||||
export { AzureDevOpsApi } from './AzureDevOpsApi';
|
||||
export { BuildResult, BuildStatus } from './types';
|
||||
export type { RepoBuild, PullRequest } from './types';
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Build,
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import {
|
||||
GitPullRequest,
|
||||
GitPullRequestSearchCriteria,
|
||||
GitRepository,
|
||||
PullRequestStatus,
|
||||
} from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
|
||||
export { BuildResult, BuildStatus, PullRequestStatus };
|
||||
export type {
|
||||
Build,
|
||||
GitPullRequest,
|
||||
GitPullRequestSearchCriteria,
|
||||
GitRepository,
|
||||
};
|
||||
|
||||
export type RepoBuild = {
|
||||
id?: number;
|
||||
title: string;
|
||||
link?: string;
|
||||
status?: BuildStatus;
|
||||
result?: BuildResult;
|
||||
queueTime?: Date;
|
||||
startTime?: Date;
|
||||
finishTime?: Date;
|
||||
source: string;
|
||||
uniqueName?: string;
|
||||
};
|
||||
|
||||
export type PullRequest = {
|
||||
pullRequestId?: number;
|
||||
repoName?: string;
|
||||
title?: string;
|
||||
uniqueName?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: Date;
|
||||
sourceRefName?: string;
|
||||
targetRefName?: string;
|
||||
status?: PullRequestStatus;
|
||||
isDraft?: boolean;
|
||||
link: string;
|
||||
};
|
||||
|
||||
export type PullRequestOptions = {
|
||||
top: number;
|
||||
status: PullRequestStatus;
|
||||
};
|
||||
@@ -13,6 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { AzureDevOpsApi, BuildResult, BuildStatus } from './api';
|
||||
export type { RepoBuild, PullRequest } from './api';
|
||||
export { AzureDevOpsApi } from './api';
|
||||
export * from './service/router';
|
||||
|
||||
@@ -14,22 +14,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { AzureDevOpsApi } from '../api';
|
||||
import { createRouter } from './router';
|
||||
import { PullRequest, RepoBuild } from '../api/types';
|
||||
import {
|
||||
GitRepository,
|
||||
PullRequestStatus,
|
||||
} from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import {
|
||||
Build,
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
PullRequest,
|
||||
PullRequestStatus,
|
||||
RepoBuild,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { AzureDevOpsApi } from '../api';
|
||||
import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces';
|
||||
import { createRouter } from './router';
|
||||
import express from 'express';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import request from 'supertest';
|
||||
|
||||
describe('createRouter', () => {
|
||||
let azureDevOpsApi: jest.Mocked<AzureDevOpsApi>;
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PullRequestOptions, PullRequestStatus } from '../api/types';
|
||||
import {
|
||||
PullRequestOptions,
|
||||
PullRequestStatus,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import { WebApi, getPersonalAccessTokenHandler } from 'azure-devops-node-api';
|
||||
|
||||
import { AzureDevOpsApi } from '../api';
|
||||
|
||||
@@ -27,6 +27,42 @@ export enum BuildStatus {
|
||||
Postponed = 8,
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PullRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type PullRequest = {
|
||||
pullRequestId?: number;
|
||||
repoName?: string;
|
||||
title?: string;
|
||||
uniqueName?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: Date;
|
||||
sourceRefName?: string;
|
||||
targetRefName?: string;
|
||||
status?: PullRequestStatus;
|
||||
isDraft?: boolean;
|
||||
link: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PullRequestOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type PullRequestOptions = {
|
||||
top: number;
|
||||
status: PullRequestStatus;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "PullRequestStatus" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export enum PullRequestStatus {
|
||||
Abandoned = 2,
|
||||
Active = 1,
|
||||
All = 4,
|
||||
Completed = 3,
|
||||
NotSet = 0,
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RepoBuild" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
@@ -43,5 +79,12 @@ export type RepoBuild = {
|
||||
uniqueName?: string;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RepoBuildOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type RepoBuildOptions = {
|
||||
top?: number;
|
||||
};
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -80,3 +80,49 @@ export type RepoBuild = {
|
||||
source: string;
|
||||
uniqueName?: string;
|
||||
};
|
||||
|
||||
export type RepoBuildOptions = {
|
||||
top?: number;
|
||||
};
|
||||
|
||||
export enum PullRequestStatus {
|
||||
/**
|
||||
* Status not set. Default state.
|
||||
*/
|
||||
NotSet = 0,
|
||||
/**
|
||||
* Pull request is active.
|
||||
*/
|
||||
Active = 1,
|
||||
/**
|
||||
* Pull request is abandoned.
|
||||
*/
|
||||
Abandoned = 2,
|
||||
/**
|
||||
* Pull request is completed.
|
||||
*/
|
||||
Completed = 3,
|
||||
/**
|
||||
* Used in pull request search criteria to include all statuses.
|
||||
*/
|
||||
All = 4,
|
||||
}
|
||||
|
||||
export type PullRequest = {
|
||||
pullRequestId?: number;
|
||||
repoName?: string;
|
||||
title?: string;
|
||||
uniqueName?: string;
|
||||
createdBy?: string;
|
||||
creationDate?: Date;
|
||||
sourceRefName?: string;
|
||||
targetRefName?: string;
|
||||
status?: PullRequestStatus;
|
||||
isDraft?: boolean;
|
||||
link: string;
|
||||
};
|
||||
|
||||
export type PullRequestOptions = {
|
||||
top: number;
|
||||
status: PullRequestStatus;
|
||||
};
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"azure-devops-node-api": "^11.0.1",
|
||||
"luxon": "^2.0.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { RepoBuild, RepoBuildOptions } from './types';
|
||||
import {
|
||||
RepoBuild,
|
||||
RepoBuildOptions,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { createApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const azureDevOpsApiRef = createApiRef<AzureDevOpsApi>({
|
||||
|
||||
@@ -14,9 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AzureDevOpsApi } from './AzureDevOpsApi';
|
||||
import { RepoBuild, RepoBuildOptions } from './types';
|
||||
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
RepoBuild,
|
||||
RepoBuildOptions,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { AzureDevOpsApi } from './AzureDevOpsApi';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
|
||||
export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
|
||||
export type RepoBuild = {
|
||||
id?: number;
|
||||
title: string;
|
||||
link?: string;
|
||||
status?: BuildStatus;
|
||||
result?: BuildResult;
|
||||
queueTime?: Date;
|
||||
source: string;
|
||||
};
|
||||
|
||||
export type RepoBuildOptions = {
|
||||
top?: number;
|
||||
};
|
||||
@@ -17,7 +17,7 @@
|
||||
import {
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import { getBuildResultComponent, getBuildStateComponent } from './BuildTable';
|
||||
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
|
||||
@@ -18,7 +18,8 @@ import { Box, Typography } from '@material-ui/core';
|
||||
import {
|
||||
BuildResult,
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
RepoBuild,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import {
|
||||
Link,
|
||||
ResponseErrorPanel,
|
||||
@@ -34,7 +35,6 @@ import {
|
||||
|
||||
import { DateTime } from 'luxon';
|
||||
import React from 'react';
|
||||
import { RepoBuild } from '../../api/types';
|
||||
|
||||
export const getBuildResultComponent = (result: number | undefined) => {
|
||||
switch (result) {
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { RepoBuild, RepoBuildOptions } from '../api/types';
|
||||
import {
|
||||
RepoBuild,
|
||||
RepoBuildOptions,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
@@ -158,7 +158,11 @@ export const CoverageHistoryChart = () => {
|
||||
margin={{ right: 48, top: 32 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="timestamp" tickFormatter={formatDateToHuman} />
|
||||
<XAxis
|
||||
dataKey="timestamp"
|
||||
tickFormatter={formatDateToHuman}
|
||||
reversed
|
||||
/>
|
||||
<YAxis dataKey="line.percentage" />
|
||||
<YAxis dataKey="branch.percentage" />
|
||||
<Tooltip labelFormatter={formatDateToHuman} />
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import { getVoidLogger, loadBackendConfig } from '@backstage/backend-common';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { Config, ConfigReader } from '@backstage/config';
|
||||
import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
import {
|
||||
ClusterDetails,
|
||||
FetchResponseWrapper,
|
||||
@@ -27,8 +27,8 @@ import {
|
||||
KubernetesServiceLocator,
|
||||
ObjectFetchParams,
|
||||
} from '../types/types';
|
||||
import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common';
|
||||
import { KubernetesBuilder } from './KubernetesBuilder';
|
||||
import { KubernetesFanOutHandler } from './KubernetesFanOutHandler';
|
||||
|
||||
describe('KubernetesBuilder', () => {
|
||||
let app: express.Express;
|
||||
@@ -37,7 +37,12 @@ describe('KubernetesBuilder', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
const logger = getVoidLogger();
|
||||
config = await loadBackendConfig({ logger, argv: [] });
|
||||
config = new ConfigReader({
|
||||
kubernetes: {
|
||||
serviceLocatorMethod: { type: 'multiTenant' },
|
||||
clusterLocatorMethods: [{ type: 'config', clusters: [] }],
|
||||
},
|
||||
});
|
||||
|
||||
const clusters: ClusterDetails[] = [
|
||||
{
|
||||
|
||||
@@ -14,11 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
getVoidLogger,
|
||||
loadBackendConfig,
|
||||
SingleHostDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
import { getVoidLogger, SingleHostDiscovery } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { Request, Response } from 'express';
|
||||
import * as http from 'http';
|
||||
import { createProxyMiddleware, Options } from 'http-proxy-middleware';
|
||||
@@ -35,7 +32,14 @@ const mockCreateProxyMiddleware = createProxyMiddleware as jest.MockedFunction<
|
||||
describe('createRouter', () => {
|
||||
it('works', async () => {
|
||||
const logger = getVoidLogger();
|
||||
const config = await loadBackendConfig({ logger, argv: [] });
|
||||
const config = new ConfigReader({
|
||||
backend: {
|
||||
baseUrl: 'https://example.com:7000',
|
||||
listen: {
|
||||
port: 7000,
|
||||
},
|
||||
},
|
||||
});
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
const router = await createRouter({
|
||||
config,
|
||||
|
||||
+74
-6
@@ -254,7 +254,7 @@ describe('createPublishGithubPullRequestAction', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('with executable file', () => {
|
||||
describe('with executable file mode 755', () => {
|
||||
let input: GithubPullRequestActionInput;
|
||||
let ctx: ActionContext<GithubPullRequestActionInput>;
|
||||
|
||||
@@ -268,9 +268,9 @@ describe('createPublishGithubPullRequestAction', () => {
|
||||
|
||||
mockFs({
|
||||
[workspacePath]: {
|
||||
'file.txt': mockFs.file({
|
||||
content: 'Hello there!',
|
||||
mode: 33277, // File mode: 100755
|
||||
'hello.sh': mockFs.file({
|
||||
content: 'echo Hello there!',
|
||||
mode: 0o100755,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -297,8 +297,76 @@ describe('createPublishGithubPullRequestAction', () => {
|
||||
{
|
||||
commit: 'Create my new app',
|
||||
files: {
|
||||
'file.txt': {
|
||||
content: Buffer.from('Hello there!').toString('base64'),
|
||||
'hello.sh': {
|
||||
content: Buffer.from('echo Hello there!').toString('base64'),
|
||||
encoding: 'base64',
|
||||
mode: '100755',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('creates outputs for the url', async () => {
|
||||
await instance.handler(ctx);
|
||||
|
||||
expect(ctx.output).toHaveBeenCalledWith(
|
||||
'remoteUrl',
|
||||
'https://github.com/myorg/myrepo/pull/123',
|
||||
);
|
||||
});
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with executable file mode 775', () => {
|
||||
let input: GithubPullRequestActionInput;
|
||||
let ctx: ActionContext<GithubPullRequestActionInput>;
|
||||
|
||||
beforeEach(() => {
|
||||
input = {
|
||||
repoUrl: 'github.com?owner=myorg&repo=myrepo',
|
||||
title: 'Create my new app',
|
||||
branchName: 'new-app',
|
||||
description: 'This PR is really good',
|
||||
};
|
||||
|
||||
mockFs({
|
||||
[workspacePath]: {
|
||||
'hello.sh': mockFs.file({
|
||||
content: 'echo Hello there!',
|
||||
mode: 0o100775,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
ctx = {
|
||||
createTemporaryDirectory: jest.fn(),
|
||||
output: jest.fn(),
|
||||
logger: getRootLogger(),
|
||||
logStream: new Writable(),
|
||||
input,
|
||||
workspacePath,
|
||||
};
|
||||
});
|
||||
it('creates a pull request', async () => {
|
||||
await instance.handler(ctx);
|
||||
|
||||
expect(fakeClient.createPullRequest).toHaveBeenCalledWith({
|
||||
owner: 'myorg',
|
||||
repo: 'myrepo',
|
||||
title: 'Create my new app',
|
||||
head: 'new-app',
|
||||
body: 'This PR is really good',
|
||||
changes: [
|
||||
{
|
||||
commit: 'Create my new app',
|
||||
files: {
|
||||
'hello.sh': {
|
||||
content: Buffer.from('echo Hello there!').toString('base64'),
|
||||
encoding: 'base64',
|
||||
mode: '100755',
|
||||
},
|
||||
|
||||
+4
-3
@@ -16,7 +16,7 @@
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import { parseRepoUrl } from './util';
|
||||
import { parseRepoUrl, isExecutable } from './util';
|
||||
|
||||
import {
|
||||
GithubCredentialsProvider,
|
||||
@@ -202,10 +202,11 @@ export const createPublishGithubPullRequestAction = ({
|
||||
.readFileSync(absPath)
|
||||
.toString('base64');
|
||||
const fileStat = fs.statSync(absPath);
|
||||
const isExecutable = fileStat.mode === 33277; // aka. 100755
|
||||
// See the properties of tree items
|
||||
// in https://docs.github.com/en/rest/reference/git#trees
|
||||
const githubTreeItemMode = isExecutable ? '100755' : '100644';
|
||||
const githubTreeItemMode = isExecutable(fileStat.mode)
|
||||
? '100755'
|
||||
: '100644';
|
||||
// Always use base64 encoding to avoid doubling a binary file in size
|
||||
// due to interpreting a binary file as utf-8 and sending github
|
||||
// the utf-8 encoded content.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import { getRepoSourceDirectory } from './util';
|
||||
import { getRepoSourceDirectory, isExecutable } from './util';
|
||||
|
||||
describe('getRepoSourceDirectory', () => {
|
||||
it('should return workspace root if no sub folder is given', () => {
|
||||
@@ -55,3 +55,33 @@ describe('getRepoSourceDirectory', () => {
|
||||
).toEqual(path.join('/', 'var', 'workspace', 'absolute', 'secret'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('isExecutable', () => {
|
||||
it('should return true for file mode 777', () => {
|
||||
expect(isExecutable(0o100777)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 775', () => {
|
||||
expect(isExecutable(0o100775)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 755', () => {
|
||||
expect(isExecutable(0o100755)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 700', () => {
|
||||
expect(isExecutable(0o100700)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 770', () => {
|
||||
expect(isExecutable(0o100770)).toBe(true);
|
||||
});
|
||||
it('should return true for file mode 670', () => {
|
||||
expect(isExecutable(0o100670)).toBe(true);
|
||||
});
|
||||
it('should return false for file mode 644', () => {
|
||||
expect(isExecutable(0o100644)).toBe(false);
|
||||
});
|
||||
it('should return false for file mode 600', () => {
|
||||
expect(isExecutable(0o100600)).toBe(false);
|
||||
});
|
||||
it('should return false for file mode 640', () => {
|
||||
expect(isExecutable(0o100640)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -101,3 +101,8 @@ export const parseRepoUrl = (
|
||||
|
||||
return { host, owner, repo, organization, workspace, project };
|
||||
};
|
||||
export const isExecutable = (fileMode: number) => {
|
||||
const executeBitMask = 0o000111;
|
||||
const res = fileMode & executeBitMask;
|
||||
return res > 0;
|
||||
};
|
||||
|
||||
@@ -9011,10 +9011,10 @@ apollo-server-caching@^0.7.0:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
apollo-server-core@^2.21.0, apollo-server-core@^2.25.2:
|
||||
version "2.25.2"
|
||||
resolved "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.25.2.tgz#ff65da5e512d9b5ca54c8e5e8c78ee28b5987247"
|
||||
integrity sha512-lrohEjde2TmmDTO7FlOs8x5QQbAS0Sd3/t0TaK2TWaodfzi92QAvIsq321Mol6p6oEqmjm8POIDHW1EuJd7XMA==
|
||||
apollo-server-core@^2.25.3:
|
||||
version "2.25.3"
|
||||
resolved "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.25.3.tgz#1a649fd14b3928f5b6e65f0002b380fcfde56862"
|
||||
integrity sha512-Midow3uZoJ9TjFNeCNSiWElTVZlvmB7G7tG6PPoxIR9Px90/v16Q6EzunDIO0rTJHRC3+yCwZkwtf8w2AcP0sA==
|
||||
dependencies:
|
||||
"@apollographql/apollo-tools" "^0.5.0"
|
||||
"@apollographql/graphql-playground-html" "1.6.27"
|
||||
@@ -9055,10 +9055,10 @@ apollo-server-errors@^2.5.0:
|
||||
resolved "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.5.0.tgz#5d1024117c7496a2979e3e34908b5685fe112b68"
|
||||
integrity sha512-lO5oTjgiC3vlVg2RKr3RiXIIQ5pGXBFxYGGUkKDhTud3jMIhs+gel8L8zsEjKaKxkjHhCQAA/bcEfYiKkGQIvA==
|
||||
|
||||
apollo-server-express@^2.16.1, apollo-server-express@^2.21.0:
|
||||
version "2.25.2"
|
||||
resolved "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.25.2.tgz#58cd819694ff4c2dec6945a95c5dff6aa2719ef6"
|
||||
integrity sha512-A2gF2e85vvDugPlajbhr0A14cDFDIGX0mteNOJ8P3Z3cIM0D4hwrWxJidI+SzobefDIyIHu1dynFedJVhV0euQ==
|
||||
apollo-server-express@^2.16.1, apollo-server-express@^2.25.3:
|
||||
version "2.25.3"
|
||||
resolved "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.25.3.tgz#33fe0dae27fa71c8710e714efd93451bf2eb105f"
|
||||
integrity sha512-tTFYn0oKH2qqLwVj7Ez2+MiKleXACODiGh5IxsB7VuYCPMAi9Yl8iUSlwTjQUvgCWfReZjnf0vFL2k5YhDlrtQ==
|
||||
dependencies:
|
||||
"@apollographql/graphql-playground-html" "1.6.27"
|
||||
"@types/accepts" "^1.3.5"
|
||||
@@ -9067,7 +9067,7 @@ apollo-server-express@^2.16.1, apollo-server-express@^2.21.0:
|
||||
"@types/express" "^4.17.12"
|
||||
"@types/express-serve-static-core" "^4.17.21"
|
||||
accepts "^1.3.5"
|
||||
apollo-server-core "^2.25.2"
|
||||
apollo-server-core "^2.25.3"
|
||||
apollo-server-types "^0.9.0"
|
||||
body-parser "^1.18.3"
|
||||
cors "^2.8.5"
|
||||
@@ -9095,12 +9095,12 @@ apollo-server-types@^0.9.0:
|
||||
apollo-server-env "^3.1.0"
|
||||
|
||||
apollo-server@^2.16.1:
|
||||
version "2.21.0"
|
||||
resolved "https://registry.npmjs.org/apollo-server/-/apollo-server-2.21.0.tgz#4e62131885b4a8a26bb8b5e77177bd0d4d210852"
|
||||
integrity sha512-OqngjOSB0MEH6VKGWHcrqt4y39HlhYh9CrMvn4PhadTt53IPYRmBglk5qSRA8xMorGqy60iKrOReqj5YfCjTOg==
|
||||
version "2.25.3"
|
||||
resolved "https://registry.npmjs.org/apollo-server/-/apollo-server-2.25.3.tgz#2e5db9ce5217389625ac5014551dcbdeeedcd1d8"
|
||||
integrity sha512-+eUY2//DLkU7RkJLn6CTl1P89/ZMHuUQnWqv8La2iJ2hLT7Me+nMx+hgHl3LqlT/qDstQ8qA45T85FuCayplmQ==
|
||||
dependencies:
|
||||
apollo-server-core "^2.21.0"
|
||||
apollo-server-express "^2.21.0"
|
||||
apollo-server-core "^2.25.3"
|
||||
apollo-server-express "^2.25.3"
|
||||
express "^4.0.0"
|
||||
graphql-subscriptions "^1.0.0"
|
||||
graphql-tools "^4.0.8"
|
||||
@@ -15591,20 +15591,20 @@ graphql-extensions@^0.15.0:
|
||||
apollo-server-env "^3.1.0"
|
||||
apollo-server-types "^0.9.0"
|
||||
|
||||
graphql-language-service-interface@2.8.2, graphql-language-service-interface@^2.9.0:
|
||||
version "2.8.2"
|
||||
resolved "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.8.2.tgz#b3bb2aef7eaf0dff0b4ea419fa412c5f66fa268b"
|
||||
integrity sha512-otbOQmhgkAJU1QJgQkMztNku6SbJLu/uodoFOYOOtJsizTjrMs93vkYaHCcYnLA3oi1Goj27XcHjMnRCYQOZXQ==
|
||||
graphql-language-service-interface@^2.9.0:
|
||||
version "2.9.1"
|
||||
resolved "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.9.1.tgz#be0b11b06b78730ea9d250e0e2290e7ed9c8d283"
|
||||
integrity sha512-yGsE67fxJBXxY82+rLDMvUpmzpOUM8XFB+k+xOTUyABWs27osKaoGiuDDXAVGg1adhm+cpunWbipe763ZJkAVA==
|
||||
dependencies:
|
||||
graphql-language-service-parser "^1.9.0"
|
||||
graphql-language-service-types "^1.8.0"
|
||||
graphql-language-service-utils "^2.5.1"
|
||||
graphql-language-service-parser "^1.10.0"
|
||||
graphql-language-service-types "^1.8.3"
|
||||
graphql-language-service-utils "^2.6.0"
|
||||
vscode-languageserver-types "^3.15.1"
|
||||
|
||||
graphql-language-service-parser@1.9.0, graphql-language-service-parser@^1.10.0, graphql-language-service-parser@^1.9.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.9.0.tgz#79af21294119a0a7e81b6b994a1af36833bab724"
|
||||
integrity sha512-B5xPZLbBmIp0kHvpY1Z35I5DtPoDK9wGxQVRDIzcBaiIvAmlTrDvjo3bu7vKREdjFbYKvWNgrEWENuprMbF17Q==
|
||||
graphql-language-service-parser@^1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.10.0.tgz#116f4be849754f6afb4c196421a43fe96d87b278"
|
||||
integrity sha512-cLExv0EjqT2hsKdwVTPmKU6eMfjZAjxqywgCPnWD48eJn6tyuePMyG7ye+jpX1PRPPx/cDHfFJGf8sUclchvng==
|
||||
dependencies:
|
||||
graphql-language-service-types "^1.8.0"
|
||||
|
||||
@@ -15618,13 +15618,10 @@ graphql-language-service-types@^1.8.2:
|
||||
resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.8.2.tgz#50ae56f69cc24fcfc3daa129b68b0eb9421e8578"
|
||||
integrity sha512-Sj07RHnMwAhEvAt7Jdt1l/x56ZpoNh+V6g+T58CF6GiYqI5l4vXqqRB4d4xHDcNQX98GpJfnf3o8BqPgP3C5Sw==
|
||||
|
||||
graphql-language-service-utils@^2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.5.1.tgz#832ad4b0a9da03fdded756932c27e057ccf71302"
|
||||
integrity sha512-Lzz723cYrYlVN4WVzIyFGg3ogoe+QYAIBfdtDboiIILoy0FTmqbyC2TOErqbmWKqO4NK9xDA95cSRFbWiHYj0g==
|
||||
dependencies:
|
||||
graphql-language-service-types "^1.8.0"
|
||||
nullthrows "^1.0.0"
|
||||
graphql-language-service-types@^1.8.3:
|
||||
version "1.8.3"
|
||||
resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.8.3.tgz#d7d688d74c122c4d9cc4cceae761a1f2a3c396a1"
|
||||
integrity sha512-m+RHnlGkKDcesW/gC4M7I2pSmWJB84uWS6LtnjplO/07JN312nJCJYCwV/DBny2m1fmSOxN7H/o+JW0l56KwBA==
|
||||
|
||||
graphql-language-service-utils@^2.5.3:
|
||||
version "2.5.3"
|
||||
@@ -15634,6 +15631,14 @@ graphql-language-service-utils@^2.5.3:
|
||||
graphql-language-service-types "^1.8.0"
|
||||
nullthrows "^1.0.0"
|
||||
|
||||
graphql-language-service-utils@^2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.6.0.tgz#d04904641248167ccbb381d8705ba97daa784954"
|
||||
integrity sha512-idqwmbREixhDuQMcYp8WH0btQT02xZny8MO/HduNTVjnPrmTYnZUbpZ9AejdflmaKoS0o8nNvgXQ0GpIOzbG5g==
|
||||
dependencies:
|
||||
graphql-language-service-types "^1.8.3"
|
||||
nullthrows "^1.0.0"
|
||||
|
||||
graphql-language-service@^3.1.6:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-3.2.0.tgz#e0eb6d5dea2cab92549a253d7a6b4fa0cce178b7"
|
||||
|
||||
Reference in New Issue
Block a user