@equinor/fusion-framework-plugin-context-navigation 1.0.0 → 1.0.1
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/dist/esm/__tests__/create-path-adapter.test.js +31 -0
- package/dist/esm/__tests__/create-path-adapter.test.js.map +1 -0
- package/dist/esm/adapters/create-path-adapter.js +9 -6
- package/dist/esm/adapters/create-path-adapter.js.map +1 -1
- package/dist/esm/utils/url/index.js +1 -0
- package/dist/esm/utils/url/index.js.map +1 -1
- package/dist/esm/utils/url/resolve-route-tail.js +21 -0
- package/dist/esm/utils/url/resolve-route-tail.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/__tests__/create-path-adapter.test.d.ts +2 -0
- package/dist/types/__tests__/create-path-adapter.test.d.ts.map +1 -0
- package/dist/types/adapters/create-path-adapter.d.ts.map +1 -1
- package/dist/types/utils/url/index.d.ts +1 -0
- package/dist/types/utils/url/index.d.ts.map +1 -1
- package/dist/types/utils/url/resolve-route-tail.d.ts +14 -0
- package/dist/types/utils/url/resolve-route-tail.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createPathAdapter } from '../adapters/create-path-adapter';
|
|
3
|
+
const CONTEXT_ID = '11111111-1111-1111-1111-111111111111';
|
|
4
|
+
describe('createPathAdapter', () => {
|
|
5
|
+
const adapter = createPathAdapter();
|
|
6
|
+
it('drops the context segment and sub-route when context becomes null', () => {
|
|
7
|
+
const currentURL = new URL(`/apps/my-app/${CONTEXT_ID}/settings/general`, 'https://example.com');
|
|
8
|
+
const result = adapter.encode({ context: null, currentURL });
|
|
9
|
+
expect(result?.pathname).toBe('/apps/my-app');
|
|
10
|
+
});
|
|
11
|
+
it('preserves the sub-route when swapping to a new context', () => {
|
|
12
|
+
const currentURL = new URL(`/apps/my-app/${CONTEXT_ID}/settings/general`, 'https://example.com');
|
|
13
|
+
const result = adapter.encode({
|
|
14
|
+
context: { id: 'new-context-id' },
|
|
15
|
+
currentURL,
|
|
16
|
+
});
|
|
17
|
+
expect(result?.pathname).toBe('/apps/my-app/new-context-id/settings/general');
|
|
18
|
+
});
|
|
19
|
+
it('preserves the full route tail when there was no prior context id to distinguish from a route name', () => {
|
|
20
|
+
// With no active context, the segment after the app key is a route name
|
|
21
|
+
// (e.g. "settings"), not a context id — it must be folded into the tail
|
|
22
|
+
// rather than clobbered by the new context id.
|
|
23
|
+
const currentURL = new URL('/apps/my-app/settings/general', 'https://example.com');
|
|
24
|
+
const result = adapter.encode({
|
|
25
|
+
context: { id: CONTEXT_ID },
|
|
26
|
+
currentURL,
|
|
27
|
+
});
|
|
28
|
+
expect(result?.pathname).toBe(`/apps/my-app/${CONTEXT_ID}/settings/general`);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=create-path-adapter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-path-adapter.test.js","sourceRoot":"","sources":["../../../src/__tests__/create-path-adapter.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,UAAU,GAAG,sCAAsC,CAAC;AAE1D,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IAEpC,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,gBAAgB,UAAU,mBAAmB,EAC7C,qBAAqB,CACtB,CAAC;QACF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAE7D,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,gBAAgB,UAAU,mBAAmB,EAC7C,qBAAqB,CACtB,CAAC;QACF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC5B,OAAO,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAW;YAC1C,UAAU;SACX,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mGAAmG,EAAE,GAAG,EAAE;QAC3G,wEAAwE;QACxE,wEAAwE;QACxE,+CAA+C;QAC/C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,+BAA+B,EAAE,qBAAqB,CAAC,CAAC;QACnF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC5B,OAAO,EAAE,EAAE,EAAE,EAAE,UAAU,EAAW;YACpC,UAAU;SACX,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,gBAAgB,UAAU,mBAAmB,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { stripContextQueryParam } from '../utils/url/strip-context-query-param';
|
|
|
3
3
|
import { parseAppRoute } from '../utils/url/parse-app-route';
|
|
4
4
|
import { UUID_PATTERN } from '../constants';
|
|
5
5
|
import { buildAppRoute } from '../utils/url/build-app-route';
|
|
6
|
+
import { resolveRouteTail } from '../utils/url/resolve-route-tail';
|
|
6
7
|
/**
|
|
7
8
|
* Path adapter — encodes context identity as the first path segment after
|
|
8
9
|
* the app basename.
|
|
@@ -60,18 +61,20 @@ export function createPathAdapter() {
|
|
|
60
61
|
/**
|
|
61
62
|
* Encode context into the URL as a path segment.
|
|
62
63
|
*
|
|
63
|
-
* - **Null context:** removes the context segment
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
64
|
+
* - **Null context:** removes the context segment and drops any sub-route,
|
|
65
|
+
* resetting the app to its root view — there's no valid context to resolve
|
|
66
|
+
* the sub-route against.
|
|
67
|
+
* - **Active context:** places/replaces the context id as the segment after
|
|
68
|
+
* the app key, preserving the existing sub-route.
|
|
68
69
|
*/
|
|
69
70
|
encode({ context, currentURL }) {
|
|
70
71
|
const match = parseAppRoute(currentURL.pathname);
|
|
71
72
|
// Pathname doesn't match the /apps/{key}/... shape — not a Fusion app route, bail out
|
|
72
73
|
if (!match)
|
|
73
74
|
return null;
|
|
74
|
-
const targetPath = context === null
|
|
75
|
+
const targetPath = context === null
|
|
76
|
+
? buildAppRoute(match.appKey)
|
|
77
|
+
: buildAppRoute(match.appKey, context.id, resolveRouteTail(match));
|
|
75
78
|
const url = new URL(targetPath, currentURL.origin);
|
|
76
79
|
url.search = currentURL.search;
|
|
77
80
|
stripContextQueryParam(url);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-path-adapter.js","sourceRoot":"","sources":["../../../src/adapters/create-path-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"create-path-adapter.js","sourceRoot":"","sources":["../../../src/adapters/create-path-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,EAAE,EAAE,MAAM;QAEV;;;;;;WAMG;QACH,SAAS,CAAC,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAA4B;YAC7E,4FAA4F;YAC5F,IAAI,0BAA0B,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC3C,OAAO,KAAK,CAAC;YACf,CAAC;YAED,0FAA0F;YAC1F,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxC,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,QAAQ,GAAG,eAAe,CAAC;YACjC,kEAAkE;YAClE,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;gBACxB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,iFAAiF;YACjF,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAChD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAED;;;;;;;;WAQG;QACH,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,EAAoD;YAC9E,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YACjD,sFAAsF;YACtF,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YAExB,MAAM,UAAU,GACd,OAAO,KAAK,IAAI;gBACd,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC;gBAC7B,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;YAEvE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YACnD,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;YAC/B,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC5B,+EAA+E;YAC/E,OAAO,GAAG,CAAC;QACb,CAAC;QAED;;;;WAIG;QACH,MAAM,CAAC,GAAQ;YACb,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1C,qGAAqG;YACrG,IAAI,KAAK,EAAE,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3D,OAAO,KAAK,CAAC,SAAS,CAAC;YACzB,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -3,5 +3,6 @@ export { buildAppRoute } from './build-app-route';
|
|
|
3
3
|
export { CONTEXT_QUERY_PARAM_KEY, UUID_PATTERN } from '../../constants';
|
|
4
4
|
export { stripContextQueryParam } from './strip-context-query-param';
|
|
5
5
|
export { resolveContextIdFromUrl } from './resolve-context-id-from-url';
|
|
6
|
+
export { resolveRouteTail } from './resolve-route-tail';
|
|
6
7
|
export { buildContextUrlForStrategy } from './build-context-url-for-strategy';
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/utils/url/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/utils/url/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { UUID_PATTERN } from '../../constants';
|
|
2
|
+
/**
|
|
3
|
+
* Reconstructs the full sub-route tail from a parsed app route.
|
|
4
|
+
*
|
|
5
|
+
* `contextId` is a positional capture, not a verified context — when the URL has
|
|
6
|
+
* no active context that slot actually holds a route name (e.g. "settings" in
|
|
7
|
+
* `/apps/app/settings/general`). Folding it back into the tail prevents it from
|
|
8
|
+
* being silently discarded when a real context id is substituted into that slot.
|
|
9
|
+
*
|
|
10
|
+
* @param match - The `contextId`/`rest` segments from `parseAppRoute`.
|
|
11
|
+
* @returns The full sub-route tail, or `undefined` when there is none.
|
|
12
|
+
*/
|
|
13
|
+
export const resolveRouteTail = (match) => {
|
|
14
|
+
// A UUID in this slot is a real context id — the tail is just whatever follows it
|
|
15
|
+
if (match.contextId && UUID_PATTERN.test(match.contextId)) {
|
|
16
|
+
return match.rest;
|
|
17
|
+
}
|
|
18
|
+
// Otherwise the slot is a route name, not a context — rejoin it with the rest to keep the full tail
|
|
19
|
+
return [match.contextId, match.rest].filter(Boolean).join('/') || undefined;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=resolve-route-tail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-route-tail.js","sourceRoot":"","sources":["../../../../src/utils/url/resolve-route-tail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,KAAgD,EAC5B,EAAE;IACtB,kFAAkF;IAClF,IAAI,KAAK,CAAC,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1D,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IACD,oGAAoG;IACpG,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;AAC9E,CAAC,CAAC"}
|
package/dist/esm/version.js
CHANGED