@mxtommy/kip 4.4.0 → 4.5.0
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/.github/copilot-instructions.md +21 -5
- package/.github/instructions/best-practices.instructions.md +4 -0
- package/.github/instructions/project.instructions.md +47 -10
- package/CHANGELOG.md +13 -0
- package/README.md +11 -7
- package/package.json +8 -5
- package/plugin/duckdb-parquet-storage.service.js +1206 -0
- package/plugin/history-series.service.js +439 -0
- package/plugin/index.js +796 -81
- package/plugin/openApi.json +258 -20
- package/plugin/plugin-auth.service.js +75 -0
- package/plugin-config-data/kip/historicalData/kip-history.duckdb +0 -0
- package/plugin-config-data/kip/historicalData/parquet/chart-1/1772344583976-1772344583976.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1771408800000-1771408890000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584154-1772344584154.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584191-1772344584191.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584268-1772344584268.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-2/1771502400000-1771502400000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-3/1771408800000-1771408890000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-3/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-3/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-3/1772344584268-1772344584268.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-4/1771408800000-1771408890000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-4/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-4/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-5/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-5/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-6/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771408800000-1771408890000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771412400000-1771412490000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771419600000-1771419650000.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584191-1772344584191.parquet +0 -0
- package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584268-1772344584268.parquet +0 -0
- package/public/assets/help-docs/chartplotter.md +5 -18
- package/public/assets/help-docs/community.md +0 -3
- package/public/assets/help-docs/configuration.md +1 -1
- package/public/assets/help-docs/contact-us.md +0 -4
- package/public/assets/help-docs/dashboards.md +20 -18
- package/public/assets/help-docs/datainspector.md +7 -5
- package/public/assets/help-docs/history-api.md +116 -0
- package/public/assets/help-docs/menu.json +18 -6
- package/public/assets/help-docs/nodered-control-flows.md +125 -0
- package/public/assets/help-docs/putcontrols.md +101 -60
- package/public/assets/help-docs/welcome.md +6 -7
- package/public/assets/help-docs/widget-historical-series.md +66 -0
- package/public/assets/help-docs/zones.md +5 -10
- package/public/chunk-2ICAVOT2.js +10 -0
- package/public/chunk-6XFWUUDD.js +3 -0
- package/public/chunk-A6DQJFP4.js +16 -0
- package/public/chunk-B75MT7ND.js +1 -0
- package/public/{chunk-HJQQWPGC.js → chunk-CEB42O2C.js} +1 -1
- package/public/chunk-CHGXAEKT.js +2 -0
- package/public/chunk-D7VDX7ZF.js +5 -0
- package/public/chunk-DD4F6F4S.js +9 -0
- package/public/{chunk-KIR67PZ2.js → chunk-DEGYRCMI.js} +1 -1
- package/public/{chunk-UVAQADRE.js → chunk-DEM56G4S.js} +1 -1
- package/public/chunk-DYTBBUMI.js +4 -0
- package/public/{chunk-PGELIHBX.js → chunk-EDNYYQIZ.js} +2 -2
- package/public/chunk-FNF7M3AE.js +1 -0
- package/public/chunk-IHURI4IH.js +5 -0
- package/public/chunk-J3LDKVIS.js +50 -0
- package/public/{chunk-PSF2OKKT.js → chunk-JB4YVVNW.js} +1 -1
- package/public/chunk-KPHICV76.js +5 -0
- package/public/chunk-KZ5DUKAX.js +1 -0
- package/public/{chunk-BNIQFWQ6.js → chunk-LQDSU4WS.js} +3 -3
- package/public/{chunk-PDYVZHOK.js → chunk-MGPPVLZ7.js} +1 -1
- package/public/{chunk-TKC7ROZ7.js → chunk-R7RQHWKJ.js} +1 -1
- package/public/chunk-S72JTJPN.js +6 -0
- package/public/chunk-UYIJND2R.js +1 -0
- package/public/chunk-YCEXTKGG.js +1 -0
- package/public/chunk-YKJKIWXO.js +6 -0
- package/public/index.html +1 -1
- package/public/main-EG2WF4EO.js +1 -0
- package/tools/schematics/create-host2-widget/files/readme/README.md.template +1 -1
- package/public/assets/help-docs/datasets.md +0 -95
- package/public/chunk-2KMYPGX4.js +0 -2
- package/public/chunk-2MWBAYPJ.js +0 -8
- package/public/chunk-3BGR52TW.js +0 -53
- package/public/chunk-4IHRH3BQ.js +0 -9
- package/public/chunk-557F3J5T.js +0 -1
- package/public/chunk-5DLSQ773.js +0 -4
- package/public/chunk-7HLFWAA7.js +0 -1
- package/public/chunk-IWK4FHBL.js +0 -5
- package/public/chunk-J4IGUIZA.js +0 -6
- package/public/chunk-JP7ZAJ6C.js +0 -3
- package/public/chunk-KKJXPB75.js +0 -8
- package/public/chunk-MMIOUKLI.js +0 -1
- package/public/chunk-PESXPDBT.js +0 -2
- package/public/chunk-PKATAZA2.js +0 -1
- package/public/chunk-TGGJAGV7.js +0 -15
- package/public/chunk-VH4ZIU4T.js +0 -4
- package/public/chunk-XEJJOWK6.js +0 -2
- package/public/main-I7M3MAJT.js +0 -1
- package/rm-npmjs-beta.sh +0 -50
package/plugin/openApi.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"openapi": "3.0.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"version": "1.1.0",
|
|
5
|
-
"title": "KIP
|
|
6
|
-
"description": "
|
|
5
|
+
"title": "KIP Plugin API",
|
|
6
|
+
"description": "Endpoints\n- List remote displays and control remote dashboard of a given KIP instance.\n- Configure data series for widget framework historical data series and data chart widgets.",
|
|
7
7
|
"termsOfService": "http://signalk.org/terms/",
|
|
8
8
|
"license": {
|
|
9
9
|
"name": "Apache 2.0",
|
|
@@ -22,7 +22,11 @@
|
|
|
22
22
|
"tags": [
|
|
23
23
|
{
|
|
24
24
|
"name": "Displays",
|
|
25
|
-
"description": "KIP display discovery and control."
|
|
25
|
+
"description": "KIP remote display discovery and control."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "Series",
|
|
29
|
+
"description": "KIP widget history series configuration."
|
|
26
30
|
}
|
|
27
31
|
],
|
|
28
32
|
"components": {
|
|
@@ -63,17 +67,11 @@
|
|
|
63
67
|
]
|
|
64
68
|
},
|
|
65
69
|
"ScreenListOrNull": {
|
|
66
|
-
"
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
"type": "null"
|
|
75
|
-
}
|
|
76
|
-
]
|
|
70
|
+
"type": "array",
|
|
71
|
+
"nullable": true,
|
|
72
|
+
"items": {
|
|
73
|
+
"$ref": "#/components/schemas/ScreenItem"
|
|
74
|
+
}
|
|
77
75
|
},
|
|
78
76
|
"SuccessResponse": {
|
|
79
77
|
"type": "object",
|
|
@@ -129,14 +127,86 @@
|
|
|
129
127
|
}
|
|
130
128
|
},
|
|
131
129
|
"AnyObjectOrNull": {
|
|
132
|
-
"
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
130
|
+
"type": "object",
|
|
131
|
+
"nullable": true,
|
|
132
|
+
"additionalProperties": true
|
|
133
|
+
},
|
|
134
|
+
"SeriesDefinition": {
|
|
135
|
+
"type": "object",
|
|
136
|
+
"properties": {
|
|
137
|
+
"seriesId": {
|
|
138
|
+
"type": "string"
|
|
139
|
+
},
|
|
140
|
+
"datasetUuid": {
|
|
141
|
+
"type": "string"
|
|
142
|
+
},
|
|
143
|
+
"ownerWidgetUuid": {
|
|
144
|
+
"type": "string"
|
|
145
|
+
},
|
|
146
|
+
"ownerWidgetSelector": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"nullable": true
|
|
149
|
+
},
|
|
150
|
+
"path": {
|
|
151
|
+
"type": "string"
|
|
152
|
+
},
|
|
153
|
+
"context": {
|
|
154
|
+
"type": "string",
|
|
155
|
+
"nullable": true
|
|
156
|
+
},
|
|
157
|
+
"source": {
|
|
158
|
+
"type": "string",
|
|
159
|
+
"nullable": true
|
|
160
|
+
},
|
|
161
|
+
"timeScale": {
|
|
162
|
+
"type": "string",
|
|
163
|
+
"nullable": true
|
|
164
|
+
},
|
|
165
|
+
"period": {
|
|
166
|
+
"type": "integer",
|
|
167
|
+
"nullable": true
|
|
168
|
+
},
|
|
169
|
+
"retentionDurationMs": {
|
|
170
|
+
"type": "integer",
|
|
171
|
+
"nullable": true
|
|
172
|
+
},
|
|
173
|
+
"sampleTime": {
|
|
174
|
+
"type": "integer",
|
|
175
|
+
"nullable": true
|
|
176
|
+
},
|
|
177
|
+
"enabled": {
|
|
178
|
+
"type": "boolean",
|
|
179
|
+
"default": true
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
"required": [
|
|
183
|
+
"seriesId",
|
|
184
|
+
"datasetUuid",
|
|
185
|
+
"ownerWidgetUuid",
|
|
186
|
+
"path"
|
|
187
|
+
]
|
|
188
|
+
},
|
|
189
|
+
"SeriesReconcileResult": {
|
|
190
|
+
"type": "object",
|
|
191
|
+
"properties": {
|
|
192
|
+
"created": {
|
|
193
|
+
"type": "integer"
|
|
136
194
|
},
|
|
137
|
-
{
|
|
138
|
-
"type": "
|
|
195
|
+
"updated": {
|
|
196
|
+
"type": "integer"
|
|
197
|
+
},
|
|
198
|
+
"deleted": {
|
|
199
|
+
"type": "integer"
|
|
200
|
+
},
|
|
201
|
+
"total": {
|
|
202
|
+
"type": "integer"
|
|
139
203
|
}
|
|
204
|
+
},
|
|
205
|
+
"required": [
|
|
206
|
+
"created",
|
|
207
|
+
"updated",
|
|
208
|
+
"deleted",
|
|
209
|
+
"total"
|
|
140
210
|
]
|
|
141
211
|
}
|
|
142
212
|
},
|
|
@@ -149,6 +219,15 @@
|
|
|
149
219
|
"schema": {
|
|
150
220
|
"type": "string"
|
|
151
221
|
}
|
|
222
|
+
},
|
|
223
|
+
"SeriesIdParam": {
|
|
224
|
+
"in": "path",
|
|
225
|
+
"required": true,
|
|
226
|
+
"name": "seriesId",
|
|
227
|
+
"description": "Series identifier (dataset UUID)",
|
|
228
|
+
"schema": {
|
|
229
|
+
"type": "string"
|
|
230
|
+
}
|
|
152
231
|
}
|
|
153
232
|
},
|
|
154
233
|
"securitySchemes": {
|
|
@@ -456,6 +535,165 @@
|
|
|
456
535
|
}
|
|
457
536
|
}
|
|
458
537
|
}
|
|
538
|
+
},
|
|
539
|
+
"/plugins/kip/series": {
|
|
540
|
+
"get": {
|
|
541
|
+
"tags": [
|
|
542
|
+
"Series"
|
|
543
|
+
],
|
|
544
|
+
"summary": "List all configured history series",
|
|
545
|
+
"responses": {
|
|
546
|
+
"200": {
|
|
547
|
+
"description": "Current series definitions",
|
|
548
|
+
"content": {
|
|
549
|
+
"application/json": {
|
|
550
|
+
"schema": {
|
|
551
|
+
"type": "array",
|
|
552
|
+
"items": {
|
|
553
|
+
"$ref": "#/components/schemas/SeriesDefinition"
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
"400": {
|
|
560
|
+
"description": "Bad request",
|
|
561
|
+
"content": {
|
|
562
|
+
"application/json": {
|
|
563
|
+
"schema": {
|
|
564
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
"/plugins/kip/series/{seriesId}": {
|
|
573
|
+
"parameters": [
|
|
574
|
+
{
|
|
575
|
+
"$ref": "#/components/parameters/SeriesIdParam"
|
|
576
|
+
}
|
|
577
|
+
],
|
|
578
|
+
"put": {
|
|
579
|
+
"tags": [
|
|
580
|
+
"Series"
|
|
581
|
+
],
|
|
582
|
+
"summary": "Create or update a series definition",
|
|
583
|
+
"requestBody": {
|
|
584
|
+
"required": true,
|
|
585
|
+
"content": {
|
|
586
|
+
"application/json": {
|
|
587
|
+
"schema": {
|
|
588
|
+
"$ref": "#/components/schemas/SeriesDefinition"
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
"responses": {
|
|
594
|
+
"200": {
|
|
595
|
+
"description": "Series upserted",
|
|
596
|
+
"content": {
|
|
597
|
+
"application/json": {
|
|
598
|
+
"schema": {
|
|
599
|
+
"$ref": "#/components/schemas/SeriesDefinition"
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
"400": {
|
|
605
|
+
"description": "Bad request",
|
|
606
|
+
"content": {
|
|
607
|
+
"application/json": {
|
|
608
|
+
"schema": {
|
|
609
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
},
|
|
616
|
+
"delete": {
|
|
617
|
+
"tags": [
|
|
618
|
+
"Series"
|
|
619
|
+
],
|
|
620
|
+
"summary": "Delete a series definition",
|
|
621
|
+
"responses": {
|
|
622
|
+
"200": {
|
|
623
|
+
"description": "Series removed",
|
|
624
|
+
"content": {
|
|
625
|
+
"application/json": {
|
|
626
|
+
"schema": {
|
|
627
|
+
"$ref": "#/components/schemas/SuccessResponse"
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
"404": {
|
|
633
|
+
"description": "Series not found",
|
|
634
|
+
"content": {
|
|
635
|
+
"application/json": {
|
|
636
|
+
"schema": {
|
|
637
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
"400": {
|
|
643
|
+
"description": "Bad request",
|
|
644
|
+
"content": {
|
|
645
|
+
"application/json": {
|
|
646
|
+
"schema": {
|
|
647
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
"/plugins/kip/series/reconcile": {
|
|
656
|
+
"post": {
|
|
657
|
+
"tags": [
|
|
658
|
+
"Series"
|
|
659
|
+
],
|
|
660
|
+
"summary": "Reconcile full desired series set",
|
|
661
|
+
"requestBody": {
|
|
662
|
+
"required": true,
|
|
663
|
+
"content": {
|
|
664
|
+
"application/json": {
|
|
665
|
+
"schema": {
|
|
666
|
+
"type": "array",
|
|
667
|
+
"items": {
|
|
668
|
+
"$ref": "#/components/schemas/SeriesDefinition"
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
"responses": {
|
|
675
|
+
"200": {
|
|
676
|
+
"description": "Reconcile summary",
|
|
677
|
+
"content": {
|
|
678
|
+
"application/json": {
|
|
679
|
+
"schema": {
|
|
680
|
+
"$ref": "#/components/schemas/SeriesReconcileResult"
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
"400": {
|
|
686
|
+
"description": "Bad request",
|
|
687
|
+
"content": {
|
|
688
|
+
"application/json": {
|
|
689
|
+
"schema": {
|
|
690
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
459
697
|
}
|
|
460
698
|
}
|
|
461
699
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeUserScope = normalizeUserScope;
|
|
4
|
+
exports.resolveAuthenticatedUserScope = resolveAuthenticatedUserScope;
|
|
5
|
+
exports.resolveReadUserScope = resolveReadUserScope;
|
|
6
|
+
exports.resolveWriteUserScopeOrReject = resolveWriteUserScopeOrReject;
|
|
7
|
+
/**
|
|
8
|
+
* Normalizes a candidate user scope value.
|
|
9
|
+
*
|
|
10
|
+
* @param {unknown} value Candidate scope value.
|
|
11
|
+
* @returns {string | null} Trimmed scope or null when empty.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const scope = normalizeUserScope(' demo-user ');
|
|
15
|
+
*/
|
|
16
|
+
function normalizeUserScope(value) {
|
|
17
|
+
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
18
|
+
return normalized.length > 0 ? normalized : null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolves authenticated user scope from request identity fields.
|
|
22
|
+
*
|
|
23
|
+
* @param {Request} req Incoming Express request.
|
|
24
|
+
* @returns {string | null} Resolved scope or null when unavailable.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* const scope = resolveAuthenticatedUserScope(req);
|
|
28
|
+
*/
|
|
29
|
+
function resolveAuthenticatedUserScope(req) {
|
|
30
|
+
// Check for skPrincipal.identifier as the primary method for authenticated scope resolution
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
+
const skPrincipal = req.skPrincipal;
|
|
33
|
+
if (skPrincipal && typeof skPrincipal === 'object') {
|
|
34
|
+
const skPrincipalId = normalizeUserScope(skPrincipal.identifier);
|
|
35
|
+
if (skPrincipalId) {
|
|
36
|
+
return skPrincipalId;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolves user scope for read operations, returning a fallback when unauthenticated.
|
|
43
|
+
*
|
|
44
|
+
* @param {Request} req Incoming Express request.
|
|
45
|
+
* @param {string} [fallback='anonymous'] Fallback scope value.
|
|
46
|
+
* @returns {string} Resolved or fallback scope.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const scope = resolveReadUserScope(req);
|
|
50
|
+
*/
|
|
51
|
+
function resolveReadUserScope(req, fallback = 'anonymous') {
|
|
52
|
+
return resolveAuthenticatedUserScope(req) ?? fallback;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolves user scope for write operations and rejects the request when unresolved.
|
|
56
|
+
*
|
|
57
|
+
* @param {Request} req Incoming Express request.
|
|
58
|
+
* @param {Response} res Express response used for rejection.
|
|
59
|
+
* @param {string} operation Operation label for diagnostics.
|
|
60
|
+
* @param {(message: string) => void} errorLogger Logger callback for refusal messages.
|
|
61
|
+
* @param {TAuthFailureResponder} sendFail Response helper callback.
|
|
62
|
+
* @returns {string | null} Resolved scope or null when rejected.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const scope = resolveWriteUserScopeOrReject(req, res, 'PUT /series/:seriesId', console.error, sendFail);
|
|
66
|
+
*/
|
|
67
|
+
function resolveWriteUserScopeOrReject(req, res, operation, errorLogger, sendFail) {
|
|
68
|
+
const userScope = resolveAuthenticatedUserScope(req);
|
|
69
|
+
if (userScope) {
|
|
70
|
+
return userScope;
|
|
71
|
+
}
|
|
72
|
+
errorLogger(`[SERIES AUTH] Refused ${operation}: unresolved authenticated user scope method=${req.method} path=${req.path} ip=${req.ip}`);
|
|
73
|
+
sendFail(res, 403, 'Authenticated user scope is required for series write operations');
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/chart-1/1772344583976-1772344583976.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-1/1771408800000-1771408890000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-1/1771412400000-1771412490000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-1/1771419600000-1771419650000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584154-1772344584154.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584191-1772344584191.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584268-1772344584268.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-2/1771502400000-1771502400000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-3/1771408800000-1771408890000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-3/1771412400000-1771412490000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-3/1771419600000-1771419650000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-3/1772344584268-1772344584268.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-4/1771408800000-1771408890000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-4/1771412400000-1771412490000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-4/1771419600000-1771419650000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-5/1771412400000-1771412490000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-5/1771419600000-1771419650000.parquet
ADDED
|
Binary file
|
package/plugin-config-data/kip/historicalData/parquet/live-6/1771419600000-1771419650000.parquet
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
## Chartplotter Mode
|
|
2
2
|
Chartplotter Mode provides a persistent dual‑panel navigation layout: a continuously live Freeboard‑SK chart on one side and an actively switchable KIP dashboard on the other. Switching dashboards never unloads or blinks the chart, giving you an MFD‑style experience powered entirely by Signal K.
|
|
3
3
|
|
|
4
|
-
---
|
|
5
4
|
|
|
6
5
|
## When to Use It
|
|
7
6
|
Use Chartplotter Mode when you want uninterrupted situational awareness (chart + vessel motion + routing context) while cycling between specialized dashboards (navigation, engines, energy, racing, night watch, etc.). If you only need a chart on a few dashboards or have very constrained hardware, the standalone Freeboard‑SK widget may be sufficient.
|
|
8
7
|
|
|
9
|
-
---
|
|
10
8
|
|
|
11
9
|
## Key Capabilities
|
|
12
10
|
- Persistent Freeboard‑SK chart (no reload on dashboard change)
|
|
@@ -16,7 +14,6 @@ Use Chartplotter Mode when you want uninterrupted situational awareness (chart +
|
|
|
16
14
|
- Remote dashboard switching compatible (chart forced collapse preserved remotely)
|
|
17
15
|
- Optional panel side selection (left or right)
|
|
18
16
|
|
|
19
|
-
---
|
|
20
17
|
|
|
21
18
|
## Enabling & Basic Setup
|
|
22
19
|
1. Open Actions → Settings → Display.
|
|
@@ -25,9 +22,8 @@ Use Chartplotter Mode when you want uninterrupted situational awareness (chart +
|
|
|
25
22
|
4. Optionally, enable the per‑dashboard “Auto-collapse Freeboard-SK panel when displaying this dashboard” flag if you want that dashboard to hide the chart and use the full width.
|
|
26
23
|
5. Enter dashboard edit mode if you wish to resize the split (see Resizing section), then Save to persist or Cancel to discard.
|
|
27
24
|
|
|
28
|
-
Tip
|
|
25
|
+
>**Tip:** Remove any existing Freeboard‑SK widget instances to avoid redundant chart rendering once mode is enabled.
|
|
29
26
|
|
|
30
|
-
---
|
|
31
27
|
|
|
32
28
|
## Orientation & Layout Behavior
|
|
33
29
|
| Environment | Layout |
|
|
@@ -37,7 +33,6 @@ Tip: Remove any existing Freeboard‑SK widget instances to avoid redundant char
|
|
|
37
33
|
|
|
38
34
|
The transition is automatic; no manual toggle is required. The per‑dashboard collapse still applies regardless of orientation.
|
|
39
35
|
|
|
40
|
-
---
|
|
41
36
|
|
|
42
37
|
## Resizing the Split
|
|
43
38
|
1. Enter dashboard edit mode on any dashboard (Actions → Unlock / Edit button).
|
|
@@ -46,12 +41,11 @@ The transition is automatic; no manual toggle is required. The per‑dashboard c
|
|
|
46
41
|
|
|
47
42
|
<img src="../../assets/help-docs/img/splitdeviderhandle.png" alt="Resize the split" title="Split handle" width="100%">
|
|
48
43
|
|
|
49
|
-
Notes
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
>**Notes:**
|
|
45
|
+
>- Width changes are only committed on Save (prevents accidental layout shifts).
|
|
46
|
+
>- Cancel always restores the original ratio before the edit session began.
|
|
47
|
+
>- The persisted ratio applies across dashboards (unless a dashboard is collapsed).
|
|
53
48
|
|
|
54
|
-
---
|
|
55
49
|
|
|
56
50
|
## Per‑Dashboard Collapse
|
|
57
51
|
Each dashboard can force the chart panel closed to maximize data area. This is ideal for engine diagnostics, racing performance pages, or night watch minimalism. When you switch to a collapsed dashboard, the chart panel is hidden; switching back to a normal dashboard restores it instantly with its prior state and zoom.
|
|
@@ -61,12 +55,10 @@ Characteristics:
|
|
|
61
55
|
- No chart reload occurs when re‑expanding—state (position, zoom, layers) persists.
|
|
62
56
|
- Remote control switches respect the same collapse logic.
|
|
63
57
|
|
|
64
|
-
---
|
|
65
58
|
|
|
66
59
|
## Selecting Chart Panel Side
|
|
67
60
|
Change side via Settings → Display → “Freeboard‑SK panel side”. This updates the split instantly. If a dashboard is collapsed, the side preference is applied the next time a non‑collapsed dashboard is shown.
|
|
68
61
|
|
|
69
|
-
---
|
|
70
62
|
|
|
71
63
|
## Chartplotter Mode vs Freeboard‑SK Widget
|
|
72
64
|
| Aspect | Chartplotter Mode | Freeboard‑SK Widget |
|
|
@@ -78,12 +70,10 @@ Change side via Settings → Display → “Freeboard‑SK panel side”. This u
|
|
|
78
70
|
| Memory footprint | Higher baseline (Freeboard-SK always resident) | Lower when dashboard lack the widget |
|
|
79
71
|
| Best for | Continuous nav + multi‑dashboard workflow (MFD) | Occasional chart reference |
|
|
80
72
|
|
|
81
|
-
---
|
|
82
73
|
|
|
83
74
|
## Remote Control Integration
|
|
84
75
|
When another KIP instance changes your active dashboard (Remote Control feature), the chartplotter mode and collapsed dashboard settings are respected. No special configuration is required.
|
|
85
76
|
|
|
86
|
-
---
|
|
87
77
|
|
|
88
78
|
## Performance & Resource Notes
|
|
89
79
|
- The persistent chart consumes GPU/CPU continuously; on very low‑power hardware consider disabling Chartplotter Mode for purely data dashboards.
|
|
@@ -91,7 +81,6 @@ When another KIP instance changes your active dashboard (Remote Control feature)
|
|
|
91
81
|
- Avoid unnecessary high‑frequency (sub‑500 ms) widget sampling if chart responsiveness matters.
|
|
92
82
|
- Keep embedded iframes (Embed widget) minimal when running persistent chart + heavy datasets.
|
|
93
83
|
|
|
94
|
-
---
|
|
95
84
|
|
|
96
85
|
## Troubleshooting
|
|
97
86
|
| Issue | Possible Cause | Fix |
|
|
@@ -102,7 +91,6 @@ When another KIP instance changes your active dashboard (Remote Control feature)
|
|
|
102
91
|
| Freeboard‑SK widget shows duplicate chart | Legacy widget still on a dashboard | Remove the Freeboard‑SK widget when using Chartplotter Mode |
|
|
103
92
|
| Performance feels sluggish | High widget sampling or heavy embeds | Increase sample times, remove unused widgets, collapse non‑nav dashboards, investigate hardware resource consumption |
|
|
104
93
|
|
|
105
|
-
---
|
|
106
94
|
|
|
107
95
|
## FAQs
|
|
108
96
|
**Does the chart keep its zoom and layers when collapsed dashboards are shown?** Yes. The panel is hidden, not destroyed.
|
|
@@ -115,7 +103,6 @@ When another KIP instance changes your active dashboard (Remote Control feature)
|
|
|
115
103
|
|
|
116
104
|
**Will remote control commands interrupt a resize session?** If remote switching occurs mid‑edit, the Drag resize session ends when you Save or Cancel; uncommitted changes do not apply until you explicitly save.
|
|
117
105
|
|
|
118
|
-
---
|
|
119
106
|
|
|
120
107
|
## Related Help
|
|
121
108
|
- Dashboards and Layout
|
|
@@ -17,7 +17,6 @@ Curated videos created by community members. Ordered to highlight broad onboardi
|
|
|
17
17
|
|
|
18
18
|
Improve or add entries: PR or Discord #showcase.
|
|
19
19
|
|
|
20
|
-
---
|
|
21
20
|
|
|
22
21
|
## Authors & Channels
|
|
23
22
|
Creator channels producing helpful KIP or Signal K related content.
|
|
@@ -53,7 +52,6 @@ Open a PR or post in Discord #showcase with:
|
|
|
53
52
|
- Focus summary (1 line)
|
|
54
53
|
- One featured video (link + short purpose sentence)
|
|
55
54
|
|
|
56
|
-
---
|
|
57
55
|
|
|
58
56
|
## More Community Resources
|
|
59
57
|
|
|
@@ -63,6 +61,5 @@ Open a PR or post in Discord #showcase with:
|
|
|
63
61
|
- [SensESP](https://signalk.org/SensESP/) — A Signal K sensor development toolkit for the ESP32 platform
|
|
64
62
|
- [OpenMarine Community](https://openmarine.net/) — OpenPlotter, MacArthur HAT and open source marine tech
|
|
65
63
|
|
|
66
|
-
---
|
|
67
64
|
|
|
68
65
|
> Want to contribute a video or resource? Share your link in the Discord #showcase channel or open a GitHub issue!
|
|
@@ -19,7 +19,7 @@ To log in to Signal K, you must first create a user. Follow these steps to creat
|
|
|
19
19
|
|
|
20
20
|
## Login to Server Mode
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
>In this mode, your configuration is shared across all devices **as long as you authenticate to Signal K using the same User ID**. It's that simple!
|
|
23
23
|
|
|
24
24
|
On the **Configurations** page, you can perform the following actions:
|
|
25
25
|
|
|
@@ -6,7 +6,6 @@ We’d love to hear from you. The KIP community is active and friendly—whether
|
|
|
6
6
|
|
|
7
7
|
Use Discord for quick questions, sharing dashboards, comparing hardware setups, and learning how others integrate KIP with Signal K.
|
|
8
8
|
|
|
9
|
-
---
|
|
10
9
|
|
|
11
10
|
## When to Use GitHub Issues
|
|
12
11
|
|
|
@@ -42,7 +41,6 @@ Tell us:
|
|
|
42
41
|
|
|
43
42
|
If you’re willing to help test or prototype—say so. That speeds things up.
|
|
44
43
|
|
|
45
|
-
---
|
|
46
44
|
|
|
47
45
|
## Response Expectations
|
|
48
46
|
- Discord: often same-day community responses; core maintainer availability may vary.
|
|
@@ -51,14 +49,12 @@ If you’re willing to help test or prototype—say so. That speeds things up.
|
|
|
51
49
|
|
|
52
50
|
If something critical slips through, feel free to politely bump the issue after about a week.
|
|
53
51
|
|
|
54
|
-
---
|
|
55
52
|
|
|
56
53
|
## Contributing Beyond Issues
|
|
57
54
|
- Share dashboards, layouts, or usage patterns. Use the Discord #showcase chanel with a few pictures (great inspiration for others!).
|
|
58
55
|
- Help answer other users’ questions on Discord.
|
|
59
56
|
- Test new widgets or configuration flows and give feedback.
|
|
60
57
|
|
|
61
|
-
---
|
|
62
58
|
|
|
63
59
|
## Thank You
|
|
64
60
|
Your feedback, curiosity, and ideas directly shape KIP. Whether it’s a tiny typo fix or a major feature concept—every contribution moves the project forward.
|