@meshmakers/octo-meshboard 3.3.390

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,490 @@
1
+ # OctoMesh MeshBoard Library
2
+
3
+ A flexible, widget-based dashboard library for Angular applications in the OctoMesh platform.
4
+
5
+ ## Overview
6
+
7
+ MeshBoard provides a grid-based dashboard system with configurable widgets that can display data from various sources including runtime entities, persistent queries, and aggregations.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @meshmakers/octo-meshboard
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ### Basic Integration
18
+
19
+ Add the MeshBoard route to your application:
20
+
21
+ ```typescript
22
+ import { Routes } from '@angular/router';
23
+ import { UnsavedChangesGuard } from '@meshmakers/shared-ui';
24
+
25
+ export const routes: Routes = [
26
+ {
27
+ path: "dashboard",
28
+ loadComponent: () =>
29
+ import('@meshmakers/octo-meshboard').then(m => m.MeshBoardViewComponent),
30
+ canDeactivate: [UnsavedChangesGuard]
31
+ }
32
+ ];
33
+ ```
34
+
35
+ ### Load Specific MeshBoard by rtId
36
+
37
+ ```typescript
38
+ {
39
+ path: "dashboard/:rtId",
40
+ loadComponent: () =>
41
+ import('@meshmakers/octo-meshboard').then(m => m.MeshBoardViewComponent),
42
+ canDeactivate: [UnsavedChangesGuard]
43
+ }
44
+ ```
45
+
46
+ ### Load MeshBoard by Well-Known Name
47
+
48
+ Use `meshBoardWellKnownName` in route data to load a specific MeshBoard:
49
+
50
+ ```typescript
51
+ {
52
+ path: "cockpit",
53
+ loadComponent: () =>
54
+ import('@meshmakers/octo-meshboard').then(m => m.MeshBoardViewComponent),
55
+ canDeactivate: [UnsavedChangesGuard],
56
+ data: {
57
+ meshBoardWellKnownName: 'cockpit',
58
+ breadcrumb: [{ label: "Cockpit", url: "cockpit" }]
59
+ }
60
+ }
61
+ ```
62
+
63
+ **Note:** If the MeshBoard with the specified `rtWellKnownName` does not exist, an error message will be displayed with instructions on how to create it.
64
+
65
+ ### Setting the Well-Known Name
66
+
67
+ To set a Well-Known Name for a MeshBoard:
68
+
69
+ 1. Open the MeshBoard Settings dialog
70
+ 2. Enter a unique identifier in the "Well-Known Name" field (e.g., `cockpit`, `sales-dashboard`)
71
+ 3. Save the MeshBoard
72
+
73
+ The Well-Known Name should be lowercase with hyphens, similar to URL slugs.
74
+
75
+ ## Architecture
76
+
77
+ ```
78
+ octo-meshboard/
79
+ ├── containers/
80
+ │ └── meshboard-view/ # Main view component
81
+ ├── widgets/ # Widget implementations
82
+ │ ├── bar-chart-widget/
83
+ │ ├── entity-card-widget/
84
+ │ ├── gauge-widget/
85
+ │ ├── kpi-widget/
86
+ │ ├── pie-chart-widget/
87
+ │ ├── service-health-widget/
88
+ │ ├── stats-grid-widget/
89
+ │ ├── status-indicator-widget/
90
+ │ └── table-widget/
91
+ ├── services/
92
+ │ ├── meshboard-state.service.ts # State management
93
+ │ ├── meshboard-data.service.ts # Data fetching
94
+ │ ├── meshboard-persistence.service.ts # Backend persistence
95
+ │ ├── meshboard-variable.service.ts # Variable resolution
96
+ │ ├── widget-factory.service.ts # Widget creation
97
+ │ └── widget-registry.service.ts # Widget registration
98
+ ├── dialogs/ # Configuration dialogs
99
+ ├── models/ # TypeScript interfaces
100
+ └── graphQL/ # GraphQL queries/mutations
101
+ ```
102
+
103
+ ## Widget Types
104
+
105
+ ### KPI Widget
106
+ Displays a single value with optional label, prefix, suffix, and trend indicator.
107
+
108
+ ```typescript
109
+ interface KpiWidgetConfig {
110
+ type: 'kpi';
111
+ valueAttribute: string;
112
+ labelAttribute?: string;
113
+ prefix?: string;
114
+ suffix?: string;
115
+ icon?: string;
116
+ trend?: 'up' | 'down' | 'neutral';
117
+ // For persistent query mode
118
+ queryMode?: 'simpleCount' | 'aggregation' | 'groupedAggregation';
119
+ queryValueField?: string;
120
+ filters?: WidgetFilterConfig[];
121
+ }
122
+ ```
123
+
124
+ ### Gauge Widget
125
+ Displays a numeric value as arc, circular, linear, or radial gauge.
126
+
127
+ ```typescript
128
+ interface GaugeWidgetConfig {
129
+ type: 'gauge';
130
+ gaugeType: 'arc' | 'circular' | 'linear' | 'radial';
131
+ valueAttribute: string;
132
+ min?: number;
133
+ max?: number;
134
+ ranges?: GaugeRange[];
135
+ showLabel?: boolean;
136
+ prefix?: string;
137
+ suffix?: string;
138
+ }
139
+ ```
140
+
141
+ ### Table Widget
142
+ Displays data in a configurable table with sorting and filtering.
143
+
144
+ ```typescript
145
+ interface TableWidgetConfig {
146
+ type: 'table';
147
+ columns: TableColumn[];
148
+ sorting?: TableSortConfig[];
149
+ filters?: WidgetFilterConfig[];
150
+ pageSize?: number;
151
+ sortable?: boolean;
152
+ }
153
+ ```
154
+
155
+ ### Pie Chart Widget
156
+ Displays data as pie or donut chart.
157
+
158
+ ```typescript
159
+ interface PieChartWidgetConfig {
160
+ type: 'pieChart';
161
+ chartType: 'pie' | 'donut';
162
+ categoryField: string;
163
+ valueField: string;
164
+ showLabels?: boolean;
165
+ showLegend?: boolean;
166
+ legendPosition?: 'top' | 'bottom' | 'left' | 'right';
167
+ filters?: WidgetFilterConfig[];
168
+ }
169
+ ```
170
+
171
+ ### Bar Chart Widget
172
+ Displays data as column, bar, or stacked charts.
173
+
174
+ ```typescript
175
+ interface BarChartWidgetConfig {
176
+ type: 'barChart';
177
+ chartType: 'column' | 'bar' | 'stackedColumn' | 'stackedBar' | 'stackedColumn100' | 'stackedBar100';
178
+ categoryField: string;
179
+ series: BarChartSeries[];
180
+ // Dynamic series mode
181
+ seriesGroupField?: string;
182
+ valueField?: string;
183
+ showLegend?: boolean;
184
+ legendPosition?: 'top' | 'bottom' | 'left' | 'right';
185
+ filters?: WidgetFilterConfig[];
186
+ }
187
+ ```
188
+
189
+ ### Stats Grid Widget
190
+ Displays multiple KPIs in a grid layout.
191
+
192
+ ```typescript
193
+ interface StatsGridWidgetConfig {
194
+ type: 'statsGrid';
195
+ stats: StatItem[];
196
+ columns?: number;
197
+ }
198
+ ```
199
+
200
+ ### Service Health Widget
201
+ Displays service health status with pulse animation.
202
+
203
+ ```typescript
204
+ interface ServiceHealthWidgetConfig {
205
+ type: 'serviceHealth';
206
+ navigateOnClick?: boolean;
207
+ detailRoute?: string;
208
+ showPulse?: boolean;
209
+ }
210
+ ```
211
+
212
+ ### Status Indicator Widget
213
+ Displays boolean status (e.g., ENABLED/DISABLED).
214
+
215
+ ```typescript
216
+ interface StatusIndicatorWidgetConfig {
217
+ type: 'statusIndicator';
218
+ trueLabel?: string;
219
+ falseLabel?: string;
220
+ trueColor?: string;
221
+ falseColor?: string;
222
+ }
223
+ ```
224
+
225
+ ## Data Sources
226
+
227
+ ### Runtime Entity Data Source
228
+ Fetches a single entity by CK type or rtId.
229
+
230
+ ```typescript
231
+ interface RuntimeEntityDataSource {
232
+ type: 'runtimeEntity';
233
+ ckTypeId?: string;
234
+ rtId?: string;
235
+ attributePaths?: string[];
236
+ includeAssociations?: boolean;
237
+ }
238
+ ```
239
+
240
+ ### Persistent Query Data Source
241
+ Executes a saved query by its rtId.
242
+
243
+ ```typescript
244
+ interface PersistentQueryDataSource {
245
+ type: 'persistentQuery';
246
+ queryRtId: string;
247
+ queryName?: string;
248
+ }
249
+ ```
250
+
251
+ ### Aggregation Data Source
252
+ Performs aggregation queries (count, sum, avg, min, max).
253
+
254
+ ```typescript
255
+ interface AggregationDataSource {
256
+ type: 'aggregation';
257
+ queries: AggregationQuery[];
258
+ }
259
+
260
+ interface AggregationQuery {
261
+ id: string;
262
+ ckTypeId: string;
263
+ aggregation: 'count' | 'sum' | 'avg' | 'min' | 'max';
264
+ attribute?: string;
265
+ filters?: WidgetFilterConfig[];
266
+ }
267
+ ```
268
+
269
+ ### Construction Kit Query Data Source
270
+ Queries Construction Kit metadata (models, types, attributes).
271
+
272
+ ```typescript
273
+ interface ConstructionKitQueryDataSource {
274
+ type: 'constructionKitQuery';
275
+ queryTarget: 'models' | 'types' | 'attributes' | 'associationRoles' | 'enums' | 'records';
276
+ groupBy?: string;
277
+ valueField?: string;
278
+ categoryField?: string;
279
+ }
280
+ ```
281
+
282
+ ### Service Call Data Source
283
+ Calls services for status/health information.
284
+
285
+ ```typescript
286
+ interface ServiceCallDataSource {
287
+ type: 'serviceCall';
288
+ callType: 'modelAvailable' | 'healthCheck';
289
+ modelName?: string;
290
+ serviceType?: 'identity' | 'asset-repository' | 'bot' | 'communication-controller' | 'mesh-adapter' | 'custom';
291
+ customEndpoint?: string;
292
+ }
293
+ ```
294
+
295
+ ## Variables
296
+
297
+ MeshBoard supports variables that can be used in filter values. Variables use the syntax `${variableName}` or `$variableName`.
298
+
299
+ ### Defining Variables
300
+
301
+ Variables are defined at the MeshBoard level:
302
+
303
+ ```typescript
304
+ interface MeshBoardVariable {
305
+ name: string; // Variable name (without $)
306
+ label?: string; // Display label
307
+ description?: string;
308
+ type: 'string' | 'number' | 'boolean' | 'date' | 'datetime';
309
+ source: 'static' | 'timeFilter';
310
+ value: string;
311
+ defaultValue?: string;
312
+ }
313
+ ```
314
+
315
+ ### Using Variables in Filters
316
+
317
+ ```typescript
318
+ const filter: WidgetFilterConfig = {
319
+ attributePath: 'createdDate',
320
+ operator: 'gte',
321
+ comparisonValue: '${timeRangeFrom}'
322
+ };
323
+ ```
324
+
325
+ ### Time Filter Variables
326
+
327
+ When the time filter is enabled, two variables are automatically available:
328
+ - `${timeRangeFrom}` - Start of selected time range (ISO string)
329
+ - `${timeRangeTo}` - End of selected time range (ISO string)
330
+
331
+ ## Time Filter
332
+
333
+ Enable a global time filter for the MeshBoard:
334
+
335
+ ```typescript
336
+ interface MeshBoardTimeFilterConfig {
337
+ enabled: boolean;
338
+ pickerConfig?: {
339
+ availableTypes?: ('year' | 'quarter' | 'month' | 'relative' | 'custom')[];
340
+ minYear?: number;
341
+ maxYear?: number;
342
+ defaultRelativeValue?: number;
343
+ defaultRelativeUnit?: 'hours' | 'days' | 'weeks' | 'months';
344
+ showTime?: boolean;
345
+ };
346
+ selection?: TimeRangeSelection;
347
+ }
348
+ ```
349
+
350
+ ## Services
351
+
352
+ ### MeshBoardStateService
353
+
354
+ Central state management for MeshBoard.
355
+
356
+ ```typescript
357
+ // Load initial MeshBoard
358
+ await stateService.loadInitialMeshBoard();
359
+
360
+ // Switch to specific MeshBoard
361
+ await stateService.switchToMeshBoard(rtId);
362
+
363
+ // Switch by well-known name
364
+ await stateService.switchToMeshBoardByWellKnownName('cockpit');
365
+
366
+ // Save current MeshBoard
367
+ await stateService.saveMeshBoard();
368
+
369
+ // Access state
370
+ const config = stateService.meshBoardConfig();
371
+ const isLoading = stateService.isLoading();
372
+ const availableBoards = stateService.availableMeshBoards();
373
+ ```
374
+
375
+ ### MeshBoardVariableService
376
+
377
+ Resolves variables in filter values.
378
+
379
+ ```typescript
380
+ // Resolve variables in a string
381
+ const resolved = variableService.resolveVariables('${timeRangeFrom}', variables);
382
+
383
+ // Convert filters to DTO with resolved variables
384
+ const dtoFilters = variableService.convertToFieldFilterDto(filters, variables);
385
+ ```
386
+
387
+ ### WidgetRegistryService
388
+
389
+ Registry for widget types and their configurations.
390
+
391
+ ```typescript
392
+ // Get widget component
393
+ const component = registry.getWidgetComponent('kpi');
394
+
395
+ // Get default size
396
+ const size = registry.getDefaultSize('table');
397
+
398
+ // Get registration
399
+ const registration = registry.getRegistration('barChart');
400
+ ```
401
+
402
+ ## Creating Custom Widgets
403
+
404
+ ### 1. Create Widget Component
405
+
406
+ ```typescript
407
+ @Component({
408
+ selector: 'my-custom-widget',
409
+ standalone: true,
410
+ template: `...`
411
+ })
412
+ export class MyCustomWidgetComponent implements OnInit {
413
+ @Input() config!: MyCustomWidgetConfig;
414
+
415
+ private readonly dataService = inject(MeshBoardDataService);
416
+ private readonly stateService = inject(MeshBoardStateService);
417
+ }
418
+ ```
419
+
420
+ ### 2. Create Config Dialog Component
421
+
422
+ ```typescript
423
+ @Component({
424
+ selector: 'my-custom-config-dialog',
425
+ standalone: true,
426
+ template: `...`
427
+ })
428
+ export class MyCustomConfigDialogComponent {
429
+ @Input() initialTitle = '';
430
+ @Input() initialDataSource?: DataSource;
431
+
432
+ @Output() save = new EventEmitter<MyCustomConfigResult>();
433
+ @Output() cancelled = new EventEmitter<void>();
434
+ }
435
+ ```
436
+
437
+ ### 3. Register Widget
438
+
439
+ In your app initialization:
440
+
441
+ ```typescript
442
+ const registry = inject(WidgetRegistryService);
443
+
444
+ registry.registerWidget({
445
+ type: 'myCustom',
446
+ component: MyCustomWidgetComponent,
447
+ configDialogComponent: MyCustomConfigDialogComponent,
448
+ defaultSize: { colSpan: 2, rowSpan: 2 },
449
+ getInitialConfig: (widget) => ({
450
+ initialTitle: widget.title,
451
+ initialDataSource: widget.dataSource
452
+ }),
453
+ applyConfigResult: (widget, result) => ({
454
+ ...widget,
455
+ title: result.title,
456
+ dataSource: result.dataSource,
457
+ customOption: result.customOption
458
+ })
459
+ });
460
+ ```
461
+
462
+ ## Persistence
463
+
464
+ MeshBoards are persisted using the `System.UI/Dashboard` and `System.UI/DashboardWidget` Construction Kit types.
465
+
466
+ ### Required CK Model
467
+
468
+ The MeshBoard feature requires the `System.UI` CK model version >= 1.0.1.
469
+
470
+ ### Backend Structure
471
+
472
+ - **Dashboard**: Contains grid configuration (columns, rowHeight, gap) and metadata
473
+ - **DashboardWidget**: Contains widget type, position, and serialized config
474
+
475
+ ## Build
476
+
477
+ ```bash
478
+ npm run build:octo-meshboard
479
+ ```
480
+
481
+ ## Dependencies
482
+
483
+ - `@angular/core` >= 17
484
+ - `@progress/kendo-angular-layout` (TileLayout)
485
+ - `@progress/kendo-angular-charts` (Charts)
486
+ - `@progress/kendo-angular-gauges` (Gauges)
487
+ - `@progress/kendo-angular-grid` (Table)
488
+ - `@meshmakers/octo-services` (GraphQL services)
489
+ - `@meshmakers/octo-ui` (UI components)
490
+ - `@meshmakers/shared-ui` (Shared components)