Merge branch 'master' of https://github.com/backstage/backstage into marley/7678-pull-request-dashboard

This commit is contained in:
Marley Powell
2021-11-09 15:42:45 +00:00
84 changed files with 1577 additions and 697 deletions
+9
View File
@@ -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`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-client': patch
---
Improved API documentation for catalog-client.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': patch
---
Only use settings that have a value when creating a new FirestoreKeyStore instance
+14
View File
@@ -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"
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-code-coverage': patch
---
Make dates in X-Axis sort in ascending order
+14
View File
@@ -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"
},
```
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/core-app-api': patch
'@backstage/core-plugin-api': patch
---
Improve API documentation for @backstage/core-plugin-api
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Fix a bug where only file mode 775 is considered an executable
+5
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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": {
+10 -30
View File
@@ -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;
};
+99 -1
View File
@@ -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,
+123 -10
View File
@@ -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[];
+2 -5
View File
@@ -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>,
+30
View File
@@ -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,
+1 -1
View File
@@ -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,
+59 -1
View File
@@ -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,
+16 -1
View File
@@ -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';
+85 -14
View File
@@ -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 -10
View File
@@ -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;
+3 -42
View File
@@ -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;
};
+1 -2
View File
@@ -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';
+43
View File
@@ -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)
```
+46
View File
@@ -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;
};
-1
View File
@@ -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 {
-34
View File
@@ -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,
@@ -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',
},
@@ -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;
};
+37 -32
View File
@@ -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"