UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

1,245 lines 114 kB
import * as i0 from '@angular/core';
import { Injectable, signal, inject, EventEmitter, Output, Input, Component, DestroyRef, ViewChild } from '@angular/core';
import { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from 'lz-string';
import * as i2 from '@c8y/ngx-components';
import { AlertService, MOChunkLoaderService, DatapointSyncService, ContextRouteService, ClipboardService, ViewContext, CoreModule, Permissions, GainsightService, CommonModule, FormsModule as FormsModule$1, WidgetTimeContextDateRangeService, IconDirective } from '@c8y/ngx-components';
import { gettext } from '@c8y/ngx-components/gettext';
import * as i5 from '@angular/cdk/a11y';
import { A11yModule } from '@angular/cdk/a11y';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import * as i2$1 from '@angular/forms';
import { FormBuilder, FormsModule, ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';
import { Router, ActivatedRoute, NavigationStart } from '@angular/router';
import * as i4$1 from '@c8y/ngx-components/alarm-event-selector';
import { AlarmEventSelectorModule } from '@c8y/ngx-components/alarm-event-selector';
import * as i1 from '@c8y/ngx-components/context-dashboard';
import { ContextDashboardService, ContextDashboardType, ContextDashboardModule } from '@c8y/ngx-components/context-dashboard';
import * as i3$1 from '@c8y/ngx-components/datapoint-selector';
import { DatapointSelectorModule } from '@c8y/ngx-components/datapoint-selector';
import { DatapointsExportSelectorComponent } from '@c8y/ngx-components/datapoints-export-selector';
import { CHART_VIEW_CONTEXT, PRODUCT_EXPERIENCE_DATA_EXPLORER_AND_GRAPH } from '@c8y/ngx-components/echart/models';
import { ChartHelpersService, ChartsComponent, ChartEventsService, ChartAlarmsService } from '@c8y/ngx-components/echart';
import * as i4 from 'ngx-bootstrap/dropdown';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import * as i6 from 'ngx-bootstrap/tooltip';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { PopoverModule } from 'ngx-bootstrap/popover';
import { INTERVALS } from '@c8y/ngx-components/interval-picker';
import { TimeContextComponent } from '@c8y/ngx-components/time-context';
import { BsModalService } from 'ngx-bootstrap/modal';
import { firstValueFrom, merge, of, map as map$1 } from 'rxjs';
import { InventoryService } from '@c8y/client';
import * as i3 from '@angular/common';
import { ReportDashboardModule, ReportDashboardService } from '@c8y/ngx-components/report-dashboard';
import { map } from 'rxjs/operators';

const adjectives = [
    'caffeinated',
    'sleepy',
    'hungry',
    'puzzled',
    'overexcited',
    'daydreaming',
    'chocolate-loving',
    'coffee-powered',
    'cookie-craving',
    'disco-ready',
    'weekend-mode',
    'pizza-powered',
    'nap-seeking',
    'wifi-hunting',
    'battery-hungry',
    'donut-powered',
    'tea-sipping',
    'keyboard-loving',
    'screen-staring',
    'mouse-chasing',
    'code-dreaming',
    'pixel-perfect',
    'bug-finding',
    'zoom-tired',
    'meeting-dodging',
    'deadline-racing',
    'coffee-seeking',
    'sandwich-craving',
    'debug-ready',
    'rest-needing'
];
const nouns = [
    'sensor',
    'robot',
    'thermostat',
    'gateway',
    'dashboard',
    'widget',
    'gadget',
    'button',
    'antenna',
    'beacon',
    'adapter',
    'gizmo',
    'hub',
    'switch',
    'chip',
    'controller',
    'display',
    'terminal',
    'processor',
    'transmitter',
    'receiver',
    'pod',
    'device',
    'module',
    'relay',
    'node',
    'bridge',
    'screen',
    'router',
    'box'
];

class NameGeneratorService {
    generateName() {
        const getRandomElement = (arr) => arr[Math.floor(Math.random() * arr.length)];
        const randomAdjective = getRandomElement(adjectives);
        const randomNoun = getRandomElement(nouns);
        return `${randomAdjective}_${randomNoun}`;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NameGeneratorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NameGeneratorService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NameGeneratorService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

const DATA_EXPLORER_BASE_CONFIG = {
    datapoints: [],
    alarmsEventsConfigs: [],
    dateFrom: null,
    dateTo: null,
    interval: 'hours',
    aggregation: null,
    realtime: false,
    isAutoRefreshEnabled: false,
    refreshInterval: 0,
    displayMarkedLine: true,
    displayMarkedPoint: true,
    mergeMatchingDatapoints: false,
    forceMergeDatapoints: false,
    showLabelAndUnit: true,
    showSlider: true,
    displayDateSelection: false,
    yAxisSplitLines: false,
    xAxisSplitLines: false,
    numberOfDecimalPlaces: 2
};
const REVERSE_KEY_MAP = {
    d: 'datapoints',
    a: 'alarmsEventsConfigs',
    f: 'fragment',
    s: 'series',
    t: '__target',
    m: '__template',
    l: 'label',
    r: 'filters',
    y: 'timelineType',
    df: 'dateFrom',
    dt: 'dateTo',
    ac: '__active',
    c: 'color',
    i: 'id',
    tp: 'type'
};
const KEY_MAP = Object.fromEntries(Object.entries(REVERSE_KEY_MAP).map(([shortKey, longKey]) => [longKey, shortKey]));

class WorkspaceConfigurationService {
    constructor() {
        this.baseKey = 'c8y-configs';
        this.baseDefaultKey = 'c8y-default-config-id';
        this.contextIdSignal = signal(null, ...(ngDevMode ? [{ debugName: "contextIdSignal" }] : []));
        this.alertService = inject(AlertService);
    }
    get LOCAL_STORAGE_KEY() {
        const id = this.contextIdSignal();
        return id !== null ? `${this.baseKey}-${id}` : this.baseKey;
    }
    get LOCAL_STORAGE_DEFAULT_ID_KEY() {
        const id = this.contextIdSignal();
        return id !== null ? `${this.baseDefaultKey}-${id}` : this.baseDefaultKey;
    }
    /**
     * Generates a full datapoint explorer link from a bare config
     */
    generateExplorerLink(config, label, id) {
        const diffed = this.removeDefaults(config);
        const minified = this.minifyKeys(diffed);
        const compressed = compressToEncodedURIComponent(JSON.stringify(minified));
        const url = `/datapointexplorer-v2?id=${id}&label=${encodeURIComponent(label)}&config=${compressed}`;
        return url;
    }
    /** Load workspace configs from localStorage  */
    getConfigurations() {
        const configurations = localStorage.getItem(this.LOCAL_STORAGE_KEY);
        if (configurations) {
            const parsedConfigs = JSON.parse(configurations);
            return parsedConfigs.map(workspaceConfig => {
                if (typeof workspaceConfig.config === 'string') {
                    return {
                        ...workspaceConfig,
                        config: this.decodeConfig(workspaceConfig.config)
                    };
                }
                return workspaceConfig;
            });
        }
        return [];
    }
    getDefaultConfigurationId() {
        return localStorage.getItem(this.LOCAL_STORAGE_DEFAULT_ID_KEY);
    }
    /** Save workspace configs in localStorage */
    saveConfigurations(configurations, id) {
        localStorage.setItem(this.LOCAL_STORAGE_KEY, JSON.stringify(configurations));
        localStorage.setItem(this.LOCAL_STORAGE_DEFAULT_ID_KEY, id);
    }
    /**
     *
     * @param urlConfig - configuration from the URL, either compressed string or already decoded object
     * @returns
     */
    getConfigurationFromUrl(urlConfig) {
        if (typeof urlConfig === 'string') {
            const decodedConfig = this.decodeConfig(urlConfig);
            const expandedConfig = this.expandKeys(decodedConfig);
            return expandedConfig;
        }
        return this.expandKeys(urlConfig);
    }
    /**
     * Encode a config for the URL:
     * - Cleanup the __target objects to contain only name and id
     * - Remove default values (diff from base)
     * - Minify keys
     * - Compress with lz-string
     */
    encodeConfig(config) {
        const normalized = this.cleanUpTargetObject(config);
        const diffed = this.removeDefaults(normalized);
        const minified = this.minifyKeys(diffed);
        return compressToEncodedURIComponent(JSON.stringify(minified));
    }
    /**
     * Decode a config from the URL:
     * - Decompress
     * - Expand keys
     * - Merge with base config
     */
    decodeConfig(urlConfig) {
        if (!urlConfig)
            return null;
        try {
            const decompressed = decompressFromEncodedURIComponent(urlConfig);
            if (!decompressed)
                return null;
            const parsed = JSON.parse(decompressed);
            const expanded = this.expandKeys(parsed);
            return { ...DATA_EXPLORER_BASE_CONFIG, ...expanded };
        }
        catch {
            this.alertService.danger(gettext('The decoded configuration is invalid and could not be loaded.'));
        }
    }
    /** Minify keys recursively using KEY_MAP */
    minifyKeys(config) {
        if (Array.isArray(config))
            return config.map(object => this.minifyKeys(object));
        if (config !== Object(config))
            return config;
        return Object.fromEntries(Object.entries(config).map(([originalKey, originalValue]) => [
            KEY_MAP[originalKey] || originalKey,
            this.minifyKeys(originalValue)
        ]));
    }
    /** Expand keys recursively using REVERSE_KEY_MAP */
    expandKeys(config) {
        if (Array.isArray(config))
            return config.map(o => this.expandKeys(o));
        if (config !== Object(config))
            return config;
        return Object.fromEntries(Object.entries(config).map(([originalKey, originalValue]) => [
            REVERSE_KEY_MAP[originalKey] || originalKey,
            this.expandKeys(originalValue)
        ]));
    }
    /**
     * Remove properties from `config` that match `base` so only changed values remain.
     */
    removeDefaults(config) {
        const result = {};
        for (const key in config) {
            if (!(key in DATA_EXPLORER_BASE_CONFIG) || DATA_EXPLORER_BASE_CONFIG[key] !== config[key]) {
                result[key] = config[key];
            }
        }
        return result;
    }
    /**
     * Cleans up __target objects to only keep id and name and remove the rest.
     */
    cleanUpTargetObject(config) {
        const configCopy = { ...config };
        // Cleanup the datapoints array
        if (Array.isArray(configCopy.datapoints)) {
            configCopy.datapoints = configCopy.datapoints.map((dp) => {
                if (dp && typeof dp === 'object' && dp.__target && typeof dp.__target === 'object') {
                    const { id, name } = dp.__target;
                    const target = {};
                    if (id !== undefined)
                        target.id = id;
                    if (name !== undefined)
                        target.name = name;
                    return { ...dp, __target: target };
                }
                return dp;
            });
        }
        // Cleanup the alarmEventsConfig array
        if (Array.isArray(configCopy.alarmsEventsConfigs)) {
            configCopy.alarmsEventsConfigs = configCopy.alarmsEventsConfigs.map((a) => {
                if (a && typeof a === 'object' && a.__target && typeof a.__target === 'object') {
                    const { id, name } = a.__target;
                    const target = {};
                    if (id !== undefined)
                        target.id = id;
                    if (name !== undefined)
                        target.name = name;
                    return { ...a, __target: target };
                }
                return a;
            });
        }
        return configCopy;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: WorkspaceConfigurationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: WorkspaceConfigurationService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: WorkspaceConfigurationService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

class DataExplorerService {
    constructor() {
        this.inventory = inject(InventoryService);
        this.contextDashboardService = inject(ContextDashboardService);
        this.workspaceConfigurationService = inject(WorkspaceConfigurationService);
        this.moChunkLoader = inject(MOChunkLoaderService);
        this.datapointSyncService = inject(DatapointSyncService);
        this.router = inject(Router);
        this.maxNumberOfManagedObjectsPerRequest = 50;
    }
    async fetchReportDashboard(reportId) {
        return (await this.inventory.list({
            pageSize: 1,
            query: `has('c8y_Dashboard!name!report_${reportId}')`
        })).data[0];
    }
    async fetchContextDashboard(dashboardId, contextAsset) {
        const context = contextAsset.c8y_isDevice
            ? ContextDashboardType.Device
            : ContextDashboardType.Group;
        return firstValueFrom(this.contextDashboardService.getDashboard$(dashboardId, [context]));
    }
    async loadManagedObjectsInChunks(uniqIds) {
        const { results, errors } = await this.moChunkLoader.processInChunks(uniqIds, this.maxNumberOfManagedObjectsPerRequest, ids => this.loadAChunkOfManagedObjects(ids));
        return { result: results, errors };
    }
    /**
     * Navigate to datapoint explorer with given config.
     * The goal of this method is to navigate to the data explorer with a provided config from any other application.
     * @param config Configuration to use
     * @param label Label to be displayed for the configuration
     * @param id ID for the configuration
     */
    navigateToDataExplorer(config, label, id) {
        const url = this.getUrlForConfig(config, label, id);
        this.router.navigateByUrl(url);
    }
    /**
     * Generate a URL for the datapoint explorer with the given config.
     * The goal of this method is to generate a shareable link to the data explorer.
     * @param config Configuration to use
     * @param label Label to be displayed for the configuration
     * @param id ID for the configuration
     * @returns The generated URL
     */
    getUrlForConfig(config, label, id) {
        return this.workspaceConfigurationService.generateExplorerLink(config, label, id);
    }
    processAlarmEventConfigs(config) {
        const firstTarget = config.alarmsEventsConfigs.find(ae => ae.__target)?.__target;
        config.alarmsEventsConfigs = config.alarmsEventsConfigs.map((ae, index) => {
            if (ae.__active === undefined)
                ae.__active = true;
            if (!ae.__target && firstTarget)
                ae.__target = firstTarget;
            if (!ae.color)
                ae.color = this.generateColor(index);
            return ae;
        });
    }
    processDatapoints(config) {
        const firstTarget = config.datapoints.find(dp => dp.__target)?.__target;
        config.datapoints = config.datapoints.map((dp, index) => {
            // Default __active
            if (dp.__active === undefined)
                dp.__active = true;
            if (!dp.__target && firstTarget)
                dp.__target = firstTarget;
            if (!dp.color && !dp.__template)
                dp.color = this.generateColor(index);
            if (!dp.label)
                dp.label = `${dp.fragment} -> ${dp.series}`;
            return dp;
        });
    }
    /**
     * Generates a color from a fixed palette based on the index.
     * Used to assign colors to alarm/event configs in the UI.
     */
    generateColor(index) {
        // Simple palette, can expand
        const palette = ['#c87d33', '#8c145f', '#8cd7fd', '#59a036', '#fb00ff', '#8d4c22', '#fbb2d7'];
        return palette[index % palette.length];
    }
    async loadAndAssignManagedObjects(config, uniqueIds) {
        const managedObjectsResult = await this.loadManagedObjectsInChunks([...uniqueIds]);
        const managedObjects = managedObjectsResult.result;
        const errors = managedObjectsResult.errors;
        config.datapoints = this.datapointSyncService.assignUpdatedValues(config.datapoints, managedObjects, errors);
    }
    async loadAChunkOfManagedObjects(uniqIds) {
        return this.moChunkLoader.loadAChunkOfManagedObjectsBase(uniqIds, this.inventory, this.maxNumberOfManagedObjectsPerRequest, id => this.moChunkLoader.getStatusDetails(id));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DataExplorerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DataExplorerService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DataExplorerService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

class WorkspaceConfigComponent {
    constructor() {
        this.silent = false;
        this.onConfigurationChange = new EventEmitter();
        this.configurations = [];
        this.navigationSubscription = null;
        this.shouldCleanParams = false;
        this.activeConfigTooltip = gettext('Active configuration cannot be removed');
        this.removeConfigTooltip = gettext('Remove configuration');
        this.formBuilder = inject(FormBuilder);
        this.workspaceConfigurationService = inject(WorkspaceConfigurationService);
        this.contextRouteService = inject(ContextRouteService);
        this.clipboardService = inject(ClipboardService);
        this.activatedRoute = inject(ActivatedRoute);
        this.router = inject(Router);
        this.nameGeneratorService = inject(NameGeneratorService);
        this.datapointSyncService = inject(DatapointSyncService);
        this.dataExplorerService = inject(DataExplorerService);
    }
    ngOnInit() {
        this.initializeContextSourceId();
        this.initializeConfigurations();
        this.initWorkspaceForm();
        this.subscribeToRouterEvents();
    }
    ngOnChanges(changes) {
        if (changes.updatedConfig && !changes.updatedConfig.firstChange) {
            this.updateConfigurations();
        }
    }
    ngOnDestroy() {
        if (this.shouldCleanParams) {
            this.router.navigate([], {
                queryParams: {
                    config: null,
                    id: null,
                    label: null
                },
                queryParamsHandling: 'merge'
            });
        }
        this.navigationSubscription?.unsubscribe();
    }
    addConfig(duplicatedConfig, id, label) {
        const name = this.nameGeneratorService.generateName();
        const workspace = {
            id: id || new Date().toISOString(),
            label: label || name,
            config: { datapoints: [], alarmsEventsConfigs: [] }
        };
        if (duplicatedConfig) {
            workspace.config = duplicatedConfig;
        }
        this.configurations = [workspace, ...this.configurations];
        this.initWorkspaceForm();
        this.changeConfiguration(true, workspace);
    }
    changeConfiguration(selected, configuration) {
        if (!selected) {
            return;
        }
        if (this.currentConfiguration?.id === configuration.id) {
            return;
        }
        this.currentConfiguration = configuration;
        localStorage.setItem(this.workspaceConfigurationService.LOCAL_STORAGE_DEFAULT_ID_KEY, this.currentConfiguration.id);
        this.onConfigurationChange.emit(configuration.config);
    }
    updateConfigurationLabel(configuration) {
        this.configurations = this.configurations.map(c => c.id === configuration.id ? configuration : c);
        if (this.currentConfiguration.id === configuration.id) {
            this.currentConfiguration = configuration;
        }
        this.workspaceConfigurationService.saveConfigurations(this.configurations, this.currentConfiguration?.id || '');
    }
    deleteConfiguration(configuration) {
        this.configurations = this.configurations.filter(c => c.id !== configuration.id);
        this.initWorkspaceForm();
        this.workspaceConfigurationService.saveConfigurations(this.configurations, this.currentConfiguration?.id || '');
    }
    clearAll() {
        this.configurations = [this.currentConfiguration];
        this.initWorkspaceForm();
        this.workspaceConfigurationService.saveConfigurations(this.configurations, this.currentConfiguration?.id || '');
    }
    async shareConfig(configuration) {
        await this.clipboardService.writeText(JSON.stringify(configuration.config));
    }
    async addConfigFromUrl(queryParams) {
        const id = queryParams.id || new Date().toISOString();
        const label = queryParams.label || this.nameGeneratorService.generateName();
        const config = this.workspaceConfigurationService.getConfigurationFromUrl(queryParams.config || {});
        this.addConfig(config, id, label);
        if (config.datapoints?.length) {
            this.dataExplorerService.processDatapoints(config);
        }
        const uniqueIds = this.datapointSyncService.getManagedObjectIds(config.datapoints || []);
        if (uniqueIds.length) {
            await this.dataExplorerService.loadAndAssignManagedObjects(config, uniqueIds);
        }
        if (config.alarmsEventsConfigs?.length) {
            this.dataExplorerService.processAlarmEventConfigs(config);
        }
        this.onConfigurationChange.emit(config);
    }
    updateConfigurations() {
        const config = { ...this.updatedConfig };
        this.currentConfiguration.config = config;
        this.configurations = this.configurations.map(currentConfig => currentConfig.id === this.currentConfiguration.id ? this.currentConfiguration : currentConfig);
        const queryParams = {
            id: this.currentConfiguration.id,
            label: this.currentConfiguration.label,
            config: this.workspaceConfigurationService.encodeConfig(config)
        };
        this.workspaceConfigurationService.saveConfigurations(this.configurations, this.currentConfiguration.id);
        const control = this.configurationsFormGroup.controls['configurations'];
        const index = this.configurations.findIndex(c => c.id === this.currentConfiguration.id);
        if (index !== -1) {
            control.at(index).patchValue({
                label: this.currentConfiguration.label,
                config: this.currentConfiguration.config,
                id: this.currentConfiguration.id
            });
        }
        this.router.navigate([], {
            queryParams,
            queryParamsHandling: 'merge'
        });
    }
    initializeConfigurations() {
        const configurations = this.workspaceConfigurationService.getConfigurations();
        const defaultId = this.defaultConfigurationId ?? this.workspaceConfigurationService.getDefaultConfigurationId();
        const queryParams = this.router.parseUrl(this.router.url).queryParams;
        if (configurations.length) {
            this.configurations = configurations;
            this.currentConfiguration =
                this.configurations.find(c => c.id === defaultId) || this.configurations[0];
            this.onConfigurationChange.emit(this.currentConfiguration.config);
            if (queryParams?.id && !this.configurations.find(c => c.id === queryParams.id)) {
                this.addConfigFromUrl(queryParams);
            }
            else if (queryParams?.id &&
                this.configurations.find(c => c.id === queryParams.id) &&
                this.currentConfiguration.id !== queryParams.id) {
                this.currentConfiguration = this.configurations.find(c => c.id === queryParams.id);
                this.changeConfiguration(true, this.currentConfiguration);
            }
        }
        if (!this.currentConfiguration) {
            if (Object.keys(queryParams).length === 0) {
                this.addConfig();
                return;
            }
            this.addConfigFromUrl(queryParams);
        }
    }
    initWorkspaceForm() {
        this.configurationsFormGroup = this.formBuilder.group({
            configurations: this.formBuilder.array([])
        });
        this.patchForm();
    }
    patchForm() {
        const control = this.configurationsFormGroup.controls['configurations'];
        this.configurations.forEach(workspace => {
            control.push(this.patchValues(workspace));
        });
    }
    patchValues(workspace) {
        return this.formBuilder.group({
            label: [workspace.label],
            config: [workspace.config],
            id: [workspace.id]
        });
    }
    /**
     * Subscribe to router events to clean query params when navigating away, but only when navigating between group or device context
     * Otherwise it breaks GC.
     */
    subscribeToRouterEvents() {
        this.navigationSubscription = this.router.events.subscribe(event => {
            if (event instanceof NavigationStart) {
                const urlTree = this.router.parseUrl(event.url);
                if (urlTree.queryParams['config'] ||
                    urlTree.queryParams['id'] ||
                    urlTree.queryParams['label']) {
                    this.shouldCleanParams = true;
                }
                else {
                    this.shouldCleanParams = false;
                }
            }
        });
    }
    initializeContextSourceId() {
        const routeContext = this.contextRouteService.getContextData(this.activatedRoute);
        if (!routeContext) {
            this.workspaceConfigurationService.contextIdSignal.set(null);
            return;
        }
        const { context, contextData } = routeContext;
        if ([ViewContext.Device, ViewContext.Group].includes(context)) {
            this.workspaceConfigurationService.contextIdSignal.set(contextData?.id);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: WorkspaceConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: WorkspaceConfigComponent, isStandalone: true, selector: "c8y-workspace-config", inputs: { updatedConfig: "updatedConfig", silent: "silent", defaultConfigurationId: "defaultConfigurationId" }, outputs: { onConfigurationChange: "onConfigurationChange" }, usesOnChanges: true, ngImport: i0, template: "@if (!silent) {\n  <div\n    class=\"dropdown\"\n    #actionbar_dropdown=\"bs-dropdown\"\n    [cdkTrapFocus]=\"actionbar_dropdown.isOpen\"\n    dropdown\n    [insideClick]=\"true\"\n  >\n    <button\n      class=\"dropdown-toggle form-control l-h-tight d-flex a-i-center\"\n      attr.aria-label=\"{{ currentConfiguration?.label }}\"\n      tooltip=\"{{ 'Selected configuration' | translate }}\"\n      placement=\"top\"\n      container=\"body\"\n      data-cy=\"current-configuration-dropdown-button\"\n      [adaptivePosition]=\"false\"\n      [delay]=\"500\"\n      dropdownToggle\n    >\n      <i\n        class=\"m-r-4\"\n        c8yIcon=\"list\"\n      ></i>\n      <div class=\"d-col text-left fit-w\">\n        <span class=\"text-12\">\n          {{ 'Configuration' | translate }}\n        </span>\n        <span class=\"text-10 text-muted text-truncate\">\n          {{ currentConfiguration?.label }}\n        </span>\n      </div>\n      <span class=\"caret m-r-16 m-l-4\"></span>\n    </button>\n    <div\n      class=\"dropdown-menu dropdown-menu-wide dropdown-menu-action-bar\"\n      *dropdownMenu\n    >\n      <div class=\"sticky-top separator-bottom p-t-8 p-b-8 p-l-16 p-r-16\">\n        <p>\n          <strong>{{ 'Data explorer configurations' | translate }}</strong>\n        </p>\n        <p>\n          <small>{{ 'Easily switch and manage configurations.' | translate }}</small>\n        </p>\n      </div>\n      <c8y-list-group class=\"no-border-last\">\n        <form [formGroup]=\"configurationsFormGroup\">\n          <div formArrayName=\"configurations\">\n            @for (\n              configuration of configurationsFormGroup.controls.configurations['controls'];\n              track $index\n            ) {\n              <c8y-li\n                class=\"p-0\"\n                [dense]=\"true\"\n              >\n                <c8y-li-radio\n                  style=\"min-height: 48px\"\n                  [selected]=\"configuration.value.id === currentConfiguration.id\"\n                  (onSelect)=\"changeConfiguration($event, configuration.value)\"\n                ></c8y-li-radio>\n\n                <div class=\"d-flex a-i-center gap-8\">\n                  <div\n                    class=\"min-width-0\"\n                    [formGroupName]=\"$index\"\n                  >\n                    <label\n                      class=\"editable\"\n                      [ngClass]=\"{\n                        updated:\n                          configuration.controls.label.touched && configuration.controls.label.dirty\n                      }\"\n                    >\n                      <input\n                        class=\"form-control\"\n                        [style.width.ch]=\"configuration.value.label || 25\"\n                        [attr.aria-label]=\"'Configuration label' | translate\"\n                        placeholder=\"{{ 'Configuration 1' | translate }}\"\n                        type=\"text\"\n                        autocomplete=\"off\"\n                        required\n                        formControlName=\"label\"\n                        (blur)=\"updateConfigurationLabel(configuration.value)\"\n                        (keydown.enter)=\"\n                          $event.preventDefault(); updateConfigurationLabel(configuration.value)\n                        \"\n                      />\n                    </label>\n                  </div>\n\n                  <div class=\"flex-nogrow d-flex gap-8\">\n                    <button\n                      class=\"btn-dot btn m-0\"\n                      [attr.aria-label]=\"'Duplicate configuration' | translate\"\n                      tooltip=\"{{ 'Duplicate configuration' | translate }}\"\n                      placement=\"left\"\n                      (click)=\"addConfig(configuration.value.config)\"\n                      [delay]=\"500\"\n                    >\n                      <i c8yIcon=\"copy\"></i>\n                    </button>\n\n                    <button\n                      class=\"btn-dot btn btn-dot--danger\"\n                      [attr.aria-label]=\"'Remove configurations' | translate\"\n                      tooltip=\"{{\n                        (configuration.value.id === currentConfiguration.id\n                          ? activeConfigTooltip\n                          : removeConfigTooltip\n                        ) | translate\n                      }}\"\n                      placement=\"left\"\n                      [delay]=\"500\"\n                      (click)=\"$event.stopPropagation(); deleteConfiguration(configuration.value)\"\n                      [disabled]=\"configuration.value.id === currentConfiguration.id\"\n                    >\n                      <i c8yIcon=\"minus-circle\"></i>\n                    </button>\n                  </div>\n                </div>\n              </c8y-li>\n            }\n          </div>\n        </form>\n      </c8y-list-group>\n      <div class=\"sticky-bottom separator-top\">\n        <div class=\"d-flex p-l-16 p-r-16 p-t-8 p-b-8\">\n          <button\n            class=\"btn btn-danger btn-sm flex-grow m-r-4\"\n            (click)=\"clearAll()\"\n            [disabled]=\"configurations.length < 2\"\n          >\n            <i [c8yIcon]=\"'delete'\"></i>\n            {{ 'Delete all configurations' | translate }}\n          </button>\n          <button\n            class=\"btn btn-default btn-sm flex-grow\"\n            type=\"button\"\n            (click)=\"addConfig()\"\n          >\n            <i [c8yIcon]=\"'add-circle-outline'\"></i>\n            {{ 'Add configuration' | translate }}\n          </button>\n        </div>\n      </div>\n    </div>\n  </div>\n}\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.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: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: i2.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemRadioComponent, selector: "c8y-list-item-radio, c8y-li-radio", inputs: ["selected", "name", "disabled", "value"], outputs: ["onSelect"] }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2$1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "directive", type: i4.BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: i4.BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: i4.BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i5.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.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: i2.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: WorkspaceConfigComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-workspace-config', standalone: true, imports: [CoreModule, BsDropdownModule, FormsModule, A11yModule, TooltipModule], template: "@if (!silent) {\n  <div\n    class=\"dropdown\"\n    #actionbar_dropdown=\"bs-dropdown\"\n    [cdkTrapFocus]=\"actionbar_dropdown.isOpen\"\n    dropdown\n    [insideClick]=\"true\"\n  >\n    <button\n      class=\"dropdown-toggle form-control l-h-tight d-flex a-i-center\"\n      attr.aria-label=\"{{ currentConfiguration?.label }}\"\n      tooltip=\"{{ 'Selected configuration' | translate }}\"\n      placement=\"top\"\n      container=\"body\"\n      data-cy=\"current-configuration-dropdown-button\"\n      [adaptivePosition]=\"false\"\n      [delay]=\"500\"\n      dropdownToggle\n    >\n      <i\n        class=\"m-r-4\"\n        c8yIcon=\"list\"\n      ></i>\n      <div class=\"d-col text-left fit-w\">\n        <span class=\"text-12\">\n          {{ 'Configuration' | translate }}\n        </span>\n        <span class=\"text-10 text-muted text-truncate\">\n          {{ currentConfiguration?.label }}\n        </span>\n      </div>\n      <span class=\"caret m-r-16 m-l-4\"></span>\n    </button>\n    <div\n      class=\"dropdown-menu dropdown-menu-wide dropdown-menu-action-bar\"\n      *dropdownMenu\n    >\n      <div class=\"sticky-top separator-bottom p-t-8 p-b-8 p-l-16 p-r-16\">\n        <p>\n          <strong>{{ 'Data explorer configurations' | translate }}</strong>\n        </p>\n        <p>\n          <small>{{ 'Easily switch and manage configurations.' | translate }}</small>\n        </p>\n      </div>\n      <c8y-list-group class=\"no-border-last\">\n        <form [formGroup]=\"configurationsFormGroup\">\n          <div formArrayName=\"configurations\">\n            @for (\n              configuration of configurationsFormGroup.controls.configurations['controls'];\n              track $index\n            ) {\n              <c8y-li\n                class=\"p-0\"\n                [dense]=\"true\"\n              >\n                <c8y-li-radio\n                  style=\"min-height: 48px\"\n                  [selected]=\"configuration.value.id === currentConfiguration.id\"\n                  (onSelect)=\"changeConfiguration($event, configuration.value)\"\n                ></c8y-li-radio>\n\n                <div class=\"d-flex a-i-center gap-8\">\n                  <div\n                    class=\"min-width-0\"\n                    [formGroupName]=\"$index\"\n                  >\n                    <label\n                      class=\"editable\"\n                      [ngClass]=\"{\n                        updated:\n                          configuration.controls.label.touched && configuration.controls.label.dirty\n                      }\"\n                    >\n                      <input\n                        class=\"form-control\"\n                        [style.width.ch]=\"configuration.value.label || 25\"\n                        [attr.aria-label]=\"'Configuration label' | translate\"\n                        placeholder=\"{{ 'Configuration 1' | translate }}\"\n                        type=\"text\"\n                        autocomplete=\"off\"\n                        required\n                        formControlName=\"label\"\n                        (blur)=\"updateConfigurationLabel(configuration.value)\"\n                        (keydown.enter)=\"\n                          $event.preventDefault(); updateConfigurationLabel(configuration.value)\n                        \"\n                      />\n                    </label>\n                  </div>\n\n                  <div class=\"flex-nogrow d-flex gap-8\">\n                    <button\n                      class=\"btn-dot btn m-0\"\n                      [attr.aria-label]=\"'Duplicate configuration' | translate\"\n                      tooltip=\"{{ 'Duplicate configuration' | translate }}\"\n                      placement=\"left\"\n                      (click)=\"addConfig(configuration.value.config)\"\n                      [delay]=\"500\"\n                    >\n                      <i c8yIcon=\"copy\"></i>\n                    </button>\n\n                    <button\n                      class=\"btn-dot btn btn-dot--danger\"\n                      [attr.aria-label]=\"'Remove configurations' | translate\"\n                      tooltip=\"{{\n                        (configuration.value.id === currentConfiguration.id\n                          ? activeConfigTooltip\n                          : removeConfigTooltip\n                        ) | translate\n                      }}\"\n                      placement=\"left\"\n                      [delay]=\"500\"\n                      (click)=\"$event.stopPropagation(); deleteConfiguration(configuration.value)\"\n                      [disabled]=\"configuration.value.id === currentConfiguration.id\"\n                    >\n                      <i c8yIcon=\"minus-circle\"></i>\n                    </button>\n                  </div>\n                </div>\n              </c8y-li>\n            }\n          </div>\n        </form>\n      </c8y-list-group>\n      <div class=\"sticky-bottom separator-top\">\n        <div class=\"d-flex p-l-16 p-r-16 p-t-8 p-b-8\">\n          <button\n            class=\"btn btn-danger btn-sm flex-grow m-r-4\"\n            (click)=\"clearAll()\"\n            [disabled]=\"configurations.length < 2\"\n          >\n            <i [c8yIcon]=\"'delete'\"></i>\n            {{ 'Delete all configurations' | translate }}\n          </button>\n          <button\n            class=\"btn btn-default btn-sm flex-grow\"\n            type=\"button\"\n            (click)=\"addConfig()\"\n          >\n            <i [c8yIcon]=\"'add-circle-outline'\"></i>\n            {{ 'Add configuration' | translate }}\n          </button>\n        </div>\n      </div>\n    </div>\n  </div>\n}\n" }]
        }], propDecorators: { updatedConfig: [{
                type: Input
            }], silent: [{
                type: Input
            }], defaultConfigurationId: [{
                type: Input
            }], onConfigurationChange: [{
                type: Output
            }] } });

class CreateNewReportModalComponent {
    constructor(contextDashboardService) {
        this.contextDashboardService = contextDashboardService;
        this.reportName = '';
        this.labels = { cancel: gettext('Cancel'), ok: gettext('Send') };
        this.result = new Promise((resolve, reject) => {
            this._resolve = resolve;
            this._reject = reject;
        });
        this.styling = {
            themeClass: 'dashboard-theme-light',
            headerClass: 'panel-title-regular'
        };
        this.DEFAULT_DASHBOARD_ICON = 'th';
        this.DEFAULT_DASHBOARD_PRIORITY = 5000;
        this.DEFAULT_DASHBOARD_MARGIN = 12;
    }
    async save() {
        const dashboard = {
            name: this.reportName,
            icon: this.DEFAULT_DASHBOARD_ICON,
            c8y_IsNavigatorNode: null,
            priority: this.DEFAULT_DASHBOARD_PRIORITY,
            description: '',
            widgetMargin: this.DEFAULT_DASHBOARD_MARGIN,
            classes: { [this.styling.headerClass]: true },
            widgetClasses: { [this.styling.headerClass]: true },
            translateDashboardTitle: true
        };
        try {
            const { name, icon, c8y_IsNavigatorNode, priority, description, translateDashboardTitle } = dashboard;
            const report = (await this.contextDashboardService.createReport({
                name,
                icon,
                c8y_IsNavigatorNode,
                priority,
                description,
                translateDashboardTitle
            })).data;
            await this.contextDashboardService.create(dashboard, undefined, `${this.contextDashboardService.REPORT_PARTIAL_NAME}${report.id}`);
            this._resolve(report);
        }
        catch (ex) {
            this._reject(ex);
        }
    }
    cancel() {
        this._reject();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CreateNewReportModalComponent, deps: [{ token: i1.ContextDashboardService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: CreateNewReportModalComponent, isStandalone: true, selector: "c8y-create-new-report-modal", ngImport: i0, template: "<c8y-modal\n  [title]=\"'Create new report with widget' | translate\"\n  [headerClasses]=\"'dialog-header'\"\n  [disabled]=\"reportName === ''\"\n  (onDismiss)=\"cancel()\"\n  (onClose)=\"save()\"\n  [labels]=\"labels\"\n>\n  <ng-container c8y-modal-title>\n    <span c8yIcon=\"c8y-reports\"></span>\n  </ng-container>\n\n  <p class=\"text-center bg-component text-balance sticky-top p-l-24 p-r-24 p-t-8 p-b-8 separator-bottom\">\n   {{' Create a new report with the Data points graph widget using the current configuration.' | translate}}\n  </p>\n  <div class=\"p-24 p-t-8\">\n    <c8y-form-group>\n      <label\n        for=\"reportName\"\n        translate\n        >\n        Report name\n      </label>\n      <input\n        class=\"form-control\"\n        id=\"reportName\"\n        placeholder=\"{{ 'e.g. My data point Report' }}\"\n        name=\"name\"\n        type=\"text\"\n        autocomplete=\"off\"\n        required\n        [(ngModel)]=\"reportName\"\n      />\n      <c8y-messages></c8y-messages>\n    </c8y-form-group>\n  </div>\n</c8y-modal>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.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: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i2.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: i2.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "ngmodule", type: ReportDashboardModule }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CreateNewReportModalComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-create-new-report-modal', standalone: true, imports: [ReactiveFormsModule, CoreModule, ReportDashboardModule], template: "<c8y-modal\n  [title]=\"'Create new report with widget' | translate\"\n  [headerClasses]=\"'dialog-header'\"\n  [disabled]=\"reportName === ''\"\n  (onDismiss)=\"cancel()\"\n  (onClose)=\"save()\"\n  [labels]=\"labels\"\n>\n  <ng-container c8y-modal-title>\n    <span c8yIcon=\"c8y-reports\"></span>\n  </ng-container>\n\n  <p class=\"text-center bg-component text-balance sticky-top p-l-24 p-r-24 p-t-8 p-b-8 separator-bottom\">\n   {{' Create a new report with the Data points graph widget using the current configuration.' | translate}}\n  </p>\n  <div class=\"p-24 p-t-8\">\n    <c8y-form-group>\n      <label\n        for=\"reportName\"\n        translate\n        >\n        Report name\n      </label>\n      <input\n        class=\"form-control\"\n        id=\"reportName\"\n        placeholder=\"{{ 'e.g. My data point Report' }}\"\n        name=\"name\"\n        type=\"text\"\n        autocomplete=\"off\"\n        required\n        [(ngModel)]=\"reportName\"\n      />\n      <c8y-messages></c8y-messages>\n    </c8y-form-group>\n  </div>\n</c8y-modal>\n" }]
        }], ctorParameters: () => [{ type: i1.ContextDashboardService }] });

class SendAsWidgetToDashboardModal {
    constructor() {
        this.dashboards = [];
        this.result = new Promise((resolve, reject) => {
            this._resolve = resolve;
            this._reject = reject;
        });
        this.labels = { cancel: gettext('Cancel'), ok: gettext('Send') };
        this.contextDashboardService = inject(ContextDashboardService);
    }
    async ngOnInit() {
        const context = this.contextAsset.c8y_IsDevice
            ? ContextDashboardType.Device
            : ContextDashboardType.Group;
        this.dashboards = (await this.contextDashboardService.getContextDashboards(this.contextAsset, [
            context
        ])).data;
        if (this.dashboards.length > 0) {
            this.form = this.initForm();
        }
        this.numberOfSelectedDashboards$ = merge(this.form.valueChanges, of(this.form.value)).pipe(map(value => Object.values(value).filter(Boolean).length));
    }
    save() {
        this._resolve(this.form.value);
    }
    cancel() {
        this._reject();
    }
    initForm() {
        const controls = this.dashboards.reduce((acc, dashboard) => ({
            ...acc,
            [dashboard.id]: new FormControl(false)
        }), {});
        return new FormGroup(controls);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SendAsWidgetToDashboardModal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SendAsWidgetToDashboardModal, isStandalone: true, selector: "c8y-send-as-widget-to-dashboard-modal", inputs: { contextAsset: "contextAsset" }, ngImport: i0, template: "<c8y-modal\n  [title]=\"'Send as widget to dashboards' | translate\"\n  [disabled]=\"!form || form.invalid\"\n  [headerClasses]=\"'dialog-header'\"\n  (onDismiss)=\"cancel()\"\n  (onClose)=\"save()\"\n  [labels]=\"labels\"\n>\n  <ng-container c8y-modal-title>\n    <span c8yIcon=\"th\"></span>\n  </ng-container>\n\n  <c8y-list-group\n    class=\"m-b-0 no-border-last\"\n    *ngIf=\"form\"\n    [formGroup]=\"form\"\n  >\n    <c8y-li>\n      <p\n        class=\"text-center text-medium\"\n        *ngIf=\"numberOfSelectedDashboards$ | async as numberOfDashboards; else noSelectedDashboards\"\n        translate\n        [translateParams]=\"{ numberOfDashboards: numberOfDashboards }\"\n        ngNonBindable\n      >\n        {{ numberOfDashboards }} dashboards selected for widget\n      </p>\n      <ng-template #noSelectedDashboards>\n        <p\n          class=\"text-center text-medium\"\n          translate\n        >\n          Select one or more dashboards to send the Data points graph widget with the current\n          configuration\n        </p>\n      </ng-template>\n    </c8y-li>\n    <c8y-li *ngFor=\"let dashboard of dashboards\">\n      <c8y-li-checkbox\n        [attr.data-cy]=\"'branding-apply-branding-to-app-checkbox-' + dashboard.id\"\n        [formControlName]=\"dashboard.id\"\n      ></c8y-li-checkbox>\n      <c8y-li-icon class=\"p-l-0\">\n        <i c8yIcon=\"{{ dashboard.icon }}\"></i>\n      </c8y-li-icon>\n      <div\n        class=\"text-truncate\"\n        title=\"{{ dashboard.name }}\"\n      >\n        {{ dashboard.name }}\n      </div>\n    </c8y-li>\n  </c8y-list-group>\n\n  <c8y-ui-empty-state\n    [icon]=\"'th'\"\n    [title]=\"'There are no dashboards defined.' | translate\"\n    [subtitle]=\"'Add a dashboard first.' | translate\"\n    *ngIf=\"dashboards.length === 0\"\n  ></c8y-ui-empty-state>\n</c8y-modal>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: i2.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }, { kind: "ngmodule", type: ContextDashboardModule }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SendAsWidgetToDashboardModal, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-send-as-widget-to-dashboard-modal', standalone: true, imports: [ReactiveFormsModule, CoreModule, ContextDashboardModule], template: "<c8y-modal\n  [title]=\"'Send as widget to dashboards' | translate\"\n  [disabled]=\"!form || form.invalid\"\n  [headerClasses]=\"'dialog-header'\"\n  (onDismiss)=\"cancel()\"\n  (onClose)=\"save()\"\n  [labels]=\"labels\"\n>\n  <ng-container c8y-modal-title>\n    <span c8yIcon=\"th\"></span>\n  </ng-container>\n\n  <c8y-list-group\n    class=\"m-b-0 no-border-last\"\n    *ngIf=\"form\"\n    [formGroup]=\"form\"\n  >\n    <c8y-li>\n      <p\n        class=\"text-center text-medium\"\n        *ngIf=\"numberOfSelectedDashboards$ | async as numberOfDashboards; else noSelectedDashboards\"\n        translate\n        [translateParams]=\"{ numberOfDashboards: numberOfDashboards }\"\n        ngNonBindable\n      >\n        {{ numberOfDashboards }} dashboards selected for widget\n      </p>\n      <ng-template #noSelectedDashboards>\n        <p\n          class=\"text-center text-medium\"\n          translate\n        >\n          Select one or more dashboards to send the Data points graph widget with the current\n          configuration\n        </p>\n      </ng-template>\n    </c8y-li>\n    <c8y-li *ngFor=\"let dashboard of dashboards\">\n      <c8y-li-checkbox\n        [attr.data-cy]=\"'branding-apply-branding-to-app-checkbox-' + dashboard.id\"\n        [formControlName]=\"dashboard.id\"\n      ></c8y-li-checkbox>\n      <c8y-li-icon class=\"p-l-0\">\n        <i c8yIcon=\"{{ dashboard.icon }}\"></i>\n      </c8y-li-icon>\n      <div\n        class=\"text-truncate\"\n        title=\"{{ dashboard.name }}\"\n      >\n        {{ dashboard.name }}\n      </div>\n    </c8y-li>\n  </c8y-list-group>\n\n  <c8y-ui-empty-state\n    [icon]=\"'th'\"\n    [title]=\"'There are no dashboards defined.' | translate\"\n    [subtitle]=\"'Add a dashboard first.' | translate\"\n    *ngIf=\"dashboards.length === 0\"\n  ></c8y-ui-empty-state>\n</c8y-modal>\n" }]
        }], propDecorators: { contextAsset: [{
                type: Input
            }] } });

class SendAsWidgetToReportModal {
    constructor() {
        this.reports = [];
        this.result = new Promise((resolve, reject) => {
            this._resolve = resolve;
            this._reject = reject;
        });
        this.labels = { cancel: gettext('Cancel'), ok: gettext('Send') };
        this.reportDashboardService = inject(ReportDashboardService);
    }
    async ngOnInit() {
        this.reports = (await this.reportDashboardService.listReports({ pageSize: 2000 })).data;
        if (this.reports.length > 0) {
            this.form = this.initForm();
        }
        this.numberOfSelectedReports$ = merge(this.form.valueChanges, of(this.form.value)).pipe(map(value => Object.values(value).filter(Boolean).length));
    }
    save() {
        this._resolve(this.form.value);
    }
    cancel() {
        this._reject();
    }
    initForm() {
        const controls = this.reports.reduce((acc, report) => ({
            ...acc,
            [report.id]: new FormControl(false)
        }), {});
        return new FormGroup(controls);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SendAsWidgetToReportModal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SendAsWidgetToReportModal, isStandalone: true, selector: "c8y-send-as-widget-to-report-modal", ngImport: i0, template: "<c8y-modal\n  [title]=\"'Send as widget to reports' | translate\"\n  [disabled]=\"!form || form.invalid\"\n  [headerClasses]=\"'dialog-header'\"\n  (onDismiss)=\"cancel()\"\n  (onClose)=\"save()\"\n  [labels]=\"labels\"\n>\n  <ng-container c8y-modal-title>\n    <span c8yIcon=\"c8y-reports\"></span>\n  </ng-container>\n\n  <c8y-list-group\n    class=\"m-b-0 no-border-last\"\n    *ngIf=\"form\"\n    [formGroup]=\"form\"\n  >\n    <c8y-li>\n      <p\n        class=\"text-center text-medium\"\n        *ngIf=\"numberOfSelectedReports$ | async as numberOfReports; else noSelectedReports\"\n        translate\n        [translateParams]=\"{ numberOfReports: numberOfReports }\"\n        ngNonBindable\n      >\n        {{ numberOfReports }} reports selected for widget\n      </p>\n      <ng-template #noSelectedReports>\n        <p\n          class=\"text-center text-medium\"\n          translate\n        >\n          Select one or more reports to send the Data points graph widget with the current configuration\n        </p>\n      </ng-template>\n    </c8y-li>\n    <c8y-li *ngFor=\"let report of reports\">\n      <c8y-li-checkbox\n        [attr.data-cy]=\"'branding-apply-branding-to-app-checkbox-' + report.id\"\n        [formControlName]=\"report.id\"\n      ></c8y-li-checkbox>\n      <c8y-li-icon class=\"p-l-0\">\n        <i c8yIcon=\"{{ report.icon }}\"></i>\n      </c8y-li-icon>\n      <div class=\"text-truncate\" title=\"{{report.name}}\">{{ report.name }}</div>\n    </c8y-li>\n  </c8y-list-group>\n\n  <c8y-ui-empty-state\n    [icon]=\"'c8y-reports'\"\n    [title]=\"'There are no reports defined.' | translate\"\n    [subtitle]=\"'Add a report first.' | translate\"\n    *ngIf=\"reports.length === 0\"\n  ></c8y-ui-empty-state>\n</c8y-modal>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: i2.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }, { kind: "ngmodule", type: ReportDashboardModule }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SendAsWidgetToReportModal, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-send-as-widget-to-report-modal', standalone: true, imports: [ReactiveFormsModule, CoreModule, ReportDashboardModule], template: "<c8y-modal\n  [title]=\"'Send as widget to reports' | translate\"\n  [disabled]=\"!form || form.invalid\"\n  [headerClasses]=\"'dialog-header'\"\n  (onDismiss)=\"cancel()\"\n  (onClose)=\"save()\"\n  [labels]=\"labels\"\n>\n  <ng-container c8y-modal-title>\n    <span c8yIcon=\"c8y-reports\"></span>\n  </ng-container>\n\n  <c8y-list-group\n    class=\"m-b-0 no-border-last\"\n    *ngIf=\"form\"\n    [formGroup]=\"form\"\n  >\n    <c8y-li>\n      <p\n        class=\"text-center text-medium\"\n        *ngIf=\"numberOfSelectedReports$ | async as numberOfReports; else noSelectedReports\"\n        translate\n        [translateParams]=\"{ numberOfReports: numberOfReports }\"\n        ngNonBindable\n      >\n        {{ numberOfReports }} reports selected for widget\n      </p>\n      <ng-template #noSelectedReports>\n        <p\n          class=\"text-center text-medium\"\n          translate\n        >\n          Select one or more reports to send the Data points graph widget with the current configuration\n        </p>\n      </ng-template>\n    </c8y-li>\n    <c8y-li *ngFor=\"let report of reports\">\n      <c8y-li-checkbox\n        [attr.data-cy]=\"'branding-apply-branding-to-app-checkbox-' + report.id\"\n        [formControlName]=\"report.id\"\n      ></c8y-li-checkbox>\n      <c8y-li-icon class=\"p-l-0\">\n        <i c8yIcon=\"{{ report.icon }}\"></i>\n      </c8y-li-icon>\n      <div class=\"text-truncate\" title=\"{{report.name}}\">{{ report.name }}</div>\n    </c8y-li>\n  </c8y-list-group>\n\n  <c8y-ui-empty-state\n    [icon]=\"'c8y-reports'\"\n    [title]=\"'There are no reports defined.' | translate\"\n    [subtitle]=\"'Add a report first.' | translate\"\n    *ngIf=\"reports.length === 0\"\n  ></c8y-ui-empty-state>\n</c8y-modal>\n" }]
        }] });

class DatapointExplorerComponent {
    #destroyRef;
    constructor() {
        this.config = { datapoints: [], alarmsEventsConfigs: [] };
        this.alarms = [];
        this.events = [];
        this.datapointsOutOfSync = new Map();
        this.activeDatapoints = [];
        this.hasAtLeastOneAlarmActive = true;
        this.isMarkedAreaEnabled = false;
        this.alarmsOrEventsHaveNoMatchingDps = false;
        this.canAddReport = false;
        this.datapointSelectDefaultFormOptions = {
            showRange: true,
            showChart: true
        };
        this.chartViewContext = CHART_VIEW_CONTEXT.DATAPOINT_EXPLORER;
        this.#destroyRef = inject(DestroyRef);
        this.dataExplorerService = inject(DataExplorerService);
        this.formBuilder = inject(FormBuilder);
        this.alertService = inject(AlertService);
        this.bsModalService = inject(BsModalService);
        this.permissions = inject(Permissions);
        this.contextDashboardService = inject(ContextDashboardService);
        this.activatedRoute = inject(ActivatedRoute);
        this.contextRouteService = inject(ContextRouteService);
        this.chartHelpersService = inject(ChartHelpersService);
        this.gainsightService = inject(GainsightService);
        this.datapointSyncService = inject(DatapointSyncService);
        this.formGroup = this.initForm();
        this.settings$ = this.activatedRoute.data.pipe(map$1(data => data.settings));
    }
    ngOnInit() {
        this.contextAsset = this.initializeContextSourceId();
        this.checkForMatchingDatapoints();
        this.canAddReport = this.permissions.hasAnyRole([
            Permissions.ROLE_INVENTORY_CREATE,
            Permissions.ROLE_INVENTORY_ADMIN,
            Permissions.ROLE_MANAGED_OBJECT_ADMIN,
            Permissions.ROLE_MANAGED_OBJECT_CREATE
        ]);
        // Initialize timeProps from config if available
        if (this.config.dateFrom && this.config.dateTo) {
            this.timeProps = {
                dateFrom: new Date(this.config.dateFrom),
                dateTo: new Date(this.config.dateTo),
                interval: (this.config.interval === 'none' ? null : this.config.interval),
                realtime: this.config.realtime,
                aggregation: this.config.aggregation
            };
        }
        this.formGroup.valueChanges
            .pipe(takeUntilDestroyed(this.#destroyRef))
            .subscribe(configChange => {
            const { alarms, events, ...configValues } = configChange;
            this.config = {
                ...configValues,
                alarmsEventsConfigs: [...(alarms || []), ...(events || [])]
            };
            this.updateExportConfig();
            this.checkForMatchingDatapoints();
        });
        const configSummaryGS = this.chartHelpersService.getConfigSummaryForGainsight(this.config);
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_DATA_EXPLORER_AND_GRAPH.EVENTS.DATA_EXPLORER_AND_GRAPH, {
            component: PRODUCT_EXPERIENCE_DATA_EXPLORER_AND_GRAPH.COMPONENTS.DATA_EXPLORER_DETAILS,
            action: PRODUCT_EXPERIENCE_DATA_EXPLORER_AND_GRAPH.ACTIONS.DATA_EXPLORER_CONFIG_INIT,
            ...configSummaryGS
        });
    }
    onTimeContextChange(timeProps) {
        const realtime = this.formGroup.controls.realtime.value;
        if (timeProps.realtime !== realtime) {
            this.formGroup.patchValue({
                realtime: timeProps.realtime,
                isAutoRefreshEnabled: timeProps.realtime,
                refreshInterval: 5000,
                aggregation: timeProps.realtime ? null : timeProps.aggregation || null
            });
        }
        if (timeProps.realtime) {
            // Force aggregation to null when realtime is active
            if (this.formGroup.value.aggregation !== null) {
                this.formGroup.patchValue({ aggregation: null });
            }
            if (timeProps.currentDateContextInterval !== this.formGroup.value.interval) {
                this.formGroup.patchValue({ interval: timeProps.currentDateContextInterval });
            }
            this.timeProps = {
                dateFrom: new Date(timeProps.currentDateContextFromDate),
                dateTo: new Date(timeProps.currentDateContextToDate),
                interval: timeProps.currentDateContextInterval,
                realtime: timeProps.realtime,
                aggregation: timeProps.aggregation
            };
            return;
        }
        this.formGroup.patchValue({
            dateFrom: timeProps.currentDateContextFromDate,
            dateTo: timeProps.currentDateContextToDate,
            interval: timeProps.currentDateContextInterval,
            aggregation: timeProps.aggregation || null
        });
        this.timeProps = {
            dateFrom: new Date(timeProps.currentDateContextFromDate),
            dateTo: new Date(timeProps.currentDateContextToDate),
            interval: timeProps.currentDateContextInterval,
            realtime: timeProps.realtime,
            aggregation: timeProps.aggregation
        };
    }
    async onConfigurationChange(config) {
        const uniqueIds = this.datapointSyncService.getManagedObjectIds(config.datapoints || []);
        if (uniqueIds.length) {
            const managedObjectsResult = await this.dataExplorerService.loadManagedObjectsInChunks(uniqueIds);
            const managedObjects = managedObjectsResult.result;
            const errors = managedObjectsResult.errors;
            config.datapoints = this.datapointSyncService.assignUpdatedValues(config.datapoints, managedObjects, errors);
        }
        // Calculate date range based on interval if not provided
        const hasExplicitDates = this.isActualDate(config.dateFrom) && this.isActualDate(config.dateTo);
        let dateFrom, dateTo;
        if (hasExplicitDates) {
            dateFrom = new Date(config.dateFrom);
            dateTo = new Date(config.dateTo);
        }
        else {
            const intervalDef = INTERVALS.find(i => i.id === config.interval);
            dateTo = new Date();
            dateFrom = new Date(dateTo.getTime() - (intervalDef?.timespanInMs || 60 * 60 * 1000));
        }
        this.timeProps = {
            dateFrom,
            dateTo,
            interval: config?.interval,
            realtime: config?.realtime,
            aggregation: config?.realtime ? null : config?.aggregation
        };
        this.alarms = config.alarmsEventsConfigs.filter(ae => ae.timelineType === 'ALARM');
        this.events = config.alarmsEventsConfigs.filter(ae => ae.timelineType === 'EVENT');
        const configSummaryGS = this.chartHelpersService.getConfigSummaryForGainsight(config);
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_DATA_EXPLORER_AND_GRAPH.EVENTS.DATA_EXPLORER_AND_GRAPH, {
            component: PRODUCT_EXPERIENCE_DATA_EXPLORER_AND_GRAPH.COMPONENTS.DATA_EXPLORER_DETAILS,
            action: PRODUCT_EXPERIENCE_DATA_EXPLORER_AND_GRAPH.ACTIONS.DATA_EXPLORER_CONFIG_CHANGE,
            ...configSummaryGS
        });
        // Ensure realtime properties and dates are set correctly
        this.formGroup.patchValue({
            alarms: this.alarms,
            events: this.events,
            ...config,
            dateFrom,
            dateTo,
            isAutoRefreshEnabled: config.realtime ? true : config.isAutoRefreshEnabled || false,
            refreshInterval: config.realtime ? 5000 : config.refreshInterval || 0
        });
        // Update config directly to ensure ChartsComponent receives correct values
        // Create NEW object reference so Angular detects the change
        const { alarms, events, ...configValues } = this.formGroup.value;
        this.config = {
            ...this.config, // Keep existing properties
            ...configValues,
            alarmsEventsConfigs: [...(alarms || []), ...(events || [])]
        };
    }
    onSliderZoom(timeProps) {
        // When user manually zooms with slider, pause realtime and disable auto-refresh
        this.formGroup.patchValue({
            ...timeProps,
            realtime: false,
            isAutoRefreshEnabled: false,
            refreshInterval: 0
        });
        // When user zooms, it becomes a custom time range
        this.timeProps = {
            dateFrom: new Date(timeProps.dateFrom.getTime()),
            dateTo: new Date(timeProps.dateTo.getTime()),
            interval: 'custom',
            realtime: false
        };
        // Directly stop realtime and update the button state and interval
        if (this.timeContext) {
            this.timeContext.stopRealtime();
            const currentInterval = this.timeContext.form.value.currentDateContextInterval;
            setTimeout(() => {
                this.timeContext.form.patchValue({
                    currentDateContextFromDate: timeProps.dateFrom.toISOString(),
                    currentDateContextToDate: timeProps.dateTo.toISOString(),
                    temporaryUserSelectedFromDate: timeProps.dateFrom.toISOString(),
                    temporaryUserSelectedToDate: timeProps.dateTo.toISOString(),
                    realtime: false
                }, { emitEvent: false });
                // Enable aggregation control since realtime is now off
                this.timeContext.form.controls.aggregation.enable();
                if (currentInterval !== 'custom') {
                    this.timeContext.form.patchValue({
                        currentDateContextInterval: 'custom'
                    });
                }
                else {
                    this.timeContext['update']({
                        date: [timeProps.dateFrom, timeProps.dateTo],
                        interval: 'custom',
                        realtime: false,
                        aggregation: this.timeContext.form.value.aggregation
                    });
                }
            }, 0);
        }
    }
    updateTimeRangeOnRealtime(timeRange) {
        this.formGroup.patchValue(timeRange, { emitEvent: false });
    }
    updateAlarmsAndEvents(alarmsEventsConfigs) {
        this.alarms = alarmsEventsConfigs.filter(this.isAlarm);
        this.events = alarmsEventsConfigs.filter(this.isEvent);
        this.hasAtLeastOneAlarmActive = this.hasActiveAlarms(this.alarms);
    }
    handleDatapointOutOfSync(dpOutOfSync) {
        const key = (dp) => dp.__target?.id + dp.fragment + dp.series;
        const dpMatch = this.config.datapoints?.find(dp => key(dp) === key(dpOutOfSync));
        if (!dpMatch) {
            return;
        }
        this.datapointsOutOfSync.set(dpMatch, true);
    }
    updateActiveDatapoints(activeDatapoints) {
        this.activeDatapoints = [...activeDatapoints];
    }
    updateAggregatedSliderDatapoint(selectedDatapoint) {
        const aggregatedDatapoint = this.chartHelpersService.findMatchingDatapoint(this.activeDatapoints, selectedDatapoint);
        this.formGroup.patchValue({ aggregatedDatapoint });
    }
    async createNewReportWithWidget() {
        const modal = this.bsModalService.show(CreateNewReportModalComponent, {
            ignoreBackdropClick: true,
            keyboard: false,
            class: 'modal-sm'
        });
        const content = modal.content;
        try {
            const report = await content.result;
            const reportDashboard = await this.dataExplorerService.fetchReportDashboard(report.id);
            const widget = this.createWidgetConfig();
            reportDashboard.c8y_Dashboard.children = { [widget.id]: widget };
            await this.contextDashboardService.update(reportDashboard);
            this.alertService.success(gettext('Report and widget created.'));
        }
        catch (e) {
            if (e) {
                this.alertService.danger(gettext('Failed to create report and widget.'));
                this.alertService.addServerFailure(e);
            }
            // else: modal was closed
        }
    }
    async sendAsWidgetToReport() {
        const modal = this.bsModalService.show(SendAsWidgetToReportModal, {
            ignoreBackdropClick: true,
            keyboard: false,
            class: 'modal-sm'
        });
        const content = modal.content;
        try {
            const reports = await content.result;
            const selectedReports = Object.entries(reports).filter(([, value]) => value);
            const reportPromises = selectedReports.map(async ([reportId]) => {
                const reportDashboard = await this.dataExplorerService.fetchReportDashboard(reportId);
                const widget = this.createWidgetConfig();
                const children = reportDashboard.c8y_Dashboard.children || {};
                reportDashboard.c8y_Dashboard.children = { ...children, [widget.id]: widget };
                await this.contextDashboardService.update(reportDashboard);
            });
            await Promise.all(reportPromises);
            this.alertService.success(gettext('Widget created.'));
        }
        catch (e) {
            if (e) {
                this.alertService.danger(gettext('Failed to create widget.'));
                this.alertService.addServerFailure(e);
            }
            // else: modal was closed
        }
    }
    async sendAsWidgetToDashboard() {
        const modal = this.bsModalService.show(SendAsWidgetToDashboardModal, {
            ignoreBackdropClick: true,
            keyboard: false,
            class: 'modal-sm',
            initialState: {
                contextAsset: this.contextAsset
            }
        });
        const content = modal.content;
        try {
            const dashboards = await content.result;
            const selectedDashboards = Object.entries(dashboards).filter(([, value]) => value);
            const dashboardPromises = selectedDashboards.map(async ([dashboardId]) => {
                const dashboard = await this.dataExplorerService.fetchContextDashboard(dashboardId, this.contextAsset);
                const widget = this.createWidgetConfig();
                const children = dashboard.c8y_Dashboard.children || {};
                dashboard.c8y_Dashboard.children = { ...children, [widget.id]: widget };
                await this.contextDashboardService.update(dashboard);
            });
            await Promise.all(dashboardPromises);
            this.alertService.success(gettext('Widget created.'));
        }
        catch (e) {
            if (e) {
                this.alertService.danger(gettext('Failed to create widget.'));
                this.alertService.addServerFailure(e);
            }
            // else: modal was closed
        }
    }
    isActualDate(val) {
        if (!val)
            return false;
        const date = new Date(val);
        return date instanceof Date && !isNaN(date.getTime());
    }
    isAlarm(item) {
        return item.timelineType === 'ALARM';
    }
    isEvent(item) {
        return item.timelineType === 'EVENT';
    }
    hasActiveAlarms(alarms) {
        return alarms.length > 0 && alarms.some(alarm => alarm.__active);
    }
    checkForMatchingDatapoints() {
        const allMatch = this.config?.alarmsEventsConfigs?.every(ae => this.formGroup.value.datapoints?.some(dp => dp.__target?.id === ae.__target?.id));
        queueMicrotask(() => {
            this.alarmsOrEventsHaveNoMatchingDps = !allMatch;
        });
    }
    updateExportConfig() {
        const datapointDetails = this.config.datapoints
            .filter(({ __active }) => __active)
            .map(({ __target, fragment, series }) => ({
            deviceName: __target.name,
            source: __target.id,
            valueFragmentSeries: series,
            valueFragmentType: fragment
        }));
        if (datapointDetails.length === 0) {
            this.exportConfig = null;
        }
        else {
            this.exportConfig = {
                aggregation: this.config.aggregation,
                dateFrom: new Date(this.config.dateFrom).toISOString(),
                dateTo: new Date(this.config.dateTo).toISOString(),
                datapointDetails: datapointDetails
            };
        }
    }
    initializeContextSourceId() {
        const routeContext = this.contextRouteService.getContextData(this.activatedRoute);
        if (!routeContext) {
            return;
        }
        const { context, contextData } = routeContext;
        if ([ViewContext.Device, ViewContext.Group].includes(context)) {
            return contextData;
        }
    }
    createWidgetConfig() {
        return {
            name: gettext('Data points graph'),
            title: gettext('Data points'),
            _width: 24,
            _height: 12,
            config: this.config
        };
    }
    initForm() {
        return this.formBuilder.group({
            datapoints: [this.config.datapoints || []],
            aggregatedDatapoint: [this.config.aggregatedDatapoint || null],
            alarms: [this.alarms || []],
            events: [this.events || []],
            dateFrom: [this.config.dateFrom || null],
            dateTo: [this.config.dateFrom || null],
            interval: [this.config.interval || 'hours'],
            aggregation: [this.config.aggregation || null],
            realtime: [this.config.realtime || false],
            isAutoRefreshEnabled: [this.config.isAutoRefreshEnabled || false],
            refreshInterval: [this.config.refreshInterval || 5000],
            displayMarkedLine: [true, []],
            displayMarkedPoint: [true, []],
            mergeMatchingDatapoints: [true, []],
            forceMergeDatapoints: [false, []],
            showLabelAndUnit: [true, []],
            showSlider: [true, []],
            displayDateSelection: [false, []],
            yAxisSplitLines: [false],
            xAxisSplitLines: [false],
            numberOfDecimalPlaces: [2, [Validators.required, Validators.min(0), Validators.max(10)]]
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DatapointExplorerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DatapointExplorerComponent, isStandalone: true, selector: "c8y-datapoint-explorer", providers: [
            ChartEventsService,
            ChartAlarmsService,
            ChartHelpersService,
            WidgetTimeContextDateRangeService
        ], viewQueries: [{ propertyName: "chart", first: true, predicate: ["chart"], descendants: true }, { propertyName: "timeContext", first: true, predicate: ["timeContext"], descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Data explorer' | translate }}</c8y-title>\n\n<c8y-time-context\n  #timeContext\n  (contextChange)=\"onTimeContextChange($event)\"\n  [changedDateContext]=\"timeProps\"\n  [timeContext]=\"(settings$ | async)?.timeContext\"\n></c8y-time-context>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n  <c8y-workspace-config\n    [updatedConfig]=\"config\"\n    [silent]=\"(settings$ | async)?.hideWorkspaceConfig\"\n    (onConfigurationChange)=\"onConfigurationChange($event)\"\n  ></c8y-workspace-config>\n</c8y-action-bar-item>\n\n@if (!(settings$ | async)?.hideExportSelector) {\n  <c8y-action-bar-item [placement]=\"'right'\">\n    <c8y-datapoints-export-selector\n      [exportConfig]=\"exportConfig\"\n      [containerClass]=\"'d-contents'\"\n    ></c8y-datapoints-export-selector>\n  </c8y-action-bar-item>\n}\n\n@if (!(settings$ | async)?.hideWidgetActions) {\n  @if (contextAsset) {\n    <c8y-action-bar-item\n      [placement]=\"'more'\"\n      [priority]=\"-2000\"\n    >\n      <button\n        class=\"btn btn-link\"\n        title=\"{{ 'Send as widget to dashboard' | translate }}\"\n        type=\"button\"\n        data-cy=\"widgets-dashboard--copy-dashboard\"\n        (click)=\"sendAsWidgetToDashboard()\"\n        [disabled]=\"config?.datapoints?.length === 0 || !canAddReport\"\n      >\n        <i c8yIcon=\"th\"></i>\n        <span>{{ 'Send as widget to dashboard' | translate }}</span>\n      </button>\n    </c8y-action-bar-item>\n  } @else {\n    <c8y-action-bar-item\n      [placement]=\"'more'\"\n      [priority]=\"-2000\"\n    >\n      <button\n        title=\"{{ 'Send as widget to report' | translate }}\"\n        type=\"button\"\n        data-cy=\"widgets-dashboard--copy-dashboard\"\n        (click)=\"sendAsWidgetToReport()\"\n        [disabled]=\"config?.datapoints?.length === 0 || !canAddReport\"\n      >\n        <i c8yIcon=\"c8y-reports\"></i>\n        <span>{{ 'Send as widget to report' | translate }}</span>\n      </button>\n    </c8y-action-bar-item>\n\n    <c8y-action-bar-item\n      [placement]=\"'more'\"\n      [priority]=\"-2000\"\n    >\n      <button\n        title=\"{{ 'Create a new report with widget' | translate }}\"\n        type=\"button\"\n        data-cy=\"widgets-dashboard--copy-dashboard\"\n        (click)=\"createNewReportWithWidget()\"\n        [disabled]=\"config?.datapoints?.length === 0 || !canAddReport\"\n      >\n        <i c8yIcon=\"c8y-reports\"></i>\n        <span>{{ 'Create a new report with widget' | translate }}</span>\n      </button>\n    </c8y-action-bar-item>\n  }\n}\n\n<div class=\"content-fullpage d-grid grid__col--auto-360 gap-24\">\n  <div class=\"d-col gap-16\">\n    <c8y-charts\n      class=\"flex-grow data-point-explorer\"\n      #chart\n      [config]=\"config\"\n      [alerts]=\"alerts\"\n      [chartViewContext]=\"chartViewContext\"\n      (updateAlarmsAndEvents)=\"updateAlarmsAndEvents($event)\"\n      (configChangeOnZoomOut)=\"onSliderZoom($event)\"\n      (datapointOutOfSync)=\"handleDatapointOutOfSync($event)\"\n      (timeRangeChangeOnRealtime)=\"updateTimeRangeOnRealtime($event)\"\n      (isMarkedAreaEnabled)=\"isMarkedAreaEnabled = $event\"\n      (updateActiveDatapoints)=\"updateActiveDatapoints($event)\"\n      (updateAggregatedSliderDatapoint)=\"updateAggregatedSliderDatapoint($event)\"\n    ></c8y-charts>\n    <form\n      class=\"m-l-48 m-r-48\"\n      [formGroup]=\"formGroup\"\n    >\n      <div class=\"d-grid-lg grid__col--4-4-4 gap-16\">\n        <fieldset class=\"c8y-fieldset form-group-sm m-t-md-0 p-b-8\">\n          <legend>{{ 'Axis' | translate }}</legend>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Y-axis helper lines' | translate\"\n          >\n            <input\n              name=\"yAxisSplitLines\"\n              type=\"checkbox\"\n              formControlName=\"yAxisSplitLines\"\n            />\n            <span></span>\n            <span translate>Y-axis helper lines</span>\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'X-axis helper lines' | translate\"\n          >\n            <input\n              name=\"xAxisSplitLines\"\n              type=\"checkbox\"\n              formControlName=\"xAxisSplitLines\"\n            />\n            <span></span>\n            <span translate>X-axis helper lines</span>\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Merge matching data points into single axis' | translate\"\n          >\n            <input\n              name=\"mergeMatchingDatapoints\"\n              type=\"checkbox\"\n              formControlName=\"mergeMatchingDatapoints\"\n            />\n            <span></span>\n            <span translate>Merge matching data points into single axis</span>\n            <button\n              class=\"btn-dot m-l-8\"\n              [attr.aria-label]=\"\n                'Data points with the same min and max values will be merged into a single axis. The values must be defined in the data point configuration.'\n                  | translate\n              \"\n              [tooltip]=\"\n                'Data points with the same min and max values will be merged into a single axis. The values must be defined in the data point configuration.'\n                  | translate\n              \"\n              container=\"body\"\n              type=\"button\"\n              (click)=\"$event.stopPropagation()\"\n              [adaptivePosition]=\"false\"\n            >\n              <i\n                class=\"text-info\"\n                c8yIcon=\"info\"\n              ></i>\n            </button>\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Force merge all data points into single axis' | translate\"\n          >\n            <input\n              name=\"forceMergeDatapoints\"\n              type=\"checkbox\"\n              formControlName=\"forceMergeDatapoints\"\n            />\n            <span></span>\n            <span translate>Force merge all data points into single axis</span>\n            <button\n              class=\"btn-dot m-l-8\"\n              [attr.aria-label]=\"\n                'All axes will be force merged to a single axis with the scale being set to the max and min value of all axes. It\\'s recommended to use this option for data points with similar values.'\n                  | translate\n              \"\n              [tooltip]=\"\n                'All axes will be force merged to a single axis with the scale being set to the max and min value of all axes. It\\'s recommended to use this option for data points with similar values.'\n                  | translate\n              \"\n              container=\"body\"\n              type=\"button\"\n              (click)=\"$event.stopPropagation()\"\n              [adaptivePosition]=\"false\"\n            >\n              <i\n                class=\"text-info\"\n                c8yIcon=\"info\"\n              ></i>\n            </button>\n          </label>\n        </fieldset>\n        <fieldset class=\"c8y-fieldset form-group-sm m-t-md-0 p-b-8\">\n          <legend>{{ 'Alarms & events' | translate }}</legend>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Show vertical line when alarm occurs' | translate\"\n          >\n            <input\n              name=\"displayMarkedLine\"\n              type=\"checkbox\"\n              formControlName=\"displayMarkedLine\"\n            />\n            <span></span>\n            <span translate>Show vertical line on every occurrence</span>\n          </label>\n\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Show icon when alarm or event occurs' | translate\"\n          >\n            <input\n              name=\"displayMarkedPoint\"\n              type=\"checkbox\"\n              formControlName=\"displayMarkedPoint\"\n            />\n            <span></span>\n            <span>\n              {{\n                'Show icon when triggered`When alarms and events occur the icon will be shown`'\n                  | translate\n              }}\n            </span>\n            @if (alarmsOrEventsHaveNoMatchingDps) {\n              <button\n                class=\"btn-dot m-l-8\"\n                [attr.aria-label]=\"\n                  'Some alarms or events have no matching data points. No icons will be shown for them.'\n                    | translate\n                \"\n                [tooltip]=\"\n                  'Some alarms or events have no matching data points. No icons will be shown for them.'\n                    | translate\n                \"\n                container=\"body\"\n                type=\"button\"\n                (click)=\"$event.stopPropagation()\"\n                [adaptivePosition]=\"false\"\n              >\n                <i\n                  class=\"text-info\"\n                  c8yIcon=\"info\"\n                ></i>\n              </button>\n            }\n          </label>\n        </fieldset>\n        <fieldset class=\"c8y-fieldset form-group-sm m-t-md-0 p-b-8\">\n          <legend>{{ 'Chart' | translate }}</legend>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Show labels and units' | translate\"\n          >\n            <input\n              name=\"showLabelAndUnit\"\n              type=\"checkbox\"\n              formControlName=\"showLabelAndUnit\"\n            />\n            <span></span>\n            <span translate>Display labels and units on Y-axis</span>\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Show slider' | translate\"\n          >\n            <input\n              name=\"showSlider\"\n              type=\"checkbox\"\n              formControlName=\"showSlider\"\n            />\n            <span></span>\n            <span translate>Show slider</span>\n          </label>\n        </fieldset>\n      </div>\n    </form>\n  </div>\n  <div class=\"card inner-scroll bg-level-1\">\n    <form\n      class=\"bg-inherit\"\n      [formGroup]=\"formGroup\"\n    >\n      <c8y-datapoint-selection-list\n        class=\"bg-inherit separator-top d-block\"\n        name=\"datapoints\"\n        [minActiveCount]=\"0\"\n        [defaultFormOptions]=\"datapointSelectDefaultFormOptions\"\n        [config]=\"{ contextAsset: contextAsset }\"\n        formControlName=\"datapoints\"\n        [allowDragAndDrop]=\"true\"\n      ></c8y-datapoint-selection-list>\n\n      <c8y-alarm-event-selection-list\n        class=\"bg-inherit\"\n        name=\"alarms\"\n        formControlName=\"alarms\"\n        [timelineType]=\"'ALARM'\"\n        [datapoints]=\"config.datapoints\"\n      ></c8y-alarm-event-selection-list>\n\n      <c8y-alarm-event-selection-list\n        class=\"bg-inherit\"\n        name=\"events\"\n        formControlName=\"events\"\n        [timelineType]=\"'EVENT'\"\n        [datapoints]=\"config.datapoints\"\n      ></c8y-alarm-event-selection-list>\n\n      <div class=\"p-l-16 p-r-16 form-group p-b-16\">\n        <label\n          [title]=\"'Number of decimal places' | translate\"\n          translate\n        >\n          Number of decimal places\n        </label>\n        <input\n          class=\"form-control\"\n          name=\"numberOfDecimalPlaces\"\n          type=\"number\"\n          formControlName=\"numberOfDecimalPlaces\"\n          [placeholder]=\"'e.g. {{ example }}' | translate: { example: 1 }\"\n        />\n        <c8y-messages\n          [show]=\"\n            formGroup.controls?.numberOfDecimalPlaces?.touched &&\n            formGroup?.controls?.numberOfDecimalPlaces?.errors\n          \"\n        ></c8y-messages>\n      </div>\n    </form>\n  </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.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: i2$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i2.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DatapointSelectorModule }, { kind: "component", type: i3$1.DatapointSelectionListComponent, selector: "c8y-datapoint-selection-list", inputs: ["actions", "allowDragAndDrop", "config", "defaultFormOptions", "maxActiveCount", "minActiveCount", "resolveContext", "listTitle"], outputs: ["isValid", "change"] }, { kind: "ngmodule", type: AlarmEventSelectorModule }, { kind: "component", type: i4$1.AlarmEventSelectionListComponent, selector: "c8y-alarm-event-selection-list", inputs: ["timelineType", "canRemove", "canEdit", "canDragAndDrop", "title", "addButtonLabel", "hideSource", "inline", "activeToggleAsSwitch", "omitProperties", "datapoints", "config"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.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: PopoverModule }, { kind: "component", type: TimeContextComponent, selector: "c8y-time-context", inputs: ["changedDateContext", "controlsAvailable", "timeContext", "context"], outputs: ["contextChange"] }, { kind: "component", type: ChartsComponent, selector: "c8y-charts", inputs: ["config", "alerts", "chartViewContext"], outputs: ["configChangeOnZoomOut", "timeRangeChangeOnRealtime", "datapointOutOfSync", "updateAlarmsAndEvents", "isMarkedAreaEnabled", "finishLoading", "updateActiveDatapoints", "updateAggregatedSliderDatapoint"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "ngmodule", type: A11yModule }, { kind: "component", type: DatapointsExportSelectorComponent, selector: "c8y-datapoints-export-selector", inputs: ["containerClass", "exportConfig"], outputs: ["isOpen"] }, { kind: "component", type: WorkspaceConfigComponent, selector: "c8y-workspace-config", inputs: ["updatedConfig", "silent", "defaultConfigurationId"], outputs: ["onConfigurationChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DatapointExplorerComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-datapoint-explorer', standalone: true, imports: [
                        CoreModule,
                        CommonModule,
                        DatapointSelectorModule,
                        AlarmEventSelectorModule,
                        TooltipModule,
                        PopoverModule,
                        TimeContextComponent,
                        ChartsComponent,
                        BsDropdownModule,
                        FormsModule$1,
                        A11yModule,
                        DatapointsExportSelectorComponent,
                        WorkspaceConfigComponent,
                        IconDirective
                    ], providers: [
                        ChartEventsService,
                        ChartAlarmsService,
                        ChartHelpersService,
                        WidgetTimeContextDateRangeService
                    ], template: "<c8y-title>{{ 'Data explorer' | translate }}</c8y-title>\n\n<c8y-time-context\n  #timeContext\n  (contextChange)=\"onTimeContextChange($event)\"\n  [changedDateContext]=\"timeProps\"\n  [timeContext]=\"(settings$ | async)?.timeContext\"\n></c8y-time-context>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n  <c8y-workspace-config\n    [updatedConfig]=\"config\"\n    [silent]=\"(settings$ | async)?.hideWorkspaceConfig\"\n    (onConfigurationChange)=\"onConfigurationChange($event)\"\n  ></c8y-workspace-config>\n</c8y-action-bar-item>\n\n@if (!(settings$ | async)?.hideExportSelector) {\n  <c8y-action-bar-item [placement]=\"'right'\">\n    <c8y-datapoints-export-selector\n      [exportConfig]=\"exportConfig\"\n      [containerClass]=\"'d-contents'\"\n    ></c8y-datapoints-export-selector>\n  </c8y-action-bar-item>\n}\n\n@if (!(settings$ | async)?.hideWidgetActions) {\n  @if (contextAsset) {\n    <c8y-action-bar-item\n      [placement]=\"'more'\"\n      [priority]=\"-2000\"\n    >\n      <button\n        class=\"btn btn-link\"\n        title=\"{{ 'Send as widget to dashboard' | translate }}\"\n        type=\"button\"\n        data-cy=\"widgets-dashboard--copy-dashboard\"\n        (click)=\"sendAsWidgetToDashboard()\"\n        [disabled]=\"config?.datapoints?.length === 0 || !canAddReport\"\n      >\n        <i c8yIcon=\"th\"></i>\n        <span>{{ 'Send as widget to dashboard' | translate }}</span>\n      </button>\n    </c8y-action-bar-item>\n  } @else {\n    <c8y-action-bar-item\n      [placement]=\"'more'\"\n      [priority]=\"-2000\"\n    >\n      <button\n        title=\"{{ 'Send as widget to report' | translate }}\"\n        type=\"button\"\n        data-cy=\"widgets-dashboard--copy-dashboard\"\n        (click)=\"sendAsWidgetToReport()\"\n        [disabled]=\"config?.datapoints?.length === 0 || !canAddReport\"\n      >\n        <i c8yIcon=\"c8y-reports\"></i>\n        <span>{{ 'Send as widget to report' | translate }}</span>\n      </button>\n    </c8y-action-bar-item>\n\n    <c8y-action-bar-item\n      [placement]=\"'more'\"\n      [priority]=\"-2000\"\n    >\n      <button\n        title=\"{{ 'Create a new report with widget' | translate }}\"\n        type=\"button\"\n        data-cy=\"widgets-dashboard--copy-dashboard\"\n        (click)=\"createNewReportWithWidget()\"\n        [disabled]=\"config?.datapoints?.length === 0 || !canAddReport\"\n      >\n        <i c8yIcon=\"c8y-reports\"></i>\n        <span>{{ 'Create a new report with widget' | translate }}</span>\n      </button>\n    </c8y-action-bar-item>\n  }\n}\n\n<div class=\"content-fullpage d-grid grid__col--auto-360 gap-24\">\n  <div class=\"d-col gap-16\">\n    <c8y-charts\n      class=\"flex-grow data-point-explorer\"\n      #chart\n      [config]=\"config\"\n      [alerts]=\"alerts\"\n      [chartViewContext]=\"chartViewContext\"\n      (updateAlarmsAndEvents)=\"updateAlarmsAndEvents($event)\"\n      (configChangeOnZoomOut)=\"onSliderZoom($event)\"\n      (datapointOutOfSync)=\"handleDatapointOutOfSync($event)\"\n      (timeRangeChangeOnRealtime)=\"updateTimeRangeOnRealtime($event)\"\n      (isMarkedAreaEnabled)=\"isMarkedAreaEnabled = $event\"\n      (updateActiveDatapoints)=\"updateActiveDatapoints($event)\"\n      (updateAggregatedSliderDatapoint)=\"updateAggregatedSliderDatapoint($event)\"\n    ></c8y-charts>\n    <form\n      class=\"m-l-48 m-r-48\"\n      [formGroup]=\"formGroup\"\n    >\n      <div class=\"d-grid-lg grid__col--4-4-4 gap-16\">\n        <fieldset class=\"c8y-fieldset form-group-sm m-t-md-0 p-b-8\">\n          <legend>{{ 'Axis' | translate }}</legend>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Y-axis helper lines' | translate\"\n          >\n            <input\n              name=\"yAxisSplitLines\"\n              type=\"checkbox\"\n              formControlName=\"yAxisSplitLines\"\n            />\n            <span></span>\n            <span translate>Y-axis helper lines</span>\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'X-axis helper lines' | translate\"\n          >\n            <input\n              name=\"xAxisSplitLines\"\n              type=\"checkbox\"\n              formControlName=\"xAxisSplitLines\"\n            />\n            <span></span>\n            <span translate>X-axis helper lines</span>\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Merge matching data points into single axis' | translate\"\n          >\n            <input\n              name=\"mergeMatchingDatapoints\"\n              type=\"checkbox\"\n              formControlName=\"mergeMatchingDatapoints\"\n            />\n            <span></span>\n            <span translate>Merge matching data points into single axis</span>\n            <button\n              class=\"btn-dot m-l-8\"\n              [attr.aria-label]=\"\n                'Data points with the same min and max values will be merged into a single axis. The values must be defined in the data point configuration.'\n                  | translate\n              \"\n              [tooltip]=\"\n                'Data points with the same min and max values will be merged into a single axis. The values must be defined in the data point configuration.'\n                  | translate\n              \"\n              container=\"body\"\n              type=\"button\"\n              (click)=\"$event.stopPropagation()\"\n              [adaptivePosition]=\"false\"\n            >\n              <i\n                class=\"text-info\"\n                c8yIcon=\"info\"\n              ></i>\n            </button>\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Force merge all data points into single axis' | translate\"\n          >\n            <input\n              name=\"forceMergeDatapoints\"\n              type=\"checkbox\"\n              formControlName=\"forceMergeDatapoints\"\n            />\n            <span></span>\n            <span translate>Force merge all data points into single axis</span>\n            <button\n              class=\"btn-dot m-l-8\"\n              [attr.aria-label]=\"\n                'All axes will be force merged to a single axis with the scale being set to the max and min value of all axes. It\\'s recommended to use this option for data points with similar values.'\n                  | translate\n              \"\n              [tooltip]=\"\n                'All axes will be force merged to a single axis with the scale being set to the max and min value of all axes. It\\'s recommended to use this option for data points with similar values.'\n                  | translate\n              \"\n              container=\"body\"\n              type=\"button\"\n              (click)=\"$event.stopPropagation()\"\n              [adaptivePosition]=\"false\"\n            >\n              <i\n                class=\"text-info\"\n                c8yIcon=\"info\"\n              ></i>\n            </button>\n          </label>\n        </fieldset>\n        <fieldset class=\"c8y-fieldset form-group-sm m-t-md-0 p-b-8\">\n          <legend>{{ 'Alarms & events' | translate }}</legend>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Show vertical line when alarm occurs' | translate\"\n          >\n            <input\n              name=\"displayMarkedLine\"\n              type=\"checkbox\"\n              formControlName=\"displayMarkedLine\"\n            />\n            <span></span>\n            <span translate>Show vertical line on every occurrence</span>\n          </label>\n\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Show icon when alarm or event occurs' | translate\"\n          >\n            <input\n              name=\"displayMarkedPoint\"\n              type=\"checkbox\"\n              formControlName=\"displayMarkedPoint\"\n            />\n            <span></span>\n            <span>\n              {{\n                'Show icon when triggered`When alarms and events occur the icon will be shown`'\n                  | translate\n              }}\n            </span>\n            @if (alarmsOrEventsHaveNoMatchingDps) {\n              <button\n                class=\"btn-dot m-l-8\"\n                [attr.aria-label]=\"\n                  'Some alarms or events have no matching data points. No icons will be shown for them.'\n                    | translate\n                \"\n                [tooltip]=\"\n                  'Some alarms or events have no matching data points. No icons will be shown for them.'\n                    | translate\n                \"\n                container=\"body\"\n                type=\"button\"\n                (click)=\"$event.stopPropagation()\"\n                [adaptivePosition]=\"false\"\n              >\n                <i\n                  class=\"text-info\"\n                  c8yIcon=\"info\"\n                ></i>\n              </button>\n            }\n          </label>\n        </fieldset>\n        <fieldset class=\"c8y-fieldset form-group-sm m-t-md-0 p-b-8\">\n          <legend>{{ 'Chart' | translate }}</legend>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Show labels and units' | translate\"\n          >\n            <input\n              name=\"showLabelAndUnit\"\n              type=\"checkbox\"\n              formControlName=\"showLabelAndUnit\"\n            />\n            <span></span>\n            <span translate>Display labels and units on Y-axis</span>\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"'Show slider' | translate\"\n          >\n            <input\n              name=\"showSlider\"\n              type=\"checkbox\"\n              formControlName=\"showSlider\"\n            />\n            <span></span>\n            <span translate>Show slider</span>\n          </label>\n        </fieldset>\n      </div>\n    </form>\n  </div>\n  <div class=\"card inner-scroll bg-level-1\">\n    <form\n      class=\"bg-inherit\"\n      [formGroup]=\"formGroup\"\n    >\n      <c8y-datapoint-selection-list\n        class=\"bg-inherit separator-top d-block\"\n        name=\"datapoints\"\n        [minActiveCount]=\"0\"\n        [defaultFormOptions]=\"datapointSelectDefaultFormOptions\"\n        [config]=\"{ contextAsset: contextAsset }\"\n        formControlName=\"datapoints\"\n        [allowDragAndDrop]=\"true\"\n      ></c8y-datapoint-selection-list>\n\n      <c8y-alarm-event-selection-list\n        class=\"bg-inherit\"\n        name=\"alarms\"\n        formControlName=\"alarms\"\n        [timelineType]=\"'ALARM'\"\n        [datapoints]=\"config.datapoints\"\n      ></c8y-alarm-event-selection-list>\n\n      <c8y-alarm-event-selection-list\n        class=\"bg-inherit\"\n        name=\"events\"\n        formControlName=\"events\"\n        [timelineType]=\"'EVENT'\"\n        [datapoints]=\"config.datapoints\"\n      ></c8y-alarm-event-selection-list>\n\n      <div class=\"p-l-16 p-r-16 form-group p-b-16\">\n        <label\n          [title]=\"'Number of decimal places' | translate\"\n          translate\n        >\n          Number of decimal places\n        </label>\n        <input\n          class=\"form-control\"\n          name=\"numberOfDecimalPlaces\"\n          type=\"number\"\n          formControlName=\"numberOfDecimalPlaces\"\n          [placeholder]=\"'e.g. {{ example }}' | translate: { example: 1 }\"\n        />\n        <c8y-messages\n          [show]=\"\n            formGroup.controls?.numberOfDecimalPlaces?.touched &&\n            formGroup?.controls?.numberOfDecimalPlaces?.errors\n          \"\n        ></c8y-messages>\n      </div>\n    </form>\n  </div>\n</div>\n" }]
        }], ctorParameters: () => [], propDecorators: { chart: [{
                type: ViewChild,
                args: ['chart']
            }], timeContext: [{
                type: ViewChild,
                args: ['timeContext']
            }] } });

/**
 * Generated bundle index. Do not edit.
 */

export { DATA_EXPLORER_BASE_CONFIG, DataExplorerService, DatapointExplorerComponent, KEY_MAP, NameGeneratorService, REVERSE_KEY_MAP, WorkspaceConfigurationService };
//# sourceMappingURL=c8y-ngx-components-datapoint-explorer-view.mjs.map