Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
77ad705
feat(module-state): add robust storage interface, PouchDB adapter, an…
odinr Aug 22, 2025
35abb10
feat(app): add state management module with PouchDB support and enhan…
odinr Aug 25, 2025
bfb2f33
feat(app_state): implement state management with useAppState hook and…
odinr Aug 25, 2025
99f260d
feat(cookbook-react-state): add comprehensive state management cookbo…
odinr Aug 26, 2025
b439b0b
feat(cookbooks-app-react-state-replication): Create a cookbook for st…
odinr Aug 27, 2025
04ff468
docs(state): add cautionary notes and best practices for state manage…
odinr Aug 27, 2025
2bbbe7a
feat: add state management module with sync capabilities and React hooks
odinr Sep 29, 2025
0c2a3e8
fix(state): address code quality review comments on PR #3286
alftore Jun 25, 2026
c73e995
fix: sync pnpm-lock.yaml with workspace:^ specifiers
odinr Aug 4, 2026
a50ff5a
fix: repair rebase-induced regressions and TS7 build breakage
odinr Aug 4, 2026
4a72cf4
chore: fix fusion-lint diagnostics across state module, app, react/ap…
odinr Aug 4, 2026
f6394a5
fix: replace react-router-dom with @equinor/fusion-framework-react-ro…
odinr Aug 4, 2026
9be4107
docs: sync CODEMAP.md with module-state package and new state cookbooks
odinr Aug 4, 2026
d3593e7
chore: align app-react-state cookbook deps with react 19 / typescript 7
odinr Aug 4, 2026
b4ebce8
chore: add changesets for app-react-state cookbook dependency alignment
odinr Aug 4, 2026
3fafb99
fix: use canonical Router component in state-replication cookbook
odinr Aug 4, 2026
67beec6
chore: add changeset for canonical Router migration
odinr Aug 4, 2026
5cb3e32
refactor(module-state): sync remote storage through IHttpClient
odinr Aug 4, 2026
3cb4f09
feat(cookbook-app-react-state): merge app-react-state-replication int…
odinr Aug 5, 2026
6875484
feat(react-app): add useStateSyncEvents hook and fix state module eve…
odinr Aug 5, 2026
eace769
chore: consolidate state feature changesets
odinr Aug 5, 2026
b3165a2
refactor(cookbook-app-react-state): teaching-quality cleanup pass
odinr Aug 5, 2026
c2b9512
style: apply biome formatting fixes flagged by reviewdog
odinr Aug 5, 2026
261dacc
fix(module-state): remove misleading StateErrorEvent from StateSyncEv…
odinr Aug 5, 2026
58fce0b
fix(module-state): correct ./events subpath types path
odinr Aug 5, 2026
10ebe1e
fix(module-state): preserve caller SyncOptions in PouchDbSyncStorage.…
odinr Aug 5, 2026
c51f6a3
fix(react-app): stabilize effect deps and default value in useAppState
odinr Aug 5, 2026
8f0f07d
fix(module): use unknown instead of any in create-module-configs reduce
odinr Aug 5, 2026
9f900df
docs(app): fix Quick Start import to the actual ./enable-state subpath
odinr Aug 5, 2026
720cc33
docs(app): fix escaped {@link} JSDoc tag on AppConfigurator
odinr Aug 5, 2026
44d0087
fix(module-state): tighten AllowedValue to JSON-serializable shapes
odinr Aug 5, 2026
d5467ac
fix(module-state): remove dangling JSDoc block in StateModuleConfig
odinr Aug 5, 2026
d2941eb
fix(module-state): use relative imports for the package's own public API
odinr Aug 5, 2026
fbc78a2
docs: fix backtick-instead-of-apostrophe typo in state caution note
odinr Aug 5, 2026
35c0f5e
chore(react-app): remove unused fast-deep-equal dependency
odinr Aug 5, 2026
a014e9f
docs(react-app): fix useAppState TSDoc issues
odinr Aug 5, 2026
bd4498e
docs(state): distill README into topic guides and wire into vue-press
odinr Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .changeset/app_state-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
"@equinor/fusion-framework-app": minor
---

Add state management module support to @equinor/fusion-framework-app

This change introduces comprehensive state management capabilities to the app package, allowing developers to easily enable persistent state storage in their Fusion applications.

**Features**

- **State Module Enabler**: Added `enableState` function that configures the state module with PouchDB storage
- **Package Exports**: Added new export path `./enable-state` for the state enabler function
- **Type Definitions**: Added typesVersions support for the new state enabler
- **Peer Dependencies**: Added `@equinor/fusion-framework-module-state` as an optional peer dependency
- **Storage Configuration**: Automatic app-scoped storage with key prefixing to prevent state collisions

**Usage**

Applications can now enable state management by:

```typescript
import { enableState } from '@equinor/fusion-framework-app/enable-state';

export const configure = (configurator) => {
enableState(configurator);
};
```

The state module provides persistent storage with automatic app-key scoping and uses PouchDB for reliable data persistence across browser sessions.

**Note**: Applications must install `@equinor/fusion-framework-module-state` to use this functionality.
28 changes: 28 additions & 0 deletions .changeset/cookbook-app-react-state_merge-with-replication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@equinor/fusion-framework-cookbook-app-react-state": major
---

Merged the `app-react-state` and `app-react-state-replication` cookbooks into one comprehensive
`@equinor/fusion-framework-cookbook-app-react-state` cookbook covering the full
`@equinor/fusion-framework-module-state` surface:

- **Basics** page: `useAppState` fundamentals - boolean, string, and optional state with no
`defaultValue` - using the state module's own zero-config default storage.
- **Profile** and **Todos** pages: object and list state, now optionally upgraded to CouchDB
replication via `PouchDbSyncStorage` when `FUSION_SPA_COUCHDB_URL` is set (see `.env.example`)
- unset, the cookbook runs with no Docker/CouchDB setup required.
- Replaced the cookbook's custom `app-state-with-replication` module (a hand-rolled
`StateProvider`/sync-event reimplementation) with the framework's own `PouchDbSyncStorage` and
native `onStateSync.status` / `onStateSync.change` / `onStateSync.complete` / `onStateSync.error`
events, dispatched through the app's `event` module.
- Removed `predev`'s automatic CouchDB startup - `pnpm couchdb:start` is now an explicit, optional
step for trying the replication demo.
- The `SyncStatusMonitor`/`SyncEventList`/`SyncStatusIndicator` components now consume the
framework's `useStateSyncEvents` hook (`@equinor/fusion-framework-react-app/state`) instead of a
cookbook-local hook/Context reimplementation of the same subscription logic.
- Simplified `ProfileManager` from 10 files (a `@equinor/fusion-observable` reducer, action
creators, and seven single-field presentational components) down to a single component using
plain `useAppState` + immutable object spreads, matching the pattern already used by the
`Basics` and `Todos` pages - and dropped the now-unused `@equinor/fusion-observable` dependency.
- Removed leftover debug `console.log`s and dead types (`SyncStatus`, `ReplicationSettings`) left
over from the pre-merge, hand-rolled sync implementation.
40 changes: 40 additions & 0 deletions .changeset/module-state_sync-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
"@equinor/fusion-framework-module-state": major
---

**🚀 Introducing the Fusion Framework State Module**

**@equinor/fusion-framework-module-state** is a new reactive state management module with built-in synchronization capabilities and comprehensive event system for enterprise-grade applications.

**🗄️ Synchronization Features**
- **PouchDbSyncStorage**: Bidirectional synchronization with remote databases
- **Real-time sync events**: Monitor sync progress, errors, and status changes
- **Conflict resolution**: Automatic handling of concurrent data modifications
- **Live sync options**: Configurable heartbeat, retry, and timeout settings

**📡 Event System**
Comprehensive event architecture for type-safe state management:

**Event Classes:**
- `StateEntryCreatedEvent` - Item creation tracking
- `StateEntryUpdatedEvent` - Item modification events
- `StateEntryDeletedEvent` - Item removal notifications
- `StateSyncChangeEvent` - Sync data changes
- `StateSyncCompleteEvent` - Sync operation completion
- `StateSyncErrorEvent` - Sync failure handling
- `StateSyncStatusEvent` - Sync status monitoring
- `StateOperationSuccessEvent` - Successful operations
- `StateOperationFailureEvent` - Operation failure tracking

**Event Organization:**
- `StateChangeEvent` - CRUD operation events
- `StateSyncEvent` - Synchronization events
- `StateOperationEvent` - Operation result events

**🏗️ Core Architecture**
- **StateProvider**: Reactive state management with observable patterns
- **Storage Interface**: Extensible storage backends with sync capabilities
- **Type Safety**: Comprehensive TypeScript definitions
- **Memory Management**: Proper cleanup and disposal patterns
- Storage and sync events are dispatched through the app's `event` module, so `onStateSync.*`
listeners registered via `useAppModule('event').addEventListener(...)` actually fire.
5 changes: 5 additions & 0 deletions .changeset/module_fix-reduce-type-inference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@equinor/fusion-framework-module": patch
---

Internal: pin explicit generic types on the `reduce` operator in `createModuleConfigs` so the accumulator type is no longer inferred as `unknown` under TypeScript 7's stricter inference, which broke builds for consumers with composite project references.
32 changes: 32 additions & 0 deletions .changeset/react-app_state-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
"@equinor/fusion-framework-react-app": minor
---

Add state management support to `@equinor/fusion-framework-react-app/state`:

- `enableAppState` - configures the app to use `@equinor/fusion-framework-module-state`, with
app-scoped storage key prefixing to prevent state collisions between apps.
- `useAppState` - a persistent, cross-component-synchronized alternative to `useState`, backed by
the state module's storage.
- `useStateSyncEvents` - subscribes to the app's `onStateSync.status`/`.change`/`.complete`/`.error`
events (dispatched when storage is configured for replication, e.g. `PouchDbSyncStorage`) and
returns the most recent events, oldest first, bounded to a given `limit`. Also re-exports
`StateSyncEvent` and `StateSyncEventType` from `@equinor/fusion-framework-module-state` for
convenience.

```typescript
import { enableAppState } from '@equinor/fusion-framework-react-app/state';

export const configure = (configurator) => {
enableAppState(configurator);
};
```

```typescript
import { useAppState, useStateSyncEvents } from '@equinor/fusion-framework-react-app/state';

const [count, setCount] = useAppState('counter', { defaultValue: 0 });
const events = useStateSyncEvents(20);
```

Requires the optional peer dependency `@equinor/fusion-framework-module-state`.
6 changes: 4 additions & 2 deletions CODEMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Format: `package name` → path → role.
| `@equinor/fusion-framework-module-service-discovery` | `packages/modules/service-discovery` | Service discovery |
| `@equinor/fusion-framework-module-services` | `packages/modules/services` | Typed Fusion service clients |
| `@equinor/fusion-framework-module-signalr` | `packages/modules/signalr` | SignalR transport |
| `@equinor/fusion-framework-module-state` | `packages/modules/state` | Replicated/persisted app state (PouchDB-backed sync) |
| `@equinor/fusion-framework-module-telemetry` | `packages/modules/telemetry` | Microsoft telemetry |
| `@equinor/fusion-framework-module-widget` | `packages/modules/widget` | Widget loading |

Expand Down Expand Up @@ -141,8 +142,9 @@ Format: `package name` → path → role.
`app-react-bookmark`, `app-react-bookmark-advanced`, `app-react-charts`, `app-react-context`,
`app-react-context-custom-error`, `app-react-environment-variables`, `app-react-feature-flag`,
`app-react-module`, `app-react-msal`, `app-react-observable`, `app-react-people`,
`app-react-router`, `app-react-router-legacy`, `app-react-settings`, `app-react-styling`,
`app-vanilla`, `poc-portal`, `portal`, `portal-analytics`.
`app-react-router`, `app-react-router-legacy`, `app-react-settings`, `app-react-state`,
`app-react-styling`, `app-vanilla`, `poc-portal`, `portal`,
`portal-analytics`.

Package name pattern: `@equinor/fusion-framework-cookbook-<folder>`.

Expand Down
8 changes: 8 additions & 0 deletions cookbooks/app-react-state/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Local CouchDB replication demo (optional)
#
# Unset (the default), the state module uses its own default storage - the same
# zero-config behavior any consuming app gets.
#
# To see the `Profile`, `Todos`, and sync-event pages replicate against a local Docker
# CouchDB instead: run `pnpm couchdb:start`, copy this file to `.env`, then restart `pnpm dev`.
FUSION_SPA_COUCHDB_URL=http://admin:admin@localhost:5984/cookbooks_app_state
Loading
Loading