core-app-api: navigate to app base URL on signout
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
---
|
||||
|
||||
The `signOut` method of the `IdentityApi` will now navigate the user back to the base URL of the app as indicated by the `app.baseUrl` config.
|
||||
+14
-2
@@ -31,7 +31,7 @@ describe('AppIdentityProxy', () => {
|
||||
|
||||
it('should forward user identities', async () => {
|
||||
const proxy = new AppIdentityProxy();
|
||||
proxy.setTarget(mockIdentityApi);
|
||||
proxy.setTarget(mockIdentityApi, { signOutTargetUrl: '/' });
|
||||
|
||||
const logs = await withLogCollector(async () => {
|
||||
mockIdentityApi.getBackstageIdentity.mockResolvedValueOnce({
|
||||
@@ -55,7 +55,7 @@ describe('AppIdentityProxy', () => {
|
||||
|
||||
it('should warn about invalid user entity refs', async () => {
|
||||
const proxy = new AppIdentityProxy();
|
||||
proxy.setTarget(mockIdentityApi);
|
||||
proxy.setTarget(mockIdentityApi, { signOutTargetUrl: '/' });
|
||||
|
||||
const logs = await withLogCollector(async () => {
|
||||
mockIdentityApi.getBackstageIdentity.mockResolvedValueOnce({
|
||||
@@ -79,4 +79,16 @@ describe('AppIdentityProxy', () => {
|
||||
error: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should navigate to target URL on sign out', async () => {
|
||||
const proxy = new AppIdentityProxy();
|
||||
proxy.setTarget(mockIdentityApi, { signOutTargetUrl: '/foo' });
|
||||
Object.defineProperty(window, 'location', {
|
||||
writable: true,
|
||||
value: {},
|
||||
});
|
||||
|
||||
await proxy.signOut();
|
||||
expect(location.href).toBe('/foo');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -49,6 +49,7 @@ export class AppIdentityProxy implements IdentityApi {
|
||||
private target?: CompatibilityIdentityApi;
|
||||
private waitForTarget: Promise<CompatibilityIdentityApi>;
|
||||
private resolveTarget: (api: CompatibilityIdentityApi) => void = () => {};
|
||||
private signOutTargetUrl = '/';
|
||||
|
||||
constructor() {
|
||||
this.waitForTarget = new Promise<CompatibilityIdentityApi>(resolve => {
|
||||
@@ -57,8 +58,12 @@ export class AppIdentityProxy implements IdentityApi {
|
||||
}
|
||||
|
||||
// This is called by the app manager once the sign-in page provides us with an implementation
|
||||
setTarget(identityApi: CompatibilityIdentityApi) {
|
||||
setTarget(
|
||||
identityApi: CompatibilityIdentityApi,
|
||||
targetOptions: { signOutTargetUrl: string },
|
||||
) {
|
||||
this.target = identityApi;
|
||||
this.signOutTargetUrl = targetOptions.signOutTargetUrl;
|
||||
this.resolveTarget(identityApi);
|
||||
}
|
||||
|
||||
@@ -119,6 +124,6 @@ export class AppIdentityProxy implements IdentityApi {
|
||||
|
||||
async signOut(): Promise<void> {
|
||||
await this.waitForTarget.then(target => target.signOut());
|
||||
location.reload();
|
||||
location.href = this.signOutTargetUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,41 +334,49 @@ export class AppManager implements BackstageApp {
|
||||
children: ReactElement;
|
||||
}) => {
|
||||
const [identityApi, setIdentityApi] = useState<IdentityApi>();
|
||||
const configApi = useApi(configApiRef);
|
||||
const basePath = getBasePath(configApi);
|
||||
|
||||
if (!identityApi) {
|
||||
return <Component onSignInSuccess={setIdentityApi} />;
|
||||
}
|
||||
|
||||
this.appIdentityProxy.setTarget(identityApi);
|
||||
this.appIdentityProxy.setTarget(identityApi, {
|
||||
signOutTargetUrl: basePath || '/',
|
||||
});
|
||||
return children;
|
||||
};
|
||||
|
||||
const AppRouter = ({ children }: PropsWithChildren<{}>) => {
|
||||
const configApi = useApi(configApiRef);
|
||||
const mountPath = `${getBasePath(configApi)}/*`;
|
||||
const basePath = getBasePath(configApi);
|
||||
const mountPath = `${basePath}/*`;
|
||||
const { routeObjects } = useContext(InternalAppContext);
|
||||
|
||||
// If the app hasn't configured a sign-in page, we just continue as guest.
|
||||
if (!SignInPageComponent) {
|
||||
this.appIdentityProxy.setTarget({
|
||||
getUserId: () => 'guest',
|
||||
getIdToken: async () => undefined,
|
||||
getProfile: () => ({
|
||||
email: 'guest@example.com',
|
||||
displayName: 'Guest',
|
||||
}),
|
||||
getProfileInfo: async () => ({
|
||||
email: 'guest@example.com',
|
||||
displayName: 'Guest',
|
||||
}),
|
||||
getBackstageIdentity: async () => ({
|
||||
type: 'user',
|
||||
userEntityRef: 'user:default/guest',
|
||||
ownershipEntityRefs: ['user:default/guest'],
|
||||
}),
|
||||
getCredentials: async () => ({}),
|
||||
signOut: async () => {},
|
||||
});
|
||||
this.appIdentityProxy.setTarget(
|
||||
{
|
||||
getUserId: () => 'guest',
|
||||
getIdToken: async () => undefined,
|
||||
getProfile: () => ({
|
||||
email: 'guest@example.com',
|
||||
displayName: 'Guest',
|
||||
}),
|
||||
getProfileInfo: async () => ({
|
||||
email: 'guest@example.com',
|
||||
displayName: 'Guest',
|
||||
}),
|
||||
getBackstageIdentity: async () => ({
|
||||
type: 'user',
|
||||
userEntityRef: 'user:default/guest',
|
||||
ownershipEntityRefs: ['user:default/guest'],
|
||||
}),
|
||||
getCredentials: async () => ({}),
|
||||
signOut: async () => {},
|
||||
},
|
||||
{ signOutTargetUrl: basePath || '/' },
|
||||
);
|
||||
|
||||
return (
|
||||
<RouterComponent>
|
||||
|
||||
Reference in New Issue
Block a user