Compare commits
	
		
			13 Commits
		
	
	
		
			03284d26dd
			...
			80fec7ccaa
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					80fec7ccaa | ||
| 
						 | 
					1a1cd7a81c | ||
| a782d8ebe9 | |||
| 
						 | 
					a0816afaea | ||
| 
						 | 
					6746047fe2 | ||
| 
						 | 
					7266c98a10 | ||
| 
						 | 
					e873f5af5b | ||
| 
						 | 
					44f476d5fd | ||
| 
						 | 
					200f3e95eb | ||
| 
						 | 
					1a8bc43c60 | ||
| 
						 | 
					6dccaa8ce5 | ||
| 
						 | 
					f2cb5d4d64 | ||
| 6252cc120b | 
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
		 Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 62 KiB  | 
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -23,6 +23,30 @@
 | 
				
			|||||||
  content: "b";
 | 
					  content: "b";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fm-trijntje:before {
 | 
				
			||||||
 | 
					  content: "c";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fm-satellite:before {
 | 
				
			||||||
 | 
					  content: "d";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fm-sensoterra:before {
 | 
				
			||||||
 | 
					  content: "e";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fm-blight:before {
 | 
				
			||||||
 | 
					  content: "f";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fm-agrodatacube:before {
 | 
				
			||||||
 | 
					  content: "g";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fm-app-menu:before {
 | 
				
			||||||
 | 
					  content: "h";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@font-face {
 | 
					@font-face {
 | 
				
			||||||
  font-family: "FarmMaps";
 | 
					  font-family: "FarmMaps";
 | 
				
			||||||
  src: url("./FMIconFont.woff") format("woff"), /* Modern Browsers */
 | 
					  src: url("./FMIconFont.woff") format("woff"), /* Modern Browsers */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ export const STARTSEARCHSUCCESS = '[Map] StartSearchSuccess';
 | 
				
			|||||||
export const SELECTFEATURE = '[Map] SelectFeature';
 | 
					export const SELECTFEATURE = '[Map] SelectFeature';
 | 
				
			||||||
export const SELECTITEM = '[Map] SelectItem';
 | 
					export const SELECTITEM = '[Map] SelectItem';
 | 
				
			||||||
export const SELECTITEMSUCCESS = '[Map] SelectItemSuccess';
 | 
					export const SELECTITEMSUCCESS = '[Map] SelectItemSuccess';
 | 
				
			||||||
 | 
					export const SETSELECTEDITEMLAYER = '[Map] SetSelectedItemLayer';
 | 
				
			||||||
export const SELECTTEMPORALITEMSSUCCESS = '[Map] SelectTemporalItemsSuccess';
 | 
					export const SELECTTEMPORALITEMSSUCCESS = '[Map] SelectTemporalItemsSuccess';
 | 
				
			||||||
export const NEXTTEMPORAL = '[Map] NextTemporal';
 | 
					export const NEXTTEMPORAL = '[Map] NextTemporal';
 | 
				
			||||||
export const PREVIOUSTEMPORAL = '[Map] PreviousTemporal';
 | 
					export const PREVIOUSTEMPORAL = '[Map] PreviousTemporal';
 | 
				
			||||||
@@ -32,6 +33,7 @@ export const SETVISIBILITY = '[Map] SetVisibility';
 | 
				
			|||||||
export const SETOPACITY = '[Map] SetOpacity';
 | 
					export const SETOPACITY = '[Map] SetOpacity';
 | 
				
			||||||
export const SETLAYERINDEX = '[Map] SetLayerIndex';
 | 
					export const SETLAYERINDEX = '[Map] SetLayerIndex';
 | 
				
			||||||
export const REMOVELAYER = '[Map] RemoveLayer';
 | 
					export const REMOVELAYER = '[Map] RemoveLayer';
 | 
				
			||||||
 | 
					export const CLEARLAYERS = '[Map] ClearLayers';
 | 
				
			||||||
export const LOADBASELAYERS = '[Map] LoadLayers';
 | 
					export const LOADBASELAYERS = '[Map] LoadLayers';
 | 
				
			||||||
export const LOADBASELAYERSSUCCESS = '[Map] LoadLayersSuccess';
 | 
					export const LOADBASELAYERSSUCCESS = '[Map] LoadLayersSuccess';
 | 
				
			||||||
export const SELECTBASELAYER = '[Map] SelectBaseLayers';
 | 
					export const SELECTBASELAYER = '[Map] SelectBaseLayers';
 | 
				
			||||||
@@ -42,6 +44,7 @@ export const SETSTYLE = '[Map] SetStyle';
 | 
				
			|||||||
export const SHOWLAYERSWITCHER = '[Map] ShowLayerSwitcher';
 | 
					export const SHOWLAYERSWITCHER = '[Map] ShowLayerSwitcher';
 | 
				
			||||||
export const CLEAR = '[Map] Clear';
 | 
					export const CLEAR = '[Map] Clear';
 | 
				
			||||||
export const SETREPLACEURL = '[Map] SetReplaceUrl';
 | 
					export const SETREPLACEURL = '[Map] SetReplaceUrl';
 | 
				
			||||||
 | 
					export const SETFEATURES = '[Map] SetFeatures'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class Clear implements Action {
 | 
					export class Clear implements Action {
 | 
				
			||||||
  readonly type = CLEAR;
 | 
					  readonly type = CLEAR;
 | 
				
			||||||
@@ -180,6 +183,12 @@ export class AddLayer implements Action {
 | 
				
			|||||||
  constructor(public item:IItem,public layerIndex=-1) { }
 | 
					  constructor(public item:IItem,public layerIndex=-1) { }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class SetSelectedItemLayer implements Action {
 | 
				
			||||||
 | 
					  readonly type = SETSELECTEDITEMLAYER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(public item:IItem,public layerIndex=-1) { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class SetVisibility implements Action {
 | 
					export class SetVisibility implements Action {
 | 
				
			||||||
  readonly type = SETVISIBILITY;
 | 
					  readonly type = SETVISIBILITY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -204,6 +213,12 @@ export class RemoveLayer implements Action {
 | 
				
			|||||||
  constructor(public itemLayer: IItemLayer) { }
 | 
					  constructor(public itemLayer: IItemLayer) { }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class ClearLayers implements Action {
 | 
				
			||||||
 | 
					  readonly type = CLEARLAYERS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor() { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class LoadBaseLayers implements Action {
 | 
					export class LoadBaseLayers implements Action {
 | 
				
			||||||
  readonly type = LOADBASELAYERS;
 | 
					  readonly type = LOADBASELAYERS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -256,6 +271,12 @@ export class SetReplaceUrl implements Action {
 | 
				
			|||||||
  constructor(public replaceUrl:boolean) {}
 | 
					  constructor(public replaceUrl:boolean) {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class SetFeatures implements Action {
 | 
				
			||||||
 | 
					  readonly type = SETFEATURES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(public features: Array<Feature>) { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Actions = SetMapState
 | 
					export type Actions = SetMapState
 | 
				
			||||||
  | Init
 | 
					  | Init
 | 
				
			||||||
  | Clear
 | 
					  | Clear
 | 
				
			||||||
@@ -278,6 +299,7 @@ export type Actions = SetMapState
 | 
				
			|||||||
  | SetTimeSpan
 | 
					  | SetTimeSpan
 | 
				
			||||||
  | AddLayer
 | 
					  | AddLayer
 | 
				
			||||||
  | RemoveLayer
 | 
					  | RemoveLayer
 | 
				
			||||||
 | 
					  | ClearLayers
 | 
				
			||||||
  | SetVisibility
 | 
					  | SetVisibility
 | 
				
			||||||
  | SetOpacity
 | 
					  | SetOpacity
 | 
				
			||||||
  | SetLayerIndex
 | 
					  | SetLayerIndex
 | 
				
			||||||
@@ -291,5 +313,7 @@ export type Actions = SetMapState
 | 
				
			|||||||
  | DoQuery
 | 
					  | DoQuery
 | 
				
			||||||
  | SetStyle
 | 
					  | SetStyle
 | 
				
			||||||
  | ShowLayerSwitcher
 | 
					  | ShowLayerSwitcher
 | 
				
			||||||
  | SetReplaceUrl;
 | 
					  | SetReplaceUrl
 | 
				
			||||||
 | 
					  | SetFeatures
 | 
				
			||||||
 | 
					  | SetSelectedItemLayer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,10 @@ const routes = [
 | 
				
			|||||||
        path: '',
 | 
					        path: '',
 | 
				
			||||||
        component: MapComponent   
 | 
					        component: MapComponent   
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: ':xCenter/:yCenter/:zoom/:rotation/:baseLayer',
 | 
				
			||||||
 | 
					        component: MapComponent
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
       path: ':xCenter/:yCenter/:zoom/:rotation/:baseLayer/:queryState',
 | 
					       path: ':xCenter/:yCenter/:zoom/:rotation/:baseLayer/:queryState',
 | 
				
			||||||
       component: MapComponent
 | 
					       component: MapComponent
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,7 +129,7 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange
 | 
				
			|||||||
        source: new VectorTileSource({
 | 
					        source: new VectorTileSource({
 | 
				
			||||||
          maxZoom: rt.maxzoom,
 | 
					          maxZoom: rt.maxzoom,
 | 
				
			||||||
          minZoom: rt.minzoom,
 | 
					          minZoom: rt.minzoom,
 | 
				
			||||||
          format: new MVT(),
 | 
					          format: new MVT({idProperty:'OBJECTID'}),
 | 
				
			||||||
          url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/{z}/{x}/{y}.pbf?v=${Date.parse(item.updated)}`
 | 
					          url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/{z}/{x}/{y}.pbf?v=${Date.parse(item.updated)}`
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        style: (feature) => {
 | 
					        style: (feature) => {
 | 
				
			||||||
@@ -196,7 +196,7 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(l.minzoom) {
 | 
					    if(l.minzoom) {
 | 
				
			||||||
      layer.setMinZoom(14);
 | 
					      layer.setMinZoom(l.minzoom);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if(l.maxzoom) {
 | 
					    if(l.maxzoom) {
 | 
				
			||||||
      layer.setMaxZoom(l.maxzoom);
 | 
					      layer.setMaxZoom(l.maxzoom);
 | 
				
			||||||
@@ -219,12 +219,9 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return new style.Style(
 | 
					            return new style.Style(
 | 
				
			||||||
              {               
 | 
					              {               
 | 
				
			||||||
                fill: new style.Fill({
 | 
					 | 
				
			||||||
                  color: 'red'
 | 
					 | 
				
			||||||
                }),
 | 
					 | 
				
			||||||
                stroke: new style.Stroke({
 | 
					                stroke: new style.Stroke({
 | 
				
			||||||
                  color: 'red',
 | 
					                  color: 'red',
 | 
				
			||||||
                  width: 1.25
 | 
					                  width: 2
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
@@ -392,14 +389,14 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange
 | 
				
			|||||||
    //if(event.type === 'click' && !this.onFeatureSelected.observers.length) return;
 | 
					    //if(event.type === 'click' && !this.onFeatureSelected.observers.length) return;
 | 
				
			||||||
    //if(event.type === 'pointermode' && !this.onFeatureHover.observers.length) return;
 | 
					    //if(event.type === 'pointermode' && !this.onFeatureHover.observers.length) return;
 | 
				
			||||||
    if(this.itemLayer && this.itemLayer.layer) {
 | 
					    if(this.itemLayer && this.itemLayer.layer) {
 | 
				
			||||||
 | 
					       this.selectedFeatures = {};
 | 
				
			||||||
       this.itemLayer.layer.getFeatures(event.pixel).then((features) => {      
 | 
					       this.itemLayer.layer.getFeatures(event.pixel).then((features) => {      
 | 
				
			||||||
         this.selectedFeatures = {};
 | 
					 | 
				
			||||||
         if(!features.length) return;
 | 
					         if(!features.length) return;
 | 
				
			||||||
        let fid = features[0].getId();
 | 
					        let fid = features[0].getId();
 | 
				
			||||||
        this.selectedFeatures[fid] = features[0];    
 | 
					        this.selectedFeatures[fid] = features[0];    
 | 
				
			||||||
        console.debug(features[0]);
 | 
					        console.debug(features[0]);
 | 
				
			||||||
        if(this.selectionLayer) this.selectionLayer.changed();
 | 
					 | 
				
			||||||
       })
 | 
					       })
 | 
				
			||||||
 | 
					       if(this.selectionLayer) this.selectionLayer.changed();
 | 
				
			||||||
    }    
 | 
					    }    
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,9 +19,10 @@
 | 
				
			|||||||
  period:period$|async,
 | 
					  period:period$|async,
 | 
				
			||||||
  compassHeading:compassHeading$|async,
 | 
					  compassHeading:compassHeading$|async,
 | 
				
			||||||
  styles:styles$|async,
 | 
					  styles:styles$|async,
 | 
				
			||||||
  selectedFeature:selectedFeature$|async
 | 
					  selectedFeature:selectedFeature$|async,
 | 
				
			||||||
 | 
					  fullscreen:fullscreen$|async
 | 
				
			||||||
} as state">
 | 
					} as state">
 | 
				
			||||||
  <aol-map #map (moveEnd)="handleOnMoveEnd($event)" (click)="handleOnMouseDown($event)" [ngClass]="{'panel-visible':state.panelVisible}" class="map">
 | 
					  <aol-map #map (moveEnd)="handleOnMoveEnd($event)" (click)="handleOnMouseDown($event)" [ngClass]="{'panel-visible':state.panelVisible,'fullscreen':state.fullscreen}" class="map">
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@@ -38,7 +39,7 @@
 | 
				
			|||||||
      <fm-map-item-source-vector [styles]="state.styles" [features]="state.features" (onFeatureSelected)="handleFeatureClick($event)" (onFeatureHover)="handleFeatureHover($event)" [selectedFeature]="state.selectedFeature" [selectedItem]="state.selectedItem"></fm-map-item-source-vector>
 | 
					      <fm-map-item-source-vector [styles]="state.styles" [features]="state.features" (onFeatureSelected)="handleFeatureClick($event)" (onFeatureHover)="handleFeatureHover($event)" [selectedFeature]="state.selectedFeature" [selectedItem]="state.selectedItem"></fm-map-item-source-vector>
 | 
				
			||||||
    </aol-layer-vector>
 | 
					    </aol-layer-vector>
 | 
				
			||||||
    <!-- <fm-map-gps-location [position]="state.position" [headingTolerance]="20" [showHeading]="true" [heading]="state.compassHeading"></fm-map-gps-location> -->
 | 
					    <!-- <fm-map-gps-location [position]="state.position" [headingTolerance]="20" [showHeading]="true" [heading]="state.compassHeading"></fm-map-gps-location> -->
 | 
				
			||||||
    <div class="control-container">
 | 
					    <div class="control-container" >
 | 
				
			||||||
      <router-outlet name="map-controls"></router-outlet>
 | 
					      <router-outlet name="map-controls"></router-outlet>
 | 
				
			||||||
      <fm-map-layer-switcher></fm-map-layer-switcher>
 | 
					      <fm-map-layer-switcher></fm-map-layer-switcher>
 | 
				
			||||||
      <fm-map-pan-to-location [position]="state.position" [mapState]="state.mapState" [animate]="true"></fm-map-pan-to-location>
 | 
					      <fm-map-pan-to-location [position]="state.position" [mapState]="state.mapState" [animate]="true"></fm-map-pan-to-location>
 | 
				
			||||||
@@ -46,9 +47,11 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <fm-map-file-drop-target [parentCode]="state.parentCode" (onFileDropped)="handleFileDropped($event)"></fm-map-file-drop-target>
 | 
					    <fm-map-file-drop-target [parentCode]="state.parentCode" (onFileDropped)="handleFileDropped($event)"></fm-map-file-drop-target>
 | 
				
			||||||
  </aol-map>
 | 
					  </aol-map>
 | 
				
			||||||
  <fm-map-map-search #mapSearch [openedModalName]="state.openedModalName" (onOpenModal)="handleOpenModal($event)" (onCloseModal)="handleCloseModal()" [ngClass]="{'menuVisible':state.menuVisible}" (onToggleMenu)="handleToggleMenu($event)" (onSearchCollapse)="handleSearchCollapse($event)" (onSearchExpand)="handleSearchExpand($event)" [collapsed]="state.searchCollapsed" [searchMinified]="state.searchMinified" (onSearch)="handleSearch($event)" (onClear)="handleClearSearch($event)" [filterOptions]="state.queryState" [clearEnabled]="state.clearEnabled" [period]="state.period"></fm-map-map-search>
 | 
					  <div *ngIf="noContent">
 | 
				
			||||||
  <fm-side-panel [resizeable]="true" [visible]="state.panelVisible" [collapsed]="state.panelCollapsed" [collapsable]="false">
 | 
					    <fm-map-map-search #mapSearch [openedModalName]="state.openedModalName" (onOpenModal)="handleOpenModal($event)" (onCloseModal)="handleCloseModal()" [ngClass]="{'menuVisible':state.menuVisible}" (onToggleMenu)="handleToggleMenu($event)" (onSearchCollapse)="handleSearchCollapse($event)" (onSearchExpand)="handleSearchExpand($event)" [collapsed]="state.searchCollapsed" [searchMinified]="state.searchMinified" (onSearch)="handleSearch($event)" (onClear)="handleClearSearch($event)" [filterOptions]="state.queryState" [clearEnabled]="state.clearEnabled" [period]="state.period"></fm-map-map-search>
 | 
				
			||||||
    <div class="panel-wrapper">
 | 
					  </div>
 | 
				
			||||||
 | 
					  <fm-side-panel [resizeable]="true" [visible]="state.panelVisible && noContent" [collapsed]="state.panelCollapsed" [collapsable]="false">
 | 
				
			||||||
 | 
					    <div class="panel-wrapper" *ngIf="noContent">
 | 
				
			||||||
      <div class="panel-top bg-secondary" *ngIf="!(state.searchMinified)">
 | 
					      <div class="panel-top bg-secondary" *ngIf="!(state.searchMinified)">
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="panel-bottom">
 | 
					      <div class="panel-bottom">
 | 
				
			||||||
@@ -67,6 +70,9 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>  
 | 
					    </div>  
 | 
				
			||||||
  </fm-side-panel>
 | 
					  </fm-side-panel>
 | 
				
			||||||
 | 
					  <fm-side-panel [resizeable]="true" [visible]="!noContent">
 | 
				
			||||||
 | 
					    <router-outlet></router-outlet>
 | 
				
			||||||
 | 
					  </fm-side-panel>
 | 
				
			||||||
</ng-container>
 | 
					</ng-container>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,6 +49,10 @@ aol-map { position:absolute;width:100%;height:calc(100vh + 4rem);}
 | 
				
			|||||||
.control-container {
 | 
					.control-container {
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  right: 1em;
 | 
					  right: 1em;
 | 
				
			||||||
 | 
					  bottom: 8.1em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fullscreen .control-container {
 | 
				
			||||||
  bottom: 5em;
 | 
					  bottom: 5em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { Component, OnInit, OnDestroy, HostListener, ViewChild, AfterViewInit,NgZone } from '@angular/core';
 | 
					import { Component, OnInit, OnDestroy, HostListener, ViewChild, AfterViewInit,NgZone,ElementRef } from '@angular/core';
 | 
				
			||||||
import { Location } from '@angular/common';
 | 
					import { Location } from '@angular/common';
 | 
				
			||||||
import { Observable, Subject, Subscription, from,of ,EMPTY } from 'rxjs';
 | 
					import { Observable, Subject, Subscription, from,of ,EMPTY } from 'rxjs';
 | 
				
			||||||
import { withLatestFrom, switchMap,skip  } from 'rxjs/operators';
 | 
					import { withLatestFrom, switchMap,skip  } from 'rxjs/operators';
 | 
				
			||||||
@@ -79,10 +79,13 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
				
			|||||||
  public overlayLayersCollapsed: boolean = true;
 | 
					  public overlayLayersCollapsed: boolean = true;
 | 
				
			||||||
  public extent$: Observable<Extent> = this.store.select(mapReducers.selectGetExtent);
 | 
					  public extent$: Observable<Extent> = this.store.select(mapReducers.selectGetExtent);
 | 
				
			||||||
  public styles$:Observable<IStyles> = this.store.select(mapReducers.selectGetStyles);
 | 
					  public styles$:Observable<IStyles> = this.store.select(mapReducers.selectGetStyles);
 | 
				
			||||||
 | 
					  public fullscreen$: Observable<boolean> = this.store.select(commonReducers.selectGetFullScreen);
 | 
				
			||||||
  private lastUrl = "";
 | 
					  private lastUrl = "";
 | 
				
			||||||
  private initialized: boolean = false;
 | 
					  private initialized: boolean = false;
 | 
				
			||||||
 | 
					  public noContent: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @ViewChild('map') map;
 | 
					  @ViewChild('map') map;
 | 
				
			||||||
 | 
					  @ViewChild('contentDiv') contentDiv: ElementRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(private store: Store<mapReducers.State | commonReducers.State>,
 | 
					  constructor(private store: Store<mapReducers.State | commonReducers.State>,
 | 
				
			||||||
    private route: ActivatedRoute,
 | 
					    private route: ActivatedRoute,
 | 
				
			||||||
@@ -237,23 +240,27 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  ngAfterViewInit() {
 | 
					  ngAfterViewInit() {
 | 
				
			||||||
    console.debug("View init");
 | 
					    console.debug("View init");
 | 
				
			||||||
 | 
					    if(this.route.children.length == 0) {
 | 
				
			||||||
 | 
					      this.noContent=true;
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
    this.initCustomStyles();
 | 
					    this.initCustomStyles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // url to state
 | 
					    // url to state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let urlMapState = this.getMapStateFromUrl(this.route.snapshot.paramMap);
 | 
					      let urlMapState = this.getMapStateFromUrl(this.route.snapshot.paramMap);
 | 
				
			||||||
      let urlQueryState = this.getQueryStateFromUrl(this.route.snapshot.paramMap);
 | 
					      let urlQueryState = this.getQueryStateFromUrl(this.route.snapshot.paramMap);
 | 
				
			||||||
      if(urlQueryState && urlMapState) {
 | 
					      if(urlQueryState && urlMapState && this.noContent) {
 | 
				
			||||||
        this.store.dispatch(new mapActions.SetState(urlMapState,urlQueryState));
 | 
					        this.store.dispatch(new mapActions.SetState(urlMapState,urlQueryState));
 | 
				
			||||||
        window.localStorage.setItem("FarmMapsCommonMap_mapState",this.serializeMapState(urlMapState));
 | 
					        window.localStorage.setItem("FarmMapsCommonMap_mapState",this.serializeMapState(urlMapState));
 | 
				
			||||||
      } else if(urlQueryState) {
 | 
					      } else if(urlQueryState && this.noContent) {
 | 
				
			||||||
        this.store.dispatch(new mapActions.SetQueryState(urlQueryState));
 | 
					        this.store.dispatch(new mapActions.SetQueryState(urlQueryState));
 | 
				
			||||||
      }  else {
 | 
					      }  else {
 | 
				
			||||||
        this.store.dispatch(new mapActions.SetReplaceUrl(true));
 | 
					        this.store.dispatch(new mapActions.SetReplaceUrl(true));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.paramSub = this.route.paramMap.pipe(withLatestFrom(this.state$),switchMap(([params,state]) => {
 | 
					      this.paramSub = this.route.paramMap.pipe(withLatestFrom(this.state$),switchMap(([params,state]) => {
 | 
				
			||||||
         if(this.initialized) {
 | 
					         if(this.initialized && this.noContent) {
 | 
				
			||||||
          let urlQueryState = this.getQueryStateFromUrl(params);
 | 
					          let urlQueryState = this.getQueryStateFromUrl(params);
 | 
				
			||||||
          if( this.serializeService.serialize(state.queryState) != this.serializeService.serialize(urlQueryState)) {
 | 
					          if( this.serializeService.serialize(state.queryState) != this.serializeService.serialize(urlQueryState)) {
 | 
				
			||||||
            return of(new mapActions.SetState(state.mapState,urlQueryState));
 | 
					            return of(new mapActions.SetState(state.mapState,urlQueryState));
 | 
				
			||||||
@@ -318,23 +325,24 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  replaceUrl(mapState: IMapState, queryState: IQueryState, replace: boolean = true) {
 | 
					  replaceUrl(mapState: IMapState, queryState: IQueryState, replace: boolean = true) {
 | 
				
			||||||
 | 
					      if(this.noContent) {
 | 
				
			||||||
 | 
					        let newMapState = this.serializeMapState(mapState);
 | 
				
			||||||
 | 
					        let newQueryState = this.serializeService.serialize(queryState);
 | 
				
			||||||
 | 
					        let currentMapState = this.serializeMapState(this.getMapStateFromUrl(this.route.snapshot.paramMap));
 | 
				
			||||||
 | 
					        let urlQueryState = this.getQueryStateFromUrl(this.route.snapshot.paramMap);
 | 
				
			||||||
 | 
					        let currentQueryState = urlQueryState==null?"":this.serializeService.serialize(urlQueryState);
 | 
				
			||||||
 | 
					        if(mapState.baseLayerCode!="" && ((newMapState!= currentMapState)  || (newQueryState!=currentQueryState))) {
 | 
				
			||||||
 | 
					          let parts =["."];
 | 
				
			||||||
 | 
					          parts.push(mapState.xCenter.toFixed(5));
 | 
				
			||||||
 | 
					          parts.push(mapState.yCenter.toFixed(5));
 | 
				
			||||||
 | 
					          parts.push( mapState.zoom.toFixed(0));
 | 
				
			||||||
 | 
					          parts.push( mapState.rotation.toFixed(2));        
 | 
				
			||||||
 | 
					          parts.push(mapState.baseLayerCode);
 | 
				
			||||||
 | 
					          parts.push( this.serializeService.serialize(queryState));
 | 
				
			||||||
          
 | 
					          
 | 
				
			||||||
      let newMapState = this.serializeMapState(mapState);
 | 
					          console.debug("Replace url",parts);
 | 
				
			||||||
      let newQueryState = this.serializeService.serialize(queryState);
 | 
					          this.router.navigate(parts, { replaceUrl: replace,relativeTo:this.route.parent });
 | 
				
			||||||
      let currentMapState = this.serializeMapState(this.getMapStateFromUrl(this.route.snapshot.paramMap));
 | 
					        }  
 | 
				
			||||||
      let urlQueryState = this.getQueryStateFromUrl(this.route.snapshot.paramMap);
 | 
					 | 
				
			||||||
      let currentQueryState = urlQueryState==null?"":this.serializeService.serialize(urlQueryState);
 | 
					 | 
				
			||||||
      if(mapState.baseLayerCode!="" && ((newMapState!= currentMapState)  || (newQueryState!=currentQueryState))) {
 | 
					 | 
				
			||||||
        let parts =["."];
 | 
					 | 
				
			||||||
        parts.push(mapState.xCenter.toFixed(5));
 | 
					 | 
				
			||||||
        parts.push(mapState.yCenter.toFixed(5));
 | 
					 | 
				
			||||||
        parts.push( mapState.zoom.toFixed(0));
 | 
					 | 
				
			||||||
        parts.push( mapState.rotation.toFixed(2));        
 | 
					 | 
				
			||||||
        parts.push(mapState.baseLayerCode);
 | 
					 | 
				
			||||||
        parts.push( this.serializeService.serialize(queryState));
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        console.debug("Replace url",parts);
 | 
					 | 
				
			||||||
        this.router.navigate(parts, { replaceUrl: replace,relativeTo:this.route.parent });
 | 
					 | 
				
			||||||
      }     
 | 
					      }     
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -150,6 +150,19 @@ export class MapEffects {
 | 
				
			|||||||
      return actions;
 | 
					      return actions;
 | 
				
			||||||
    }));
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Effect()
 | 
				
			||||||
 | 
					    zoomToExtent2$: Observable<Action> = this.actions$.pipe(
 | 
				
			||||||
 | 
					      ofType(mapActions.SETFEATURES),
 | 
				
			||||||
 | 
					      map((action: mapActions.SetFeatures) => {
 | 
				
			||||||
 | 
					        let extent = createEmpty();
 | 
				
			||||||
 | 
					           if (extent) {
 | 
				
			||||||
 | 
					            for (let f of action.features) {
 | 
				
			||||||
 | 
					              extend(extent, (f as Feature).getGeometry().getExtent());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }        
 | 
				
			||||||
 | 
					        return new mapActions.SetExtent(extent);
 | 
				
			||||||
 | 
					      }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Effect()
 | 
					  @Effect()
 | 
				
			||||||
  hideMenu$: Observable<Action> = this.actions$.pipe(
 | 
					  hideMenu$: Observable<Action> = this.actions$.pipe(
 | 
				
			||||||
    ofType(mapActions.STARTSEARCHSUCCESS),
 | 
					    ofType(mapActions.STARTSEARCHSUCCESS),
 | 
				
			||||||
@@ -181,6 +194,14 @@ export class MapEffects {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    ));
 | 
					    ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Effect()
 | 
				
			||||||
 | 
					    selectItemSuccessSetLayer$: Observable<Action> = this.actions$.pipe(
 | 
				
			||||||
 | 
					      ofType(mapActions.SELECTITEMSUCCESS),
 | 
				
			||||||
 | 
					      map((action:mapActions.SelectItemSuccess) => 
 | 
				
			||||||
 | 
					         new mapActions.SetSelectedItemLayer(action.item)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Effect()
 | 
					  @Effect()
 | 
				
			||||||
  selectItemSuccess$: Observable<Action> = this.actions$.pipe(
 | 
					  selectItemSuccess$: Observable<Action> = this.actions$.pipe(
 | 
				
			||||||
    ofType(mapActions.SELECTITEMSUCCESS),
 | 
					    ofType(mapActions.SELECTITEMSUCCESS),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,6 +138,12 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
				
			|||||||
        inSearch:false
 | 
					        inSearch:false
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case mapActions.SETFEATURES: {
 | 
				
			||||||
 | 
					      let a = action as mapActions.SetFeatures;
 | 
				
			||||||
 | 
					      return tassign(state, {
 | 
				
			||||||
 | 
					        features: a.features
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    case mapActions.SELECTFEATURE: {
 | 
					    case mapActions.SELECTFEATURE: {
 | 
				
			||||||
      let a = action as mapActions.SelectFeature;
 | 
					      let a = action as mapActions.SelectFeature;
 | 
				
			||||||
      return tassign(state, {
 | 
					      return tassign(state, {
 | 
				
			||||||
@@ -157,18 +163,10 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    case mapActions.SELECTITEMSUCCESS: {
 | 
					    case mapActions.SELECTITEMSUCCESS: {
 | 
				
			||||||
      let a = action as mapActions.SelectItemSuccess;
 | 
					      let a = action as mapActions.SelectItemSuccess;
 | 
				
			||||||
      var itemLayer = null;
 | 
					 | 
				
			||||||
      if (a.item && "vnd.farmmaps.itemtype.layer,vnd.farmmaps.itemtype.shape.processed,vnd.farmmaps.itemtype.geotiff.processed".indexOf(a.item.itemType) >=0 ) {
 | 
					 | 
				
			||||||
        itemLayer = new ItemLayer(a.item);
 | 
					 | 
				
			||||||
        itemLayer.layerIndex =  a.item.data.layers?a.item.data.layers[0].index:-1;
 | 
					 | 
				
			||||||
      } else if (a.item && a.item.itemType == "vnd.farmmaps.itemtype.temporal") {
 | 
					 | 
				
			||||||
        itemLayer = new TemporalItemLayer(a.item);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return tassign(state, {
 | 
					      return tassign(state, {
 | 
				
			||||||
        inSearch:false,
 | 
					        inSearch:false,
 | 
				
			||||||
        selectedItem: a.item,
 | 
					        selectedItem: a.item,
 | 
				
			||||||
        parentItem: a.parentItem,
 | 
					        parentItem: a.parentItem,
 | 
				
			||||||
        selectedItemLayer: itemLayer,
 | 
					 | 
				
			||||||
        panelVisible: a.item != null,
 | 
					        panelVisible: a.item != null,
 | 
				
			||||||
        clearEnabled: a.item != null,
 | 
					        clearEnabled: a.item != null,
 | 
				
			||||||
        searchCollapsed: false,
 | 
					        searchCollapsed: false,
 | 
				
			||||||
@@ -176,6 +174,20 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
				
			|||||||
        queryState: tassign(state.queryState, {itemCode:a.item ? a.item.code:null})
 | 
					        queryState: tassign(state.queryState, {itemCode:a.item ? a.item.code:null})
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case mapActions.SETSELECTEDITEMLAYER: {
 | 
				
			||||||
 | 
					      let a = action as mapActions.SetSelectedItemLayer;
 | 
				
			||||||
 | 
					      var itemLayer = null;
 | 
				
			||||||
 | 
					      if (a.item && "vnd.farmmaps.itemtype.layer,vnd.farmmaps.itemtype.shape.processed,vnd.farmmaps.itemtype.geotiff.processed".indexOf(a.item.itemType) >=0 ) {
 | 
				
			||||||
 | 
					        itemLayer = new ItemLayer(a.item);
 | 
				
			||||||
 | 
					        itemLayer.layerIndex = a.layerIndex>=0?a.layerIndex:a.item.data.layers?a.item.data.layers[0].index:-1;
 | 
				
			||||||
 | 
					      } else if (a.item && a.item.itemType == "vnd.farmmaps.itemtype.temporal") {
 | 
				
			||||||
 | 
					        itemLayer = new TemporalItemLayer(a.item);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return tassign(state, {
 | 
				
			||||||
 | 
					        selectedItemLayer: itemLayer,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    case mapActions.SELECTTEMPORALITEMSSUCCESS:{
 | 
					    case mapActions.SELECTTEMPORALITEMSSUCCESS:{
 | 
				
			||||||
      let a = action as mapActions.SelectTemporalItemsSuccess;
 | 
					      let a = action as mapActions.SelectTemporalItemsSuccess;
 | 
				
			||||||
      let selectedItemLayer=tassign(state.selectedItemLayer) as TemporalItemLayer;
 | 
					      let selectedItemLayer=tassign(state.selectedItemLayer) as TemporalItemLayer;
 | 
				
			||||||
@@ -343,6 +355,9 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
				
			|||||||
      newLayers.splice(i, 1);
 | 
					      newLayers.splice(i, 1);
 | 
				
			||||||
      return tassign(state, { overlayLayers: newLayers, selectedOverlayLayer: selectedOverlayLayer });
 | 
					      return tassign(state, { overlayLayers: newLayers, selectedOverlayLayer: selectedOverlayLayer });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case mapActions.CLEARLAYERS: {
 | 
				
			||||||
 | 
					      return tassign(state, {overlayLayers: [], selectedOverlayLayer: null});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    case mapActions.SETVISIBILITY: {
 | 
					    case mapActions.SETVISIBILITY: {
 | 
				
			||||||
      let a = action as mapActions.SetVisibility;
 | 
					      let a = action as mapActions.SetVisibility;
 | 
				
			||||||
      let newLayers = state.overlayLayers.slice(0);
 | 
					      let newLayers = state.overlayLayers.slice(0);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,8 @@ export const TOGGLEMENU = '[AppCommon] ToggleMenu';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const TOGGLEACCOUNTMENU = '[AppCommon] ToggleAccountMenu';
 | 
					export const TOGGLEACCOUNTMENU = '[AppCommon] ToggleAccountMenu';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const TOGGLEAPPMENU = '[AppCommon] ToggleAppMenu';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const SETMENUVISIBLE = '[AppCommon] SetMenuVisible';
 | 
					export const SETMENUVISIBLE = '[AppCommon] SetMenuVisible';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ONLINE = '[AppCommon] Online';
 | 
					export const ONLINE = '[AppCommon] Online';
 | 
				
			||||||
@@ -283,6 +285,12 @@ export class ToggleAccountMenu implements Action {
 | 
				
			|||||||
  constructor() { }
 | 
					  constructor() { }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class ToggleAppMenu implements Action {
 | 
				
			||||||
 | 
					  readonly type = TOGGLEAPPMENU;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor() { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class SetMenuVisible implements Action {
 | 
					export class SetMenuVisible implements Action {
 | 
				
			||||||
  readonly type = SETMENUVISIBLE;
 | 
					  readonly type = SETMENUVISIBLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -346,6 +354,7 @@ export type Actions = OpenModal
 | 
				
			|||||||
  | CloseAll
 | 
					  | CloseAll
 | 
				
			||||||
  | Online
 | 
					  | Online
 | 
				
			||||||
  | Offline
 | 
					  | Offline
 | 
				
			||||||
  | SetPageMode;
 | 
					  | SetPageMode
 | 
				
			||||||
 | 
					  | ToggleAppMenu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,7 @@ import * as commonEffects from './effects/app-common.effects';
 | 
				
			|||||||
import { SecureOAuthStorage} from './shared/secureOAuthStorage';
 | 
					import { SecureOAuthStorage} from './shared/secureOAuthStorage';
 | 
				
			||||||
import { GradientComponent } from './components/gradient/gradient.component';
 | 
					import { GradientComponent } from './components/gradient/gradient.component';
 | 
				
			||||||
import { GradientSelectComponent } from './components/gradient-select/gradient-select.component';
 | 
					import { GradientSelectComponent } from './components/gradient-select/gradient-select.component';
 | 
				
			||||||
 | 
					import { AppMenuComponent } from './components/app-menu/app-menu.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export {
 | 
					export {
 | 
				
			||||||
  SafePipe,
 | 
					  SafePipe,
 | 
				
			||||||
@@ -126,7 +127,8 @@ export {
 | 
				
			|||||||
    HasClaimDirective,
 | 
					    HasClaimDirective,
 | 
				
			||||||
    UserMenuComponent,
 | 
					    UserMenuComponent,
 | 
				
			||||||
    GradientComponent,
 | 
					    GradientComponent,
 | 
				
			||||||
    GradientSelectComponent
 | 
					    GradientSelectComponent,
 | 
				
			||||||
 | 
					    AppMenuComponent
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  exports: [
 | 
					  exports: [
 | 
				
			||||||
    NgbModule,
 | 
					    NgbModule,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					<div>
 | 
				
			||||||
 | 
					    <div   (click)="toggle($event)" class="rounded-circle menu-button hidden"  [ngClass]="{'hidden':!user}">
 | 
				
			||||||
 | 
					        <span i18n-title title="Apps"><i class="fm fm-app-menu" aria-hidden="true"></i></span>
 | 
				
			||||||
 | 
					        <div class="menu hidden" [ngClass]="{'hidden':!showMenu}">                                     
 | 
				
			||||||
 | 
					            <router-outlet name="app-menu"></router-outlet>            
 | 
				
			||||||
 | 
					       </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					.menu-button {
 | 
				
			||||||
 | 
					    background-color: gray;  
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    width: 2.5em;
 | 
				
			||||||
 | 
					    height: 2.5em;
 | 
				
			||||||
 | 
					    line-height: 2.5em;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    font-size: 1rem;
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					div.menu-button > span {
 | 
				
			||||||
 | 
					    color:white;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.menu {
 | 
				
			||||||
 | 
					    max-height: 100vh;
 | 
				
			||||||
 | 
					    //transition: max-height 0.2s;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    box-shadow: 0 0 20px rgba(0,0,0,.3);
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 3rem;
 | 
				
			||||||
 | 
					    right:0;
 | 
				
			||||||
 | 
					    background-color: #fff;
 | 
				
			||||||
 | 
					    border-radius: 0.25rem;
 | 
				
			||||||
 | 
					    padding: 0.5rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card {      
 | 
				
			||||||
 | 
					    padding:0.5rem;
 | 
				
			||||||
 | 
					    min-width: 10rem;          
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card-body {
 | 
				
			||||||
 | 
					    text-align: left;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.hidden {
 | 
				
			||||||
 | 
					    max-height: 0;   
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.menu.hidden {
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.menu-button.hidden {
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import { ComponentFixture, TestBed } from '@angular/core/testing';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { AppMenuComponent } from './app-menu.component';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('AppMenuComponent', () => {
 | 
				
			||||||
 | 
					  let component: AppMenuComponent;
 | 
				
			||||||
 | 
					  let fixture: ComponentFixture<AppMenuComponent>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(async () => {
 | 
				
			||||||
 | 
					    await TestBed.configureTestingModule({
 | 
				
			||||||
 | 
					      declarations: [ AppMenuComponent ]
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    .compileComponents();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    fixture = TestBed.createComponent(AppMenuComponent);
 | 
				
			||||||
 | 
					    component = fixture.componentInstance;
 | 
				
			||||||
 | 
					    fixture.detectChanges();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create', () => {
 | 
				
			||||||
 | 
					    expect(component).toBeTruthy();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					import { Component, OnInit, Input } from '@angular/core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { IUser } from '../../models/user';
 | 
				
			||||||
 | 
					import {Store} from '@ngrx/store';
 | 
				
			||||||
 | 
					import * as appReducers from '../../reducers/app-common.reducer';
 | 
				
			||||||
 | 
					import * as appActions from '../../actions/app-common.actions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  selector: 'fm-app-menu',
 | 
				
			||||||
 | 
					  templateUrl: './app-menu.component.html',
 | 
				
			||||||
 | 
					  styleUrls: ['./app-menu.component.scss']
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AppMenuComponent implements OnInit {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Input() user:IUser;
 | 
				
			||||||
 | 
					  @Input() showMenu:boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(private store: Store<appReducers.State>) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  toggle(event:MouseEvent) {
 | 
				
			||||||
 | 
					    event.stopPropagation();
 | 
				
			||||||
 | 
					    this.store.dispatch(new appActions.ToggleAppMenu());
 | 
				
			||||||
 | 
					  } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -31,6 +31,7 @@
 | 
				
			|||||||
    <fm-resumable-file-upload></fm-resumable-file-upload>
 | 
					    <fm-resumable-file-upload></fm-resumable-file-upload>
 | 
				
			||||||
  </ng-container>  
 | 
					  </ng-container>  
 | 
				
			||||||
  <div class="user-menu apponly">
 | 
					  <div class="user-menu apponly">
 | 
				
			||||||
 | 
					    <fm-app-menu [user]="user|async" [showMenu]="appMenuVisible|async"></fm-app-menu>
 | 
				
			||||||
    <fm-user-menu [user]="user|async" [showMenu]="accountMenuVisible|async"></fm-user-menu>    
 | 
					    <fm-user-menu [user]="user|async" [showMenu]="accountMenuVisible|async"></fm-user-menu>    
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div class="healthstatus-container online apponly" [ngClass]="{'online' :(isOnline|async)}">
 | 
					  <div class="healthstatus-container online apponly" [ngClass]="{'online' :(isOnline|async)}">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,8 +34,8 @@ body { background: #f1f1f1; line-height: 18px; user-select:none;font-family: Lat
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.app {
 | 
					.app {
 | 
				
			||||||
  width:100vw;
 | 
					  width:100%;
 | 
				
			||||||
  height:100vh;
 | 
					  height:100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.app > .navbar {
 | 
					.app > .navbar {
 | 
				
			||||||
@@ -124,3 +124,8 @@ body { background: #f1f1f1; line-height: 18px; user-select:none;font-family: Lat
 | 
				
			|||||||
.online {
 | 
					.online {
 | 
				
			||||||
  max-height:0em;
 | 
					  max-height:0em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fm-app-menu,fm-user-menu {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  margin-left: 1rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  public routeLoading: Observable<boolean> = this.store$.select(appReducers.selectGetRouteLoading);
 | 
					  public routeLoading: Observable<boolean> = this.store$.select(appReducers.selectGetRouteLoading);
 | 
				
			||||||
  public menuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetMenuVisible);
 | 
					  public menuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetMenuVisible);
 | 
				
			||||||
  public accountMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAccountMenuVisible);
 | 
					  public accountMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAccountMenuVisible);
 | 
				
			||||||
 | 
					  public appMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAppMenuVisible);
 | 
				
			||||||
  public user: Observable<IUser> = this.store$.select(appReducers.SelectGetUser);
 | 
					  public user: Observable<IUser> = this.store$.select(appReducers.SelectGetUser);
 | 
				
			||||||
  public isPageMode: Observable<boolean> =  this.store$.select(appReducers.SelectGetIsPageMode);
 | 
					  public isPageMode: Observable<boolean> =  this.store$.select(appReducers.SelectGetIsPageMode);
 | 
				
			||||||
  @Input() showUploadProgress: boolean = true;
 | 
					  @Input() showUploadProgress: boolean = true;
 | 
				
			||||||
@@ -101,6 +102,10 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
    return action;
 | 
					    return action;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async loadItemTypes() {
 | 
				
			||||||
 | 
					     await this.itemTypeService$.load(this.appConfig$)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit() {
 | 
					  ngOnInit() {
 | 
				
			||||||
    this.InstallRouteEventHandler();
 | 
					    this.InstallRouteEventHandler();
 | 
				
			||||||
    this.InstallEventServiceEventHandler();
 | 
					    this.InstallEventServiceEventHandler();
 | 
				
			||||||
@@ -108,7 +113,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
    this.InstallHealthCheck();
 | 
					    this.InstallHealthCheck();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //load item types
 | 
					    //load item types
 | 
				
			||||||
    this.itemTypeService$.load(this.appConfig$)
 | 
					    this.loadItemTypes();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @HostListener('document:keyup', ['$event'])
 | 
					  @HostListener('document:keyup', ['$event'])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,8 @@ export class AuthCallbackComponent {
 | 
				
			|||||||
    oauthService$.loadDiscoveryDocument().then(() => {
 | 
					    oauthService$.loadDiscoveryDocument().then(() => {
 | 
				
			||||||
      oauthService$.tryLoginCodeFlow().then(() => {
 | 
					      oauthService$.tryLoginCodeFlow().then(() => {
 | 
				
			||||||
        router$.navigateByUrl((oauthService$.state && oauthService$.state!="")?decodeURIComponent(oauthService$.state):"");
 | 
					        router$.navigateByUrl((oauthService$.state && oauthService$.state!="")?decodeURIComponent(oauthService$.state):"");
 | 
				
			||||||
 | 
					      }).catch(() => {
 | 
				
			||||||
 | 
					        router$.navigateByUrl("/");
 | 
				
			||||||
      });    
 | 
					      });    
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,6 @@
 | 
				
			|||||||
    text-align: center;
 | 
					    text-align: center;
 | 
				
			||||||
    font-size: 1rem;
 | 
					    font-size: 1rem;
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    display: inline-block;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
div.menu-button > span {
 | 
					div.menu-button > span {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,4 +3,14 @@ export interface IUser {
 | 
				
			|||||||
  name?: string;
 | 
					  name?: string;
 | 
				
			||||||
  email?: string;
 | 
					  email?: string;
 | 
				
			||||||
  claims: any;
 | 
					  claims: any;
 | 
				
			||||||
 | 
					  firstName?: string;
 | 
				
			||||||
 | 
					  lastName?: string;
 | 
				
			||||||
 | 
					  address?: string;
 | 
				
			||||||
 | 
					  postalCode?: string;
 | 
				
			||||||
 | 
					  city?: string;
 | 
				
			||||||
 | 
					  country?: string;
 | 
				
			||||||
 | 
					  phone?: string;
 | 
				
			||||||
 | 
					  mobile?: string;
 | 
				
			||||||
 | 
					  organisation?: string;
 | 
				
			||||||
 | 
					  cocNumber?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -21,6 +21,7 @@ export interface State {
 | 
				
			|||||||
  userPackages: IPackages,
 | 
					  userPackages: IPackages,
 | 
				
			||||||
  userSettingsRoot: IItem,
 | 
					  userSettingsRoot: IItem,
 | 
				
			||||||
  accountMenuVisible: boolean,
 | 
					  accountMenuVisible: boolean,
 | 
				
			||||||
 | 
					  appMenuVisible: boolean,
 | 
				
			||||||
  isOnline: boolean,
 | 
					  isOnline: boolean,
 | 
				
			||||||
  isPageMode:boolean
 | 
					  isPageMode:boolean
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -37,6 +38,7 @@ export const initialState: State = {
 | 
				
			|||||||
  userPackages: {},
 | 
					  userPackages: {},
 | 
				
			||||||
  userSettingsRoot: null,
 | 
					  userSettingsRoot: null,
 | 
				
			||||||
  accountMenuVisible: false,
 | 
					  accountMenuVisible: false,
 | 
				
			||||||
 | 
					  appMenuVisible: false,
 | 
				
			||||||
  isOnline: true,
 | 
					  isOnline: true,
 | 
				
			||||||
  isPageMode: true
 | 
					  isPageMode: true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -95,17 +97,20 @@ export function reducer(state = initialState, action: appCommonActions.Actions )
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case appCommonActions.TOGGLEMENU: {
 | 
					    case appCommonActions.TOGGLEMENU: {
 | 
				
			||||||
      return tassign(state, { menuVisible: !state.menuVisible,accountMenuVisible:!state.menuVisible?false:state.accountMenuVisible });
 | 
					      return tassign(state, { menuVisible: !state.menuVisible,accountMenuVisible:!state.menuVisible?false:state.accountMenuVisible,appMenuVisible:!state.menuVisible?false:state.appMenuVisible });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case appCommonActions.TOGGLEACCOUNTMENU: {
 | 
					    case appCommonActions.TOGGLEACCOUNTMENU: {
 | 
				
			||||||
      return tassign(state, { accountMenuVisible: !state.accountMenuVisible });
 | 
					      return tassign(state, { accountMenuVisible: !state.accountMenuVisible,appMenuVisible:false });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case appCommonActions.TOGGLEAPPMENU: {
 | 
				
			||||||
 | 
					      return tassign(state, { appMenuVisible: !state.appMenuVisible,accountMenuVisible:false });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case appCommonActions.ESCAPE: {
 | 
					    case appCommonActions.ESCAPE: {
 | 
				
			||||||
      return tassign(state, { menuVisible: false,accountMenuVisible:false });
 | 
					      return tassign(state, { menuVisible: false,accountMenuVisible:false,appMenuVisible: false });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case appCommonActions.SETMENUVISIBLE: {
 | 
					    case appCommonActions.SETMENUVISIBLE: {
 | 
				
			||||||
      let a = action as appCommonActions.SetMenuVisible;
 | 
					      let a = action as appCommonActions.SetMenuVisible;
 | 
				
			||||||
      return tassign(state, { menuVisible: a.visible,accountMenuVisible:a.visible?false:state.accountMenuVisible });
 | 
					      return tassign(state, { menuVisible: a.visible,accountMenuVisible:a.visible?false:state.accountMenuVisible,appMenuVisible:a.visible?false:state.appMenuVisible  });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case appCommonActions.INITUSERPACKAGESSUCCESS:{
 | 
					    case appCommonActions.INITUSERPACKAGESSUCCESS:{
 | 
				
			||||||
      let a = action as appCommonActions.InitUserPackagesSuccess;
 | 
					      let a = action as appCommonActions.InitUserPackagesSuccess;
 | 
				
			||||||
@@ -124,7 +129,7 @@ export function reducer(state = initialState, action: appCommonActions.Actions )
 | 
				
			|||||||
      return tassign(state,{user:null,initialized:false});
 | 
					      return tassign(state,{user:null,initialized:false});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case appCommonActions.CLOSEALL: {
 | 
					    case appCommonActions.CLOSEALL: {
 | 
				
			||||||
      return tassign(state,{accountMenuVisible:false,menuVisible:false });
 | 
					      return tassign(state,{accountMenuVisible:false,appMenuVisible:false, menuVisible:false });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case appCommonActions.ONLINE:{
 | 
					    case appCommonActions.ONLINE:{
 | 
				
			||||||
      return tassign(state,{isOnline:true});
 | 
					      return tassign(state,{isOnline:true});
 | 
				
			||||||
@@ -153,6 +158,7 @@ export const getUser = (state: State) => state.user;
 | 
				
			|||||||
export const getUserPackages = (state: State) => state.userPackages;
 | 
					export const getUserPackages = (state: State) => state.userPackages;
 | 
				
			||||||
export const getUserSettingsRoot = (state: State) => state.userSettingsRoot;
 | 
					export const getUserSettingsRoot = (state: State) => state.userSettingsRoot;
 | 
				
			||||||
export const getAccountMenuVisible = (state: State) => state.accountMenuVisible;
 | 
					export const getAccountMenuVisible = (state: State) => state.accountMenuVisible;
 | 
				
			||||||
 | 
					export const getAppMenuVisible = (state: State) => state.appMenuVisible;
 | 
				
			||||||
export const getIsOnline = (state: State) => state.isOnline;
 | 
					export const getIsOnline = (state: State) => state.isOnline;
 | 
				
			||||||
export const getIsPageMode = (state: State) => state.isPageMode;
 | 
					export const getIsPageMode = (state: State) => state.isPageMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -169,6 +175,7 @@ export const SelectGetUser = createSelector(selectAppCommonState,getUser);
 | 
				
			|||||||
export const SelectGetUserPackages = createSelector(selectAppCommonState,getUserPackages);
 | 
					export const SelectGetUserPackages = createSelector(selectAppCommonState,getUserPackages);
 | 
				
			||||||
export const SelectGetUserSettingsRoot = createSelector(selectAppCommonState,getUserSettingsRoot);
 | 
					export const SelectGetUserSettingsRoot = createSelector(selectAppCommonState,getUserSettingsRoot);
 | 
				
			||||||
export const SelectGetAccountMenuVisible = createSelector(selectAppCommonState,getAccountMenuVisible);
 | 
					export const SelectGetAccountMenuVisible = createSelector(selectAppCommonState,getAccountMenuVisible);
 | 
				
			||||||
 | 
					export const SelectGetAppMenuVisible = createSelector(selectAppCommonState,getAppMenuVisible);
 | 
				
			||||||
export const SelectGetIsOnline = createSelector(selectAppCommonState,getIsOnline);
 | 
					export const SelectGetIsOnline = createSelector(selectAppCommonState,getIsOnline);
 | 
				
			||||||
export const SelectGetIsPageMode = createSelector(selectAppCommonState,getIsPageMode);
 | 
					export const SelectGetIsPageMode = createSelector(selectAppCommonState,getIsPageMode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,4 +18,8 @@ export class UserService {
 | 
				
			|||||||
  getCurrentUser(): Observable<IUser> {
 | 
					  getCurrentUser(): Observable<IUser> {
 | 
				
			||||||
    return this.httpClient.get<IUser>(`${this.ApiEndpoint()}/api/v1/currentuser`);
 | 
					    return this.httpClient.get<IUser>(`${this.ApiEndpoint()}/api/v1/currentuser`);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  updateCurrentUser(user: IUser): Observable<IUser> {
 | 
				
			||||||
 | 
					    return this.httpClient.put<IUser>(`${this.ApiEndpoint()}/api/v1/currentuser`, user);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "issuer": "https://accounts.farmmaps.awtest.nl",
 | 
					    "issuer": "https://accounts.test.farmmaps.eu",
 | 
				
			||||||
    "clientId": "farmmapsdev",
 | 
					    "clientId": "farmmapsdev",
 | 
				
			||||||
    "audience": "https://farmmaps.awtest.nl/",
 | 
					    "audience": "https://test.farmmaps.eu/",
 | 
				
			||||||
    "requireHttps": true,
 | 
					    "requireHttps": true,
 | 
				
			||||||
    "apiEndPoint": "https://farmmaps.awtest.nl",
 | 
					    "apiEndPoint": "https://test.farmmaps.eu",
 | 
				
			||||||
    "grantType":"code"
 | 
					    "grantType":"code"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
		Reference in New Issue
	
	Block a user