@mxtommy/kip 4.5.0-beta.1 → 4.5.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.
Files changed (102) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +11 -7
  3. package/package.json +21 -8
  4. package/plugin/duckdb-parquet-storage.service.js +1182 -0
  5. package/plugin/history-series.service.js +439 -0
  6. package/plugin/index.js +705 -30
  7. package/plugin/openApi.json +253 -3
  8. package/plugin/plugin-auth.service.js +75 -0
  9. package/public/assets/help-docs/chartplotter.md +5 -18
  10. package/public/assets/help-docs/community.md +0 -3
  11. package/public/assets/help-docs/configuration.md +1 -1
  12. package/public/assets/help-docs/contact-us.md +0 -4
  13. package/public/assets/help-docs/dashboards.md +20 -18
  14. package/public/assets/help-docs/datainspector.md +7 -5
  15. package/public/assets/help-docs/history-api.md +116 -0
  16. package/public/assets/help-docs/menu.json +18 -6
  17. package/public/assets/help-docs/nodered-control-flows.md +125 -0
  18. package/public/assets/help-docs/putcontrols.md +101 -60
  19. package/public/assets/help-docs/welcome.md +6 -7
  20. package/public/assets/help-docs/widget-historical-series.md +66 -0
  21. package/public/assets/help-docs/zones.md +5 -10
  22. package/public/chunk-A6DQJFP4.js +16 -0
  23. package/public/chunk-B75MT7ND.js +1 -0
  24. package/public/{chunk-T6TFVZVM.js → chunk-CEB42O2C.js} +1 -1
  25. package/public/chunk-CHGXAEKT.js +2 -0
  26. package/public/chunk-D7VDX7ZF.js +5 -0
  27. package/public/{chunk-ZQER6AIQ.js → chunk-DEGYRCMI.js} +1 -1
  28. package/public/{chunk-M2B5OYGO.js → chunk-DEM56G4S.js} +1 -1
  29. package/public/chunk-DYTBBUMI.js +4 -0
  30. package/public/chunk-EQ2N7KDA.js +3 -0
  31. package/public/chunk-FNF7M3AE.js +1 -0
  32. package/public/chunk-IHURI4IH.js +5 -0
  33. package/public/{chunk-YIYYVDFO.js → chunk-IYRLINL7.js} +2 -2
  34. package/public/{chunk-5FEX27I4.js → chunk-JB4YVVNW.js} +1 -1
  35. package/public/chunk-JGGMFMY5.js +1 -0
  36. package/public/chunk-KPHICV76.js +5 -0
  37. package/public/{chunk-QZKCRH3H.js → chunk-KZ5DUKAX.js} +1 -1
  38. package/public/{chunk-HMOOTAEA.js → chunk-LQDSU4WS.js} +3 -3
  39. package/public/{chunk-IXQ7KIFY.js → chunk-MGPPVLZ7.js} +1 -1
  40. package/public/{chunk-QVCLOCEC.js → chunk-R7RQHWKJ.js} +1 -1
  41. package/public/chunk-RONXIZ2U.js +9 -0
  42. package/public/chunk-S72JTJPN.js +6 -0
  43. package/public/{chunk-KFFAA7DL.js → chunk-VCY32MWT.js} +8 -8
  44. package/public/chunk-YCEXTKGG.js +1 -0
  45. package/public/chunk-YKJKIWXO.js +6 -0
  46. package/public/chunk-ZV7IYYEQ.js +50 -0
  47. package/public/index.html +1 -1
  48. package/public/main-FQESQQV6.js +1 -0
  49. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -84
  50. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  51. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -35
  52. package/.github/copilot-instructions.md +0 -205
  53. package/.github/instructions/angular.instructions.md +0 -123
  54. package/.github/instructions/best-practices.instructions.md +0 -59
  55. package/.github/instructions/project.instructions.md +0 -432
  56. package/.github/workflows/ci.yml +0 -37
  57. package/docs/widget-schematic.md +0 -102
  58. package/images/ActionSidenav.png +0 -0
  59. package/images/ChartplotterMode.png +0 -0
  60. package/images/KIPDemo.png +0 -0
  61. package/images/KipBrightness-1024.png +0 -0
  62. package/images/KipConfig-Units-1024.png +0 -0
  63. package/images/KipConfig-display-1024x488.png +0 -0
  64. package/images/KipFreeboard-SK-1024.png +0 -0
  65. package/images/KipGaugeSample1-1024x545.png +0 -0
  66. package/images/KipGaugeSample2-1024x488.png +0 -0
  67. package/images/KipGaugeSample3-1024x508.png +0 -0
  68. package/images/KipNightMode-1024.png +0 -0
  69. package/images/KipWidgetConfig-layout-1024.png +0 -0
  70. package/images/KipWidgetConfig-paths-1024x488.png +0 -0
  71. package/images/Options.png +0 -0
  72. package/images/exterior_user_installs.png +0 -0
  73. package/images/formfactor.png +0 -0
  74. package/public/assets/help-docs/datasets.md +0 -95
  75. package/public/chunk-2OB7ZJBR.js +0 -3
  76. package/public/chunk-6GGJZDRE.js +0 -1
  77. package/public/chunk-6V4GGGXE.js +0 -2
  78. package/public/chunk-A5BW6BUM.js +0 -1
  79. package/public/chunk-DGE5YFPU.js +0 -5
  80. package/public/chunk-G6M3Z3BY.js +0 -53
  81. package/public/chunk-GMGZLXY7.js +0 -4
  82. package/public/chunk-GUZ3BDVZ.js +0 -2
  83. package/public/chunk-ICDGHQFP.js +0 -6
  84. package/public/chunk-JCNE4QHQ.js +0 -15
  85. package/public/chunk-K6XYUNG4.js +0 -8
  86. package/public/chunk-LGCQEN7V.js +0 -4
  87. package/public/chunk-O3JH7UTR.js +0 -1
  88. package/public/chunk-Q3USFT4F.js +0 -2
  89. package/public/chunk-VIKU7BH7.js +0 -1
  90. package/public/chunk-XMQPXXLW.js +0 -8
  91. package/public/main-4URMGBQS.js +0 -1
  92. package/rm-npmjs-beta.sh +0 -50
  93. package/tools/schematics/collection.json +0 -9
  94. package/tools/schematics/create-host2-widget/files/readme/README.md.template +0 -109
  95. package/tools/schematics/create-host2-widget/files/spec/widget-__name@dasherize__.component.spec.ts +0 -38
  96. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.html +0 -6
  97. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.scss +0 -5
  98. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.ts.template +0 -94
  99. package/tools/schematics/create-host2-widget/index.js +0 -138
  100. package/tools/schematics/create-host2-widget/schema.json +0 -89
  101. package/tools/schematics/create-host2-widget/test/create-host2-widget.spec.ts +0 -70
  102. package/tools/schematics/create-host2-widget/utils/formatting.js +0 -119
@@ -2,8 +2,8 @@
2
2
  "openapi": "3.0.0",
3
3
  "info": {
4
4
  "version": "1.1.0",
5
- "title": "KIP Remote Displays API",
6
- "description": "API endpoints to list KIP displays and control dashboard for a given KIP instance via the Signal K self.displays tree.\n\nUsage:\n- List displays:\n curl -s http://localhost:3000/plugins/kip/displays\n- Read a display's screens:\n curl -s http://localhost:3000/plugins/kip/displays/{displayId}\n- Set a display entry:\n curl -s -X PUT -H 'Content-Type: application/json' -d '{\"displayName\":\"Mast\"}' http://localhost:3000/plugins/kip/displays/{displayId}\n- Get current screen index:\n curl -s http://localhost:3000/plugins/kip/displays/{displayId}/screenIndex\n- Set current screen index:\n curl -s -X PUT -H 'Content-Type: application/json' -d '{\"screenIdx\":1}' http://localhost:3000/plugins/kip/displays/{displayId}/screenIndex\n- Get requested screen change index:\n curl -s http://localhost:3000/plugins/kip/displays/{displayId}/activeScreen\n- Request a screen change:\n curl -s -X PUT -H 'Content-Type: application/json' -d '{\"screenIdx\":1}' http://localhost:3000/plugins/kip/displays/{displayId}/activeScreen",
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": {
@@ -126,6 +130,84 @@
126
130
  "type": "object",
127
131
  "nullable": true,
128
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"
194
+ },
195
+ "updated": {
196
+ "type": "integer"
197
+ },
198
+ "deleted": {
199
+ "type": "integer"
200
+ },
201
+ "total": {
202
+ "type": "integer"
203
+ }
204
+ },
205
+ "required": [
206
+ "created",
207
+ "updated",
208
+ "deleted",
209
+ "total"
210
+ ]
129
211
  }
130
212
  },
131
213
  "parameters": {
@@ -137,6 +219,15 @@
137
219
  "schema": {
138
220
  "type": "string"
139
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
+ }
140
231
  }
141
232
  },
142
233
  "securitySchemes": {
@@ -444,6 +535,165 @@
444
535
  }
445
536
  }
446
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
+ }
447
697
  }
448
698
  }
449
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
+ }
@@ -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: Remove any existing Freeboard‑SK widget instances to avoid redundant chart rendering once mode is enabled.
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
- - Width changes are only committed on Save (prevents accidental layout shifts).
51
- - Cancel always restores the original ratio before the edit session began.
52
- - The persisted ratio applies across dashboards (unless a dashboard is collapsed).
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
- *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!*
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.
@@ -1,9 +1,8 @@
1
1
  ## Managing Dashboards
2
2
  Dashboards let you group widgets by task—navigation, engines, energy, weather, racing, night watch, and more. This guide covers creating, organizing, and editing dashboards, plus an overview of available widget types.
3
3
 
4
- ---
5
4
 
6
- ## 1. Dashboard Pages Panel
5
+ ## Dashboard Pages Panel
7
6
  Open the Actions menu and select Settings.
8
7
 
9
8
  Here you can:
@@ -24,9 +23,8 @@ Choose icons that reflect each dashboard’s purpose (e.g. compass for navigatio
24
23
  | Duplicate | Long press → Duplicate | Long click → Duplicate |
25
24
  | Delete | Long press → Delete | Long click → Delete |
26
25
 
27
- ---
28
26
 
29
- ## 2. Editing Dashboard Layouts
27
+ ## Editing Dashboard Layouts
30
28
  1. Navigate to the dashboard you want to change (swipe or use dashboard selector).
31
29
  2. Open the Actions menu.
32
30
  3. Tap the Unlock/Lock button at the bottom to toggle edit mode.
@@ -42,11 +40,18 @@ In edit mode, widgets show dashed outlines.
42
40
  - Delete a widget (long press → Delete, then confirm)
43
41
  - Save changes (Check button) or discard (X button) in the lower right
44
42
 
45
- Tip: If you can’t add a widget, free up space by resizing or moving existing ones first.
43
+ >**Tip:** If you can’t add a widget, free up space by resizing or moving existing ones first.
46
44
 
47
- ---
45
+ ## Viewing Widget History on Locked Dashboards
46
+ When a dashboard is locked (normal viewing mode), you can open a history chart for a widget without entering edit mode:
48
47
 
49
- ## 3. Workflow: From Idea to Dashboard
48
+ - **Desktop / mouse:** right-click on the widget
49
+ - **Touch device:** two-finger tap on the widget
50
+
51
+ KIP opens a history chart dialog and loads historical series data for that widget using the History API.
52
+
53
+
54
+ ## Workflow: From Idea to Dashboard
50
55
  1. Define the purpose (e.g. “Night Nav” = heading, COG, SOG, depth, wind, batteries, minimal brightness)
51
56
  2. Create or duplicate a dashboard similar to what you want
52
57
  3. Enter edit mode and add required widgets
@@ -54,9 +59,8 @@ Tip: If you can’t add a widget, free up space by resizing or moving existing o
54
59
  5. Arrange and size for readability at your viewing distance
55
60
  6. Exit edit mode and test switching at real brightness/environment
56
61
 
57
- ---
58
62
 
59
- ## 4. Widget Gallery (Overview)
63
+ ## Widget Gallery (Overview)
60
64
  KIP widgets turn Signal K data into readable visuals and controls. Available widget types:
61
65
 
62
66
  - **Numeric** – Displays numeric data in a clear and concise format, with options to show min/max values and a background minichart for trends.
@@ -65,9 +69,9 @@ KIP widgets turn Signal K data into readable visuals and controls. Available wid
65
69
  - **Position** – Displays latitude and longitude for location tracking and navigation.
66
70
  - **Static Label** – Add customizable labels to organize and clarify your dashboard layout.
67
71
  - **Zones State Panel**: Monitor the health/state of path data. Each panel control displays path data severity and status messages (driven by Signal K metadata zones).
68
- - **Switch Panel** – Group of toggle switches, indicator lights, and press buttons for digital switching and operations.
69
- - **Slider** – Range slider for adjusting values (e.g. lighting intensity).
70
- - **Multi State Switch** - Lists all available device/path operating modes/states (e.g., On, Off, Charge Only, Invert Only), highlights the current state, and lets you select a new state to send to the device and see the result.
72
+ - **Switch Panel** – Group of toggle switches, indicator lights, and press buttons for digital switching and operations. See [Digital Switching and PUT Path Setup](putcontrols.md).
73
+ - **Slider** – Range slider for adjusting values (e.g. lighting intensity). See [Digital Switching and PUT Path Setup](putcontrols.md).
74
+ - **Multi State Switch** - Lists all available device/path operating modes/states (e.g., On, Off, Charge Only, Invert Only), highlights the current state, and lets you select a new state to send to the device and see the result. See [Digital Switching and PUT Path Setup](putcontrols.md).
71
75
  - **Compact Linear** – Simple horizontal linear gauge with a large value label and modern look.
72
76
  - **Linear** – Horizontal or vertical linear gauge with zone highlighting.
73
77
  - **Radial** – Radial gauge with configurable dials and zone highlighting.
@@ -87,9 +91,8 @@ KIP widgets turn Signal K data into readable visuals and controls. Available wid
87
91
  - **Racer - Start Timer** – Advanced racing countdown timer with OCS status and auto dashboard switching.
88
92
  - **Countdown Timer** – Simple race start countdown timer with start, pause, sync, and reset options.
89
93
 
90
- ---
91
94
 
92
- ## 5. Performance & Layout Tips
95
+ ## Performance & Layout Tips
93
96
  - Favor clarity over cramming: leave space around high‑priority values
94
97
  - Group related widgets (navigation, energy, engines, environment)
95
98
  - Use consistent units per dashboard (e.g. all speeds in knots, all temps in °C or °F—don’t mix)
@@ -99,19 +102,18 @@ KIP widgets turn Signal K data into readable visuals and controls. Available wid
99
102
  - Know your device’s hardware limits and adjust widget count per dashboard accordingly
100
103
  - Avoid embedding too many external webpages—each adds load
101
104
 
102
- ---
103
105
 
104
- ## 6. Troubleshooting
106
+ ## Troubleshooting
105
107
  | Issue | Possible Cause | Fix |
106
108
  |------------------------|---------------------------------------|---------------------------------------------------------------------|
107
109
  | Data shows “—” or blank| Path missing/not configured/null value | Open widget config, verify Signal K path exists and updates. Use Data Inspector and Signal K Data Browser to view raw data from the server. |
108
110
  | Wrong units | Default convert unit used | Edit widget config paths and set the desired target unit. |
109
111
  | Slow dashboard switching| Excessive data sampling/too many widgets| Increase sample times; remove unused widgets. Split widgets into separate dashboards. Optimize system resource usage. |
110
112
  | Embedded page blank | Cross‑origin blocked | See "Embed Page Viewer" help section. |
113
+ | History dialog not opening on locked dashboard | Dashboard is still in edit mode, or interaction did not register as right-click / two-finger tap | Lock the dashboard first, then retry with a right-click (desktop) or two-finger tap (touch). |
111
114
 
112
- ---
113
115
 
114
- ## 7. Next Steps
116
+ ## Next Steps
115
117
  See also:
116
118
  - Remote Control (switch dashboards on unattended displays)
117
119
  - Night Mode (automatic theme + brightness)