Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
513b511
feat: upgrade Admin UI to React 19 with Bootstrap 5
dirkwa Jan 15, 2026
6d05ec7
refactor: modernize Redux to hooks and convert components to TypeScript
dirkwa Jan 16, 2026
53ae11d
refactor: remove unused connect() from ActionCellRenderer
dirkwa Jan 16, 2026
6801a20
chore: clean up migration leftovers and improve documentation
dirkwa Jan 16, 2026
c3db230
Clean up documentation and remove vesselpositions demo package
dirkwa Jan 17, 2026
8578a12
docs(fix): Vite was before React19.
dirkwa Jan 17, 2026
26464bd
Remove bundle-stats.html from repository
dirkwa Jan 17, 2026
cf56af9
chore: enable TypeScript strict mode and add plugin error boundaries
dirkwa Jan 17, 2026
cd64cc4
chore: enable noUnusedLocals and noUnusedParameters in tsconfig
dirkwa Jan 17, 2026
0c39d87
fix: show install/remove progress status in app store
dirkwa Jan 17, 2026
834cae3
fix: add error boundary for incompatible webapps in embedded view
dirkwa Jan 17, 2026
1982237
fix: npm run format
dirkwa Jan 17, 2026
6951349
fix: dropdown menu clipped in app store when filtering
dirkwa Jan 17, 2026
717a8b5
feat: upgrade to React 19.2 with React Compiler and useEffectEvent
dirkwa Jan 19, 2026
c9b5e10
fix(admin-ui): add htmlFor attributes to switch labels for accessibility
dirkwa Jan 19, 2026
9fca821
fix(admin-ui): resolve accessibility warnings for switch labels
dirkwa Jan 19, 2026
995889d
chore(admin-ui): update vite plugin versions for npm compatibility
dirkwa Jan 19, 2026
6465658
fix(admin-ui): wrap DataRow checkboxes in labels for accessibility
dirkwa Jan 19, 2026
ea79dbb
perf(admin-ui): optimize DataBrowser with React 19 features and RAW m…
dirkwa Jan 19, 2026
73089fe
chore(admin-ui): add React 19 ESLint plugins and fix violations
dirkwa Jan 23, 2026
91841d6
fix: use stacked layout for DataBrowser on narrow screens
dirkwa Jan 24, 2026
0ffbdad
fix: use stacked layout for DataBrowser on narrow screens
dirkwa Jan 24, 2026
d02255e
fix: npm format
dirkwa Jan 24, 2026
62f787e
style(admin-ui): format VirtualizedDataTable
dirkwa Jan 25, 2026
e97e38a
refactor: migrate admin UI state management from Redux to Zustand
dirkwa Jan 26, 2026
8b9c774
fix: proxy settings
dirkwa Jan 26, 2026
2e279a3
fix: npm format
dirkwa Jan 26, 2026
134400e
feat: add React 19 Admin UI with runtime switching
dirkwa Jan 26, 2026
504fee4
feat: add Keeper API integration to Admin UI
dirkwa Jan 26, 2026
0d08682
fix: npmrc
dirkwa Jan 26, 2026
407cd81
fix: devDependencies
dirkwa Jan 26, 2026
bfe1562
fix(admin-ui): remove unused Redux dependencies
dirkwa Jan 26, 2026
939aac4
fix(lint): update eslint-react plugin to fix zod-validation-error
dirkwa Jan 26, 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
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
package-lock=false
legacy-peer-deps=true
46 changes: 43 additions & 3 deletions docs/breaking_changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,51 @@ title: Breaking Changes

# Breaking Changes & Deprecations

The introduction of new REST APIs in version 2 and the move to an operations based model has resulted in some version 1 paths being flagged for deprecation.
This document lists breaking changes and deprecations in Signal K Server.

It is recommended that applications and plugins referencing these deprecated paths update their operation to reference the version 2 paths.
---

## Admin UI: React 19 Migration

The Admin UI has been upgraded from React 16 to **React 19**. This is a significant update that may affect embedded webapps and plugin configuration panels.

### What Changed

| Component | Before | After |
| ------------ | ---------- | ---------- |
| React | 16.14.0 | 19.x |
| React DOM | 16.14.0 | 19.x |
| React Router | 4.x | 6.x |
| Language | JavaScript | TypeScript |

### Impact on Embedded Webapps

**If your webapp uses Module Federation to share React with the Admin UI:**

1. **Singleton sharing is now required** - Your webapp must configure React and ReactDOM as singletons with `requiredVersion: false`. See [vite.config.js](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/vite.config.js) for the current configuration.

2. **React 19 compatibility** - If your webapp bundles its own React, it should be compatible with components rendered by the host. Most React 16/17/18 code works unchanged in React 19, but some deprecated APIs have been removed.

3. **String refs removed** - React 19 no longer supports string refs (`ref="myRef"`). Use `useRef()` instead.

4. **`defaultProps` on function components** - Deprecated. Use JavaScript default parameters instead.

### Impact on Plugin Configuration Panels

Plugin configuration panels using `./PluginConfigurationPanel` export continue to work. The props interface remains the same:

- `configuration` - the plugin's configuration data
- `save` - function to save configuration

### No Impact

- **Standalone webapps** - Webapps that don't use Module Federation sharing are not affected
- **Server APIs** - All Signal K HTTP and WebSocket APIs remain unchanged
- **Plugin JavaScript APIs** - Server-side plugin APIs are not affected

---

## Changes
## REST API Changes

The following changes have been implemented with the introduction of **Resources API** and apply to applications using the `./signalk/v2/resources` endpoint.

Expand Down
40 changes: 23 additions & 17 deletions docs/develop/plugins/custom_renderers.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ As of Signalk V 2.17.0, you'll notice that the path appears in the Data Browser

<img width="751" height="236" alt="Screenshot 2025-12-15 at 1 56 08 PM" src="https://github.com/user-attachments/assets/2514d3f7-9b6a-4f50-a6cf-d5e8868199a4" />

This is a Custom Renderer. The code for it is embedded in the DataBrowser package. See: [ValueRenderer.js](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/src/views/DataBrowser/ValueRenderers.js).
This is a Custom Renderer. The code for it is embedded in the DataBrowser package. See: [ValueRenderers.tsx](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/src/views/DataBrowser/ValueRenderers.tsx).

As of Signalk V 2.19.0, there are additional embedded Custom Renderers for Notifications, Attitude, Direction, Meters and Large Arrays.

Expand All @@ -30,30 +30,36 @@ const BoldRenderer = ({ value }) => {
}
```

There are more interesting examples in the ValueRenderer.js file.
There are more interesting examples in the ValueRenderers.tsx file.

## Making Your Renderer Available at Runtime

- Create a plugin
- Add your Component in a separate file (usually under [plugin dir]/src/component)
- Add webpack includes and scripts to your package.json
- Add build tool includes and scripts to your package.json (Webpack or Vite)
- Add keyword "signalk-node-server-addon" to your package.json
- Create a webpack.config.js (see any Plugin with their own configuration component) file that exports the renderer:

```
plugins: [
new ModuleFederationPlugin({
name: "Sample renderer",
library: { type: "var", name: packageJson.name.replace(/[-@/]/g, "_") },
filename: "remoteEntry.js",
exposes: {
"SampleRenderer": "./src/components/SampleRenderer",
},
shared: [{ react: { singleton: false, strictVersion: true } }],
}),
...
- Configure Module Federation to export the renderer. Example using Webpack:

```javascript
plugins: [
new ModuleFederationPlugin({
name: "Sample renderer",
library: { type: "var", name: packageJson.name.replace(/[-@/]/g, "_") },
filename: "remoteEntry.js",
exposes: {
"./SampleRenderer": "./src/components/SampleRenderer",
},
shared: {
react: { singleton: true, requiredVersion: false },
"react-dom": { singleton: true, requiredVersion: false }
},
}),
...
]
```

**Important:** Configure React as a singleton with `requiredVersion: false` to share the host's React 19 instance. See [vite.config.js](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/vite.config.js) for the Admin UI's configuration.

- Build your plugin (`npm run build`)

## Use Your Renderer
Expand Down
23 changes: 15 additions & 8 deletions docs/develop/webapps.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Signal K Server provides the following ways to add web-based user interfaces to
1. **Standalone WebApps** are web applications that when launched, the server Admin UI disappears and the webapp controls the whole page (browser window / tab).

2. **Embedded WebApps** are web applications that when launched, are **embedded in the server Admin UI**, leaving the toolbar and menu available to the user.
![vesselpositions](../img/vesselpositions.png 'Vesselpositions Embedded Webapp')

3. **Embedded Plugin Configuration Forms** are forms provided by a plugin that the server embeds within the _Plugin Config_ screen to replace the generic form rendered using the plugin _configuration schema_. This allows a richer set of controls to be provided for the user to configure the plugin compared to the more generice server generated form provides.
![calibration](../img/calibration.png 'Calibration plugin configuration form')
Expand Down Expand Up @@ -151,21 +150,29 @@ _Example response:_

## Embedded Components and Admin UI / Server interfaces

Embedded components are implemented using [Webpack Federated Modules](https://webpack.js.org/concepts/module-federation/) and [React Code Splitting](https://reactjs.org/docs/code-splitting.html).
Embedded components are implemented using [Module Federation](https://module-federation.io/) and [React Code Splitting](https://react.dev/reference/react/lazy).

_Note: There is no keyword for a module that provides only embedded components, use `signalk-webapp` instead._

You need to configured Webpack to create the necessary code for federation using _ModuleFederationPlugin_ and expose the component with fixed names:
You need to configure your build tool (Webpack or Vite) to create the necessary code for federation and expose the component with fixed names:

- embeddable webapp: `./AppPanel`
- plugin configuration form: `./PluginConfigurationPanel`
- embedded component: `./AddonPanel`

The ModuleFederationPlugin library name must match the package name and be a "safe" name for a webpack module like in `library: { type: 'var', name: packageJson.name.replace(/[-@/]/g, '_') },`
The ModuleFederationPlugin library name must match the package name and be a "safe" name for a module like in `library: { type: 'var', name: packageJson.name.replace(/[-@/]/g, '_') },`

The exposed modules need to `export default` a React component - both class based components and stateless functional components can be used. The server dependencies like `reactstrap` can and should be used. Add `@signalk/server-admin-ui-dependencies` as a dependency to the webapp, it defines the depedencies used by the server admin UI.
The exposed modules need to `export default` a React component. Functional components with hooks are recommended. The server dependencies like `reactstrap` can and should be used. Add `@signalk/server-admin-ui-dependencies` as a dependency to the webapp, it defines the dependencies used by the server admin UI.

See the vesselpositions embedded webapp/component and Calibration plugin for examples of each. It is probably easier to start with either one and modify them to suit your needs. Don't forget to change the module id and name in package.json!
### React Version Compatibility

The Admin UI uses **React 19** with shared dependencies via Module Federation. Your embedded webapp should:

1. **Share React as a singleton** - Configure Module Federation to use the host's React instance with `requiredVersion: false`. See [vite.config.js](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/vite.config.js) for the current configuration.

2. **Use functional components** - The Admin UI is built with functional components and React hooks. While class components still work, functional components are recommended for consistency.

See the Calibration plugin for an example. It is probably easier to start with an existing plugin and modify it to suit your needs. Don't forget to change the module id and name in package.json!

## WebApp / Component and Admin UI / Server interfaces

Expand All @@ -180,13 +187,13 @@ Embedded webapp properties:
- getting and setting application data
- opening an automatically reconnecting WebSocket connection to the server
- getting Signal K data via `get`
- [Embedded](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/src/views/Webapps/Embedded.js)
- [Embedded](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/src/views/Webapps/Embedded.tsx)

PluginConfigurationForm properties:

- `configuration` : the configuration data of the plugin
- `save`: function to save the configuration data
- [EmbeddedPluginConfigurationForm](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/src/views/Configuration/EmbeddedPluginConfigurationForm.js)
- [EmbeddedPluginConfigurationForm](https://github.com/SignalK/signalk-server/blob/master/packages/server-admin-ui/src/views/Configuration/EmbeddedPluginConfigurationForm.tsx)

**_Note: The documentation regarding embedded WebApps and Components provided at this time is rudimentary and should be considered under development as the concept is evolving._**

Expand Down
Binary file removed docs/img/vesselpositions.png
Binary file not shown.
1 change: 1 addition & 0 deletions docs/installation/command_line.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ Signal K Server provides the following command line options and environment vari
| `BACKPRESSURE_ENTER` | WebSocket backpressure threshold in bytes to enter backpressure mode _(default is 524288 / 512KB)_. When a client's send buffer exceeds this, the server switches to accumulating only latest values per path. |
| `BACKPRESSURE_EXIT` | WebSocket backpressure threshold in bytes to exit backpressure mode _(default is 1024 / 1KB)_. When the buffer drains below this, accumulated values are flushed. Primarily for testing. |
| `EVENT_EMITTER_MAX_LISTENERS` | Maximum number of delta event listeners _(default is 50)_. Increase if you see MaxListenersExceededWarning when connecting many WebSocket clients. |
| `SIGNALK_ADMIN_UI` | Select the Admin UI version. Set to `react19` to use the React 19 Admin UI. If not set, the legacy Admin UI is used. |
33 changes: 28 additions & 5 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const globals = require('globals')
const tseslint = require('typescript-eslint')
const prettier = require('eslint-config-prettier/flat')
const react = require('eslint-plugin-react')
const reactHooks = require('eslint-plugin-react-hooks')
const reactCompiler = require('eslint-plugin-react-compiler')
const eslintReact = require('@eslint-react/eslint-plugin')
const chai = require('eslint-plugin-chai-friendly')

module.exports = defineConfig([
Expand All @@ -19,7 +22,9 @@ module.exports = defineConfig([
'examples/wasm-plugins/**/build/**',
'examples/wasm-plugins/**/plugin.js',
'examples/wasm-plugins/**/plugin.d.ts',
'packages/assemblyscript-plugin-sdk/build/**'
'packages/assemblyscript-plugin-sdk/build/**',
// Legacy admin UI - kept as fallback, not actively maintained
'packages/server-admin-ui/**'
]),

// TypeScript options
Expand Down Expand Up @@ -58,26 +63,44 @@ module.exports = defineConfig([
}
},

// Server-admin UI specific options
// Server-admin UI React 19 specific options
{
settings: {
react: {
version: 'detect'
}
},
files: ['packages/server-admin-ui/src/**/*.js'],
extends: [common(), react.configs.flat.recommended],
files: ['packages/server-admin-ui-react19/src/**/*.{js,jsx,ts,tsx}'],
extends: [
common('@typescript-eslint/'),
tseslint.configs.recommended,
react.configs.flat.recommended,
eslintReact.configs['recommended-typescript']
],
plugins: {
'react-hooks': reactHooks,
'react-compiler': reactCompiler
},
languageOptions: {
parser: tseslint.parser,
parserOptions: {
ecmaFeatures: {
jsx: true
}
},
project: './packages/server-admin-ui-react19/tsconfig.json'
},
globals: {
...globals.browser
}
},
rules: {
// React hooks rules
...reactHooks.configs.recommended.rules,
// React compiler rules
'react-compiler/react-compiler': 'warn',
// React 17+ with new JSX transform doesn't require React in scope
'react/react-in-jsx-scope': 'off',
// Disable prop-types (using TypeScript)
'react/prop-types': 'off',
'react/no-string-refs': 'off',
'react/no-direct-mutation-state': 'off'
Expand Down
Loading
Loading