@mxtommy/kip 4.5.0 → 4.5.2

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 (98) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/package.json +28 -18
  3. package/plugin/duckdb-parquet-storage.service.js +199 -104
  4. package/plugin/index.js +137 -109
  5. package/public/{chunk-D7VDX7ZF.js → chunk-67V4XHCY.js} +1 -1
  6. package/public/chunk-BTFZS2TW.js +16 -0
  7. package/public/{chunk-UYIJND2R.js → chunk-CD5TQSCS.js} +1 -1
  8. package/public/chunk-FZFDGAQO.js +1 -0
  9. package/public/{chunk-EDNYYQIZ.js → chunk-I4SJ5UNN.js} +1 -1
  10. package/public/{chunk-2ICAVOT2.js → chunk-IH4CEW4C.js} +7 -7
  11. package/public/chunk-ISF5E3CX.js +50 -0
  12. package/public/{chunk-6XFWUUDD.js → chunk-KQEEYPK3.js} +2 -2
  13. package/public/chunk-NFJ4RQSE.js +4 -0
  14. package/public/{chunk-DEM56G4S.js → chunk-OPTBDYBL.js} +1 -1
  15. package/public/{chunk-YCEXTKGG.js → chunk-P4CRTB7N.js} +1 -1
  16. package/public/{chunk-IHURI4IH.js → chunk-P7JKENHI.js} +3 -3
  17. package/public/chunk-Q2ANAJAD.js +1 -0
  18. package/public/{chunk-B75MT7ND.js → chunk-R36UY4Q4.js} +1 -1
  19. package/public/{chunk-CHGXAEKT.js → chunk-RCYOZLZB.js} +1 -1
  20. package/public/{chunk-KPHICV76.js → chunk-SJFJEOSG.js} +1 -1
  21. package/public/{chunk-MGPPVLZ7.js → chunk-TBNKOU7M.js} +1 -1
  22. package/public/chunk-TVNXBPFF.js +6 -0
  23. package/public/{chunk-S72JTJPN.js → chunk-VPF5756E.js} +1 -1
  24. package/public/chunk-VXCYPAWR.js +1 -0
  25. package/public/{chunk-DD4F6F4S.js → chunk-VXTTEFRP.js} +8 -8
  26. package/public/{chunk-R7RQHWKJ.js → chunk-WH5CIUSB.js} +1 -1
  27. package/public/{chunk-LQDSU4WS.js → chunk-WQSJFJLW.js} +1 -1
  28. package/public/{chunk-KZ5DUKAX.js → chunk-XBSU7OGT.js} +1 -1
  29. package/public/{chunk-CEB42O2C.js → chunk-YI3MZWRZ.js} +1 -1
  30. package/public/index.html +1 -1
  31. package/public/main-B6TXB3EB.js +1 -0
  32. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -84
  33. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  34. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -35
  35. package/.github/copilot-instructions.md +0 -218
  36. package/.github/instructions/angular.instructions.md +0 -123
  37. package/.github/instructions/best-practices.instructions.md +0 -59
  38. package/.github/instructions/project.instructions.md +0 -468
  39. package/.github/workflows/ci.yml +0 -37
  40. package/docs/widget-schematic.md +0 -102
  41. package/images/ActionSidenav.png +0 -0
  42. package/images/ChartplotterMode.png +0 -0
  43. package/images/KIPDemo.png +0 -0
  44. package/images/KipBrightness-1024.png +0 -0
  45. package/images/KipConfig-Units-1024.png +0 -0
  46. package/images/KipConfig-display-1024x488.png +0 -0
  47. package/images/KipFreeboard-SK-1024.png +0 -0
  48. package/images/KipGaugeSample1-1024x545.png +0 -0
  49. package/images/KipGaugeSample2-1024x488.png +0 -0
  50. package/images/KipGaugeSample3-1024x508.png +0 -0
  51. package/images/KipNightMode-1024.png +0 -0
  52. package/images/KipWidgetConfig-layout-1024.png +0 -0
  53. package/images/KipWidgetConfig-paths-1024x488.png +0 -0
  54. package/images/Options.png +0 -0
  55. package/images/exterior_user_installs.png +0 -0
  56. package/images/formfactor.png +0 -0
  57. package/plugin-config-data/kip/historicalData/kip-history.duckdb +0 -0
  58. package/plugin-config-data/kip/historicalData/parquet/chart-1/1772344583976-1772344583976.parquet +0 -0
  59. package/plugin-config-data/kip/historicalData/parquet/live-1/1771408800000-1771408890000.parquet +0 -0
  60. package/plugin-config-data/kip/historicalData/parquet/live-1/1771412400000-1771412490000.parquet +0 -0
  61. package/plugin-config-data/kip/historicalData/parquet/live-1/1771419600000-1771419650000.parquet +0 -0
  62. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584154-1772344584154.parquet +0 -0
  63. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584191-1772344584191.parquet +0 -0
  64. package/plugin-config-data/kip/historicalData/parquet/live-1/1772344584268-1772344584268.parquet +0 -0
  65. package/plugin-config-data/kip/historicalData/parquet/live-2/1771502400000-1771502400000.parquet +0 -0
  66. package/plugin-config-data/kip/historicalData/parquet/live-3/1771408800000-1771408890000.parquet +0 -0
  67. package/plugin-config-data/kip/historicalData/parquet/live-3/1771412400000-1771412490000.parquet +0 -0
  68. package/plugin-config-data/kip/historicalData/parquet/live-3/1771419600000-1771419650000.parquet +0 -0
  69. package/plugin-config-data/kip/historicalData/parquet/live-3/1772344584268-1772344584268.parquet +0 -0
  70. package/plugin-config-data/kip/historicalData/parquet/live-4/1771408800000-1771408890000.parquet +0 -0
  71. package/plugin-config-data/kip/historicalData/parquet/live-4/1771412400000-1771412490000.parquet +0 -0
  72. package/plugin-config-data/kip/historicalData/parquet/live-4/1771419600000-1771419650000.parquet +0 -0
  73. package/plugin-config-data/kip/historicalData/parquet/live-5/1771412400000-1771412490000.parquet +0 -0
  74. package/plugin-config-data/kip/historicalData/parquet/live-5/1771419600000-1771419650000.parquet +0 -0
  75. package/plugin-config-data/kip/historicalData/parquet/live-6/1771419600000-1771419650000.parquet +0 -0
  76. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771408800000-1771408890000.parquet +0 -0
  77. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771412400000-1771412490000.parquet +0 -0
  78. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1771419600000-1771419650000.parquet +0 -0
  79. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584191-1772344584191.parquet +0 -0
  80. package/plugin-config-data/kip/historicalData/parquet/live-prefixed-1/1772344584268-1772344584268.parquet +0 -0
  81. package/public/chunk-A6DQJFP4.js +0 -16
  82. package/public/chunk-DEGYRCMI.js +0 -1
  83. package/public/chunk-DYTBBUMI.js +0 -4
  84. package/public/chunk-FNF7M3AE.js +0 -1
  85. package/public/chunk-J3LDKVIS.js +0 -50
  86. package/public/chunk-JB4YVVNW.js +0 -1
  87. package/public/chunk-YKJKIWXO.js +0 -6
  88. package/public/main-EG2WF4EO.js +0 -1
  89. package/tools/schematics/collection.json +0 -9
  90. package/tools/schematics/create-host2-widget/files/readme/README.md.template +0 -109
  91. package/tools/schematics/create-host2-widget/files/spec/widget-__name@dasherize__.component.spec.ts +0 -38
  92. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.html +0 -6
  93. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.scss +0 -5
  94. package/tools/schematics/create-host2-widget/files/widget/widget-__name@dasherize__.component.ts.template +0 -94
  95. package/tools/schematics/create-host2-widget/index.js +0 -138
  96. package/tools/schematics/create-host2-widget/schema.json +0 -89
  97. package/tools/schematics/create-host2-widget/test/create-host2-widget.spec.ts +0 -70
  98. package/tools/schematics/create-host2-widget/utils/formatting.js +0 -119
@@ -1,468 +0,0 @@
1
- # KIP Project Instructions
2
-
3
- This file is longer-form reference material. For the canonical, up-to-date KIP coding rules (especially Host2 widgets), follow [.github/copilot-instructions.md](../copilot-instructions.md).
4
-
5
- ## 1. Project Overview
6
- KIP Instrument MFD is an advanced and versatile marine instrumentation package designed to display Signal K data in a modern, customizable dashboard, on boats. It provides real-time visualization of navigation, wind, engine, and other marine data streams offered by Signal K, supporting a wide range of widgets and configuration options. The project aims to deliver a user-friendly, extensible, and visually appealing interface for both professional and recreational marine users.
7
-
8
- - **Key technologies:** Angular (v20+), Angular Material, Signal K, TypeScript, SCSS.
9
-
10
- ---
11
-
12
- ## 2. Architecture & Structure
13
- - **Main folders:**
14
- - `src/app/`: Main application code.
15
- - `src/app/widgets/`: Widget components (e.g., wind, autopilot).
16
- - `src/app/widget-config/`: Widget configuration components and logic.
17
- - `src/app/core/`: Core services, interfaces, and utilities.
18
- - **Component structure:**
19
- - Each widget has its own component, template, and theme SCSS in `src/app/widgets/`.
20
- - All widget configuration logic and UI is centralized and handled independently by components in `src/app/widget-config/`.
21
- - Creating a new widget does not require changes to `src/app/widget-config/` unless your widget introduces new configuration properties or needs a custom config UI.
22
- - The main configuration form logic is in `src/app/widget-config/modal-widget-config/`. For unique widget config needs, you may add a new config component (e.g., `modal-widget-<name>-config`).
23
- - Widget logic/UI and widget configuration are separate concepts that work together.
24
-
25
- ### Finalized architecture (2026 Q1)
26
- - **History series reconciliation pipeline:** Dashboard widget topology is normalized by `DashboardHistorySeriesSyncService` and reconciled through `KipSeriesApiClientService` into plugin-backed series definitions.
27
- - **Dataset lifecycle centralization:** `WidgetDatasetOrchestratorService` is the write-owner for widget datasets (create/edit/remove and owner-based cleanup).
28
- - **Shared history adaptation:** `HistoryToChartMapperService` centralizes History API values-to-chart datapoint mapping, including average aliases and circular-angle summary stats.
29
- - **Delete-path cleanup simplification:** Dashboard delete flow now performs owner UUID dataset cleanup via lifecycle service instead of selector-specific branches.
30
-
31
- ### Architecture guardrails for contributors
32
- - Replace direct widget/dashboard `DatasetStreamService` write calls with `WidgetDatasetOrchestratorService` sync/remove helpers.
33
- - Preserve stable widget UUID ownership contracts; these IDs are used for dataset and series reconciliation behavior.
34
- - Keep history response transformation logic in `HistoryToChartMapperService` to avoid divergence across chart consumers.
35
- - Avoid reintroducing legacy widget-selector cleanup branches.
36
-
37
- ---
38
-
39
- ## 4. Conventions & Patterns
40
- - **Naming:**
41
- - Use descriptive, camelCase names for variables and controls.
42
- - Widget config properties match the widget’s function (e.g., `trueWindAngle`, `drift`).
43
- - **Forms:**
44
- - Use Angular Reactive Forms for all configuration UIs.
45
- - Group related controls in form groups.
46
- - **Theming:**
47
- - Use SCSS mixins for light/dark themes.
48
- - Theme mixins must be included in global or component styles.
49
-
50
- ---
51
-
52
- ## 5. Development Workflow
53
- - **Linting:**
54
- - Run `npm run lint` before every commit (enforced with Husky pre-commit hook).
55
- - **Testing:**
56
- - _To be defined._
57
- - **Build & Serve:**
58
- - `npm run dev` for development server.
59
- - `npm run build:dev` for KIP only development build.
60
- - `npm run build:prod` for KIP only production build.
61
- - `npm run build:all` for KIP and KIP plugin production build.
62
-
63
- ---
64
-
65
- ## 6. Documentation & Comments
66
- - **Document all custom validators and business rules.**
67
- - **Update this file and the README with any major changes or new patterns.**
68
- - **JSDoc requirement:** Every public TypeScript property and public method must include full JSDoc containing: purpose, parameters, return value, and at least one usage example.
69
-
70
- ---
71
-
72
-
73
- ## 8. Core Service Summaries
74
- All major services in `src/app/core/services/` are summarized below for Copilot and developer context. Each entry includes purpose, key methods/responsibilities, dependencies, and usage notes.
75
-
76
- - **AppNetworkInitService (`app-initNetwork.service.ts`)**
77
- - Purpose: Loads network services (Signal K connection, authentication, Storage Service) and retrieves configurations from the Signal K server and loaded it before app startup using Angular's `APP_INITIALIZER`.
78
- - Key methods: `initNetworkServices()`, config loading, login management.
79
- - Dependencies: SignalKConnectionService, AuthenticationService, StorageService, DataService, SignalKDeltaService.
80
- - Usage: Ensures network, authentication, Storage Service and configuration are ready before app bootstraps.
81
-
82
- - **AuthenticationService (`authentication.service.ts`)**
83
- - Purpose: Handles user/device authentication with the Signal K server.
84
- - Key methods: `login()`, `logout()`, token management, exposes `isLoggedIn$` observable.
85
- - Dependencies: SignalKConnectionService, HttpClient.
86
-
87
- - **DialogService (`dialog.service.ts`)**
88
- - Purpose: Centralizes all app dialogs using Angular Material.
89
- - Dependencies: MatDialog, Dialog components.
90
- - Usage: Used throughout the app to open modals and dialogs for user interaction.
91
-
92
- - **SignalKConnectionService (`signalk-connection.service.ts`)**
93
- - Purpose: Manages the WebSocket connection to the Signal K server, including reconnect logic and status tracking.
94
- - Key methods: `connect()`, `disconnect()`, status observables.
95
- - Dependencies: WebSocket, AuthenticationService.
96
-
97
- - **SignalKDeltaService (`signalk-delta.service.ts`)**
98
- - Purpose: Handles real-time delta updates from Signal K, distributing data to widgets and services.
99
- - Key methods: Delta subscription, data distribution.
100
- - Dependencies: SignalKConnectionService, DataService.
101
-
102
- - **DataService (`data.service.ts`)**
103
- - Purpose: Central data provider for Signal K and other sources; handles subscriptions, value updates, and metadata management.
104
- - Key methods: `subscribeToPath()`, `getValue()`, `getMetadata()`, data and metadata update distribution.
105
- - Dependencies: SignalKDeltaService, StorageService.
106
-
107
- - **AppService (`app-service.ts`)**
108
- - Purpose: Centralizes app-wide utilities, notifications, and theme management.
109
- - Key methods: Notification helpers, theme switching, app-level utilities.
110
- - Dependencies: Angular core, theme and notification services.
111
-
112
- - **UIEventService (`uiEvent.service.ts`)**
113
- - Purpose: Manages UI events such as drag, fullscreen, wake lock, and hotkeys.
114
- - Key methods: Event emitters, hotkey handlers.
115
- - Dependencies: Angular core, browser APIs.
116
-
117
- - **SettingsService (`settings.service.ts`)**
118
- - Purpose: Manages persistent app settings, user preferences, and configuration storage.
119
- - Key methods: `getSetting()`, `setSetting()`, config file management.
120
- - Dependencies: StorageService.
121
-
122
- - **StorageService (`storage.service.ts`)**
123
- - Purpose: Provides persistent storage for app data, settings, and user preferences.
124
- - Key methods: `getItem()`, `setItem()`, config file management.
125
- - Dependencies: LocalStorage, IndexedDB, or similar.
126
-
127
- - **NotificationsService (`notifications.service.ts`)**
128
- - Key methods: Notification state management, audio/visual alerts, muting.
129
- - Dependencies: SettingsService, DataService, SignalkRequestsService.
130
-
131
- - **ToastService (`toast.service.ts`)**
132
- - Purpose: In-app snackbars using Angular Material.
133
- - Key methods: `show(message, duration = 1500, silent = true, action = 'Dismiss', severity = 'message')`.
134
- - Dependencies: MatSnackBar, SettingsService.
135
- - Usage: Use for short, user-visible feedback (login errors, PUT failures, success confirmations). Sound is suppressed when `silent=true` or user sound settings disable audio.
136
-
137
- - **CanvasService (`canvas.service.ts`)**
138
- - Purpose: Provides drawing and rendering utilities for widgets and dashboard components.
139
- - Key methods: Canvas context helpers, drawing utilities.
140
- - Dependencies: None (core Angular).
141
-
142
- - **DashboardService (`dashboard.service.ts`)**
143
- - Purpose: Handles dashboard layout, widget arrangement, and dashboard state.
144
- - Key methods: Layout management, widget arrangement, dashboard state.
145
- - Dependencies: StorageService, WidgetService.
146
-
147
- - **DatasetStreamService (`dataset-stream.service.ts`)**
148
- - Purpose: Manages data sets, including loading, saving, and updating widget data sources.
149
- - Key methods: Data set CRUD, data source updates.
150
- - Dependencies: DataService, StorageService.
151
-
152
- - **WidgetDatasetOrchestratorService (`widget-dataset-orchestrator.service.ts`)**
153
- - Purpose: Centralized dataset orchestration for widget lifecycle operations.
154
- - Key methods: `syncDataChartDataset()`, `syncNumericMiniChartDataset()`, `syncWindTrendsDatasets()`, `removeOwnedDatasets()`.
155
- - Dependencies: DatasetStreamService.
156
- - Usage: Preferred write path for widget/dash dataset lifecycle actions.
157
-
158
- - **HistoryToChartMapperService (`history-to-chart-mapper.service.ts`)**
159
- - Purpose: Shared adapter for converting History API value responses into chart datapoints.
160
- - Key methods: `mapValuesToChartDatapoints()`.
161
- - Dependencies: None (core mapping service).
162
- - Usage: Keeps chart history behavior consistent across all consumers.
163
-
164
- - **DashboardHistorySeriesSyncService (`dashboard-history-series-sync.service.ts`)**
165
- - Purpose: Derives desired historical-series definitions from current dashboard/widget state and reconciles with plugin backend.
166
- - Key methods: Internal extraction + debounced reconcile scheduling.
167
- - Dependencies: DashboardService, KipSeriesApiClientService, SignalKConnectionService.
168
- - Usage: Single orchestration path for add/edit/delete/copy/paste/duplicate widget series convergence.
169
-
170
- - **KipSeriesApiClientService (`kip-series-api-client.service.ts`)**
171
- - Purpose: Frontend bridge to KIP plugin series reconcile endpoint.
172
- - Key methods: `reconcileSeries()`.
173
- - Dependencies: HttpClient, SignalKConnectionService.
174
- - Usage: Posts full desired series definitions to plugin for canonical reconciliation.
175
-
176
- - **PluginConfigClientService (`plugin-config-client.service.ts`)**
177
- - Purpose: Plugin configuration foundation service for dependency checks and plugin state/config persistence via Signal K `/plugins` endpoints.
178
- - Key methods: `listPlugins()`, `getPlugin()`, `getPluginConfig()`, `savePluginConfig()`, `setPluginEnabled()`, `validateDependency()`, `normalizePluginSchema()`.
179
- - Dependencies: HttpClient, SignalKConnectionService.
180
- - Usage: Source of truth for plugin detection and config save flows; no plugin install/uninstall support.
181
-
182
- - **SignalKRequestsService (`signalk-requests.service.ts`)**
183
- - Purpose: Handles requests to the Signal K server, such as PUT/POST operations and custom actions.
184
- - Key methods: `sendRequest()`, custom action handlers.
185
- - Dependencies: SignalKConnectionService, DataService.
186
-
187
- - **TimersService (`timers.service.ts`)**
188
- - Purpose: Centralized timer utility for app and widgets, supporting intervals, timeouts, and scheduling.
189
- - Key methods: Timer creation, interval management.
190
- - Dependencies: Angular core.
191
-
192
- - **UnitsService (`units.service.ts`)**
193
- - Purpose: Handles unit conversion and formatting for all displayed data.
194
- - Key methods: `convert()`, `format()`, unit preference management.
195
- - Dependencies: SettingsService.
196
-
197
- - **WidgetService (`widget.service.ts`)**
198
- - Purpose: Manages widget registration, configuration, and lifecycle.
199
- - Key methods: Widget registration, config helpers, lifecycle management.
200
- - Dependencies: DashboardService, DataService.
201
-
202
- ---
203
-
204
- ## 9. Host2 Widget Architecture
205
-
206
- Host2 widget rules are maintained in one place to avoid duplication. Use the canonical Host2 widget contract and patterns from:
207
-
208
- - [.github/copilot-instructions.md](../copilot-instructions.md)
209
-
210
- Quick reminders:
211
- - Always guard `runtime.options()` and `cfg.paths?.key?.path` before observing.
212
- - Register all `streams.observe(...)` in a single `effect()` and group subscriptions in one `untracked()` block.
213
- - Keep transient UI state in signals; do not mutate the merged config object.
214
- ---
215
-
216
- ## 10. KIP Colors, Theming, and Widget Best Practices
217
-
218
- - **KIP Color & Theming Concepts:**
219
- - KIP uses a centralized theme system with color roles defined in SCSS and exposed to TypeScript via CSS variables and the `AppService`.
220
- - Theme colors (e.g., `contrast`, `blue`, `zoneAlarm`, `background`, etc.) are defined in SCSS files (`styles.scss`, theme partials) and mapped to CSS variables (e.g., `--kip-blue-color`).
221
- - The `AppService` provides a `cssThemeColorRoles$` observable and a `theme()` signal for accessing current theme colors in TypeScript.
222
- - Theme switching (light, dark, night) is handled by toggling classes on `<body>` and updating CSS variables.
223
- - All widgets should use theme colors for UI consistency and accessibility.
224
-
225
- - **Best Practices for Using Colors & Theming in Widgets:**
226
- - **TypeScript:**
227
- - Access theme colors via `this.theme().<colorRole>` (e.g., `this.theme().zoneAlarm`, `this.theme().contrast`).
228
- - Never hardcode color hex values in widget TypeScript; always use theme roles.
229
- - For dynamic coloring (e.g., based on state/zones), use the correct theme role for each state (see `zoneAlarm`, `zoneWarn`, etc.).
230
- - Use the color mapping pattern as in `getColors()` for supporting multiple color roles and dim/dimmer variants.
231
- - When updating widget visuals (e.g., gauge, highlights), always update with theme colors to support live theme switching.
232
- - **SCSS:**
233
- - Use CSS variables (e.g., `var(--kip-blue-color)`) for all color assignments in widget/component styles.
234
- - Do not use static hex codes; always reference a theme variable.
235
- - For custom widget styles, define new CSS variables in the theme partials if needed, and use them in your SCSS.
236
- - Use the `.light-theme`, `.night-theme`, and default (dark) selectors to override variables for each theme as needed.
237
- - Use SCSS mixins for reusable style patterns and to support theme switching.
238
- - **General:**
239
- - Always test widgets in all themes (light, dark, night) to ensure colors are accessible and visually correct.
240
- - Use theme roles for all UI elements, including backgrounds, borders, text, and highlights.
241
- - For state-based coloring (e.g., alarms, warnings), use the corresponding zone color from the theme.
242
- - Avoid inline styles for colors; prefer class-based or variable-based styling.
243
- ---
244
-
245
- ## 11. Additional Instructions & Cross-References
246
-
247
- ### **Related Instruction Files:**
248
- - **README.md**: Project overview, setup instructions, and development guidelines
249
- - **`.github/instructions/angular.instructions.md`**: Detailed Angular v20+ coding standards, component patterns, and framework-specific best practices
250
-
251
- ### **Instruction Hierarchy:**
252
- 1. **Primary**: This `COPILOT.md` file (KIP-specific project guidelines and architecture)
253
- 2. **Secondary**: `.github/instructions/angular.instructions.md` (Angular framework standards and modern patterns)
254
- 3. **Tertiary**: `README.md` (General project information and setup)
255
-
256
- ### **Usage Notes:**
257
- - All Angular development should follow both this COPILOT.md file AND the angular.instructions.md guidelines
258
- - When conflicts arise, KIP-specific guidelines in this file take precedence over general Angular patterns
259
- - For widget development, use the Host2 widget architecture (sections 9 & 13) – standalone components + directives (no inheritance)
260
- - For general Angular coding (components, services, forms, component), follow the modern Angular v20+ patterns in angular.instructions.md
261
-
262
- ---
263
-
264
- ## 12. SVG Animation Utilities (requestAnimationFrame Helpers)
265
-
266
- High-performance SVG animations in KIP (e.g., wind steering dial laylines, sector bands, rotating indicators) use a small set of utilities found in `src/app/widgets/utils/svg-animate.util.ts` to ensure:
267
-
268
- - No unnecessary Angular change detection on every animation frame
269
- - Consistent easing and shortest‑path angle interpolation
270
- - Centralized cancellation logic (preventing overlapping animations per element/concern)
271
- - Readable, minimal widget component code
272
-
273
- ### 12.1 Design Principles
274
- 1. Run frame loops outside Angular's `NgZone` to avoid triggering change detection ~60 times/sec.
275
- 2. Only re-enter the zone once per animation (on completion callback) if UI state needs Angular binding updates.
276
- 3. Gate “tiny” animations (angle deltas below a threshold) to avoid visual jitter and wasted work.
277
- 4. Always animate the shortest angular path (wrap via ±180 logic) for rotational continuity.
278
- 5. Provide generic primitives (angle + sector interpolation) so components don’t duplicate interpolation math.
279
-
280
- ### 12.2 Provided Functions
281
- | Function | Purpose | Key Inputs | Notes |
282
- |----------|---------|-----------|-------|
283
- | `animateRotation(el, fromDeg, toDeg, durationMs, onDone?, ngZone?)` | Smoothly rotates an SVG element (`transform: rotate(...)`) | Element, start+end angles, duration | Tracks per-element frame id internally (WeakMap) so a new call cancels the prior rotation for that element. |
284
- | `animateRudderWidth(rectEl, fromWidth, toWidth, durationMs, onDone?, ngZone?)` | Interpolates a `<rect>` width | SVGRectElement, numeric widths | Same outside-zone strategy; width set via `setAttribute`. |
285
- | `animateAngleTransition(fromDeg, toDeg, durationMs, applyFn, onDone?, ngZone?)` | Generic angle interpolation (no DOM assumptions) | Angles, duration, callback(angle) | Use for derived geometry (e.g., computing a path string). |
286
- | `animateSectorTransition(from: SectorAngles, to: SectorAngles, durationMs, applyFn, onDone?, ngZone?)` | Interpolates a structured group of three related angles (`min, mid, max`) | Objects with `{min, mid, max}` | Uses same angle normalization per field + easing. |
287
-
288
- `SectorAngles` interface:
289
- ```
290
- interface SectorAngles { min: number; mid: number; max: number; }
291
- ```
292
-
293
- ### 12.3 NgZone Strategy
294
- All helpers accept an optional `NgZone`. When provided they:
295
- 1. Call `ngZone.runOutsideAngular()` wrapping the frame loop.
296
- 2. Use `requestAnimationFrame` until elapsed >= duration.
297
- 3. Apply easing (cubic in/out) and normalized shortest-path interpolation.
298
- 4. On final frame, invoke `onDone` inside Angular (`ngZone.run(...)`) so any bound template values update once.
299
-
300
- If `ngZone` is omitted they still function (pure browser environment) — suitable for non-Angular contexts or tests.
301
-
302
- ### 12.4 Cancellation Rules
303
- - `animateRotation` & `animateRudderWidth` internally keep a WeakMap<Element, frameId>; a new call replaces the old.
304
- - Callers of `animateAngleTransition` / `animateSectorTransition` receive the raw `frameId` and MUST store & cancel it if a new animation is started for the same conceptual target (e.g., a layline or sector band) before completion.
305
- - Always cancel outstanding frame ids in `ngOnDestroy` to avoid orphan rAF callbacks if the component is torn down mid-animation.
306
-
307
- ### 12.5 Angle Handling Details
308
- - Input angles are normalized to [0, 360).
309
- - Delta uses wrapped signed difference: `((to - from + 540) % 360) - 180` for shortest path.
310
- - Interpolated angle = `from + easedT * delta`; final angle normalized again.
311
- - A small epsilon (e.g., ~0.25°) can be used by callers to skip tiny animations; component sets `EPS_ANGLE` constant.
312
-
313
- ### 12.6 Easing
314
- Currently a fixed cubic ease-in-out: `t < 0.5 ? 4t^3 : 1 - pow(-2t + 2, 3)/2`. Chosen for smooth acceleration/deceleration without overshoot. If future needs arise, expose an optional easing parameter (keep backward compatibility by defaulting to cubic in/out).
315
-
316
- ### 12.7 Usage Patterns
317
-
318
- Rotate an indicator:
319
- ```
320
- this.animationFrameIds.set(
321
- el,
322
- animateRotation(el, currentAngle, targetAngle, 300, () => { /* one-time post animation logic */ }, this.ngZone)
323
- );
324
- ```
325
-
326
- Animate a layline path angle:
327
- ```
328
- if (this.portLaylineAnimId) cancelAnimationFrame(this.portLaylineAnimId);
329
- this.portLaylineAnimId = animateAngleTransition(
330
- prevAngle,
331
- nextAngle,
332
- 300,
333
- angle => this.updateLaylinePath(angle, /* isPort= */ true),
334
- () => { this.portLaylineAnimId = null; },
335
- this.ngZone
336
- );
337
- ```
338
-
339
- Animate a wind sector (three angles):
340
- ```
341
- if (this.portSectorAnimId) cancelAnimationFrame(this.portSectorAnimId);
342
- this.portSectorAnimId = animateSectorTransition(
343
- previousSector,
344
- newSector,
345
- 300,
346
- sector => this.updateSectorPath(sector, true),
347
- () => { this.portSectorAnimId = null; },
348
- this.ngZone
349
- );
350
- ```
351
-
352
- ### 12.8 When NOT to Animate
353
- - First render / initialization where the user has no prior visual expectation — just set final state.
354
- - Discontinuous jumps (e.g., compass wrap after data gap) that would produce a long spin — snap instead.
355
- - Extremely small (< epsilon) changes — update instantly.
356
-
357
- ### 12.9 Testing Tips
358
- - For deterministic unit tests, inject a mock `performance.now()` / substitute a manual time advance, or abstract the timestamp acquisition behind a seam if greater test coverage is required.
359
- - Validate shortest-path logic with cases like `from=350 → to=10` (should rotate +20°, not -340°).
360
- - Confirm cancellation by firing a second animation mid-way; the first should not apply further frames.
361
-
362
- ### 12.10 Future Extensions (Backlog Ideas)
363
- - Optional custom easing function parameter.
364
- - Support for group animations (batch multiple angle transitions under one rAF loop for micro-optimizations).
365
- - Auto-prefetch “snap if > threshold degrees” heuristic inside helpers (today caller decides).
366
-
367
- ---
368
-
369
- ## 13. create-host2-widget Schematic (Host2 Widget Generator)
370
-
371
- The `create-host2-widget` schematic scaffolds a production-ready Host2 widget with optional zones support, tests, and README guidance. It enforces current architectural patterns (signals + directives) and reduces manual registration effort.
372
-
373
- ### 13.1 When To Use
374
- Use the schematic for any new widget that:
375
- - Consumes one (or more, to be added later) Signal K path values.
376
- - Requires standard lifecycle (config merging, unit conversion, timeout handling) via `WidgetRuntimeDirective` + `WidgetStreamsDirective`.
377
- - Optionally needs zones metadata visualization.
378
-
379
- ### 13.2 Invocation Examples
380
- Minimal (interactive prompts for all options):
381
- ```
382
- npm run generate:widget
383
- ```
384
- or
385
- ```
386
- ng g create-host2-widget
387
- ```
388
-
389
- Non-interactive with explicit options:
390
- ```
391
- npx schematics ./tools/schematics/collection.json:create-host2-widget \
392
- --name tides-chart \
393
- --title "Tides Chart" \
394
- --registerWidget Core \
395
- --pathType number \
396
- --pathDefault navigation.speedThroughWater \
397
- --zonesSupport=false \
398
- --addSpec=true \
399
- --todoBlock=false \
400
- --readme=true
401
- ```
402
-
403
- ### 13.3 Options Reference
404
- | Option | Values / Type | Default | Purpose | Notes |
405
- |--------|---------------|---------|---------|-------|
406
- | `name` | string (kebab-case) | — (required) | Base name (component selector becomes `widget-<name>`) | Must be unique under `src/app/widgets/` |
407
- | `title` | string | — (required) | Display title (Add Widget dialog) | Used in WidgetService definition object |
408
- | `registerWidget` | `Core | Gauge | Component | Racing | No` | — | Auto-register in `widget.service.ts` or skip | `No` (case-insensitive) means skip registration |
409
- | `pathType` | `number|string|boolean|Date` | `number` | Primary path value type | Influences stream conversion & formatting |
410
- | `pathDefault` | string/null | `null` | Pre-filled Signal K path | Leave null if unsure |
411
- | `zonesSupport` | boolean | `false` | Include zones metadata scaffolding | Adds metadata directive & highlights logic placeholder |
412
- | `addSpec` | boolean | `true` | Generate spec test file | Basic presence test; extend manually |
413
- | `todoBlock` | boolean | `true` | Include instructional TODO comments | Set false for clean production scaffold |
414
- | `readme` | boolean | `true` | Generate widget README | Developer-focused quick guide |
415
- | `debugLogging` | boolean | `false` | Verbose schematic execution logs | Helpful when troubleshooting formatting/registration |
416
-
417
- Hidden defaults inserted into templates: `sampleTime=1000`, `convertUnitTo=null`, placeholder icon & description (replace post-gen).
418
-
419
- ### 13.4 Generated Artifacts
420
- - `widget-<name>.component.ts|html|scss` – Host2 component & view.
421
- - Optional `widget-<name>.component.spec.ts` when `--addSpec=true`.
422
- - Optional `README.md` (widget-local developer instructions) when `--readme=true`.
423
- - Service registration (import, component map entry, widget definition object) unless `registerWidget=No`.
424
-
425
- ### 13.5 Post-Generation Checklist
426
- - Replace placeholder icon (`placeholder-icon`) with an actual symbol id in `src/assets/svg/icons.svg` and update `widget.service.ts` entry.
427
- - Write a concise, user-facing description in the WidgetService definition object.
428
- - Adjust `DEFAULT_CONFIG.displayName` and color.
429
- - Decide whether to keep or remove TODO comments (regen with `--todoBlock=false` once stable).
430
- - Add any additional paths (with guards) and corresponding `streams.observe` registrations.
431
- - If zones used: adapt highlight computation (unit, scale bounds, colors) and remove unused scaffolding.
432
- - Add/expand tests (mock streams, theme, optional zones metadata).
433
-
434
- ### 13.6 Zones Support Notes
435
- If `--zonesSupport=true`:
436
- - `WidgetMetadataDirective` is injected; you must call `metadata.observe('signalKPath')` (or other path key) only if a path is configured.
437
- - `metadata.zones()` exposes current zones; pass through `getHighlights` with min/max scale & unit for overlays.
438
- - Always guard: missing path OR zones → return empty highlight array.
439
-
440
- ### 13.7 Common Pitfalls & Resolutions
441
- | Pitfall | Cause | Resolution |
442
- |---------|-------|-----------|
443
- | Widget not listed in Add dialog | Chose `registerWidget No` or category mismatch | Regenerate OR manually add definition to `widget.service.ts` |
444
- | Duplicate import/service entry | Manual edits then re-run schematic | Remove redundant lines; schematic guards imports but verify component map |
445
- | Runtime error in highlights | Accessing undefined scale or wrong path key | Guard `cfg.paths['signalKPath']` and ensure scale present before computing |
446
- | Units not converting | Missing or null `convertUnitTo` in path config | Add target unit in path definition (number types only) |
447
- | Tests failing after adding new paths | Spec doesn’t mock added streams | Update spec to provide minimal mock path observation |
448
-
449
- ### 13.8 Recommended Development Flow
450
- 1. Generate widget with `--todoBlock=true` for guidance.
451
- 2. Implement path observation & basic rendering logic.
452
- 3. Add zones (if required) and verify highlight behavior with test data.
453
- 4. Remove TODO comments (or regenerate clean variant) once stable.
454
- 5. Add additional paths & unit tests (timeout, no-path, zones absent).
455
- 6. Finalize icon & description, then open PR.
456
-
457
- ### 13.9 Troubleshooting Registration
458
- If the schematic ran but the widget is missing:
459
- 1. Open `widget.service.ts` and search for your selector (e.g., `widget-tides-chart`).
460
- 2. Confirm: import line, component map entry, and definition object exist.
461
- 3. If absent, re-run with `--debugLogging=true` to inspect logs, or manually paste the generated object from another widget as a template.
462
-
463
- ### 13.10 Conventions Recap
464
- - One effect for all observers.
465
- - Guard optional paths before observing.
466
- - Signals for state; avoid extraneous change detection.
467
- - Use `untracked()` when registering observers to prevent superfluous effect retriggers.
468
- ---
@@ -1,37 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [ main, master, develop ]
6
- pull_request:
7
- branches: [ main, master, develop ]
8
-
9
- jobs:
10
- build:
11
- runs-on: ubuntu-latest
12
-
13
- strategy:
14
- matrix:
15
- node-version: [20.x, 22.x]
16
-
17
- steps:
18
- - name: Checkout repository
19
- uses: actions/checkout@v4
20
-
21
- - name: Setup Node.js ${{ matrix.node-version }}
22
- uses: actions/setup-node@v4
23
- with:
24
- node-version: ${{ matrix.node-version }}
25
- cache: 'npm'
26
-
27
- - name: Install dependencies
28
- run: npm i
29
-
30
- - name: Lint
31
- run: npm run lint
32
-
33
- - name: Run tests
34
- run: npm run test:headless
35
-
36
- - name: Build All (Webapp & Plugin)
37
- run: npm run build:all
@@ -1,102 +0,0 @@
1
- ## Host2 Widget Schematic
2
-
3
- Use the custom schematic to scaffold a new Host2 architecture widget.
4
-
5
- ### Command
6
-
7
- ```
8
- npx schematics ./tools/schematics/collection.json:create-host2-widget \
9
- --name speed-over-ground \
10
- --title "Speed Over Ground" \
11
- --description "Displays SOG from navigation.speedOverGround" \
12
- --icon navigation-speed \
13
- --path-key numericPath \
14
- --path-description "Speed Over Ground" \
15
- --convert-unit-to knots \
16
- --sample-time 1000 \
17
- --register-widget Core
18
- ```
19
-
20
- Only the required flags are `--name`, `--title`, `--description`, and `--icon` when running non-interactively. By default `--dry-run=false` is applied via the npm script.
21
-
22
- ### Prompting Behavior
23
-
24
- The schematic now uses Angular schema `x-prompt` for both required and optional fields.
25
-
26
- Modes:
27
- 1. Non-interactive (default when values supplied or CLI run without `--interactive`): Only missing required fields will prompt; others use defaults.
28
- 2. Interactive (`--interactive` or `--interactive=true`): Prompts sequentially for every field (required + optional) unless you provided it on the command line.
29
-
30
- Flag naming: CLI flags must be kebab-case. Each dashed flag maps to camelCase schema properties (e.g. `--register-widget` → `registerWidget`, `--sample-time` → `sampleTime`). Using camelCase directly (e.g. `--registerWidget`) will fail with an "Unknown argument" error.
31
-
32
- Examples:
33
- ```
34
- # Minimal required (will prompt for any missing among required)
35
- npm run generate:widget -- --name depth --title Depth --description "Shows depth" --icon depth-icon --register-widget Core
36
-
37
- # Full guided session (asks optional too)
38
- npm run generate:widget -- --interactive --name aws --title "Apparent Wind" --description "Displays apparent wind" --icon wind --register-widget Core
39
-
40
- # Skip service registration
41
- npm run generate:widget -- --name scratch --title Scratch --description "Sandbox" --icon placeholder --register-widget no
42
- ```
43
-
44
- ### Important Options (subset)
45
-
46
- | Option | Default | Notes |
47
- | ------ | ------- | ----- |
48
- | name | (none) | Kebab-case base name without `widget-` prefix |
49
- | title | (none) | Display name inserted into widget definition |
50
- | description | (none) | One-line description for registry |
51
- | icon | (none) | Icon key placeholder (replace later) |
52
- | category | Core | One of Core, Gauge, Component, Racing |
53
- | pathKey (flag: --path-key) | signalKPath | Internal key used for data stream observation |
54
- | pathDescription (flag: --path-description) | My Path | Shown in config UIs (future) |
55
- | pathType (flag: --path-type) | number | number|string|boolean|Date |
56
- | convertUnitTo (flag: --convert-unit-to) | unitless | Target display unit (UnitsService) |
57
- | sampleTime (flag: --sample-time) | 1000 | ms between sampled updates |
58
- | registerWidget (flag: --register-widget) | (none) | Category (Core/Gauge/Component/Racing) or 'no' to skip service update |
59
- | addSpec | true | Generates a basic host test wrapper spec |
60
- | readme | true | Emits README.md with scaffold notes |
61
- | interactive | false | Use `--interactive` to have the CLI ask for any values you did not supply |
62
-
63
- ### What Gets Generated
64
-
65
- ```
66
- src/app/widgets/widget-<name>/<name>.component.ts
67
- src/app/widgets/widget-<name>/<name>.component.html
68
- src/app/widgets/widget-<name>/<name>.component.scss
69
- src/app/widgets/widget-<name>/<name>.component.spec.ts (if --addSpec)
70
- src/app/widgets/widget-<name>/README.md (if --readme)
71
- ```
72
-
73
- If `registerWidget` is not set to `no`, the schematic also updates `WidgetService`:
74
- 1. Adds an import for the new component.
75
- 2. Adds the component class to `_componentTypeMap`.
76
- 3. Inserts a widget definition object into `_widgetDefinition` (automatically ordered within its category).
77
-
78
- ### After Generation Checklist
79
-
80
- - Replace placeholder `icon` in the widget definition with a real SVG symbol id.
81
- - Adjust `DEFAULT_CONFIG.paths` if you need multiple paths (add entries & observers in one `untracked` block).
82
- - Implement formatting / unit display logic using existing helper services if needed.
83
- - Flesh out the spec with domain assertions (current spec only verifies instantiation).
84
-
85
- ### Removing a Generated Widget
86
-
87
- Manual cleanup steps:
88
- 1. Delete the folder `src/app/widgets/widget-<name>`.
89
- 2. Remove the import, map entry, and definition block for the widget from `WidgetService`.
90
-
91
- ### Troubleshooting
92
-
93
- | Symptom | Cause | Fix |
94
- | ------- | ----- | --- |
95
- | Duplicate README like `README<name>.md` | Older schematic version left name in filename | Delete the redundant file & upgrade schematic (already fixed) |
96
- | Widget already exists error | Folder collision | Choose a different `--name` or delete the existing widget |
97
- | No WidgetService update | Service path changed | Adjust `WIDGET_SERVICE` constant in schematic factory |
98
-
99
- ### Development Notes
100
-
101
- - Template sources end with `.template`; a post-processing rule strips the suffix for final emission.
102
- - Config UI generation was intentionally removed; future re-introduction would require new templates.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file