Allow passing identity providers as a union type
This commit is contained in:
@@ -25,14 +25,16 @@ import Root from './components/Root';
|
||||
import * as plugins from './plugins';
|
||||
import { apis } from './apis';
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
import { providers } from './authProviders';
|
||||
import { providers } from './identityProviders';
|
||||
|
||||
const app = createApp({
|
||||
apis,
|
||||
plugins: Object.values(plugins),
|
||||
components: {
|
||||
SignInPage: props => {
|
||||
return <SignInPage {...props} providers={providers} />;
|
||||
return (
|
||||
<SignInPage {...props} providers={['guest', 'custom', ...providers]} />
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -19,9 +19,6 @@ import {
|
||||
gitlabAuthApiRef,
|
||||
oktaAuthApiRef,
|
||||
githubAuthApiRef,
|
||||
commonProvider,
|
||||
customProvider,
|
||||
guestProvider,
|
||||
} from '@backstage/core';
|
||||
|
||||
export const providers = [
|
||||
@@ -30,35 +27,23 @@ export const providers = [
|
||||
title: 'Google',
|
||||
message: 'Sign In using Google',
|
||||
apiRef: googleAuthApiRef,
|
||||
provider: commonProvider,
|
||||
},
|
||||
{
|
||||
id: 'gitlab-auth-provider',
|
||||
title: 'Gitlab',
|
||||
message: 'Sign In using Gitlab',
|
||||
apiRef: gitlabAuthApiRef,
|
||||
provider: commonProvider,
|
||||
},
|
||||
{
|
||||
id: 'github-auth-provider',
|
||||
title: 'Github',
|
||||
message: 'Sign In using Github',
|
||||
apiRef: githubAuthApiRef,
|
||||
provider: commonProvider,
|
||||
},
|
||||
{
|
||||
id: 'okta-auth-provider',
|
||||
title: 'Okta',
|
||||
message: 'Sign In using Okta',
|
||||
apiRef: oktaAuthApiRef,
|
||||
provider: commonProvider,
|
||||
},
|
||||
{
|
||||
id: 'guest-provider',
|
||||
provider: guestProvider,
|
||||
},
|
||||
{
|
||||
id: 'custom-provider',
|
||||
provider: customProvider,
|
||||
},
|
||||
];
|
||||
@@ -21,18 +21,22 @@ import { Content } from '../Content/Content';
|
||||
import { ContentHeader } from '../ContentHeader/ContentHeader';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import { SignInPageProps, useApi, configApiRef } from '@backstage/core-api';
|
||||
import { useSignInProviders } from './providers';
|
||||
import { SignInProviderConfig } from './types';
|
||||
import { useSignInProviders, getSignInProviders } from './providers';
|
||||
import { IdentityProviders } from './types';
|
||||
import { Progress } from '../../components/Progress';
|
||||
|
||||
export type Props = SignInPageProps & {
|
||||
providers: SignInProviderConfig[];
|
||||
providers: IdentityProviders;
|
||||
};
|
||||
|
||||
export const SignInPage: FC<Props> = ({ onResult, providers }) => {
|
||||
export const SignInPage: FC<Props> = ({ onResult, providers = [] }) => {
|
||||
const configApi = useApi(configApiRef);
|
||||
|
||||
const [loading, providerElements] = useSignInProviders(providers, onResult);
|
||||
const signInProviders = getSignInProviders(providers);
|
||||
const [loading, providerElements] = useSignInProviders(
|
||||
signInProviders,
|
||||
onResult,
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
|
||||
@@ -21,12 +21,12 @@ import {
|
||||
ProviderComponent,
|
||||
ProviderLoader,
|
||||
SignInProvider,
|
||||
CommonSignInConfig,
|
||||
SignInConfig,
|
||||
} from './types';
|
||||
import { useApi, errorApiRef } from '@backstage/core-api';
|
||||
|
||||
const Component: ProviderComponent = ({ provider, onResult }) => {
|
||||
const { apiRef, title, message } = provider as CommonSignInConfig;
|
||||
const Component: ProviderComponent = ({ config, onResult }) => {
|
||||
const { apiRef, title, message } = config as SignInConfig;
|
||||
const authApi = useApi(apiRef);
|
||||
const errorApi = useApi(errorApiRef);
|
||||
|
||||
|
||||
@@ -15,6 +15,3 @@
|
||||
*/
|
||||
|
||||
export { SignInPage } from './SignInPage';
|
||||
export { commonProvider } from './commonProvider';
|
||||
export { guestProvider } from './guestProvider';
|
||||
export { customProvider } from './customProvider';
|
||||
|
||||
@@ -22,12 +22,53 @@ import {
|
||||
useApiHolder,
|
||||
errorApiRef,
|
||||
} from '@backstage/core-api';
|
||||
import { SignInProviderConfig, CommonSignInConfig } from './types';
|
||||
import { SignInConfig, IdentityProviders, SignInProvider } from './types';
|
||||
import { commonProvider } from './commonProvider';
|
||||
import { guestProvider } from './guestProvider';
|
||||
import { customProvider } from './customProvider';
|
||||
|
||||
const PROVIDER_STORAGE_KEY = '@backstage/core:SignInPage:provider';
|
||||
|
||||
export type SignInProviderId = 'guest' | 'custom' | string;
|
||||
|
||||
export type SignInProviderType = {
|
||||
[id in SignInProviderId]: {
|
||||
components: SignInProvider;
|
||||
id: SignInProviderId;
|
||||
config?: SignInConfig;
|
||||
};
|
||||
};
|
||||
|
||||
const signInProviders: { [id in SignInProviderId]: SignInProvider } = {
|
||||
guest: guestProvider,
|
||||
custom: customProvider,
|
||||
common: commonProvider,
|
||||
};
|
||||
|
||||
export function getSignInProviders(
|
||||
identityProviders: IdentityProviders,
|
||||
): SignInProviderType {
|
||||
const providers = identityProviders.reduce(
|
||||
(acc: SignInProviderType, config) => {
|
||||
if (typeof config === 'string') {
|
||||
acc[config] = { components: signInProviders[config], id: config };
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
const { id } = config as SignInConfig;
|
||||
acc[id] = { components: signInProviders.common, id, config };
|
||||
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
export const useSignInProviders = (
|
||||
providers: SignInProviderConfig[],
|
||||
providers: SignInProviderType,
|
||||
onResult: SignInPageProps['onResult'],
|
||||
) => {
|
||||
const errorApi = useApi(errorApiRef);
|
||||
@@ -58,7 +99,7 @@ export const useSignInProviders = (
|
||||
// We can't use storageApi here, as it might have a dependency on the IdentityApi
|
||||
const selectedProviderId = localStorage.getItem(
|
||||
PROVIDER_STORAGE_KEY,
|
||||
) as string;
|
||||
) as SignInProviderId;
|
||||
|
||||
// No provider selected, let the user pick one
|
||||
if (selectedProviderId === null) {
|
||||
@@ -66,19 +107,16 @@ export const useSignInProviders = (
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const config = providers.find(
|
||||
provider => provider.id === selectedProviderId,
|
||||
);
|
||||
if (!config) {
|
||||
const provider = providers[selectedProviderId];
|
||||
if (!provider) {
|
||||
setLoading(false);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let didCancel = false;
|
||||
const { apiRef } = config as CommonSignInConfig;
|
||||
|
||||
config.provider
|
||||
.loader(apiHolder, apiRef)
|
||||
provider.components
|
||||
.loader(apiHolder, provider.config?.apiRef!)
|
||||
.then(result => {
|
||||
if (didCancel) {
|
||||
return;
|
||||
@@ -105,19 +143,21 @@ export const useSignInProviders = (
|
||||
// This renders all available sign-in providers
|
||||
const elements = useMemo(
|
||||
() =>
|
||||
providers.map(config => {
|
||||
const { Component } = config.provider;
|
||||
Object.keys(providers).map(key => {
|
||||
const provider = providers[key];
|
||||
|
||||
const { Component } = provider.components;
|
||||
|
||||
const handleResult = (result: SignInResult) => {
|
||||
localStorage.setItem(PROVIDER_STORAGE_KEY, config.id);
|
||||
localStorage.setItem(PROVIDER_STORAGE_KEY, provider.id);
|
||||
|
||||
handleWrappedResult(result);
|
||||
};
|
||||
|
||||
return (
|
||||
<Component
|
||||
key={config.id}
|
||||
provider={config}
|
||||
key={provider.id}
|
||||
config={provider.config!}
|
||||
onResult={handleResult}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -24,30 +24,21 @@ import {
|
||||
ProfileInfoApi,
|
||||
BackstageIdentityApi,
|
||||
SessionStateApi,
|
||||
OpenIdConnectApi,
|
||||
} from '@backstage/core-api';
|
||||
|
||||
export type SignInConfig = {
|
||||
id: string;
|
||||
provider: SignInProvider;
|
||||
};
|
||||
|
||||
export type CommonSignInConfig = SignInConfig & {
|
||||
title: string;
|
||||
message: string;
|
||||
apiRef: ApiRef<
|
||||
OAuthApi &
|
||||
ProfileInfoApi &
|
||||
BackstageIdentityApi &
|
||||
SessionStateApi &
|
||||
OpenIdConnectApi
|
||||
OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionStateApi
|
||||
>;
|
||||
};
|
||||
|
||||
export type SignInProviderConfig = SignInConfig | CommonSignInConfig;
|
||||
export type IdentityProviders = ('guest' | 'custom' | SignInConfig)[];
|
||||
|
||||
export type ProviderComponent = ComponentType<
|
||||
SignInPageProps & { provider: SignInProviderConfig }
|
||||
SignInPageProps & { config: SignInConfig }
|
||||
>;
|
||||
|
||||
export type ProviderLoader = (
|
||||
|
||||
Reference in New Issue
Block a user