Skip to content

Commit d2a03dc

Browse files
Merge branch 'main' into bugfix/document-blueprint-entity-actions
2 parents d83353d + 5963240 commit d2a03dc

File tree

9 files changed

+158
-18
lines changed

9 files changed

+158
-18
lines changed

src/apps/app/app-auth.controller.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
import {
2-
UMB_AUTH_CONTEXT,
3-
UMB_MODAL_APP_AUTH,
4-
UMB_STORAGE_REDIRECT_URL,
5-
type UmbUserLoginState,
6-
} from '@umbraco-cms/backoffice/auth';
1+
import { UMB_AUTH_CONTEXT, UMB_MODAL_APP_AUTH, type UmbUserLoginState } from '@umbraco-cms/backoffice/auth';
72
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
83
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
94
import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
105
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
116
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
7+
import { setStoredPath } from '@umbraco-cms/backoffice/utils';
128

139
export class UmbAppAuthController extends UmbControllerBase {
1410
#authContext?: typeof UMB_AUTH_CONTEXT.TYPE;
@@ -71,7 +67,12 @@ export class UmbAppAuthController extends UmbControllerBase {
7167
}
7268

7369
// Save the current state
74-
sessionStorage.setItem(UMB_STORAGE_REDIRECT_URL, window.location.href);
70+
let currentUrl = window.location.href;
71+
const searchParams = new URLSearchParams(window.location.search);
72+
if (searchParams.has('returnPath')) {
73+
currentUrl = decodeURIComponent(searchParams.get('returnPath') || currentUrl);
74+
}
75+
setStoredPath(currentUrl);
7576

7677
// Figure out which providers are available
7778
const availableProviders = await firstValueFrom(this.#authContext.getAuthProviders(umbExtensionsRegistry));

src/apps/app/app.element.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { UmbAppContext } from './app.context.js';
44
import { UmbServerConnection } from './server-connection.js';
55
import { UmbAppAuthController } from './app-auth.controller.js';
66
import type { UMB_AUTH_CONTEXT } from '@umbraco-cms/backoffice/auth';
7-
import { UMB_STORAGE_REDIRECT_URL, UmbAuthContext } from '@umbraco-cms/backoffice/auth';
7+
import { UmbAuthContext } from '@umbraco-cms/backoffice/auth';
88
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
99
import { UUIIconRegistryEssential } from '@umbraco-cms/backoffice/external/uui';
1010
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@@ -18,6 +18,7 @@ import {
1818
umbExtensionsRegistry,
1919
} from '@umbraco-cms/backoffice/extension-registry';
2020
import { filter, first, firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
21+
import { retrieveStoredPath } from '@umbraco-cms/backoffice/utils';
2122

2223
@customElement('umb-app')
2324
export class UmbAppElement extends UmbLitElement {
@@ -87,13 +88,14 @@ export class UmbAppElement extends UmbLitElement {
8788

8889
this.observe(this.#authContext.authorizationSignal, () => {
8990
// Redirect to the saved state or root
90-
let currentRoute = '';
91-
const savedRoute = sessionStorage.getItem(UMB_STORAGE_REDIRECT_URL);
92-
if (savedRoute) {
93-
sessionStorage.removeItem(UMB_STORAGE_REDIRECT_URL);
94-
currentRoute = savedRoute.endsWith('logout') ? currentRoute : savedRoute;
91+
const url = retrieveStoredPath();
92+
const isBackofficePath = url?.pathname.startsWith(this.backofficePath) ?? true;
93+
94+
if (isBackofficePath) {
95+
history.replaceState(null, '', url?.toString() ?? '');
96+
} else {
97+
window.location.href = url?.toString() ?? this.backofficePath;
9598
}
96-
history.replaceState(null, '', currentRoute);
9799
});
98100
}
99101

@@ -173,9 +175,13 @@ export class UmbAppElement extends UmbLitElement {
173175

174176
// Try to initialise the auth flow and get the runtime status
175177
try {
176-
// If the runtime level is "install" we should clear any cached tokens
178+
// If the runtime level is "install" or ?status=false is set, we should clear any cached tokens
177179
// else we should try and set the auth status
178-
if (this.#serverConnection.getStatus() === RuntimeLevelModel.INSTALL) {
180+
const searchParams = new URLSearchParams(window.location.search);
181+
if (
182+
(searchParams.has('status') && searchParams.get('status') === 'false') ||
183+
this.#serverConnection.getStatus() === RuntimeLevelModel.INSTALL
184+
) {
179185
await this.#authContext.clearTokenStorage();
180186
} else {
181187
await this.#setAuthStatus();

src/packages/core/utils/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ export * from './get-processed-image-url.function.js';
55
export * from './math/math.js';
66
export * from './object/deep-merge.function.js';
77
export * from './pagination-manager/pagination.manager.js';
8+
export * from './path/ensure-local-path.function.js';
89
export * from './path/ensure-path-ends-with-slash.function.js';
910
export * from './path/path-decode.function.js';
1011
export * from './path/path-encode.function.js';
1112
export * from './path/path-folder-name.function.js';
13+
export * from './path/stored-path.function.js';
1214
export * from './path/umbraco-path.function.js';
1315
export * from './path/url-pattern-to-string.function.js';
1416
export * from './selection-manager/selection.manager.js';
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { expect } from '@open-wc/testing';
2+
import { ensureLocalPath } from './ensure-local-path.function.js';
3+
4+
describe('ensureLocalPath', () => {
5+
it('should return the same URL if it is a local URL', () => {
6+
const localUrl = new URL('/test', window.location.origin);
7+
expect(ensureLocalPath(localUrl).href).to.eq(localUrl.href);
8+
});
9+
10+
it('should return the fallback URL if the input URL is not a local URL', () => {
11+
const nonLocalUrl = new URL('https://example.com/test');
12+
const fallbackUrl = new URL('http://localhost/fallback');
13+
expect(ensureLocalPath(nonLocalUrl, fallbackUrl).href).to.eq(fallbackUrl.href);
14+
});
15+
16+
it('should return the same URL if it is a local path', () => {
17+
const localPath = '/test';
18+
expect(ensureLocalPath(localPath).pathname).to.eq(localPath);
19+
});
20+
21+
it('should return the fallback URL if the input path is not a local path', () => {
22+
const nonLocalPath = 'https://example.com/test';
23+
const fallbackUrl = new URL('http://localhost/fallback');
24+
expect(ensureLocalPath(nonLocalPath, fallbackUrl).href).to.eq(fallbackUrl.href);
25+
});
26+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Ensure that the path is a local path.
3+
*/
4+
export function ensureLocalPath(path: URL | string, fallbackPath?: URL | string): URL {
5+
const url = new URL(path, window.location.origin);
6+
if (url.origin === window.location.origin) {
7+
return url;
8+
}
9+
return fallbackPath ? new URL(fallbackPath) : new URL(window.location.origin);
10+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { expect } from '@open-wc/testing';
2+
import { retrieveStoredPath, setStoredPath } from './stored-path.function.js';
3+
import { UMB_STORAGE_REDIRECT_URL } from '@umbraco-cms/backoffice/auth';
4+
5+
describe('retrieveStoredPath', () => {
6+
beforeEach(() => {
7+
sessionStorage.clear();
8+
});
9+
10+
it('should return a null if no path is stored', () => {
11+
expect(retrieveStoredPath()).to.be.null;
12+
});
13+
14+
it('should return the stored path if a path is stored', () => {
15+
const testSafeUrl = new URL('/test', window.location.origin);
16+
setStoredPath(testSafeUrl.toString());
17+
expect(retrieveStoredPath()?.toString()).to.eq(testSafeUrl.toString());
18+
});
19+
20+
it('should remove the stored path after it is retrieved', () => {
21+
setStoredPath('/test');
22+
retrieveStoredPath();
23+
expect(sessionStorage.getItem(UMB_STORAGE_REDIRECT_URL)).to.be.null;
24+
});
25+
26+
it('should return null if the stored path ends with "logout"', () => {
27+
setStoredPath('/logout');
28+
expect(retrieveStoredPath()).to.be.null;
29+
});
30+
31+
it('should not be possible to trick it with a fake URL', () => {
32+
setStoredPath('//www.google.com');
33+
expect(retrieveStoredPath()).to.be.null;
34+
35+
// also test setting it directly in sessionStorage (this will return the current path instead of the fake path)
36+
sessionStorage.setItem(UMB_STORAGE_REDIRECT_URL, '//www.google.com');
37+
expect(retrieveStoredPath()?.pathname).to.eq(window.location.pathname);
38+
});
39+
});
40+
41+
describe('setStoredPath', () => {
42+
beforeEach(() => {
43+
sessionStorage.clear();
44+
});
45+
46+
it('should store a local path', () => {
47+
const testSafeUrl = new URL('/test', window.location.origin);
48+
setStoredPath(testSafeUrl.toString());
49+
expect(sessionStorage.getItem(UMB_STORAGE_REDIRECT_URL)).to.eq(testSafeUrl.toString());
50+
});
51+
52+
it('should not store a non-local path', () => {
53+
setStoredPath('https://example.com/test');
54+
expect(sessionStorage.getItem(UMB_STORAGE_REDIRECT_URL)).to.be.null;
55+
});
56+
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { ensureLocalPath } from './ensure-local-path.function.js';
2+
import { UMB_STORAGE_REDIRECT_URL } from '@umbraco-cms/backoffice/auth';
3+
4+
/**
5+
* Retrieve the stored path from the session storage.
6+
* @remark This is used to redirect the user to the correct page after login.
7+
*/
8+
export function retrieveStoredPath(): URL | null {
9+
let currentRoute = '';
10+
const savedRoute = sessionStorage.getItem(UMB_STORAGE_REDIRECT_URL);
11+
if (savedRoute) {
12+
sessionStorage.removeItem(UMB_STORAGE_REDIRECT_URL);
13+
currentRoute = savedRoute.endsWith('logout') ? currentRoute : savedRoute;
14+
}
15+
16+
return currentRoute ? ensureLocalPath(currentRoute) : null;
17+
}
18+
19+
/**
20+
* Store the path in the session storage.
21+
* @remark This is used to redirect the user to the correct page after login.
22+
* @remark The path must be a local path, otherwise it is not stored.
23+
*/
24+
export function setStoredPath(path: string): void {
25+
const url = new URL(path, window.location.origin);
26+
if (url.origin !== window.location.origin) {
27+
return;
28+
}
29+
sessionStorage.setItem(UMB_STORAGE_REDIRECT_URL, url.toString());
30+
}

src/packages/documents/documents/tree/manifests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const rootTreeItem: ManifestTreeItem = {
5151
type: 'treeItem',
5252
kind: 'default',
5353
alias: 'Umb.TreeItem.Document.Root',
54-
name: 'Document Tree Item',
54+
name: 'Document Tree Root',
5555
forEntityTypes: [UMB_DOCUMENT_ROOT_ENTITY_TYPE],
5656
};
5757

src/packages/media/media/tree/manifests.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,22 @@ const treeItem: ManifestTreeItem = {
4444
name: 'Media Tree Item',
4545
element: () => import('./tree-item/media-tree-item.element.js'),
4646
api: () => import('./tree-item/media-tree-item.context.js'),
47-
forEntityTypes: [UMB_MEDIA_ROOT_ENTITY_TYPE, UMB_MEDIA_ENTITY_TYPE],
47+
forEntityTypes: [UMB_MEDIA_ENTITY_TYPE],
48+
};
49+
50+
const rootTreeItem: ManifestTreeItem = {
51+
type: 'treeItem',
52+
kind: 'default',
53+
alias: 'Umb.TreeItem.Media.Root',
54+
name: 'Media Tree Root',
55+
forEntityTypes: [UMB_MEDIA_ROOT_ENTITY_TYPE],
4856
};
4957

5058
export const manifests: Array<ManifestTypes> = [
5159
treeRepository,
5260
treeStore,
5361
tree,
5462
treeItem,
63+
rootTreeItem,
5564
...reloadTreeItemChildrenManifests,
5665
];

0 commit comments

Comments
 (0)