Skip to content

Commit c28b79a

Browse files
committed
docs: add plugin documentation, migration guides, and changesets
VuePress documentation: - Add top-level plugins section with overview of plugin vs module intent and the context-navigation plugin README - Add context routing strategy migration guide under modules/context - Update sidebar and theme config for new plugin section Changesets: - plugin-context-navigation: initial release (minor) - module-context: routing strategy addition (minor) - module-navigation: trailing-slash and basename fix (patch) - dev-portal: context navigation integration (patch) Also updates pnpm-lock.yaml for new plugin package dependency.
1 parent d0513d2 commit c28b79a

10 files changed

Lines changed: 2582 additions & 1147 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@equinor/fusion-framework-dev-portal": patch
3+
---
4+
5+
Integrate `@equinor/fusion-framework-plugin-context-navigation` into the dev portal.
6+
7+
Portal context-to-URL reconciliation is now handled by `@equinor/fusion-framework-plugin-context-navigation`, replacing the ad-hoc hook-based approach.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
"@equinor/fusion-framework-module-context": minor
3+
---
4+
5+
Add configurable `ContextRoutingStrategy` with `query` and `path` modes for context-aware deep links.
6+
7+
The context module now supports a `routingStrategy` configuration field that controls how context identifiers are written to URLs:
8+
9+
- **`query`** (recommended) — encodes context as the `$contextId` query parameter.
10+
- **`path`** — encodes context as a path segment (legacy convention).
11+
12+
URL resolution (reading context from a URL) is always query-first: the plugin checks `$contextId` query param first, then falls back to path-segment extraction regardless of the declared strategy.
13+
14+
Apps with custom URL shapes should use `setContextPathExtractor` / `setContextPathGenerator` hooks directly — the context navigation plugin's custom adapter picks up those hooks automatically without requiring a separate strategy value.
15+
16+
The `generatePathFromContext` callback now receives the active `routingStrategy` as a third argument so host integrations can produce strategy-appropriate URLs.
17+
18+
When no strategy is explicitly configured, the module defaults to `path` for backward compatibility and logs a console warning encouraging explicit configuration.
19+
20+
**Deprecations:** `resolveContextFromPath` utilities are deprecated in favour of `@equinor/fusion-framework-plugin-context-navigation`, which handles URL-to-context reconciliation via adapters. `resolveInitialContext` has been simplified to only resolve from the parent context — URL-based resolution is now handled by the plugin. `extractContextIdFromPath` remains supported — it is the default extractor used by `setContextPathExtractor` and the custom adapter fallback.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@equinor/fusion-framework-module-navigation": patch
3+
---
4+
5+
Fix basename boundary matching and trailing-slash handling.
6+
7+
- `normalizePathname` no longer strips trailing slashes — only collapses consecutive slashes. Trailing slash is now preserved as part of the path identity.
8+
- `_isWithinBasenameScope` uses a path-boundary check (`pathname === basename || pathname.startsWith(basename + '/')`) to prevent false positives from apps with overlapping name prefixes (e.g. `/apps/my-app` no longer matches `/apps/my-app-other/foo`).
9+
- `_localizePath` falls back to `'/'` when the basename-stripped pathname is empty.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
"@equinor/fusion-framework-plugin-context-navigation": minor
3+
---
4+
5+
Initial release of the context navigation plugin.
6+
7+
Adapter-based, event-driven plugin that reconciles context selection with the browser URL for portal hosts. Ships with built-in adapters for query-param, path-segment, and custom URL shapes, plus two pre-wired source strategies:
8+
9+
- **app-first** — app sets context, the plugin encodes it to the URL.
10+
- **context-first** — the plugin decodes context from the URL on startup, redirects to a configurable null-context URL when no context is resolvable.
11+
12+
```ts
13+
import { enableContextNavigation } from '@equinor/fusion-framework-plugin-context-navigation';
14+
import { createAppFirstSource } from '@equinor/fusion-framework-plugin-context-navigation/sources';
15+
16+
enableContextNavigation(configurator, (builder) => {
17+
builder.setSourceFactory(createAppFirstSource());
18+
});
19+
```

pnpm-lock.yaml

Lines changed: 2418 additions & 1147 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vue-press/src/.vuepress/sidebar.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,4 +451,11 @@ export default sidebar({
451451
],
452452
},
453453
],
454+
'/plugins/': [
455+
'',
456+
{
457+
text: 'Context Navigation',
458+
link: 'context-navigation/',
459+
},
460+
],
454461
});

vue-press/src/.vuepress/theme.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const navbar: NavbarOptions = [
1515
text: 'Modules',
1616
link: '/modules/',
1717
},
18+
{
19+
text: 'Plugins',
20+
link: '/plugins/',
21+
},
1822
{
1923
text: 'CLI',
2024
link: '/cli/',
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
title: Migration - Context Routing Strategy
3+
description: Migration guide for adding explicit routing strategy to your app's context module configuration.
4+
category: Module
5+
tag:
6+
- context
7+
- migration
8+
- routing-strategy
9+
- url
10+
- query
11+
- path
12+
---
13+
14+
<!-- @include: ../../../../packages/modules/context/docs/migration-routing-strategy.md -->

vue-press/src/plugins/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
title: Plugins
3+
category: Plugin
4+
tag:
5+
- plugins
6+
- extension
7+
- intent
8+
---
9+
10+
Plugins extend an existing Fusion Framework host with behavior that is optional, targeted, and intent-driven.
11+
12+
Use this section when you need to answer questions like:
13+
14+
- What is a plugin in Fusion Framework?
15+
- Why would I use a plugin instead of a module?
16+
- What behavior does this plugin add to an existing portal or app?
17+
18+
## What Is A Plugin?
19+
20+
A plugin is an add-on that hooks into an already configured Fusion Framework host and contributes one focused behavior.
21+
22+
The key intent is extension, not foundation. A plugin does not usually define a new core runtime capability the way a module does. Instead, a plugin composes with modules that are already present and adds cross-cutting behavior such as URL reconciliation, diagnostics, policy enforcement, or host-specific workflows.
23+
24+
In practice, a plugin is a good fit when the behavior is:
25+
26+
- Optional for the host
27+
- Focused on one workflow or concern
28+
- Built on top of existing module instances
29+
- Easier to enable or disable as a single unit
30+
31+
## Why Use A Plugin?
32+
33+
Use a plugin when you want to capture host intent clearly.
34+
35+
If the host intent is "add this behavior to the portal," a plugin is often the better abstraction than pushing that behavior down into a general-purpose module. That keeps the core module graph smaller and makes the host configuration easier to read.
36+
37+
Plugins are useful because they:
38+
39+
- Make optional behavior explicit in host configuration
40+
- Keep cross-cutting concerns separate from core modules
41+
- Encapsulate one integration pattern behind a small enable/configure surface
42+
- Let portal authors express intent directly: enable this behavior, for this host, with these rules
43+
44+
## Plugin Intent vs Module Intent
45+
46+
Modules and plugins can both affect runtime behavior, but they communicate different intent.
47+
48+
| Surface | Primary intent | Typical role |
49+
|---|---|---|
50+
| **Module** | Provide a core capability | State, services, routing, auth, events, telemetry |
51+
| **Plugin** | Extend a host with focused behavior | Reconciliation, host policies, workflow glue, optional host features |
52+
53+
If your intent is "the framework needs this capability to exist," that usually belongs in a module.
54+
55+
If your intent is "this host should apply this behavior on top of existing capabilities," that usually belongs in a plugin.
56+
57+
## Available Plugins
58+
59+
- [Context Navigation](./context-navigation/)
60+
61+
## Current Plugin
62+
63+
### Context Navigation
64+
65+
The `@equinor/fusion-framework-plugin-context-navigation` package captures a very specific host intent:
66+
67+
keep the browser URL synchronized with the active app context.
68+
69+
It does not replace the context module or navigation module. It composes them. The plugin observes app and context state, chooses the right URL adapter, and applies URL updates consistently for the portal host.
70+
71+
That is a strong plugin fit because the intent is host-level behavior built on top of existing modules rather than a new foundational capability.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
title: Context Navigation Plugin
3+
category: Plugin
4+
tag:
5+
- context
6+
- navigation
7+
- routing
8+
- url-sync
9+
---
10+
11+
<ModuleBadge module="plugins/context-navigation" package="@equinor/fusion-framework-plugin-context-navigation" />
12+
13+
<!-- @include: ../../../../packages/plugins/context-navigation/README.md -->

0 commit comments

Comments
 (0)