Skip to content

Commit 73bfe52

Browse files
authored
fix(module-context): restore path-based initial context resolution (#5288)
* fix(module-context): restore path-based fallback in resolveInitialContext The context-navigation plugin (#4751) removed URL-based resolution from resolveInitialContext in favor of the plugin. Consumers not yet on the plugin lost the ability to resolve initial context from the path, so restore it as a deprecated fallback composed with parent-context resolution. * fix(resolve-initial-context): make options parameter optional in resolveInitialContext
1 parent 5b86d65 commit 73bfe52

5 files changed

Lines changed: 44 additions & 9 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@equinor/fusion-framework-module-context": patch
3+
---
4+
5+
Restore path-based resolution as a fallback in `resolveInitialContext`, composed with parent-context resolution. The context-navigation plugin introduced in #4751 removed this from the module, but consumers not yet migrated to the plugin lost initial-context resolution from the URL. `resolveInitialContext` now accepts a `path` option (`extract`/`validate`) used to resolve context from the URL before falling back to the parent context.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@equinor/fusion-framework-plugin-context-navigation": patch
3+
---
4+
5+
Fix `createPathAdapter` matching on non-app routes. `canHandle` now rejects a URL when `currentURL.pathname` does not parse as a valid app route (e.g. portal chrome), preventing the path adapter from incorrectly claiming ownership of URLs where there is no app route to encode context into.

packages/modules/context/src/configurator.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,12 @@ export class ContextModuleConfigurator implements IContextModuleConfigurator {
249249
Promise.resolve({} as Partial<ContextModuleConfig>),
250250
);
251251

252-
config.resolveInitialContext ??= resolveInitialContext();
252+
config.resolveInitialContext ??= resolveInitialContext({
253+
path: {
254+
extract: config.extractContextIdFromPath,
255+
validate: config.extractContextIdFromPath ? () => true : undefined,
256+
},
257+
});
253258

254259
// TODO(#5119) - make less lazy
255260
config.client ??= await (async (): Promise<ContextModuleConfig['client']> => {
Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import type { ModulesInstance } from '@equinor/fusion-framework-module';
22
import type { ContextModule } from '../module';
33
import type { ContextModuleConfig } from '../configurator';
4-
import { concat, EMPTY, of, take } from 'rxjs';
4+
import { concat, EMPTY, first, of } from 'rxjs';
5+
import resolveContextFromPath, { type ContextPathResolveArgs } from './resolve-context-from-path';
6+
import type { NavigationModule } from '@equinor/fusion-framework-module-navigation';
57

68
/**
79
* Resolves the initial context from the parent module.
@@ -11,6 +13,7 @@ import { concat, EMPTY, of, take } from 'rxjs';
1113
*/
1214
export const resolveContextFromParent: ContextModuleConfig['resolveInitialContext'] = ({ ref }) => {
1315
const parentContext = (ref as ModulesInstance<[ContextModule]>)?.context;
16+
// check if the parent has context module
1417
if (!parentContext) {
1518
// No parent context available — either portal level or parent lacks context module.
1619
return EMPTY;
@@ -22,19 +25,31 @@ export const resolveContextFromParent: ContextModuleConfig['resolveInitialContex
2225
/**
2326
* Resolves the initial context for a Fusion Framework context module.
2427
*
25-
* Attempts to resolve the initial context from the parent context provider.
26-
* URL-based resolution is handled by the context-navigation plugin.
28+
* will try to resolve the initial context from the path, and if that fails, it will try to resolve the context from the parent.
2729
*
30+
* @param options - Optional configuration for resolving the context path.
2831
* @returns A function that accepts the module's reference and modules, and returns an Observable of the resolved initial context.
2932
*/
33+
3034
// Deliberately co-located with resolveContextFromParent, which it composes with
3135
// fusion-lint-disable-next-line single-export-per-file
3236
export const resolveInitialContext =
33-
(): Required<ContextModuleConfig>['resolveInitialContext'] =>
37+
(options?: {
38+
path?: ContextPathResolveArgs;
39+
}): Required<ContextModuleConfig>['resolveInitialContext'] =>
3440
({ ref, modules }) => {
35-
// Resolve from parent context if available.
36-
// URL-based resolution is handled by the context-navigation plugin.
37-
return concat(resolveContextFromParent({ ref, modules })).pipe(take(1));
41+
const { context, navigation } = modules;
42+
// create a path resolver from the context module
43+
const pathResolver = resolveContextFromPath(context, options?.path);
44+
// use the path from the navigation module, or the path from the parent navigation module
45+
const pathname =
46+
navigation?.path.pathname ??
47+
(ref as Partial<ModulesInstance<[NavigationModule]>>).navigation?.path.pathname;
48+
// try to resolve the context from the path, and if that fails, try to resolve the context from the parent
49+
return concat(
50+
pathname ? pathResolver(pathname) : EMPTY,
51+
resolveContextFromParent({ ref, modules }),
52+
).pipe(first());
3853
};
3954

4055
export default resolveInitialContext;

packages/plugins/context-navigation/src/adapters/create-path-adapter.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,17 @@ export function createPathAdapter(): ContextNavigationAdapter {
4141
* Accepts apps with explicit `'path'` strategy or no declared strategy
4242
* (the path adapter serves as the system-wide default fallback).
4343
*/
44-
canHandle({ appContext, routingStrategy }: AdapterResolutionContext): boolean {
44+
canHandle({ appContext, routingStrategy, currentURL }: AdapterResolutionContext): boolean {
4545
// Custom generators mean the app owns its URL shape — the custom adapter handles it, not us
4646
if (hasCustomContextGenerators(appContext)) {
4747
return false;
4848
}
4949

50+
// Not an app route (e.g. portal chrome) — nothing for this adapter to encode context into
51+
if (!parseAppRoute(currentURL.pathname)) {
52+
return false;
53+
}
54+
5055
const declared = routingStrategy;
5156
// App explicitly opted into path-segment routing — take ownership
5257
if (declared === 'path') {

0 commit comments

Comments
 (0)