@vertesia/ui 1.3.0-dev.20260620.061059Z → 1.3.0-dev.20260621.071017Z
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/router/HistoryNavigator.d.ts.map +1 -1
- package/lib/router/HistoryNavigator.js +4 -1
- package/lib/router/HistoryNavigator.js.map +1 -1
- package/lib/router/Nav.d.ts.map +1 -1
- package/lib/router/Nav.js +7 -1
- package/lib/router/Nav.js.map +1 -1
- package/lib/router/Router.d.ts.map +1 -1
- package/lib/router/Router.js +9 -4
- package/lib/router/Router.js.map +1 -1
- package/lib/router/path.d.ts +15 -0
- package/lib/router/path.d.ts.map +1 -1
- package/lib/router/path.js +43 -0
- package/lib/router/path.js.map +1 -1
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/session/UserSession.js +15 -7
- package/lib/session/UserSession.js.map +1 -1
- package/lib/session/auth/domainRouting.d.ts +10 -0
- package/lib/session/auth/domainRouting.d.ts.map +1 -1
- package/lib/session/auth/domainRouting.js +15 -0
- package/lib/session/auth/domainRouting.js.map +1 -1
- package/lib/vertesia-ui-router.js +1 -1
- package/lib/vertesia-ui-router.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/package.json +6 -6
- package/src/router/HistoryNavigator.ts +4 -1
- package/src/router/Nav.tsx +7 -1
- package/src/router/Router.tsx +9 -4
- package/src/router/path.test.ts +87 -0
- package/src/router/path.ts +38 -0
- package/src/session/UserSession.ts +15 -7
- package/src/session/auth/domainRouting.test.ts +28 -1
- package/src/session/auth/domainRouting.ts +16 -0
|
@@ -5,7 +5,7 @@ import { jwtDecode } from 'jwt-decode';
|
|
|
5
5
|
import { createContext, useContext } from 'react';
|
|
6
6
|
|
|
7
7
|
import { getComposableToken } from './auth/composable';
|
|
8
|
-
import { authReturnUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
|
|
8
|
+
import { authReturnUrl, mountRootUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
|
|
9
9
|
import { getFirebaseAuth } from './auth/firebase';
|
|
10
10
|
|
|
11
11
|
import { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from './constants';
|
|
@@ -168,12 +168,13 @@ class UserSession {
|
|
|
168
168
|
this.authToken = undefined;
|
|
169
169
|
this.setSession = undefined;
|
|
170
170
|
this.client.withAuthCallback(undefined);
|
|
171
|
-
// Navigate to root to avoid React rendering errors when
|
|
171
|
+
// Navigate to the app root to avoid React rendering errors when
|
|
172
172
|
// unmounting deeply nested route components during logout.
|
|
173
|
-
//
|
|
174
|
-
//
|
|
173
|
+
// Use the mount root (not bare '/') so a gateway-mounted app stays
|
|
174
|
+
// on its mount. Only navigate if user was actually logged in to
|
|
175
|
+
// avoid an infinite reload loop on fresh/incognito sessions.
|
|
175
176
|
if (wasLoggedIn) {
|
|
176
|
-
location.replace(
|
|
177
|
+
location.replace(mountRootUrl().toString());
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
180
|
}
|
|
@@ -188,7 +189,9 @@ class UserSession {
|
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
191
|
|
|
191
|
-
|
|
192
|
+
const url = mountRootUrl();
|
|
193
|
+
url.searchParams.set('a', targetAccountId);
|
|
194
|
+
window.location.replace(url.toString());
|
|
192
195
|
}
|
|
193
196
|
|
|
194
197
|
async switchProject(targetProjectId: string) {
|
|
@@ -196,7 +199,12 @@ class UserSession {
|
|
|
196
199
|
localStorage.setItem(`${LastSelectedProjectId_KEY}-${this.account.id}`, targetProjectId);
|
|
197
200
|
}
|
|
198
201
|
|
|
199
|
-
|
|
202
|
+
const url = mountRootUrl();
|
|
203
|
+
if (this.account?.id) {
|
|
204
|
+
url.searchParams.set('a', this.account.id);
|
|
205
|
+
}
|
|
206
|
+
url.searchParams.set('p', targetProjectId);
|
|
207
|
+
window.location.replace(url.toString());
|
|
200
208
|
}
|
|
201
209
|
|
|
202
210
|
async fetchAccounts() {
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { shouldRedirectToCentralAuth, shouldUseFirebaseAuth } from './domainRouting';
|
|
2
|
+
import { mountRootUrl, shouldRedirectToCentralAuth, shouldUseFirebaseAuth } from './domainRouting';
|
|
3
|
+
|
|
4
|
+
// Stub document.baseURI to simulate the served `<base href>` (deep gateway mount) or its absence.
|
|
5
|
+
function setBaseURI(baseURI: string) {
|
|
6
|
+
(globalThis as { document?: unknown }).document = { baseURI };
|
|
7
|
+
}
|
|
3
8
|
|
|
4
9
|
describe('domainRouting', () => {
|
|
5
10
|
afterEach(() => {
|
|
6
11
|
delete (globalThis as { window?: unknown }).window;
|
|
12
|
+
delete (globalThis as { document?: unknown }).document;
|
|
7
13
|
});
|
|
8
14
|
|
|
9
15
|
it("uses Firebase auth when AUTH_MODE is 'firebase'", () => {
|
|
@@ -23,4 +29,25 @@ describe('domainRouting', () => {
|
|
|
23
29
|
expect(shouldUseFirebaseAuth()).toBe(false);
|
|
24
30
|
expect(shouldRedirectToCentralAuth()).toBe(true);
|
|
25
31
|
});
|
|
32
|
+
|
|
33
|
+
describe('mountRootUrl', () => {
|
|
34
|
+
it('returns the deep gateway mount root (dropping any deep route / query / hash)', () => {
|
|
35
|
+
const mount = 'https://gw.example.com/tenants/05948c_5ed5f4/apps/furniture-catalog/versions/v1/app/';
|
|
36
|
+
setBaseURI(mount);
|
|
37
|
+
expect(mountRootUrl().toString()).toBe(mount);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('strips an existing query and hash so callers control the reload target', () => {
|
|
41
|
+
setBaseURI('https://gw.example.com/tenants/t/apps/a/versions/v/app/');
|
|
42
|
+
const url = mountRootUrl();
|
|
43
|
+
url.searchParams.set('a', 'acct1');
|
|
44
|
+
url.searchParams.set('p', 'proj1');
|
|
45
|
+
expect(url.toString()).toBe('https://gw.example.com/tenants/t/apps/a/versions/v/app/?a=acct1&p=proj1');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('is the origin root for the Studio UI (no <base> element)', () => {
|
|
49
|
+
setBaseURI('https://studio.vertesia.io/');
|
|
50
|
+
expect(mountRootUrl().toString()).toBe('https://studio.vertesia.io/');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
26
53
|
});
|
|
@@ -33,3 +33,19 @@ export function authReturnUrl(): URL {
|
|
|
33
33
|
target.hash = '';
|
|
34
34
|
return target;
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The app's mount root URL — the served `<base href>` (or the origin root for the Studio UI).
|
|
39
|
+
*
|
|
40
|
+
* Used for full-reload navigations that intentionally reset to the app root (logout, account /
|
|
41
|
+
* project switch). Building these from a bare `/` drops a gateway-mounted app off its mount and
|
|
42
|
+
* lands on a URL that serves no app; resolving against `document.baseURI` keeps the reload inside
|
|
43
|
+
* the mount. For the Studio UI (no `<base>` element) `document.baseURI` is the origin root, so the
|
|
44
|
+
* behavior is unchanged.
|
|
45
|
+
*/
|
|
46
|
+
export function mountRootUrl(): URL {
|
|
47
|
+
const url = new URL(document.baseURI);
|
|
48
|
+
url.hash = '';
|
|
49
|
+
url.search = '';
|
|
50
|
+
return url;
|
|
51
|
+
}
|