UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

250 lines (242 loc) 26.4 kB
import * as i0 from '@angular/core'; import { Injectable, Component, Input, ViewChild, makeEnvironmentProviders } from '@angular/core'; import { FormsModule } from '@angular/forms'; import * as i3 from '@angular/router'; import { RouterModule } from '@angular/router'; import * as i2 from '@c8y/ngx-components'; import { CoreModule, ViewContext, EventRealtimeService, ActionBarModule, TimeIntervalComponent, hookRoute, gettext } from '@c8y/ngx-components'; import * as i1 from '@c8y/client'; import { identity, isEmpty, last, first } from 'lodash-es'; import { BehaviorSubject, Subject, combineLatest, pipe } from 'rxjs'; import { map, share, distinctUntilChanged, switchMap, tap } from 'rxjs/operators'; import * as i5 from '@angular/common'; import * as i4 from '@c8y/ngx-components/map'; import { MapComponent, MapModule } from '@c8y/ngx-components/map'; const LOCATION_UPDATE_EVENT_TYPE = 'c8y_LocationUpdate'; class TrackingService { static { this.BASE_FILTER = { pageSize: 1000, withTotalPages: true, type: LOCATION_UPDATE_EVENT_TYPE }; } constructor(eventService, geo) { this.eventService = eventService; this.geo = geo; this.trackVisible = true; this.hasEvents = false; this._polylineEventsSubject$ = new BehaviorSubject([]); this.deviceId$ = new Subject(); this.timeInterval$ = new Subject(); this.reload$ = new BehaviorSubject(null); this.polyline$ = this._polylineEventsSubject$.asObservable().pipe(map(events => (events || []).map(event => this.geo.getLatLong(event)).filter(identity)), share()); this.events$ = combineLatest([ this.deviceId$.pipe(distinctUntilChanged()), this.timeInterval$, this.reload$ ]).pipe(switchMap(([source, interval]) => { const { dateFrom, dateTo } = interval; return this.eventService.list({ ...TrackingService.BASE_FILTER, source, dateFrom: dateFrom.toISOString(), dateTo: dateTo.toISOString() }); }), tap(() => this._polylineEventsSubject$.next([])), share()); this.pipe = pipe(tap(events => (this.hasEvents = !isEmpty(events))), map((events) => (events || []).filter(event => this.isMatchingEvent(event))), tap((events) => { const prepend = this.compareEvents(last(this._polylineEventsSubject$.value), first(events)) < 0; const polyline = prepend ? [...events, ...this._polylineEventsSubject$.value] : [...this._polylineEventsSubject$.value, ...events]; this._polylineEventsSubject$.next(polyline); })); } setDeviceId(deviceId) { this.deviceId$.next(deviceId); } setInterval(interval) { this.timeInterval$.next(interval); } clearTrack() { this._polylineEventsSubject$.next([]); } reload() { this.reload$.next(); } async latestPositionUpdate(mo) { const dateTo = new Date(); dateTo.setDate(dateTo.getDate() + 1); const filters = { fragmentType: 'c8y_Position', dateFrom: new Date(0).toISOString(), dateTo: dateTo.toISOString(), pageSize: 1, source: mo.id }; const events = await this.eventService.list(filters); return events?.data?.length ? new Date(events.data[0].time) : undefined; } toggleTrack() { if (this.trackVisible) { this.clearTrack(); } else { this.reload(); } this.trackVisible = !this.trackVisible; } isLocationUpdateEvent(event) { return event.type === LOCATION_UPDATE_EVENT_TYPE; } isMatchingEvent(event) { return this.isLocationUpdateEvent(event); } compareEvents(a, b) { return Date.parse(a?.time) - Date.parse(b?.time); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingService, deps: [{ token: i1.EventService }, { token: i2.GeoService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.EventService }, { type: i2.GeoService }] }); class TrackingMarkerPopupComponent { constructor(trackingService) { this.trackingService = trackingService; /** * Displays link to device tracking tab. */ this.showTrackingLink = false; } async ngOnInit() { this.isDevice = !this.trackingService.isLocationUpdateEvent(this.context); if (this.isDevice) { this.trackingService.setDeviceId(this.context.id); this.date = await this.trackingService.latestPositionUpdate(this.context); } else { this.date = this.context.time; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingMarkerPopupComponent, deps: [{ token: TrackingService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: TrackingMarkerPopupComponent, isStandalone: true, selector: "c8y-tracking-marker-popup", inputs: { context: "context", showTrackingLink: "showTrackingLink" }, ngImport: i0, template: "<div class=\"map-marker\">\n <a\n class=\"text-truncate text-14 text-medium p-0 m-b-8 deviceLink\"\n [title]=\"context?.name\"\n *ngIf=\"isDevice\"\n [routerLink]=\"['/device/', context?.id]\"\n >\n {{ context?.name }}\n </a>\n <div\n class=\"m-b-8\"\n ng-if=\"lastUpdated\"\n >\n <p class=\"m-0\">{{ 'Position:' | translate }}</p>\n <div class=\"text-muted\">\n <p class=\"m-b-0\">{{ context?.c8y_Position?.lat }},</p>\n <p class=\"m-t-0\">{{ context?.c8y_Position?.lng }}</p>\n </div>\n @if (!!context?.c8y_Position?.alt || context?.c8y_Position?.alt === 0) {\n <p class=\"m-0\">{{ 'Altitude:' | translate }}</p>\n <div class=\"text-muted\">\n <p\n class=\"m-b-0\"\n [translate]=\"'{{alt}} m`meters, altitude`'\"\n [translateParams]=\"{ alt: context?.c8y_Position?.alt }\"\n ></p>\n </div>\n }\n @if (!!date) {\n <p class=\"m-0 p-t-4\">{{ 'Date and time:' | translate }}</p>\n <span class=\"text-muted\">{{ date | c8yDate }}</span>\n }\n </div>\n\n @if (isDevice) {\n @if (showTrackingLink) {\n <span>\n Go to\n <a [routerLink]=\"['/device', context?.id, 'tracking']\">Tracking</a>\n </span>\n } @else {\n <div class=\"d-flex a-i-center\">\n <label\n class=\"c8y-switch\"\n for=\"switch\"\n >\n <input\n id=\"switch\"\n type=\"checkbox\"\n [checked]=\"trackingService.trackVisible\"\n (change)=\"trackingService.toggleTrack()\"\n />\n <span></span>\n </label>\n <div class=\"description p-b-0\">\n {{ 'Show track' | translate }}\n </div>\n </div>\n }\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.DatePipe, name: "c8yDate" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: FormsModule }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingMarkerPopupComponent, decorators: [{ type: Component, args: [{ standalone: true, selector: 'c8y-tracking-marker-popup', imports: [CoreModule, RouterModule, FormsModule], template: "<div class=\"map-marker\">\n <a\n class=\"text-truncate text-14 text-medium p-0 m-b-8 deviceLink\"\n [title]=\"context?.name\"\n *ngIf=\"isDevice\"\n [routerLink]=\"['/device/', context?.id]\"\n >\n {{ context?.name }}\n </a>\n <div\n class=\"m-b-8\"\n ng-if=\"lastUpdated\"\n >\n <p class=\"m-0\">{{ 'Position:' | translate }}</p>\n <div class=\"text-muted\">\n <p class=\"m-b-0\">{{ context?.c8y_Position?.lat }},</p>\n <p class=\"m-t-0\">{{ context?.c8y_Position?.lng }}</p>\n </div>\n @if (!!context?.c8y_Position?.alt || context?.c8y_Position?.alt === 0) {\n <p class=\"m-0\">{{ 'Altitude:' | translate }}</p>\n <div class=\"text-muted\">\n <p\n class=\"m-b-0\"\n [translate]=\"'{{alt}} m`meters, altitude`'\"\n [translateParams]=\"{ alt: context?.c8y_Position?.alt }\"\n ></p>\n </div>\n }\n @if (!!date) {\n <p class=\"m-0 p-t-4\">{{ 'Date and time:' | translate }}</p>\n <span class=\"text-muted\">{{ date | c8yDate }}</span>\n }\n </div>\n\n @if (isDevice) {\n @if (showTrackingLink) {\n <span>\n Go to\n <a [routerLink]=\"['/device', context?.id, 'tracking']\">Tracking</a>\n </span>\n } @else {\n <div class=\"d-flex a-i-center\">\n <label\n class=\"c8y-switch\"\n for=\"switch\"\n >\n <input\n id=\"switch\"\n type=\"checkbox\"\n [checked]=\"trackingService.trackVisible\"\n (change)=\"trackingService.toggleTrack()\"\n />\n <span></span>\n </label>\n <div class=\"description p-b-0\">\n {{ 'Show track' | translate }}\n </div>\n </div>\n }\n }\n</div>\n" }] }], ctorParameters: () => [{ type: TrackingService }], propDecorators: { context: [{ type: Input }], showTrackingLink: [{ type: Input }] } }); class TrackingTabFactory { constructor(contextRouteService, geoService) { this.contextRouteService = contextRouteService; this.geoService = geoService; } canActivate(snapshot) { const contextData = this.contextRouteService.getContextData(snapshot); return (contextData?.context === ViewContext.Device && !isEmpty(this.geoService.getLatLong(contextData?.contextData))); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingTabFactory, deps: [{ token: i2.ContextRouteService }, { token: i2.GeoService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingTabFactory, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingTabFactory, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i2.ContextRouteService }, { type: i2.GeoService }] }); class TrackingComponent { constructor(service, realtime, contextRouteService, activatedRoute) { this.service = service; this.realtime = realtime; this.contextRouteService = contextRouteService; this.activatedRoute = activatedRoute; this.dateRangePickerConfig = { adaptivePosition: true, showPreviousMonth: true, preventChangeToNextMonth: true }; this.config = { realtime: true, follow: false, zoomLevel: 12, fitBoundsOptions: { padding: [50, 50] } }; this.maxDate = new Date(); this.activeMarkers = {}; this.realtimeDisabled = false; } async ngOnInit() { const { contextData } = this.contextRouteService.getContextData(this.activatedRoute); this.device = contextData; } async ngAfterViewInit() { this.service.setDeviceId(this.device.id); this.togglePositionRealtime(this.realtime.active); } toggleMarker(event) { let marker = this.map.findMarker(event); if (marker) { this.map.removeMarker(marker); delete this.activeMarkers[`p${event.id}`]; } else { marker = this.map.getTrackingMarker(event); this.map.addMarkerToMap(marker); this.activeMarkers[`p${event.id}`] = true; } } togglePositionRealtime(active) { this.config = { ...this.config, realtime: active }; } toggleRealtime(interval) { const currentTimeInRange = Date.now() <= interval?.dateTo?.getTime(); this.togglePositionRealtime(currentTimeInRange); this.realtimeDisabled = !currentTimeInRange; if (currentTimeInRange) { this.realtime.start(); } else { this.realtime.stop(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingComponent, deps: [{ token: TrackingService }, { token: i2.EventRealtimeService }, { token: i2.ContextRouteService }, { token: i3.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TrackingComponent, isStandalone: true, selector: "c8y-tracking", providers: [EventRealtimeService], viewQueries: [{ propertyName: "map", first: true, predicate: MapComponent, descendants: true }], ngImport: i0, template: "<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n>\n <c8y-realtime-btn\n [service]=\"realtime\"\n [disabled]=\"realtimeDisabled\"\n (onToggle)=\"togglePositionRealtime($event)\"\n ></c8y-realtime-btn>\n</c8y-action-bar-item>\n<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"60\"\n>\n <c8y-time-interval\n [maxCustomDate]=\"maxDate\"\n [dateRangePickerConfig]=\"dateRangePickerConfig\"\n (interval)=\"service.setInterval($event); toggleRealtime($event)\"\n ></c8y-time-interval>\n</c8y-action-bar-item>\n\n<div class=\"card card--grid content-fullpage d-grid grid__col--8-4--md\">\n <div class=\"bg-white p-relative\">\n <c8y-map\n [config]=\"config\"\n [assets]=\"device\"\n [polyline$]=\"service.polyline$\"\n [polylineOptions]=\"{ color: 'darkblue' }\"\n >\n <div *c8yMapPopup=\"let context\">\n <c8y-tracking-marker-popup [context]=\"context\"></c8y-tracking-marker-popup>\n </div>\n </c8y-map>\n </div>\n\n <div class=\"d-flex d-col bg-inherit content-fullpage bg-gray-white\">\n <div class=\"card-header large-padding separator sticky-top\">\n <span\n class=\"card-title\"\n translate\n >\n Tracking events\n </span>\n </div>\n <div class=\"inner-scroll\">\n <c8y-list-group class=\"c8y-list__group--strip\">\n <ng-template\n c8yFor\n let-event\n [c8yForOf]=\"service.events$\"\n [c8yForPipe]=\"service.pipe\"\n [c8yForRealtime]=\"realtime\"\n [c8yForRealtimeOptions]=\"{ entityOrId: device }\"\n [c8yForLoadMore]=\"'hidden'\"\n [c8yForNotFound]=\"empty\"\n (c8yForLoadMoreComponent)=\"\n loadMoreComponent = $event; loadMoreComponent.useIntersection = false\n \"\n >\n <c8y-li\n class=\"pointer\"\n [ngClass]=\"{ 'text-primary text-bold': activeMarkers['p' + event?.id] }\"\n (click)=\"toggleMarker(event)\"\n [attr.data-cy]=\"'c8y-tracking--tracking-event-item-' + event?.id\"\n >\n <c8y-li-icon [ngClass]=\"{ 'text-primary': activeMarkers['p' + event?.id] }\">\n <i c8yIcon=\"c8y-location\"></i>\n </c8y-li-icon>\n <c8y-li-body>\n <div class=\"d-flex\">\n <span>\n {{ event.time | date: 'mediumDate' }}\n </span>\n <span class=\"m-l-auto\">\n {{ event.time | date: 'mediumTime' }}\n </span>\n </div>\n </c8y-li-body>\n </c8y-li>\n </ng-template>\n </c8y-list-group>\n </div>\n\n <!-- empty state -->\n <ng-template #empty>\n <c8y-ui-empty-state\n icon=\"c8y-location\"\n [title]=\"'No tracking events found.' | translate\"\n [subtitle]=\"'Select another time range.' | translate\"\n *ngIf=\"!service.hasEvents\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </ng-template>\n\n <div *ngIf=\"loadMoreComponent?.hasMore\">\n <button\n class=\"btn btn-link fit-w sticky-bottom separator-top\"\n [title]=\"'Load more' | translate\"\n type=\"button\"\n [disabled]=\"loadMoreComponent?.isLoading\"\n (click)=\"loadMoreComponent.loadMore()\"\n data-cy=\"c8y-tracking--load-more\"\n >\n {{ 'Load more' | translate }}\n </button>\n </div>\n\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-default\"\n [title]=\"'Deselect all markers' | translate\"\n type=\"button\"\n [disabled]=\"(activeMarkers | json) === '{}'\"\n (click)=\"map.clearMarkers('event'); activeMarkers = {}\"\n >\n {{ 'Deselect all markers' | translate }}\n </button>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: MapModule }, { kind: "component", type: i4.MapComponent, selector: "c8y-map", inputs: ["config", "assets", "polyline$", "polylineOptions"], outputs: ["onRealtimeUpdate", "onMove", "onMoveEnd", "onZoomStart", "onZoomEnd", "onMap", "onInit"] }, { kind: "directive", type: i4.MapPopupDirective, selector: "[c8yMapPopup]" }, { kind: "ngmodule", type: ActionBarModule }, { kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { 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: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i5.JsonPipe, name: "json" }, { kind: "pipe", type: i5.DatePipe, name: "date" }, { kind: "directive", type: i2.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { 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.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: i2.RealtimeButtonComponent, selector: "c8y-realtime-btn", inputs: ["service", "label", "title", "disabled"], outputs: ["onToggle"] }, { kind: "component", type: i2.TimeIntervalComponent, selector: "c8y-time-interval", inputs: ["minCustomDate", "maxCustomDate", "dateRangePickerConfig", "selectedInterval"], outputs: ["interval"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: TrackingMarkerPopupComponent, selector: "c8y-tracking-marker-popup", inputs: ["context", "showTrackingLink"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingComponent, decorators: [{ type: Component, args: [{ standalone: true, imports: [ MapModule, ActionBarModule, CoreModule, TimeIntervalComponent, FormsModule, TrackingMarkerPopupComponent ], providers: [EventRealtimeService], selector: 'c8y-tracking', template: "<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n>\n <c8y-realtime-btn\n [service]=\"realtime\"\n [disabled]=\"realtimeDisabled\"\n (onToggle)=\"togglePositionRealtime($event)\"\n ></c8y-realtime-btn>\n</c8y-action-bar-item>\n<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"60\"\n>\n <c8y-time-interval\n [maxCustomDate]=\"maxDate\"\n [dateRangePickerConfig]=\"dateRangePickerConfig\"\n (interval)=\"service.setInterval($event); toggleRealtime($event)\"\n ></c8y-time-interval>\n</c8y-action-bar-item>\n\n<div class=\"card card--grid content-fullpage d-grid grid__col--8-4--md\">\n <div class=\"bg-white p-relative\">\n <c8y-map\n [config]=\"config\"\n [assets]=\"device\"\n [polyline$]=\"service.polyline$\"\n [polylineOptions]=\"{ color: 'darkblue' }\"\n >\n <div *c8yMapPopup=\"let context\">\n <c8y-tracking-marker-popup [context]=\"context\"></c8y-tracking-marker-popup>\n </div>\n </c8y-map>\n </div>\n\n <div class=\"d-flex d-col bg-inherit content-fullpage bg-gray-white\">\n <div class=\"card-header large-padding separator sticky-top\">\n <span\n class=\"card-title\"\n translate\n >\n Tracking events\n </span>\n </div>\n <div class=\"inner-scroll\">\n <c8y-list-group class=\"c8y-list__group--strip\">\n <ng-template\n c8yFor\n let-event\n [c8yForOf]=\"service.events$\"\n [c8yForPipe]=\"service.pipe\"\n [c8yForRealtime]=\"realtime\"\n [c8yForRealtimeOptions]=\"{ entityOrId: device }\"\n [c8yForLoadMore]=\"'hidden'\"\n [c8yForNotFound]=\"empty\"\n (c8yForLoadMoreComponent)=\"\n loadMoreComponent = $event; loadMoreComponent.useIntersection = false\n \"\n >\n <c8y-li\n class=\"pointer\"\n [ngClass]=\"{ 'text-primary text-bold': activeMarkers['p' + event?.id] }\"\n (click)=\"toggleMarker(event)\"\n [attr.data-cy]=\"'c8y-tracking--tracking-event-item-' + event?.id\"\n >\n <c8y-li-icon [ngClass]=\"{ 'text-primary': activeMarkers['p' + event?.id] }\">\n <i c8yIcon=\"c8y-location\"></i>\n </c8y-li-icon>\n <c8y-li-body>\n <div class=\"d-flex\">\n <span>\n {{ event.time | date: 'mediumDate' }}\n </span>\n <span class=\"m-l-auto\">\n {{ event.time | date: 'mediumTime' }}\n </span>\n </div>\n </c8y-li-body>\n </c8y-li>\n </ng-template>\n </c8y-list-group>\n </div>\n\n <!-- empty state -->\n <ng-template #empty>\n <c8y-ui-empty-state\n icon=\"c8y-location\"\n [title]=\"'No tracking events found.' | translate\"\n [subtitle]=\"'Select another time range.' | translate\"\n *ngIf=\"!service.hasEvents\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </ng-template>\n\n <div *ngIf=\"loadMoreComponent?.hasMore\">\n <button\n class=\"btn btn-link fit-w sticky-bottom separator-top\"\n [title]=\"'Load more' | translate\"\n type=\"button\"\n [disabled]=\"loadMoreComponent?.isLoading\"\n (click)=\"loadMoreComponent.loadMore()\"\n data-cy=\"c8y-tracking--load-more\"\n >\n {{ 'Load more' | translate }}\n </button>\n </div>\n\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-default\"\n [title]=\"'Deselect all markers' | translate\"\n type=\"button\"\n [disabled]=\"(activeMarkers | json) === '{}'\"\n (click)=\"map.clearMarkers('event'); activeMarkers = {}\"\n >\n {{ 'Deselect all markers' | translate }}\n </button>\n </div>\n </div>\n</div>\n" }] }], ctorParameters: () => [{ type: TrackingService }, { type: i2.EventRealtimeService }, { type: i2.ContextRouteService }, { type: i3.ActivatedRoute }], propDecorators: { map: [{ type: ViewChild, args: [MapComponent] }] } }); const trackingFeatureProvider = makeEnvironmentProviders([ TrackingTabFactory, hookRoute({ path: 'tracking', component: TrackingComponent, context: ViewContext.Device, label: gettext('Tracking'), icon: 'crosshairs', canActivate: [TrackingTabFactory] }) ]); /** * Generated bundle index. Do not edit. */ export { TrackingComponent, TrackingMarkerPopupComponent, TrackingService, TrackingTabFactory, trackingFeatureProvider }; //# sourceMappingURL=c8y-ngx-components-tracking.mjs.map