@signalk/app-dock 1.2.1 → 1.3.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/README.md +30 -0
- package/package.json +6 -1
- package/public/dock.css +62 -0
- package/public/dock.js +170 -17
- package/public/index.html +4 -0
- package/.gitattributes +0 -5
- package/.github/release.yml +0 -37
- package/.github/workflows/ci.yml +0 -11
- package/.github/workflows/label-by-title.yml +0 -67
- package/.github/workflows/release-please.yml +0 -109
- package/.github/workflows/release_on_tag.yml +0 -82
- package/.github/workflows/stale.yml +0 -42
- package/.prettierignore +0 -6
- package/.prettierrc +0 -6
- package/.release-please-manifest.json +0 -3
- package/AGENTS.md +0 -134
- package/CLAUDE.md +0 -1
- package/eslint.config.js +0 -59
- package/release-please-config.json +0 -11
- package/src/configpanel/PluginConfigurationPanel.js +0 -549
- package/src/configpanel/index.js +0 -1
- package/test/plugin.test.js +0 -696
- package/webpack.config.js +0 -39
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Publishes the tag it runs on to npm. Release tags come from release-please:
|
|
2
|
-
# merging its release PR creates the tag and the GitHub Release, then
|
|
3
|
-
# release-please.yml dispatches this workflow on the tag. Pre-release tags
|
|
4
|
-
# (-beta.N, -rc.N, -alpha.N) are pushed by hand, and only a pushed tag gets
|
|
5
|
-
# its GitHub Release created here.
|
|
6
|
-
name: 'Release on tag'
|
|
7
|
-
|
|
8
|
-
on:
|
|
9
|
-
push:
|
|
10
|
-
tags:
|
|
11
|
-
- 'v*'
|
|
12
|
-
# How release-please.yml starts this on a tag it created: that tag, pushed
|
|
13
|
-
# with GITHUB_TOKEN, raises no push event.
|
|
14
|
-
workflow_dispatch:
|
|
15
|
-
|
|
16
|
-
concurrency:
|
|
17
|
-
group: release-${{ github.ref }}
|
|
18
|
-
cancel-in-progress: false
|
|
19
|
-
|
|
20
|
-
jobs:
|
|
21
|
-
# A dispatched run is on a tag release-please made, and release-please made
|
|
22
|
-
# its Release too; creating one here would be a second for the same tag.
|
|
23
|
-
release:
|
|
24
|
-
if: ${{ github.event_name == 'push' }}
|
|
25
|
-
permissions:
|
|
26
|
-
contents: write
|
|
27
|
-
runs-on: ubuntu-latest
|
|
28
|
-
timeout-minutes: 10
|
|
29
|
-
steps:
|
|
30
|
-
- name: Create Release
|
|
31
|
-
uses: softprops/action-gh-release@v3
|
|
32
|
-
with:
|
|
33
|
-
tag_name: ${{ github.ref_name }}
|
|
34
|
-
name: ${{ github.ref_name }}
|
|
35
|
-
generate_release_notes: true
|
|
36
|
-
prerelease: ${{ contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') || contains(github.ref_name, 'rc') }}
|
|
37
|
-
env:
|
|
38
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
39
|
-
|
|
40
|
-
publish:
|
|
41
|
-
needs: release
|
|
42
|
-
# Runs after the Release on a pushed tag, and without it on a dispatched
|
|
43
|
-
# one, where that job is skipped. A dispatch can name any ref; only a
|
|
44
|
-
# release tag is published.
|
|
45
|
-
if: ${{ !cancelled() && needs.release.result != 'failure' && startsWith(github.ref, 'refs/tags/v') }}
|
|
46
|
-
permissions:
|
|
47
|
-
id-token: write
|
|
48
|
-
contents: read
|
|
49
|
-
runs-on: ubuntu-latest
|
|
50
|
-
timeout-minutes: 10
|
|
51
|
-
steps:
|
|
52
|
-
- uses: actions/checkout@v6
|
|
53
|
-
|
|
54
|
-
- uses: actions/setup-node@v6
|
|
55
|
-
with:
|
|
56
|
-
node-version: '24.x'
|
|
57
|
-
registry-url: 'https://registry.npmjs.org'
|
|
58
|
-
|
|
59
|
-
- run: npm ci
|
|
60
|
-
|
|
61
|
-
- name: Verify the tag matches package.json
|
|
62
|
-
run: |
|
|
63
|
-
TAG="${GITHUB_REF_NAME#v}"
|
|
64
|
-
PKG="$(node -p "require('./package.json').version")"
|
|
65
|
-
if [ "$TAG" != "$PKG" ]; then
|
|
66
|
-
echo "::error::tag $GITHUB_REF_NAME does not match package.json version $PKG"
|
|
67
|
-
exit 1
|
|
68
|
-
fi
|
|
69
|
-
echo "tag and package.json agree on $PKG"
|
|
70
|
-
|
|
71
|
-
- name: Publish to npm
|
|
72
|
-
run: |
|
|
73
|
-
tag="${GITHUB_REF#refs/tags/}"
|
|
74
|
-
if [[ "$tag" == *alpha* ]]; then
|
|
75
|
-
npm publish --provenance --access public --tag alpha
|
|
76
|
-
elif [[ "$tag" == *beta* ]]; then
|
|
77
|
-
npm publish --provenance --access public --tag beta
|
|
78
|
-
elif [[ "$tag" == *rc* ]]; then
|
|
79
|
-
npm publish --provenance --access public --tag rc
|
|
80
|
-
else
|
|
81
|
-
npm publish --provenance --access public
|
|
82
|
-
fi
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Marks issues labeled "awaiting response" as stale after 30 days of inactivity
|
|
2
|
-
# and closes them 30 days after that (60 days total). Issues labeled
|
|
3
|
-
# "good first task" or "help wanted" are exempt. Pull requests are never
|
|
4
|
-
# touched. The workflow runs daily and can also be triggered manually.
|
|
5
|
-
name: Stale issues
|
|
6
|
-
|
|
7
|
-
on:
|
|
8
|
-
schedule:
|
|
9
|
-
- cron: '17 1 * * *'
|
|
10
|
-
workflow_dispatch:
|
|
11
|
-
|
|
12
|
-
permissions:
|
|
13
|
-
contents: read
|
|
14
|
-
issues: write
|
|
15
|
-
|
|
16
|
-
concurrency:
|
|
17
|
-
group: stale
|
|
18
|
-
cancel-in-progress: false
|
|
19
|
-
|
|
20
|
-
jobs:
|
|
21
|
-
stale:
|
|
22
|
-
runs-on: ubuntu-latest
|
|
23
|
-
timeout-minutes: 10
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/stale@v10
|
|
26
|
-
with:
|
|
27
|
-
days-before-issue-stale: 30
|
|
28
|
-
days-before-issue-close: 30
|
|
29
|
-
stale-issue-label: 'stale'
|
|
30
|
-
any-of-issue-labels: 'awaiting response'
|
|
31
|
-
exempt-issue-labels: 'good first task,help wanted'
|
|
32
|
-
stale-issue-message: >
|
|
33
|
-
This issue is marked as awaiting a response from the reporter and
|
|
34
|
-
has had no activity for 30 days. It will be closed in another 30
|
|
35
|
-
days if there is no further update. If the issue is still
|
|
36
|
-
relevant, please reply with any missing information.
|
|
37
|
-
close-issue-message: >
|
|
38
|
-
Closing this issue because it has been stale for 60 days without
|
|
39
|
-
a response. Please reopen if this is still relevant.
|
|
40
|
-
days-before-pr-stale: -1
|
|
41
|
-
days-before-pr-close: -1
|
|
42
|
-
operations-per-run: 100
|
package/.prettierignore
DELETED
package/.prettierrc
DELETED
package/AGENTS.md
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# @signalk/app-dock
|
|
2
|
-
|
|
3
|
-
A Signal K server plugin plus webapp: a macOS-style dock for switching between Signal K webapps on touch screens. The
|
|
4
|
-
dock page holds each app in an iframe, and a double-tap anywhere brings up the dock. User-facing behaviour is documented
|
|
5
|
-
in `README.md`; this file covers what a contributor needs to keep intact.
|
|
6
|
-
|
|
7
|
-
## Architecture
|
|
8
|
-
|
|
9
|
-
Three surfaces ship together from one package:
|
|
10
|
-
|
|
11
|
-
- **`plugin/index.js`**: the server plugin (CommonJS). It holds the schema, seeds the default apps on first start, serves
|
|
12
|
-
the dock's HTTP routes, and registers the `environment.mode` PUT handler for the night-mode button.
|
|
13
|
-
- **`public/dock.js`, `dock.css`, `index.html`**: the dock itself, served as-is at `/@signalk/app-dock/`. Plain browser
|
|
14
|
-
JavaScript with **no build step**: edit and reload.
|
|
15
|
-
- **`src/configpanel/`**: the React 19 config panel that the admin UI loads through Webpack Module Federation (keyword
|
|
16
|
-
`signalk-plugin-configurator`). `npm run build:config` writes `public/remoteEntry.js` and its chunks.
|
|
17
|
-
|
|
18
|
-
`public/config.html` is an older standalone configurator that the schema description links to; the admin UI shows the
|
|
19
|
-
React panel.
|
|
20
|
-
|
|
21
|
-
## Rules to keep in mind
|
|
22
|
-
|
|
23
|
-
- **Seed once, never rewrite.** `start()` seeds `DEFAULT_APPS` only when the saved `apps` is not an array. An app list
|
|
24
|
-
that already exists, even an empty one, is the user's and is never changed.
|
|
25
|
-
- **The default app list lives in three places.** `DEFAULT_APPS` in `plugin/index.js`, `NO_ADMIN_DEFAULTS` in
|
|
26
|
-
`public/dock.js` (served to visitors the plugin's `/settings` refuses), and the welcome-tour text in
|
|
27
|
-
`public/index.html`. Change them together.
|
|
28
|
-
- **`savePluginOptions` replaces the whole saved configuration.** Build every save from a complete configuration
|
|
29
|
-
(`running ? pluginSettings : savedSettings()`), never from a partial object.
|
|
30
|
-
- **Routes must work while the plugin is stopped.** signalk-server registers the router of every loaded plugin, enabled
|
|
31
|
-
or not. A handler that needs the configuration reads `app.readPluginOptions()` when `running` is false.
|
|
32
|
-
- **Access is opt-in per route.** Routes on `router` are admin-only. `router.access('readonly' | 'readwrite')`
|
|
33
|
-
(signalk-server 2.31 and later) opens a route to more users; feature-detect it (`typeof router.access === 'function'`)
|
|
34
|
-
so older servers keep working admin-only. `/config` stays admin-only on every server. When access changes, update the
|
|
35
|
-
access detection at the top of `dock.js` and the **Access** table in `README.md` with it.
|
|
36
|
-
- **`/settings` is readable by every visitor with read access.** Never put credentials or anything secret in it; that
|
|
37
|
-
includes app URLs.
|
|
38
|
-
- **Taps pass through.** The double-tap listener is passive, never calls `preventDefault()`, and there is no overlay
|
|
39
|
-
element. It attaches to the dock document and, recursively, to every same-origin iframe document, so apps that embed
|
|
40
|
-
other apps still open the dock.
|
|
41
|
-
- **One iframe sandbox string.** `switchToApp()` and the tour's Plugin Config link in `dock.js` create iframes with the
|
|
42
|
-
same `sandbox` value; keep them identical. `allow-top-navigation-by-user-activation` is what lets a dock opened inside
|
|
43
|
-
a dock break out to the top window (the guard at the top of `dock.js`).
|
|
44
|
-
- **Live config reload.** The dock polls the plugin every 5 s. A setting that changes how the dock is built belongs in
|
|
45
|
-
`STRUCTURAL_KEYS` in `dock.js` (the page reloads); app-list changes rebuild the dock in place.
|
|
46
|
-
- **New settings touch four places:** the schema in `plugin/index.js`, `DEFAULTS` in `dock.js`, the config panel in
|
|
47
|
-
`src/configpanel/`, and the **Settings** table in `README.md`.
|
|
48
|
-
- **Browser globals are declared.** ESLint lints `dock.js` as a classic script with an explicit globals list in
|
|
49
|
-
`eslint.config.js`; add a browser API there when `dock.js` starts using it.
|
|
50
|
-
|
|
51
|
-
## Build output is committed
|
|
52
|
-
|
|
53
|
-
`public/remoteEntry.js`, `public/main.js`, `public/540.js`, `public/805.js` and `public/540.js.LICENSE.txt` are Webpack
|
|
54
|
-
output and are tracked in git. After changing `src/configpanel/`, run `npm run build:config` and commit the regenerated
|
|
55
|
-
files with the source change. `prepublishOnly` rebuilds them at publish time. Prettier and ESLint skip them, and ESLint
|
|
56
|
-
also skips `src/`.
|
|
57
|
-
|
|
58
|
-
## Icons
|
|
59
|
-
|
|
60
|
-
`public/app-icon.svg` is the source icon: the `signalk.appIcon` shown by the admin UI and the App Store, the favicon,
|
|
61
|
-
and the dock's own logo. `public/app-icon-180.png` (apple-touch-icon) is generated from it and
|
|
62
|
-
`public/app-icon-maskable.svg` is maintained by hand; see **Icon assets** in `README.md`.
|
|
63
|
-
|
|
64
|
-
## Tests
|
|
65
|
-
|
|
66
|
-
`npm test` runs `test/plugin.test.js` with `node:test` against a mock `app` (`createMockApp()`). Cover new routes,
|
|
67
|
-
settings and seeding behaviour there. `dock.js` has no automated tests; check dock changes in a browser against a
|
|
68
|
-
running server (see **Development** in `README.md`).
|
|
69
|
-
|
|
70
|
-
## Workflow conventions
|
|
71
|
-
|
|
72
|
-
This repo is maintained by Dirk Wahrheit.
|
|
73
|
-
|
|
74
|
-
- Branch names use **hyphens**, never slashes.
|
|
75
|
-
- Angular conventional commits: `<type>(<scope>): <subject>`. PR titles use the same format; the generated release
|
|
76
|
-
notes are built from them.
|
|
77
|
-
- The PR title's type also picks its section in the release notes. `.github/workflows/label-by-title.yml` labels each
|
|
78
|
-
PR when it is opened or its title edited: `feat`/`perf` → `enhancement` (🚀 Features), `fix` → `bug` (🐛 Fixes),
|
|
79
|
-
`docs` → `documentation` (📖 Documentation), `build`/`ci`/`test`/`chore`/`refactor`/`style` → `skip-changelog`
|
|
80
|
-
(left out). Any other type lands under Other. A label set by hand stays until the title is next edited. Keep the
|
|
81
|
-
workflow and `.github/release.yml` naming the same labels.
|
|
82
|
-
- One logical change per commit.
|
|
83
|
-
- No `Co-Authored-By` lines. No "Generated with Claude Code" attribution.
|
|
84
|
-
- Never commit directly to `main`. Every change goes through a PR.
|
|
85
|
-
- PR descriptions: no checkboxes. "Tested" lists what actually ran, not what was planned.
|
|
86
|
-
- No hand-written CHANGELOG; GitHub Releases carry generated notes.
|
|
87
|
-
|
|
88
|
-
### Before opening a PR
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
npm run format # prettier --write + eslint --fix
|
|
92
|
-
npm run lint
|
|
93
|
-
npm test
|
|
94
|
-
npm run build:config # only when src/configpanel/ changed; commit the output
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
CI (`.github/workflows/ci.yml`) calls signalk-server's shared `plugin-ci.yml`: install, `npm test`, plugin lifecycle
|
|
98
|
-
and schema checks, npm-pack contents, and an App Store style `--ignore-scripts` install. It does **not** run Prettier or
|
|
99
|
-
ESLint, so run them locally.
|
|
100
|
-
|
|
101
|
-
### Releases
|
|
102
|
-
|
|
103
|
-
Releases are cut by release-please. Every releasable push to `main` updates a standing release PR titled
|
|
104
|
-
`chore(release): X.Y.Z` that bumps `version` in `package.json` and `package-lock.json`. Merging it creates the tag and
|
|
105
|
-
the GitHub Release, and `.github/workflows/release-please.yml` then dispatches `release_on_tag.yml` on the tag, which
|
|
106
|
-
publishes to npm with provenance (OIDC trusted publishing, no token).
|
|
107
|
-
|
|
108
|
-
- **The version follows the commits:** `feat` → minor, `fix`, `perf` and `revert` → patch, `!` or a
|
|
109
|
-
`BREAKING CHANGE:` footer → major. A `Release-As: X.Y.Z` footer overrides it. Do not bump the version in an ordinary
|
|
110
|
-
PR.
|
|
111
|
-
- **A push with nothing releasable leaves the release PR alone.** The `gate` job in `release-please.yml` decides what
|
|
112
|
-
counts; its comment lists the cases. Revert with a conventional `revert:` subject, since release-please ignores
|
|
113
|
-
GitHub's `Revert "…"`. Change the gate's last alternative together with `pull-request-title-pattern` in
|
|
114
|
-
`release-please-config.json`, or the release PR's merge never creates a tag.
|
|
115
|
-
- **Merge the release PR once it lists your change.** release-please refreshes it a moment after each merge; a
|
|
116
|
-
release PR merged before that still ships the change (the tag is on top of it) but its notes leave it out.
|
|
117
|
-
- **Pre-releases are cut by hand:** a `chore(release): X.Y.Z-beta.N` PR, then an annotated tag `vX.Y.Z-beta.N` pushed
|
|
118
|
-
on its merge commit. `release_on_tag.yml` creates their Release itself and publishes under the npm dist-tag `alpha`,
|
|
119
|
-
`beta` or `rc` that the tag contains.
|
|
120
|
-
|
|
121
|
-
## File layout
|
|
122
|
-
|
|
123
|
-
| Path | Purpose |
|
|
124
|
-
| ----------------------------- | ------------------------------------------------------------------------------------- |
|
|
125
|
-
| `plugin/index.js` | Plugin entry: schema, default-app seeding, routes, night-mode PUT handler. |
|
|
126
|
-
| `public/index.html` | Dock page: idle screen, dock, backdrop, loading overlay, welcome tour. |
|
|
127
|
-
| `public/dock.js` | Dock logic: access detection, config loading and polling, iframes, double-tap, dock. |
|
|
128
|
-
| `public/dock.css` | Dock styling, magnification, positions. |
|
|
129
|
-
| `public/manifest.webmanifest` | PWA manifest for Add to Home Screen. |
|
|
130
|
-
| `public/config.html` | Older standalone configurator. |
|
|
131
|
-
| `src/configpanel/` | React config panel for the admin UI (Module Federation remote). |
|
|
132
|
-
| `webpack.config.js` | Builds `src/configpanel/` into `public/`; shares React as a singleton with the admin. |
|
|
133
|
-
| `test/plugin.test.js` | Plugin tests (`node:test`). |
|
|
134
|
-
| `docs/screenshots/` | App Store screenshots, listed in `package.json` under `signalk.screenshots`. |
|
package/CLAUDE.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@AGENTS.md
|
package/eslint.config.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
const prettier = require('eslint-config-prettier')
|
|
2
|
-
|
|
3
|
-
module.exports = [
|
|
4
|
-
{ ignores: ['src/**', 'public/remoteEntry.js', 'public/540.js', 'public/805.js', 'public/main.js'] },
|
|
5
|
-
{
|
|
6
|
-
files: ['plugin/**/*.js', 'test/**/*.js'],
|
|
7
|
-
languageOptions: {
|
|
8
|
-
ecmaVersion: 2022,
|
|
9
|
-
sourceType: 'commonjs',
|
|
10
|
-
globals: {
|
|
11
|
-
require: 'readonly',
|
|
12
|
-
module: 'readonly',
|
|
13
|
-
exports: 'readonly',
|
|
14
|
-
__dirname: 'readonly',
|
|
15
|
-
__filename: 'readonly',
|
|
16
|
-
process: 'readonly',
|
|
17
|
-
console: 'readonly',
|
|
18
|
-
setTimeout: 'readonly',
|
|
19
|
-
clearTimeout: 'readonly',
|
|
20
|
-
setInterval: 'readonly',
|
|
21
|
-
clearInterval: 'readonly',
|
|
22
|
-
globalThis: 'readonly'
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
rules: {
|
|
26
|
-
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
|
27
|
-
'no-undef': 'error'
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
files: ['public/dock.js'],
|
|
32
|
-
languageOptions: {
|
|
33
|
-
ecmaVersion: 2022,
|
|
34
|
-
sourceType: 'script',
|
|
35
|
-
globals: {
|
|
36
|
-
window: 'readonly',
|
|
37
|
-
document: 'readonly',
|
|
38
|
-
navigator: 'readonly',
|
|
39
|
-
fetch: 'readonly',
|
|
40
|
-
console: 'readonly',
|
|
41
|
-
setTimeout: 'readonly',
|
|
42
|
-
clearTimeout: 'readonly',
|
|
43
|
-
setInterval: 'readonly',
|
|
44
|
-
requestAnimationFrame: 'readonly',
|
|
45
|
-
Promise: 'readonly',
|
|
46
|
-
Set: 'readonly',
|
|
47
|
-
Infinity: 'readonly',
|
|
48
|
-
MutationObserver: 'readonly',
|
|
49
|
-
URLSearchParams: 'readonly',
|
|
50
|
-
location: 'readonly'
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
rules: {
|
|
54
|
-
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
|
55
|
-
'no-undef': 'error'
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
prettier
|
|
59
|
-
]
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
|
-
"release-type": "node",
|
|
4
|
-
"include-component-in-tag": false,
|
|
5
|
-
"changelog-type": "github",
|
|
6
|
-
"skip-changelog": true,
|
|
7
|
-
"pull-request-title-pattern": "chore(release): ${version}",
|
|
8
|
-
"packages": {
|
|
9
|
-
".": {}
|
|
10
|
-
}
|
|
11
|
-
}
|