@meshmakers/octo-meshboard 3.4.1120 → 3.4.1140
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.
|
@@ -1110,9 +1110,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
1110
1110
|
}]
|
|
1111
1111
|
}], ctorParameters: () => [{ type: i1.Apollo }] });
|
|
1112
1112
|
|
|
1113
|
-
// Re-export all GraphQL types from @meshmakers/octo-services
|
|
1114
|
-
// This file is NOT generated - it imports shared types from the library
|
|
1115
|
-
|
|
1116
1113
|
/**
|
|
1117
1114
|
* Central registry for widget types.
|
|
1118
1115
|
* Manages widget components, config dialogs, and their interactions.
|
|
@@ -2538,17 +2535,26 @@ class MeshBoardStateService {
|
|
|
2538
2535
|
/**
|
|
2539
2536
|
* The IANA time zone to forward to the resolution-aware series query so calendar
|
|
2540
2537
|
* rollups are selected in the board's zone (AB#4190). Maps the board mode:
|
|
2541
|
-
* `'utc'` → `'UTC'`, an IANA id → itself, and `'local'` →
|
|
2542
|
-
*
|
|
2543
|
-
*
|
|
2544
|
-
*
|
|
2538
|
+
* `'utc'` → `'UTC'`, an IANA id → itself, and `'local'` → the browser's own IANA
|
|
2539
|
+
* zone. The result is therefore always the same basis `resolveCurrentTimeRange()`
|
|
2540
|
+
* used to compute the `{from, to}` window — in `'local'` mode that window is built
|
|
2541
|
+
* from browser-local wall clocks, so naming that zone is what makes the two agree.
|
|
2542
|
+
*
|
|
2543
|
+
* `'local'` used to send nothing, which left the resolver on UTC. Under the default
|
|
2544
|
+
* per-query comparison policy a calendar rung stored in another zone then has no
|
|
2545
|
+
* determinate grain and drops out of the ladder, so the board silently fell back to
|
|
2546
|
+
* a finer rung, reported signal `Ok`, and drew a window that was not the one asked
|
|
2547
|
+
* for (AB#5157 review). `undefined` now only means the browser named no zone at all.
|
|
2545
2548
|
*/
|
|
2546
2549
|
resolveStreamDataTimeZone() {
|
|
2547
2550
|
const mode = this.timeZoneMode();
|
|
2551
|
+
if (mode === 'utc') {
|
|
2552
|
+
return 'UTC';
|
|
2553
|
+
}
|
|
2548
2554
|
if (mode === 'local') {
|
|
2549
|
-
return undefined;
|
|
2555
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;
|
|
2550
2556
|
}
|
|
2551
|
-
return mode
|
|
2557
|
+
return mode;
|
|
2552
2558
|
}
|
|
2553
2559
|
/**
|
|
2554
2560
|
* Stores the source rtIds resolved from an entity selector's current
|
|
@@ -2948,6 +2954,7 @@ const ResolveSeriesQueryDocumentDto = gql `
|
|
|
2948
2954
|
signal
|
|
2949
2955
|
actualPoints
|
|
2950
2956
|
diagnostic
|
|
2957
|
+
finerRungAvailableFrom
|
|
2951
2958
|
}
|
|
2952
2959
|
}
|
|
2953
2960
|
}
|
|
@@ -3161,7 +3168,8 @@ class QueryExecutorService {
|
|
|
3161
3168
|
reducingFunction: decision.reducingFunction,
|
|
3162
3169
|
signal: decision.signal,
|
|
3163
3170
|
actualPoints: decision.actualPoints ?? null,
|
|
3164
|
-
diagnostic: decision.diagnostic ?? null
|
|
3171
|
+
diagnostic: decision.diagnostic ?? null,
|
|
3172
|
+
finerRungAvailableFrom: decision.finerRungAvailableFrom ?? null
|
|
3165
3173
|
};
|
|
3166
3174
|
}
|
|
3167
3175
|
/**
|
|
@@ -9366,7 +9374,7 @@ class TableWidgetComponent {
|
|
|
9366
9374
|
</div>
|
|
9367
9375
|
}
|
|
9368
9376
|
</div>
|
|
9369
|
-
`, isInline: true, styles: [".table-widget{height:100%;width:100%;display:flex;flex-direction:column}.no-config-overlay{display:flex;align-items:center;justify-content:center;height:100%;color:var(--kendo-color-subtle, #6c757d);font-style:italic}:host ::ng-deep mm-list-view{height:100%}:host ::ng-deep .k-grid{height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ListViewComponent, selector: "mm-list-view", inputs: ["pageSize", "skip", "autoPageSize", "rowIsClickable", "showRowCheckBoxes", "showRowSelectAllCheckBox", "contextMenuType", "leftToolbarActions", "rightToolbarActions", "actionCommandItems", "contextMenuCommandItems", "excelExportFileName", "pdfExportFileName", "pageable", "sortable", "rowFilterEnabled", "searchTextBoxEnabled", "persistListState", "listStateKey", "resizable", "actionsColumnWidth", "hideCheckboxesBelow", "cardModeBelow", "rowClass", "messages", "selectable", "columns"], outputs: ["rowClicked", "resetFilters"] }, { kind: "directive", type: TableWidgetDataSourceDirective, selector: "[mmTableWidgetDataSource]", inputs: ["config"], outputs: ["queryColumnsLoaded"], exportAs: ["mmTableWidgetDataSource"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
9377
|
+
`, isInline: true, styles: [".table-widget{height:100%;width:100%;display:flex;flex-direction:column}.no-config-overlay{display:flex;align-items:center;justify-content:center;height:100%;color:var(--kendo-color-subtle, #6c757d);font-style:italic}:host ::ng-deep mm-list-view{height:100%}:host ::ng-deep .k-grid{height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ListViewComponent, selector: "mm-list-view", inputs: ["pageSize", "skip", "autoPageSize", "rowIsClickable", "showRowCheckBoxes", "showRowSelectAllCheckBox", "contextMenuType", "leftToolbarActions", "rightToolbarActions", "actionCommandItems", "contextMenuCommandItems", "excelExportFileName", "pdfExportFileName", "pageable", "sortable", "rowFilterEnabled", "searchTextBoxEnabled", "persistListState", "listStateKey", "resizable", "actionsColumnWidth", "hideCheckboxesBelow", "cardModeBelow", "collapseCommandsBelow", "rowClass", "messages", "selectable", "columns"], outputs: ["rowClicked", "resetFilters"] }, { kind: "directive", type: TableWidgetDataSourceDirective, selector: "[mmTableWidgetDataSource]", inputs: ["config"], outputs: ["queryColumnsLoaded"], exportAs: ["mmTableWidgetDataSource"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
9370
9378
|
}
|
|
9371
9379
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TableWidgetComponent, decorators: [{
|
|
9372
9380
|
type: Component,
|
|
@@ -14629,6 +14637,9 @@ class LineChartWidgetComponent {
|
|
|
14629
14637
|
* Resolution-aware hint (AB#4290): a short badge describing the archive-selection outcome —
|
|
14630
14638
|
* `null` for a clean reduction (signal OK), a warning otherwise (fewer points delivered, or no
|
|
14631
14639
|
* compatible rollup so the raw archive was returned unreduced). Mirrors the resolver's signal.
|
|
14640
|
+
* `CoverageLimited` (AB#5157) is a distinct badge: a finer rung was skipped for holding no data
|
|
14641
|
+
* over the window, which is a history gap rather than a density problem — so it is always shown,
|
|
14642
|
+
* bypassing the {@link RESOLUTION_LIMIT_WARN_PX} suppression that mutes a merely coarse line.
|
|
14632
14643
|
*/
|
|
14633
14644
|
resolutionHint = computed(() => {
|
|
14634
14645
|
const s = this._resolutionSignal();
|
|
@@ -14636,6 +14647,20 @@ class LineChartWidgetComponent {
|
|
|
14636
14647
|
return null;
|
|
14637
14648
|
const diag = s.diagnostic ?? '';
|
|
14638
14649
|
switch (s.signal) {
|
|
14650
|
+
case SeriesResolutionSignalDto.CoverageLimitedDto: {
|
|
14651
|
+
// Coverage, not density (AB#5157): the finer rung was skipped because it holds NO data
|
|
14652
|
+
// over the window, so the pixel-density suppression must not apply — a dense-looking
|
|
14653
|
+
// coarse line is still the wrong answer to "where is my history?". Always flagged.
|
|
14654
|
+
const availableFrom = formatInstant(s.finerRungAvailableFrom, this.stateService.timeZoneMode(), {
|
|
14655
|
+
day: '2-digit', month: '2-digit', year: 'numeric'
|
|
14656
|
+
});
|
|
14657
|
+
return {
|
|
14658
|
+
text: '⚠ no history',
|
|
14659
|
+
title: availableFrom
|
|
14660
|
+
? `History at this resolution is available from ${availableFrom}`
|
|
14661
|
+
: diag || 'A finer resolution exists but holds no data for this time range.'
|
|
14662
|
+
};
|
|
14663
|
+
}
|
|
14639
14664
|
case SeriesResolutionSignalDto.ResolutionLimitedDto: {
|
|
14640
14665
|
const delivered = s.actualPoints ?? s.points;
|
|
14641
14666
|
const requested = this._resolutionTarget();
|
|
@@ -14670,7 +14695,20 @@ class LineChartWidgetComponent {
|
|
|
14670
14695
|
const delivered = s.actualPoints ?? s.points;
|
|
14671
14696
|
const requested = this._resolutionTarget();
|
|
14672
14697
|
const ofReq = requested ? ` (the chart could show ~${requested})` : '';
|
|
14698
|
+
const diag = s.diagnostic ?? '';
|
|
14673
14699
|
switch (s.signal) {
|
|
14700
|
+
case SeriesResolutionSignalDto.CoverageLimitedDto: {
|
|
14701
|
+
const availableFrom = formatInstant(s.finerRungAvailableFrom, this.stateService.timeZoneMode(), {
|
|
14702
|
+
day: '2-digit', month: '2-digit', year: 'numeric'
|
|
14703
|
+
});
|
|
14704
|
+
const from = availableFrom
|
|
14705
|
+
? ` That resolution only has history from ${availableFrom} onwards.`
|
|
14706
|
+
: '';
|
|
14707
|
+
return `A finer resolution exists for this series, but it holds no data for the selected time range, `
|
|
14708
|
+
+ `so the chart fell back to a coarser one (${delivered} point(s)${ofReq}).${from} `
|
|
14709
|
+
+ `The values are correct — narrow the range to a covered period to see finer detail.`
|
|
14710
|
+
+ (diag ? ` ${diag}` : '');
|
|
14711
|
+
}
|
|
14674
14712
|
case SeriesResolutionSignalDto.ResolutionLimitedDto:
|
|
14675
14713
|
return `This chart auto-selects the coarsest stored resolution that still fits the view. `
|
|
14676
14714
|
+ `For this time range the finest matching rollup only provides ${delivered} point(s)${ofReq}, `
|
|
@@ -14928,28 +14966,23 @@ class LineChartWidgetComponent {
|
|
|
14928
14966
|
if (!resolution) {
|
|
14929
14967
|
return { rows: [], signal: null, requestedPoints: targetPoints };
|
|
14930
14968
|
}
|
|
14931
|
-
//
|
|
14932
|
-
//
|
|
14933
|
-
//
|
|
14934
|
-
//
|
|
14935
|
-
//
|
|
14936
|
-
//
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14940
|
-
const bucket = resolution.effectiveBucketMs;
|
|
14941
|
-
const alignedFrom = Math.floor(from.getTime() / bucket) * bucket;
|
|
14942
|
-
qFrom = new Date(alignedFrom);
|
|
14943
|
-
qTo = new Date(alignedFrom + Math.max(1, resolution.points) * bucket);
|
|
14944
|
-
}
|
|
14969
|
+
// The requested window is passed through unchanged. The widget used to snap it to the
|
|
14970
|
+
// resolver's effective-bucket grid, because the downsampling engine binned from whatever start
|
|
14971
|
+
// it was handed and an unaligned window (a relative "last N days" filter ending at the current
|
|
14972
|
+
// wall clock) made every bin miss the stored points. That alignment now happens where the grain
|
|
14973
|
+
// is actually known — the engine snaps its own axis origin — and doing it here was wrong twice
|
|
14974
|
+
// over for a calendar rung (AB#5157 review): `effectiveBucketMs` is an average, so anchoring it
|
|
14975
|
+
// to the epoch landed the axis off the calendar boundaries and outside the requested window,
|
|
14976
|
+
// and sizing the end as points × bucket cut the running period off. No client can compute this
|
|
14977
|
+
// axis: neither the grain nor the rung's alignment is part of the query contract.
|
|
14945
14978
|
// Group-aggregation mode (AB#4714): one downsampling call PER GROUP, each with the whole
|
|
14946
14979
|
// group's rtIds, so the transient downsampling reduces over every member (per
|
|
14947
14980
|
// requiredAggregation) into one aggregate line. Default mode: one call per source rtId, keeping
|
|
14948
14981
|
// each source its own series. See loadGroupAggregatedRows / loadPerRtIdRows.
|
|
14949
14982
|
const downsample = (rtIds, label) => this.queryExecutor.downsampleByArchive({
|
|
14950
14983
|
archiveRtId: resolution.archiveRtId,
|
|
14951
|
-
from
|
|
14952
|
-
to
|
|
14984
|
+
from,
|
|
14985
|
+
to,
|
|
14953
14986
|
limit: Math.max(1, resolution.points),
|
|
14954
14987
|
sourcePath,
|
|
14955
14988
|
aggregation: resolution.reducingFunction,
|
|
@@ -15734,7 +15767,7 @@ class LineChartConfigDialogComponent {
|
|
|
15734
15767
|
[(ngModel)]="selectedPersistentQuery"
|
|
15735
15768
|
(querySelected)="onQuerySelected($event)"
|
|
15736
15769
|
placeholder="Select a Query..."
|
|
15737
|
-
hint="Select a query
|
|
15770
|
+
hint="Select a stream-data query on the archive you want to chart — a simple one is enough. The widget picks the rollup rung and downsamples itself; the fields below group the rows into series.">
|
|
15738
15771
|
</mm-query-selector>
|
|
15739
15772
|
</div>
|
|
15740
15773
|
|
|
@@ -15995,7 +16028,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
15995
16028
|
[(ngModel)]="selectedPersistentQuery"
|
|
15996
16029
|
(querySelected)="onQuerySelected($event)"
|
|
15997
16030
|
placeholder="Select a Query..."
|
|
15998
|
-
hint="Select a query
|
|
16031
|
+
hint="Select a stream-data query on the archive you want to chart — a simple one is enough. The widget picks the rollup rung and downsamples itself; the fields below group the rows into series.">
|
|
15999
16032
|
</mm-query-selector>
|
|
16000
16033
|
</div>
|
|
16001
16034
|
|