Merge branch 'master' of https://github.com/backstage/backstage into marley/7678-pull-request-custom-filters
This commit is contained in:
@@ -47,6 +47,16 @@ export type AtlassianProviderOptions = {
|
||||
};
|
||||
};
|
||||
|
||||
// @public
|
||||
export type AuthHandler<AuthResult> = (
|
||||
input: AuthResult,
|
||||
) => Promise<AuthHandlerResult>;
|
||||
|
||||
// @public
|
||||
export type AuthHandlerResult = {
|
||||
profile: ProfileInfo;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "AuthProviderFactory" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
@@ -258,7 +268,6 @@ export const createOAuth2Provider: (
|
||||
options?: OAuth2ProviderOptions | undefined,
|
||||
) => AuthProviderFactory;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "OidcProviderOptions" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "createOidcProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
@@ -534,6 +543,20 @@ export type OAuthState = {
|
||||
origin?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type OidcAuthResult = {
|
||||
tokenset: TokenSet;
|
||||
userinfo: UserinfoResponse;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type OidcProviderOptions = {
|
||||
authHandler?: AuthHandler<OidcAuthResult>;
|
||||
signIn?: {
|
||||
resolver?: SignInResolver<OidcAuthResult>;
|
||||
};
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "oktaEmailSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
@@ -606,6 +629,22 @@ export type SamlProviderOptions = {
|
||||
};
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SignInInfo<AuthResult> = {
|
||||
profile: ProfileInfo;
|
||||
result: AuthResult;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type SignInResolver<AuthResult> = (
|
||||
info: SignInInfo<AuthResult>,
|
||||
context: {
|
||||
tokenIssuer: TokenIssuer;
|
||||
catalogIdentityClient: CatalogIdentityClient;
|
||||
logger: Logger_2;
|
||||
},
|
||||
) => Promise<BackstageSignInResult>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "TokenIssuer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
@@ -637,8 +676,6 @@ export type WebMessageResponse =
|
||||
// Warnings were encountered during analysis:
|
||||
//
|
||||
// src/identity/types.d.ts:31:9 - (ae-forgotten-export) The symbol "AnyJWK" needs to be exported by the entry point index.d.ts
|
||||
// src/providers/atlassian/provider.d.ts:37:5 - (ae-forgotten-export) The symbol "AuthHandler" needs to be exported by the entry point index.d.ts
|
||||
// src/providers/atlassian/provider.d.ts:42:9 - (ae-forgotten-export) The symbol "SignInResolver" needs to be exported by the entry point index.d.ts
|
||||
// src/providers/aws-alb/provider.d.ts:77:5 - (ae-forgotten-export) The symbol "AwsAlbResult" needs to be exported by the entry point index.d.ts
|
||||
// src/providers/github/provider.d.ts:71:58 - (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag
|
||||
// src/providers/github/provider.d.ts:71:90 - (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag
|
||||
|
||||
@@ -34,6 +34,10 @@ export type {
|
||||
AuthProviderRouteHandlers,
|
||||
AuthProviderFactoryOptions,
|
||||
AuthProviderFactory,
|
||||
AuthHandler,
|
||||
AuthHandlerResult,
|
||||
SignInResolver,
|
||||
SignInInfo,
|
||||
} from './types';
|
||||
|
||||
// These types are needed for a postMessage from the login pop-up
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type { OidcAuthResult, OidcProviderOptions } from './provider';
|
||||
export { createOidcProvider } from './provider';
|
||||
|
||||
@@ -56,7 +56,11 @@ type OidcImpl = {
|
||||
client: Client;
|
||||
};
|
||||
|
||||
type AuthResult = {
|
||||
/**
|
||||
* authentication result for the OIDC which includes the token set and user information (a profile response sent by OIDC server)
|
||||
* @public
|
||||
*/
|
||||
export type OidcAuthResult = {
|
||||
tokenset: TokenSet;
|
||||
userinfo: UserinfoResponse;
|
||||
};
|
||||
@@ -66,8 +70,8 @@ export type Options = OAuthProviderOptions & {
|
||||
scope?: string;
|
||||
prompt?: string;
|
||||
tokenSignedResponseAlg?: string;
|
||||
signInResolver?: SignInResolver<AuthResult>;
|
||||
authHandler: AuthHandler<AuthResult>;
|
||||
signInResolver?: SignInResolver<OidcAuthResult>;
|
||||
authHandler: AuthHandler<OidcAuthResult>;
|
||||
tokenIssuer: TokenIssuer;
|
||||
catalogIdentityClient: CatalogIdentityClient;
|
||||
logger: Logger;
|
||||
@@ -78,8 +82,8 @@ export class OidcAuthProvider implements OAuthHandlers {
|
||||
private readonly scope?: string;
|
||||
private readonly prompt?: string;
|
||||
|
||||
private readonly signInResolver?: SignInResolver<AuthResult>;
|
||||
private readonly authHandler: AuthHandler<AuthResult>;
|
||||
private readonly signInResolver?: SignInResolver<OidcAuthResult>;
|
||||
private readonly authHandler: AuthHandler<OidcAuthResult>;
|
||||
private readonly tokenIssuer: TokenIssuer;
|
||||
private readonly catalogIdentityClient: CatalogIdentityClient;
|
||||
private readonly logger: Logger;
|
||||
@@ -113,7 +117,7 @@ export class OidcAuthProvider implements OAuthHandlers {
|
||||
): Promise<{ response: OAuthResponse; refreshToken?: string }> {
|
||||
const { strategy } = await this.implementation;
|
||||
const strategyResponse = await executeFrameHandlerStrategy<
|
||||
AuthResult,
|
||||
OidcAuthResult,
|
||||
PrivateInfo
|
||||
>(req, strategy);
|
||||
const {
|
||||
@@ -158,7 +162,7 @@ export class OidcAuthProvider implements OAuthHandlers {
|
||||
(
|
||||
tokenset: TokenSet,
|
||||
userinfo: UserinfoResponse,
|
||||
done: PassportDoneCallback<AuthResult, PrivateInfo>,
|
||||
done: PassportDoneCallback<OidcAuthResult, PrivateInfo>,
|
||||
) => {
|
||||
if (typeof done !== 'function') {
|
||||
throw new Error(
|
||||
@@ -180,7 +184,7 @@ export class OidcAuthProvider implements OAuthHandlers {
|
||||
|
||||
// Use this function to grab the user profile info from the token
|
||||
// Then populate the profile with it
|
||||
private async handleResult(result: AuthResult): Promise<OAuthResponse> {
|
||||
private async handleResult(result: OidcAuthResult): Promise<OAuthResponse> {
|
||||
const { profile } = await this.authHandler(result);
|
||||
const response: OAuthResponse = {
|
||||
providerInfo: {
|
||||
@@ -210,27 +214,37 @@ export class OidcAuthProvider implements OAuthHandlers {
|
||||
}
|
||||
}
|
||||
|
||||
export const oAuth2DefaultSignInResolver: SignInResolver<AuthResult> = async (
|
||||
info,
|
||||
ctx,
|
||||
) => {
|
||||
const { profile } = info;
|
||||
export const oAuth2DefaultSignInResolver: SignInResolver<OidcAuthResult> =
|
||||
async (info, ctx) => {
|
||||
const { profile } = info;
|
||||
|
||||
if (!profile.email) {
|
||||
throw new Error('Profile contained no email');
|
||||
}
|
||||
const userId = profile.email.split('@')[0];
|
||||
const token = await ctx.tokenIssuer.issueToken({
|
||||
claims: { sub: userId, ent: [`user:default/${userId}`] },
|
||||
});
|
||||
return { id: userId, token };
|
||||
};
|
||||
if (!profile.email) {
|
||||
throw new Error('Profile contained no email');
|
||||
}
|
||||
const userId = profile.email.split('@')[0];
|
||||
const token = await ctx.tokenIssuer.issueToken({
|
||||
claims: { sub: userId, ent: [`user:default/${userId}`] },
|
||||
});
|
||||
return { id: userId, token };
|
||||
};
|
||||
|
||||
/**
|
||||
* OIDC provider callback options. An auth handler and a sign in resolver
|
||||
* can be passed while creating a OIDC provider.
|
||||
*
|
||||
* authHandler : called after sign in was successful, a new object must be returned which includes a profile
|
||||
* signInResolver: called after sign in was successful, expects to return a new {@link BackstageSignInResult}
|
||||
*
|
||||
* Both options are optional. There is fallback for authHandler where the default handler expect an e-mail explicitly
|
||||
* otherwise it throws an error
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type OidcProviderOptions = {
|
||||
authHandler?: AuthHandler<AuthResult>;
|
||||
authHandler?: AuthHandler<OidcAuthResult>;
|
||||
|
||||
signIn?: {
|
||||
resolver?: SignInResolver<AuthResult>;
|
||||
resolver?: SignInResolver<OidcAuthResult>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -260,7 +274,7 @@ export const createOidcProvider = (
|
||||
tokenIssuer,
|
||||
});
|
||||
|
||||
const authHandler: AuthHandler<AuthResult> = options?.authHandler
|
||||
const authHandler: AuthHandler<OidcAuthResult> = options?.authHandler
|
||||
? options.authHandler
|
||||
: async ({ userinfo }) => ({
|
||||
profile: {
|
||||
@@ -271,7 +285,7 @@ export const createOidcProvider = (
|
||||
});
|
||||
const signInResolverFn =
|
||||
options?.signIn?.resolver ?? oAuth2DefaultSignInResolver;
|
||||
const signInResolver: SignInResolver<AuthResult> = info =>
|
||||
const signInResolver: SignInResolver<OidcAuthResult> = info =>
|
||||
signInResolverFn(info, {
|
||||
catalogIdentityClient,
|
||||
tokenIssuer,
|
||||
|
||||
@@ -240,6 +240,10 @@ export type ProfileInfo = {
|
||||
picture?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* type of sign in information context, includes the profile information and authentication result which contains auth. related information
|
||||
* @public
|
||||
*/
|
||||
export type SignInInfo<AuthResult> = {
|
||||
/**
|
||||
* The simple profile passed down for use in the frontend.
|
||||
@@ -252,6 +256,11 @@ export type SignInInfo<AuthResult> = {
|
||||
result: AuthResult;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign in resolver type describes the function which handles the result of a successful authentication
|
||||
* and it must return a valid {@link BackstageSignInResult}
|
||||
* @public
|
||||
*/
|
||||
export type SignInResolver<AuthResult> = (
|
||||
info: SignInInfo<AuthResult>,
|
||||
context: {
|
||||
@@ -261,6 +270,10 @@ export type SignInResolver<AuthResult> = (
|
||||
},
|
||||
) => Promise<BackstageSignInResult>;
|
||||
|
||||
/**
|
||||
* The return type of authentication handler which must contain a valid profile information
|
||||
* @public
|
||||
*/
|
||||
export type AuthHandlerResult = { profile: ProfileInfo };
|
||||
|
||||
/**
|
||||
@@ -270,6 +283,8 @@ export type AuthHandlerResult = { profile: ProfileInfo };
|
||||
*
|
||||
* Throwing an error in the function will cause the authentication to fail, making it
|
||||
* possible to use this function as a way to limit access to a certain group of users.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AuthHandler<AuthResult> = (
|
||||
input: AuthResult,
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/plugin-catalog-react
|
||||
|
||||
## 0.6.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4c0f0b2003: Removed dependency on `@backstage/core-app-api`.
|
||||
|
||||
## 0.6.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -271,14 +271,13 @@ export const EntityRefLink: React_2.ForwardRefExoticComponent<
|
||||
| 'children'
|
||||
| 'key'
|
||||
| 'id'
|
||||
| 'className'
|
||||
| 'classes'
|
||||
| 'innerRef'
|
||||
| 'defaultChecked'
|
||||
| 'defaultValue'
|
||||
| 'suppressContentEditableWarning'
|
||||
| 'suppressHydrationWarning'
|
||||
| 'accessKey'
|
||||
| 'className'
|
||||
| 'contentEditable'
|
||||
| 'contextMenu'
|
||||
| 'draggable'
|
||||
@@ -519,6 +518,7 @@ export const EntityRefLink: React_2.ForwardRefExoticComponent<
|
||||
| 'onTransitionEndCapture'
|
||||
| 'component'
|
||||
| 'variant'
|
||||
| 'innerRef'
|
||||
| 'download'
|
||||
| 'href'
|
||||
| 'hrefLang'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-catalog-react",
|
||||
"description": "A frontend library that helps other Backstage plugins interact with the catalog",
|
||||
"version": "0.6.5",
|
||||
"version": "0.6.6",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
@@ -31,7 +31,6 @@
|
||||
"dependencies": {
|
||||
"@backstage/catalog-client": "^0.5.2",
|
||||
"@backstage/catalog-model": "^0.9.7",
|
||||
"@backstage/core-app-api": "^0.2.0",
|
||||
"@backstage/core-components": "^0.8.0",
|
||||
"@backstage/core-plugin-api": "^0.3.0",
|
||||
"@backstage/errors": "^0.1.4",
|
||||
@@ -54,6 +53,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.10.1",
|
||||
"@backstage/core-app-api": "^0.2.0",
|
||||
"@backstage/test-utils": "^0.1.24",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { catalogApiRef } from '../api';
|
||||
import { useEntityListProvider } from './useEntityListProvider';
|
||||
@@ -107,7 +108,9 @@ export function useEntityTypeFilter(): EntityTypeReturn {
|
||||
const stillValidTypes = selectedTypes.filter(value =>
|
||||
newTypes.includes(value),
|
||||
);
|
||||
setSelectedTypes(stillValidTypes);
|
||||
if (!isEqual(selectedTypes, stillValidTypes)) {
|
||||
setSelectedTypes(stillValidTypes);
|
||||
}
|
||||
}, [loading, kind, selectedTypes, setSelectedTypes, entities]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -172,8 +172,9 @@ export const WorkflowRunsTable = ({
|
||||
});
|
||||
|
||||
const githubHost = hostname || 'github.com';
|
||||
const hasNoRuns = !loading && !tableProps.loading && !runs;
|
||||
|
||||
return !runs ? (
|
||||
return hasNoRuns ? (
|
||||
<EmptyState
|
||||
missing="data"
|
||||
title="No Workflow Data"
|
||||
|
||||
@@ -68,7 +68,7 @@ export const createBuiltinActions: (options: {
|
||||
reader: UrlReader;
|
||||
integrations: ScmIntegrations;
|
||||
catalogClient: CatalogApi;
|
||||
containerRunner: ContainerRunner;
|
||||
containerRunner?: ContainerRunner;
|
||||
config: Config;
|
||||
}) => TemplateAction<any>[];
|
||||
|
||||
@@ -289,7 +289,7 @@ export interface RouterOptions {
|
||||
// (undocumented)
|
||||
config: Config;
|
||||
// (undocumented)
|
||||
containerRunner: ContainerRunner;
|
||||
containerRunner?: ContainerRunner;
|
||||
// (undocumented)
|
||||
database: PluginDatabaseManager;
|
||||
// (undocumented)
|
||||
|
||||
@@ -46,22 +46,17 @@ export const createBuiltinActions = (options: {
|
||||
reader: UrlReader;
|
||||
integrations: ScmIntegrations;
|
||||
catalogClient: CatalogApi;
|
||||
containerRunner: ContainerRunner;
|
||||
containerRunner?: ContainerRunner;
|
||||
config: Config;
|
||||
}) => {
|
||||
const { reader, integrations, containerRunner, catalogClient, config } =
|
||||
options;
|
||||
|
||||
return [
|
||||
const actions = [
|
||||
createFetchPlainAction({
|
||||
reader,
|
||||
integrations,
|
||||
}),
|
||||
createFetchCookiecutterAction({
|
||||
reader,
|
||||
integrations,
|
||||
containerRunner,
|
||||
}),
|
||||
createFetchTemplateAction({
|
||||
integrations,
|
||||
reader,
|
||||
@@ -97,4 +92,16 @@ export const createBuiltinActions = (options: {
|
||||
integrations,
|
||||
}),
|
||||
];
|
||||
|
||||
if (containerRunner) {
|
||||
actions.push(
|
||||
createFetchCookiecutterAction({
|
||||
reader,
|
||||
integrations,
|
||||
containerRunner,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return actions;
|
||||
};
|
||||
|
||||
@@ -55,7 +55,7 @@ export interface RouterOptions {
|
||||
catalogClient: CatalogApi;
|
||||
actions?: TemplateAction<any>[];
|
||||
taskWorkers?: number;
|
||||
containerRunner: ContainerRunner;
|
||||
containerRunner?: ContainerRunner;
|
||||
taskBroker?: TaskBroker;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ describe('TechDocsStorageClient', () => {
|
||||
).resolves.toEqual(
|
||||
`${mockBaseUrl}/static/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test.js`,
|
||||
);
|
||||
|
||||
await expect(
|
||||
storageApi.getBaseUrl('../test.js', mockEntity, 'some-docs-path'),
|
||||
).resolves.toEqual(
|
||||
`${mockBaseUrl}/static/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test.js`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return base url with correct entity structure', async () => {
|
||||
|
||||
@@ -263,9 +263,11 @@ export class TechDocsStorageClient implements TechDocsStorageApi {
|
||||
const { kind, namespace, name } = entityId;
|
||||
|
||||
const apiOrigin = await this.getApiOrigin();
|
||||
const newBaseUrl = `${apiOrigin}/static/docs/${namespace}/${kind}/${name}/${path}`;
|
||||
|
||||
return new URL(
|
||||
oldBaseUrl,
|
||||
`${apiOrigin}/static/docs/${namespace}/${kind}/${name}/${path}`,
|
||||
newBaseUrl.endsWith('/') ? newBaseUrl : `${newBaseUrl}/`,
|
||||
).toString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user