Compare commits
	
		
			137 Commits
		
	
	
		
			f2c133e9bd
			...
			develop
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					9b86927e2c | ||
| 
						 | 
					e224b80995 | ||
| 
						 | 
					88f3d9ef1a | ||
| 6737029a61 | |||
| 
						 | 
					d4786564bd | ||
| 6fd69d7999 | |||
| 
						 | 
					4ec75b3d5a | ||
| 04e3f1e71f | |||
| 
						 | 
					df77631299 | ||
| a8d0f05c81 | |||
| 
						 | 
					c79637be77 | ||
| 
						 | 
					b5e11da9a8 | ||
| 
						 | 
					9d45c25a95 | ||
| 
						 | 
					2ffce50c47 | ||
| 
						 | 
					f50ff878e0 | ||
| 09c74448a8 | |||
| 205b73b30e | |||
| 
						 | 
					313cc59fe7 | ||
| c3fb42c65f | |||
| 
						 | 
					6b73fb0d55 | ||
| ea641caf38 | |||
| ac15b2018d | |||
| 
						 | 
					fe73f615ad | ||
| 
						 | 
					3e1b3ee78e | ||
| 
						 | 
					58391b7828 | ||
| 
						 | 
					b2b2a1e8be | ||
| 
						 | 
					0d96a1be4f | ||
| d599430cb0 | |||
| 
						 | 
					e17911b339 | ||
| 
						 | 
					9d6cbffb3d | ||
| 
						 | 
					a11eb81e73 | ||
| 
						 | 
					4fc3ad933c | ||
| 
						 | 
					e6d90c9e61 | ||
| 250b3841fe | |||
| 51291cd86f | |||
| 
						 | 
					e9e3b719a4 | ||
| 
						 | 
					1c0ad57b0a | ||
| 
						 | 
					8684ba25c8 | ||
| 78ca3044cf | |||
| 2e55b5a70e | |||
| 
						 | 
					af0a3dca2d | ||
| f039898c26 | |||
| 
						 | 
					ab19b1c2ce | ||
| a2641f8ea5 | |||
| 
						 | 
					d6841c8f83 | ||
| 187b24ab97 | |||
| b80ddf7854 | |||
| 
						 | 
					79bc3d9082 | ||
| 1c92ad4c28 | |||
| 
						 | 
					61e6de0052 | ||
| fb25b92349 | |||
| 
						 | 
					e78f2893ae | ||
| 51170b45e9 | |||
| 
						 | 
					7365bea145 | ||
| dc096065b4 | |||
| 
						 | 
					b9850311ea | ||
| ee9c050db3 | |||
| 
						 | 
					95200d9920 | ||
| 
						 | 
					ee1ce21cca | ||
| 
						 | 
					467f7447bf | ||
| 
						 | 
					1df4496058 | ||
| 
						 | 
					2137f3f07e | ||
| a46e8040b2 | |||
| 
						 | 
					2ca9730735 | ||
| 3d2ca8fb9f | |||
| 6810da8b79 | |||
| 
						 | 
					4866a6f22d | ||
| 84a1004977 | |||
| 39c619a837 | |||
| 
						 | 
					758613aa12 | ||
| 6914a61bc4 | |||
| 9f43287433 | |||
| 
						 | 
					10df983ae3 | ||
| 78249811ab | |||
| df14427d60 | |||
| 
						 | 
					c7c131d437 | ||
| b2fe8f3bd7 | |||
| 
						 | 
					3027c69fa8 | ||
| 5995d205a4 | |||
| 
						 | 
					fd479c92d8 | ||
| e9880d6eb2 | |||
| 
						 | 
					a4438d8a90 | ||
| 89061774de | |||
| 
						 | 
					362e6c8534 | ||
| 64a0e58238 | |||
| 
						 | 
					a3d4dfbd59 | ||
| 4c106ebff3 | |||
| 
						 | 
					5c8fd64521 | ||
| 72ba8eca81 | |||
| 
						 | 
					f89f741265 | ||
| 50af55acb2 | |||
| 
						 | 
					cc879b85e5 | ||
| b4a0a4584d | |||
| 8ab1611f39 | |||
| 
						 | 
					475c522039 | ||
| 068396ac9a | |||
| 
						 | 
					4a30707ec6 | ||
| 852b1db895 | |||
| 
						 | 
					fcbd68eca0 | ||
| 3a42f9114e | |||
| 3f664b472c | |||
| 
						 | 
					57811f3f2e | ||
| 5e1bc6d705 | |||
| d4a230f96d | |||
| 
						 | 
					ed1e1478b2 | ||
| afe013a59a | |||
| db3734f8a3 | |||
| 
						 | 
					86f75c7f78 | ||
| a7abb4072b | |||
| 
						 | 
					61d6446d75 | ||
| 392008ae4b | |||
| 093c26c7f3 | |||
| 
						 | 
					a8e1ba6c02 | ||
| e64fbfd014 | |||
| 8cd7b85de2 | |||
| 
						 | 
					ddc7f97e27 | ||
| 24e3765c28 | |||
| 
						 | 
					86f3ddb34b | ||
| d6c55ef82b | |||
| d977ddfb7b | |||
| 
						 | 
					0e8bd5343d | ||
| ceeaa89ba3 | |||
| 
						 | 
					c3dbf85eb6 | ||
| ad5fe95b55 | |||
| 
						 | 
					6b95fb7f77 | ||
| da7e193219 | |||
| 31f9b48bd7 | |||
| 
						 | 
					1d6b30edff | ||
| 349a76395b | |||
| 
						 | 
					32b3b98f76 | ||
| 010ed6e010 | |||
| a8675f5c49 | |||
| 
						 | 
					f76ef44dee | ||
| 2387a0e39e | |||
| 98980fc857 | |||
| 
						 | 
					6f7d8fe248 | ||
| 03a1ccd597 | 
@@ -52,7 +52,7 @@ ng serve
 | 
			
		||||
```
 | 
			
		||||
*Go*`
 | 
			
		||||
 | 
			
		||||
Point your browser to http://localhost:4200 
 | 
			
		||||
Point your browser to http://localhost:4200
 | 
			
		||||
 | 
			
		||||
*ESLint*
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17438
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										17438
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										38
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								package.json
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "farmmaps-lib-app",
 | 
			
		||||
  "version": "4.10.0",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
  "version": "4.19.0",
 | 
			
		||||
  "scripts":   {
 | 
			
		||||
    "ng": "ng",
 | 
			
		||||
    "start": "ng serve",
 | 
			
		||||
    "build": "ng build",
 | 
			
		||||
@@ -10,16 +10,16 @@
 | 
			
		||||
    "e2e": "ng e2e"
 | 
			
		||||
  },
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
  "dependencies":   {
 | 
			
		||||
    "@angular-eslint/eslint-plugin": "^18.2.0",
 | 
			
		||||
    "@angular/animations": "^18.2.3",
 | 
			
		||||
    "@angular/common": "^18.2.3",
 | 
			
		||||
    "@angular/compiler": "^18.2.3",
 | 
			
		||||
    "@angular/core": "^18.2.3",
 | 
			
		||||
    "@angular/forms": "^18.2.3",
 | 
			
		||||
    "@angular/platform-browser": "^18.2.3",
 | 
			
		||||
    "@angular/platform-browser-dynamic": "^18.2.3",
 | 
			
		||||
    "@angular/router": "^18.2.3",
 | 
			
		||||
    "@angular/animations": "18.2.3",
 | 
			
		||||
    "@angular/common": "18.2.3",
 | 
			
		||||
    "@angular/compiler": "18.2.3",
 | 
			
		||||
    "@angular/core": "18.2.3",
 | 
			
		||||
    "@angular/forms": "18.2.3",
 | 
			
		||||
    "@angular/platform-browser": "18.2.3",
 | 
			
		||||
    "@angular/platform-browser-dynamic": "18.2.3",
 | 
			
		||||
    "@angular/router": "18.2.3",
 | 
			
		||||
    "@farmmaps/common": "file:dist/common",
 | 
			
		||||
    "@farmmaps/common-map": "file:dist/common-map",
 | 
			
		||||
    "@farmmaps/common-map3d": "file:dist/common-map3d",
 | 
			
		||||
@@ -56,17 +56,17 @@
 | 
			
		||||
    "util": "^0.12.4",
 | 
			
		||||
    "zone.js": "~0.14.10"
 | 
			
		||||
  },
 | 
			
		||||
  "optionalDependencies": {
 | 
			
		||||
  "optionalDependencies":   {
 | 
			
		||||
    "@lmdb/lmdb-linux-x64": "^3.1.0",
 | 
			
		||||
    "@rollup/rollup-linux-x64-gnu": "^4.21.2"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
  "devDependencies":   {
 | 
			
		||||
    "@angular-builders/custom-webpack": "^18.0.0",
 | 
			
		||||
    "@angular-devkit/build-angular": "^18.2.3",
 | 
			
		||||
    "@angular/cli": "^18.2.3",
 | 
			
		||||
    "@angular/compiler-cli": "^18.2.3",
 | 
			
		||||
    "@angular/language-service": "^18.2.3",
 | 
			
		||||
    "@angular/localize": "^18.2.3",
 | 
			
		||||
    "@angular-devkit/build-angular": "18.2.3",
 | 
			
		||||
    "@angular/cli": "18.2.3",
 | 
			
		||||
    "@angular/compiler-cli": "18.2.3",
 | 
			
		||||
    "@angular/language-service": "18.2.3",
 | 
			
		||||
    "@angular/localize": "18.2.3",
 | 
			
		||||
    "@types/arcgis-rest-api": "^10.4.5",
 | 
			
		||||
    "@types/jasmine": "~2.8.8",
 | 
			
		||||
    "@types/jasminewd2": "^2.0.9",
 | 
			
		||||
@@ -90,4 +90,4 @@
 | 
			
		||||
    "ts-node": "^8.8.1",
 | 
			
		||||
    "typescript": "~5.4.4"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
    "tslib": "^2.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "peerDependencies": {
 | 
			
		||||
    "@angular/core": "^18.2.3",
 | 
			
		||||
    "@angular/core": "18.2.3",
 | 
			
		||||
    "ngrx-store-localstorage": "^18.0.0",
 | 
			
		||||
    "@ngrx/effects": "^18.0.2",
 | 
			
		||||
    "@ngrx/router-store": "^18.0.2",
 | 
			
		||||
 
 | 
			
		||||
@@ -59,6 +59,8 @@ export const TOGGLESHOWDATALAYERSLIDE = '[Map] ToggleShowDataLayerSlide'
 | 
			
		||||
export const SETVIEWSTATE = '[Map] SetViewState'
 | 
			
		||||
export const CLEARFEATURES = '[Map] ClearFeatures';
 | 
			
		||||
export const SETPANELEXTRAWIDE = '[Map] SetPanelExtraWide';
 | 
			
		||||
export const BACKUPFEATURES = '[Map] BackupFeatures';
 | 
			
		||||
export const RESTOREFEATURES = '[Map] RestoreFeatures';
 | 
			
		||||
 | 
			
		||||
export class Clear implements Action {
 | 
			
		||||
  readonly type = CLEAR;
 | 
			
		||||
@@ -347,6 +349,16 @@ export class SetPanelExtraWide implements Action {
 | 
			
		||||
  constructor(public panelExtraWide:boolean) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class BackupFeatures implements Action {
 | 
			
		||||
  readonly type = BACKUPFEATURES;
 | 
			
		||||
  constructor() {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class RestoreFeatures implements Action {
 | 
			
		||||
  readonly type = RESTOREFEATURES;
 | 
			
		||||
  constructor() {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Actions = SetMapState
 | 
			
		||||
  | Init
 | 
			
		||||
  | Clear
 | 
			
		||||
@@ -395,5 +407,7 @@ export type Actions = SetMapState
 | 
			
		||||
  | ToggleShowDataLayerSlide
 | 
			
		||||
  | SetViewState
 | 
			
		||||
  | ClearFeatures
 | 
			
		||||
  | SetPanelExtraWide;
 | 
			
		||||
  | SetPanelExtraWide
 | 
			
		||||
  | BackupFeatures
 | 
			
		||||
  | RestoreFeatures;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,7 @@ import { RotationResetComponent } from './components/aol/rotation-reset/rotation
 | 
			
		||||
import { ZoomToExtentComponent } from './components/aol/zoom-to-extent/zoom-to-extent.component';
 | 
			
		||||
import { FeatureListContainerComponent } from './components/feature-list-container/feature-list-container.component';
 | 
			
		||||
import { FeatureListCropfieldComponent } from './components/feature-list-cropfield/feature-list-cropfield.component';
 | 
			
		||||
import { FeatureListObservationComponent } from './components/feature-list-observation/feature-list-observation.component';
 | 
			
		||||
import { FeatureListCroppingschemeComponent } from './components/feature-list-croppingscheme/feature-list-croppingscheme.component';
 | 
			
		||||
import { FeatureListFeatureContainerComponent } from './components/feature-list-feature-container/feature-list-feature-container.component';
 | 
			
		||||
import { FeatureListFeatureCropfieldComponent } from './components/feature-list-feature-cropfield/feature-list-feature-cropfield.component';
 | 
			
		||||
@@ -105,7 +106,7 @@ const metaReducers: Array<MetaReducer<any, any>> = [LocalStorageSync];
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  AbstractFeatureListComponent,
 | 
			
		||||
  AbstractFeatureListFeatureComponent, AbstractItemListComponent, AbstractItemListItemComponent, AbstractItemWidgetComponent, AbstractSelectedItemComponent, DeviceOrientationService, FeatureIconService, FeatureListComponent, FeatureListContainerComponent, FeatureListCropfieldComponent, FeatureListCroppingschemeComponent, FeatureListFeatureComponent, FeatureListFeatureContainerComponent, FeatureListFeatureCropfieldComponent, FeatureListFeatureCroppingschemeComponent, FileDropTargetComponent, ForChild,
 | 
			
		||||
  AbstractFeatureListFeatureComponent, AbstractItemListComponent, AbstractItemListItemComponent, AbstractItemWidgetComponent, AbstractSelectedItemComponent, DeviceOrientationService, FeatureIconService, FeatureListComponent, FeatureListContainerComponent, FeatureListCropfieldComponent, FeatureListObservationComponent, FeatureListCroppingschemeComponent, FeatureListFeatureComponent, FeatureListFeatureContainerComponent, FeatureListFeatureCropfieldComponent, FeatureListFeatureCroppingschemeComponent, FileDropTargetComponent, ForChild,
 | 
			
		||||
  ForItemType, ForPackage, ForSourceTask, GeolocationService, GeometryThumbnailComponent, GpsLocation, IClickedFeature, ifZoomToShowDirective, IItemLayer, IMapState, IPeriodState, ISelectedFeatures, ItemLayer, ItemLayersComponent, ItemListComponent, ItemListItemComponent,
 | 
			
		||||
  ItemListItemContainerComponent, ITemporalItemLayer, ItemVectorSourceComponent, ItemWidgetListComponent, LayerListComponent, LayerSwitcher, LayerVectorImageComponent, LegendComponent, mapActions, MapComponent, mapEffects,
 | 
			
		||||
  mapReducers, MapSearchComponent, MetaDataModalComponent, PanToLocation, RotationResetComponent, SelectedItemComponent, SelectedItemContainerComponent, SelectedItemCropfieldComponent,
 | 
			
		||||
@@ -142,6 +143,7 @@ export {
 | 
			
		||||
        FeatureListContainerComponent,
 | 
			
		||||
        FeatureListCroppingschemeComponent,
 | 
			
		||||
        FeatureListCropfieldComponent,
 | 
			
		||||
        FeatureListObservationComponent,
 | 
			
		||||
        FeatureListFeatureContainerComponent,
 | 
			
		||||
        FeatureListFeatureComponent,
 | 
			
		||||
        FeatureListFeatureCroppingschemeComponent,
 | 
			
		||||
@@ -201,6 +203,7 @@ export {
 | 
			
		||||
        FeatureListContainerComponent,
 | 
			
		||||
        FeatureListCroppingschemeComponent,
 | 
			
		||||
        FeatureListCropfieldComponent,
 | 
			
		||||
        FeatureListObservationComponent,
 | 
			
		||||
        FeatureListFeatureContainerComponent,
 | 
			
		||||
        ZoomToExtentComponent,
 | 
			
		||||
        ifZoomToShowDirective,
 | 
			
		||||
@@ -214,9 +217,10 @@ export {
 | 
			
		||||
        TemporalService,
 | 
			
		||||
        { provide: AbstractFeatureListComponent, useClass: FeatureListCroppingschemeComponent, multi: true },
 | 
			
		||||
        { provide: AbstractFeatureListComponent, useClass: FeatureListCropfieldComponent, multi: true },
 | 
			
		||||
        { provide: AbstractFeatureListComponent, useClass: FeatureListObservationComponent, multi: true },        
 | 
			
		||||
        { provide: AbstractFeatureListFeatureComponent, useClass: FeatureListFeatureComponent, multi: true },
 | 
			
		||||
        { provide: AbstractFeatureListFeatureComponent, useClass: FeatureListFeatureCroppingschemeComponent, multi: true },
 | 
			
		||||
        { provide: AbstractFeatureListFeatureComponent, useClass: FeatureListFeatureCropfieldComponent, multi: true },
 | 
			
		||||
        { provide: AbstractFeatureListFeatureComponent, useClass: FeatureListFeatureCropfieldComponent, multi: true },       
 | 
			
		||||
        { provide: AbstractSelectedItemComponent, useClass: SelectedItemComponent, multi: true },
 | 
			
		||||
        { provide: AbstractSelectedItemComponent, useClass: SelectedItemCropfieldComponent, multi: true },
 | 
			
		||||
        { provide: AbstractSelectedItemComponent, useClass: SelectedItemGeotiffComponent, multi: true },
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
<div class="card border-0">
 | 
			
		||||
  <div class="card-body" *ngIf="(schemeItem|async);let schemeItem">
 | 
			
		||||
    <fm-back-button></fm-back-button>
 | 
			
		||||
    <h4 i18n>Farm</h4>
 | 
			
		||||
    <h3>{{schemeItem.name}}</h3>
 | 
			
		||||
    <div *ngIf="features;let features">
 | 
			
		||||
        <div class="cropfields">
 | 
			
		||||
          <div class="row m-0 ps-3 pe-3" *ngFor="let feature of features" [ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)">
 | 
			
		||||
          <fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
fm-map-feature-list-feature-container {
 | 
			
		||||
  width:100%;
 | 
			
		||||
  pointer-events:none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.row {
 | 
			
		||||
  border-bottom: 1px solid var(--bs-gray-500);
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  padding-left:1.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.row.selected {
 | 
			
		||||
  background-color: var(--bs-gray-100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cropfields {
 | 
			
		||||
  border-top: 1px solid var(--bs-gray-500);
 | 
			
		||||
  margin-left: -1.25rem;
 | 
			
		||||
  margin-right: -1.25rem;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,30 @@
 | 
			
		||||
import { Component, Injectable,AfterViewInit, OnInit,SimpleChanges, ChangeDetectorRef} from '@angular/core';
 | 
			
		||||
import { Location } from '@angular/common';
 | 
			
		||||
import { AbstractFeatureListComponent } from '../feature-list/feature-list.component';
 | 
			
		||||
import {ForItemType } from '../for-item/for-itemtype.decorator';
 | 
			
		||||
import {ForChild } from '../for-item/for-child.decorator';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import { commonReducers, ItemTypeService, IItem,ItemService } from '@farmmaps/common';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
@ForChild()
 | 
			
		||||
@ForItemType("vnd.farmmaps.itemtype.observation")
 | 
			
		||||
@Injectable()
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'fm-map-feature-list-observation',
 | 
			
		||||
    templateUrl: './feature-list-observation.component.html',
 | 
			
		||||
    styleUrls: ['./feature-list-observation.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class FeatureListObservationComponent extends AbstractFeatureListComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, location: Location, private itemService: ItemService) {
 | 
			
		||||
    super(store, itemTypeService,location);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public schemeItem: Observable<IItem>
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.schemeItem = this.itemService.getItem(this.queryState.parentCode);
 | 
			
		||||
  } 
 | 
			
		||||
}
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
        <li class="nav-item py-0">
 | 
			
		||||
          <span><i class="fal fa-layer-group" aria-hidden="true"></i> <span i18n>Base maps</span></span>
 | 
			
		||||
          <div  class="mb-4">
 | 
			
		||||
            <fm-map-layer-list [baseLayers]="true" [itemLayers]="baseLayers|async" [selectedLayer]="selectedBaseLayer|async" (onSelectLayer)="handleSelectBaseLayer($event)"></fm-map-layer-list>
 | 
			
		||||
            <fm-map-layer-list [baseLayers]="true" [itemLayers]="baseMaps|async" [selectedLayer]="selectedBaseLayer|async" (onSelectLayer)="handleSelectBaseLayer($event)"></fm-map-layer-list>
 | 
			
		||||
          </div>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li class="nav-item py-0">
 | 
			
		||||
@@ -20,12 +20,17 @@
 | 
			
		||||
          </div>
 | 
			
		||||
        </li>
 | 
			
		||||
        <li class="nav-item py-0" *ngIf="selectedItemLayer$ | async as selectedItemLayer">
 | 
			
		||||
          <span><i class="fal fa-layer-group" aria-hidden="true"></i> <span i18n>Data</span><span class="slideButton"><a href="#" title="Compare" class="btn btn-light btn-sm" (click)="handleToggleShowDatalayerSlide($event)"><i class="fal fa-sliders-h-square"></i></a></span></span>
 | 
			
		||||
          <span><i class="fal fa-layer-group" aria-hidden="true"></i> <span i18n>Overlay slider</span><span class="slideButton"><a href="#" title="Compare" class="btn btn-light btn-sm" (click)="handleToggleShowDatalayerSlide($event)"><i class="fal fa-sliders-h-square"></i></a></span></span>
 | 
			
		||||
          <div class="mb-4">
 | 
			
		||||
            <fm-map-layer-list [dataLayers]="true" [itemLayers]="[selectedItemLayer]" [selectedLayer]="selectedItemLayer" (onToggleVisibility)="handleOnToggleVisibility($event)" (onSetOpacity)="handleOnSetOpacity($event)" (onZoomToExtent)="handleZoomToExtent($event)" (onSelectLayer)="handleSelectOverlayLayer($event)"></fm-map-layer-list>
 | 
			
		||||
          </div>
 | 
			
		||||
        </li>
 | 
			
		||||
 | 
			
		||||
        <li class="nav-item py-0">
 | 
			
		||||
          <span><i class="fal fa-layer-group" aria-hidden="true"></i> <span i18n>Aerial photos</span></span>
 | 
			
		||||
          <div  class="mb-4">
 | 
			
		||||
            <fm-map-layer-list [baseLayers]="true" [itemLayers]="aerialMaps|async" [selectedLayer]="selectedBaseLayer|async" (onSelectLayer)="handleSelectBaseLayer($event)"></fm-map-layer-list>
 | 
			
		||||
          </div>
 | 
			
		||||
        </li>
 | 
			
		||||
      </ul>
 | 
			
		||||
  </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import { Store } from '@ngrx/store';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
import {createEmpty,extend } from 'ol/extent';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { filter, map, Observable } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'fm-map-layer-switcher',
 | 
			
		||||
@@ -17,7 +17,8 @@ export class LayerSwitcher  implements OnInit,OnChanges{
 | 
			
		||||
  public overlayLayers: Observable<Array<IItemLayer>>;
 | 
			
		||||
  public selectedOverlayLayer: Observable<IItemLayer>;
 | 
			
		||||
  public selectedItemLayer$: Observable<IItemLayer>;
 | 
			
		||||
  public baseLayers: Observable<Array<IItemLayer>>;
 | 
			
		||||
  public baseMaps: Observable<Array<IItemLayer>>;
 | 
			
		||||
  public aerialMaps: Observable<Array<IItemLayer>>;
 | 
			
		||||
  public selectedBaseLayer: Observable<IItemLayer>;
 | 
			
		||||
 | 
			
		||||
  constructor( private store: Store<mapReducers.State>) {
 | 
			
		||||
@@ -26,7 +27,8 @@ export class LayerSwitcher  implements OnInit,OnChanges{
 | 
			
		||||
  ngOnInit() { 
 | 
			
		||||
    this.overlayLayers = this.store.select(mapReducers.selectGetOverlayLayers);
 | 
			
		||||
    this.selectedOverlayLayer = this.store.select(mapReducers.selectGetSelectedOverlayLayer);
 | 
			
		||||
    this.baseLayers = this.store.select(mapReducers.selectGetBaseLayers);
 | 
			
		||||
    this.baseMaps = this.store.select(mapReducers.selectGetBaseMaps);
 | 
			
		||||
    this.aerialMaps = this.store.select(mapReducers.selectGetArealMaps);
 | 
			
		||||
    this.selectedBaseLayer = this.store.select(mapReducers.selectGetSelectedBaseLayer);
 | 
			
		||||
    this.selectedItemLayer$ = this.store.select(mapReducers.selectGetSelectedItemLayer)
 | 
			
		||||
    this.showLayerSwitcher = this.store.select(mapReducers.selectGetShowLayerSwitcher);
 | 
			
		||||
@@ -83,3 +85,4 @@ export class LayerSwitcher  implements OnInit,OnChanges{
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,11 +52,20 @@ aol-map { position:absolute;width:100%;height:calc( 100vh );}
 | 
			
		||||
  pointer-events: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen and (max-width: 768px) {
 | 
			
		||||
  .control-container {
 | 
			
		||||
    margin-left: 1em;
 | 
			
		||||
    margin-right: 1em;
 | 
			
		||||
    pointer-events: all;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.control-container {
 | 
			
		||||
  float:right;
 | 
			
		||||
  margin-right: 1em;
 | 
			
		||||
  pointer-events: all;
 | 
			
		||||
@media screen and (min-width: 768px) {
 | 
			
		||||
  .control-container {    
 | 
			
		||||
    float: right;
 | 
			
		||||
    margin-right: 1em;
 | 
			
		||||
    pointer-events: all;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.fullscreen .viewport-container {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,39 +1,39 @@
 | 
			
		||||
import { Component, OnInit, OnDestroy, HostListener, ViewChild, AfterViewInit,NgZone,ElementRef } from '@angular/core';
 | 
			
		||||
import { Component, OnInit, OnDestroy, HostListener, ViewChild, AfterViewInit, NgZone, ElementRef } from '@angular/core';
 | 
			
		||||
import { Location } from '@angular/common';
 | 
			
		||||
import { Observable, Subject, Subscription, from,of ,EMPTY } from 'rxjs';
 | 
			
		||||
import { withLatestFrom, switchMap,skip  } from 'rxjs/operators';
 | 
			
		||||
import { Observable, Subject, Subscription, from, of, EMPTY } from 'rxjs';
 | 
			
		||||
import { withLatestFrom, switchMap, skip } from 'rxjs/operators';
 | 
			
		||||
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { DeviceService } from '@farmmaps/common';
 | 
			
		||||
import {getRenderPixel} from 'ol/render';
 | 
			
		||||
import { getRenderPixel } from 'ol/render';
 | 
			
		||||
 | 
			
		||||
// Map
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
import { IMapState} from '../../models/map.state';
 | 
			
		||||
import { IClickedFeature} from '../../models/clicked.feature';
 | 
			
		||||
import { IMapState } from '../../models/map.state';
 | 
			
		||||
import { IClickedFeature } from '../../models/clicked.feature';
 | 
			
		||||
import { IQuery } from '../../reducers/map.reducer'
 | 
			
		||||
import { ISelectedFeatures } from '../../models/selected.features';
 | 
			
		||||
import { IItemLayer } from '../../models/item.layer';
 | 
			
		||||
import { IListItem, IQueryState } from '@farmmaps/common';
 | 
			
		||||
import { IPeriodState } from '../../models/period.state';
 | 
			
		||||
import {IStyles} from '../../models/style.cache';
 | 
			
		||||
import { IStyles } from '../../models/style.cache';
 | 
			
		||||
import { IDroppedFile } from '../aol/file-drop-target/file-drop-target.component';
 | 
			
		||||
import { StateSerializerService } from '@farmmaps/common';
 | 
			
		||||
import { GeolocationService} from '../../services/geolocation.service';
 | 
			
		||||
import { GeolocationService } from '../../services/geolocation.service';
 | 
			
		||||
import { GeolocatorService } from '@farmmaps/common';
 | 
			
		||||
import {DeviceOrientationService} from '../../services/device-orientation.service';
 | 
			
		||||
import { DeviceOrientationService } from '../../services/device-orientation.service';
 | 
			
		||||
 | 
			
		||||
// AppCommon
 | 
			
		||||
import { ResumableFileUploadService, ItemTypeService } from '@farmmaps/common';
 | 
			
		||||
import { IItemType, IItem } from '@farmmaps/common';
 | 
			
		||||
import {commonReducers} from '@farmmaps/common';
 | 
			
		||||
import {commonActions} from '@farmmaps/common';
 | 
			
		||||
import { commonReducers } from '@farmmaps/common';
 | 
			
		||||
import { commonActions } from '@farmmaps/common';
 | 
			
		||||
 | 
			
		||||
import {Feature} from 'ol';
 | 
			
		||||
import {Geometry,Point,Circle} from 'ol/geom';
 | 
			
		||||
import {Extent,createEmpty,extend } from 'ol/extent';
 | 
			
		||||
import {transform} from 'ol/proj';
 | 
			
		||||
import { Feature } from 'ol';
 | 
			
		||||
import { Geometry, Point, Circle } from 'ol/geom';
 | 
			
		||||
import { Extent, createEmpty, extend } from 'ol/extent';
 | 
			
		||||
import { transform } from 'ol/proj';
 | 
			
		||||
import { tassign } from 'tassign';
 | 
			
		||||
import * as style from 'ol/style';
 | 
			
		||||
 | 
			
		||||
@@ -44,7 +44,7 @@ import * as style from 'ol/style';
 | 
			
		||||
  styleUrls: ['./map.component.scss']
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
export class MapComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
			
		||||
  title = 'Map';
 | 
			
		||||
  public openedModalName$: Observable<string> = this.store.select(commonReducers.selectOpenedModalName);
 | 
			
		||||
  public itemTypes$: Observable<{ [id: string]: IItemType }>;
 | 
			
		||||
@@ -54,49 +54,51 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
  public selectedOverlayLayer$: Observable<IItemLayer> = this.store.select(mapReducers.selectGetSelectedOverlayLayer);
 | 
			
		||||
  public selectedItemLayer$: Observable<IItemLayer> = this.store.select(mapReducers.selectGetSelectedItemLayer);
 | 
			
		||||
  public baseLayers$: Observable<Array<IItemLayer>> = this.store.select(mapReducers.selectGetBaseLayers);
 | 
			
		||||
  public selectedBaseLayer$: Observable<IItemLayer> =  this.store.select(mapReducers.selectGetSelectedBaseLayer);
 | 
			
		||||
  public selectedBaseLayer$: Observable<IItemLayer> = this.store.select(mapReducers.selectGetSelectedBaseLayer);
 | 
			
		||||
  public projection$: Observable<string> = this.store.select(mapReducers.selectGetProjection);
 | 
			
		||||
  public selectedFeatures$: Subject<ISelectedFeatures> = new Subject<ISelectedFeatures>();
 | 
			
		||||
  public droppedFile$: Subject<IDroppedFile>  = new Subject<IDroppedFile>();
 | 
			
		||||
  public droppedFile$: Subject<IDroppedFile> = new Subject<IDroppedFile>();
 | 
			
		||||
  private paramSub: Subscription;
 | 
			
		||||
  private itemTypeSub: Subscription;
 | 
			
		||||
  private stateSub: Subscription;
 | 
			
		||||
  private queryStateSub: Subscription;
 | 
			
		||||
  private querySub: Subscription;
 | 
			
		||||
  public parentCode$: Observable<string> =this.store.select(mapReducers.selectGetParentCode);
 | 
			
		||||
  public parentCode$: Observable<string> = this.store.select(mapReducers.selectGetParentCode);
 | 
			
		||||
  public panelVisible$: Observable<boolean> = this.store.select(mapReducers.selectGetPanelVisible);
 | 
			
		||||
  public panelCollapsed$: Observable<boolean> = this.store.select(mapReducers.selectGetPanelCollapsed);
 | 
			
		||||
  public panelExtraWide$: Observable<boolean> = this.store.select(mapReducers.selectGetPanelExtraWide);
 | 
			
		||||
  public selectedFeature$: Observable<Feature<Geometry>> = this.store.select(mapReducers.selectGetSelectedFeature);
 | 
			
		||||
  public clickedFeature: Subject<Feature<Geometry>> = new Subject<Feature<Geometry>>();
 | 
			
		||||
  public selectedItem$: Observable<IItem> = this.store.select(mapReducers.selectGetSelectedItem);
 | 
			
		||||
  public parentItem$: Observable<IItem> =this.store.select(mapReducers.selectGetParentItem);
 | 
			
		||||
  public parentItem$: Observable<IItem> = this.store.select(mapReducers.selectGetParentItem);
 | 
			
		||||
  public queryState$: Observable<IQueryState> = this.store.select(mapReducers.selectGetQueryState);
 | 
			
		||||
  public state$:Observable<{mapState:IMapState,queryState:IQueryState}> = this.store.select(mapReducers.selectGetState);
 | 
			
		||||
  public state$: Observable<{ mapState: IMapState, queryState: IQueryState }> = this.store.select(mapReducers.selectGetState);
 | 
			
		||||
  public period$: Observable<IPeriodState> = this.store.select(mapReducers.selectGetPeriod);
 | 
			
		||||
  public clearEnabled$: Observable<boolean> = this.store.select(mapReducers.selectGetClearEnabled);
 | 
			
		||||
  public searchCollapsed$: Observable<boolean> = this.store.select(mapReducers.selectGetSearchCollapsed);
 | 
			
		||||
  public searchMinified$: Observable<boolean> = this.store.select(mapReducers.selectGetSearchMinified);
 | 
			
		||||
  public showDataLayerSlide$: Observable<boolean> = this.store.select(mapReducers.selectGetShowdataLayerSlide);
 | 
			
		||||
  public menuVisible$: Observable<boolean>;
 | 
			
		||||
  public query$: Observable<IQuery> =  this.store.select(mapReducers.selectGetQuery);
 | 
			
		||||
  public query$: Observable<IQuery> = this.store.select(mapReducers.selectGetQuery);
 | 
			
		||||
  public position$: Observable<GeolocationPosition> = this.geolocationService.getCurrentPosition();
 | 
			
		||||
  public compassHeading$: Observable<number> = this.deviceorientationService.getCurrentCompassHeading();
 | 
			
		||||
  public baseLayersCollapsed = true;
 | 
			
		||||
  public overlayLayersCollapsed = true;
 | 
			
		||||
  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 initialized = false;
 | 
			
		||||
  public noContent = false;
 | 
			
		||||
  public overrideSelectedItemLayer = false;
 | 
			
		||||
  public overrideOverlayLayers = false;
 | 
			
		||||
  public hideShowLayerValues = false;
 | 
			
		||||
  public const
 | 
			
		||||
  public dataLayerSlideValue = 50;
 | 
			
		||||
  public dataLayerSlideEnabled = false;
 | 
			
		||||
  private visibleAreaBottom = 0;
 | 
			
		||||
  private viewEnabled = true;
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  @ViewChild('map') map;
 | 
			
		||||
  @ViewChild('contentDiv') contentDiv: ElementRef;
 | 
			
		||||
 | 
			
		||||
@@ -110,47 +112,48 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
    private geolocationService: GeolocationService,
 | 
			
		||||
    private geolocaterService: GeolocatorService,
 | 
			
		||||
    private zone: NgZone,
 | 
			
		||||
    private deviceorientationService:DeviceOrientationService,
 | 
			
		||||
    public devicesService:DeviceService) {
 | 
			
		||||
      if(route && route.snapshot && route.snapshot.data && route.snapshot.data["fm-map-map"]) {
 | 
			
		||||
        const params = route.snapshot.data["fm-map-map"];
 | 
			
		||||
        this.overrideSelectedItemLayer = params["overrideSelectedItemlayer"] ? params["overrideSelectedItemlayer"] : false;
 | 
			
		||||
        this.overrideOverlayLayers = params["overrideOverlayLayers"] ? params["overrideOverlayLayers"] : false;
 | 
			
		||||
      }
 | 
			
		||||
      this.querySub = this.query$.pipe(skip(1), withLatestFrom(this.mapState$)).subscribe(([query,mapState]) =>{
 | 
			
		||||
        if(query && query.querystate) {
 | 
			
		||||
          let newQueryState = tassign(mapReducers.initialQueryState);
 | 
			
		||||
          //console.debug(`Do Query`);
 | 
			
		||||
          const urlparts=[];
 | 
			
		||||
          if (query.querystate.itemCode && query.querystate.itemCode != "") {
 | 
			
		||||
            if(query.querystate.itemType && query.querystate.itemType!= "") {
 | 
			
		||||
              const itemType = this.itemTypeService.itemTypes[query.querystate.itemType];
 | 
			
		||||
              if (itemType && itemType.viewer && itemType.viewer == "edit_in_editor" && itemType.editor) {
 | 
			
		||||
                urlparts.push('/editor');
 | 
			
		||||
                urlparts.push(itemType.editor);
 | 
			
		||||
                urlparts.push('item');
 | 
			
		||||
                urlparts.push(query.querystate.itemCode);
 | 
			
		||||
              }
 | 
			
		||||
    private deviceorientationService: DeviceOrientationService,
 | 
			
		||||
    public devicesService: DeviceService) {
 | 
			
		||||
    if (route && route.snapshot && route.snapshot.data && route.snapshot.data["fm-map-map"]) {
 | 
			
		||||
      const params = route.snapshot.data["fm-map-map"];
 | 
			
		||||
      this.overrideSelectedItemLayer = params["overrideSelectedItemlayer"] ? params["overrideSelectedItemlayer"] : false;
 | 
			
		||||
      this.overrideOverlayLayers = params["overrideOverlayLayers"] ? params["overrideOverlayLayers"] : false;
 | 
			
		||||
      this.hideShowLayerValues = params["hideShowLayerValues"] ? params["hideShowLayerValues"] : false;
 | 
			
		||||
    }
 | 
			
		||||
    this.querySub = this.query$.pipe(skip(1), withLatestFrom(this.mapState$)).subscribe(([query, mapState]) => {
 | 
			
		||||
      if (query && query.querystate) {
 | 
			
		||||
        let newQueryState = tassign(mapReducers.initialQueryState);
 | 
			
		||||
        //console.debug(`Do Query`);
 | 
			
		||||
        const urlparts = [];
 | 
			
		||||
        if (query.querystate.itemCode && query.querystate.itemCode != "") {
 | 
			
		||||
          if (query.querystate.itemType && query.querystate.itemType != "") {
 | 
			
		||||
            const itemType = this.itemTypeService.itemTypes[query.querystate.itemType];
 | 
			
		||||
            if (itemType && itemType.viewer && itemType.viewer == "edit_in_editor" && itemType.editor) {
 | 
			
		||||
              urlparts.push('/editor');
 | 
			
		||||
              urlparts.push(itemType.editor);
 | 
			
		||||
              urlparts.push('item');
 | 
			
		||||
              urlparts.push(query.querystate.itemCode);
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            newQueryState= query.querystate;
 | 
			
		||||
          }
 | 
			
		||||
          if(urlparts.length==0 ) {
 | 
			
		||||
            newQueryState.itemCode = query.querystate.itemCode;
 | 
			
		||||
            this.zone.run(() => {
 | 
			
		||||
              this.replaceUrl(mapState,newQueryState,query.replace);             
 | 
			
		||||
            })
 | 
			
		||||
          } else {
 | 
			
		||||
            this.router.navigate(urlparts);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          newQueryState = query.querystate;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      this.store.dispatch(new mapActions.Init());
 | 
			
		||||
      // this.store.select(commonReducers.getRootItems).subscribe((l) => {
 | 
			
		||||
      //    if(l && l.length>0) {
 | 
			
		||||
      //      this.store.dispatch(new mapActions.Init());
 | 
			
		||||
      //    }
 | 
			
		||||
      // });
 | 
			
		||||
        if (urlparts.length == 0) {
 | 
			
		||||
          newQueryState.itemCode = query.querystate.itemCode;
 | 
			
		||||
          this.zone.run(() => {
 | 
			
		||||
            this.replaceUrl(mapState, newQueryState, query.replace);
 | 
			
		||||
          })
 | 
			
		||||
        } else {
 | 
			
		||||
          this.router.navigate(urlparts);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    this.store.dispatch(new mapActions.Init());
 | 
			
		||||
    // this.store.select(commonReducers.getRootItems).subscribe((l) => {
 | 
			
		||||
    //    if(l && l.length>0) {
 | 
			
		||||
    //      this.store.dispatch(new mapActions.Init());
 | 
			
		||||
    //    }
 | 
			
		||||
    // });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @HostListener('document:keyup', ['$event'])
 | 
			
		||||
@@ -161,27 +164,27 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handlePanelResize(resizeTop:number) {
 | 
			
		||||
    if(resizeTop==100 || !this.devicesService.IsMobile() ) {
 | 
			
		||||
      this.visibleAreaBottom=0;
 | 
			
		||||
  handlePanelResize(resizeTop: number) {
 | 
			
		||||
    if (resizeTop == 100 || !this.devicesService.IsMobile()) {
 | 
			
		||||
      this.visibleAreaBottom = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
      this.visibleAreaBottom=100-resizeTop;
 | 
			
		||||
      if(this.visibleAreaBottom>60) {
 | 
			
		||||
        this.visibleAreaBottom=60;
 | 
			
		||||
      this.visibleAreaBottom = 100 - resizeTop;
 | 
			
		||||
      if (this.visibleAreaBottom > 60) {
 | 
			
		||||
        this.visibleAreaBottom = 60;
 | 
			
		||||
      }
 | 
			
		||||
    }      
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bottom(panelVisible:boolean) {
 | 
			
		||||
    if(panelVisible) {
 | 
			
		||||
      return this.visibleAreaBottom + '%';     
 | 
			
		||||
  bottom(panelVisible: boolean) {
 | 
			
		||||
    if (panelVisible) {
 | 
			
		||||
      return this.visibleAreaBottom + '%';
 | 
			
		||||
    } else {
 | 
			
		||||
      return "0%";
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOpenModal(modalName: string) {
 | 
			
		||||
    this.store.dispatch(new  commonActions.OpenModal(modalName));
 | 
			
		||||
    this.store.dispatch(new commonActions.OpenModal(modalName));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleCloseModal() {
 | 
			
		||||
@@ -189,7 +192,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleFileDropped(droppedFile: IDroppedFile) {
 | 
			
		||||
    this.uploadService.addFiles(droppedFile.files, droppedFile.event, { parentCode:droppedFile.parentCode, geometry:droppedFile.geometry });
 | 
			
		||||
    this.uploadService.addFiles(droppedFile.files, droppedFile.event, { parentCode: droppedFile.parentCode, geometry: droppedFile.geometry });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleFeatureClick(feature: Feature<Geometry>) {
 | 
			
		||||
@@ -205,26 +208,26 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
    this.store.dispatch(new mapActions.DoQuery(queryState));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleSidepaneloutletActivate(component:any) {
 | 
			
		||||
   if(component && component.hasOwnProperty('clickedFeature')) {
 | 
			
		||||
     (component as IClickedFeature).clickedFeature = this.clickedFeature;
 | 
			
		||||
   }
 | 
			
		||||
   if(component && component.hasOwnProperty('extrawide')) {
 | 
			
		||||
    this.store.dispatch(new mapActions.SetPanelExtraWide(true));
 | 
			
		||||
  handleSidepaneloutletActivate(component: any) {
 | 
			
		||||
    if (component && component.hasOwnProperty('clickedFeature')) {
 | 
			
		||||
      (component as IClickedFeature).clickedFeature = this.clickedFeature;
 | 
			
		||||
    }
 | 
			
		||||
    if (component && component.hasOwnProperty('extrawide')) {
 | 
			
		||||
      this.store.dispatch(new mapActions.SetPanelExtraWide(true));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 }
 | 
			
		||||
 | 
			
		||||
  handleSidepaneloutletDeactivate(component:any) {
 | 
			
		||||
    if(component && component.hasOwnProperty('clickedFeature')) {
 | 
			
		||||
  handleSidepaneloutletDeactivate(component: any) {
 | 
			
		||||
    if (component && component.hasOwnProperty('clickedFeature')) {
 | 
			
		||||
      (component as IClickedFeature).clickedFeature = null;
 | 
			
		||||
    }
 | 
			
		||||
    if(component && component.hasOwnProperty('extrawide')) {
 | 
			
		||||
    if (component && component.hasOwnProperty('extrawide')) {
 | 
			
		||||
      this.store.dispatch(new mapActions.SetPanelExtraWide(false));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handlePrerender(event:any) {
 | 
			
		||||
    if(!this.dataLayerSlideEnabled) return;
 | 
			
		||||
  handlePrerender(event: any) {
 | 
			
		||||
    if (!this.dataLayerSlideEnabled) return;
 | 
			
		||||
    const ctx = event.context;
 | 
			
		||||
    const mapSize = this.map.instance.getSize();
 | 
			
		||||
    const width = mapSize[0] * (this.dataLayerSlideValue / 100);
 | 
			
		||||
@@ -243,72 +246,74 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
    ctx.clip();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleSlideChange(event:any) {
 | 
			
		||||
     this.dataLayerSlideValue = event.target.value;
 | 
			
		||||
     this.map.instance.render();
 | 
			
		||||
  handleSlideChange(event: any) {
 | 
			
		||||
    this.dataLayerSlideValue = event.target.value;
 | 
			
		||||
    this.map.instance.render();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {    
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.initialized = false;
 | 
			
		||||
    //console.debug("Init");
 | 
			
		||||
    this.store.dispatch(new mapActions.Clear());
 | 
			
		||||
    this.selectedFeatures$.next({x:0,y:0,features:[]});
 | 
			
		||||
    this.selectedFeatures$.next({ x: 0, y: 0, features: [] });
 | 
			
		||||
    this.selectedFeatures$.next(null);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  initCustomStyles() {
 | 
			
		||||
    this.store.dispatch(new mapActions.SetStyle('vnd.farmmaps.itemtype.layer',new style.Style({
 | 
			
		||||
    this.store.dispatch(new mapActions.SetStyle('vnd.farmmaps.itemtype.layer', new style.Style({
 | 
			
		||||
      stroke: new style.Stroke({
 | 
			
		||||
        color: 'red',
 | 
			
		||||
        lineDash: [ 5,5],
 | 
			
		||||
        lineDash: [5, 5],
 | 
			
		||||
        width: 1
 | 
			
		||||
      }),
 | 
			
		||||
      geometry:(feature) =>feature.getGeometry()
 | 
			
		||||
      geometry: (feature) => feature.getGeometry()
 | 
			
		||||
    })));
 | 
			
		||||
    this.store.dispatch(new mapActions.SetStyle('vnd.farmmaps.itemtype.layer_selected',new style.Style({
 | 
			
		||||
    this.store.dispatch(new mapActions.SetStyle('vnd.farmmaps.itemtype.layer_selected', new style.Style({
 | 
			
		||||
      stroke: new style.Stroke({
 | 
			
		||||
        color: 'red',
 | 
			
		||||
        lineDash: [ 5,5],
 | 
			
		||||
        lineDash: [5, 5],
 | 
			
		||||
        width: 3
 | 
			
		||||
      }),
 | 
			
		||||
      geometry:(feature) =>feature.getGeometry()
 | 
			
		||||
      geometry: (feature) => feature.getGeometry()
 | 
			
		||||
    })));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  round(value:number,decimals:number):number {
 | 
			
		||||
  round(value: number, decimals: number): number {
 | 
			
		||||
    const d = Math.pow(10, decimals);
 | 
			
		||||
    return Math.round((value + Number.EPSILON)*d)/d;
 | 
			
		||||
    return Math.round((value + Number.EPSILON) * d) / d;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getMapStateFromUrl(params:ParamMap):IMapState {
 | 
			
		||||
  getMapStateFromUrl(params: ParamMap): IMapState {
 | 
			
		||||
    const hasUrlmapState = params.has("xCenter") && params.has("yCenter");
 | 
			
		||||
    if (hasUrlmapState) {
 | 
			
		||||
      const xCenter = parseFloat(params.get("xCenter"));
 | 
			
		||||
      const yCenter = parseFloat(params.get("yCenter"));
 | 
			
		||||
      const zoom = parseFloat(params.get("zoom"));
 | 
			
		||||
      const rotation = parseFloat(params.get("rotation"));
 | 
			
		||||
      const baseLayer = params.get("baseLayer")?params.get("baseLayer"):"";
 | 
			
		||||
      const newMapState = {zoom: zoom, rotation: rotation, xCenter: xCenter, yCenter: yCenter, baseLayerCode: baseLayer };
 | 
			
		||||
      const baseLayer = params.get("baseLayer") ? params.get("baseLayer") : "";
 | 
			
		||||
      const newMapState = { zoom: zoom, rotation: rotation, xCenter: xCenter, yCenter: yCenter, baseLayerCode: baseLayer };
 | 
			
		||||
      return newMapState;
 | 
			
		||||
    } else {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  normalizeMapState(mapState:IMapState):IMapState {
 | 
			
		||||
    if(!mapState) return null;
 | 
			
		||||
    return {zoom: this.round(mapState.zoom,0),
 | 
			
		||||
      rotation: this.round(mapState.rotation,2),
 | 
			
		||||
      xCenter: this.round(mapState.xCenter,5),
 | 
			
		||||
      yCenter: this.round(mapState.yCenter,5),
 | 
			
		||||
      baseLayerCode: mapState.baseLayerCode };
 | 
			
		||||
  normalizeMapState(mapState: IMapState): IMapState {
 | 
			
		||||
    if (!mapState) return null;
 | 
			
		||||
    return {
 | 
			
		||||
      zoom: this.round(mapState.zoom, 0),
 | 
			
		||||
      rotation: this.round(mapState.rotation, 2),
 | 
			
		||||
      xCenter: this.round(mapState.xCenter, 5),
 | 
			
		||||
      yCenter: this.round(mapState.yCenter, 5),
 | 
			
		||||
      baseLayerCode: mapState.baseLayerCode
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  serializeMapState(mapState:IMapState):string {
 | 
			
		||||
  serializeMapState(mapState: IMapState): string {
 | 
			
		||||
    return JSON.stringify(this.normalizeMapState(mapState));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getQueryStateFromUrl(params:ParamMap):IQueryState {
 | 
			
		||||
  getQueryStateFromUrl(params: ParamMap): IQueryState {
 | 
			
		||||
    if (params.has("queryState")) {
 | 
			
		||||
      const queryState = params.get("queryState");
 | 
			
		||||
      let newQueryState = tassign(mapReducers.initialQueryState);
 | 
			
		||||
@@ -323,65 +328,65 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
 | 
			
		||||
  ngAfterViewInit() {
 | 
			
		||||
    //console.debug("View init");
 | 
			
		||||
    this.noContent=true;
 | 
			
		||||
    this.noContent = true;
 | 
			
		||||
    this.route.children.forEach((entry) => {
 | 
			
		||||
      if(entry.outlet=="primary") {
 | 
			
		||||
        this.noContent=false;
 | 
			
		||||
      if (entry.outlet == "primary") {
 | 
			
		||||
        this.noContent = false;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
    this.initCustomStyles();
 | 
			
		||||
 | 
			
		||||
    // url to state
 | 
			
		||||
 | 
			
		||||
      const urlMapState = this.getMapStateFromUrl(this.route.snapshot.paramMap);
 | 
			
		||||
      const urlQueryState = this.getQueryStateFromUrl(this.route.snapshot.paramMap);
 | 
			
		||||
      if(urlQueryState && urlMapState && this.noContent) {
 | 
			
		||||
        this.store.dispatch(new mapActions.SetState(urlMapState,urlQueryState));
 | 
			
		||||
        window.localStorage.setItem("FarmMapsCommonMap_mapState",this.serializeMapState(urlMapState));
 | 
			
		||||
      } else if(urlQueryState && this.noContent) {
 | 
			
		||||
        this.store.dispatch(new mapActions.SetQueryState(urlQueryState));
 | 
			
		||||
      }  else {
 | 
			
		||||
        this.store.dispatch(new mapActions.SetReplaceUrl(true));
 | 
			
		||||
      }
 | 
			
		||||
    const urlMapState = this.getMapStateFromUrl(this.route.snapshot.paramMap);
 | 
			
		||||
    const urlQueryState = this.getQueryStateFromUrl(this.route.snapshot.paramMap);
 | 
			
		||||
    if (urlQueryState && urlMapState && this.noContent) {
 | 
			
		||||
      this.store.dispatch(new mapActions.SetState(urlMapState, urlQueryState));
 | 
			
		||||
      window.localStorage.setItem("FarmMapsCommonMap_mapState", this.serializeMapState(urlMapState));
 | 
			
		||||
    } else if (urlQueryState && this.noContent) {
 | 
			
		||||
      this.store.dispatch(new mapActions.SetQueryState(urlQueryState));
 | 
			
		||||
    } else {
 | 
			
		||||
      this.store.dispatch(new mapActions.SetReplaceUrl(true));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      this.paramSub = this.route.paramMap.pipe(withLatestFrom(this.state$),switchMap(([params,state]) => {
 | 
			
		||||
         if(this.initialized && this.noContent) {
 | 
			
		||||
          const urlQueryState = this.getQueryStateFromUrl(params);
 | 
			
		||||
          if( this.serializeService.serialize(state.queryState) != this.serializeService.serialize(urlQueryState)) {
 | 
			
		||||
            return of(new mapActions.SetState(state.mapState,urlQueryState));
 | 
			
		||||
          }          
 | 
			
		||||
         } 
 | 
			
		||||
         return EMPTY;        
 | 
			
		||||
      })).subscribe((action) => {
 | 
			
		||||
        if(action) {
 | 
			
		||||
          this.zone.run(() => {
 | 
			
		||||
            //console.debug("Url to state");
 | 
			
		||||
            this.store.dispatch(action);
 | 
			
		||||
          });
 | 
			
		||||
    this.paramSub = this.route.paramMap.pipe(withLatestFrom(this.state$), switchMap(([params, state]) => {
 | 
			
		||||
      if (this.initialized && this.noContent) {
 | 
			
		||||
        const urlQueryState = this.getQueryStateFromUrl(params);
 | 
			
		||||
        if (this.serializeService.serialize(state.queryState) != this.serializeService.serialize(urlQueryState)) {
 | 
			
		||||
          return of(new mapActions.SetState(state.mapState, urlQueryState));
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      }
 | 
			
		||||
      return EMPTY;
 | 
			
		||||
    })).subscribe((action) => {
 | 
			
		||||
      if (action) {
 | 
			
		||||
        this.zone.run(() => {
 | 
			
		||||
          //console.debug("Url to state");
 | 
			
		||||
          this.store.dispatch(action);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // state to url
 | 
			
		||||
 | 
			
		||||
    this.stateSub = this.state$.pipe(switchMap((state) => {
 | 
			
		||||
      const newUrl = this.serializeMapState(state.mapState) + "_" + this.serializeService.serialize(state.queryState);
 | 
			
		||||
      if(this.lastUrl!=newUrl) {
 | 
			
		||||
        this.lastUrl=newUrl;
 | 
			
		||||
      if (this.lastUrl != newUrl) {
 | 
			
		||||
        this.lastUrl = newUrl;
 | 
			
		||||
        return of(state);
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        return of(null);
 | 
			
		||||
      }
 | 
			
		||||
    })).subscribe((newUrlState: any) => {
 | 
			
		||||
        if(newUrlState) {
 | 
			
		||||
          //console.debug(`State to url`);
 | 
			
		||||
          this.replaceUrl(newUrlState.mapState,newUrlState.queryState,newUrlState.replaceUrl);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    this.initialized = true;   
 | 
			
		||||
      if (newUrlState) {
 | 
			
		||||
        //console.debug(`State to url`);
 | 
			
		||||
        this.replaceUrl(newUrlState.mapState, newUrlState.queryState, newUrlState.replaceUrl);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    this.initialized = true;
 | 
			
		||||
    this.showDataLayerSlide$.subscribe((v) => {
 | 
			
		||||
      this.dataLayerSlideEnabled=v;
 | 
			
		||||
      this.dataLayerSlideEnabled = v;
 | 
			
		||||
      this.map.instance.render();
 | 
			
		||||
    });
 | 
			
		||||
    this.store.select(mapReducers.selectGetViewEnabled).subscribe((v) => {
 | 
			
		||||
@@ -401,7 +406,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
    this.store.dispatch(new commonActions.ToggleMenu());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleToggleBaseLayers(event:MouseEvent) {
 | 
			
		||||
  handleToggleBaseLayers(event: MouseEvent) {
 | 
			
		||||
    this.baseLayersCollapsed = !this.baseLayersCollapsed;
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
  }
 | 
			
		||||
@@ -418,30 +423,30 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  replaceUrl(mapState: IMapState, queryState: IQueryState, replace = true) {
 | 
			
		||||
      if(this.noContent) {
 | 
			
		||||
        const newMapState = this.serializeMapState(mapState);
 | 
			
		||||
        const newQueryState = this.serializeService.serialize(queryState);
 | 
			
		||||
        const currentMapState = this.serializeMapState(this.getMapStateFromUrl(this.route.snapshot.paramMap));
 | 
			
		||||
        const urlQueryState = this.getQueryStateFromUrl(this.route.snapshot.paramMap);
 | 
			
		||||
        const currentQueryState = urlQueryState==null?"":this.serializeService.serialize(urlQueryState);
 | 
			
		||||
        if(mapState.baseLayerCode!="" && ((newMapState!= currentMapState)  || (newQueryState!=currentQueryState))) {
 | 
			
		||||
          const 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 });
 | 
			
		||||
        }  
 | 
			
		||||
      }     
 | 
			
		||||
    if (this.noContent) {
 | 
			
		||||
      const newMapState = this.serializeMapState(mapState);
 | 
			
		||||
      const newQueryState = this.serializeService.serialize(queryState);
 | 
			
		||||
      const currentMapState = this.serializeMapState(this.getMapStateFromUrl(this.route.snapshot.paramMap));
 | 
			
		||||
      const urlQueryState = this.getQueryStateFromUrl(this.route.snapshot.paramMap);
 | 
			
		||||
      const currentQueryState = urlQueryState == null ? "" : this.serializeService.serialize(urlQueryState);
 | 
			
		||||
      if (mapState.baseLayerCode != "" && ((newMapState != currentMapState) || (newQueryState != currentQueryState))) {
 | 
			
		||||
        const 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 });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOnMoveEnd(event) {    
 | 
			
		||||
    if(this.initialized && this.viewEnabled) {
 | 
			
		||||
      this.zone.run(() =>{
 | 
			
		||||
  handleOnMoveEnd(event) {
 | 
			
		||||
    if (this.initialized && this.viewEnabled) {
 | 
			
		||||
      this.zone.run(() => {
 | 
			
		||||
        //console.debug("Move end");
 | 
			
		||||
        const map = event.map;
 | 
			
		||||
        const view = map.getView();
 | 
			
		||||
@@ -461,21 +466,23 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    }   
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOnMouseDown(event: MouseEvent) {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
    this.zone.run(() =>{
 | 
			
		||||
    this.zone.run(() => {
 | 
			
		||||
      this.store.dispatch(new commonActions.CloseAll());
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleShowLayerValues(event: MouseEvent) {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
    this.zone.run(() =>{
 | 
			
		||||
      this.store.dispatch(new mapActions.ToggleLayerValuesEnabled());
 | 
			
		||||
    });
 | 
			
		||||
    if (!this.hideShowLayerValues) {
 | 
			
		||||
      event.stopPropagation();
 | 
			
		||||
      this.zone.run(() => {
 | 
			
		||||
        this.store.dispatch(new mapActions.ToggleLayerValuesEnabled());
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOnDownload(event) {
 | 
			
		||||
@@ -491,15 +498,15 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOnToggleVisibility(itemLayer: IItemLayer) {
 | 
			
		||||
    this.store.dispatch(new mapActions.SetVisibility(itemLayer,!itemLayer.visible));
 | 
			
		||||
    this.store.dispatch(new mapActions.SetVisibility(itemLayer, !itemLayer.visible));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOnSetOpacity(event:{ layer: IItemLayer,opacity:number }) {
 | 
			
		||||
  handleOnSetOpacity(event: { layer: IItemLayer, opacity: number }) {
 | 
			
		||||
    this.store.dispatch(new mapActions.SetOpacity(event.layer, event.opacity));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleZoomToExtent(itemLayer: IItemLayer) {
 | 
			
		||||
    const extent =  createEmpty();
 | 
			
		||||
    const extent = createEmpty();
 | 
			
		||||
    extend(extent, itemLayer.layer.getExtent());
 | 
			
		||||
    if (extent) {
 | 
			
		||||
      this.store.dispatch(new mapActions.SetExtent(extent));
 | 
			
		||||
@@ -514,21 +521,21 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
 | 
			
		||||
    this.store.dispatch(new mapActions.SelectOverlayLayer(itemLayer));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handlePeriodChange(period:IPeriodState) {
 | 
			
		||||
  handlePeriodChange(period: IPeriodState) {
 | 
			
		||||
    this.store.dispatch(new mapActions.SetPeriod(period));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleCitySearch(location:string) {
 | 
			
		||||
  handleCitySearch(location: string) {
 | 
			
		||||
    this.geolocaterService.geocode(location).subscribe(locations => {
 | 
			
		||||
      if( locations.length > 0) {
 | 
			
		||||
        const point = new  Point([locations[0].coordinates.lon,locations[0].coordinates.lat]);
 | 
			
		||||
      if (locations.length > 0) {
 | 
			
		||||
        const point = new Point([locations[0].coordinates.lon, locations[0].coordinates.lat]);
 | 
			
		||||
        point.transform('EPSG:4326', 'EPSG:3857');
 | 
			
		||||
        const circle = new Circle(point.getCoordinates(),5000);// 
 | 
			
		||||
        const circle = new Circle(point.getCoordinates(), 5000);// 
 | 
			
		||||
        const extent = createEmpty();
 | 
			
		||||
        extend(extent, circle.getExtent());
 | 
			
		||||
        this.store.dispatch(new mapActions.SetExtent(extent))
 | 
			
		||||
      }
 | 
			
		||||
     });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ export class SelectedItemCropfieldComponent extends AbstractSelectedItemComponen
 | 
			
		||||
  public items: Observable<IListItem[]>;
 | 
			
		||||
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, location: Location, router: Router, private itemService$: ItemService,private folderService$: FolderService) {
 | 
			
		||||
    super(store, itemTypeService,location,router);
 | 
			
		||||
    super(store, itemTypeService, itemService$, location,router);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  areaInHa(item:IItem):number {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,28 +7,31 @@
 | 
			
		||||
        <h2 *ngIf="parentOfItemType('vnd.farmmaps.itemtype.cropfield')">{{parentItem.name}}</h2>
 | 
			
		||||
        <h1>{{item.name}}</h1>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="legend-container" *ngIf="item?.data.layers;let layers">
 | 
			
		||||
        <div class="card menu-card">
 | 
			
		||||
          <div *ngIf="layers.length>1">
 | 
			
		||||
            <select (change)="onLayerChanged($event.target.value)">
 | 
			
		||||
              <option *ngFor="let l of layers;" [value]="l.index"  [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
 | 
			
		||||
            </select>
 | 
			
		||||
      <ng-container *ngIf="item?.data.layers;let layers">
 | 
			
		||||
        <div class="legend-container">
 | 
			
		||||
          <div class="card menu-card">
 | 
			
		||||
            <div *ngIf="layers.length>1">
 | 
			
		||||
              <select (change)="onLayerChanged($event.target.value)">
 | 
			
		||||
                <option *ngFor="let l of layers;" [value]="l.index"  [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
 | 
			
		||||
              </select>
 | 
			
		||||
            </div>
 | 
			
		||||
            <fm-map-layer-legend [showTitle]="layers.length == 1"
 | 
			
		||||
              [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
 | 
			
		||||
          </div>
 | 
			
		||||
          <fm-map-layer-legend [showTitle]="layers.length == 1"
 | 
			
		||||
            [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card menu-card">
 | 
			
		||||
        <ul class="p-0 mt-2">
 | 
			
		||||
          <li *ngIf="item.isEditable"><a href="#" class="ms-1 me-1" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i> <span i18n>Edit</span></a></li>
 | 
			
		||||
          <ng-container *ngIf="itemTypeService.isLayer(item)">
 | 
			
		||||
            <li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a   href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i> <span i18n>Add as overlay</span></a></li>
 | 
			
		||||
            <li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a  href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i> <span i18n>Remove overlay</span></a></li>
 | 
			
		||||
          </ng-container>
 | 
			
		||||
          <li><fm-item-link class="text-primary p-0" [itemCode]="item.code" pathSuffix="data" [showText]="true"></fm-item-link></li>
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
      <fm-map-zoom-to-show-alert [layer]="itemLayer?.layer"></fm-map-zoom-to-show-alert>
 | 
			
		||||
        <div class="card menu-card">
 | 
			
		||||
          <ul class="p-0 mt-2">
 | 
			
		||||
            <li *ngIf="item.isEditable"><a href="#" class="ms-1 me-1" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i> <span i18n>Edit</span></a></li>
 | 
			
		||||
            <ng-container *ngIf="itemTypeService.isLayer(item)">
 | 
			
		||||
              <li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a   href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i> <span i18n>Add as overlay</span></a></li>
 | 
			
		||||
              <li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a  href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i> <span i18n>Remove overlay</span></a></li>
 | 
			
		||||
            </ng-container>
 | 
			
		||||
            <li><fm-item-link class="text-primary p-0" [itemCode]="item.code" pathSuffix="data" [showText]="true"></fm-item-link></li>
 | 
			
		||||
            <li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i> <span i18n>Download</span></a></li>
 | 
			
		||||
          </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
        <fm-map-zoom-to-show-alert [layer]="itemLayer?.layer"></fm-map-zoom-to-show-alert>
 | 
			
		||||
      </ng-container>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
import { Component, Injectable } from '@angular/core';
 | 
			
		||||
import { Location } from '@angular/common';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import { commonReducers, ItemTypeService, ItemService, FolderService } from '@farmmaps/common';
 | 
			
		||||
import { Component, Injectable, OnDestroy } from '@angular/core';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { commonReducers, FolderService, IItem, IItemLinkType, ItemService, ItemTypeService, IUrlType } from '@farmmaps/common';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import { ForItemType } from '../for-item/for-itemtype.decorator';
 | 
			
		||||
import { AbstractSelectedItemComponent } from '../selected-item/selected-item.component';
 | 
			
		||||
import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ForItemType("vnd.farmmaps.itemtype.geotiff.processed")
 | 
			
		||||
@@ -16,10 +17,15 @@ import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
  templateUrl: './selected-item-geotiff.component.html',
 | 
			
		||||
  styleUrls: ['./selected-item-geotiff.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SelectedItemGeotiffComponent extends AbstractSelectedItemComponent {
 | 
			
		||||
export class SelectedItemGeotiffComponent extends AbstractSelectedItemComponent implements OnDestroy {
 | 
			
		||||
  sub: Subscription;
 | 
			
		||||
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, location: Location, router: Router, private itemService$: ItemService,private folderService$: FolderService) {
 | 
			
		||||
    super(store, itemTypeService,location,router);
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, public itemService: ItemService, itemTypeService: ItemTypeService, location: Location, router: Router, private itemService$: ItemService,private folderService$: FolderService) {
 | 
			
		||||
    super(store, itemTypeService,itemService,location,router);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy(): void {
 | 
			
		||||
    if (this.sub) this.sub.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onLayerChanged(layerIndex: number) {
 | 
			
		||||
@@ -29,4 +35,13 @@ export class SelectedItemGeotiffComponent extends AbstractSelectedItemComponent
 | 
			
		||||
  layer(layers:any,layerIndex:number) {
 | 
			
		||||
    return layers.find(l => l.index == layerIndex);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  download(event:MouseEvent,item:IItem,layers:any,layerIndex:number) {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
    const itemLink : IItemLinkType = {itemcode:item.code,query:`layer=${this.layer(layers,layerIndex).name}`,pathsuffix:"download", validminutes:10}
 | 
			
		||||
    this.sub = this.itemService.getItemLink(itemLink).subscribe((itemLinkUrl:IUrlType) => {  
 | 
			
		||||
        window.location.href = itemLinkUrl.url;     
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,25 +7,28 @@
 | 
			
		||||
        <h2 *ngIf="parentOfItemType('vnd.farmmaps.itemtype.cropfield')">{{parentItem.name}}</h2>
 | 
			
		||||
        <h1>{{item.name}}</h1>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="legend-container" *ngIf="item?.data.layers;let layers">
 | 
			
		||||
        <div class="card menu-card">
 | 
			
		||||
          <div *ngIf="layers.length>1">
 | 
			
		||||
            <select (change)="onLayerChanged($event.target.value)">
 | 
			
		||||
              <option *ngFor="let l of layers;" [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
 | 
			
		||||
            </select>
 | 
			
		||||
      <ng-container *ngIf="item?.data.layers;let layers">
 | 
			
		||||
        <div class="legend-container">
 | 
			
		||||
          <div class="card menu-card">
 | 
			
		||||
            <div *ngIf="layers.length>1">
 | 
			
		||||
              <select (change)="onLayerChanged($event.target.value)">
 | 
			
		||||
                <option *ngFor="let l of layers;" [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
 | 
			
		||||
              </select>
 | 
			
		||||
            </div>
 | 
			
		||||
            <fm-map-layer-legend [showTitle]="layers.length==1" [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
 | 
			
		||||
          </div>
 | 
			
		||||
          <fm-map-layer-legend [showTitle]="layers.length==1" [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card menu-card">
 | 
			
		||||
        <ul class="p-0 mt-2">
 | 
			
		||||
          <li *ngIf="item.isEditable"><a href="#" class="mt-1 me-1" (click)="handleOnEdit(item)" ><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i> <span i18n>Edit</span></a></li>
 | 
			
		||||
          <ng-container *ngIf="itemTypeService.isLayer(item)">
 | 
			
		||||
            <li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a   href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)" ><i class="fas fa-layer-olus" aria-hidden="true" i18n-title title="Add as layer"></i> <span i18n>Add as overlay</span></a></li>
 | 
			
		||||
            <li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a  href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)" ><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i> <span i18n>Remove overlay</span></a></li>
 | 
			
		||||
          </ng-container>
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
        <div class="card menu-card">
 | 
			
		||||
          <ul class="p-0 mt-2">
 | 
			
		||||
            <li *ngIf="item.isEditable"><a href="#" class="mt-1 me-1" (click)="handleOnEdit(item)" ><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i> <span i18n>Edit</span></a></li>
 | 
			
		||||
            <ng-container *ngIf="itemTypeService.isLayer(item)">
 | 
			
		||||
              <li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a   href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)" ><i class="fas fa-layer-olus" aria-hidden="true" i18n-title title="Add as layer"></i> <span i18n>Add as overlay</span></a></li>
 | 
			
		||||
              <li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a  href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)" ><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i> <span i18n>Remove overlay</span></a></li>
 | 
			
		||||
            </ng-container>
 | 
			
		||||
            <li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i> <span i18n>Download</span></a></li>
 | 
			
		||||
          </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
      </ng-container>
 | 
			
		||||
      <fm-map-zoom-to-show-alert [layer]="itemLayer?.layer"></fm-map-zoom-to-show-alert>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,13 @@
 | 
			
		||||
import { Component, Input, Injectable, OnInit } from '@angular/core';
 | 
			
		||||
import { Location } from '@angular/common';
 | 
			
		||||
import { Feature } from 'ol';
 | 
			
		||||
import { Component, Injectable, OnDestroy } from '@angular/core';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { commonReducers, FolderService, IItem, IItemLinkType, ItemService, ItemTypeService, IUrlType } from '@farmmaps/common';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import { commonReducers, ItemTypeService, IItem, Item, ItemService, FolderService, IListItem} from '@farmmaps/common';
 | 
			
		||||
import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
import { Router, ActivatedRoute, ParamMap, Event } from '@angular/router';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import { ForItemType } from '../for-item/for-itemtype.decorator';
 | 
			
		||||
import { AbstractSelectedItemComponent } from '../selected-item/selected-item.component';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ForItemType("vnd.farmmaps.itemtype.shape.processed")
 | 
			
		||||
@@ -18,13 +17,18 @@ import { Observable } from 'rxjs';
 | 
			
		||||
  templateUrl: './selected-item-shape.component.html',
 | 
			
		||||
  styleUrls: ['./selected-item-shape.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SelectedItemShapeComponent extends AbstractSelectedItemComponent {
 | 
			
		||||
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, location: Location, router: Router, private itemService$: ItemService,private folderService$: FolderService) {
 | 
			
		||||
    super(store, itemTypeService,location,router);
 | 
			
		||||
  }
 | 
			
		||||
export class SelectedItemShapeComponent extends AbstractSelectedItemComponent implements OnDestroy {
 | 
			
		||||
  public selectedLayer = 0;
 | 
			
		||||
  
 | 
			
		||||
  sub: Subscription;
 | 
			
		||||
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, public itemService: ItemService, itemTypeService: ItemTypeService, location: Location, router: Router, private itemService$: ItemService,private folderService$: FolderService) {
 | 
			
		||||
    super(store, itemTypeService,itemService,location,router);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy(): void {
 | 
			
		||||
    if (this.sub) this.sub.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onLayerChanged(layerIndex: number) {
 | 
			
		||||
    this.store.dispatch(new mapActions.SetLayerIndex(layerIndex));
 | 
			
		||||
  }
 | 
			
		||||
@@ -32,4 +36,13 @@ export class SelectedItemShapeComponent extends AbstractSelectedItemComponent {
 | 
			
		||||
  layer(layers:any,layerIndex:number) {
 | 
			
		||||
    return layers.find(l => l.index == layerIndex);
 | 
			
		||||
  }
 | 
			
		||||
    
 | 
			
		||||
  download(event:MouseEvent,item:IItem,layers:any,layerIndex:number) {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
    const itemLink : IItemLinkType = {itemcode:item.code,query:`layer=${this.layer(layers,layerIndex).name}`,pathsuffix:"download", validminutes:10}
 | 
			
		||||
    this.sub = this.itemService.getItemLink(itemLink).subscribe((itemLinkUrl:IUrlType) => {  
 | 
			
		||||
        window.location.href = itemLinkUrl.url;     
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,43 +7,46 @@
 | 
			
		||||
        <h2 *ngIf="parentOfItemType('vnd.farmmaps.itemtype.cropfield')">{{parentItem.name}}</h2>
 | 
			
		||||
        <h1>{{item.name}}</h1>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="legend-container" *ngIf="item?.data.layers;let layers">
 | 
			
		||||
      <ng-container *ngIf="item?.data.layers;let layers">
 | 
			
		||||
        <div class="legend-container">
 | 
			
		||||
          <div class="card menu-card">
 | 
			
		||||
            <h5><span i18n>Date</span>: {{temporalService.selectedDate(itemLayer)}}</h5>
 | 
			
		||||
            <div class="d-flex justify-content-between">
 | 
			
		||||
              <div>
 | 
			
		||||
                <button  *ngIf="temporalService.hasPrevious(itemLayer)" type="button" class="btn btn-link p-0" (click)="handlePreviousTemporal($event)">
 | 
			
		||||
                  <i class="fal fa-arrow-circle-left" aria-hidden="true" i18n-title title="Previous"></i> {{ temporalService.previousDate(itemLayer) }}
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div>
 | 
			
		||||
                <button  *ngIf="temporalService.hasNext(itemLayer)" type="button" class="btn btn-link p-0" (click)="handleNextTemporal($event)">
 | 
			
		||||
                  {{ temporalService.nextDate(itemLayer)}} <i class="fal fa-arrow-circle-right" aria-hidden="true" i18n-title title="Next"></i>
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <fm-map-zoom-to-show-alert [layer]="currentItemLayer()?.layer"></fm-map-zoom-to-show-alert>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="card menu-card pt-2">
 | 
			
		||||
            <div *ngIf="layers.length>1">
 | 
			
		||||
              <select (change)="onLayerChanged($event.target.value)">
 | 
			
		||||
                <option *ngFor="let l of layers;" [value]="l.index"  [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
 | 
			
		||||
              </select>
 | 
			
		||||
            </div>
 | 
			
		||||
            <fm-map-layer-legend [showTitle]="layers.length == 1"
 | 
			
		||||
              [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card menu-card">
 | 
			
		||||
          <h5><span i18n>Date</span>: {{temporalService.selectedDate(itemLayer)}}</h5>
 | 
			
		||||
          <div class="d-flex justify-content-between">
 | 
			
		||||
            <div>
 | 
			
		||||
              <button  *ngIf="temporalService.hasPrevious(itemLayer)" type="button" class="btn btn-link p-0" (click)="handlePreviousTemporal($event)">
 | 
			
		||||
                <i class="fal fa-arrow-circle-left" aria-hidden="true" i18n-title title="Previous"></i> {{ temporalService.previousDate(itemLayer) }}
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
              <button  *ngIf="temporalService.hasNext(itemLayer)" type="button" class="btn btn-link p-0" (click)="handleNextTemporal($event)">
 | 
			
		||||
                {{ temporalService.nextDate(itemLayer)}} <i class="fal fa-arrow-circle-right" aria-hidden="true" i18n-title title="Next"></i>
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <fm-map-zoom-to-show-alert [layer]="currentItemLayer()?.layer"></fm-map-zoom-to-show-alert>
 | 
			
		||||
          <ul class="p-0 mt-2">
 | 
			
		||||
            <li *ngIf="item.isEditable"><a href="#" class="mt-1 me-1" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i> <span i18n>Edit</span></a></li>
 | 
			
		||||
            <ng-container *ngIf="itemTypeService.isLayer(item)">
 | 
			
		||||
              <li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a   href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i> <span i18n>Add as overlay</span></a></li>
 | 
			
		||||
              <li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a  href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i> <span i18n>Remove overlay</span></a></li>
 | 
			
		||||
            </ng-container>
 | 
			
		||||
            <li><a href="#" (click)="handleGoToChart(item)"><i class="fal fa-line-chart" aria-hidden="true" i18m-title title="Show chart"></i> <span i18n>Show chart</span></a></li>
 | 
			
		||||
            <li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i> <span i18n>Download</span></a></li>
 | 
			
		||||
          </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card menu-card pt-2">
 | 
			
		||||
          <div *ngIf="layers.length>1">
 | 
			
		||||
            <select (change)="onLayerChanged($event.target.value)">
 | 
			
		||||
              <option *ngFor="let l of layers;" [value]="l.index"  [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
 | 
			
		||||
            </select>
 | 
			
		||||
          </div>
 | 
			
		||||
          <fm-map-layer-legend [showTitle]="layers.length == 1"
 | 
			
		||||
            [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card menu-card">
 | 
			
		||||
        <ul class="p-0 mt-2">
 | 
			
		||||
          <li *ngIf="item.isEditable"><a href="#" class="mt-1 me-1" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i> <span i18n>Edit</span></a></li>
 | 
			
		||||
          <ng-container *ngIf="itemTypeService.isLayer(item)">
 | 
			
		||||
            <li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a   href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i> <span i18n>Add as overlay</span></a></li>
 | 
			
		||||
            <li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a  href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i> <span i18n>Remove overlay</span></a></li>
 | 
			
		||||
          </ng-container>
 | 
			
		||||
          <li><a href="#" (click)="handleGoToChart(item)"><i class="fal fa-line-chart" aria-hidden="true" i18m-title title="Show chart"></i> <span i18n>Show chart</span></a></li>
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
      </ng-container>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,15 @@
 | 
			
		||||
import { Component, Injectable } from '@angular/core';
 | 
			
		||||
import { Location } from '@angular/common';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import { commonReducers, ItemTypeService, IItem } from '@farmmaps/common';
 | 
			
		||||
import { Component, Injectable, OnDestroy } from '@angular/core';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { commonReducers, IItem, IItemLinkType, ItemService, ItemTypeService, IUrlType } from '@farmmaps/common';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
import { IItemLayer, ITemporalItemLayer } from '../../models/item.layer';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import { TemporalService } from '../../services/temporal.service';
 | 
			
		||||
import { ForItemType } from '../for-item/for-itemtype.decorator';
 | 
			
		||||
import { AbstractSelectedItemComponent } from '../selected-item/selected-item.component';
 | 
			
		||||
import { ITemporalItemLayer} from '../../models/item.layer';
 | 
			
		||||
import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
import { IItemLayer } from '../../models/item.layer';
 | 
			
		||||
import {TemporalService} from '../../services/temporal.service';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ForItemType("vnd.farmmaps.itemtype.temporal")
 | 
			
		||||
@Injectable()
 | 
			
		||||
@@ -19,10 +18,15 @@ import {TemporalService} from '../../services/temporal.service';
 | 
			
		||||
  templateUrl: './selected-item-temporal.component.html',
 | 
			
		||||
  styleUrls: ['./selected-item-temporal.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SelectedItemTemporalComponent extends AbstractSelectedItemComponent {
 | 
			
		||||
export class SelectedItemTemporalComponent extends AbstractSelectedItemComponent implements OnDestroy {
 | 
			
		||||
  sub: Subscription;
 | 
			
		||||
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, location: Location, router: Router,public temporalService:TemporalService) {
 | 
			
		||||
    super(store, itemTypeService,location,router);
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, public itemService: ItemService, itemTypeService: ItemTypeService, location: Location, router: Router,public temporalService:TemporalService) {
 | 
			
		||||
    super(store, itemTypeService,itemService,location,router);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  ngOnDestroy(): void {
 | 
			
		||||
    if (this.sub) this.sub.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onLayerChanged(layerIndex: number) {
 | 
			
		||||
@@ -33,8 +37,6 @@ export class SelectedItemTemporalComponent extends AbstractSelectedItemComponent
 | 
			
		||||
    return  (this.itemLayer as ITemporalItemLayer)?.selectedItemLayer
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  handleNextTemporal(event:MouseEvent) {
 | 
			
		||||
    this.store.dispatch(new mapActions.NextTemporal());
 | 
			
		||||
    event.preventDefault();    
 | 
			
		||||
@@ -61,4 +63,13 @@ export class SelectedItemTemporalComponent extends AbstractSelectedItemComponent
 | 
			
		||||
    this.router.navigate(['/viewer', 'temporal', 'item', item.parentCode, new Date(Date.parse(item.dataDate)).getUTCFullYear()]);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  download(event:MouseEvent,item:IItem,layers:any,layerIndex:number) {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
    const itemLink : IItemLinkType = {itemcode:item.code,query:`layer=${this.layer(layers,layerIndex).name}`,pathsuffix:"download", validminutes:10}
 | 
			
		||||
    this.sub = this.itemService.getItemLink(itemLink).subscribe((itemLinkUrl:IUrlType) => {  
 | 
			
		||||
       window.location.href = itemLinkUrl.url;       
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ import {Component, Injectable, Input, Directive} from '@angular/core';
 | 
			
		||||
import {Location} from '@angular/common';
 | 
			
		||||
import {Store} from '@ngrx/store';
 | 
			
		||||
import * as mapReducers from '../../reducers/map.reducer';
 | 
			
		||||
import {AppConfig, commonReducers, IItem, ItemTypeService} from '@farmmaps/common';
 | 
			
		||||
import {AppConfig, commonReducers, IItem, ItemService, ItemTypeService} from '@farmmaps/common';
 | 
			
		||||
import * as mapActions from '../../actions/map.actions';
 | 
			
		||||
import {Router} from '@angular/router';
 | 
			
		||||
import { IItemLayer } from '../../models/item.layer';
 | 
			
		||||
@@ -15,7 +15,7 @@ export abstract class AbstractSelectedItemComponent {
 | 
			
		||||
  @Input() parentItem: IItem;
 | 
			
		||||
  @Input() itemLayer: IItemLayer;
 | 
			
		||||
  @Input() overlayLayers: Array<IItemLayer>;
 | 
			
		||||
  constructor(public store: Store<mapReducers.State | commonReducers.State>, public itemTypeService: ItemTypeService, private location: Location, public router: Router) {
 | 
			
		||||
  constructor(public store: Store<mapReducers.State | commonReducers.State>, public itemTypeService: ItemTypeService, public itemService: ItemService, private location: Location, public router: Router) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOnView(item: IItem) {
 | 
			
		||||
@@ -37,6 +37,11 @@ export abstract class AbstractSelectedItemComponent {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOnDelete(item: IItem) {
 | 
			
		||||
    this.itemService.deleteItem(item.code);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleAddAsLayer(item: IItem,layerIndex = -1) {
 | 
			
		||||
    this.store.dispatch(new mapActions.AddLayer(item,layerIndex));
 | 
			
		||||
    return false;
 | 
			
		||||
@@ -76,8 +81,8 @@ export abstract class AbstractSelectedItemComponent {
 | 
			
		||||
})
 | 
			
		||||
export class SelectedItemComponent extends AbstractSelectedItemComponent {
 | 
			
		||||
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, location: Location, router: Router, public config:AppConfig) {
 | 
			
		||||
    super(store, itemTypeService,location,router);
 | 
			
		||||
  constructor(store: Store<mapReducers.State | commonReducers.State>, itemTypeService: ItemTypeService, itemService: ItemService, location: Location, router: Router, public config:AppConfig) {
 | 
			
		||||
    super(store, itemTypeService,itemService,location,router);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getThumbnailUrl(item:IItem):string {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import { ILayervalue } from '../models/layer.value';
 | 
			
		||||
import * as mapActions from '../actions/map.actions';
 | 
			
		||||
import {commonActions} from '@farmmaps/common';
 | 
			
		||||
import { createSelector, createFeatureSelector } from '@ngrx/store';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import {Feature} from 'ol';
 | 
			
		||||
import {Geometry} from 'ol/geom';
 | 
			
		||||
@@ -47,6 +48,7 @@ export interface State {
 | 
			
		||||
  query:IQuery,
 | 
			
		||||
  parentCode: string,
 | 
			
		||||
  features: Array<Feature<Geometry>>,
 | 
			
		||||
  featuresBackup: Array<Feature<Geometry>>,
 | 
			
		||||
  panelVisible: boolean,
 | 
			
		||||
  panelCollapsed: boolean,
 | 
			
		||||
  panelExtraWide: boolean,
 | 
			
		||||
@@ -93,6 +95,7 @@ export const initialState: State = {
 | 
			
		||||
  query: null,
 | 
			
		||||
  parentCode: null,
 | 
			
		||||
  features: [],
 | 
			
		||||
  featuresBackup: [],
 | 
			
		||||
  panelVisible: false,
 | 
			
		||||
  panelCollapsed: false,
 | 
			
		||||
  panelExtraWide: false,
 | 
			
		||||
@@ -156,13 +159,15 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
      const a = action as mapActions.StartSearchSuccess;
 | 
			
		||||
      return tassign(state, {
 | 
			
		||||
        features: a.features,
 | 
			
		||||
        featuresBackup: [],
 | 
			
		||||
        inSearch:false
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    case mapActions.SETFEATURES: {
 | 
			
		||||
      const a = action as mapActions.SetFeatures;
 | 
			
		||||
      return tassign(state, {
 | 
			
		||||
        features: a.features
 | 
			
		||||
        features: a.features,
 | 
			
		||||
        featuresBackup: []
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    case mapActions.SELECTFEATURE: {
 | 
			
		||||
@@ -180,6 +185,7 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
        selectedItemLayer: null,
 | 
			
		||||
        showDataLayerSlide: false,
 | 
			
		||||
        features:[],
 | 
			
		||||
        featuresBackup: [],
 | 
			
		||||
        inSearch:inSearch
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
@@ -296,6 +302,7 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
      return tassign(state, {
 | 
			
		||||
        selectedItem: null,
 | 
			
		||||
        features:[],
 | 
			
		||||
        featuresBackup: [],
 | 
			
		||||
        selectedItemLayer:null,
 | 
			
		||||
        searchCollapsed: !panelVisible,
 | 
			
		||||
        panelVisible: panelVisible,
 | 
			
		||||
@@ -332,7 +339,8 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
        extent: a.feature.getGeometry().getExtent(),
 | 
			
		||||
        searchCollapsed: false,
 | 
			
		||||
        clearEnabled:true,
 | 
			
		||||
        features:features
 | 
			
		||||
        features:features,
 | 
			
		||||
        featuresBackup:[]
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    case mapActions.UPDATEFEATURESUCCESS: {
 | 
			
		||||
@@ -346,7 +354,7 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
          features.push(state.features[i]);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return tassign(state, { features: features });
 | 
			
		||||
      return tassign(state, { features: features, featuresBackup: [] });
 | 
			
		||||
    }
 | 
			
		||||
    case mapActions.EXPANDSEARCH: {
 | 
			
		||||
      return tassign(state, { searchCollapsed: false });
 | 
			
		||||
@@ -391,7 +399,7 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
      return tassign(state, {overlayLayers: [], selectedOverlayLayer: null});
 | 
			
		||||
    }
 | 
			
		||||
    case mapActions.CLEARFEATURES: {
 | 
			
		||||
      return tassign(state, {features: [], selectedFeature: null});
 | 
			
		||||
      return tassign(state, {features: [], featuresBackup: [], selectedFeature: null});
 | 
			
		||||
    }
 | 
			
		||||
    case mapActions.SETVISIBILITY: {
 | 
			
		||||
      const a = action as mapActions.SetVisibility;
 | 
			
		||||
@@ -509,6 +517,7 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
        searchCollapsed: true,
 | 
			
		||||
        searchMinified: false,
 | 
			
		||||
        features: [],
 | 
			
		||||
        featuresBackup: [],
 | 
			
		||||
        query:initialState.query,
 | 
			
		||||
        showLayerSwitcher: false,
 | 
			
		||||
        extent: null,
 | 
			
		||||
@@ -556,7 +565,8 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
          selectedItem: null,
 | 
			
		||||
          selectedItemLayer: null,
 | 
			
		||||
          showDataLayerSlide: false,
 | 
			
		||||
          features:[]
 | 
			
		||||
          features:[],
 | 
			
		||||
          featuresBackup:[]
 | 
			
		||||
         });
 | 
			
		||||
      }
 | 
			
		||||
      if(state.features.length>0)  {
 | 
			
		||||
@@ -569,7 +579,7 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
        if(index>=0) {
 | 
			
		||||
          const newFeatures = state.features.slice(0);
 | 
			
		||||
          newFeatures.splice(index,1);
 | 
			
		||||
          return tassign(state,{features:newFeatures});
 | 
			
		||||
          return tassign(state,{features:newFeatures, featuresBackup:[]});
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return state;
 | 
			
		||||
@@ -578,6 +588,17 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
 | 
			
		||||
      const a= action as mapActions.SetPanelExtraWide;
 | 
			
		||||
      return tassign(state,{panelExtraWide:a.panelExtraWide});
 | 
			
		||||
    }
 | 
			
		||||
    case mapActions.BACKUPFEATURES: {
 | 
			
		||||
      return tassign(state, {
 | 
			
		||||
        featuresBackup: _.cloneDeep(state.features)
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    case mapActions.RESTOREFEATURES: {
 | 
			
		||||
      return tassign(state, {
 | 
			
		||||
        features: _.cloneDeep(state.featuresBackup),
 | 
			
		||||
        featuresBackup: []
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    default: {
 | 
			
		||||
      return state;
 | 
			
		||||
    }
 | 
			
		||||
@@ -637,6 +658,8 @@ export const selectGetExtent = createSelector(selectMapState, getExtent);
 | 
			
		||||
export const selectGetViewExtent = createSelector(selectMapState, getViewExtent);
 | 
			
		||||
export const selectGetOverlayLayers = createSelector(selectMapState, getOverlayLayers);
 | 
			
		||||
export const selectGetBaseLayers = createSelector(selectMapState, getBaseLayers);
 | 
			
		||||
export const selectGetBaseMaps = createSelector(selectGetBaseLayers, (layers) => layers.filter(layer => layer.item.data.category === "baseMap"));
 | 
			
		||||
export const selectGetArealMaps = createSelector(selectGetBaseLayers, (layers) => layers.filter(layer => layer.item.data.category === "aerialPhoto").sort((a, b) => a.item.dataDate <= b.item.dataDate ? 1 : -1));
 | 
			
		||||
export const selectGetProjection = createSelector(selectMapState, getProjection);
 | 
			
		||||
export const selectGetSelectedBaseLayer = createSelector(selectMapState, getSelectedBaseLayer);
 | 
			
		||||
export const selectGetSelectedOverlayLayer = createSelector(selectMapState, getSelectedOverlayLayer);
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@
 | 
			
		||||
    "tslib": "^2.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "peerDependencies": {
 | 
			
		||||
    "@angular/common": "^18.2.3",
 | 
			
		||||
    "@angular/core":  "^18.2.3",
 | 
			
		||||
    "@angular/common": "18.2.3",
 | 
			
		||||
    "@angular/core":  "18.2.3",
 | 
			
		||||
    "cesium": "^1.97.0",
 | 
			
		||||
    "ol-cesium": ">=2.13.0"
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,9 @@
 | 
			
		||||
  },
 | 
			
		||||
  "peerDependencies": {
 | 
			
		||||
    "@ng-bootstrap/ng-bootstrap": "^17.0.1",
 | 
			
		||||
    "@angular/common": "^18.2.3",
 | 
			
		||||
    "@angular/core": "^18.2.3",
 | 
			
		||||
    "@angular/forms": "^18.2.3",
 | 
			
		||||
    "@angular/common": "18.2.3",
 | 
			
		||||
    "@angular/core": "18.2.3",
 | 
			
		||||
    "@angular/forms": "18.2.3",
 | 
			
		||||
    "@ngrx/effects": "^18.0.2",
 | 
			
		||||
    "@ngrx/router-store": "^18.0.2",
 | 
			
		||||
    "@ngrx/store": "^18.0.2",
 | 
			
		||||
 
 | 
			
		||||
@@ -71,6 +71,8 @@ export const TOGGLENOTIFICATIONMENU = '[AppCommon] ToggleNotificationMenu';
 | 
			
		||||
 | 
			
		||||
export const TOGGLEHELPMENU = '[AppCommon] ToggleHelpMenu';
 | 
			
		||||
 | 
			
		||||
export const TOGGLESETTINGMENU = '[AppCommon] ToggleSettingMenu';
 | 
			
		||||
 | 
			
		||||
export const SETMENUVISIBLE = '[AppCommon] SetMenuVisible';
 | 
			
		||||
 | 
			
		||||
export const ONLINE = '[AppCommon] Online';
 | 
			
		||||
@@ -81,6 +83,11 @@ export const SETPAGEMODE = '[AppCommon] SetPageMode';
 | 
			
		||||
 | 
			
		||||
export const SETUNREADNOTIFICATIONS = '[AppCommon] SetUnreadNotifications';
 | 
			
		||||
 | 
			
		||||
export const SWITCHLANGUAGE = '[AppCommon] SwitchLanguage';
 | 
			
		||||
 | 
			
		||||
export const SETSETTINGMENUBACKGROUNDCOLOR = '[AppCommon] SetSettingMenuBackgroundColor';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export class InitUser implements Action {
 | 
			
		||||
  readonly type = INITUSER;
 | 
			
		||||
 | 
			
		||||
@@ -332,6 +339,12 @@ export class ToggleHelpMenu implements Action {
 | 
			
		||||
  constructor() { }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class ToggleSettingMenu implements Action {
 | 
			
		||||
  readonly type = TOGGLESETTINGMENU;
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SetMenuVisible implements Action {
 | 
			
		||||
  readonly type = SETMENUVISIBLE;
 | 
			
		||||
 | 
			
		||||
@@ -363,6 +376,17 @@ export class SetUnreadNotifications implements Action {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
export class SwitchLanguage implements Action {
 | 
			
		||||
  readonly type = SWITCHLANGUAGE;
 | 
			
		||||
 | 
			
		||||
  constructor(public locale:string) { }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SetSettingMenuBackgroundColor implements Action {
 | 
			
		||||
  readonly type = SETSETTINGMENUBACKGROUNDCOLOR;
 | 
			
		||||
 | 
			
		||||
  constructor(public color:string) { }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Actions = OpenModal
 | 
			
		||||
  | InitRoot
 | 
			
		||||
@@ -408,7 +432,10 @@ export type Actions = OpenModal
 | 
			
		||||
  | ToggleAppMenu
 | 
			
		||||
  | ToggleNotificationMenu
 | 
			
		||||
  | ToggleHelpMenu
 | 
			
		||||
  | ToggleSettingMenu
 | 
			
		||||
  | NotificationEvent
 | 
			
		||||
  | SetUnreadNotifications;
 | 
			
		||||
  | SetUnreadNotifications
 | 
			
		||||
  | SwitchLanguage
 | 
			
		||||
  | SetSettingMenuBackgroundColor;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ import { SchemaService } from './services/schema.service';
 | 
			
		||||
import { FolderService } from './services/folder.service';
 | 
			
		||||
import { TimespanService } from './services/timespan.service';
 | 
			
		||||
import { ItemService } from './services/item.service';
 | 
			
		||||
import { TaskService } from './services/task.service';
 | 
			
		||||
import { AdminService } from './services/admin.service';
 | 
			
		||||
import { EventService } from './services/event.service';
 | 
			
		||||
import { TypeaheadService } from './services/typeahead.service';
 | 
			
		||||
@@ -44,6 +45,7 @@ export {
 | 
			
		||||
  ItemTypeService,
 | 
			
		||||
  TimespanService,
 | 
			
		||||
  ItemService,
 | 
			
		||||
  TaskService,
 | 
			
		||||
  AdminService,
 | 
			
		||||
  EventService,
 | 
			
		||||
  TypeaheadService,
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ import { HasClaimDirective } from './components/has-claim/has-claim.directive';
 | 
			
		||||
import { HasPackageDirective } from './components/has-package/has-package.directive';
 | 
			
		||||
import { HasRoleDirective } from './components/has-role/has-role.directive';
 | 
			
		||||
import { HelpMenuComponent } from './components/help-menu/help-menu.component';
 | 
			
		||||
import { SettingMenuComponent } from './components/setting-menu/setting-menu.component';
 | 
			
		||||
import { ItemLinkComponent } from './components/item-link/item-link.component';
 | 
			
		||||
import { MenuBackgroundComponent } from './components/menu-background/menu-background.component';
 | 
			
		||||
import { NotFoundComponent } from './components/not-found/not-found.component';
 | 
			
		||||
@@ -104,6 +105,7 @@ export {
 | 
			
		||||
        AppMenuComponent,
 | 
			
		||||
        NotificationMenuComponent,
 | 
			
		||||
        HelpMenuComponent,
 | 
			
		||||
        SettingMenuComponent,
 | 
			
		||||
        BackButtonComponent,
 | 
			
		||||
        ThumbnailComponent,
 | 
			
		||||
        EditImageModalComponent,
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@
 | 
			
		||||
    <fm-resumable-file-upload></fm-resumable-file-upload>
 | 
			
		||||
  </ng-container>  
 | 
			
		||||
  <div class="user-menu apponly">
 | 
			
		||||
    <fm-setting-menu [user]="user|async" [showMenu]="settingMenuVisible|async" [backgroundColor]="settingMenuBackgroundColor|async"></fm-setting-menu>
 | 
			
		||||
    <fm-help-menu [user]="user|async" [showMenu]="helpMenuVisible|async"></fm-help-menu>
 | 
			
		||||
    <fm-notification-menu [user]="user|async" [unread]="unreadNotifications|async" [showMenu]="notificationMenuVisible|async"></fm-notification-menu>
 | 
			
		||||
    <fm-app-menu [user]="user|async" [showMenu]="appMenuVisible|async"></fm-app-menu>
 | 
			
		||||
 
 | 
			
		||||
@@ -119,7 +119,7 @@ body { background: #f1f1f1; line-height: 18px; user-select:none;font-family: Lat
 | 
			
		||||
  max-height:0em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fm-help-menu,fm-app-menu,fm-user-menu,fm-notification-menu {
 | 
			
		||||
fm-help-menu,fm-app-menu,fm-user-menu,fm-notification-menu,fm-setting-menu {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  margin-left: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -45,10 +45,12 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
  public accountMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAccountMenuVisible);
 | 
			
		||||
  public appMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAppMenuVisible);
 | 
			
		||||
  public notificationMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetNotificationMenuVisible);
 | 
			
		||||
  public settingMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetSettingMenuVisible);
 | 
			
		||||
  public helpMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetHelpMenuVisible);
 | 
			
		||||
  public unreadNotifications: Observable<number> = this.store$.select(appReducers.SelectgetUnreadNotifications);
 | 
			
		||||
  public user: Observable<IUser> = this.store$.select(appReducers.SelectGetUser);
 | 
			
		||||
  public isPageMode: Observable<boolean> = this.store$.select(appReducers.SelectGetIsPageMode);
 | 
			
		||||
  public settingMenuBackgroundColor: Observable<string> = this.store$.select(appReducers.SelectGetSettingMenuBackgroundColor);
 | 
			
		||||
  @Input() showUploadProgress = true;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import {Component, HostListener} from '@angular/core';
 | 
			
		||||
import {Location} from "@angular/common";
 | 
			
		||||
import { DeviceService} from '../../services/device.service';
 | 
			
		||||
import { Location } from "@angular/common";
 | 
			
		||||
import { Component, EventEmitter, HostListener, Output } from '@angular/core';
 | 
			
		||||
import { DeviceService } from '../../services/device.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'fm-back-button',
 | 
			
		||||
@@ -8,16 +8,18 @@ import { DeviceService} from '../../services/device.service';
 | 
			
		||||
  styleUrls: ['./back-button.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class BackButtonComponent {
 | 
			
		||||
  @Output() beforeLocationBack = new EventEmitter();
 | 
			
		||||
 | 
			
		||||
  @HostListener('click')
 | 
			
		||||
  onBackClicked() {
 | 
			
		||||
    this.beforeLocationBack.emit();
 | 
			
		||||
    this.location.back();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(private location: Location,private deviceService:DeviceService) { }
 | 
			
		||||
  constructor(private location: Location,private deviceService:DeviceService) {    
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public show() {
 | 
			
		||||
    return !this.deviceService.IsMobile();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
        <i class="fal fa-image"></i>
 | 
			
		||||
        <div i18n>No image selected</div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <image-cropper #imageCropper
 | 
			
		||||
      <image-cropper #imageCropper output="base64" 
 | 
			
		||||
      [imageChangedEvent]="imageChangedEvent"
 | 
			
		||||
      [maintainAspectRatio]="true"
 | 
			
		||||
      [format]="imageType"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ div.resumable-file-upload {
 | 
			
		||||
  bottom: 0px;
 | 
			
		||||
  width: 300px;
 | 
			
		||||
  max-height: 250px;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
  /*z-index:2000 !important;*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
<div>
 | 
			
		||||
    <div (click)="toggle($event)" class="rounded-circle menu-button hidden" [style.background-color]="backgroundColor" [ngClass]="{'hidden':!user || noContent}">
 | 
			
		||||
        <span i18n-title title="Settings"><i class="fas fa-gear" aria-hidden="true"></i></span>
 | 
			
		||||
        <div class="menu hidden" [ngClass]="{'hidden':!showMenu}">                                     
 | 
			
		||||
            <router-outlet name="setting-menu" (activate)="activateRoute()" (deactivate)="deActivateRoute()"></router-outlet>            
 | 
			
		||||
       </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -0,0 +1,80 @@
 | 
			
		||||
.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: calc( 100vh - 4rem);
 | 
			
		||||
    //transition: max-height 0.2s;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    box-shadow: 0 0 20px rgba(0,0,0,.3);
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 3.4rem;
 | 
			
		||||
    right:0.5rem;
 | 
			
		||||
    left:0.5rem;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    border-radius: 0.25rem;
 | 
			
		||||
    padding: 0.5rem;
 | 
			
		||||
    z-index: 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:host-context(.fullscreen)  .menu  {
 | 
			
		||||
    top:4em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@media screen and (min-width: 44rem)  {
 | 
			
		||||
    .menu {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 3rem;
 | 
			
		||||
        right:0;
 | 
			
		||||
        left: unset;
 | 
			
		||||
        max-width: 30em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    :host-context(.fullscreen)  .menu  {
 | 
			
		||||
        top: 3rem;
 | 
			
		||||
    }
 | 
			
		||||
}    
 | 
			
		||||
 | 
			
		||||
.unread {
 | 
			
		||||
    display: block;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top:-0.5em;
 | 
			
		||||
    right: -0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.unread.hidden {
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
import { Input } from '@angular/core';
 | 
			
		||||
import { Component, OnInit } 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-setting-menu',
 | 
			
		||||
  templateUrl: './setting-menu.component.html',
 | 
			
		||||
  styleUrls: ['./setting-menu.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SettingMenuComponent implements OnInit {
 | 
			
		||||
  
 | 
			
		||||
  @Input() user:IUser;
 | 
			
		||||
  @Input() showMenu:boolean;
 | 
			
		||||
  @Input() backgroundColor:string;
 | 
			
		||||
  public noContent = true;
 | 
			
		||||
 | 
			
		||||
  constructor(private store: Store<appReducers.State>) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toggle(event:MouseEvent) {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
    this.store.dispatch(new appActions.ToggleSettingMenu());
 | 
			
		||||
  } 
 | 
			
		||||
 | 
			
		||||
  activateRoute() {
 | 
			
		||||
    this.noContent=false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  deActivateRoute() {
 | 
			
		||||
    this.noContent=true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { Injectable, Inject, LOCALE_ID } from '@angular/core';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { OAuthService,UserInfo } from 'angular-oauth2-oidc';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
@@ -16,6 +16,7 @@ import {StateSerializerService} from '../services/state-serializer.service';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AppCommonEffects {
 | 
			
		||||
  locale: string;
 | 
			
		||||
 | 
			
		||||
  login$ =  createEffect(() => this.actions$.pipe(
 | 
			
		||||
    ofType(appCommonActions.LOGIN),
 | 
			
		||||
@@ -47,11 +48,27 @@ export class AppCommonEffects {
 | 
			
		||||
    first(),
 | 
			
		||||
    switchMap((action) => {
 | 
			
		||||
        return zip(this.userService$.getCurrentUser(),from(this.oauthService$.loadUserProfile())).pipe(
 | 
			
		||||
        switchMap(([user,userInfo]) => {return of(new appCommonActions.InitUserSuccess(user,userInfo as UserInfo))} ),
 | 
			
		||||
        switchMap(([user,userInfo]) => {
 | 
			
		||||
          if (location.hostname === 'localhost' || user.language === undefined || user.language === this.locale) 
 | 
			
		||||
          {
 | 
			
		||||
            return of(new appCommonActions.InitUserSuccess(user,userInfo as UserInfo))
 | 
			
		||||
          }
 | 
			
		||||
          return of(new appCommonActions.SwitchLanguage(user.language))
 | 
			
		||||
        }),
 | 
			
		||||
        catchError(error => of(new appCommonActions.Fail(error))))
 | 
			
		||||
    }
 | 
			
		||||
  )));
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
  switchLanguage$ = createEffect(() => this.actions$.pipe(
 | 
			
		||||
    ofType(appCommonActions.SWITCHLANGUAGE),
 | 
			
		||||
    switchMap((action) => {
 | 
			
		||||
      const a = action as appCommonActions.SwitchLanguage;
 | 
			
		||||
      if (location.href.includes(`/${this.locale}/`)) {
 | 
			
		||||
        const newPath = location.href.replace(`/${this.locale}/`, `/${a.locale}/`);
 | 
			
		||||
        location.replace(newPath);
 | 
			
		||||
      }
 | 
			
		||||
      return of(undefined);
 | 
			
		||||
    })),{ dispatch:false});
 | 
			
		||||
 | 
			
		||||
  initUserPackages$ =  createEffect(() => this.actions$.pipe(
 | 
			
		||||
    ofType(appCommonActions.INITUSERPACKAGES),
 | 
			
		||||
@@ -134,15 +151,22 @@ export class AppCommonEffects {
 | 
			
		||||
      withLatestFrom(this.store$.select(appCommonReducers.selectGetItemTypes)),
 | 
			
		||||
      switchMap(([action, itemtypes]) => {
 | 
			
		||||
        const a = action as appCommonActions.EditItem;
 | 
			
		||||
        var editor =  "property";
 | 
			
		||||
        var editor = "property";
 | 
			
		||||
        if(a.item.itemType) {
 | 
			
		||||
          const itemType = itemtypes[a.item.itemType];
 | 
			
		||||
          var editor = itemType && itemType.editor ? itemType.editor : editor;  
 | 
			
		||||
        }
 | 
			
		||||
      this.router$.navigate(['/editor',editor,'item', a.item.code])
 | 
			
		||||
      return [];
 | 
			
		||||
    }
 | 
			
		||||
  )));
 | 
			
		||||
        if (editor == 'croppingscheme') { 
 | 
			
		||||
          // Exeception: no 'item' in route
 | 
			
		||||
          this.router$.navigate(['/editor', editor, a.item.code])
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          this.router$.navigate(['/editor', editor, 'item', a.item.code])
 | 
			
		||||
        }
 | 
			
		||||
        return [];
 | 
			
		||||
      }
 | 
			
		||||
    )
 | 
			
		||||
  ));
 | 
			
		||||
 | 
			
		||||
  viewItem$ =  createEffect(() => this.actions$.pipe(
 | 
			
		||||
    ofType(appCommonActions.VIEWITEM),
 | 
			
		||||
@@ -201,7 +225,8 @@ export class AppCommonEffects {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  constructor(private actions$: Actions, private store$: Store<appCommonReducers.State>, private oauthService$: OAuthService, private itemService$: ItemService, private folderService$:FolderService, private userService$: UserService, private router$: Router, private stateSerializerService$:StateSerializerService) {
 | 
			
		||||
  constructor(private actions$: Actions, private store$: Store<appCommonReducers.State>, private oauthService$: OAuthService, private itemService$: ItemService, private folderService$:FolderService, private userService$: UserService, private router$: Router, private stateSerializerService$:StateSerializerService, @Inject(LOCALE_ID) locale: string) {
 | 
			
		||||
    this.locale = locale;
 | 
			
		||||
    store$.dispatch(new appCommonActions.LoadItemTypes());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -26,6 +26,7 @@ export class Item implements IItem {
 | 
			
		||||
  public data?:any;
 | 
			
		||||
  public isEditable?:boolean;
 | 
			
		||||
  public owner?: string;
 | 
			
		||||
  public fullPath?: string;
 | 
			
		||||
 | 
			
		||||
  constructor() {  
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
 | 
			
		||||
export interface IItemTask  {
 | 
			
		||||
  code?: string;
 | 
			
		||||
  workflowCode?: string;
 | 
			
		||||
  taskType?: string;
 | 
			
		||||
  attributes?: any;
 | 
			
		||||
  message?: string,
 | 
			
		||||
@@ -11,6 +12,7 @@ export interface IItemTask  {
 | 
			
		||||
 | 
			
		||||
export class ItemTask implements IItemTask {
 | 
			
		||||
  public code?:string;
 | 
			
		||||
  public workflowCode?: string;
 | 
			
		||||
  public taskType?: string;
 | 
			
		||||
  public attributes?: any;
 | 
			
		||||
  public message?: string;
 | 
			
		||||
@@ -18,6 +20,6 @@ export class ItemTask implements IItemTask {
 | 
			
		||||
  public started?: Date;
 | 
			
		||||
  public finished?: Date;
 | 
			
		||||
 | 
			
		||||
  constructor() {  
 | 
			
		||||
  constructor() {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,11 @@ export interface State {
 | 
			
		||||
  appMenuVisible: boolean,
 | 
			
		||||
  notificationMenuVisible: boolean,
 | 
			
		||||
  helpMenuVisible: boolean,
 | 
			
		||||
  settingMenuVisible: boolean,
 | 
			
		||||
  unreadNotifications: number,
 | 
			
		||||
  isOnline: boolean,
 | 
			
		||||
  isPageMode:boolean
 | 
			
		||||
  isPageMode:boolean,
 | 
			
		||||
  settingMenuBackgroundColor:string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const initialState: State = {
 | 
			
		||||
@@ -47,9 +49,11 @@ export const initialState: State = {
 | 
			
		||||
  appMenuVisible: false,
 | 
			
		||||
  notificationMenuVisible: false,
 | 
			
		||||
  helpMenuVisible: false,
 | 
			
		||||
  settingMenuVisible: false,
 | 
			
		||||
  unreadNotifications: 0,
 | 
			
		||||
  isOnline: true,
 | 
			
		||||
  isPageMode: true
 | 
			
		||||
  isPageMode: true,
 | 
			
		||||
  settingMenuBackgroundColor:'rgb(128, 128, 128)'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function reducer(state = initialState, action: appCommonActions.Actions ): State {
 | 
			
		||||
@@ -106,26 +110,29 @@ export function reducer(state = initialState, action: appCommonActions.Actions )
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.TOGGLEMENU: {
 | 
			
		||||
      return tassign(state, { menuVisible: !state.menuVisible,accountMenuVisible:!state.menuVisible?false:state.accountMenuVisible,appMenuVisible:!state.menuVisible?false:state.appMenuVisible,notificationMenuVisible:!state.menuVisible?false:state.notificationMenuVisible,helpMenuVisible:!state.menuVisible?false:state.helpMenuVisible });
 | 
			
		||||
      return tassign(state, { menuVisible: !state.menuVisible,accountMenuVisible:!state.menuVisible?false:state.accountMenuVisible,appMenuVisible:!state.menuVisible?false:state.appMenuVisible,notificationMenuVisible:!state.menuVisible?false:state.notificationMenuVisible,helpMenuVisible:!state.menuVisible?false:state.helpMenuVisible,settingMenuVisible:!state.menuVisible?false:state.settingMenuVisible });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.TOGGLEACCOUNTMENU: {
 | 
			
		||||
      return tassign(state, { accountMenuVisible: !state.accountMenuVisible,appMenuVisible:false,notificationMenuVisible:false,helpMenuVisible:false });
 | 
			
		||||
      return tassign(state, { accountMenuVisible: !state.accountMenuVisible,appMenuVisible:false,notificationMenuVisible:false,helpMenuVisible:false,settingMenuVisible:false });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.TOGGLEAPPMENU: {
 | 
			
		||||
      return tassign(state, { appMenuVisible: !state.appMenuVisible,accountMenuVisible:false,notificationMenuVisible:false,helpMenuVisible:false });
 | 
			
		||||
      return tassign(state, { appMenuVisible: !state.appMenuVisible,accountMenuVisible:false,notificationMenuVisible:false,helpMenuVisible:false,settingMenuVisible:false });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.TOGGLENOTIFICATIONMENU: {
 | 
			
		||||
      return tassign(state, { notificationMenuVisible : !state.notificationMenuVisible,accountMenuVisible:false,appMenuVisible:false,helpMenuVisible:false });
 | 
			
		||||
      return tassign(state, { notificationMenuVisible : !state.notificationMenuVisible,accountMenuVisible:false,appMenuVisible:false,helpMenuVisible:false,settingMenuVisible:false });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.TOGGLEHELPMENU: {
 | 
			
		||||
      return tassign(state, { helpMenuVisible : !state.helpMenuVisible,accountMenuVisible:false,appMenuVisible:false,notificationMenuVisible:false });
 | 
			
		||||
      return tassign(state, { helpMenuVisible : !state.helpMenuVisible,accountMenuVisible:false,appMenuVisible:false,notificationMenuVisible:false,settingMenuVisible:false });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.TOGGLESETTINGMENU: {
 | 
			
		||||
      return tassign(state, { settingMenuVisible : !state.settingMenuVisible,accountMenuVisible:false,appMenuVisible:false,notificationMenuVisible:false,helpMenuVisible:false });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.ESCAPE: {
 | 
			
		||||
      return tassign(state, { menuVisible: false,accountMenuVisible:false,appMenuVisible: false,notificationMenuVisible:false,helpMenuVisible:false });
 | 
			
		||||
      return tassign(state, { menuVisible: false,accountMenuVisible:false,appMenuVisible: false,notificationMenuVisible:false,helpMenuVisible:false,settingMenuVisible:false });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.SETMENUVISIBLE: {
 | 
			
		||||
      const a = action as appCommonActions.SetMenuVisible;
 | 
			
		||||
      return tassign(state, { menuVisible: a.visible,accountMenuVisible:a.visible?false:state.accountMenuVisible,appMenuVisible:a.visible?false:state.appMenuVisible,notificationMenuVisible:a.visible?false:state.notificationMenuVisible,helpMenuVisible:a.visible?false:state.helpMenuVisible });
 | 
			
		||||
      return tassign(state, { menuVisible: a.visible,accountMenuVisible:a.visible?false:state.accountMenuVisible,appMenuVisible:a.visible?false:state.appMenuVisible,notificationMenuVisible:a.visible?false:state.notificationMenuVisible,helpMenuVisible:a.visible?false:state.helpMenuVisible,settingMenuVisible:a.visible?false:state.settingMenuVisible });
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.INITUSERPACKAGESSUCCESS:{
 | 
			
		||||
      const a = action as appCommonActions.InitUserPackagesSuccess;
 | 
			
		||||
@@ -182,6 +189,10 @@ export function reducer(state = initialState, action: appCommonActions.Actions )
 | 
			
		||||
      const a = action as appCommonActions.SetUnreadNotifications;
 | 
			
		||||
      return tassign(state,{unreadNotifications:a.unread});
 | 
			
		||||
    }
 | 
			
		||||
    case appCommonActions.SETSETTINGMENUBACKGROUNDCOLOR: {
 | 
			
		||||
      const a = action as appCommonActions.SetSettingMenuBackgroundColor;
 | 
			
		||||
      return tassign(state,{settingMenuBackgroundColor:a.color});
 | 
			
		||||
    }    
 | 
			
		||||
    default: {
 | 
			
		||||
      return state;
 | 
			
		||||
    }
 | 
			
		||||
@@ -203,9 +214,11 @@ export const getAccountMenuVisible = (state: State) => state.accountMenuVisible;
 | 
			
		||||
export const getAppMenuVisible = (state: State) => state.appMenuVisible;
 | 
			
		||||
export const getNotificationMenuVisible = (state: State) => state.notificationMenuVisible;
 | 
			
		||||
export const getHelpMenuVisible = (state: State) => state.helpMenuVisible;
 | 
			
		||||
export const getSettingMenuVisible = (state: State) => state.settingMenuVisible;
 | 
			
		||||
export const getUnreadNotifications = (state: State) => state.unreadNotifications;
 | 
			
		||||
export const getIsOnline = (state: State) => state.isOnline;
 | 
			
		||||
export const getIsPageMode = (state: State) => state.isPageMode;
 | 
			
		||||
export const getSettingMenuBackgroundColor = (state: State) => state.settingMenuBackgroundColor;
 | 
			
		||||
 | 
			
		||||
export const selectAppCommonState = createFeatureSelector<State>(MODULE_NAME);
 | 
			
		||||
 | 
			
		||||
@@ -227,9 +240,9 @@ export const SelectGetAccountMenuVisible = createSelector(selectAppCommonState,g
 | 
			
		||||
export const SelectGetAppMenuVisible = createSelector(selectAppCommonState,getAppMenuVisible);
 | 
			
		||||
export const SelectGetNotificationMenuVisible = createSelector(selectAppCommonState,getNotificationMenuVisible);
 | 
			
		||||
export const SelectGetHelpMenuVisible = createSelector(selectAppCommonState,getHelpMenuVisible);
 | 
			
		||||
export const SelectGetSettingMenuVisible = createSelector(selectAppCommonState,getSettingMenuVisible);
 | 
			
		||||
export const SelectgetUnreadNotifications = createSelector(selectAppCommonState,getUnreadNotifications);
 | 
			
		||||
 | 
			
		||||
export const SelectGetIsOnline = createSelector(selectAppCommonState,getIsOnline);
 | 
			
		||||
export const SelectGetIsPageMode = createSelector(selectAppCommonState,getIsPageMode);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const SelectGetSettingMenuBackgroundColor= createSelector(selectAppCommonState,getSettingMenuBackgroundColor);
 | 
			
		||||
 
 | 
			
		||||
@@ -52,4 +52,20 @@ export class AdminService {
 | 
			
		||||
  postItemTask(item: IItem, task: IItemTask): Observable<IItemTask> {
 | 
			
		||||
    return this.httpClient.post<IItemTask>(`${this.ApiEndpoint()}/api/v1/admin/${item.code}/tasks`, task);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFileStorageOverview(): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/admin/filestorage/folderinfo/overview`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFileStorageInfo(user: string): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/admin/filestorage/folderinfo/${user}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFileStorageLog(): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/admin/filestorage/folderinfo/log`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  validateEmail(user: IUser) {
 | 
			
		||||
    return this.httpClient.post(`${this.ApiEndpoint()}/api/v1/admin/user/${user.code}/validateemail`, user);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,12 @@
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { map } from 'rxjs/operators';
 | 
			
		||||
import { IItemType } from '../models/item.type';
 | 
			
		||||
import { IItemLinkType } from '../models/itemlink.type';
 | 
			
		||||
import { IUrlType } from '../models/url.type';
 | 
			
		||||
import { IItem } from '../models/item';
 | 
			
		||||
import { IJsonline } from '../models/json-line';
 | 
			
		||||
import { IItemTask } from '../models/itemTask';
 | 
			
		||||
import { HttpClient, HttpParams, HttpHeaders } from "@angular/common/http";
 | 
			
		||||
import { AppConfig } from "../shared/app.config";
 | 
			
		||||
import {Injectable} from '@angular/core';
 | 
			
		||||
import {Observable} from 'rxjs';
 | 
			
		||||
import {IItemType} from '../models/item.type';
 | 
			
		||||
import {IItemLinkType} from '../models/itemlink.type';
 | 
			
		||||
import {IItem} from '../models/item';
 | 
			
		||||
import {IJsonline} from '../models/json-line';
 | 
			
		||||
import {IItemTask} from '../models/itemTask';
 | 
			
		||||
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
 | 
			
		||||
import {AppConfig} from '../shared/app.config';
 | 
			
		||||
import {ItemTypeService} from './itemtype.service';
 | 
			
		||||
import {IListItem} from '../models/list.item';
 | 
			
		||||
 | 
			
		||||
@@ -81,7 +79,8 @@ export class ItemService {
 | 
			
		||||
 | 
			
		||||
  getItemList(itemType?: string, dataFilter?: any, level?: number, atItemLocationItemCode?: string,
 | 
			
		||||
    indexed?: boolean, validToday?: boolean,tags?:string,crs?:string, startDate?: Date, endDate?: Date,
 | 
			
		||||
    skip?: number, take?: number, sourceTask?: string): Observable<IItem[]> {
 | 
			
		||||
    skip?: number, take?: number, sourceTask?: string, exactMatchStartOrEndDate?: boolean, owner?:string,
 | 
			
		||||
    includeFullpath?: boolean): Observable<IItem[]> {
 | 
			
		||||
    let params = new HttpParams();
 | 
			
		||||
    if(itemType)  params = params.append("it", itemType);
 | 
			
		||||
    if(dataFilter) params = params.append("df", JSON.stringify(dataFilter));
 | 
			
		||||
@@ -96,20 +95,29 @@ export class ItemService {
 | 
			
		||||
    if (sourceTask) params = params.append("sourceTask", sourceTask);
 | 
			
		||||
    if(skip) params = params.append("skip", skip);
 | 
			
		||||
    if(take) params = params.append("take", take);
 | 
			
		||||
    if(exactMatchStartOrEndDate !== undefined) params = params.append("exactMatchStartOrEndDate", exactMatchStartOrEndDate);
 | 
			
		||||
    if(owner) params = params.append("owner", owner);
 | 
			
		||||
    if(includeFullpath) params = params.append("includeFullpath",includeFullpath?"true":"false");
 | 
			
		||||
    return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/`, { params: params });
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  getItemListCount(itemType: string, startDate?: Date, endDate?: Date, sourceTask?: string): Observable<number> {
 | 
			
		||||
 | 
			
		||||
  getItemListCount(itemType: string, startDate?: Date, endDate?: Date, sourceTask?: string,
 | 
			
		||||
    indexed?: boolean, exactMatchStartOrEndDate?: boolean, owner?:string): Observable<number> {
 | 
			
		||||
    let params = new HttpParams();
 | 
			
		||||
    params = params.append("it", itemType);
 | 
			
		||||
    if (sourceTask) params = params.append("sourceTask", sourceTask);
 | 
			
		||||
    if (startDate) params = params.append("sDate", startDate.toISOString());
 | 
			
		||||
    if (endDate) params = params.append("eDate", endDate.toISOString());
 | 
			
		||||
    if(indexed) params = params.append("ind",indexed?"true":"false");
 | 
			
		||||
    if(exactMatchStartOrEndDate !== undefined) params = params.append("exactMatchStartOrEndDate", exactMatchStartOrEndDate);
 | 
			
		||||
    if(owner) params = params.append("owner", owner);
 | 
			
		||||
    return this.httpClient.get<number>(`${this.ApiEndpoint()}/api/v1/items/count`, { params: params });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getChildItemList(parentcode: string, itemType?: string, dataFilter?: any, level = 1, deep = true,
 | 
			
		||||
                   startDate?: Date, endDate?: Date, skip?: number, take?: number): Observable<IItem[]> {
 | 
			
		||||
                   startDate?: Date, endDate?: Date, skip?: number, take?: number,
 | 
			
		||||
                   exactMatchStartOrEndDate?: boolean, owner?:string, indexed?: boolean,
 | 
			
		||||
                  atItemLocationItemCode?: string): Observable<IItem[]> {
 | 
			
		||||
    let params = new HttpParams();
 | 
			
		||||
    if(itemType != null) {
 | 
			
		||||
      params = params.append("it", itemType);
 | 
			
		||||
@@ -121,13 +129,19 @@ export class ItemService {
 | 
			
		||||
    params = params.append("deep", deep.toString());
 | 
			
		||||
    if (startDate) params = params.append("sDate", startDate.toISOString());
 | 
			
		||||
    if (endDate) params = params.append("eDate", endDate.toISOString());
 | 
			
		||||
    if(exactMatchStartOrEndDate !== undefined) params = params.append("exactMatchStartOrEndDate", exactMatchStartOrEndDate);
 | 
			
		||||
    if(owner) params = params.append("owner", owner);
 | 
			
		||||
 | 
			
		||||
    if(skip) params = params.append("skip", skip);
 | 
			
		||||
    if(take) params = params.append("take", take);
 | 
			
		||||
    if(indexed) params = params.append("ind",indexed?"true":"false");
 | 
			
		||||
    if(atItemLocationItemCode) params = params.append("ail",atItemLocationItemCode);
 | 
			
		||||
    return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/${parentcode}/children`, { params: params });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getChildItemListCount(parentcode: string, itemType?: string,dataFilter?: any): Observable<number> {
 | 
			
		||||
  getChildItemListCount(parentcode: string, itemType?: string,dataFilter?: any,
 | 
			
		||||
                        startDate?: Date, endDate?: Date, exactMatchStartOrEndDate?: boolean, owner?:string,
 | 
			
		||||
                        indexed?: boolean): Observable<number> {
 | 
			
		||||
    let params = new HttpParams();
 | 
			
		||||
    if(itemType != null) {
 | 
			
		||||
      params = params.append("it", itemType);
 | 
			
		||||
@@ -135,6 +149,11 @@ export class ItemService {
 | 
			
		||||
    if (dataFilter != null) {
 | 
			
		||||
      params = params.append("df", JSON.stringify(dataFilter));
 | 
			
		||||
    }
 | 
			
		||||
    if (startDate) params = params.append("sDate", startDate.toISOString());
 | 
			
		||||
    if (endDate) params = params.append("eDate", endDate.toISOString());
 | 
			
		||||
    if(exactMatchStartOrEndDate !== undefined) params = params.append("exactMatchStartOrEndDate", exactMatchStartOrEndDate);
 | 
			
		||||
    if(owner) params = params.append("owner", owner);
 | 
			
		||||
    if(indexed) params = params.append("ind",indexed?"true":"false");
 | 
			
		||||
    return this.httpClient.get<number>(`${this.ApiEndpoint()}/api/v1/items/${parentcode}/children/count`, { params: params });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,37 +15,37 @@ export class ItemTypeService {
 | 
			
		||||
 | 
			
		||||
     getIcon(itemType: string) {
 | 
			
		||||
       let icon = "fal fa-file";
 | 
			
		||||
       if (this.itemTypes[itemType]) icon = this.itemTypes[itemType].icon;
 | 
			
		||||
       if (this.itemTypes && this.itemTypes[itemType]) icon = this.itemTypes[itemType].icon;
 | 
			
		||||
       return icon;
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
     getColor(itemType: string) {
 | 
			
		||||
       let color = "#000000";
 | 
			
		||||
       if (this.itemTypes[itemType]) color = this.itemTypes[itemType].iconColor;
 | 
			
		||||
       if (this.itemTypes && this.itemTypes[itemType]) color = this.itemTypes[itemType].iconColor;
 | 
			
		||||
       return color;
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
     getExtraAttributes(itemType: string) {
 | 
			
		||||
      let extraAttributes = null;
 | 
			
		||||
      if (this.itemTypes[itemType] && this.itemTypes[itemType].extraAttributes) extraAttributes = this.itemTypes[itemType].extraAttributes;
 | 
			
		||||
      if (this.itemTypes && this.itemTypes[itemType] && this.itemTypes[itemType]?.extraAttributes) extraAttributes = this.itemTypes[itemType]?.extraAttributes;
 | 
			
		||||
      return extraAttributes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getSchema(itemType: string): string {
 | 
			
		||||
      let schema = null;
 | 
			
		||||
      if (this.itemTypes[itemType]) schema = this.itemTypes[itemType].schema;
 | 
			
		||||
      if (this.itemTypes && this.itemTypes[itemType]) schema = this.itemTypes[itemType].schema;
 | 
			
		||||
      return schema;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
     hasViewer(item: IItem) {
 | 
			
		||||
        const itemType: string = item.itemType;
 | 
			
		||||
        if (this.itemTypes[itemType]) return this.itemTypes[itemType].viewer !== undefined;
 | 
			
		||||
        if (this.itemTypes && this.itemTypes[itemType]) return this.itemTypes[itemType].viewer !== undefined;
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      hasEditor(item: IItem) {
 | 
			
		||||
        const itemType: string = item.itemType;
 | 
			
		||||
        if (this.itemTypes[itemType]) return this.itemTypes[itemType].editor !== undefined;
 | 
			
		||||
        if (this.itemTypes && this.itemTypes[itemType]) return this.itemTypes[itemType].editor !== undefined;
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								projects/common/src/fm/services/task.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								projects/common/src/fm/services/task.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
import {Injectable} from '@angular/core';
 | 
			
		||||
import {HttpClient, HttpParams} from '@angular/common/http';
 | 
			
		||||
import {AppConfig} from '../shared/app.config';
 | 
			
		||||
 | 
			
		||||
@Injectable({
 | 
			
		||||
  providedIn: 'root',
 | 
			
		||||
})
 | 
			
		||||
export class TaskService {
 | 
			
		||||
  constructor(public httpClient: HttpClient, public appConfig: AppConfig) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ApiEndpoint() {
 | 
			
		||||
    return this.appConfig.getConfig("apiEndPoint");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTask(taskCode: string) {
 | 
			
		||||
    return this.httpClient.get<any>(`${this.appConfig.getConfig('apiEndPoint')}/api/v1/tasks/${taskCode}`)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTasks(workflowCode: string, itemCode: string = null, taskType: string = null, skip = 0, take = 25) {
 | 
			
		||||
    let params = new HttpParams();
 | 
			
		||||
 | 
			
		||||
    if (workflowCode) {
 | 
			
		||||
      params = params.append('workflowCode', workflowCode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (itemCode) {
 | 
			
		||||
      params = params.append('itemCode', itemCode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (taskType) {
 | 
			
		||||
      params = params.append('taskType', taskType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    params = params.append('skip', skip.toString());
 | 
			
		||||
    params = params.append('take', take.toString());
 | 
			
		||||
    return this.httpClient.get<any>(`${this.appConfig.getConfig('apiEndPoint')}/api/v1/tasks`,
 | 
			
		||||
      {params: params})
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -31,8 +31,8 @@
 | 
			
		||||
    "tslib": "^2.3.0"
 | 
			
		||||
  },
 | 
			
		||||
  "peerDependencies": {
 | 
			
		||||
    "@angular/common": "^18.2.3",
 | 
			
		||||
    "@angular/core": "^18.2.3",
 | 
			
		||||
    "@angular/common": "18.2.3",
 | 
			
		||||
    "@angular/core": "18.2.3",
 | 
			
		||||
    "ol": "^8.2.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ const routes = [
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    canActivate: [NavBarGuard],
 | 
			
		||||
    //canActivate: [NavBarGuard],
 | 
			
		||||
    component: LandingpageComponent
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
@@ -43,6 +43,11 @@ const routes = [
 | 
			
		||||
    component: TestComponent,
 | 
			
		||||
    outlet: 'help-menu'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: TestComponent,
 | 
			
		||||
    outlet: 'setting-menu'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: LogoComponent,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user