@c8y/ngx-components 1024.1.8 → 1024.2.4

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 (49) hide show
  1. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +64 -25
  2. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
  3. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs +363 -38
  4. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs.map +1 -1
  5. package/fesm2022/c8y-ngx-components-echart-models.mjs.map +1 -1
  6. package/fesm2022/c8y-ngx-components-echart.mjs +796 -123
  7. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  8. package/fesm2022/c8y-ngx-components-global-context.mjs +391 -54
  9. package/fesm2022/c8y-ngx-components-global-context.mjs.map +1 -1
  10. package/fesm2022/c8y-ngx-components-time-context.mjs +146 -20
  11. package/fesm2022/c8y-ngx-components-time-context.mjs.map +1 -1
  12. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +198 -24
  13. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
  14. package/fesm2022/c8y-ngx-components.mjs +100 -32
  15. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  16. package/locales/de.po +80 -8
  17. package/locales/es.po +80 -8
  18. package/locales/fr.po +80 -8
  19. package/locales/ja_JP.po +80 -8
  20. package/locales/ko.po +80 -8
  21. package/locales/locales.pot +79 -7
  22. package/locales/nl.po +80 -8
  23. package/locales/pl.po +80 -8
  24. package/locales/pt_BR.po +80 -8
  25. package/locales/zh_CN.po +80 -8
  26. package/locales/zh_TW.po +80 -8
  27. package/package.json +1 -1
  28. package/types/c8y-ngx-components-datapoint-explorer-view.d.ts +4 -1
  29. package/types/c8y-ngx-components-datapoint-explorer-view.d.ts.map +1 -1
  30. package/types/c8y-ngx-components-datapoint-selector.d.ts +93 -5
  31. package/types/c8y-ngx-components-datapoint-selector.d.ts.map +1 -1
  32. package/types/c8y-ngx-components-echart-models.d.ts +25 -3
  33. package/types/c8y-ngx-components-echart-models.d.ts.map +1 -1
  34. package/types/c8y-ngx-components-echart.d.ts +65 -5
  35. package/types/c8y-ngx-components-echart.d.ts.map +1 -1
  36. package/types/c8y-ngx-components-global-context.d.ts +187 -7
  37. package/types/c8y-ngx-components-global-context.d.ts.map +1 -1
  38. package/types/c8y-ngx-components-time-context.d.ts +50 -8
  39. package/types/c8y-ngx-components-time-context.d.ts.map +1 -1
  40. package/types/c8y-ngx-components-widgets-implementations-alarms.d.ts +1 -0
  41. package/types/c8y-ngx-components-widgets-implementations-alarms.d.ts.map +1 -1
  42. package/types/c8y-ngx-components-widgets-implementations-datapoints-graph.d.ts +25 -0
  43. package/types/c8y-ngx-components-widgets-implementations-datapoints-graph.d.ts.map +1 -1
  44. package/types/c8y-ngx-components-widgets-implementations-datapoints-list.d.ts +1 -0
  45. package/types/c8y-ngx-components-widgets-implementations-datapoints-list.d.ts.map +1 -1
  46. package/types/c8y-ngx-components-widgets-implementations-scada.d.ts +2 -0
  47. package/types/c8y-ngx-components-widgets-implementations-scada.d.ts.map +1 -1
  48. package/types/c8y-ngx-components.d.ts +50 -11
  49. package/types/c8y-ngx-components.d.ts.map +1 -1
@@ -1,12 +1,12 @@
1
1
  import { gettext } from '@c8y/ngx-components/gettext';
2
- import { aggregationType } from '@c8y/client';
2
+ import { aggregationType, MeasurementService } from '@c8y/client';
3
3
  import * as i0 from '@angular/core';
4
- import { computed, signal, Injectable, inject, input, forwardRef, ChangeDetectionStrategy, Component, DestroyRef, output, Input, ChangeDetectorRef, ViewChild, EventEmitter, viewChild, effect, HostListener, Output, InjectionToken, TemplateRef, untracked, ContentChild, NgModule } from '@angular/core';
4
+ import { computed, signal, Injectable, inject, input, output, forwardRef, ChangeDetectionStrategy, Component, DestroyRef, Input, ChangeDetectorRef, ViewChild, EventEmitter, viewChild, effect, HostListener, Output, InjectionToken, TemplateRef, untracked, ContentChild, NgModule } from '@angular/core';
5
5
  import * as i4 from '@c8y/ngx-components';
6
- import { ViewContext, I18nModule, IconDirective, FormGroupComponent, MessagesComponent, MessageDirective, DateTimePickerModule, C8yTranslatePipe, DatePipe, TabsOutletComponent, FormsModule as FormsModule$1, CountdownIntervalModule, CountdownIntervalComponent, AlertService, ContextRouteService, DashboardChildComponent, hookActionBar } from '@c8y/ngx-components';
7
- import { BehaviorSubject, map, distinctUntilChanged, shareReplay, fromEvent, filter, debounceTime, startWith, tap as tap$1, firstValueFrom, combineLatest, Subject, take, skip, throttleTime, merge as merge$1, EMPTY } from 'rxjs';
6
+ import { ViewContext, I18nModule, IconDirective, FormGroupComponent, MessagesComponent, MessageDirective, DateTimePickerModule, C8yTranslatePipe, DatePipe, TabsOutletComponent, FormsModule as FormsModule$1, AUTO_POINTS_TOOLTIP, AUTO_POINTS_TOOLTIP_KEPT, CountdownIntervalModule, CountdownIntervalComponent, AlertService, ContextRouteService, DashboardChildComponent, hookActionBar } from '@c8y/ngx-components';
7
+ import { BehaviorSubject, map, distinctUntilChanged, shareReplay, fromEvent, filter, debounce, timer, debounceTime, startWith, tap as tap$1, firstValueFrom, combineLatest, Subject, take, skip, throttleTime, merge as merge$1, EMPTY } from 'rxjs';
8
8
  import * as i1 from '@angular/forms';
9
- import { FormBuilder, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, FormControl } from '@angular/forms';
9
+ import { FormBuilder, FormsModule, NG_VALUE_ACCESSOR, Validators, ReactiveFormsModule, FormControl } from '@angular/forms';
10
10
  import { pick, omit, isObject, isEqual, transform, some, cloneDeep, merge, isEmpty } from 'lodash-es';
11
11
  import { ActivatedRoute, Router, NavigationStart, NavigationEnd, ActivationEnd } from '@angular/router';
12
12
  import * as i1$1 from '@angular/common';
@@ -17,7 +17,7 @@ import * as i2 from 'ngx-bootstrap/tooltip';
17
17
  import { TooltipModule } from 'ngx-bootstrap/tooltip';
18
18
  import * as i1$2 from 'ngx-bootstrap/collapse';
19
19
  import { CollapseModule } from 'ngx-bootstrap/collapse';
20
- import * as i2$2 from 'ngx-bootstrap/popover';
20
+ import * as i3 from 'ngx-bootstrap/popover';
21
21
  import { PopoverModule } from 'ngx-bootstrap/popover';
22
22
  import * as i2$1 from 'ngx-bootstrap/dropdown';
23
23
  import { BsDropdownModule, BsDropdownDirective } from 'ngx-bootstrap/dropdown';
@@ -189,8 +189,17 @@ const AGGREGATION_ICON_TYPE = {
189
189
  UNDEFINED: 'line-chart',
190
190
  MINUTELY: 'hourglass',
191
191
  HOURLY: 'clock-o',
192
- DAILY: 'calendar-o'
192
+ DAILY: 'calendar-o',
193
+ AUTO: 'automation'
193
194
  };
195
+ /** Short label for the automatic aggregation mode — used as the picker option title. */
196
+ const AUTO_AGGREGATION_TEXT = gettext('Auto`automatic aggregation mode`');
197
+ /**
198
+ * Long label for the automatic aggregation mode — used where the current value is shown
199
+ * (picker tooltip, action-bar display) so it reads consistently alongside "Minutely
200
+ * aggregation", "Hourly aggregation", etc.
201
+ */
202
+ const AUTO_AGGREGATION_TEXT_LONG = gettext('Automatic aggregation');
194
203
  const AGGREGATION_ICONS = {
195
204
  undefined: AGGREGATION_ICON_TYPE.UNDEFINED,
196
205
  MINUTELY: AGGREGATION_ICON_TYPE.MINUTELY,
@@ -198,7 +207,7 @@ const AGGREGATION_ICONS = {
198
207
  DAILY: AGGREGATION_ICON_TYPE.DAILY
199
208
  };
200
209
  const AGGREGATION_TEXTS = {
201
- disabled: gettext('No aggregation with realtime enabled'),
210
+ disabled: gettext('Unavailable while real-time or auto-refresh is on.'),
202
211
  undefined: gettext('No aggregation'),
203
212
  null: gettext('No aggregation'),
204
213
  MINUTELY: gettext('Minutely aggregation'),
@@ -224,6 +233,12 @@ const AGGREGATION_LABELS = {
224
233
  [aggregationType.DAILY]: AGGREGATIONS[3].title
225
234
  };
226
235
 
236
+ /**
237
+ * Shared popover text explaining the aggregation control. Used by the history-mode
238
+ * configuration controls and the (legacy) time-context component so both stay in sync.
239
+ * "Auto" is intentionally not re-explained here — it has its own dedicated tooltip.
240
+ */
241
+ const AGGREGATION_POPOVER_TEXT = gettext("Groups measurements into larger time intervals to improve readability and performance. 'None' shows raw data; other options group measurements into minute, hour, or day intervals.");
227
242
  /**
228
243
  * Time duration constants (ms)
229
244
  */
@@ -241,6 +256,8 @@ const TIME_DURATION = {
241
256
  const TIMING = {
242
257
  /** Debounce time for form value changes (ms) */
243
258
  FORM_DEBOUNCE: 100,
259
+ /** Debounce time while the user is typing into a text/number field (ms) */
260
+ TYPING_DEBOUNCE: 500,
244
261
  /** Throttle time for context changes (ms) */
245
262
  CONTEXT_THROTTLE: 200,
246
263
  /** Tooltip delay time (ms) */
@@ -255,6 +272,20 @@ const UI_PRIORITIES = {
255
272
  /** High priority for configuration controls */
256
273
  CONFIGURATION_PRIORITY: 1000
257
274
  };
275
+ /**
276
+ * Bounds for the auto-aggregation "Datapoints target" control (how many buckets the auto
277
+ * interval aims for). Shared by the slider, the number input, and the clamping/validation logic.
278
+ */
279
+ const AUTO_AGGREGATION_DATAPOINTS = {
280
+ /** Minimum number of target datapoints. */
281
+ MIN: 2,
282
+ /** Maximum number of target datapoints. */
283
+ MAX: 2000,
284
+ /** Increment for slider and number stepper. Must divide MAX - MIN so the slider reaches MAX. */
285
+ STEP: 1,
286
+ /** Default target when auto mode is enabled. */
287
+ DEFAULT: 300
288
+ };
258
289
 
259
290
  /**
260
291
  * Central utility for all DateTimeContext operations.
@@ -2722,6 +2753,52 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
2722
2753
  }]
2723
2754
  }] });
2724
2755
 
2756
+ /**
2757
+ * Detects whether the current tenant has been migrated to the time series measurement store.
2758
+ *
2759
+ * The automatic ("Auto") aggregation mode relies on `aggregationInterval` support, which is
2760
+ * only available on time-series-migrated tenants, so UI controls offering it must be hidden
2761
+ * on non-migrated tenants.
2762
+ *
2763
+ * @deprecated The detection itself is a workaround: the measurement detail endpoint responds
2764
+ * with 405 on migrated tenants because it is disabled there. To be replaced when the platform
2765
+ * exposes a proper way to identify time series migration (same approach as
2766
+ * `WidgetDatapointsSelectorComponent.detectTimeSeriesMigration`).
2767
+ */
2768
+ class TimeSeriesMigrationService {
2769
+ constructor() {
2770
+ this.measurementService = inject(MeasurementService);
2771
+ this.migrationCheck = null;
2772
+ }
2773
+ /**
2774
+ * Resolves to `true` when the tenant is migrated to time series.
2775
+ * The result is cached for the lifetime of the application, as migration
2776
+ * state cannot change within a session.
2777
+ */
2778
+ isTimeSeriesMigrated() {
2779
+ if (!this.migrationCheck) {
2780
+ this.migrationCheck = this.detectMigration();
2781
+ }
2782
+ return this.migrationCheck;
2783
+ }
2784
+ async detectMigration() {
2785
+ try {
2786
+ // Any id works: on migrated tenants the endpoint itself is disabled and returns 405.
2787
+ await this.measurementService.detail(1);
2788
+ return false;
2789
+ }
2790
+ catch (err) {
2791
+ return err?.res?.status === 405;
2792
+ }
2793
+ }
2794
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimeSeriesMigrationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2795
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimeSeriesMigrationService, providedIn: 'root' }); }
2796
+ }
2797
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimeSeriesMigrationService, decorators: [{
2798
+ type: Injectable,
2799
+ args: [{ providedIn: 'root' }]
2800
+ }] });
2801
+
2725
2802
  class GlobalContextUtilsService {
2726
2803
  /**
2727
2804
  * Compares two objects and returns an object containing only the fields that changed.
@@ -2825,6 +2902,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
2825
2902
  }]
2826
2903
  }] });
2827
2904
 
2905
+ const AUTO_AGGREGATION_ID = 'AUTO';
2906
+ const AUTO_ITEM = { id: AUTO_AGGREGATION_ID, title: AUTO_AGGREGATION_TEXT };
2828
2907
  class AggregationPickerComponent {
2829
2908
  constructor() {
2830
2909
  /**
@@ -2845,10 +2924,31 @@ class AggregationPickerComponent {
2845
2924
  * Default is dropdown.
2846
2925
  */
2847
2926
  this.layout = input('dropdown', ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
2927
+ /**
2928
+ * When true, appends an "Auto" option to the radio group that signals automatic
2929
+ * aggregation selection. Use together with `autoModeActive` and `(autoModeChange)`.
2930
+ * Only meaningful in radio layout.
2931
+ */
2932
+ this.showAutoMode = input(false, ...(ngDevMode ? [{ debugName: "showAutoMode" }] : /* istanbul ignore next */ []));
2933
+ /**
2934
+ * Controls whether the "Auto" radio option appears checked.
2935
+ * Bind to your form's auto-mode boolean so the picker reflects external state.
2936
+ */
2937
+ this.autoModeActive = input(false, ...(ngDevMode ? [{ debugName: "autoModeActive" }] : /* istanbul ignore next */ []));
2938
+ /**
2939
+ * When true, the "Auto" option is rendered but disabled (greyed out). Use for widgets that show
2940
+ * the option for discoverability but do not support auto mode (only the Data graph does).
2941
+ */
2942
+ this.autoModeDisabled = input(false, ...(ngDevMode ? [{ debugName: "autoModeDisabled" }] : /* istanbul ignore next */ []));
2943
+ /** Emits `true` when the user selects "Auto", `false` when switching away from it. */
2944
+ this.autoModeChange = output();
2848
2945
  this._disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : /* istanbul ignore next */ []));
2849
2946
  this.disabled = computed(() => this._disabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
2850
2947
  this.AGGREGATIONS = AGGREGATIONS;
2948
+ this.AUTO_ITEM_ID = AUTO_AGGREGATION_ID;
2949
+ this.AVAILABLE_AGGREGATIONS = computed(() => this.showAutoMode() ? [...AGGREGATIONS, AUTO_ITEM] : AGGREGATIONS, ...(ngDevMode ? [{ debugName: "AVAILABLE_AGGREGATIONS" }] : /* istanbul ignore next */ []));
2851
2950
  this.AGGREGATION_ICONS = AGGREGATION_ICONS;
2951
+ this.AUTO_ICON = AGGREGATION_ICON_TYPE.AUTO;
2852
2952
  this.AGGREGATION_TEXTS = AGGREGATION_TEXTS;
2853
2953
  this._value = signal(null, ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
2854
2954
  this.value = computed(() => this._value(), ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
@@ -2856,13 +2956,20 @@ class AggregationPickerComponent {
2856
2956
  this.touched = computed(() => this._touched(), ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
2857
2957
  // Computed helpers for cleaner templates
2858
2958
  this.currentText = computed(() => {
2959
+ if (this.autoModeActive()) {
2960
+ return AUTO_AGGREGATION_TEXT_LONG;
2961
+ }
2859
2962
  const value = this._value();
2860
2963
  return value ? this.AGGREGATION_TEXTS[value] : this.AGGREGATION_TEXTS.undefined;
2861
2964
  }, ...(ngDevMode ? [{ debugName: "currentText" }] : /* istanbul ignore next */ []));
2862
2965
  this.currentIcon = computed(() => {
2966
+ if (this.autoModeActive()) {
2967
+ return AGGREGATION_ICON_TYPE.AUTO;
2968
+ }
2863
2969
  const value = this._value();
2864
2970
  return value ? this.AGGREGATION_ICONS[value] : this.AGGREGATION_ICONS.undefined;
2865
2971
  }, ...(ngDevMode ? [{ debugName: "currentIcon" }] : /* istanbul ignore next */ []));
2972
+ this.AUTO_MODE_TOOLTIP = gettext('Auto picks an aggregation interval from the time range and the aggregation points per chart you set. Available only for the Data graph widget.');
2866
2973
  // eslint-disable-next-line @typescript-eslint/no-empty-function
2867
2974
  this.onChange = _ => { };
2868
2975
  // eslint-disable-next-line @typescript-eslint/no-empty-function
@@ -2893,13 +3000,33 @@ class AggregationPickerComponent {
2893
3000
  }
2894
3001
  }
2895
3002
  selectAggregation(aggregation) {
2896
- // Early return if value hasn't changed (no-op)
2897
- if (aggregation === this._value()) {
3003
+ const isAuto = aggregation === AUTO_AGGREGATION_ID;
3004
+ // Early return: Auto is disabled for this widget
3005
+ if (isAuto && this.autoModeDisabled()) {
3006
+ return;
3007
+ }
3008
+ // Early return: clicking Auto when already in auto mode
3009
+ if (isAuto && this.autoModeActive()) {
3010
+ return;
3011
+ }
3012
+ // Early return: clicking the same non-auto aggregation when not in auto mode
3013
+ if (!isAuto && !this.autoModeActive() && aggregation === this._value()) {
2898
3014
  return;
2899
3015
  }
2900
3016
  this.markAsTouched();
2901
- this._value.set(aggregation);
2902
- this.onChange(aggregation);
3017
+ const wasAuto = this.autoModeActive();
3018
+ if (isAuto) {
3019
+ this._value.set(null);
3020
+ this.onChange(null);
3021
+ this.autoModeChange.emit(true);
3022
+ }
3023
+ else {
3024
+ this._value.set(aggregation);
3025
+ this.onChange(aggregation);
3026
+ if (wasAuto) {
3027
+ this.autoModeChange.emit(false);
3028
+ }
3029
+ }
2903
3030
  }
2904
3031
  resetValue() {
2905
3032
  if (this._value() !== null) {
@@ -2908,13 +3035,13 @@ class AggregationPickerComponent {
2908
3035
  }
2909
3036
  }
2910
3037
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AggregationPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2911
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AggregationPickerComponent, isStandalone: true, selector: "c8y-aggregation-picker", inputs: { disabledAggregations: { classPropertyName: "disabledAggregations", publicName: "disabledAggregations", isSignal: true, isRequired: false, transformFunction: null }, resetToDefault: { classPropertyName: "resetToDefault", publicName: "resetToDefault", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
3038
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AggregationPickerComponent, isStandalone: true, selector: "c8y-aggregation-picker", inputs: { disabledAggregations: { classPropertyName: "disabledAggregations", publicName: "disabledAggregations", isSignal: true, isRequired: false, transformFunction: null }, resetToDefault: { classPropertyName: "resetToDefault", publicName: "resetToDefault", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, showAutoMode: { classPropertyName: "showAutoMode", publicName: "showAutoMode", isSignal: true, isRequired: false, transformFunction: null }, autoModeActive: { classPropertyName: "autoModeActive", publicName: "autoModeActive", isSignal: true, isRequired: false, transformFunction: null }, autoModeDisabled: { classPropertyName: "autoModeDisabled", publicName: "autoModeDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { autoModeChange: "autoModeChange" }, providers: [
2912
3039
  {
2913
3040
  provide: NG_VALUE_ACCESSOR,
2914
3041
  useExisting: forwardRef(() => AggregationPickerComponent),
2915
3042
  multi: true
2916
3043
  }
2917
- ], ngImport: i0, template: "@if (layout() === 'dropdown') {\n <div\n class=\"dropdown\"\n style=\"border: 0; margin-left: -1px\"\n container=\"body\"\n #dropdown=\"bs-dropdown\"\n dropdown\n [attr.data-cy]=\"'global-context--aggregation-picker'\"\n [insideClick]=\"true\"\n [isDisabled]=\"disabled()\"\n >\n <button\n class=\"dropdown-toggle form-control p-t-0 p-b-0 l-h-1 d-flex a-i-center\"\n [attr.aria-label]=\"currentText() | translate\"\n tooltip=\"{{ (disabled() ? AGGREGATION_TEXTS.disabled : currentText()) | translate }}\"\n placement=\"top\"\n container=\"body\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"dropdown.isOpen\"\n type=\"button\"\n [attr.data-cy]=\"'global-context--aggregation-picker-' + value()\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"currentIcon()\"\n ></i>\n <span class=\"caret m-r-8 m-l-4\"></span>\n </button>\n\n <ul\n class=\"dropdown-menu dropdown-menu-right--xs\"\n role=\"listbox\"\n *dropdownMenu\n >\n @for (aggregation of AGGREGATIONS; track aggregation.id || $index) {\n @let isDisabled = aggregation.id ? disabledAggregations()[aggregation.id] : false;\n <li\n [class.active]=\"aggregation.id === value()\"\n [class.disabled]=\"isDisabled\"\n >\n <button\n class=\"\"\n [attr.aria-selected]=\"aggregation.id === value()\"\n role=\"option\"\n (click)=\"selectAggregation(aggregation.id); dropdown.isOpen = false\"\n [disabled]=\"isDisabled\"\n [attr.data-cy]=\"'global-context--aggregation-picker-input-' + aggregation.id\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"\n aggregation.id ? AGGREGATION_ICONS[aggregation.id] : AGGREGATION_ICONS.undefined\n \"\n ></i>\n <span>{{ aggregation.title | translate }}</span>\n </button>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (layout() === 'radio') {\n <div\n class=\"radio-group d-flex-md a-i-center gap-16\"\n [attr.aria-label]=\"'Aggregation options' | translate\"\n role=\"radiogroup\"\n >\n @for (aggregation of AGGREGATIONS; track aggregation.id || $index) {\n @let isDisabled = aggregation.id ? disabledAggregations()[aggregation.id] : false;\n <label\n class=\"c8y-radio\"\n [attr.data-cy]=\"'global-context--aggregation-picker-input-' + aggregation.id\"\n >\n <input\n name=\"aggregation\"\n role=\"radio\"\n type=\"radio\"\n [value]=\"aggregation.id\"\n [checked]=\"aggregation.id === value()\"\n [disabled]=\"isDisabled\"\n (change)=\"selectAggregation(aggregation.id)\"\n />\n <span></span>\n <i\n class=\"icon-16 m-l-4\"\n [c8yIcon]=\"\n aggregation.id ? AGGREGATION_ICONS[aggregation.id] : AGGREGATION_ICONS.undefined\n \"\n ></i>\n <span>{{ aggregation.title | translate }}</span>\n </label>\n }\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "directive", type: i2$1.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i2$1.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i2$1.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "ngmodule", type: I18nModule }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3044
+ ], ngImport: i0, template: "@if (layout() === 'dropdown') {\n <div\n class=\"dropdown\"\n style=\"border: 0; margin-left: -1px\"\n container=\"body\"\n #dropdown=\"bs-dropdown\"\n dropdown\n [attr.data-cy]=\"'global-context--aggregation-picker'\"\n [insideClick]=\"true\"\n [isDisabled]=\"disabled()\"\n >\n <button\n class=\"dropdown-toggle form-control p-t-0 p-b-0 l-h-1 d-flex a-i-center\"\n [attr.aria-label]=\"currentText() | translate\"\n tooltip=\"{{ (disabled() ? AGGREGATION_TEXTS.disabled : currentText()) | translate }}\"\n placement=\"top\"\n container=\"body\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"dropdown.isOpen\"\n type=\"button\"\n [attr.data-cy]=\"'global-context--aggregation-picker-' + value()\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"currentIcon()\"\n ></i>\n <span class=\"caret m-r-8 m-l-4\"></span>\n </button>\n\n <ul\n class=\"dropdown-menu dropdown-menu-right--xs\"\n role=\"listbox\"\n *dropdownMenu\n >\n @for (aggregation of AVAILABLE_AGGREGATIONS(); track aggregation.id || $index) {\n @let isAutoItem = aggregation.id === AUTO_ITEM_ID;\n @let isDisabled =\n isAutoItem\n ? autoModeDisabled()\n : aggregation.id\n ? disabledAggregations()[aggregation.id]\n : false;\n <li\n [class.active]=\"\n isAutoItem ? autoModeActive() : !autoModeActive() && aggregation.id === value()\n \"\n [class.disabled]=\"isDisabled\"\n >\n <button\n class=\"\"\n [attr.aria-selected]=\"\n isAutoItem ? autoModeActive() : !autoModeActive() && aggregation.id === value()\n \"\n role=\"option\"\n (click)=\"selectAggregation(aggregation.id); dropdown.isOpen = false\"\n [disabled]=\"isDisabled\"\n [attr.data-cy]=\"'global-context--aggregation-picker-input-' + aggregation.id\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"\n isAutoItem\n ? AUTO_ICON\n : aggregation.id\n ? AGGREGATION_ICONS[aggregation.id]\n : AGGREGATION_ICONS.undefined\n \"\n ></i>\n <span>{{ aggregation.title | translate }}</span>\n </button>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (layout() === 'radio') {\n <div\n class=\"radio-group d-flex-md a-i-center gap-16\"\n [class.flex-wrap]=\"showAutoMode()\"\n [attr.aria-label]=\"'Aggregation options' | translate\"\n role=\"radiogroup\"\n >\n @for (aggregation of AVAILABLE_AGGREGATIONS(); track aggregation.id || $index) {\n @let isAutoItem = aggregation.id === AUTO_ITEM_ID;\n @let isDisabled =\n isAutoItem\n ? autoModeDisabled()\n : aggregation.id\n ? disabledAggregations()[aggregation.id]\n : false;\n @let isChecked =\n isAutoItem ? autoModeActive() : !autoModeActive() && aggregation.id === value();\n <label\n class=\"c8y-radio\"\n [class.disabled]=\"isDisabled\"\n [attr.data-cy]=\"'global-context--aggregation-picker-input-' + aggregation.id\"\n >\n <input\n name=\"aggregation\"\n role=\"radio\"\n type=\"radio\"\n [value]=\"aggregation.id\"\n [checked]=\"isChecked\"\n [disabled]=\"isDisabled\"\n (change)=\"selectAggregation(aggregation.id)\"\n />\n <span></span>\n <i\n class=\"icon-16 m-l-4\"\n [c8yIcon]=\"\n isAutoItem\n ? AUTO_ICON\n : aggregation.id\n ? AGGREGATION_ICONS[aggregation.id]\n : AGGREGATION_ICONS.undefined\n \"\n aria-hidden=\"true\"\n ></i>\n <span>{{ aggregation.title | translate }}</span>\n @if (isAutoItem) {\n <button\n class=\"btn-help btn-help--sm m-l-4\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"AUTO_MODE_TOOLTIP | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n }\n </label>\n }\n\n @if (showAutoMode() && autoModeActive()) {\n <ng-content select=\"[autoAggregationOptions]\"></ng-content>\n }\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "directive", type: i2$1.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i2$1.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i2$1.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "ngmodule", type: I18nModule }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i3.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2918
3045
  }
2919
3046
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AggregationPickerComponent, decorators: [{
2920
3047
  type: Component,
@@ -2924,8 +3051,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
2924
3051
  useExisting: forwardRef(() => AggregationPickerComponent),
2925
3052
  multi: true
2926
3053
  }
2927
- ], standalone: true, imports: [TooltipModule, BsDropdownModule, I18nModule, IconDirective, FormsModule], template: "@if (layout() === 'dropdown') {\n <div\n class=\"dropdown\"\n style=\"border: 0; margin-left: -1px\"\n container=\"body\"\n #dropdown=\"bs-dropdown\"\n dropdown\n [attr.data-cy]=\"'global-context--aggregation-picker'\"\n [insideClick]=\"true\"\n [isDisabled]=\"disabled()\"\n >\n <button\n class=\"dropdown-toggle form-control p-t-0 p-b-0 l-h-1 d-flex a-i-center\"\n [attr.aria-label]=\"currentText() | translate\"\n tooltip=\"{{ (disabled() ? AGGREGATION_TEXTS.disabled : currentText()) | translate }}\"\n placement=\"top\"\n container=\"body\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"dropdown.isOpen\"\n type=\"button\"\n [attr.data-cy]=\"'global-context--aggregation-picker-' + value()\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"currentIcon()\"\n ></i>\n <span class=\"caret m-r-8 m-l-4\"></span>\n </button>\n\n <ul\n class=\"dropdown-menu dropdown-menu-right--xs\"\n role=\"listbox\"\n *dropdownMenu\n >\n @for (aggregation of AGGREGATIONS; track aggregation.id || $index) {\n @let isDisabled = aggregation.id ? disabledAggregations()[aggregation.id] : false;\n <li\n [class.active]=\"aggregation.id === value()\"\n [class.disabled]=\"isDisabled\"\n >\n <button\n class=\"\"\n [attr.aria-selected]=\"aggregation.id === value()\"\n role=\"option\"\n (click)=\"selectAggregation(aggregation.id); dropdown.isOpen = false\"\n [disabled]=\"isDisabled\"\n [attr.data-cy]=\"'global-context--aggregation-picker-input-' + aggregation.id\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"\n aggregation.id ? AGGREGATION_ICONS[aggregation.id] : AGGREGATION_ICONS.undefined\n \"\n ></i>\n <span>{{ aggregation.title | translate }}</span>\n </button>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (layout() === 'radio') {\n <div\n class=\"radio-group d-flex-md a-i-center gap-16\"\n [attr.aria-label]=\"'Aggregation options' | translate\"\n role=\"radiogroup\"\n >\n @for (aggregation of AGGREGATIONS; track aggregation.id || $index) {\n @let isDisabled = aggregation.id ? disabledAggregations()[aggregation.id] : false;\n <label\n class=\"c8y-radio\"\n [attr.data-cy]=\"'global-context--aggregation-picker-input-' + aggregation.id\"\n >\n <input\n name=\"aggregation\"\n role=\"radio\"\n type=\"radio\"\n [value]=\"aggregation.id\"\n [checked]=\"aggregation.id === value()\"\n [disabled]=\"isDisabled\"\n (change)=\"selectAggregation(aggregation.id)\"\n />\n <span></span>\n <i\n class=\"icon-16 m-l-4\"\n [c8yIcon]=\"\n aggregation.id ? AGGREGATION_ICONS[aggregation.id] : AGGREGATION_ICONS.undefined\n \"\n ></i>\n <span>{{ aggregation.title | translate }}</span>\n </label>\n }\n </div>\n}\n" }]
2928
- }], propDecorators: { disabledAggregations: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledAggregations", required: false }] }], resetToDefault: [{ type: i0.Input, args: [{ isSignal: true, alias: "resetToDefault", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }] } });
3054
+ ], standalone: true, imports: [TooltipModule, BsDropdownModule, I18nModule, IconDirective, FormsModule, PopoverModule], template: "@if (layout() === 'dropdown') {\n <div\n class=\"dropdown\"\n style=\"border: 0; margin-left: -1px\"\n container=\"body\"\n #dropdown=\"bs-dropdown\"\n dropdown\n [attr.data-cy]=\"'global-context--aggregation-picker'\"\n [insideClick]=\"true\"\n [isDisabled]=\"disabled()\"\n >\n <button\n class=\"dropdown-toggle form-control p-t-0 p-b-0 l-h-1 d-flex a-i-center\"\n [attr.aria-label]=\"currentText() | translate\"\n tooltip=\"{{ (disabled() ? AGGREGATION_TEXTS.disabled : currentText()) | translate }}\"\n placement=\"top\"\n container=\"body\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"dropdown.isOpen\"\n type=\"button\"\n [attr.data-cy]=\"'global-context--aggregation-picker-' + value()\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n dropdownToggle\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"currentIcon()\"\n ></i>\n <span class=\"caret m-r-8 m-l-4\"></span>\n </button>\n\n <ul\n class=\"dropdown-menu dropdown-menu-right--xs\"\n role=\"listbox\"\n *dropdownMenu\n >\n @for (aggregation of AVAILABLE_AGGREGATIONS(); track aggregation.id || $index) {\n @let isAutoItem = aggregation.id === AUTO_ITEM_ID;\n @let isDisabled =\n isAutoItem\n ? autoModeDisabled()\n : aggregation.id\n ? disabledAggregations()[aggregation.id]\n : false;\n <li\n [class.active]=\"\n isAutoItem ? autoModeActive() : !autoModeActive() && aggregation.id === value()\n \"\n [class.disabled]=\"isDisabled\"\n >\n <button\n class=\"\"\n [attr.aria-selected]=\"\n isAutoItem ? autoModeActive() : !autoModeActive() && aggregation.id === value()\n \"\n role=\"option\"\n (click)=\"selectAggregation(aggregation.id); dropdown.isOpen = false\"\n [disabled]=\"isDisabled\"\n [attr.data-cy]=\"'global-context--aggregation-picker-input-' + aggregation.id\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"\n isAutoItem\n ? AUTO_ICON\n : aggregation.id\n ? AGGREGATION_ICONS[aggregation.id]\n : AGGREGATION_ICONS.undefined\n \"\n ></i>\n <span>{{ aggregation.title | translate }}</span>\n </button>\n </li>\n }\n </ul>\n </div>\n}\n\n@if (layout() === 'radio') {\n <div\n class=\"radio-group d-flex-md a-i-center gap-16\"\n [class.flex-wrap]=\"showAutoMode()\"\n [attr.aria-label]=\"'Aggregation options' | translate\"\n role=\"radiogroup\"\n >\n @for (aggregation of AVAILABLE_AGGREGATIONS(); track aggregation.id || $index) {\n @let isAutoItem = aggregation.id === AUTO_ITEM_ID;\n @let isDisabled =\n isAutoItem\n ? autoModeDisabled()\n : aggregation.id\n ? disabledAggregations()[aggregation.id]\n : false;\n @let isChecked =\n isAutoItem ? autoModeActive() : !autoModeActive() && aggregation.id === value();\n <label\n class=\"c8y-radio\"\n [class.disabled]=\"isDisabled\"\n [attr.data-cy]=\"'global-context--aggregation-picker-input-' + aggregation.id\"\n >\n <input\n name=\"aggregation\"\n role=\"radio\"\n type=\"radio\"\n [value]=\"aggregation.id\"\n [checked]=\"isChecked\"\n [disabled]=\"isDisabled\"\n (change)=\"selectAggregation(aggregation.id)\"\n />\n <span></span>\n <i\n class=\"icon-16 m-l-4\"\n [c8yIcon]=\"\n isAutoItem\n ? AUTO_ICON\n : aggregation.id\n ? AGGREGATION_ICONS[aggregation.id]\n : AGGREGATION_ICONS.undefined\n \"\n aria-hidden=\"true\"\n ></i>\n <span>{{ aggregation.title | translate }}</span>\n @if (isAutoItem) {\n <button\n class=\"btn-help btn-help--sm m-l-4\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"AUTO_MODE_TOOLTIP | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n }\n </label>\n }\n\n @if (showAutoMode() && autoModeActive()) {\n <ng-content select=\"[autoAggregationOptions]\"></ng-content>\n }\n </div>\n}\n" }]
3055
+ }], propDecorators: { disabledAggregations: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledAggregations", required: false }] }], resetToDefault: [{ type: i0.Input, args: [{ isSignal: true, alias: "resetToDefault", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], showAutoMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAutoMode", required: false }] }], autoModeActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoModeActive", required: false }] }], autoModeDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoModeDisabled", required: false }] }], autoModeChange: [{ type: i0.Output, args: ["autoModeChange"] }] } });
2929
3056
 
2930
3057
  /**
2931
3058
  * Component for configuring history mode settings
@@ -2956,6 +3083,7 @@ class HistoryModeConfigurationControlsComponent {
2956
3083
  constructor() {
2957
3084
  this.AGGREGATION_TEXTS = AGGREGATION_TEXTS;
2958
3085
  this.DATE_FORMAT = 'medium';
3086
+ this.AUTO_AGGREGATION_DATAPOINTS = AUTO_AGGREGATION_DATAPOINTS;
2959
3087
  this.errorMessages = {
2960
3088
  dateAfterRangeMax: gettext('This date is after the latest allowed date.'),
2961
3089
  dateBeforeRangeMin: gettext('This date is before the earliest allowed date.'),
@@ -2964,10 +3092,11 @@ class HistoryModeConfigurationControlsComponent {
2964
3092
  };
2965
3093
  // Popover messages for translation extraction
2966
3094
  this.TIME_RANGE_PICKER_POPOVER = gettext('Specify the exact start and end date/time of the time period to analyse. This provides a static view of historical data within the selected timeframe.');
2967
- this.AGGREGATION_POPOVER = gettext("Groups data points into larger time intervals to simplify visualization and improve performance. 'None' shows raw data, while other options combine data points into minute, hour, or day groupings.");
3095
+ this.AGGREGATION_POPOVER = AGGREGATION_POPOVER_TEXT;
2968
3096
  this.destroyRef = inject(DestroyRef);
2969
3097
  this.formBuilder = inject(FormBuilder);
2970
3098
  this.aggregationPickerService = inject(AggregationPickerService);
3099
+ this.timeSeriesMigrationService = inject(TimeSeriesMigrationService);
2971
3100
  this.settingsSignal = signal({
2972
3101
  showAutoRefresh: true,
2973
3102
  showTimeContext: true,
@@ -2979,14 +3108,35 @@ class HistoryModeConfigurationControlsComponent {
2979
3108
  this.disabledAggregations = signal({}, ...(ngDevMode ? [{ debugName: "disabledAggregations" }] : /* istanbul ignore next */ []));
2980
3109
  this.dateFromErrors = signal(null, ...(ngDevMode ? [{ debugName: "dateFromErrors" }] : /* istanbul ignore next */ []));
2981
3110
  this.dateToErrors = signal(null, ...(ngDevMode ? [{ debugName: "dateToErrors" }] : /* istanbul ignore next */ []));
3111
+ /** Whether auto-aggregation mode is active. */
3112
+ this.isAutoModeActive = signal(false, ...(ngDevMode ? [{ debugName: "isAutoModeActive" }] : /* istanbul ignore next */ []));
3113
+ /** Whether the "Auto" option should be shown but disabled (greyed) for the current widget. */
3114
+ this.autoModeDisabled = computed(() => !!this.settingsSignal().autoModeDisabled, ...(ngDevMode ? [{ debugName: "autoModeDisabled" }] : /* istanbul ignore next */ []));
3115
+ /**
3116
+ * The "Auto" option requires the tenant to be migrated to time series
3117
+ * (auto mode uses `aggregationInterval`, unsupported on non-migrated tenants).
3118
+ */
3119
+ this.isTimeSeriesMigrated = signal(false, ...(ngDevMode ? [{ debugName: "isTimeSeriesMigrated" }] : /* istanbul ignore next */ []));
3120
+ /** Popover text for the "Keep point count on zoom" checkbox. */
3121
+ this.KEEP_DATA_ON_ZOOM_IN_POPOVER = gettext('When enabled, the chart reloads data at a finer or coarser interval as you zoom in or out, so it always shows the number of points you set. When disabled, it reuses the already loaded data.');
2982
3122
  this.currentForm = this.createForm();
3123
+ this.lastProcessedFormValue = this.currentForm.value;
3124
+ this.timeSeriesMigrationService
3125
+ .isTimeSeriesMigrated()
3126
+ .then(isMigrated => this.isTimeSeriesMigrated.set(isMigrated));
2983
3127
  this.currentForm.valueChanges
2984
- .pipe(takeUntilDestroyed(this.destroyRef), debounceTime(100))
3128
+ .pipe(takeUntilDestroyed(this.destroyRef),
3129
+ // Typing into the datapoints number field gets a longer debounce so the context (and
3130
+ // the charts consuming it) does not refresh on every keystroke.
3131
+ debounce(formValue => timer(this.isDatapointsOnlyChange(formValue)
3132
+ ? TIMING.TYPING_DEBOUNCE
3133
+ : TIMING.FORM_DEBOUNCE)))
2985
3134
  .subscribe(formValue => {
2986
3135
  this.handleFormValueChange(formValue);
3136
+ this.lastProcessedFormValue = this.currentForm.value;
2987
3137
  });
2988
3138
  this.currentForm.statusChanges
2989
- .pipe(takeUntilDestroyed(this.destroyRef), debounceTime(100))
3139
+ .pipe(takeUntilDestroyed(this.destroyRef), debounceTime(TIMING.FORM_DEBOUNCE))
2990
3140
  .subscribe(() => {
2991
3141
  this.updateErrorSignals();
2992
3142
  this.validationStatus.emit(this.currentForm.valid);
@@ -2994,11 +3144,47 @@ class HistoryModeConfigurationControlsComponent {
2994
3144
  this.updateErrorSignals();
2995
3145
  this.validationStatus.emit(this.currentForm.valid);
2996
3146
  }
3147
+ /** Called by the aggregation picker's (autoModeChange) output. */
3148
+ onAutoModeChange(isAuto) {
3149
+ this.currentForm.patchValue({ autoAggregationEnabled: isAuto });
3150
+ this.isAutoModeActive.set(isAuto);
3151
+ }
2997
3152
  setDateToNow() {
2998
3153
  const now = new Date();
2999
3154
  now.setSeconds(0, 0);
3000
3155
  this.currentForm.get('dateTimeContext')?.get('dateTo')?.setValue(now.toISOString());
3001
3156
  }
3157
+ /**
3158
+ * Commits a valid "Points per chart" value when the user leaves the field: snaps
3159
+ * an out-of-range number back into [MIN, MAX], and restores the last applied value when the
3160
+ * field was left empty. Called on the number input's change/blur — while typing, invalid or
3161
+ * empty values are simply not emitted (see handleFormValueChange).
3162
+ */
3163
+ clampDatapoints() {
3164
+ const control = this.currentForm.get('autoAggregationDatapoints');
3165
+ const value = control?.value;
3166
+ if (value === null || value === undefined || Number.isNaN(value)) {
3167
+ const lastApplied = this.contextState()?.autoAggregation?.datapoints ?? AUTO_AGGREGATION_DATAPOINTS.DEFAULT;
3168
+ control?.setValue(this.clampToDatapointsBounds(lastApplied));
3169
+ return;
3170
+ }
3171
+ const clamped = this.clampToDatapointsBounds(value);
3172
+ if (clamped !== value) {
3173
+ control?.setValue(clamped);
3174
+ }
3175
+ }
3176
+ clampToDatapointsBounds(value) {
3177
+ return Math.min(AUTO_AGGREGATION_DATAPOINTS.MAX, Math.max(AUTO_AGGREGATION_DATAPOINTS.MIN, value));
3178
+ }
3179
+ /**
3180
+ * Whether `formValue` differs from the last processed form value only in the
3181
+ * `autoAggregationDatapoints` field, i.e. the user is typing into the datapoints input.
3182
+ */
3183
+ isDatapointsOnlyChange(formValue) {
3184
+ const previous = this.lastProcessedFormValue;
3185
+ return (formValue.autoAggregationDatapoints !== previous.autoAggregationDatapoints &&
3186
+ isEqual({ ...formValue, autoAggregationDatapoints: null }, { ...previous, autoAggregationDatapoints: null }));
3187
+ }
3002
3188
  updateErrorSignals() {
3003
3189
  const dateTimeContext = this.currentForm?.get('dateTimeContext');
3004
3190
  const dateFromControl = dateTimeContext?.get('dateFrom');
@@ -3018,7 +3204,7 @@ class HistoryModeConfigurationControlsComponent {
3018
3204
  this.dateToErrors.set(Object.keys(dateToControlErrors).length > 0 ? dateToControlErrors : null);
3019
3205
  }
3020
3206
  handleFormValueChange(formValue) {
3021
- const { dateTimeContext, aggregation } = formValue;
3207
+ const { dateTimeContext, aggregation, autoAggregationEnabled, autoAggregationDatapoints, autoAggregationKeepDataOnZoomIn } = formValue;
3022
3208
  if (!dateTimeContext) {
3023
3209
  return;
3024
3210
  }
@@ -3032,18 +3218,37 @@ class HistoryModeConfigurationControlsComponent {
3032
3218
  // Calculate disabled aggregations regardless of validation
3033
3219
  // This allows us to disable aggregations even for edge cases like dateFrom === dateTo
3034
3220
  dateTimeContext.interval = TIME_INTERVAL.CUSTOM;
3035
- const { selectedAggregation, disabledAggregations } = this.aggregationPickerService.calculateAggregation([new Date(dateTimeContext.dateFrom), new Date(dateTimeContext.dateTo)], aggregation ?? null);
3221
+ const { selectedAggregation, disabledAggregations } = this.aggregationPickerService.calculateAggregation([new Date(dateTimeContext.dateFrom), new Date(dateTimeContext.dateTo)], autoAggregationEnabled ? null : (aggregation ?? null));
3036
3222
  this.disabledAggregations.set(disabledAggregations);
3037
3223
  // Skip emission if validation fails (e.g., dateFrom > dateTo), but still update UI
3038
3224
  if (!this.isValidDateTimeContext(dateTimeContext)) {
3039
3225
  return;
3040
3226
  }
3041
- if (selectedAggregation !== undefined) {
3227
+ if (autoAggregationEnabled && !this.isValidDatapoints(autoAggregationDatapoints)) {
3228
+ return;
3229
+ }
3230
+ // Only auto-update the standard aggregation when not in auto mode
3231
+ if (!autoAggregationEnabled && selectedAggregation !== undefined) {
3042
3232
  this.currentForm.patchValue({ aggregation: selectedAggregation }, { emitEvent: false });
3043
3233
  }
3044
- const emission = structuredClone(this.currentForm.value);
3234
+ const emission = {
3235
+ dateTimeContext: structuredClone(dateTimeContext),
3236
+ aggregation: autoAggregationEnabled ? null : (this.currentForm.value.aggregation ?? null),
3237
+ autoAggregation: autoAggregationEnabled
3238
+ ? {
3239
+ datapoints: autoAggregationDatapoints,
3240
+ keepDataOnZoomIn: autoAggregationKeepDataOnZoomIn ?? true
3241
+ }
3242
+ : null
3243
+ };
3045
3244
  this.contextChange.emit(emission);
3046
3245
  }
3246
+ isValidDatapoints(value) {
3247
+ return (typeof value === 'number' &&
3248
+ !Number.isNaN(value) &&
3249
+ value >= AUTO_AGGREGATION_DATAPOINTS.MIN &&
3250
+ value <= AUTO_AGGREGATION_DATAPOINTS.MAX);
3251
+ }
3047
3252
  isValidDateTimeContext(dateTimeContext) {
3048
3253
  if (!dateTimeContext) {
3049
3254
  return false;
@@ -3067,8 +3272,12 @@ class HistoryModeConfigurationControlsComponent {
3067
3272
  dateFrom: defaults.dateFrom,
3068
3273
  dateTo: defaults.dateTo
3069
3274
  },
3070
- aggregation: null
3275
+ aggregation: null,
3276
+ autoAggregationEnabled: false,
3277
+ autoAggregationDatapoints: AUTO_AGGREGATION_DATAPOINTS.DEFAULT,
3278
+ autoAggregationKeepDataOnZoomIn: true
3071
3279
  }, { emitEvent: false });
3280
+ this.lastProcessedFormValue = this.currentForm.value;
3072
3281
  this.disabledAggregations.set({});
3073
3282
  this.validationStatus.emit(this.currentForm.valid);
3074
3283
  return;
@@ -3094,10 +3303,15 @@ class HistoryModeConfigurationControlsComponent {
3094
3303
  clonedContext.dateTo = normalizedTo.toISOString();
3095
3304
  this.currentForm.patchValue({
3096
3305
  dateTimeContext: clonedContext,
3097
- aggregation: ctx.aggregation ?? null
3306
+ aggregation: ctx.autoAggregation ? null : (ctx.aggregation ?? null),
3307
+ autoAggregationEnabled: !!ctx.autoAggregation,
3308
+ autoAggregationDatapoints: this.clampToDatapointsBounds(ctx.autoAggregation?.datapoints ?? AUTO_AGGREGATION_DATAPOINTS.DEFAULT),
3309
+ autoAggregationKeepDataOnZoomIn: ctx.autoAggregation?.keepDataOnZoomIn ?? true
3098
3310
  }, { emitEvent: false });
3311
+ this.lastProcessedFormValue = this.currentForm.value;
3312
+ this.isAutoModeActive.set(!!ctx.autoAggregation);
3099
3313
  // Update disabled aggregations but DON'T override the value
3100
- const { disabledAggregations } = this.aggregationPickerService.calculateAggregation([new Date(clonedContext.dateFrom), new Date(clonedContext.dateTo)], ctx.aggregation ?? null);
3314
+ const { disabledAggregations } = this.aggregationPickerService.calculateAggregation([new Date(clonedContext.dateFrom), new Date(clonedContext.dateTo)], ctx.autoAggregation ? null : (ctx.aggregation ?? null));
3101
3315
  this.disabledAggregations.set(disabledAggregations);
3102
3316
  this.validationStatus.emit(this.currentForm.valid);
3103
3317
  }
@@ -3112,7 +3326,13 @@ class HistoryModeConfigurationControlsComponent {
3112
3326
  });
3113
3327
  return this.formBuilder.group({
3114
3328
  dateTimeContext,
3115
- aggregation: this.formBuilder.control(null)
3329
+ aggregation: this.formBuilder.control(null),
3330
+ autoAggregationEnabled: this.formBuilder.control(false),
3331
+ autoAggregationDatapoints: this.formBuilder.control(AUTO_AGGREGATION_DATAPOINTS.DEFAULT, [
3332
+ Validators.min(AUTO_AGGREGATION_DATAPOINTS.MIN),
3333
+ Validators.max(AUTO_AGGREGATION_DATAPOINTS.MAX)
3334
+ ]),
3335
+ autoAggregationKeepDataOnZoomIn: this.formBuilder.control(true)
3116
3336
  });
3117
3337
  }
3118
3338
  getDefaultDateRange() {
@@ -3143,7 +3363,7 @@ class HistoryModeConfigurationControlsComponent {
3143
3363
  };
3144
3364
  }
3145
3365
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: HistoryModeConfigurationControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3146
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: HistoryModeConfigurationControlsComponent, isStandalone: true, selector: "c8y-history-mode-configuration-controls", inputs: { settings: "settings", context: "context" }, outputs: { contextChange: "contextChange", validationStatus: "validationStatus" }, ngImport: i0, template: "@if (currentForm) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AGGREGATION = settings.showAggregation;\n\n <form [formGroup]=\"currentForm\">\n <div class=\"content-flex-100\">\n <div\n class=\"col-4\"\n [ngClass]=\"{ 'm-b-8': !SHOW_AGGREGATION }\"\n >\n @if (SHOW_TIME_CONTEXT) {\n @let dateTimeContext = currentForm.get('dateTimeContext');\n @let tempDateFromValue = dateTimeContext.get('dateFrom')?.value;\n @let tempDateToValue = dateTimeContext.get('dateTo')?.value;\n @let fromErrors = dateFromErrors();\n @let toErrors = dateToErrors();\n\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item time-context m-r-4\">\n <i\n class=\"\"\n [c8yIcon]=\"'calendar'\"\n ></i>\n </div>\n {{ 'Date & time range' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"TIME_RANGE_PICKER_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"content-flex-58 d-flex a-i-center m-b-0 p-t-16\">\n <c8y-form-group\n [class.has-error]=\"fromErrors\"\n class=\"form-group-sm d-flex a-i-center col-5 flex-wrap\"\n >\n <label\n class=\"m-b-sm-0 m-r-8 text-nowrap\"\n style=\"min-width: 30px\"\n [title]=\"'From`date`' | translate\"\n for=\"dateFrom\"\n translate\n >\n From`date`\n </label>\n <c8y-date-time-picker\n [class.has-error]=\"fromErrors\"\n id=\"dateFrom\"\n [maxDate]=\"tempDateToValue\"\n [placeholder]=\"'From`date`' | translate\"\n [formControl]=\"dateTimeContext.get('dateFrom')\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"fromErrors\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"errorMessages.dateAfterRangeMax | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"errorMessages.invalidDateTime | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateRange\"\n [text]=\"errorMessages.invalidDateRange | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group\n [class.has-error]=\"toErrors\"\n class=\"form-group-sm d-flex flex-wrap col-7 a-i-center\"\n >\n <label\n class=\"m-b-sm-0 text-nowrap m-r-8\"\n style=\"min-width: 30px\"\n [title]=\"'To`date`' | translate\"\n for=\"dateTo\"\n translate\n >\n To`date`\n </label>\n <c8y-date-time-picker\n [class.has-error]=\"toErrors\"\n id=\"dateTo\"\n [minDate]=\"tempDateFromValue\"\n [placeholder]=\"'To`date`' | translate\"\n [formControl]=\"dateTimeContext.get('dateTo')\"\n ></c8y-date-time-picker>\n <button\n class=\"btn btn-sm btn-default m-l-4\"\n [title]=\"'Set to current time' | translate\"\n type=\"button\"\n (click)=\"setDateToNow()\"\n >\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"'clock-o'\"\n ></i>\n {{ 'Now' | translate }}\n </button>\n <c8y-messages [show]=\"toErrors\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"errorMessages.dateBeforeRangeMin | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"errorMessages.invalidDateTime | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n <div class=\"col-\">\n @if (SHOW_AGGREGATION) {\n @let selectedAggregation = currentForm.get('aggregation')?.value;\n\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item aggregation m-r-4\">\n <i [c8yIcon]=\"'input'\"></i>\n </div>\n {{ 'Aggregation' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"AGGREGATION_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"p-t-16 p-b-16 m-b-4\">\n <c8y-aggregation-picker\n formControlName=\"aggregation\"\n [resetToDefault]=\"true\"\n [disabledAggregations]=\"disabledAggregations()\"\n [layout]=\"'radio'\"\n ></c8y-aggregation-picker>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n </div>\n </form>\n}\n", dependencies: [{ kind: "ngmodule", type: I18nModule }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i2$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: AggregationPickerComponent, selector: "c8y-aggregation-picker", inputs: ["disabledAggregations", "resetToDefault", "layout"] }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage", "additionalMessages"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "ngmodule", type: DateTimePickerModule }, { kind: "component", type: i4.DateTimePickerComponent, selector: "c8y-date-time-picker", inputs: ["minDate", "maxDate", "placeholder", "dateInputFormat", "adaptivePosition", "size", "dateType", "config"], outputs: ["onDateSelected"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3366
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: HistoryModeConfigurationControlsComponent, isStandalone: true, selector: "c8y-history-mode-configuration-controls", inputs: { settings: "settings", context: "context" }, outputs: { contextChange: "contextChange", validationStatus: "validationStatus" }, ngImport: i0, template: "@if (currentForm) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AGGREGATION = settings.showAggregation;\n\n <form [formGroup]=\"currentForm\">\n <div class=\"content-flex-100\">\n <div\n class=\"col-4\"\n [ngClass]=\"{ 'm-b-8': !SHOW_AGGREGATION }\"\n >\n @if (SHOW_TIME_CONTEXT) {\n @let dateTimeContext = currentForm.get('dateTimeContext');\n @let tempDateFromValue = dateTimeContext.get('dateFrom')?.value;\n @let tempDateToValue = dateTimeContext.get('dateTo')?.value;\n @let fromErrors = dateFromErrors();\n @let toErrors = dateToErrors();\n\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item time-context m-r-4\">\n <i\n class=\"\"\n [c8yIcon]=\"'calendar'\"\n ></i>\n </div>\n {{ 'Date & time range' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"TIME_RANGE_PICKER_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"content-flex-58 d-flex a-i-center m-b-0 p-t-16\">\n <c8y-form-group\n [class.has-error]=\"fromErrors\"\n class=\"form-group-sm d-flex a-i-center col-5 flex-wrap\"\n >\n <label\n class=\"m-b-sm-0 m-r-8 text-nowrap\"\n style=\"min-width: 30px\"\n [title]=\"'From`date`' | translate\"\n for=\"dateFrom\"\n translate\n >\n From`date`\n </label>\n <c8y-date-time-picker\n [class.has-error]=\"fromErrors\"\n id=\"dateFrom\"\n [maxDate]=\"tempDateToValue\"\n [placeholder]=\"'From`date`' | translate\"\n [formControl]=\"dateTimeContext.get('dateFrom')\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"fromErrors\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"errorMessages.dateAfterRangeMax | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"errorMessages.invalidDateTime | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateRange\"\n [text]=\"errorMessages.invalidDateRange | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group\n [class.has-error]=\"toErrors\"\n class=\"form-group-sm d-flex col-7 a-i-center\"\n >\n <label\n class=\"m-b-sm-0 text-nowrap m-r-8\"\n style=\"min-width: 30px\"\n [title]=\"'To`date`' | translate\"\n for=\"dateTo\"\n translate\n >\n To`date`\n </label>\n <c8y-date-time-picker\n [class.has-error]=\"toErrors\"\n id=\"dateTo\"\n [minDate]=\"tempDateFromValue\"\n [placeholder]=\"'To`date`' | translate\"\n [formControl]=\"dateTimeContext.get('dateTo')\"\n ></c8y-date-time-picker>\n <button\n class=\"btn btn-sm btn-default m-l-4\"\n [title]=\"'Set to current time' | translate\"\n type=\"button\"\n (click)=\"setDateToNow()\"\n >\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"'clock-o'\"\n ></i>\n {{ 'Now' | translate }}\n </button>\n <c8y-messages [show]=\"toErrors\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"errorMessages.dateBeforeRangeMin | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"errorMessages.invalidDateTime | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n <div class=\"col-8\">\n @if (SHOW_AGGREGATION) {\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item aggregation m-r-4\">\n <i [c8yIcon]=\"'input'\"></i>\n </div>\n {{ 'Aggregation' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"AGGREGATION_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n\n <c8y-form-group class=\"p-t-16 m-b-4 p-b-16\">\n <c8y-aggregation-picker\n formControlName=\"aggregation\"\n [layout]=\"'radio'\"\n [resetToDefault]=\"true\"\n [showAutoMode]=\"isTimeSeriesMigrated()\"\n [autoModeActive]=\"isAutoModeActive()\"\n [autoModeDisabled]=\"autoModeDisabled()\"\n [disabledAggregations]=\"disabledAggregations()\"\n (autoModeChange)=\"onAutoModeChange($event)\"\n >\n <div\n class=\"d-flex a-i-center gap-16 flex-wrap\"\n autoAggregationOptions\n >\n <div class=\"d-flex a-i-center\">\n <label\n class=\"m-b-0 m-r-8 text-nowrap\"\n for=\"autoAggregationDatapoints\"\n >\n {{ 'Points per chart' | translate }}\n </label>\n @let datapointsRangeText =\n 'Enter a value between {{ min }} and {{ max }}.'\n | translate\n : {\n min: AUTO_AGGREGATION_DATAPOINTS.MIN,\n max: AUTO_AGGREGATION_DATAPOINTS.MAX\n };\n <c8y-form-group class=\"form-group-sm m-b-0\">\n <input\n class=\"form-control input-sm\"\n style=\"width: 60px\"\n [attr.title]=\"datapointsRangeText\"\n [attr.aria-label]=\"'Points per chart' | translate\"\n id=\"autoAggregationDatapoints\"\n type=\"number\"\n [min]=\"AUTO_AGGREGATION_DATAPOINTS.MIN\"\n [max]=\"AUTO_AGGREGATION_DATAPOINTS.MAX\"\n [step]=\"AUTO_AGGREGATION_DATAPOINTS.STEP\"\n [formControl]=\"currentForm.controls.autoAggregationDatapoints\"\n (change)=\"clampDatapoints()\"\n data-cy=\"global-context--auto-aggregation-datapoints-input\"\n />\n @let datapointsErrors = currentForm.get('autoAggregationDatapoints')?.errors;\n <c8y-messages\n class=\"m-t-4\"\n [show]=\"datapointsErrors\"\n >\n <c8y-message\n name=\"min\"\n [text]=\"datapointsRangeText\"\n ></c8y-message>\n <c8y-message\n name=\"max\"\n [text]=\"datapointsRangeText\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n <label\n class=\"c8y-switch m-b-0\"\n [title]=\"'Keep point count on zoom' | translate\"\n >\n <input\n type=\"checkbox\"\n [formControl]=\"currentForm.controls.autoAggregationKeepDataOnZoomIn\"\n data-cy=\"global-context--auto-aggregation-keep-data-on-zoom-in\"\n />\n <span></span>\n <span>{{ 'Keep point count on zoom' | translate }}</span>\n <button\n class=\"btn-help btn-help--sm m-l-4\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"KEEP_DATA_ON_ZOOM_IN_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </label>\n </div>\n </c8y-aggregation-picker>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n </div>\n </form>\n}\n", dependencies: [{ kind: "ngmodule", type: I18nModule }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i3.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage", "additionalMessages"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "ngmodule", type: DateTimePickerModule }, { kind: "component", type: i4.DateTimePickerComponent, selector: "c8y-date-time-picker", inputs: ["minDate", "maxDate", "placeholder", "dateInputFormat", "adaptivePosition", "size", "dateType", "config"], outputs: ["onDateSelected"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AggregationPickerComponent, selector: "c8y-aggregation-picker", inputs: ["disabledAggregations", "resetToDefault", "layout", "showAutoMode", "autoModeActive", "autoModeDisabled"], outputs: ["autoModeChange"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3147
3367
  }
3148
3368
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: HistoryModeConfigurationControlsComponent, decorators: [{
3149
3369
  type: Component,
@@ -3156,12 +3376,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
3156
3376
  FormsModule,
3157
3377
  PopoverModule,
3158
3378
  FormGroupComponent,
3159
- AggregationPickerComponent,
3160
3379
  MessagesComponent,
3161
3380
  MessageDirective,
3162
3381
  DateTimePickerModule,
3163
- NgClass
3164
- ], template: "@if (currentForm) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AGGREGATION = settings.showAggregation;\n\n <form [formGroup]=\"currentForm\">\n <div class=\"content-flex-100\">\n <div\n class=\"col-4\"\n [ngClass]=\"{ 'm-b-8': !SHOW_AGGREGATION }\"\n >\n @if (SHOW_TIME_CONTEXT) {\n @let dateTimeContext = currentForm.get('dateTimeContext');\n @let tempDateFromValue = dateTimeContext.get('dateFrom')?.value;\n @let tempDateToValue = dateTimeContext.get('dateTo')?.value;\n @let fromErrors = dateFromErrors();\n @let toErrors = dateToErrors();\n\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item time-context m-r-4\">\n <i\n class=\"\"\n [c8yIcon]=\"'calendar'\"\n ></i>\n </div>\n {{ 'Date & time range' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"TIME_RANGE_PICKER_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"content-flex-58 d-flex a-i-center m-b-0 p-t-16\">\n <c8y-form-group\n [class.has-error]=\"fromErrors\"\n class=\"form-group-sm d-flex a-i-center col-5 flex-wrap\"\n >\n <label\n class=\"m-b-sm-0 m-r-8 text-nowrap\"\n style=\"min-width: 30px\"\n [title]=\"'From`date`' | translate\"\n for=\"dateFrom\"\n translate\n >\n From`date`\n </label>\n <c8y-date-time-picker\n [class.has-error]=\"fromErrors\"\n id=\"dateFrom\"\n [maxDate]=\"tempDateToValue\"\n [placeholder]=\"'From`date`' | translate\"\n [formControl]=\"dateTimeContext.get('dateFrom')\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"fromErrors\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"errorMessages.dateAfterRangeMax | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"errorMessages.invalidDateTime | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateRange\"\n [text]=\"errorMessages.invalidDateRange | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group\n [class.has-error]=\"toErrors\"\n class=\"form-group-sm d-flex flex-wrap col-7 a-i-center\"\n >\n <label\n class=\"m-b-sm-0 text-nowrap m-r-8\"\n style=\"min-width: 30px\"\n [title]=\"'To`date`' | translate\"\n for=\"dateTo\"\n translate\n >\n To`date`\n </label>\n <c8y-date-time-picker\n [class.has-error]=\"toErrors\"\n id=\"dateTo\"\n [minDate]=\"tempDateFromValue\"\n [placeholder]=\"'To`date`' | translate\"\n [formControl]=\"dateTimeContext.get('dateTo')\"\n ></c8y-date-time-picker>\n <button\n class=\"btn btn-sm btn-default m-l-4\"\n [title]=\"'Set to current time' | translate\"\n type=\"button\"\n (click)=\"setDateToNow()\"\n >\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"'clock-o'\"\n ></i>\n {{ 'Now' | translate }}\n </button>\n <c8y-messages [show]=\"toErrors\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"errorMessages.dateBeforeRangeMin | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"errorMessages.invalidDateTime | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n <div class=\"col-\">\n @if (SHOW_AGGREGATION) {\n @let selectedAggregation = currentForm.get('aggregation')?.value;\n\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item aggregation m-r-4\">\n <i [c8yIcon]=\"'input'\"></i>\n </div>\n {{ 'Aggregation' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"AGGREGATION_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"p-t-16 p-b-16 m-b-4\">\n <c8y-aggregation-picker\n formControlName=\"aggregation\"\n [resetToDefault]=\"true\"\n [disabledAggregations]=\"disabledAggregations()\"\n [layout]=\"'radio'\"\n ></c8y-aggregation-picker>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n </div>\n </form>\n}\n" }]
3382
+ NgClass,
3383
+ AggregationPickerComponent
3384
+ ], template: "@if (currentForm) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AGGREGATION = settings.showAggregation;\n\n <form [formGroup]=\"currentForm\">\n <div class=\"content-flex-100\">\n <div\n class=\"col-4\"\n [ngClass]=\"{ 'm-b-8': !SHOW_AGGREGATION }\"\n >\n @if (SHOW_TIME_CONTEXT) {\n @let dateTimeContext = currentForm.get('dateTimeContext');\n @let tempDateFromValue = dateTimeContext.get('dateFrom')?.value;\n @let tempDateToValue = dateTimeContext.get('dateTo')?.value;\n @let fromErrors = dateFromErrors();\n @let toErrors = dateToErrors();\n\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item time-context m-r-4\">\n <i\n class=\"\"\n [c8yIcon]=\"'calendar'\"\n ></i>\n </div>\n {{ 'Date & time range' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"TIME_RANGE_PICKER_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"content-flex-58 d-flex a-i-center m-b-0 p-t-16\">\n <c8y-form-group\n [class.has-error]=\"fromErrors\"\n class=\"form-group-sm d-flex a-i-center col-5 flex-wrap\"\n >\n <label\n class=\"m-b-sm-0 m-r-8 text-nowrap\"\n style=\"min-width: 30px\"\n [title]=\"'From`date`' | translate\"\n for=\"dateFrom\"\n translate\n >\n From`date`\n </label>\n <c8y-date-time-picker\n [class.has-error]=\"fromErrors\"\n id=\"dateFrom\"\n [maxDate]=\"tempDateToValue\"\n [placeholder]=\"'From`date`' | translate\"\n [formControl]=\"dateTimeContext.get('dateFrom')\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"fromErrors\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"errorMessages.dateAfterRangeMax | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"errorMessages.invalidDateTime | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateRange\"\n [text]=\"errorMessages.invalidDateRange | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group\n [class.has-error]=\"toErrors\"\n class=\"form-group-sm d-flex col-7 a-i-center\"\n >\n <label\n class=\"m-b-sm-0 text-nowrap m-r-8\"\n style=\"min-width: 30px\"\n [title]=\"'To`date`' | translate\"\n for=\"dateTo\"\n translate\n >\n To`date`\n </label>\n <c8y-date-time-picker\n [class.has-error]=\"toErrors\"\n id=\"dateTo\"\n [minDate]=\"tempDateFromValue\"\n [placeholder]=\"'To`date`' | translate\"\n [formControl]=\"dateTimeContext.get('dateTo')\"\n ></c8y-date-time-picker>\n <button\n class=\"btn btn-sm btn-default m-l-4\"\n [title]=\"'Set to current time' | translate\"\n type=\"button\"\n (click)=\"setDateToNow()\"\n >\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"'clock-o'\"\n ></i>\n {{ 'Now' | translate }}\n </button>\n <c8y-messages [show]=\"toErrors\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"errorMessages.dateBeforeRangeMin | translate\"\n ></c8y-message>\n <c8y-message\n name=\"invalidDateTime\"\n [text]=\"errorMessages.invalidDateTime | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n <div class=\"col-8\">\n @if (SHOW_AGGREGATION) {\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item aggregation m-r-4\">\n <i [c8yIcon]=\"'input'\"></i>\n </div>\n {{ 'Aggregation' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"AGGREGATION_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n\n <c8y-form-group class=\"p-t-16 m-b-4 p-b-16\">\n <c8y-aggregation-picker\n formControlName=\"aggregation\"\n [layout]=\"'radio'\"\n [resetToDefault]=\"true\"\n [showAutoMode]=\"isTimeSeriesMigrated()\"\n [autoModeActive]=\"isAutoModeActive()\"\n [autoModeDisabled]=\"autoModeDisabled()\"\n [disabledAggregations]=\"disabledAggregations()\"\n (autoModeChange)=\"onAutoModeChange($event)\"\n >\n <div\n class=\"d-flex a-i-center gap-16 flex-wrap\"\n autoAggregationOptions\n >\n <div class=\"d-flex a-i-center\">\n <label\n class=\"m-b-0 m-r-8 text-nowrap\"\n for=\"autoAggregationDatapoints\"\n >\n {{ 'Points per chart' | translate }}\n </label>\n @let datapointsRangeText =\n 'Enter a value between {{ min }} and {{ max }}.'\n | translate\n : {\n min: AUTO_AGGREGATION_DATAPOINTS.MIN,\n max: AUTO_AGGREGATION_DATAPOINTS.MAX\n };\n <c8y-form-group class=\"form-group-sm m-b-0\">\n <input\n class=\"form-control input-sm\"\n style=\"width: 60px\"\n [attr.title]=\"datapointsRangeText\"\n [attr.aria-label]=\"'Points per chart' | translate\"\n id=\"autoAggregationDatapoints\"\n type=\"number\"\n [min]=\"AUTO_AGGREGATION_DATAPOINTS.MIN\"\n [max]=\"AUTO_AGGREGATION_DATAPOINTS.MAX\"\n [step]=\"AUTO_AGGREGATION_DATAPOINTS.STEP\"\n [formControl]=\"currentForm.controls.autoAggregationDatapoints\"\n (change)=\"clampDatapoints()\"\n data-cy=\"global-context--auto-aggregation-datapoints-input\"\n />\n @let datapointsErrors = currentForm.get('autoAggregationDatapoints')?.errors;\n <c8y-messages\n class=\"m-t-4\"\n [show]=\"datapointsErrors\"\n >\n <c8y-message\n name=\"min\"\n [text]=\"datapointsRangeText\"\n ></c8y-message>\n <c8y-message\n name=\"max\"\n [text]=\"datapointsRangeText\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n <label\n class=\"c8y-switch m-b-0\"\n [title]=\"'Keep point count on zoom' | translate\"\n >\n <input\n type=\"checkbox\"\n [formControl]=\"currentForm.controls.autoAggregationKeepDataOnZoomIn\"\n data-cy=\"global-context--auto-aggregation-keep-data-on-zoom-in\"\n />\n <span></span>\n <span>{{ 'Keep point count on zoom' | translate }}</span>\n <button\n class=\"btn-help btn-help--sm m-l-4\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"KEEP_DATA_ON_ZOOM_IN_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </label>\n </div>\n </c8y-aggregation-picker>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n </div>\n </form>\n}\n" }]
3165
3385
  }], ctorParameters: () => [], propDecorators: { settings: [{
3166
3386
  type: Input
3167
3387
  }], context: [{
@@ -3618,7 +3838,7 @@ class LiveModeConfigurationControlsComponent {
3618
3838
  }, { emitEvent: false });
3619
3839
  }
3620
3840
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LiveModeConfigurationControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3621
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: LiveModeConfigurationControlsComponent, isStandalone: true, selector: "c8y-live-mode-configuration-controls", inputs: { settings: "settings", intervalOptions: "intervalOptions", context: "context" }, outputs: { contextChange: "contextChange" }, ngImport: i0, template: "@if (form) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AUTO_REFRESH = settings.showAutoRefresh;\n\n <form [formGroup]=\"form\">\n <div class=\"content-flex-82\">\n <div class=\"col-5\">\n @if (SHOW_TIME_CONTEXT) {\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item time-context m-r-4\">\n <i [c8yIcon]=\"'calendar'\"></i>\n </div>\n {{ 'Date & time' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"TIME_RANGE_PICKER_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"m-b-4 p-t-16 p-b-16\">\n <c8y-date-time-context-picker\n formControlName=\"dateTimeContext\"\n [config]=\"{ showDateTo: false, showDateFrom: true }\"\n [intervalOptions]=\"intervalOptions\"\n ></c8y-date-time-context-picker>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n <div class=\"col-3\">\n @if (SHOW_AUTO_REFRESH) {\n <fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex\">\n <div class=\"standalone btn-icon-dot__item auto-refresh m-r-4\">\n <i [c8yIcon]=\"'refresh'\"></i>\n </div>\n {{ 'Auto refresh' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"REFRESH_POPOVER_MESSAGE | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"m-b-8 form-group-sm p-t-16 p-b-16\">\n <div class=\"d-flex gap-8 a-i-center\">\n <label class=\"c8y-switch c8y-switch--inline\">\n <input\n type=\"checkbox\"\n #arInput\n formControlName=\"isAutoRefreshEnabled\"\n />\n <span></span>\n <span>\n {{ 'Auto refresh enabled' | translate }}\n </span>\n </label>\n </div>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n </div>\n </form>\n}\n", dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: DateTimeContextPickerComponent, selector: "c8y-date-time-context-picker", inputs: ["disabled", "shouldDisableInterval", "config", "intervalOptions"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i2$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3841
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: LiveModeConfigurationControlsComponent, isStandalone: true, selector: "c8y-live-mode-configuration-controls", inputs: { settings: "settings", intervalOptions: "intervalOptions", context: "context" }, outputs: { contextChange: "contextChange" }, ngImport: i0, template: "@if (form) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AUTO_REFRESH = settings.showAutoRefresh;\n\n <form [formGroup]=\"form\">\n <div class=\"content-flex-82\">\n <div class=\"col-5\">\n @if (SHOW_TIME_CONTEXT) {\n <fieldset class=\"c8y-fieldset\">\n <legend>\n <div class=\"standalone btn-icon-dot__item time-context m-r-4\">\n <i [c8yIcon]=\"'calendar'\"></i>\n </div>\n {{ 'Date & time' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"TIME_RANGE_PICKER_POPOVER | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"m-b-4 p-t-16 p-b-16\">\n <c8y-date-time-context-picker\n formControlName=\"dateTimeContext\"\n [config]=\"{ showDateTo: false, showDateFrom: true }\"\n [intervalOptions]=\"intervalOptions\"\n ></c8y-date-time-context-picker>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n <div class=\"col-3\">\n @if (SHOW_AUTO_REFRESH) {\n <fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex\">\n <div class=\"standalone btn-icon-dot__item auto-refresh m-r-4\">\n <i [c8yIcon]=\"'refresh'\"></i>\n </div>\n {{ 'Auto refresh' | translate }}\n <button\n class=\"btn-help btn-help--sm\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"REFRESH_POPOVER_MESSAGE | translate\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </legend>\n <c8y-form-group class=\"m-b-8 form-group-sm p-t-16 p-b-16\">\n <div class=\"d-flex gap-8 a-i-center\">\n <label class=\"c8y-switch c8y-switch--inline\">\n <input\n type=\"checkbox\"\n #arInput\n formControlName=\"isAutoRefreshEnabled\"\n />\n <span></span>\n <span>\n {{ 'Auto refresh enabled' | translate }}\n </span>\n </label>\n </div>\n </c8y-form-group>\n </fieldset>\n }\n </div>\n </div>\n </form>\n}\n", dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: DateTimeContextPickerComponent, selector: "c8y-date-time-context-picker", inputs: ["disabled", "shouldDisableInterval", "config", "intervalOptions"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i3.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3622
3842
  }
3623
3843
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LiveModeConfigurationControlsComponent, decorators: [{
3624
3844
  type: Component,
@@ -4057,7 +4277,7 @@ class ConfigurationCollapseComponent {
4057
4277
  this.hasPendingChanges.set(!isEqual(snapshot, latest));
4058
4278
  }
4059
4279
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ConfigurationCollapseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4060
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ConfigurationCollapseComponent, isStandalone: true, selector: "c8y-configuration-collapse", inputs: { supportedModes: { classPropertyName: "supportedModes", publicName: "supportedModes", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { contextChange: "contextChange", refreshOptionChange: "refreshOptionChange", savePreferenceChange: "savePreferenceChange" }, host: { classAttribute: "d-contents" }, ngImport: i0, template: "<div\n class=\"c8y-global-context\"\n data-cy=\"global-context--configuration-panel\"\n [collapse]=\"isCollapsed()\"\n (collapsed)=\"onCollapsed()\"\n (expanded)=\"onExpanded()\"\n [isAnimated]=\"true\"\n>\n <div class=\"p-t-16 p-b-16 p-l-24 p-r-24 separator-bottom\">\n <span\n class=\"h4\"\n translate\n >\n Time mode\n </span>\n </div>\n <div>\n @if (!isCollapsed()) {\n <c8y-configuration-controls\n [activeMode]=\"activeMode()\"\n [liveContext]=\"liveViewContext()\"\n [historyContext]=\"historyViewContext()\"\n [supportedModes]=\"supportedModes()\"\n (refreshOptionChange)=\"onModeSelected($event)\"\n (contextChange)=\"onModeChange($event)\"\n (validationStatus)=\"onValidationStatusChange($event)\"\n ></c8y-configuration-controls>\n }\n </div>\n <div class=\"c8y-top-drawer--footer\">\n <div class=\"d-flex a-i-center gap-8\">\n <button\n class=\"btn btn-default\"\n [title]=\"'Close help' | translate\"\n aria-controls=\"collapseHelp\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n type=\"button\"\n (click)=\"toggle()\"\n data-cy=\"global-context--Close-button\"\n translate\n >\n Close\n </button>\n <button\n class=\"btn btn-primary\"\n [title]=\"'Apply global context' | translate\"\n aria-controls=\"collapseHelp\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n type=\"button\"\n (click)=\"apply()\"\n [disabled]=\"!hasPendingChanges() || !isFormValid()\"\n translate\n data-cy=\"global-date-context--Apply-button\"\n >\n Apply\n </button>\n\n <label class=\"c8y-checkbox d-flex align-items-center m-b-0\">\n <input\n class=\"m-r-4\"\n type=\"checkbox\"\n [ngModel]=\"shouldSave()\"\n (ngModelChange)=\"shouldSaveInDashboard($event)\"\n />\n <span class=\"a-s-center m-r-8\"></span>\n <span\n class=\"text-truncate\"\n translate\n >\n Save in dashboard configuration\n </span>\n <button\n class=\"btn-help btn-help--sm m-l-4\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"helpText | translate\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </label>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: CollapseModule }, { kind: "directive", type: i1$2.CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i2$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: ConfigurationControlsComponent, selector: "c8y-configuration-controls", inputs: ["controlsDisplayMode", "settings", "activeMode", "liveContext", "historyContext", "supportedModes", "intervalOptions", "tabsOutletName"], outputs: ["refreshOptionChange", "contextChange", "validationStatus"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4280
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ConfigurationCollapseComponent, isStandalone: true, selector: "c8y-configuration-collapse", inputs: { supportedModes: { classPropertyName: "supportedModes", publicName: "supportedModes", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { contextChange: "contextChange", refreshOptionChange: "refreshOptionChange", savePreferenceChange: "savePreferenceChange" }, host: { classAttribute: "d-contents" }, ngImport: i0, template: "<div\n class=\"c8y-global-context\"\n data-cy=\"global-context--configuration-panel\"\n [collapse]=\"isCollapsed()\"\n (collapsed)=\"onCollapsed()\"\n (expanded)=\"onExpanded()\"\n [isAnimated]=\"true\"\n>\n <div class=\"p-t-16 p-b-16 p-l-24 p-r-24 separator-bottom\">\n <span\n class=\"h4\"\n translate\n >\n Time mode\n </span>\n </div>\n <div>\n @if (!isCollapsed()) {\n <c8y-configuration-controls\n [activeMode]=\"activeMode()\"\n [liveContext]=\"liveViewContext()\"\n [historyContext]=\"historyViewContext()\"\n [supportedModes]=\"supportedModes()\"\n (refreshOptionChange)=\"onModeSelected($event)\"\n (contextChange)=\"onModeChange($event)\"\n (validationStatus)=\"onValidationStatusChange($event)\"\n ></c8y-configuration-controls>\n }\n </div>\n <div class=\"c8y-top-drawer--footer\">\n <div class=\"d-flex a-i-center gap-8\">\n <button\n class=\"btn btn-default\"\n [title]=\"'Close help' | translate\"\n aria-controls=\"collapseHelp\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n type=\"button\"\n (click)=\"toggle()\"\n data-cy=\"global-context--Close-button\"\n translate\n >\n Close\n </button>\n <button\n class=\"btn btn-primary\"\n [title]=\"'Apply global context' | translate\"\n aria-controls=\"collapseHelp\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n type=\"button\"\n (click)=\"apply()\"\n [disabled]=\"!hasPendingChanges() || !isFormValid()\"\n translate\n data-cy=\"global-date-context--Apply-button\"\n >\n Apply\n </button>\n\n <label class=\"c8y-checkbox d-flex align-items-center m-b-0\">\n <input\n class=\"m-r-4\"\n type=\"checkbox\"\n [ngModel]=\"shouldSave()\"\n (ngModelChange)=\"shouldSaveInDashboard($event)\"\n />\n <span class=\"a-s-center m-r-8\"></span>\n <span\n class=\"text-truncate\"\n translate\n >\n Save in dashboard configuration\n </span>\n <button\n class=\"btn-help btn-help--sm m-l-4\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"helpText | translate\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n </label>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: CollapseModule }, { kind: "directive", type: i1$2.CollapseDirective, selector: "[collapse]", inputs: ["display", "isAnimated", "collapse"], outputs: ["collapsed", "collapses", "expanded", "expands"], exportAs: ["bs-collapse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i3.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: ConfigurationControlsComponent, selector: "c8y-configuration-controls", inputs: ["controlsDisplayMode", "settings", "activeMode", "liveContext", "historyContext", "supportedModes", "intervalOptions", "tabsOutletName"], outputs: ["refreshOptionChange", "contextChange", "validationStatus"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4061
4281
  }
4062
4282
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ConfigurationCollapseComponent, decorators: [{
4063
4283
  type: Component,
@@ -4612,16 +4832,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
4612
4832
  class AggregationDisplayComponent {
4613
4833
  constructor() {
4614
4834
  this.aggregation = input(null, ...(ngDevMode ? [{ debugName: "aggregation" }] : /* istanbul ignore next */ []));
4615
- this.AGGREGATION_ICONS = AGGREGATION_ICONS;
4835
+ /**
4836
+ * When true, the display shows "Auto" regardless of `aggregation`. Auto mode stores a null
4837
+ * aggregation, so without this flag the display would fall back to "No aggregation".
4838
+ */
4839
+ this.autoMode = input(false, ...(ngDevMode ? [{ debugName: "autoMode" }] : /* istanbul ignore next */ []));
4840
+ /** Number of aggregation points, shown as a badge next to "Auto" while auto mode is active. */
4841
+ this.autoPoints = input(null, ...(ngDevMode ? [{ debugName: "autoPoints" }] : /* istanbul ignore next */ []));
4842
+ /** Whether the point count is kept on zoom; surfaced in the tooltip while auto mode is active. */
4843
+ this.autoKeepPointCount = input(null, ...(ngDevMode ? [{ debugName: "autoKeepPointCount" }] : /* istanbul ignore next */ []));
4844
+ // Exposed for the template's tooltip (`@let`).
4616
4845
  this.AGGREGATION_TEXTS = AGGREGATION_TEXTS;
4846
+ this.AUTO_AGGREGATION_TEXT = AUTO_AGGREGATION_TEXT;
4847
+ this.AUTO_POINTS_TOOLTIP = AUTO_POINTS_TOOLTIP;
4848
+ this.AUTO_POINTS_TOOLTIP_KEPT = AUTO_POINTS_TOOLTIP_KEPT;
4849
+ /** Short label shown as the current aggregation, accounting for auto mode. */
4850
+ this.displayText = computed(() => {
4851
+ if (this.autoMode()) {
4852
+ return AUTO_AGGREGATION_TEXT;
4853
+ }
4854
+ const aggregation = this.aggregation();
4855
+ return aggregation ? AGGREGATION_LABELS[aggregation] : AGGREGATION_LABELS.NONE;
4856
+ }, ...(ngDevMode ? [{ debugName: "displayText" }] : /* istanbul ignore next */ []));
4857
+ /** Icon shown next to the current aggregation, accounting for auto mode. */
4858
+ this.displayIcon = computed(() => {
4859
+ if (this.autoMode()) {
4860
+ return AGGREGATION_ICON_TYPE.AUTO;
4861
+ }
4862
+ const aggregation = this.aggregation();
4863
+ return aggregation ? AGGREGATION_ICONS[aggregation] : AGGREGATION_ICONS.undefined;
4864
+ }, ...(ngDevMode ? [{ debugName: "displayIcon" }] : /* istanbul ignore next */ []));
4617
4865
  }
4618
4866
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AggregationDisplayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4619
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.17", type: AggregationDisplayComponent, isStandalone: true, selector: "c8y-aggregation-display", inputs: { aggregation: { classPropertyName: "aggregation", publicName: "aggregation", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"d-flex a-i-center l-h-tight form-control\">\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"aggregation() ? AGGREGATION_ICONS[aggregation()] : AGGREGATION_ICONS.undefined\"\n ></i>\n <div class=\"d-col text-left fit-w min-width-0\">\n <span\n class=\"text-10 l-h-1 text-muted text-truncate\"\n title=\"{{ 'Aggregation' | translate }}\"\n >\n {{ 'Aggregation' | translate }}\n </span>\n <span\n class=\"text-12 l-h-1 text-medium text-truncate\"\n title=\"{{ AGGREGATION_TEXTS[aggregation()] | translate }}\"\n data-cy=\"global-date-context--Aggregation-display-value\"\n >\n {{ AGGREGATION_TEXTS[aggregation()] | translate }}\n </span>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4867
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AggregationDisplayComponent, isStandalone: true, selector: "c8y-aggregation-display", inputs: { aggregation: { classPropertyName: "aggregation", publicName: "aggregation", isSignal: true, isRequired: false, transformFunction: null }, autoMode: { classPropertyName: "autoMode", publicName: "autoMode", isSignal: true, isRequired: false, transformFunction: null }, autoPoints: { classPropertyName: "autoPoints", publicName: "autoPoints", isSignal: true, isRequired: false, transformFunction: null }, autoKeepPointCount: { classPropertyName: "autoKeepPointCount", publicName: "autoKeepPointCount", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"d-flex a-i-center l-h-tight form-control\">\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"displayIcon()\"\n ></i>\n <div class=\"d-col text-left fit-w min-width-0\">\n <span\n class=\"text-10 l-h-1 text-muted text-truncate\"\n title=\"{{ 'Aggregation' | translate }}\"\n >\n {{ 'Aggregation' | translate }}\n </span>\n @let titleText =\n autoMode()\n ? autoPoints() != null\n ? ((autoKeepPointCount() ? AUTO_POINTS_TOOLTIP_KEPT : AUTO_POINTS_TOOLTIP)\n | translate: { points: autoPoints() })\n : (AUTO_AGGREGATION_TEXT | translate)\n : aggregation()\n ? (AGGREGATION_TEXTS[aggregation()] | translate)\n : (AGGREGATION_TEXTS.null | translate);\n <span\n class=\"text-12 l-h-1 text-medium d-flex a-i-center gap-4\"\n [title]=\"titleText\"\n data-cy=\"global-date-context--Aggregation-display-value\"\n >\n <span class=\"text-truncate\">{{ displayText() | translate }}</span>\n @if (autoMode() && autoPoints() != null) {\n <span\n class=\"m-l-auto badge badge-info flex-no-shrink l-h-1 text-10\"\n style=\"min-height: 12px\"\n >\n {{ autoPoints() }}\n </span>\n }\n </span>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4620
4868
  }
4621
4869
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AggregationDisplayComponent, decorators: [{
4622
4870
  type: Component,
4623
- args: [{ selector: 'c8y-aggregation-display', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [C8yTranslatePipe, IconDirective], template: "<div class=\"d-flex a-i-center l-h-tight form-control\">\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"aggregation() ? AGGREGATION_ICONS[aggregation()] : AGGREGATION_ICONS.undefined\"\n ></i>\n <div class=\"d-col text-left fit-w min-width-0\">\n <span\n class=\"text-10 l-h-1 text-muted text-truncate\"\n title=\"{{ 'Aggregation' | translate }}\"\n >\n {{ 'Aggregation' | translate }}\n </span>\n <span\n class=\"text-12 l-h-1 text-medium text-truncate\"\n title=\"{{ AGGREGATION_TEXTS[aggregation()] | translate }}\"\n data-cy=\"global-date-context--Aggregation-display-value\"\n >\n {{ AGGREGATION_TEXTS[aggregation()] | translate }}\n </span>\n </div>\n</div>\n" }]
4624
- }], propDecorators: { aggregation: [{ type: i0.Input, args: [{ isSignal: true, alias: "aggregation", required: false }] }] } });
4871
+ args: [{ selector: 'c8y-aggregation-display', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [C8yTranslatePipe, IconDirective], template: "<div class=\"d-flex a-i-center l-h-tight form-control\">\n <i\n class=\"m-r-4\"\n [c8yIcon]=\"displayIcon()\"\n ></i>\n <div class=\"d-col text-left fit-w min-width-0\">\n <span\n class=\"text-10 l-h-1 text-muted text-truncate\"\n title=\"{{ 'Aggregation' | translate }}\"\n >\n {{ 'Aggregation' | translate }}\n </span>\n @let titleText =\n autoMode()\n ? autoPoints() != null\n ? ((autoKeepPointCount() ? AUTO_POINTS_TOOLTIP_KEPT : AUTO_POINTS_TOOLTIP)\n | translate: { points: autoPoints() })\n : (AUTO_AGGREGATION_TEXT | translate)\n : aggregation()\n ? (AGGREGATION_TEXTS[aggregation()] | translate)\n : (AGGREGATION_TEXTS.null | translate);\n <span\n class=\"text-12 l-h-1 text-medium d-flex a-i-center gap-4\"\n [title]=\"titleText\"\n data-cy=\"global-date-context--Aggregation-display-value\"\n >\n <span class=\"text-truncate\">{{ displayText() | translate }}</span>\n @if (autoMode() && autoPoints() != null) {\n <span\n class=\"m-l-auto badge badge-info flex-no-shrink l-h-1 text-10\"\n style=\"min-height: 12px\"\n >\n {{ autoPoints() }}\n </span>\n }\n </span>\n </div>\n</div>\n" }]
4872
+ }], propDecorators: { aggregation: [{ type: i0.Input, args: [{ isSignal: true, alias: "aggregation", required: false }] }], autoMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoMode", required: false }] }], autoPoints: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoPoints", required: false }] }], autoKeepPointCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoKeepPointCount", required: false }] }] } });
4625
4873
 
4626
4874
  /**
4627
4875
  * Source of auto-refresh state change.
@@ -4954,7 +5202,7 @@ let ContextControlsComponent$1 = class ContextControlsComponent {
4954
5202
  return pick(settings, requiredKeys);
4955
5203
  }
4956
5204
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ContextControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4957
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ContextControlsComponent, isStandalone: true, selector: "c8y-context-controls", inputs: { showDisplayModeLabel: "showDisplayModeLabel", isLoading: "isLoading", settings: "settings", context: "context" }, outputs: { contextChange: "contextChange", refresh: "refresh", contextClick: "contextClick" }, ngImport: i0, template: "@if (form) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AGGREGATION = settings.showAggregation;\n @let SHOW_AUTO_REFRESH = settings.showAutoRefresh;\n @let refreshIntervalValue = form?.get('refreshInterval')?.value;\n @let isLiveMode = refreshOption === REFRESH_OPTION.LIVE;\n\n @if (isLiveMode) {\n <form\n class=\"input-group\"\n [formGroup]=\"form\"\n >\n <c8y-auto-refresh-control\n #autoRefreshControl\n [isLoading]=\"isLoading\"\n [isAutoRefreshConnected]=\"isAutoRefreshConnected\"\n formControlName=\"isAutoRefreshEnabled\"\n [autoRefreshSeconds]=\"refreshIntervalValue\"\n (refresh)=\"refresh.emit()\"\n ></c8y-auto-refresh-control>\n <button\n class=\"btn-clean d-flex p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8 min-width-0\"\n style=\"margin-left: -1px\"\n (click)=\"contextClick.emit($event)\"\n >\n <div\n class=\"d-col a-i-start form-control\"\n style=\"flex: 0\"\n >\n <p class=\"text-muted fit-w text-10 l-h-1\">\n {{ 'Time mode' | translate }}\n </p>\n <p\n class=\"text-bold text-12 fit-w l-h-1\"\n data-cy=\"global-time-context-controls--Display-mode\"\n >\n {{ refreshOption | translate | titlecase }}\n </p>\n </div>\n\n @let interval = form.get('dateTimeContext')?.value?.interval;\n @let isCustomInterval = interval === 'custom';\n\n <c8y-time-range-display\n style=\"margin-left: -1px; min-width: 0\"\n [dateTimeContext]=\"form.get('dateTimeContext')?.value\"\n ></c8y-time-range-display>\n\n @if (!(isAnySettingsEnabled$ | async)) {\n <div\n class=\"d-col a-i-center form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <i\n class=\"dlt-c8y-icon-disconnected icon-20 text-danger\"\n [tooltip]=\"'No synced widgets' | translate\"\n placement=\"right\"\n container=\"body\"\n [delay]=\"500\"\n data-cy=\"global-time-context-controls--Widgets-disconnected\"\n ></i>\n </div>\n }\n </button>\n </form>\n } @else {\n <form [formGroup]=\"form\">\n <button\n class=\"btn-clean d-flex p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8\"\n (click)=\"contextClick.emit($event)\"\n >\n <div\n class=\"d-col a-i-center form-control\"\n style=\"flex: 0\"\n >\n <i class=\"dlt-c8y-icon-schedule1 icon-20 text-primary\"></i>\n </div>\n\n <div\n class=\"d-col a-i-start form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <p class=\"text-muted fit-w text-10 l-h-1\">\n {{ 'Time mode' | translate }}\n </p>\n <p\n class=\"text-bold text-12 fit-w l-h-1\"\n data-cy=\"global-time-context-controls--Display-mode\"\n >\n {{ refreshOption | translate | titlecase }}\n </p>\n </div>\n\n <c8y-time-range-display\n style=\"margin-left: -1px; min-width: 0\"\n [dateTimeContext]=\"form.get('dateTimeContext')?.value\"\n ></c8y-time-range-display>\n <c8y-aggregation-display\n style=\"margin-left: -1px; min-width: 0\"\n [aggregation]=\"form.get('aggregation')?.value\"\n ></c8y-aggregation-display>\n\n @if (!(isAnySettingsEnabled$ | async)) {\n <div\n class=\"d-col a-i-center form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <i\n class=\"dlt-c8y-icon-disconnected icon-20 text-danger\"\n [tooltip]=\"'No synced widgets' | translate\"\n placement=\"right\"\n container=\"body\"\n [delay]=\"500\"\n data-cy=\"global-time-context-controls--Widgets-disconnected\"\n ></i>\n </div>\n }\n </button>\n </form>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", inputs: ["isAutoRefreshConnected", "autoRefreshSeconds", "disableCounter", "isEnabled", "isLoading"], outputs: ["loadingChange", "refresh"] }, { kind: "component", type: TimeRangeDisplayComponent, selector: "c8y-time-range-display", inputs: ["dateTimeContext", "mode"] }, { kind: "component", type: AggregationDisplayComponent, selector: "c8y-aggregation-display", inputs: ["aggregation"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5205
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ContextControlsComponent, isStandalone: true, selector: "c8y-context-controls", inputs: { showDisplayModeLabel: "showDisplayModeLabel", isLoading: "isLoading", settings: "settings", context: "context" }, outputs: { contextChange: "contextChange", refresh: "refresh", contextClick: "contextClick" }, ngImport: i0, template: "@if (form) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AGGREGATION = settings.showAggregation;\n @let SHOW_AUTO_REFRESH = settings.showAutoRefresh;\n @let refreshIntervalValue = form?.get('refreshInterval')?.value;\n @let isLiveMode = refreshOption === REFRESH_OPTION.LIVE;\n\n @if (isLiveMode) {\n <form\n class=\"input-group\"\n [formGroup]=\"form\"\n >\n <c8y-auto-refresh-control\n #autoRefreshControl\n [isLoading]=\"isLoading\"\n [isAutoRefreshConnected]=\"isAutoRefreshConnected\"\n formControlName=\"isAutoRefreshEnabled\"\n [autoRefreshSeconds]=\"refreshIntervalValue\"\n (refresh)=\"refresh.emit()\"\n ></c8y-auto-refresh-control>\n <button\n class=\"btn-clean d-flex p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8 min-width-0\"\n style=\"margin-left: -1px\"\n (click)=\"contextClick.emit($event)\"\n >\n <div\n class=\"d-col a-i-start form-control\"\n style=\"flex: 0\"\n >\n <p class=\"text-muted fit-w text-10 l-h-1\">\n {{ 'Time mode' | translate }}\n </p>\n <p\n class=\"text-bold text-12 fit-w l-h-1\"\n data-cy=\"global-time-context-controls--Display-mode\"\n >\n {{ refreshOption | translate | titlecase }}\n </p>\n </div>\n\n @let interval = form.get('dateTimeContext')?.value?.interval;\n @let isCustomInterval = interval === 'custom';\n\n <c8y-time-range-display\n style=\"margin-left: -1px; min-width: 0\"\n [dateTimeContext]=\"form.get('dateTimeContext')?.value\"\n ></c8y-time-range-display>\n\n @if (!(isAnySettingsEnabled$ | async)) {\n <div\n class=\"d-col a-i-center form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <i\n class=\"dlt-c8y-icon-disconnected icon-20 text-danger\"\n [tooltip]=\"'No synced widgets' | translate\"\n placement=\"right\"\n container=\"body\"\n [delay]=\"500\"\n data-cy=\"global-time-context-controls--Widgets-disconnected\"\n ></i>\n </div>\n }\n </button>\n </form>\n } @else {\n <form [formGroup]=\"form\">\n <button\n class=\"btn-clean d-flex p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8\"\n (click)=\"contextClick.emit($event)\"\n >\n <div\n class=\"d-col a-i-center form-control\"\n style=\"flex: 0\"\n >\n <i class=\"dlt-c8y-icon-schedule1 icon-20 text-primary\"></i>\n </div>\n\n <div\n class=\"d-col a-i-start form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <p class=\"text-muted fit-w text-10 l-h-1\">\n {{ 'Time mode' | translate }}\n </p>\n <p\n class=\"text-bold text-12 fit-w l-h-1\"\n data-cy=\"global-time-context-controls--Display-mode\"\n >\n {{ refreshOption | translate | titlecase }}\n </p>\n </div>\n\n <c8y-time-range-display\n style=\"margin-left: -1px; min-width: 0\"\n [dateTimeContext]=\"form.get('dateTimeContext')?.value\"\n ></c8y-time-range-display>\n <c8y-aggregation-display\n style=\"margin-left: -1px; min-width: 0\"\n [aggregation]=\"form.get('aggregation')?.value\"\n [autoMode]=\"!!context?.autoAggregation\"\n [autoPoints]=\"context?.autoAggregation?.datapoints\"\n [autoKeepPointCount]=\"context?.autoAggregation?.keepDataOnZoomIn\"\n ></c8y-aggregation-display>\n\n @if (!(isAnySettingsEnabled$ | async)) {\n <div\n class=\"d-col a-i-center form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <i\n class=\"dlt-c8y-icon-disconnected icon-20 text-danger\"\n [tooltip]=\"'No synced widgets' | translate\"\n placement=\"right\"\n container=\"body\"\n [delay]=\"500\"\n data-cy=\"global-time-context-controls--Widgets-disconnected\"\n ></i>\n </div>\n }\n </button>\n </form>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", inputs: ["isAutoRefreshConnected", "autoRefreshSeconds", "disableCounter", "isEnabled", "isLoading"], outputs: ["loadingChange", "refresh"] }, { kind: "component", type: TimeRangeDisplayComponent, selector: "c8y-time-range-display", inputs: ["dateTimeContext", "mode"] }, { kind: "component", type: AggregationDisplayComponent, selector: "c8y-aggregation-display", inputs: ["aggregation", "autoMode", "autoPoints", "autoKeepPointCount"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4958
5206
  };
4959
5207
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ContextControlsComponent$1, decorators: [{
4960
5208
  type: Component,
@@ -4970,7 +5218,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
4970
5218
  TimeRangeDisplayComponent,
4971
5219
  AggregationDisplayComponent,
4972
5220
  AsyncPipe
4973
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (form) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AGGREGATION = settings.showAggregation;\n @let SHOW_AUTO_REFRESH = settings.showAutoRefresh;\n @let refreshIntervalValue = form?.get('refreshInterval')?.value;\n @let isLiveMode = refreshOption === REFRESH_OPTION.LIVE;\n\n @if (isLiveMode) {\n <form\n class=\"input-group\"\n [formGroup]=\"form\"\n >\n <c8y-auto-refresh-control\n #autoRefreshControl\n [isLoading]=\"isLoading\"\n [isAutoRefreshConnected]=\"isAutoRefreshConnected\"\n formControlName=\"isAutoRefreshEnabled\"\n [autoRefreshSeconds]=\"refreshIntervalValue\"\n (refresh)=\"refresh.emit()\"\n ></c8y-auto-refresh-control>\n <button\n class=\"btn-clean d-flex p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8 min-width-0\"\n style=\"margin-left: -1px\"\n (click)=\"contextClick.emit($event)\"\n >\n <div\n class=\"d-col a-i-start form-control\"\n style=\"flex: 0\"\n >\n <p class=\"text-muted fit-w text-10 l-h-1\">\n {{ 'Time mode' | translate }}\n </p>\n <p\n class=\"text-bold text-12 fit-w l-h-1\"\n data-cy=\"global-time-context-controls--Display-mode\"\n >\n {{ refreshOption | translate | titlecase }}\n </p>\n </div>\n\n @let interval = form.get('dateTimeContext')?.value?.interval;\n @let isCustomInterval = interval === 'custom';\n\n <c8y-time-range-display\n style=\"margin-left: -1px; min-width: 0\"\n [dateTimeContext]=\"form.get('dateTimeContext')?.value\"\n ></c8y-time-range-display>\n\n @if (!(isAnySettingsEnabled$ | async)) {\n <div\n class=\"d-col a-i-center form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <i\n class=\"dlt-c8y-icon-disconnected icon-20 text-danger\"\n [tooltip]=\"'No synced widgets' | translate\"\n placement=\"right\"\n container=\"body\"\n [delay]=\"500\"\n data-cy=\"global-time-context-controls--Widgets-disconnected\"\n ></i>\n </div>\n }\n </button>\n </form>\n } @else {\n <form [formGroup]=\"form\">\n <button\n class=\"btn-clean d-flex p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8\"\n (click)=\"contextClick.emit($event)\"\n >\n <div\n class=\"d-col a-i-center form-control\"\n style=\"flex: 0\"\n >\n <i class=\"dlt-c8y-icon-schedule1 icon-20 text-primary\"></i>\n </div>\n\n <div\n class=\"d-col a-i-start form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <p class=\"text-muted fit-w text-10 l-h-1\">\n {{ 'Time mode' | translate }}\n </p>\n <p\n class=\"text-bold text-12 fit-w l-h-1\"\n data-cy=\"global-time-context-controls--Display-mode\"\n >\n {{ refreshOption | translate | titlecase }}\n </p>\n </div>\n\n <c8y-time-range-display\n style=\"margin-left: -1px; min-width: 0\"\n [dateTimeContext]=\"form.get('dateTimeContext')?.value\"\n ></c8y-time-range-display>\n <c8y-aggregation-display\n style=\"margin-left: -1px; min-width: 0\"\n [aggregation]=\"form.get('aggregation')?.value\"\n ></c8y-aggregation-display>\n\n @if (!(isAnySettingsEnabled$ | async)) {\n <div\n class=\"d-col a-i-center form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <i\n class=\"dlt-c8y-icon-disconnected icon-20 text-danger\"\n [tooltip]=\"'No synced widgets' | translate\"\n placement=\"right\"\n container=\"body\"\n [delay]=\"500\"\n data-cy=\"global-time-context-controls--Widgets-disconnected\"\n ></i>\n </div>\n }\n </button>\n </form>\n }\n}\n" }]
5221
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (form) {\n @let SHOW_TIME_CONTEXT = settings.showTimeContext;\n @let SHOW_AGGREGATION = settings.showAggregation;\n @let SHOW_AUTO_REFRESH = settings.showAutoRefresh;\n @let refreshIntervalValue = form?.get('refreshInterval')?.value;\n @let isLiveMode = refreshOption === REFRESH_OPTION.LIVE;\n\n @if (isLiveMode) {\n <form\n class=\"input-group\"\n [formGroup]=\"form\"\n >\n <c8y-auto-refresh-control\n #autoRefreshControl\n [isLoading]=\"isLoading\"\n [isAutoRefreshConnected]=\"isAutoRefreshConnected\"\n formControlName=\"isAutoRefreshEnabled\"\n [autoRefreshSeconds]=\"refreshIntervalValue\"\n (refresh)=\"refresh.emit()\"\n ></c8y-auto-refresh-control>\n <button\n class=\"btn-clean d-flex p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8 min-width-0\"\n style=\"margin-left: -1px\"\n (click)=\"contextClick.emit($event)\"\n >\n <div\n class=\"d-col a-i-start form-control\"\n style=\"flex: 0\"\n >\n <p class=\"text-muted fit-w text-10 l-h-1\">\n {{ 'Time mode' | translate }}\n </p>\n <p\n class=\"text-bold text-12 fit-w l-h-1\"\n data-cy=\"global-time-context-controls--Display-mode\"\n >\n {{ refreshOption | translate | titlecase }}\n </p>\n </div>\n\n @let interval = form.get('dateTimeContext')?.value?.interval;\n @let isCustomInterval = interval === 'custom';\n\n <c8y-time-range-display\n style=\"margin-left: -1px; min-width: 0\"\n [dateTimeContext]=\"form.get('dateTimeContext')?.value\"\n ></c8y-time-range-display>\n\n @if (!(isAnySettingsEnabled$ | async)) {\n <div\n class=\"d-col a-i-center form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <i\n class=\"dlt-c8y-icon-disconnected icon-20 text-danger\"\n [tooltip]=\"'No synced widgets' | translate\"\n placement=\"right\"\n container=\"body\"\n [delay]=\"500\"\n data-cy=\"global-time-context-controls--Widgets-disconnected\"\n ></i>\n </div>\n }\n </button>\n </form>\n } @else {\n <form [formGroup]=\"form\">\n <button\n class=\"btn-clean d-flex p-l-xs-16 p-r-xs-16 m-t-xs-8 m-b-xs-8\"\n (click)=\"contextClick.emit($event)\"\n >\n <div\n class=\"d-col a-i-center form-control\"\n style=\"flex: 0\"\n >\n <i class=\"dlt-c8y-icon-schedule1 icon-20 text-primary\"></i>\n </div>\n\n <div\n class=\"d-col a-i-start form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <p class=\"text-muted fit-w text-10 l-h-1\">\n {{ 'Time mode' | translate }}\n </p>\n <p\n class=\"text-bold text-12 fit-w l-h-1\"\n data-cy=\"global-time-context-controls--Display-mode\"\n >\n {{ refreshOption | translate | titlecase }}\n </p>\n </div>\n\n <c8y-time-range-display\n style=\"margin-left: -1px; min-width: 0\"\n [dateTimeContext]=\"form.get('dateTimeContext')?.value\"\n ></c8y-time-range-display>\n <c8y-aggregation-display\n style=\"margin-left: -1px; min-width: 0\"\n [aggregation]=\"form.get('aggregation')?.value\"\n [autoMode]=\"!!context?.autoAggregation\"\n [autoPoints]=\"context?.autoAggregation?.datapoints\"\n [autoKeepPointCount]=\"context?.autoAggregation?.keepDataOnZoomIn\"\n ></c8y-aggregation-display>\n\n @if (!(isAnySettingsEnabled$ | async)) {\n <div\n class=\"d-col a-i-center form-control\"\n style=\"margin-left: -1px; flex: 0\"\n >\n <i\n class=\"dlt-c8y-icon-disconnected icon-20 text-danger\"\n [tooltip]=\"'No synced widgets' | translate\"\n placement=\"right\"\n container=\"body\"\n [delay]=\"500\"\n data-cy=\"global-time-context-controls--Widgets-disconnected\"\n ></i>\n </div>\n }\n </button>\n </form>\n }\n}\n" }]
4974
5222
  }], propDecorators: { showDisplayModeLabel: [{
4975
5223
  type: Input
4976
5224
  }], isLoading: [{
@@ -5223,6 +5471,7 @@ class GlobalContextComponent {
5223
5471
  return pick(changes, [
5224
5472
  'dateTimeContext',
5225
5473
  'aggregation',
5474
+ 'autoAggregation',
5226
5475
  'isAutoRefreshEnabled',
5227
5476
  'refreshInterval',
5228
5477
  'refreshOption',
@@ -6453,6 +6702,10 @@ function resolveConfigurationValue(key, sources, localStateValues, globalStateVa
6453
6702
  return undefined;
6454
6703
  case 'isGlobalContextReady':
6455
6704
  return undefined;
6705
+ case 'autoAggregation':
6706
+ return undefined;
6707
+ case 'aggregationFunction':
6708
+ return undefined;
6456
6709
  default: {
6457
6710
  // Exhaustive check: ensures all keys are handled at compile time
6458
6711
  const _exhaustive = key;
@@ -8641,7 +8894,7 @@ class GlobalContextInlineComponent {
8641
8894
  };
8642
8895
  }
8643
8896
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: GlobalContextInlineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8644
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: GlobalContextInlineComponent, isStandalone: true, selector: "c8y-global-context-inline", inputs: { widgetControls: { classPropertyName: "widgetControls", publicName: "widgetControls", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, dashboardChildForLegacy: { classPropertyName: "dashboardChildForLegacy", publicName: "dashboardChildForLegacy", isSignal: true, isRequired: false, transformFunction: null }, disableRefreshEmits: { classPropertyName: "disableRefreshEmits", publicName: "disableRefreshEmits", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { refresh: "refresh", globalContextChange: "globalContextChange" }, providers: [GlobalContextInlineOrchestratorService], viewQueries: [{ propertyName: "headerTemplateRef", first: true, predicate: ["headerContent"], descendants: true, read: TemplateRef, static: true }], exportAs: ["globalContextInline"], ngImport: i0, template: "<ng-template #headerContent>\n @let linkModel = linkDisplayModel();\n <ng-content select=\"#header\"></ng-content>\n\n @if (shouldShowHeaderLinks()) {\n <c8y-global-context-link-controls\n [linkStates]=\"linkModel.linkStates\"\n [controlConfigs]=\"linkModel.controlConfig\"\n (allLinksToggled)=\"toggleAllLinks($event)\"\n ></c8y-global-context-link-controls>\n }\n</ng-template>\n\n<ng-template #inlineContent>\n @let settings = inlineSettings();\n @let linkModel = linkDisplayModel();\n\n @if (form && settings) {\n <form\n class=\"d-flex gap-16 p-l-16 p-r-16 inner-scroll\"\n [ngClass]=\"{\n 'p-b-8':\n settings.showTimeContext ||\n settings.showRefresh ||\n settings.showAutoRefresh ||\n settings.showAggregation\n }\"\n [formGroup]=\"form\"\n >\n <div class=\"input-group w-auto input-group-sm\">\n @if (settings.showAggregation) {\n <c8y-aggregation-picker\n data-cy=\"global-inline-date-context--Aggregation-display\"\n [disabledAggregations]=\"getDisabledAggregations()\"\n formControlName=\"aggregation\"\n [resetToDefault]=\"true\"\n ></c8y-aggregation-picker>\n }\n\n @if (settings.showAutoRefresh) {\n <c8y-auto-refresh-control\n [isLoading]=\"isLoading()\"\n [disableCounter]=\"shouldDisableCounter\"\n formControlName=\"isAutoRefreshEnabled\"\n [autoRefreshSeconds]=\"getAutoRefreshSeconds()\"\n [isAutoRefreshConnected]=\"linkModel.linkStates.isAutoRefreshEnabled ?? false\"\n (refresh)=\"onLocalRefreshTrigger()\"\n ></c8y-auto-refresh-control>\n }\n\n @if (settings.showTimeContext) {\n @let isHistoryMode = form.get('refreshOption')?.value === REFRESH_OPTION.HISTORY;\n <c8y-date-time-context-picker\n style=\"margin-left: -1px\"\n formControlName=\"dateTimeContext\"\n [shouldDisableInterval]=\"getIntervalDisableConfig()\"\n [config]=\"\n isHistoryMode\n ? { showDateTo: true, showDateFrom: true }\n : { showDateTo: false, showDateFrom: true }\n \"\n ></c8y-date-time-context-picker>\n }\n\n @if (settings.showRefresh) {\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"'Refresh' | translate\"\n placement=\"bottom\"\n container=\"body\"\n type=\"button\"\n data-cy=\"global-inline-date-context--reload-button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"isLoading()\"\n (click)=\"refresh.emit(null)\"\n >\n <i\n [class.icon-spin]=\"isLoading()\"\n [c8yIcon]=\"'refresh'\"\n ></i>\n </button>\n </div>\n }\n </div>\n </form>\n }\n\n <ng-content select=\"#body\"></ng-content>\n</ng-template>\n\n@switch (effectiveConfig().displayMode) {\n @case (GLOBAL_CONTEXT_DISPLAY_MODE.CONFIG) {\n <ng-container [ngTemplateOutlet]=\"inlineContent\"></ng-container>\n }\n @case (GLOBAL_CONTEXT_DISPLAY_MODE.VIEW_AND_CONFIG) {\n <ng-container [ngTemplateOutlet]=\"headerContent\"></ng-container>\n <ng-container [ngTemplateOutlet]=\"inlineContent\"></ng-container>\n }\n @default {\n @if (shouldRenderHeaderInline()) {\n <ng-container [ngTemplateOutlet]=\"headerContent\"></ng-container>\n }\n <ng-container [ngTemplateOutlet]=\"inlineContent\"></ng-container>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: GlobalContextLinkControlsComponent, selector: "c8y-global-context-link-controls", inputs: ["linkStates", "controlConfigs"], outputs: ["allLinksToggled"] }, { kind: "component", type: AggregationPickerComponent, selector: "c8y-aggregation-picker", inputs: ["disabledAggregations", "resetToDefault", "layout"] }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", inputs: ["isAutoRefreshConnected", "autoRefreshSeconds", "disableCounter", "isEnabled", "isLoading"], outputs: ["loadingChange", "refresh"] }, { kind: "component", type: DateTimeContextPickerComponent, selector: "c8y-date-time-context-picker", inputs: ["disabled", "shouldDisableInterval", "config", "intervalOptions"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8897
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: GlobalContextInlineComponent, isStandalone: true, selector: "c8y-global-context-inline", inputs: { widgetControls: { classPropertyName: "widgetControls", publicName: "widgetControls", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, dashboardChildForLegacy: { classPropertyName: "dashboardChildForLegacy", publicName: "dashboardChildForLegacy", isSignal: true, isRequired: false, transformFunction: null }, disableRefreshEmits: { classPropertyName: "disableRefreshEmits", publicName: "disableRefreshEmits", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { refresh: "refresh", globalContextChange: "globalContextChange" }, providers: [GlobalContextInlineOrchestratorService], viewQueries: [{ propertyName: "headerTemplateRef", first: true, predicate: ["headerContent"], descendants: true, read: TemplateRef, static: true }], exportAs: ["globalContextInline"], ngImport: i0, template: "<ng-template #headerContent>\n @let linkModel = linkDisplayModel();\n <ng-content select=\"#header\"></ng-content>\n\n @if (shouldShowHeaderLinks()) {\n <c8y-global-context-link-controls\n [linkStates]=\"linkModel.linkStates\"\n [controlConfigs]=\"linkModel.controlConfig\"\n (allLinksToggled)=\"toggleAllLinks($event)\"\n ></c8y-global-context-link-controls>\n }\n</ng-template>\n\n<ng-template #inlineContent>\n @let settings = inlineSettings();\n @let linkModel = linkDisplayModel();\n\n @if (form && settings) {\n <form\n class=\"d-flex gap-16 p-l-16 p-r-16 inner-scroll\"\n [ngClass]=\"{\n 'p-b-8':\n settings.showTimeContext ||\n settings.showRefresh ||\n settings.showAutoRefresh ||\n settings.showAggregation\n }\"\n [formGroup]=\"form\"\n >\n <div class=\"input-group w-auto input-group-sm\">\n @if (settings.showAggregation) {\n <c8y-aggregation-picker\n data-cy=\"global-inline-date-context--Aggregation-display\"\n [disabledAggregations]=\"getDisabledAggregations()\"\n formControlName=\"aggregation\"\n [resetToDefault]=\"true\"\n ></c8y-aggregation-picker>\n }\n\n @if (settings.showAutoRefresh) {\n <c8y-auto-refresh-control\n [isLoading]=\"isLoading()\"\n [disableCounter]=\"shouldDisableCounter\"\n formControlName=\"isAutoRefreshEnabled\"\n [autoRefreshSeconds]=\"getAutoRefreshSeconds()\"\n [isAutoRefreshConnected]=\"linkModel.linkStates.isAutoRefreshEnabled ?? false\"\n (refresh)=\"onLocalRefreshTrigger()\"\n ></c8y-auto-refresh-control>\n }\n\n @if (settings.showTimeContext) {\n @let isHistoryMode = form.get('refreshOption')?.value === REFRESH_OPTION.HISTORY;\n <c8y-date-time-context-picker\n style=\"margin-left: -1px\"\n formControlName=\"dateTimeContext\"\n [shouldDisableInterval]=\"getIntervalDisableConfig()\"\n [config]=\"\n isHistoryMode\n ? { showDateTo: true, showDateFrom: true }\n : { showDateTo: false, showDateFrom: true }\n \"\n ></c8y-date-time-context-picker>\n }\n\n @if (settings.showRefresh) {\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"'Refresh' | translate\"\n placement=\"bottom\"\n container=\"body\"\n type=\"button\"\n data-cy=\"global-inline-date-context--reload-button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"isLoading()\"\n (click)=\"refresh.emit(null)\"\n >\n <i\n [class.icon-spin]=\"isLoading()\"\n [c8yIcon]=\"'refresh'\"\n ></i>\n </button>\n </div>\n }\n </div>\n </form>\n }\n\n <ng-content select=\"#body\"></ng-content>\n</ng-template>\n\n@switch (effectiveConfig().displayMode) {\n @case (GLOBAL_CONTEXT_DISPLAY_MODE.CONFIG) {\n <ng-container [ngTemplateOutlet]=\"inlineContent\"></ng-container>\n }\n @case (GLOBAL_CONTEXT_DISPLAY_MODE.VIEW_AND_CONFIG) {\n <ng-container [ngTemplateOutlet]=\"headerContent\"></ng-container>\n <ng-container [ngTemplateOutlet]=\"inlineContent\"></ng-container>\n }\n @default {\n @if (shouldRenderHeaderInline()) {\n <ng-container [ngTemplateOutlet]=\"headerContent\"></ng-container>\n }\n <ng-container [ngTemplateOutlet]=\"inlineContent\"></ng-container>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: GlobalContextLinkControlsComponent, selector: "c8y-global-context-link-controls", inputs: ["linkStates", "controlConfigs"], outputs: ["allLinksToggled"] }, { kind: "component", type: AggregationPickerComponent, selector: "c8y-aggregation-picker", inputs: ["disabledAggregations", "resetToDefault", "layout", "showAutoMode", "autoModeActive", "autoModeDisabled"], outputs: ["autoModeChange"] }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", inputs: ["isAutoRefreshConnected", "autoRefreshSeconds", "disableCounter", "isEnabled", "isLoading"], outputs: ["loadingChange", "refresh"] }, { kind: "component", type: DateTimeContextPickerComponent, selector: "c8y-date-time-context-picker", inputs: ["disabled", "shouldDisableInterval", "config", "intervalOptions"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8645
8898
  }
8646
8899
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: GlobalContextInlineComponent, decorators: [{
8647
8900
  type: Component,
@@ -9523,7 +9776,7 @@ class GlobalContextWidgetConfigComponent {
9523
9776
  ></c8y-global-context-config>
9524
9777
  </fieldset>
9525
9778
  }
9526
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ConfigContextSelectorComponent, selector: "c8y-config-context-selector" }, { kind: "component", type: GlobalContextConfigComponent, selector: "c8y-global-context-config", inputs: ["config", "isLoading", "widgetControls", "liveSnapshot", "historySnapshot"], outputs: ["refresh", "globalContextChange"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i2$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9779
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ConfigContextSelectorComponent, selector: "c8y-config-context-selector" }, { kind: "component", type: GlobalContextConfigComponent, selector: "c8y-global-context-config", inputs: ["config", "isLoading", "widgetControls", "liveSnapshot", "historySnapshot"], outputs: ["refresh", "globalContextChange"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i3.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9527
9780
  }
9528
9781
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: GlobalContextWidgetConfigComponent, decorators: [{
9529
9782
  type: Component,
@@ -9746,7 +9999,7 @@ class PreviewControlsComponent {
9746
9999
  this.config.displayMode = GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD;
9747
10000
  }
9748
10001
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: PreviewControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9749
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: PreviewControlsComponent, isStandalone: true, selector: "c8y-preview-controls", inputs: { widgetControls: "widgetControls", config: "config" }, ngImport: i0, template: "<!-- Main Controls -->\n@let isConfigMode = config?.displayMode === GLOBAL_CONTEXT_DISPLAY_MODE.CONFIG;\n@let settings = inlineControlsSettings$ | async;\n\n@if (form && settings) {\n <form\n class=\"d-flex gap-16 p-l-16 p-r-16 p-b-8 inner-scroll\"\n [formGroup]=\"form\"\n >\n <!-- Control Group Container -->\n <div class=\"input-group w-auto\">\n <!-- Aggregation Picker -->\n @if (settings.showAggregation) {\n <c8y-aggregation-picker\n formControlName=\"aggregation\"\n [resetToDefault]=\"true\"\n ></c8y-aggregation-picker>\n }\n\n <!-- Auto Refresh Controls -->\n @if (settings.showAutoRefresh) {\n <!-- Auto Refresh Toggle -->\n <c8y-auto-refresh-control\n [isLoading]=\"isLoading\"\n [disableCounter]=\"shouldDisableCounter\"\n formControlName=\"isAutoRefreshEnabled\"\n [autoRefreshSeconds]=\"form.get('refreshInterval')?.value\"\n ></c8y-auto-refresh-control>\n }\n\n @if (settings.showTimeContext) {\n @let isHistoryMode = form.get('refreshOption')?.value === REFRESH_OPTION.HISTORY;\n @let configValue =\n isHistoryMode\n ? {\n showDateTo: true,\n showDateFrom: true\n }\n : {\n showDateTo: false,\n showDateFrom: true\n };\n <c8y-date-time-context-picker\n style=\"margin-left: -1px\"\n formControlName=\"dateTimeContext\"\n [shouldDisableInterval]=\"shouldDisableCustomInterval\"\n [config]=\"configValue\"\n ></c8y-date-time-context-picker>\n }\n\n <!-- Manual Refresh Button -->\n @if (settings.showRefresh) {\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"'Refresh' | translate\"\n placement=\"bottom\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"isLoading\"\n >\n <i\n [class.icon-spin]=\"isLoading\"\n [c8yIcon]=\"'refresh'\"\n ></i>\n </button>\n </div>\n }\n </div>\n </form>\n}\n", styles: [":host{position:relative;display:block;cursor:not-allowed}:host form{position:relative;pointer-events:none;-webkit-user-select:none;user-select:none}:host form:after{content:\"\";position:absolute;inset:0;background:#ffffff0d;z-index:1;pointer-events:none}:host form button,:host form input,:host form select,:host form .dropdown-toggle,:host form .btn{cursor:not-allowed!important;opacity:.85}:host form *{pointer-events:none!important;-webkit-user-select:none!important;user-select:none!important}\n"], dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: DateTimeContextPickerComponent, selector: "c8y-date-time-context-picker", inputs: ["disabled", "shouldDisableInterval", "config", "intervalOptions"] }, { kind: "component", type: AggregationPickerComponent, selector: "c8y-aggregation-picker", inputs: ["disabledAggregations", "resetToDefault", "layout"] }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", inputs: ["isAutoRefreshConnected", "autoRefreshSeconds", "disableCounter", "isEnabled", "isLoading"], outputs: ["loadingChange", "refresh"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
10002
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: PreviewControlsComponent, isStandalone: true, selector: "c8y-preview-controls", inputs: { widgetControls: "widgetControls", config: "config" }, ngImport: i0, template: "<!-- Main Controls -->\n@let isConfigMode = config?.displayMode === GLOBAL_CONTEXT_DISPLAY_MODE.CONFIG;\n@let settings = inlineControlsSettings$ | async;\n\n@if (form && settings) {\n <form\n class=\"d-flex gap-16 p-l-16 p-r-16 p-b-8 inner-scroll\"\n [formGroup]=\"form\"\n >\n <!-- Control Group Container -->\n <div class=\"input-group w-auto\">\n <!-- Aggregation Picker -->\n @if (settings.showAggregation) {\n <c8y-aggregation-picker\n formControlName=\"aggregation\"\n [resetToDefault]=\"true\"\n ></c8y-aggregation-picker>\n }\n\n <!-- Auto Refresh Controls -->\n @if (settings.showAutoRefresh) {\n <!-- Auto Refresh Toggle -->\n <c8y-auto-refresh-control\n [isLoading]=\"isLoading\"\n [disableCounter]=\"shouldDisableCounter\"\n formControlName=\"isAutoRefreshEnabled\"\n [autoRefreshSeconds]=\"form.get('refreshInterval')?.value\"\n ></c8y-auto-refresh-control>\n }\n\n @if (settings.showTimeContext) {\n @let isHistoryMode = form.get('refreshOption')?.value === REFRESH_OPTION.HISTORY;\n @let configValue =\n isHistoryMode\n ? {\n showDateTo: true,\n showDateFrom: true\n }\n : {\n showDateTo: false,\n showDateFrom: true\n };\n <c8y-date-time-context-picker\n style=\"margin-left: -1px\"\n formControlName=\"dateTimeContext\"\n [shouldDisableInterval]=\"shouldDisableCustomInterval\"\n [config]=\"configValue\"\n ></c8y-date-time-context-picker>\n }\n\n <!-- Manual Refresh Button -->\n @if (settings.showRefresh) {\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Refresh' | translate\"\n [tooltip]=\"'Refresh' | translate\"\n placement=\"bottom\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n [disabled]=\"isLoading\"\n >\n <i\n [class.icon-spin]=\"isLoading\"\n [c8yIcon]=\"'refresh'\"\n ></i>\n </button>\n </div>\n }\n </div>\n </form>\n}\n", styles: [":host{position:relative;display:block;cursor:not-allowed}:host form{position:relative;pointer-events:none;-webkit-user-select:none;user-select:none}:host form:after{content:\"\";position:absolute;inset:0;background:#ffffff0d;z-index:1;pointer-events:none}:host form button,:host form input,:host form select,:host form .dropdown-toggle,:host form .btn{cursor:not-allowed!important;opacity:.85}:host form *{pointer-events:none!important;-webkit-user-select:none!important;user-select:none!important}\n"], dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: DateTimeContextPickerComponent, selector: "c8y-date-time-context-picker", inputs: ["disabled", "shouldDisableInterval", "config", "intervalOptions"] }, { kind: "component", type: AggregationPickerComponent, selector: "c8y-aggregation-picker", inputs: ["disabledAggregations", "resetToDefault", "layout", "showAutoMode", "autoModeActive", "autoModeDisabled"], outputs: ["autoModeChange"] }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", inputs: ["isAutoRefreshConnected", "autoRefreshSeconds", "disableCounter", "isEnabled", "isLoading"], outputs: ["loadingChange", "refresh"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9750
10003
  }
9751
10004
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: PreviewControlsComponent, decorators: [{
9752
10005
  type: Component,
@@ -10866,7 +11119,13 @@ const CONTEXT_FEATURE = {
10866
11119
  /** Manual refresh button - live mode only */
10867
11120
  REFRESH_LIVE: 'refreshLive',
10868
11121
  /** Manual refresh button - history mode only */
10869
- REFRESH_HISTORY: 'refreshHistory'
11122
+ REFRESH_HISTORY: 'refreshHistory',
11123
+ /**
11124
+ * Automatic aggregation mode ("Auto"). Computes the interval from the time frame and a target
11125
+ * datapoint count. Only meaningful for the Data graph widget; presets without it keep the
11126
+ * "Auto" option visible but disabled.
11127
+ */
11128
+ AUTO_AGGREGATION: 'autoAggregation'
10870
11129
  };
10871
11130
  /** Preset name constants for type-safe access */
10872
11131
  const PRESET_NAME = {
@@ -11041,6 +11300,7 @@ const CONTROL_PRESETS = {
11041
11300
  CONTEXT_FEATURE.HISTORY_TIME,
11042
11301
  CONTEXT_FEATURE.AUTO_REFRESH,
11043
11302
  CONTEXT_FEATURE.AGGREGATION,
11303
+ CONTEXT_FEATURE.AUTO_AGGREGATION,
11044
11304
  CONTEXT_FEATURE.REFRESH
11045
11305
  ],
11046
11306
  config: [CONTEXT_FEATURE.AUTO_REFRESH, CONTEXT_FEATURE.REFRESH],
@@ -11048,6 +11308,7 @@ const CONTROL_PRESETS = {
11048
11308
  CONTEXT_FEATURE.LIVE_TIME,
11049
11309
  CONTEXT_FEATURE.HISTORY_TIME,
11050
11310
  CONTEXT_FEATURE.AGGREGATION,
11311
+ CONTEXT_FEATURE.AUTO_AGGREGATION,
11051
11312
  CONTEXT_FEATURE.AUTO_REFRESH,
11052
11313
  CONTEXT_FEATURE.REFRESH
11053
11314
  ]
@@ -11059,6 +11320,7 @@ const CONTROL_PRESETS = {
11059
11320
  CONTEXT_FEATURE.HISTORY_TIME,
11060
11321
  CONTEXT_FEATURE.AUTO_REFRESH,
11061
11322
  CONTEXT_FEATURE.AGGREGATION,
11323
+ CONTEXT_FEATURE.AUTO_AGGREGATION,
11062
11324
  CONTEXT_FEATURE.REFRESH
11063
11325
  ],
11064
11326
  config: [
@@ -11066,12 +11328,14 @@ const CONTROL_PRESETS = {
11066
11328
  CONTEXT_FEATURE.HISTORY_TIME,
11067
11329
  CONTEXT_FEATURE.AUTO_REFRESH,
11068
11330
  CONTEXT_FEATURE.AGGREGATION,
11331
+ CONTEXT_FEATURE.AUTO_AGGREGATION,
11069
11332
  CONTEXT_FEATURE.REFRESH
11070
11333
  ],
11071
11334
  view_and_config: [
11072
11335
  CONTEXT_FEATURE.LIVE_TIME,
11073
11336
  CONTEXT_FEATURE.HISTORY_TIME,
11074
11337
  CONTEXT_FEATURE.AGGREGATION,
11338
+ CONTEXT_FEATURE.AUTO_AGGREGATION,
11075
11339
  CONTEXT_FEATURE.AUTO_REFRESH,
11076
11340
  CONTEXT_FEATURE.REFRESH
11077
11341
  ]
@@ -11206,6 +11470,9 @@ function controlsToSettings(controls, displayMode, refreshOption) {
11206
11470
  showAutoRefresh: activeControls.includes(CONTEXT_FEATURE.AUTO_REFRESH),
11207
11471
  showRefreshInterval: false,
11208
11472
  showAggregation: activeControls.includes(CONTEXT_FEATURE.AGGREGATION),
11473
+ // The "Auto" aggregation option stays visible everywhere but is only selectable for presets
11474
+ // that opt in via AUTO_AGGREGATION (the Data graph widget). Elsewhere it is greyed out.
11475
+ autoModeDisabled: !activeControls.includes(CONTEXT_FEATURE.AUTO_AGGREGATION),
11209
11476
  showRefresh: activeControls.includes(CONTEXT_FEATURE.REFRESH) ||
11210
11477
  activeControls.includes(CONTEXT_FEATURE.REFRESH_LIVE) ||
11211
11478
  activeControls.includes(CONTEXT_FEATURE.REFRESH_HISTORY)
@@ -11265,11 +11532,15 @@ class ConfigModeControls {
11265
11532
  onRefreshOptionChange(option) {
11266
11533
  this.refreshOption.set(option);
11267
11534
  const snapshot = option === REFRESH_OPTION.LIVE ? this.liveState() : this.historyState();
11535
+ const base = snapshot ?? this.config();
11536
+ const isLive = option === REFRESH_OPTION.LIVE;
11268
11537
  const context = {
11269
- ...(snapshot ?? this.config()),
11538
+ ...base,
11270
11539
  refreshOption: option,
11271
11540
  displayMode: this.displayMode(),
11272
- aggregation: option === REFRESH_OPTION.LIVE ? null : (snapshot ?? this.config()).aggregation
11541
+ aggregation: isLive ? null : base.aggregation,
11542
+ autoAggregation: isLive ? null : base.autoAggregation,
11543
+ aggregationFunction: isLive ? null : base.aggregationFunction
11273
11544
  };
11274
11545
  this.emit(context);
11275
11546
  }
@@ -11320,13 +11591,30 @@ class ConfigModeControls {
11320
11591
  }
11321
11592
  /** Emits configChange if the diff contains changes beyond transient flags. */
11322
11593
  emit(context) {
11323
- const diff = this.globalContextUtils.getChangedFields(this.lastEmittedContext(), context);
11594
+ const cleanContext = this.toContextState(context);
11595
+ const diff = this.globalContextUtils.getChangedFields(this.lastEmittedContext(), cleanContext);
11324
11596
  const substantiveDiff = { ...diff };
11325
11597
  delete substantiveDiff.isGlobalContextReady;
11326
11598
  if (Object.keys(substantiveDiff).length === 0)
11327
11599
  return;
11328
- this.lastEmittedContext.set(context);
11329
- this.configChange.emit({ context, diff });
11600
+ this.lastEmittedContext.set(cleanContext);
11601
+ this.configChange.emit({ context: cleanContext, diff });
11602
+ }
11603
+ /** Picks only known GlobalContextState fields, dropping any extra properties (e.g. datapoints) that callers may pass at runtime. */
11604
+ toContextState(cfg) {
11605
+ return {
11606
+ dateTimeContext: cfg.dateTimeContext,
11607
+ aggregation: cfg.aggregation,
11608
+ aggregationFunction: cfg.aggregationFunction,
11609
+ autoAggregation: cfg.autoAggregation,
11610
+ isAutoRefreshEnabled: cfg.isAutoRefreshEnabled,
11611
+ refreshInterval: cfg.refreshInterval,
11612
+ refreshOption: cfg.refreshOption,
11613
+ displayMode: cfg.displayMode,
11614
+ source: cfg.source,
11615
+ eventSourceId: cfg.eventSourceId,
11616
+ isGlobalContextReady: cfg.isGlobalContextReady
11617
+ };
11330
11618
  }
11331
11619
  getGlobalContextState(mode) {
11332
11620
  const globalState = this.globalContextEventService.getLatestValue(GLOBAL_CONTEXT_EVENTS.STATE_CHANGE);
@@ -11336,6 +11624,7 @@ class ConfigModeControls {
11336
11624
  dateTimeContext: globalState.dateTimeContext,
11337
11625
  refreshOption: globalState.refreshOption,
11338
11626
  aggregation: globalState.aggregation,
11627
+ autoAggregation: globalState.autoAggregation ?? null,
11339
11628
  isAutoRefreshEnabled: globalState.isAutoRefreshEnabled,
11340
11629
  refreshInterval: globalState.refreshInterval,
11341
11630
  isGlobalContextReady: true
@@ -11385,7 +11674,7 @@ class ConfigModeControls {
11385
11674
  ></c8y-configuration-controls>
11386
11675
  </fieldset>
11387
11676
  }
11388
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ConfigContextSelectorComponent, selector: "c8y-config-context-selector" }, { kind: "component", type: ConfigurationControlsComponent, selector: "c8y-configuration-controls", inputs: ["controlsDisplayMode", "settings", "activeMode", "liveContext", "historyContext", "supportedModes", "intervalOptions", "tabsOutletName"], outputs: ["refreshOptionChange", "contextChange", "validationStatus"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i2$2.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
11677
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ConfigContextSelectorComponent, selector: "c8y-config-context-selector" }, { kind: "component", type: ConfigurationControlsComponent, selector: "c8y-configuration-controls", inputs: ["controlsDisplayMode", "settings", "activeMode", "liveContext", "historyContext", "supportedModes", "intervalOptions", "tabsOutletName"], outputs: ["refreshOptionChange", "contextChange", "validationStatus"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i3.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
11389
11678
  }
11390
11679
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ConfigModeControls, decorators: [{
11391
11680
  type: Component,
@@ -11451,6 +11740,7 @@ class ContextControlsComponent {
11451
11740
  this.fb = inject(FormBuilder);
11452
11741
  this.aggregationValidationService = inject(AggregationValidationService);
11453
11742
  this.globalContextUtils = inject(GlobalContextUtilsService);
11743
+ this.timeSeriesMigrationService = inject(TimeSeriesMigrationService);
11454
11744
  this.controls = input(PRESET_NAME.DEFAULT, ...(ngDevMode ? [{ debugName: "controls" }] : /* istanbul ignore next */ []));
11455
11745
  this.displayMode = input(GLOBAL_CONTEXT_DISPLAY_MODE.DASHBOARD, ...(ngDevMode ? [{ debugName: "displayMode" }] : /* istanbul ignore next */ []));
11456
11746
  this.config = input.required(...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
@@ -11488,6 +11778,12 @@ class ContextControlsComponent {
11488
11778
  */
11489
11779
  this.refresh = output();
11490
11780
  this.lastEmittedState = signal({}, ...(ngDevMode ? [{ debugName: "lastEmittedState" }] : /* istanbul ignore next */ []));
11781
+ this._isAutoModeActive = signal(false, ...(ngDevMode ? [{ debugName: "_isAutoModeActive" }] : /* istanbul ignore next */ []));
11782
+ /**
11783
+ * The "Auto" aggregation option requires the tenant to be migrated to time series
11784
+ * (auto mode uses `aggregationInterval`, unsupported on non-migrated tenants).
11785
+ */
11786
+ this.isTimeSeriesMigrated = signal(false, ...(ngDevMode ? [{ debugName: "isTimeSeriesMigrated" }] : /* istanbul ignore next */ []));
11491
11787
  this.visibleControls = computed(() => {
11492
11788
  const cfg = this.config();
11493
11789
  if (!cfg)
@@ -11513,6 +11809,7 @@ class ContextControlsComponent {
11513
11809
  }
11514
11810
  return normalized;
11515
11811
  }, ...(ngDevMode ? [{ debugName: "visibleControls" }] : /* istanbul ignore next */ []));
11812
+ this.isAutoModeActive = this._isAutoModeActive.asReadonly();
11516
11813
  this.disabledAggregations = computed(() => {
11517
11814
  const dateCtx = this.config()?.dateTimeContext;
11518
11815
  if (!dateCtx)
@@ -11537,6 +11834,12 @@ class ContextControlsComponent {
11537
11834
  });
11538
11835
  this.syncConfigToForm();
11539
11836
  this.subscribeToFormChanges();
11837
+ effect(() => {
11838
+ this._isAutoModeActive.set(!!this.config()?.autoAggregation);
11839
+ });
11840
+ this.timeSeriesMigrationService
11841
+ .isTimeSeriesMigrated()
11842
+ .then(isMigrated => this.isTimeSeriesMigrated.set(isMigrated));
11540
11843
  }
11541
11844
  ngOnInit() {
11542
11845
  this.emitInitialNonDashboardState();
@@ -11546,6 +11849,15 @@ class ContextControlsComponent {
11546
11849
  this.onRefresh();
11547
11850
  }
11548
11851
  }
11852
+ onAutoModeChange(isAuto) {
11853
+ this._isAutoModeActive.set(isAuto);
11854
+ const context = {
11855
+ ...this.config(),
11856
+ aggregation: isAuto ? null : (this.form.get('aggregation')?.value ?? null),
11857
+ autoAggregation: isAuto ? { datapoints: AUTO_AGGREGATION_DATAPOINTS.DEFAULT } : null
11858
+ };
11859
+ this.emitIfChanged(context);
11860
+ }
11549
11861
  onRefresh() {
11550
11862
  const cfg = this.config();
11551
11863
  if (!cfg.dateTimeContext) {
@@ -11596,7 +11908,12 @@ class ContextControlsComponent {
11596
11908
  subscribeToFormChanges() {
11597
11909
  this.form.valueChanges.pipe(takeUntilDestroyed()).subscribe(value => {
11598
11910
  const context = this.clearInvalidAggregation(value);
11599
- this.emitIfChanged(context);
11911
+ // Preserve aggregation-related fields in history mode; clear them when switching to live.
11912
+ const isLive = context.refreshOption === REFRESH_OPTION.LIVE;
11913
+ const cfg = this.config();
11914
+ const autoAgg = isLive ? null : (cfg?.autoAggregation ?? null);
11915
+ const aggregationFunction = isLive ? null : (cfg?.aggregationFunction ?? null);
11916
+ this.emitIfChanged({ ...context, autoAggregation: autoAgg, aggregationFunction });
11600
11917
  });
11601
11918
  }
11602
11919
  /** Clears aggregation if in LIVE mode or invalid for current time range (HISTORY mode). */
@@ -11634,7 +11951,12 @@ class ContextControlsComponent {
11634
11951
  data-cy="global-inline-date-context--Aggregation-display"
11635
11952
  formControlName="aggregation"
11636
11953
  [disabledAggregations]="disabledAggregations()"
11954
+ [autoModeActive]="isAutoModeActive()"
11955
+ [showAutoMode]="
11956
+ visibleControls()?.includes('autoAggregation') && isTimeSeriesMigrated()
11957
+ "
11637
11958
  [resetToDefault]="true"
11959
+ (autoModeChange)="onAutoModeChange($event)"
11638
11960
  >
11639
11961
  </c8y-aggregation-picker>
11640
11962
  }
@@ -11680,7 +12002,7 @@ class ContextControlsComponent {
11680
12002
  }
11681
12003
  </div>
11682
12004
  </form>
11683
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: DateTimeContextPickerComponent, selector: "c8y-date-time-context-picker", inputs: ["disabled", "shouldDisableInterval", "config", "intervalOptions"] }, { kind: "component", type: AggregationPickerComponent, selector: "c8y-aggregation-picker", inputs: ["disabledAggregations", "resetToDefault", "layout"] }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", inputs: ["isAutoRefreshConnected", "autoRefreshSeconds", "disableCounter", "isEnabled", "isLoading"], outputs: ["loadingChange", "refresh"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
12005
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: DateTimeContextPickerComponent, selector: "c8y-date-time-context-picker", inputs: ["disabled", "shouldDisableInterval", "config", "intervalOptions"] }, { kind: "component", type: AggregationPickerComponent, selector: "c8y-aggregation-picker", inputs: ["disabledAggregations", "resetToDefault", "layout", "showAutoMode", "autoModeActive", "autoModeDisabled"], outputs: ["autoModeChange"] }, { kind: "component", type: AutoRefreshControlComponent, selector: "c8y-auto-refresh-control", inputs: ["isAutoRefreshConnected", "autoRefreshSeconds", "disableCounter", "isEnabled", "isLoading"], outputs: ["loadingChange", "refresh"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i2.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
11684
12006
  }
11685
12007
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ContextControlsComponent, decorators: [{
11686
12008
  type: Component,
@@ -11704,7 +12026,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
11704
12026
  data-cy="global-inline-date-context--Aggregation-display"
11705
12027
  formControlName="aggregation"
11706
12028
  [disabledAggregations]="disabledAggregations()"
12029
+ [autoModeActive]="isAutoModeActive()"
12030
+ [showAutoMode]="
12031
+ visibleControls()?.includes('autoAggregation') && isTimeSeriesMigrated()
12032
+ "
11707
12033
  [resetToDefault]="true"
12034
+ (autoModeChange)="onAutoModeChange($event)"
11708
12035
  >
11709
12036
  </c8y-aggregation-picker>
11710
12037
  }
@@ -12050,8 +12377,18 @@ class GlobalContextConnectorComponent {
12050
12377
  this.linkedChange.emit(linked);
12051
12378
  if (linked) {
12052
12379
  const cached = this.eventService.getLatestValue(GLOBAL_CONTEXT_EVENTS.STATE_CHANGE);
12053
- if (cached)
12054
- this.emitIfChanged(cached);
12380
+ if (cached) {
12381
+ // Normalize auto-aggregation fields to null when absent from the cached GC state.
12382
+ // getChangedFields() only iterates the new state's keys, so if the user enabled
12383
+ // autoAggregation locally while unlinked, the diff would be empty (the key is absent
12384
+ // from the GC state) and the widget would not re-sync to the GC aggregation.
12385
+ const normalizedState = {
12386
+ autoAggregation: null,
12387
+ aggregationFunction: null,
12388
+ ...cached
12389
+ };
12390
+ this.emitIfChanged(normalizedState);
12391
+ }
12055
12392
  }
12056
12393
  }
12057
12394
  onLocalChange(event) {
@@ -12332,5 +12669,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
12332
12669
  * Generated bundle index. Do not edit.
12333
12670
  */
12334
12671
 
12335
- export { AGGREGATIONS, AGGREGATION_ICONS, AGGREGATION_ICON_TYPE, AGGREGATION_LABELS, AGGREGATION_LIMITS, AGGREGATION_TEXTS, AGGREGATION_VALUES, AGGREGATION_VALUES_ARR, AggregationDisplayComponent, AggregationPickerComponent, AggregationPickerService, AggregationValidationService, AutoRefreshControlComponent, CONTEXT_FEATURE, CONTROL_PRESETS, ConfigContextSelectorComponent, ConfigModeControls, ConfigModeControls as ConfigModeControlsComponent, ConfigurationCollapseComponent, ConfigurationControlsComponent, ContextControlsComponent$1 as ContextControlsComponent, DEFAULT_WIDGET_TEMPLATE, DateContextQueryParamNames, DateTimeContextPickerComponent, DateTimeContextPickerService, DateTimeContextUtil, GLOBAL_CONTEXT_DASHBOARD_PATHS, GLOBAL_CONTEXT_DEFAULTS, GLOBAL_CONTEXT_DISPLAY_MODE, GLOBAL_CONTEXT_EVENTS, GLOBAL_CONTEXT_SOURCE, GlobalContextComponent, GlobalContextConfigComponent, GlobalContextConnectorComponent, GlobalContextEventService, GlobalContextFormService, GlobalContextInlineComponent, GlobalContextLinkControlsComponent, GlobalContextModule, GlobalContextNavigationService, GlobalContextQueryService, GlobalContextService, GlobalContextUtilsService, GlobalContextValidationService, GlobalContextWidgetConfigComponent, GlobalContextWidgetWrapperComponent, HistoryModeConfigurationControlsComponent, INTERVALS, INTERVAL_TITLES, IntervalPickerComponent, LIFETIME_INTERVAL, LINK_BTNS_CONFIG, LinkButtonsComponent, LiveModeConfigurationControlsComponent, LocalControlsComponent, PRESET_NAME, PreviewControlsComponent, REFRESH_OPTION, ROUTE_PATHS, RealtimeControlComponent, TIME_DURATION, TIME_INTERVAL, TIME_SPAN_MS, TIMING, TimeRangeDisplayComponent, UI_PRIORITIES, WIDGET_DISPLAY_MODE, WIDGET_FEATURE_MAP, WidgetConfigMigrationService, WidgetControlService, applyModeConstraints, buildAggregationExtensions, buildBaselineControls, buildWidgetControlsFromPresets, controlsToSettings, createAutoRefreshHandlers, createResult, defineWidgetControls, getSupportedModes, guards, isAggregationLinked, isAggregationUnlinked, isAutoRefreshDisabled, isAutoRefreshEnabled, isConfig, isDashboard, isDateTimeContextLinked, isDateTimeContextUnlinked, isHistory, isLive, isViewAndConfig, mergePartialControls, resolveWidgetControlsInput, setAutoRefreshControlsVisibility, setAutoRefreshLinks, updateBothSettings };
12672
+ export { AGGREGATIONS, AGGREGATION_ICONS, AGGREGATION_ICON_TYPE, AGGREGATION_LABELS, AGGREGATION_LIMITS, AGGREGATION_POPOVER_TEXT, AGGREGATION_TEXTS, AGGREGATION_VALUES, AGGREGATION_VALUES_ARR, AUTO_AGGREGATION_DATAPOINTS, AUTO_AGGREGATION_TEXT, AUTO_AGGREGATION_TEXT_LONG, AggregationDisplayComponent, AggregationPickerComponent, AggregationPickerService, AggregationValidationService, AutoRefreshControlComponent, CONTEXT_FEATURE, CONTROL_PRESETS, ConfigContextSelectorComponent, ConfigModeControls, ConfigModeControls as ConfigModeControlsComponent, ConfigurationCollapseComponent, ConfigurationControlsComponent, ContextControlsComponent$1 as ContextControlsComponent, DEFAULT_WIDGET_TEMPLATE, DateContextQueryParamNames, DateTimeContextPickerComponent, DateTimeContextPickerService, DateTimeContextUtil, GLOBAL_CONTEXT_DASHBOARD_PATHS, GLOBAL_CONTEXT_DEFAULTS, GLOBAL_CONTEXT_DISPLAY_MODE, GLOBAL_CONTEXT_EVENTS, GLOBAL_CONTEXT_SOURCE, GlobalContextComponent, GlobalContextConfigComponent, GlobalContextConnectorComponent, GlobalContextEventService, GlobalContextFormService, GlobalContextInlineComponent, GlobalContextLinkControlsComponent, GlobalContextModule, GlobalContextNavigationService, GlobalContextQueryService, GlobalContextService, GlobalContextUtilsService, GlobalContextValidationService, GlobalContextWidgetConfigComponent, GlobalContextWidgetWrapperComponent, HistoryModeConfigurationControlsComponent, INTERVALS, INTERVAL_TITLES, IntervalPickerComponent, LIFETIME_INTERVAL, LINK_BTNS_CONFIG, LinkButtonsComponent, LiveModeConfigurationControlsComponent, LocalControlsComponent, PRESET_NAME, PreviewControlsComponent, REFRESH_OPTION, ROUTE_PATHS, RealtimeControlComponent, TIME_DURATION, TIME_INTERVAL, TIME_SPAN_MS, TIMING, TimeRangeDisplayComponent, TimeSeriesMigrationService, UI_PRIORITIES, WIDGET_DISPLAY_MODE, WIDGET_FEATURE_MAP, WidgetConfigMigrationService, WidgetControlService, applyModeConstraints, buildAggregationExtensions, buildBaselineControls, buildWidgetControlsFromPresets, controlsToSettings, createAutoRefreshHandlers, createResult, defineWidgetControls, getSupportedModes, guards, isAggregationLinked, isAggregationUnlinked, isAutoRefreshDisabled, isAutoRefreshEnabled, isConfig, isDashboard, isDateTimeContextLinked, isDateTimeContextUnlinked, isHistory, isLive, isViewAndConfig, mergePartialControls, resolveWidgetControlsInput, setAutoRefreshControlsVisibility, setAutoRefreshLinks, updateBothSettings };
12336
12673
  //# sourceMappingURL=c8y-ngx-components-global-context.mjs.map