UI: Refactoring setupCustomActions in map widget
This commit is contained in:
		
							parent
							
								
									26a6bbbdee
								
							
						
					
					
						commit
						c40d8e8797
					
				@ -90,6 +90,13 @@ export interface IWidgetUtils {
 | 
			
		||||
  getEntityDetailsPageURL: (id: string, entityType: EntityType) => string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PlaceMapItemActionData {
 | 
			
		||||
  action: WidgetAction;
 | 
			
		||||
  additionalParams?: any;
 | 
			
		||||
  afterPlaceItemCallback: ($event: Event, descriptor: WidgetAction, entityId?: EntityId, entityName?: string,
 | 
			
		||||
                           additionalParams?: any, entityLabel?: string) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface WidgetActionsApi {
 | 
			
		||||
  actionDescriptorsBySourceId: {[sourceId: string]: Array<WidgetActionDescriptor>};
 | 
			
		||||
  getActionDescriptors: (actionSourceId: string) => Array<WidgetActionDescriptor>;
 | 
			
		||||
@ -106,6 +113,7 @@ export interface WidgetActionsApi {
 | 
			
		||||
                                hideDashboardToolbar?: boolean, preferredPlacement?: PopoverPlacement,
 | 
			
		||||
                                hideOnClickOutside?: boolean, popoverWidth?: string,
 | 
			
		||||
                                popoverHeight?: string, popoverStyle?: { [klass: string]: any }) => void;
 | 
			
		||||
  placeMapItem: (action: PlaceMapItemActionData) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AliasInfo {
 | 
			
		||||
 | 
			
		||||
@ -64,7 +64,7 @@ export class MapWidgetComponent implements OnInit, OnDestroy {
 | 
			
		||||
  overlayStyle: ComponentStyle = {};
 | 
			
		||||
  padding: string;
 | 
			
		||||
 | 
			
		||||
  map: TbMap<MapSetting>;
 | 
			
		||||
  private map: TbMap<MapSetting>;
 | 
			
		||||
 | 
			
		||||
  constructor(public widgetComponent: WidgetComponent,
 | 
			
		||||
              private imagePipe: ImagePipe,
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,6 @@
 | 
			
		||||
import {
 | 
			
		||||
  additionalMapDataSourcesToDatasources,
 | 
			
		||||
  BaseMapSettings,
 | 
			
		||||
  CustomActionData,
 | 
			
		||||
  DataKeyValuePair,
 | 
			
		||||
  MapBooleanFunction,
 | 
			
		||||
  mapDataLayerTypes,
 | 
			
		||||
@ -49,8 +48,8 @@ import {
 | 
			
		||||
  TbLatestMapDataLayer,
 | 
			
		||||
  UnplacedMapDataItem,
 | 
			
		||||
} from '@home/components/widget/lib/maps/data-layer/latest-map-data-layer';
 | 
			
		||||
import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
 | 
			
		||||
import { FormattedData, MapItemType, WidgetAction, widgetType } from '@shared/models/widget.models';
 | 
			
		||||
import { IWidgetSubscription, PlaceMapItemActionData, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
 | 
			
		||||
import { FormattedData, MapItemType, WidgetAction, WidgetActionType, widgetType } from '@shared/models/widget.models';
 | 
			
		||||
import { EntityDataPageLink } from '@shared/models/query/query.models';
 | 
			
		||||
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
 | 
			
		||||
import { TbMarkersDataLayer } from '@home/components/widget/lib/maps/data-layer/markers-data-layer';
 | 
			
		||||
@ -64,10 +63,9 @@ import {
 | 
			
		||||
  SelectMapEntityPanelComponent
 | 
			
		||||
} from '@home/components/widget/lib/maps/panels/select-map-entity-panel.component';
 | 
			
		||||
import { TbPopoverComponent } from '@shared/components/popover.component';
 | 
			
		||||
import { createColorMarkerShapeURI, MarkerShape } from '@home/components/widget/lib/maps/models/marker-shape.models';
 | 
			
		||||
import { createPlaceItemIcon } from '@home/components/widget/lib/maps/models/marker-shape.models';
 | 
			
		||||
import { MatIconRegistry } from '@angular/material/icon';
 | 
			
		||||
import { DomSanitizer } from '@angular/platform-browser';
 | 
			
		||||
import tinycolor from 'tinycolor2';
 | 
			
		||||
import { MapTimelinePanelComponent } from '@home/components/widget/lib/maps/panels/map-timeline-panel.component';
 | 
			
		||||
import { ComponentRef } from '@angular/core';
 | 
			
		||||
import { TbTripsDataLayer } from '@home/components/widget/lib/maps/data-layer/trips-data-layer';
 | 
			
		||||
@ -138,6 +136,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
 | 
			
		||||
  protected constructor(protected ctx: WidgetContext,
 | 
			
		||||
                        protected inputSettings: DeepPartial<S>,
 | 
			
		||||
                        protected containerElement: HTMLElement) {
 | 
			
		||||
    this.ctx.actionsApi.placeMapItem = this.placeMapItem.bind(this);
 | 
			
		||||
    this.settings = mergeDeepIgnoreArray({} as S, this.defaultSettings(), this.inputSettings as S);
 | 
			
		||||
 | 
			
		||||
    $(containerElement).empty();
 | 
			
		||||
@ -550,36 +549,40 @@ export abstract class TbMap<S extends BaseMapSettings> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private setupCustomActions() {
 | 
			
		||||
    if (!this.settings.mapActionButtons) {
 | 
			
		||||
    const widgetHeaderActions = this.ctx.actionsApi.getActionDescriptors('headerButton');
 | 
			
		||||
    const mapActionButtons = this.settings.mapActionButtons;
 | 
			
		||||
 | 
			
		||||
    const hasMarkerAction =
 | 
			
		||||
      mapActionButtons?.some(actionButton => actionButton.action.mapItemType === MapItemType.marker) ||
 | 
			
		||||
      widgetHeaderActions.some(action => action.type === WidgetActionType.placeMapItem && action.mapItemType === MapItemType.marker);
 | 
			
		||||
 | 
			
		||||
    if (hasMarkerAction) {
 | 
			
		||||
      this.setPlaceMarkerStyle();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!mapActionButtons?.length) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.customActionsToolbar = L.TB.topToolbar({
 | 
			
		||||
      mapElement: $(this.mapElement),
 | 
			
		||||
      iconRegistry: this.ctx.$injector.get(MatIconRegistry)
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const mapActionButtons = this.settings.mapActionButtons;
 | 
			
		||||
    const customTranslate = this.ctx.$injector.get(CustomTranslatePipe);
 | 
			
		||||
 | 
			
		||||
    if (mapActionButtons.length) {
 | 
			
		||||
      const customTranslate = this.ctx.$injector.get(CustomTranslatePipe);
 | 
			
		||||
 | 
			
		||||
      if (mapActionButtons.some(actionButton => actionButton.action.mapItemType === MapItemType.marker)) {
 | 
			
		||||
        this.setPlaceMarkerStyle();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      mapActionButtons.forEach(actionButton => {
 | 
			
		||||
        const actionButtonConfig = {
 | 
			
		||||
          icon: actionButton.icon,
 | 
			
		||||
          color: actionButton.color,
 | 
			
		||||
          title: customTranslate.transform(actionButton.label)
 | 
			
		||||
        };
 | 
			
		||||
        const toolbarButton = this.customActionsToolbar.toolbarButton(actionButtonConfig);
 | 
			
		||||
        toolbarButton.onClick((e, button) => this.ctx.actionsApi.handleWidgetAction(e, actionButton.action, null, null, {button}));
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    mapActionButtons.forEach(actionButton => {
 | 
			
		||||
      const actionButtonConfig = {
 | 
			
		||||
        icon: actionButton.icon,
 | 
			
		||||
        color: actionButton.color,
 | 
			
		||||
        title: customTranslate.transform(actionButton.label)
 | 
			
		||||
      };
 | 
			
		||||
      const toolbarButton = this.customActionsToolbar.toolbarButton(actionButtonConfig);
 | 
			
		||||
      toolbarButton.onClick((e, button) => this.ctx.actionsApi.handleWidgetAction(e, actionButton.action, null, null, {button}));
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public placeMapItem(actionData: CustomActionData): void {
 | 
			
		||||
  public placeMapItem(actionData: PlaceMapItemActionData): void {
 | 
			
		||||
    switch (actionData.action.mapItemType) {
 | 
			
		||||
      case MapItemType.marker:
 | 
			
		||||
        this.createMarker(actionData);
 | 
			
		||||
@ -596,20 +599,20 @@ export abstract class TbMap<S extends BaseMapSettings> {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private createMarker(actionData: CustomActionData) {
 | 
			
		||||
  private createMarker(actionData: PlaceMapItemActionData) {
 | 
			
		||||
    this.createItem(actionData, () => this.prepareDrawMode('Marker', {
 | 
			
		||||
      placeMarker: this.ctx.translate.instant('widgets.maps.data-layer.marker.place-marker-hint')
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private createRectangle(actionData: CustomActionData): void {
 | 
			
		||||
  private createRectangle(actionData: PlaceMapItemActionData): void {
 | 
			
		||||
    this.createItem(actionData, () => this.prepareDrawMode('Rectangle', {
 | 
			
		||||
      firstVertex: this.ctx.translate.instant('widgets.maps.data-layer.polygon.rectangle-place-first-point-hint'),
 | 
			
		||||
      finishRect: this.ctx.translate.instant('widgets.maps.data-layer.polygon.finish-rectangle-hint')
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private createPolygon(actionData: CustomActionData): void {
 | 
			
		||||
  private createPolygon(actionData: PlaceMapItemActionData): void {
 | 
			
		||||
    this.createItem(actionData, () => this.prepareDrawMode('Polygon', {
 | 
			
		||||
      firstVertex: this.ctx.translate.instant('widgets.maps.data-layer.polygon.polygon-place-first-point-hint'),
 | 
			
		||||
      continueLine: this.ctx.translate.instant('widgets.maps.data-layer.polygon.continue-polygon-hint'),
 | 
			
		||||
@ -617,24 +620,24 @@ export abstract class TbMap<S extends BaseMapSettings> {
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private createCircle(actionData: CustomActionData): void {
 | 
			
		||||
  private createCircle(actionData: PlaceMapItemActionData): void {
 | 
			
		||||
    this.createItem(actionData, () => this.prepareDrawMode('Circle', {
 | 
			
		||||
      startCircle: this.ctx.translate.instant('widgets.maps.data-layer.circle.place-circle-center-hint'),
 | 
			
		||||
      finishCircle: this.ctx.translate.instant('widgets.maps.data-layer.circle.finish-circle-hint')
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private createItem(actionData: CustomActionData, prepareDrawMode: () => void) {
 | 
			
		||||
  private createItem(actionData: PlaceMapItemActionData, prepareDrawMode: () => void) {
 | 
			
		||||
    if (this.isPlacingItem) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this.updatePlaceItemState(actionData.button, true);
 | 
			
		||||
    this.updatePlaceItemState(actionData.additionalParams?.button, true);
 | 
			
		||||
 | 
			
		||||
    this.map.once('pm:create', (e) => {
 | 
			
		||||
      actionData.afterPlaceItemCallback(e as any, actionData.action, null, null, {
 | 
			
		||||
        coordinates: convertLayerToCoordinates(actionData.action.mapItemType, e.layer),
 | 
			
		||||
        layer: e.layer,
 | 
			
		||||
        button: actionData.button
 | 
			
		||||
        button: actionData.additionalParams?.button
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
@ -916,7 +919,7 @@ export abstract class TbMap<S extends BaseMapSettings> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private setPlaceMarkerStyle() {
 | 
			
		||||
    createColorMarkerShapeURI(this.getCtx().$injector.get(MatIconRegistry), this.getCtx().$injector.get(DomSanitizer), MarkerShape.markerShape1, tinycolor('rgba(255,255,255,0.75)')).subscribe(
 | 
			
		||||
    createPlaceItemIcon(this.getCtx().$injector.get(MatIconRegistry), this.getCtx().$injector.get(DomSanitizer)).subscribe(
 | 
			
		||||
      ((iconUrl) => {
 | 
			
		||||
        const icon = L.icon({
 | 
			
		||||
          iconUrl,
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,6 @@ import { map } from 'rxjs/operators';
 | 
			
		||||
import { ImagePipe } from '@shared/pipe/image.pipe';
 | 
			
		||||
import { MarkerShape } from '@home/components/widget/lib/maps/models/marker-shape.models';
 | 
			
		||||
import { DateFormatSettings, simpleDateFormat } from '@shared/models/widget-settings.models';
 | 
			
		||||
import { EntityId } from '@shared/models/id/entity-id';
 | 
			
		||||
 | 
			
		||||
export enum MapType {
 | 
			
		||||
  geoMap = 'geoMap',
 | 
			
		||||
@ -1035,13 +1034,6 @@ export interface MarkerIconInfo {
 | 
			
		||||
  size: [number, number];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CustomActionData {
 | 
			
		||||
  button?: L.TB.TopToolbarButton;
 | 
			
		||||
  action: WidgetAction;
 | 
			
		||||
  afterPlaceItemCallback: ($event: Event, descriptor: WidgetAction, entityId?: EntityId, entityName?: string,
 | 
			
		||||
                           additionalParams?: any, entityLabel?: string) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type MapStringFunction = (data: FormattedData<TbMapDatasource>,
 | 
			
		||||
                                 dsData: FormattedData<TbMapDatasource>[]) => string;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,10 +17,10 @@
 | 
			
		||||
import tinycolor from 'tinycolor2';
 | 
			
		||||
import { MatIconRegistry } from '@angular/material/icon';
 | 
			
		||||
import { DomSanitizer } from '@angular/platform-browser';
 | 
			
		||||
import { Observable, of, switchMap } from 'rxjs';
 | 
			
		||||
import { Observable, of, shareReplay, switchMap } from 'rxjs';
 | 
			
		||||
import { catchError, map, take } from 'rxjs/operators';
 | 
			
		||||
import { isSvgIcon, splitIconName } from '@shared/models/icon.models';
 | 
			
		||||
import { Element, Text, G } from '@svgdotjs/svg.js';
 | 
			
		||||
import { Element, G, Text } from '@svgdotjs/svg.js';
 | 
			
		||||
 | 
			
		||||
export enum MarkerShape {
 | 
			
		||||
  markerShape1 = 'markerShape1',
 | 
			
		||||
@ -203,3 +203,14 @@ export const createColorMarkerIconElement = (iconRegistry: MatIconRegistry, domS
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let placeItemIconURI$: Observable<string>;
 | 
			
		||||
 | 
			
		||||
export const createPlaceItemIcon= (iconRegistry: MatIconRegistry, domSanitizer: DomSanitizer): Observable<string> => {
 | 
			
		||||
  if (placeItemIconURI$) {
 | 
			
		||||
    return placeItemIconURI$;
 | 
			
		||||
  }
 | 
			
		||||
  placeItemIconURI$ = createColorMarkerShapeURI(iconRegistry, domSanitizer, MarkerShape.markerShape1, tinycolor('rgba(255,255,255,0.75)')).pipe(
 | 
			
		||||
    shareReplay({refCount: true, bufferSize: 1})
 | 
			
		||||
  );
 | 
			
		||||
  return placeItemIconURI$;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -125,7 +125,6 @@ import { IModulesMap } from '@modules/common/modules-map.models';
 | 
			
		||||
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
 | 
			
		||||
import { CompiledTbFunction, compileTbFunction, isNotEmptyTbFunction } from '@shared/models/js-function.models';
 | 
			
		||||
import { HttpClient } from '@angular/common/http';
 | 
			
		||||
import type { MapWidgetComponent } from '@home/components/widget/lib/maps/map-widget.component';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-widget',
 | 
			
		||||
@ -274,7 +273,8 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges,
 | 
			
		||||
      click: this.click.bind(this),
 | 
			
		||||
      getActiveEntityInfo: this.getActiveEntityInfo.bind(this),
 | 
			
		||||
      openDashboardStateInSeparateDialog: this.openDashboardStateInSeparateDialog.bind(this),
 | 
			
		||||
      openDashboardStateInPopover: this.openDashboardStateInPopover.bind(this)
 | 
			
		||||
      openDashboardStateInPopover: this.openDashboardStateInPopover.bind(this),
 | 
			
		||||
      placeMapItem: () => {}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.widgetContext.customHeaderActions = [];
 | 
			
		||||
@ -1151,14 +1151,11 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges,
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case WidgetActionType.placeMapItem:
 | 
			
		||||
        const mapWidget: MapWidgetComponent = this.widgetContext.$scope.mapWidget
 | 
			
		||||
        if (mapWidget) {
 | 
			
		||||
          mapWidget.map.placeMapItem({
 | 
			
		||||
            action: descriptor,
 | 
			
		||||
            afterPlaceItemCallback: this.executeCustomPrettyAction.bind(this),
 | 
			
		||||
            button: additionalParams?.button
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        this.widgetContext.actionsApi.placeMapItem({
 | 
			
		||||
          action: descriptor,
 | 
			
		||||
          afterPlaceItemCallback: this.executeCustomPrettyAction.bind(this),
 | 
			
		||||
          additionalParams: additionalParams
 | 
			
		||||
        });
 | 
			
		||||
        break;
 | 
			
		||||
      case WidgetActionType.customPretty:
 | 
			
		||||
        this.executeCustomPrettyAction($event, descriptor, entityId, entityName, additionalParams, entityLabel);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user