Compare commits
59 Commits
feature/Mi
...
31d01c75c5
Author | SHA1 | Date | |
---|---|---|---|
|
31d01c75c5 | ||
|
0da8d3d46d | ||
|
60761e9f4a | ||
|
ec9684b826 | ||
|
1073044f31 | ||
|
81126974f5 | ||
06f443a503 | |||
eb560aaf33 | |||
|
464b82bfb9 | ||
|
1c75fb6f71 | ||
|
5f5d8a9712 | ||
|
dc329a0e29 | ||
|
15a09e4b05 | ||
94f973406e | |||
6404e45d66 | |||
c0f689331e | |||
0f5a5251db | |||
3352bfd805 | |||
|
60ed2afaa4 | ||
|
9ac534c171 | ||
|
cecbdb2ded | ||
|
1092d5dcaf | ||
|
4af6b2937c | ||
263fb6c3d4 | |||
|
09fa8b4f1f | ||
|
214dc3ffa1 | ||
|
fad04744cf | ||
|
033b74517f | ||
|
0b7564e874 | ||
|
0d247e6416 | ||
|
b92cc7bc09 | ||
|
eba18b0235 | ||
|
69f8184dfe | ||
|
31c1570ffb | ||
|
fe2650c4fd | ||
|
f89209c555 | ||
|
b3d0a6f0c7 | ||
|
6bd1726fc9 | ||
|
b0ff54d157 | ||
|
277dc7051e | ||
|
ace4a6b364 | ||
|
146514d386 | ||
|
1187ee9fd6 | ||
4527276254 | |||
|
6f52302875 | ||
|
cbe27c2add | ||
|
cd156ab1bc | ||
|
f9d0e2aee0 | ||
|
253b3d3c90 | ||
|
28d4adc571 | ||
|
925af1e645 | ||
|
4130e0a796 | ||
|
01933b1602 | ||
0482aa7124 | |||
75015f6d22 | |||
aa3707aa56 | |||
|
ff06b419f2 | ||
|
c1c0bd2596 | ||
|
978cbdabfc |
23
package-lock.json
generated
23
package-lock.json
generated
@@ -2692,14 +2692,14 @@
|
||||
}
|
||||
},
|
||||
"@farmmaps/common": {
|
||||
"version": "0.0.1-prerelease.267",
|
||||
"resolved": "https://repository.akkerweb.nl/repository/npm-group/@farmmaps/common/-/common-0.0.1-prerelease.267.tgz",
|
||||
"integrity": "sha512-U2D6IhxIzpZVtExnRHSP8oNyva9eYCGnZEBy7jWFCY83X4R54w/+PxCB8sK8STf14IJFJcmaSXpHc7Wyd7GrbA=="
|
||||
"version": "0.0.1-prerelease.325",
|
||||
"resolved": "https://repository.akkerweb.nl/repository/npm-group/@farmmaps/common/-/common-0.0.1-prerelease.325.tgz",
|
||||
"integrity": "sha512-taXTcyYXHqkSZfKCKr9Oqp/eXA15NY3ryIBZ3W3nV43VvzPEQHQJSiMt8uSR1/Xwt7Vim0rTjaiVF2kS0iuz9g=="
|
||||
},
|
||||
"@farmmaps/common-map": {
|
||||
"version": "0.0.1-prerelease.267",
|
||||
"resolved": "https://repository.akkerweb.nl/repository/npm-group/@farmmaps/common-map/-/common-map-0.0.1-prerelease.267.tgz",
|
||||
"integrity": "sha512-lZG9abbuVNtFNPKLddYfBRD6qhc6fMslL4wTIKjX8P7yfBM6/W5FAlkcQEJqcTj9k/0fzRlzzKQ2dJouGkctcQ=="
|
||||
"version": "0.0.1-prerelease.325",
|
||||
"resolved": "https://repository.akkerweb.nl/repository/npm-group/@farmmaps/common-map/-/common-map-0.0.1-prerelease.325.tgz",
|
||||
"integrity": "sha512-T33qDcusnxKab8hlTxgcQEfANPDag+Ys1+32UvPwkVlk7Gfa5sm0Xw6on70epBOINHMfvbsVpm3dV/lIdgZHhA=="
|
||||
},
|
||||
"@istanbuljs/schema": {
|
||||
"version": "0.1.2",
|
||||
@@ -9669,6 +9669,11 @@
|
||||
"deepmerge": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"ngx-bootstrap": {
|
||||
"version": "5.6.1",
|
||||
"resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-5.6.1.tgz",
|
||||
"integrity": "sha512-8fDs3VaaWgKpupakPKS0QaUc+1E/JMBGJDxUUODjyIkLtFr1A8vH4cjXiV3AfrPvhK27GH0oyTPyKWKcCjEtVg=="
|
||||
},
|
||||
"ngx-openlayers": {
|
||||
"version": "1.0.0-next.13",
|
||||
"resolved": "https://registry.npmjs.org/ngx-openlayers/-/ngx-openlayers-1.0.0-next.13.tgz",
|
||||
@@ -9678,9 +9683,9 @@
|
||||
}
|
||||
},
|
||||
"ngx-uploadx": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/ngx-uploadx/-/ngx-uploadx-3.3.4.tgz",
|
||||
"integrity": "sha512-kWe6HLPQQDU/5W6UlFb8btrdQfzxKAmGUALFYPLzLRNAYmUnw0Tqf5ZllI0CCriavExqmUHzfG6zQ7fme+reTg==",
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/ngx-uploadx/-/ngx-uploadx-3.5.1.tgz",
|
||||
"integrity": "sha512-G9JXAQjlwmocaJFHgxmUowFX6DrYM1kP0oMdEWErX5fYuG8gm1LCsUHeCZDZFRpGFQ/xp5mwAoS2/0H22DCr7w==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
|
13
package.json
13
package.json
@@ -19,26 +19,27 @@
|
||||
"@angular/platform-browser": "~9.1.0",
|
||||
"@angular/platform-browser-dynamic": "~9.1.0",
|
||||
"@angular/router": "~9.1.0",
|
||||
"@farmmaps/common": ">=0.0.1-prerelease.325 <0.0.1",
|
||||
"@farmmaps/common-map": ">=0.0.1-prerelease.325 <0.0.1",
|
||||
"@microsoft/signalr": "^3.1.3",
|
||||
"@farmmaps/common": ">=0.0.1-prerelease.267 <0.0.1",
|
||||
"@farmmaps/common-map": ">=0.0.1-prerelease.267 <0.0.1",
|
||||
"@ng-bootstrap/ng-bootstrap": "^6.0",
|
||||
"@ngrx/effects": "^9.0",
|
||||
"@ngrx/router-store": "^9.0",
|
||||
"@ngrx/store": "^9.0",
|
||||
"ngx-uploadx": "^3.3.4",
|
||||
"angular-oauth2-oidc": "^9.1",
|
||||
"bootstrap": "^4.4.1",
|
||||
"core-js": "^2.6.11",
|
||||
"font-awesome": "^4.7.0",
|
||||
"ngrx-store-localstorage": "^9.0",
|
||||
"ngx-bootstrap": "^5.6.1",
|
||||
"ngx-openlayers": "1.0.0-next.13",
|
||||
"ngx-uploadx": "^3.5.1",
|
||||
"ol": "6.1.1",
|
||||
"resumablejs": "^1.1.0",
|
||||
"rxjs": "^6.5.4",
|
||||
"tassign": "^1.0.0",
|
||||
"tslib": "^1.10.0",
|
||||
"zone.js": "~0.10.2",
|
||||
"ngx-openlayers": "1.0.0-next.13",
|
||||
"ol": "6.1.1"
|
||||
"zone.js": "~0.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.901.0",
|
||||
|
79
projects/common-map/package-lock.json
generated
79
projects/common-map/package-lock.json
generated
@@ -1,82 +1,5 @@
|
||||
{
|
||||
"name": "@farmmaps/common-map",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@openlayers/pepjs": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@openlayers/pepjs/-/pepjs-0.5.3.tgz",
|
||||
"integrity": "sha512-Bgvi5c14BS0FJWyYWWFstNEnXsB30nK8Jt8hkAAdqr7E0gDdBBWVDglF3Ub19wTxvgJ/CVHyTY6VuCtnyRzglg=="
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
|
||||
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
|
||||
},
|
||||
"ngx-openlayers": {
|
||||
"version": "1.0.0-next.13",
|
||||
"resolved": "https://registry.npmjs.org/ngx-openlayers/-/ngx-openlayers-1.0.0-next.13.tgz",
|
||||
"integrity": "sha512-6y724s5JV6n1oxEhryxP3wcbwzpierj9RLiMLXInfKOG3l5IO1AtPNkeK9+mKctVDUVm5URIfzzZH02Ld+bvSQ==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"ol": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ol/-/ol-6.1.1.tgz",
|
||||
"integrity": "sha512-0dL3i3eJqgOpqIjDKEY3grkeQnjAYfV5L/JCxhOu4SxiaizRwFrFgeas6LILRoxKa03jhQFbut2r2bbgcLGQeA==",
|
||||
"requires": {
|
||||
"@openlayers/pepjs": "^0.5.3",
|
||||
"pbf": "3.2.1",
|
||||
"pixelworks": "1.1.0",
|
||||
"rbush": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"pbf": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz",
|
||||
"integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==",
|
||||
"requires": {
|
||||
"ieee754": "^1.1.12",
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"pixelworks": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pixelworks/-/pixelworks-1.1.0.tgz",
|
||||
"integrity": "sha1-Hwla1I3Ki/ihyCWOAJIDGkTyLKU="
|
||||
},
|
||||
"protocol-buffers-schema": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz",
|
||||
"integrity": "sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA=="
|
||||
},
|
||||
"quickselect": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
|
||||
"integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
|
||||
},
|
||||
"rbush": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
|
||||
"integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
|
||||
"requires": {
|
||||
"quickselect": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"resolve-protobuf-schema": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
|
||||
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
|
||||
"requires": {
|
||||
"protocol-buffers-schema": "^3.3.1"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
|
||||
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
|
||||
}
|
||||
}
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@
|
||||
"@ngrx/router-store": "^9.0",
|
||||
"@ngrx/store": "^9.0",
|
||||
"tassign": "^1.0.0",
|
||||
"@farmmaps/common": ">=0.0.1-prerelease.265 <0.0.1",
|
||||
"@farmmaps/common": ">=0.0.1-prerelease.308 <0.0.1",
|
||||
"ngx-openlayers": "1.0.0-next.13",
|
||||
"ol": "6.1.1"
|
||||
}
|
||||
|
@@ -105,7 +105,7 @@ export class SelectItem implements Action {
|
||||
export class SelectItemSuccess implements Action {
|
||||
readonly type = SELECTITEMSUCCESS;
|
||||
|
||||
constructor(public item: IItem) { }
|
||||
constructor(public item: IItem, public parentItem: IItem) { }
|
||||
}
|
||||
|
||||
export class SelectTemporalItemsSuccess implements Action {
|
||||
|
@@ -64,6 +64,7 @@ import { WidgetStatusComponent } from './components/widget-status/widget-status.
|
||||
import { ForChild} from './components/for-item/for-child.decorator';
|
||||
import {ForItemType } from './components/for-item/for-itemtype.decorator';
|
||||
import { ForSourceTask} from './components/for-item/for-sourcetask.decorator';
|
||||
import { ForPackage } from './components/for-item/for-package.decorator';
|
||||
import { PanToLocation} from './components/aol/pan-to-location/pan-to-location.component';
|
||||
import {LayerSwitcher} from './components/layer-switcher/layer-switcher.component';
|
||||
|
||||
@@ -143,7 +144,8 @@ export {
|
||||
IPeriodState,
|
||||
ForChild,
|
||||
ForItemType,
|
||||
ForSourceTask
|
||||
ForSourceTask,
|
||||
ForPackage
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
|
@@ -89,13 +89,13 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange
|
||||
var layerIndex = -1;
|
||||
var layer: Layer = null;
|
||||
layerIndex = itemLayer.layerIndex != -1 ? itemLayer.layerIndex : item.data.layers[0].index;
|
||||
let source = new XYZ({ maxZoom: 19, minZoom: 1, url: `${this._apiEndPoint}/api/v1/items/${item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${item.updated.getTime()}` });
|
||||
let source = new XYZ({ maxZoom: 19, minZoom: 1, url: `${this._apiEndPoint}/api/v1/items/${item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${Date.parse(item.updated)}` });
|
||||
layer = new Tile({ source: source });
|
||||
var data = item.data;
|
||||
var l = (data && data.layers && data.layers.length > 0) ? data.layers[0] : null;
|
||||
if (l && l.rendering && l.rendering.renderoutputType == "Tiles") {
|
||||
var rt = l.rendering as IRenderoutputTiles;
|
||||
let source = new XYZ({ maxZoom: rt.maxzoom, minZoom: rt.minzoom, url: `${this._apiEndPoint}/api/v1/items/${item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${item.updated.getTime()}` });
|
||||
let source = new XYZ({ maxZoom: rt.maxzoom, minZoom: rt.minzoom, url: `${this._apiEndPoint}/api/v1/items/${item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${Date.parse(item.updated)}` });
|
||||
layer = new Tile({ source: source });
|
||||
}
|
||||
if (l && l.rendering && l.rendering.renderoutputType == "Image") {
|
||||
@@ -105,7 +105,7 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange
|
||||
units: 'pixels',
|
||||
extent: ri.extent
|
||||
});
|
||||
let source = new ImageStatic({ imageExtent: ri.extent, projection: projection, url: `${this._apiEndPoint}/api/v1/items/${item.code}/mapimage/${layerIndex}?v=${item.updated.getTime()}` });
|
||||
let source = new ImageStatic({ imageExtent: ri.extent, projection: projection, url: `${this._apiEndPoint}/api/v1/items/${item.code}/mapimage/${layerIndex}?v=${Date.parse(item.updated)}` });
|
||||
layer = new Image({ source: source });
|
||||
}
|
||||
return layer;
|
||||
@@ -125,7 +125,7 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange
|
||||
maxZoom: rt.maxzoom,
|
||||
minZoom: rt.minzoom,
|
||||
format: new MVT(),
|
||||
url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/{z}/{x}/{y}.pbf?v=${item.updated.getTime()}`
|
||||
url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/{z}/{x}/{y}.pbf?v=${Date.parse(item.updated)}`
|
||||
}),
|
||||
style: (feature) => {
|
||||
return this.getColorFromGradient(l, feature);
|
||||
@@ -137,7 +137,7 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange
|
||||
source: new XYZ({
|
||||
maxZoom: rt.maxzoom,
|
||||
minZoom: rt.minzoom,
|
||||
url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/image_tiles/${layerIndex}/{z}/{x}/{y}.png?v=${item.updated.getTime()}`
|
||||
url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/image_tiles/${layerIndex}/{z}/{x}/{y}.png?v=${Date.parse(item.updated)}`
|
||||
})
|
||||
});
|
||||
} else {
|
||||
|
@@ -2,7 +2,7 @@ import { Component, Input, OnInit, ComponentFactoryResolver, ViewChild, SimpleCh
|
||||
import { Feature } from 'ol';
|
||||
import { FeatureListComponent,AbstractFeatureListComponent } from '../feature-list/feature-list.component';
|
||||
import { WidgetHostDirective } from '../widget-host/widget-host.directive';
|
||||
import {IQueryState } from '@farmmaps/common';
|
||||
import {IQueryState,PackageService } from '@farmmaps/common';
|
||||
import * as mapReducers from '../../reducers/map.reducer';
|
||||
import * as mapActions from '../../actions/map.actions';
|
||||
import { Store } from '@ngrx/store';
|
||||
@@ -16,7 +16,7 @@ import { Observable } from 'rxjs';
|
||||
})
|
||||
export class FeatureListContainerComponent {
|
||||
|
||||
constructor(private store: Store<mapReducers.State>,private componentFactoryResolver: ComponentFactoryResolver, @Inject(AbstractFeatureListComponent) public featureLists: AbstractFeatureListComponent[] ) {
|
||||
constructor(private store: Store<mapReducers.State>,private componentFactoryResolver: ComponentFactoryResolver, @Inject(AbstractFeatureListComponent) public featureLists: AbstractFeatureListComponent[],private packageService:PackageService ) {
|
||||
}
|
||||
|
||||
@Input() features: Array<Feature>
|
||||
@@ -28,31 +28,45 @@ export class FeatureListContainerComponent {
|
||||
componentRef:any;
|
||||
|
||||
loadComponent(queryState:IQueryState) {
|
||||
var componentFactory: ComponentFactory<AbstractFeatureListComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListComponent); // default
|
||||
var selected = -1;
|
||||
for (var i = 0; i < this.featureLists.length; i++) {
|
||||
if (this.featureLists[i]['forItemType'] == queryState.itemType && this.featureLists[i]['forChild'] && queryState.parentCode && queryState.parentCode != "") {
|
||||
selected = i;
|
||||
break;
|
||||
} else if (this.featureLists[i]['forItemType'] == queryState.itemType) {
|
||||
selected = i;
|
||||
break;
|
||||
let componentFactory: ComponentFactory<AbstractFeatureListComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListComponent); // default
|
||||
let selected = -1;
|
||||
let maxMatches =0;
|
||||
let showItem = true;
|
||||
for (let i = 0; i < this.featureLists.length; i++) {
|
||||
let matches=0;
|
||||
let criteria=0;
|
||||
if (this.featureLists[i]['forItemType']) {
|
||||
criteria++;
|
||||
if( this.featureLists[i]['forItemType'].indexOf(queryState.itemType) >= 0) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
if(this.featureLists[i]['forChild'] ) {
|
||||
criteria++;
|
||||
if(queryState.parentCode && queryState.parentCode != "") {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
if(criteria == matches && matches > maxMatches) {
|
||||
selected=i;
|
||||
maxMatches = matches;
|
||||
}
|
||||
}
|
||||
if (selected >= 0) {
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.featureLists[i]['constructor'] as any);
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.featureLists[selected]['constructor'] as any);
|
||||
if (this.featureLists[selected]['collapseSearch'] === true) {
|
||||
this.store.dispatch(new mapActions.CollapseSearch());
|
||||
}
|
||||
}
|
||||
const viewContainerRef = this.widgetHost.viewContainerRef;
|
||||
viewContainerRef.clear();
|
||||
|
||||
if(showItem) {
|
||||
this.componentRef = viewContainerRef.createComponent(componentFactory);
|
||||
(<AbstractFeatureListComponent>this.componentRef.instance).features = null;
|
||||
(<AbstractFeatureListComponent>this.componentRef.instance).queryState = queryState;
|
||||
(<AbstractFeatureListComponent>this.componentRef.instance).selectedFeature = null;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.clickedFeature.subscribe((feature => {
|
||||
|
@@ -23,11 +23,27 @@ export class FeatureListFeatureContainerComponent {
|
||||
|
||||
loadComponent() {
|
||||
var componentFactory: ComponentFactory<AbstractFeatureListFeatureComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListFeatureComponent); // default
|
||||
for (var i = 0; i < this.featureLists.length; i++) {
|
||||
if (this.featureLists[i]['forItemType'] == this.feature.get("itemType")) {
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.featureLists[i]['constructor'] as any);
|
||||
|
||||
let selected = -1;
|
||||
let maxMatches =0;
|
||||
for (let i = 0; i < this.featureLists.length; i++) {
|
||||
let matches=0;
|
||||
let criteria=0;
|
||||
if (this.featureLists[i]['forItemType']) {
|
||||
criteria++;
|
||||
if(this.featureLists[i]['forItemType'].indexOf(this.feature.get("itemType")) >= 0) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
if(criteria == matches && matches > maxMatches) {
|
||||
selected=i;
|
||||
maxMatches = matches;
|
||||
}
|
||||
}
|
||||
if (selected >= 0) {
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.featureLists[selected]['constructor'] as any);
|
||||
}
|
||||
|
||||
const viewContainerRef = this.widgetHost.viewContainerRef;
|
||||
viewContainerRef.clear();
|
||||
|
||||
|
@@ -0,0 +1,5 @@
|
||||
export function ForPackage(packageCode: string) {
|
||||
return function (constructor:Function) {
|
||||
constructor.prototype.forPackage = packageCode;
|
||||
};
|
||||
}
|
@@ -23,15 +23,35 @@ export class ItemListItemContainerComponent {
|
||||
|
||||
loadComponent() {
|
||||
var componentFactory: ComponentFactory<AbstractItemListItemComponent> = this.componentFactoryResolver.resolveComponentFactory(ItemListItemComponent); // default
|
||||
for (var i = 0; i < this.itemComponentList.length; i++) {
|
||||
if (this.itemComponentList[i]['forItemType'] &&
|
||||
this.itemComponentList[i]['forItemType'].indexOf(this.item.itemType) >= 0 &&
|
||||
this.itemComponentList[i]['forSourceTask'] &&
|
||||
this.itemComponentList[i]['forSourceTask'].indexOf(this.item.sourceTask) >= 0 )
|
||||
{
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.itemComponentList[i]['constructor'] as any);
|
||||
|
||||
let selected = -1;
|
||||
let maxMatches =0;
|
||||
let showItem = true;
|
||||
for (let i = 0; i < this.itemComponentList.length; i++) {
|
||||
let matches=0;
|
||||
let criteria=0;
|
||||
if (this.itemComponentList[i]['forItemType']) {
|
||||
criteria++;
|
||||
if(this.itemComponentList[i]['forItemType'].indexOf(this.item.itemType) >= 0) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
if (this.itemComponentList[i]['forSourceTask']) {
|
||||
criteria++;
|
||||
if(this.itemComponentList[i]['forSourceTask'].indexOf(this.item.sourceTask) >= 0) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
if(criteria == matches && matches > maxMatches) {
|
||||
selected=i;
|
||||
maxMatches = matches;
|
||||
}
|
||||
}
|
||||
if (selected >= 0) {
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.itemComponentList[selected]['constructor'] as any);
|
||||
}
|
||||
|
||||
const viewContainerRef = this.widgetHost.viewContainerRef;
|
||||
viewContainerRef.clear();
|
||||
|
||||
|
@@ -36,10 +36,12 @@ export class LayerSwitcher implements OnInit,OnChanges{
|
||||
|
||||
|
||||
handleClick(event:Event) {
|
||||
event.stopPropagation();
|
||||
this.store.dispatch(new mapActions.ShowLayerSwitcher(true));
|
||||
}
|
||||
|
||||
close(event:Event) {
|
||||
event.stopPropagation();
|
||||
this.store.dispatch(new mapActions.ShowLayerSwitcher(false));
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<table class="container" *ngIf="showLegend()">
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<td colspan="3">
|
||||
<div class="title">
|
||||
<h4 *ngIf="showTitle">{{layer.name}}</h4>
|
||||
<b *ngIf="layer.unit">({{layer.unit}})</b>
|
||||
|
@@ -12,6 +12,7 @@
|
||||
panelCollapsed:panelCollapsed$|async,
|
||||
searchMinified:searchMinified$|async,
|
||||
selectedItem:selectedItem$|async,
|
||||
parentItem:parentItem$|async,
|
||||
queryState:queryState$|async,
|
||||
searchCollapsed:searchCollapsed$|async,
|
||||
clearEnabled:clearEnabled$|async,
|
||||
@@ -57,7 +58,7 @@
|
||||
</div>
|
||||
|
||||
<div *ngIf="state.selectedItem;let item">
|
||||
<fm-map-selected-item-container [item]="item" [itemLayer]="state.selectedItemLayer" [overlayLayers]="state.overlayLayers"></fm-map-selected-item-container>
|
||||
<fm-map-selected-item-container [item]="item" [parentItem]="state.parentItem" [itemLayer]="state.selectedItemLayer" [overlayLayers]="state.overlayLayers"></fm-map-selected-item-container>
|
||||
</div>
|
||||
<div *ngIf="state.features.length == 0" class="no-results m-2">
|
||||
<div *ngIf="state.queryState.query">Cannot find <span>{{state.queryState?.query}}</span></div>
|
||||
|
@@ -64,6 +64,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
|
||||
public selectedFeature$: Observable<Feature> = this.store.select(mapReducers.selectGetSelectedFeature);
|
||||
public clickedFeature: Subject<Feature> = new Subject<Feature>();
|
||||
public selectedItem$: Observable<IItem> = this.store.select(mapReducers.selectGetSelectedItem);
|
||||
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,setStateCount:number}> = this.store.select(mapReducers.selectGetState);
|
||||
public period$: Observable<IPeriodState> = this.store.select(mapReducers.selectGetPeriod);
|
||||
@@ -356,7 +357,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
|
||||
handleOnMouseDown(event: MouseEvent) {
|
||||
event.stopPropagation();
|
||||
this.zone.run(() =>{
|
||||
this.store.dispatch(new mapActions.CollapseSearch());
|
||||
this.store.dispatch(new commonActions.CloseAll());
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -18,3 +18,8 @@
|
||||
.custom-day.faded {
|
||||
background-color: rgba(2, 117, 216, 0.5);
|
||||
}
|
||||
|
||||
ngb-datepicker {
|
||||
overflow: hidden;
|
||||
max-width: calc(100vw - 3em);
|
||||
}
|
@@ -16,6 +16,7 @@ export class SelectedItemContainerComponent {
|
||||
}
|
||||
|
||||
@Input() item: IItem;
|
||||
@Input() parentItem: IItem;
|
||||
@Input() itemLayer:IItemLayer;
|
||||
@Input() overlayLayers:Array<IItemLayer>;
|
||||
|
||||
@@ -23,27 +24,41 @@ export class SelectedItemContainerComponent {
|
||||
|
||||
loadComponent() {
|
||||
let componentFactory: ComponentFactory<AbstractSelectedItemComponent> = this.componentFactoryResolver.resolveComponentFactory(SelectedItemComponent); // default
|
||||
let firstComponentWithTypeAndTask = this.selectedItemComponents
|
||||
.find(value => value['forSourceTask'] == this.item.sourceTask &&
|
||||
value['forItemType'] == this.item.itemType
|
||||
);
|
||||
|
||||
if (firstComponentWithTypeAndTask) {
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(firstComponentWithTypeAndTask['constructor'] as any);
|
||||
} else {
|
||||
let firstComponentWithType = this.selectedItemComponents
|
||||
.find(value => value['forSourceTask'] == null &&
|
||||
value['forItemType'] == this.item.itemType);
|
||||
|
||||
if (firstComponentWithType) {
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(firstComponentWithType['constructor'] as any);
|
||||
let selected = -1;
|
||||
let maxMatches =0;
|
||||
let showItem = true;
|
||||
for (let i = 0; i < this.selectedItemComponents.length; i++) {
|
||||
let matches=0;
|
||||
let criteria=0;
|
||||
if (this.selectedItemComponents[i]['forItemType'] ) {
|
||||
criteria++;
|
||||
if(this.selectedItemComponents[i]['forItemType'].indexOf(this.item.itemType) >= 0) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
if (this.selectedItemComponents[i]['forSourceTask']) {
|
||||
criteria++;
|
||||
if( this.selectedItemComponents[i]['forSourceTask'].indexOf(this.item.sourceTask) >= 0) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
if(criteria==matches && matches > maxMatches) {
|
||||
selected=i;
|
||||
maxMatches = matches;
|
||||
}
|
||||
}
|
||||
if (selected >= 0) {
|
||||
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.selectedItemComponents[selected]['constructor'] as any);
|
||||
}
|
||||
|
||||
const viewContainerRef = this.widgetHost.viewContainerRef;
|
||||
viewContainerRef.clear();
|
||||
|
||||
const componentRef = viewContainerRef.createComponent(componentFactory);
|
||||
(<AbstractSelectedItemComponent>componentRef.instance).item = this.item;
|
||||
(<AbstractSelectedItemComponent>componentRef.instance).parentItem = this.parentItem;
|
||||
(<AbstractSelectedItemComponent>componentRef.instance).itemLayer = this.itemLayer;
|
||||
(<AbstractSelectedItemComponent>componentRef.instance).overlayLayers = this.overlayLayers;
|
||||
}
|
||||
|
@@ -7,9 +7,10 @@ import { commonReducers, ItemTypeService, IItem, Item, ItemService, FolderServic
|
||||
import { Router, ActivatedRoute, ParamMap, Event } from '@angular/router';
|
||||
import { ForItemType } from '../for-item/for-itemtype.decorator';
|
||||
import { AbstractSelectedItemComponent } from '../selected-item/selected-item.component';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Observable,of } from 'rxjs';
|
||||
import {GeoJSON} from 'ol/format';
|
||||
import {getArea} from 'ol/sphere';
|
||||
import { withLatestFrom,switchMap,combineLatest } from 'rxjs/operators';
|
||||
|
||||
|
||||
@ForItemType("vnd.farmmaps.itemtype.cropfield")
|
||||
@@ -38,6 +39,25 @@ export class SelectedItemCropfieldComponent extends AbstractSelectedItemComponen
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this. items = this.folderService$.getItems(this.item.code, 0, 1000);
|
||||
var childItems = this.folderService$.getItems(this.item.code, 0, 1000);
|
||||
var atLocationItems = this.itemService$.getItemList(null,null,null,this.item.code,true);
|
||||
this.items = childItems.pipe(
|
||||
combineLatest(atLocationItems),
|
||||
switchMap(([ci,ali]) => {
|
||||
let retVal:IListItem[] = [];
|
||||
let codes = {};
|
||||
ci.forEach((listItem) => {
|
||||
retVal.push(listItem);
|
||||
codes[listItem.code]=listItem;
|
||||
});
|
||||
ali.forEach((atlocationitem) => {
|
||||
let listItem = atlocationitem as IListItem;
|
||||
let allowedItemTypes = "vnd.farmmaps.itemtype.device.senml"; // this is a hack
|
||||
if(!codes[listItem.code] && allowedItemTypes.indexOf(listItem.itemType) >= 0) {
|
||||
retVal.push(listItem);
|
||||
}
|
||||
});
|
||||
return of(retVal);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
<div class="card-body">
|
||||
<div class="mb-2"><a href="#" (click)="handleBackToList($event)" i18n>Back</a></div>
|
||||
<div class="card menu-card">
|
||||
<h2 *ngIf="parentItem">{{parentItem.name}}</h2>
|
||||
<h1>{{item.name}}</h1>
|
||||
</div>
|
||||
<div class="legend-container" *ngIf="item?.data.layers;let layers">
|
||||
@@ -13,7 +14,8 @@
|
||||
<option *ngFor="let l of layers;" [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<fm-map-layer-legend [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
|
||||
<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">
|
||||
|
@@ -4,6 +4,7 @@
|
||||
<div class="card-body">
|
||||
<div class="mb-2"><a href="#" (click)="handleBackToList($event)" i18n>Back</a></div>
|
||||
<div class="card menu-card">
|
||||
<h2 *ngIf="parentItem">{{parentItem.name}}</h2>
|
||||
<h1>{{item.name}}</h1>
|
||||
</div>
|
||||
<div class="legend-container" *ngIf="item?.data.layers;let layers">
|
||||
|
@@ -4,6 +4,7 @@
|
||||
<div class="card-body">
|
||||
<div class="mb-2"><a href="#" (click)="handleBackToList($event)" i18n>Back</a></div>
|
||||
<div class="card menu-card">
|
||||
<h2 *ngIf="parentItem">{{parentItem.name}}</h2>
|
||||
<h1>{{item.name}}</h1>
|
||||
</div>
|
||||
<div class="legend-container" *ngIf="item?.data.layers;let layers">
|
||||
@@ -28,7 +29,8 @@
|
||||
<option *ngFor="let l of layers;" [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<fm-map-layer-legend [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
|
||||
<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">
|
||||
|
@@ -35,7 +35,7 @@ export class SelectedItemTemporalComponent extends AbstractSelectedItemComponent
|
||||
nextDate():Date {
|
||||
let temporalItemLayer = this.itemLayer as ITemporalItemLayer;
|
||||
if(temporalItemLayer.nextItemLayer.item)
|
||||
return temporalItemLayer.nextItemLayer.item.dataDate;
|
||||
return new Date(Date.parse(temporalItemLayer.nextItemLayer.item.dataDate)) ;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export class SelectedItemTemporalComponent extends AbstractSelectedItemComponent
|
||||
previousDate():Date {
|
||||
let temporalItemLayer = this.itemLayer as ITemporalItemLayer;
|
||||
if(temporalItemLayer.previousItemLayer.item)
|
||||
return temporalItemLayer.previousItemLayer.item.dataDate;
|
||||
return new Date(Date.parse(temporalItemLayer.previousItemLayer.item.dataDate));
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ export class SelectedItemTemporalComponent extends AbstractSelectedItemComponent
|
||||
}
|
||||
|
||||
handleGoToChart(item: IItem) {
|
||||
this.router.navigate(['/viewer', 'temporal', 'item', item.parentCode, item.dataDate.getUTCFullYear()]);
|
||||
this.router.navigate(['/viewer', 'temporal', 'item', item.parentCode, new Date(Date.parse(item.dataDate)).getUTCFullYear()]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<div *ngIf="item;let item">
|
||||
<div class="card border-0">
|
||||
<img *ngIf="item.thumbnail" class="card-img-top" [src]="config.getConfig('apiEndPoint') +'/api/v1/items/'+item.code+'/thumbnail?v='+item.updated.getTime()" />
|
||||
<img *ngIf="item.thumbnail" class="card-img-top" [src]="getThumbnailUrl(item)" />
|
||||
<div *ngIf="!item.thumbnail" class="big-icon" [style.background-color]="itemTypeService.getColor(item.itemType)">
|
||||
<i [ngClass]="itemTypeService.getIcon(item.itemType)"></i>
|
||||
</div>
|
||||
|
@@ -11,7 +11,8 @@ import { IItemLayer } from '../../models/item.layer';
|
||||
@Injectable()
|
||||
@Directive()
|
||||
export abstract class AbstractSelectedItemComponent {
|
||||
@Input() item: IItem
|
||||
@Input() item: IItem;
|
||||
@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) {
|
||||
@@ -60,6 +61,7 @@ export abstract class AbstractSelectedItemComponent {
|
||||
event.preventDefault();
|
||||
this.location.back();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@@ -73,4 +75,8 @@ 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);
|
||||
}
|
||||
|
||||
getThumbnailUrl(item:IItem):string {
|
||||
return this.config.getConfig('apiEndPoint') +'/api/v1/items/'+item.code+'/thumbnail?v=' + Date.parse(item.updated);
|
||||
}
|
||||
}
|
||||
|
@@ -173,7 +173,14 @@ export class MapEffects {
|
||||
let itemCode = selectedItem ? selectedItem.code : "";
|
||||
if (a.itemCode != itemCode || setStateCount == 1) {
|
||||
return this.itemService$.getItem(a.itemCode).pipe(
|
||||
map((item: IItem) => new mapActions.SelectItemSuccess(item)),
|
||||
switchMap(child => {
|
||||
return this.itemService$.getItem(child.parentCode)
|
||||
.pipe(map(parent => {
|
||||
return {child, parent};
|
||||
})
|
||||
);
|
||||
}),
|
||||
map(data => new mapActions.SelectItemSuccess(data.child, data.parent)),
|
||||
catchError(error => of(new commonActions.Fail(error))))
|
||||
} else {
|
||||
return [];
|
||||
@@ -203,7 +210,7 @@ export class MapEffects {
|
||||
return this.itemService$.getChildItemList(action.item.code,null).pipe(
|
||||
map(items => new mapActions.SelectTemporalItemsSuccess(
|
||||
items.sort((a, b) =>
|
||||
-(b.dataDate.getTime() - a.dataDate.getTime())
|
||||
-(Date.parse(b.dataDate) - Date.parse(a.dataDate))
|
||||
)
|
||||
)),
|
||||
catchError(error => of(new commonActions.Fail(error))));
|
||||
@@ -247,7 +254,14 @@ export class MapEffects {
|
||||
let itemChangedAction = action as commonActions.ItemChangedEvent;
|
||||
if (selectedItem && selectedItem.code == itemChangedAction.itemCode) {
|
||||
return this.itemService$.getItem(itemChangedAction.itemCode).pipe(
|
||||
map((item: IItem) => new mapActions.SelectItemSuccess(item)),
|
||||
switchMap(child => {
|
||||
return this.itemService$.getItem(child.parentCode)
|
||||
.pipe(map(parent => {
|
||||
return {child, parent};
|
||||
})
|
||||
);
|
||||
}),
|
||||
map(data => new mapActions.SelectItemSuccess(data.child, data.parent)),
|
||||
catchError(error => of(new commonActions.Fail(error))));
|
||||
} else {
|
||||
return [];
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { IDataLayer } from '@farmmaps/common';
|
||||
|
||||
export interface IColor {
|
||||
red: number,
|
||||
green: number,
|
||||
@@ -64,11 +66,7 @@ export interface IRenderoutputImage {
|
||||
extent: [number,number,number,number]
|
||||
}
|
||||
|
||||
export interface ILayer {
|
||||
name: string,
|
||||
unit: string,
|
||||
index: number,
|
||||
scale: number,
|
||||
export interface ILayer extends IDataLayer {
|
||||
renderer: IRenderer,
|
||||
rendering: IRenderoutput
|
||||
}
|
||||
|
@@ -44,6 +44,7 @@ export interface State {
|
||||
panelCollapsed: boolean,
|
||||
selectedFeature: Feature,
|
||||
selectedItem:IItem,
|
||||
parentItem:IItem,
|
||||
clearEnabled: boolean,
|
||||
searchCollapsed: boolean,
|
||||
searchMinified: boolean,
|
||||
@@ -82,6 +83,7 @@ export const initialState: State = {
|
||||
panelCollapsed: false,
|
||||
selectedFeature: null,
|
||||
selectedItem: null,
|
||||
parentItem: null,
|
||||
clearEnabled: false,
|
||||
searchCollapsed: true,
|
||||
searchMinified:false,
|
||||
@@ -165,6 +167,7 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
|
||||
return tassign(state, {
|
||||
inSearch:false,
|
||||
selectedItem: a.item,
|
||||
parentItem: a.parentItem,
|
||||
selectedItemLayer: itemLayer,
|
||||
panelVisible: a.item != null,
|
||||
clearEnabled: a.item != null,
|
||||
@@ -307,6 +310,9 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
|
||||
case mapActions.COLLAPSESEARCH: {
|
||||
return tassign(state, { searchCollapsed: state.panelVisible ? false: true});
|
||||
}
|
||||
case commonActions.CLOSEALL: {
|
||||
return tassign(state, { searchCollapsed: state.panelVisible ? false: true,showLayerSwitcher:false});
|
||||
}
|
||||
case mapActions.SETEXTENT: {
|
||||
let a = action as mapActions.SetExtent;
|
||||
return tassign(state, { extent: a.extent });
|
||||
@@ -478,6 +484,7 @@ export const getPanelVisible = (state: State) => state.panelVisible;
|
||||
export const getPanelCollapsed = (state: State) => state.panelCollapsed;
|
||||
export const getSelectedFeature = (state: State) => state.selectedFeature;
|
||||
export const getSelectedItem = (state: State) => state.selectedItem;
|
||||
export const getParentItem = (state: State) => state.parentItem;
|
||||
export const getQueryState = (state: State) => state.queryState;
|
||||
export const getClearEnabled = (state: State) => state.clearEnabled;
|
||||
export const getSearchCollapsed = (state: State) => state.searchCollapsed;
|
||||
@@ -505,6 +512,7 @@ export const selectGetPanelVisible = createSelector(selectMapState, getPanelVisi
|
||||
export const selectGetPanelCollapsed = createSelector(selectMapState, getPanelCollapsed);
|
||||
export const selectGetSelectedFeature = createSelector(selectMapState, getSelectedFeature);
|
||||
export const selectGetSelectedItem = createSelector(selectMapState, getSelectedItem);
|
||||
export const selectGetParentItem = createSelector(selectMapState, getParentItem);
|
||||
export const selectGetQueryState = createSelector(selectMapState, getQueryState);
|
||||
export const selectGetClearEnabled = createSelector(selectMapState, getClearEnabled);
|
||||
export const selectGetSearchCollapsed = createSelector(selectMapState, getSearchCollapsed);
|
||||
|
@@ -4,6 +4,7 @@ import { IItemTypes } from '../models/item.types';
|
||||
import { IListItem } from '../models/list.item';
|
||||
import { IUser } from '../models/user';
|
||||
import { IItem } from '../models/item';
|
||||
import { UserInfo } from 'angular-oauth2-oidc';
|
||||
|
||||
export const INITUSER = '[AppCommon] InitUser';
|
||||
export const INITUSERSUCCESS = '[AppCommon] InitUserSuccess';
|
||||
@@ -17,7 +18,9 @@ export const INITROOTSUCCESS = '[Explorer] InitRootSuccess';
|
||||
export const OPENMODAL = '[AppCommon] OpenModal';
|
||||
export const CLOSEMODAL = '[AppCommon] CloseModal';
|
||||
export const LOGIN = '[AppCommon] Login';
|
||||
export const LOGOUT = '[AppCommon] Logout';
|
||||
export const ESCAPE = '[AppCommon] Escape';
|
||||
export const CLOSEALL = '[AppCommon] CloseAll';
|
||||
|
||||
export const LOADITEMTYPES = '[AppCommon] LoadItemTypes';
|
||||
export const LOADITEMTYPESSUCCESS = '[AppCommon] LoadItemTypesSuccess';
|
||||
@@ -51,6 +54,8 @@ export const UPLOADEDFILECLICK = '[AppCommon] UploadedFileClick';
|
||||
|
||||
export const TOGGLEMENU = '[AppCommon] ToggleMenu';
|
||||
|
||||
export const TOGGLEACCOUNTMENU = '[AppCommon] ToggleAccountMenu';
|
||||
|
||||
export const SETMENUVISIBLE = '[AppCommon] SetMenuVisible';
|
||||
|
||||
export class InitUser implements Action {
|
||||
@@ -62,7 +67,7 @@ export class InitUser implements Action {
|
||||
export class InitUserSuccess implements Action {
|
||||
readonly type = INITUSERSUCCESS;
|
||||
|
||||
constructor(public user:IUser ) { }
|
||||
constructor(public user:IUser,public userinfo:UserInfo ) { }
|
||||
}
|
||||
|
||||
export class InitUserPackagesSuccess implements Action {
|
||||
@@ -95,6 +100,12 @@ export class CloseModal implements Action {
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export class CloseAll implements Action {
|
||||
readonly type = CLOSEALL;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export class StartRouteLoading implements Action {
|
||||
readonly type = STARTROUTELOADING;
|
||||
|
||||
@@ -113,6 +124,12 @@ export class Login implements Action {
|
||||
constructor(public url: string) { }
|
||||
}
|
||||
|
||||
export class Logout implements Action {
|
||||
readonly type = LOGOUT;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export class Escape implements Action {
|
||||
readonly type = ESCAPE;
|
||||
|
||||
@@ -226,6 +243,12 @@ export class ToggleMenu implements Action {
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export class ToggleAccountMenu implements Action {
|
||||
readonly type = TOGGLEACCOUNTMENU;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
|
||||
export class SetMenuVisible implements Action {
|
||||
readonly type = SETMENUVISIBLE;
|
||||
|
||||
@@ -238,6 +261,7 @@ export type Actions = OpenModal
|
||||
| InitRootSuccess
|
||||
| CloseModal
|
||||
| Login
|
||||
| Logout
|
||||
| ItemChangedEvent
|
||||
| ItemAddedEvent
|
||||
| ItemDeletedEvent
|
||||
@@ -261,5 +285,8 @@ export type Actions = OpenModal
|
||||
| DeviceUpdateEvent
|
||||
| ToggleMenu
|
||||
| SetMenuVisible
|
||||
| InitUserPackagesSuccess;
|
||||
| InitUserPackagesSuccess
|
||||
| ToggleAccountMenu
|
||||
| CloseAll;
|
||||
|
||||
|
||||
|
@@ -9,6 +9,7 @@ import { OAuthModule, OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
|
||||
|
||||
//components
|
||||
import { ItemTypeService } from './services/itemtype.service';
|
||||
import { SchemaService } from './services/schema.service';
|
||||
import { FolderService } from './services/folder.service';
|
||||
import { TimespanService } from './services/timespan.service';
|
||||
import { ItemService } from './services/item.service';
|
||||
@@ -28,6 +29,8 @@ import { ResumableFileUploadService } from './components/resumable-file-upload/r
|
||||
import { NgbDateNativeAdapter } from './services/date-adapter.service'
|
||||
import { AuthConfigFactory } from './shared/authconfigFactory';
|
||||
import { StateSerializerService } from './services/state-serializer.service';
|
||||
import { PackageService } from './services/package.service';
|
||||
import { SenmlService } from './services/senml-service';
|
||||
|
||||
export {
|
||||
FolderService,
|
||||
@@ -47,7 +50,10 @@ export {
|
||||
AuthCallbackGuard,
|
||||
ResumableFileUploadService,
|
||||
NgbDateNativeAdapter,
|
||||
StateSerializerService
|
||||
StateSerializerService,
|
||||
SchemaService,
|
||||
PackageService,
|
||||
SenmlService
|
||||
};
|
||||
|
||||
@NgModule({
|
||||
@@ -71,7 +77,7 @@ export class AppCommonServiceModule {
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: appConfigFactory,
|
||||
deps: [Injector, AppConfig, OAuthService, AuthConfigFactory, OAuthStorage,ItemTypeService],
|
||||
deps: [Injector, AppConfig, OAuthService, AuthConfigFactory, OAuthStorage, ItemTypeService],
|
||||
multi: true
|
||||
},
|
||||
{
|
||||
|
@@ -31,6 +31,8 @@ import { TimespanComponent } from './components/timespan/timespan.component';
|
||||
import { TagInputComponent } from './components/tag-input/tag-input.component';
|
||||
import { MenuBackgroundComponent } from './components/menu-background/menu-background.component';
|
||||
import { HasPackageDirective} from './components/has-package/has-package.directive';
|
||||
import { HasClaimDirective} from './components/has-claim/has-claim.directive';
|
||||
import { UserMenuComponent} from './components/user-menu/user-menu.component';
|
||||
import { Alert } from './enumerations/alert.enum';
|
||||
import { IEventMessage } from './models/event.message';
|
||||
import { IItem, Item } from './models/item';
|
||||
@@ -39,11 +41,14 @@ import { IItemType } from './models/item.type';
|
||||
import { IItemTypes } from './models/item.types';
|
||||
import { IItemTask, ItemTask } from './models/itemTask';
|
||||
import { IListItem } from './models/list.item';
|
||||
import { ITypeaheadItem } from './models/typeahead.item';
|
||||
import { ITypeaheadItem } from './models/typeahead.item'
|
||||
import { IJsonline } from './models/json-line';
|
||||
import { ISenMLItem } from './models/senml-item';
|
||||
import { IPackage,IPackages } from './models/package';
|
||||
import { IUser } from './models/user';
|
||||
import { IQueryState } from './models/query.state';
|
||||
import { ICodeListItem } from './models/code.list.item';
|
||||
import { IDataLayer } from './models/data.layer';
|
||||
import * as commonActions from './actions/app-common.actions';
|
||||
import * as commonReducers from './reducers/app-common.reducer';
|
||||
import * as commonEffects from './effects/app-common.effects';
|
||||
@@ -60,7 +65,9 @@ export {
|
||||
SidePanelComponent,
|
||||
TimespanComponent,
|
||||
TagInputComponent,
|
||||
UserMenuComponent,
|
||||
HasPackageDirective,
|
||||
HasClaimDirective,
|
||||
Alert,
|
||||
IEventMessage,
|
||||
IItem,
|
||||
@@ -82,7 +89,10 @@ export {
|
||||
AuthConfigFactory,
|
||||
MenuBackgroundComponent,
|
||||
SecureOAuthStorage,
|
||||
WeatherCurrentObservation
|
||||
WeatherCurrentObservation,
|
||||
IJsonline,
|
||||
ISenMLItem,
|
||||
IDataLayer
|
||||
};
|
||||
|
||||
@NgModule({
|
||||
@@ -109,7 +119,9 @@ export {
|
||||
TagInputComponent,
|
||||
SessionClearedComponent,
|
||||
MenuBackgroundComponent,
|
||||
HasPackageDirective
|
||||
HasPackageDirective,
|
||||
HasClaimDirective,
|
||||
UserMenuComponent
|
||||
],
|
||||
exports: [
|
||||
NgbModule,
|
||||
@@ -127,7 +139,9 @@ export {
|
||||
TagInputComponent,
|
||||
SessionClearedComponent,
|
||||
MenuBackgroundComponent,
|
||||
HasPackageDirective
|
||||
HasPackageDirective,
|
||||
HasClaimDirective,
|
||||
UserMenuComponent
|
||||
]
|
||||
})
|
||||
export class AppCommonModule {
|
||||
|
@@ -23,4 +23,7 @@
|
||||
<ng-container *ngIf="showUploadProgress">
|
||||
<fm-resumable-file-upload></fm-resumable-file-upload>
|
||||
</ng-container>
|
||||
<div class="user-menu">
|
||||
<fm-user-menu [user]="user|async" [showMenu]="accountMenuVisible|async"></fm-user-menu>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -76,3 +76,14 @@ body { background: #f1f1f1; line-height: 18px; user-select:none;}
|
||||
.logo {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
transition: top 0.5s ease-out;
|
||||
position: absolute;
|
||||
top:0.25em;
|
||||
right:1em;
|
||||
}
|
||||
|
||||
.fullscreen > .user-menu {
|
||||
top:1em;
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ import { Router, NavigationStart, NavigationEnd, RouteConfigLoadStart, RouteConf
|
||||
import { Meta, Title, MetaDefinition } from '@angular/platform-browser';import { DOCUMENT } from "@angular/common";
|
||||
import { Subscription , Observable } from 'rxjs';
|
||||
import { Store, Action } from '@ngrx/store';
|
||||
import { IUser } from '../../models/user';
|
||||
|
||||
//AppCommon
|
||||
import { IEventMessage } from '../../models/event.message';
|
||||
@@ -34,6 +35,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
public fullScreen: Observable<boolean>;
|
||||
public routeLoading: Observable<boolean>;
|
||||
public menuVisible: Observable<boolean>;
|
||||
public accountMenuVisible: Observable<boolean>;
|
||||
public user:Observable<IUser>;
|
||||
@Input() showUploadProgress: boolean =true;
|
||||
|
||||
constructor(
|
||||
@@ -88,6 +91,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
this.fullScreen = this.store.select(appReducers.selectGetFullScreen);
|
||||
this.routeLoading = this.store.select(appReducers.selectGetRouteLoading);
|
||||
this.menuVisible = this.store.select(appReducers.SelectGetMenuVisible);
|
||||
this.accountMenuVisible = this.store.select(appReducers.SelectGetAccountMenuVisible);
|
||||
this.user = this.store.select(appReducers.SelectGetUser);
|
||||
this.InstallRouteEventHandler();
|
||||
this.InstallEventServiceEventHandler();
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
import { Directive, ViewContainerRef,TemplateRef,OnInit,Input,OnDestroy } from '@angular/core';
|
||||
import { Store} from '@ngrx/store';
|
||||
import * as appCommonReducer from '../../reducers/app-common.reducer'
|
||||
import { IPackages } from '../../models/package';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { skip } from 'rxjs/operators';
|
||||
import {OAuthService } from 'angular-oauth2-oidc';
|
||||
import { IUser } from '../../models/user';
|
||||
|
||||
@Directive({
|
||||
selector: '[fm-hasclaim]',
|
||||
})
|
||||
export class HasClaimDirective implements OnInit{
|
||||
@Input('fm-hasclaim') claim:string;
|
||||
|
||||
constructor(private templateRef$: TemplateRef<any>,private viewContainerRef$: ViewContainerRef,private store$: Store<appCommonReducer.State>) { }
|
||||
private user$:Observable<IUser> = this.store$.select(appCommonReducer.SelectGetUser).pipe(skip(1));
|
||||
private hasView = false;
|
||||
ngOnInit() {
|
||||
this.user$.subscribe((user) => {
|
||||
if (user.claims[this.claim]) {
|
||||
this.viewContainerRef$.createEmbeddedView(this.templateRef$);
|
||||
this.hasView=true;
|
||||
} else if (this.hasView) {
|
||||
this.viewContainerRef$.clear();
|
||||
this.hasView = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -52,20 +52,19 @@ export class ResumableFileUploadService implements OnDestroy{
|
||||
}
|
||||
|
||||
handleState(state:UploadState) {
|
||||
switch(state.status) {
|
||||
case "queue": {
|
||||
var file =this.files.find((f) => f.identifier == state.uploadId )
|
||||
if(state.status != "cancelled" && !file) {
|
||||
this.files.push(new File(state));
|
||||
this.isClosed=false;
|
||||
};break;
|
||||
}
|
||||
switch(state.status) {
|
||||
case "uploading": {
|
||||
this.isUploading = true;
|
||||
var file =this.files.find((f) => f.identifier == state.uploadId )
|
||||
if(file) {
|
||||
this.isUploading = true;
|
||||
file.progress = (state.progress?state.progress:0);
|
||||
}
|
||||
};break;
|
||||
case "complete": {
|
||||
var file =this.files.find((f) => f.identifier == state.uploadId )
|
||||
if(file) {
|
||||
var parts = state.url.split("/");
|
||||
file.itemCode = parts[parts.length-1];
|
||||
@@ -74,10 +73,9 @@ export class ResumableFileUploadService implements OnDestroy{
|
||||
}
|
||||
};break;
|
||||
case "error": {
|
||||
var file =this.files.find((f) => f.identifier == state.uploadId )
|
||||
if(file) {
|
||||
file.error=true;
|
||||
file.errorMessage = state.response;
|
||||
file.errorMessage = state.response as string;
|
||||
}
|
||||
};break;
|
||||
}
|
||||
@@ -102,6 +100,9 @@ export class ResumableFileUploadService implements OnDestroy{
|
||||
if (index > -1) {
|
||||
this.files.splice(index, 1);
|
||||
}
|
||||
if(this.files.length==0) {
|
||||
this.isUploading = false;
|
||||
}
|
||||
};
|
||||
|
||||
doClose = function () {
|
||||
|
@@ -0,0 +1,13 @@
|
||||
<div *ngIf="user">
|
||||
<div (click)="toggle($event)" class="rounded-circle menu-button" [title]="user.name">
|
||||
<span>{{getLetter()}}</span>
|
||||
<div class="menu hidden" [ngClass]="{'hidden':!showMenu}">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="username">{{user.name}}</div>
|
||||
<div><a href="#" (click)="logout($event)" i18n>logout</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,46 @@
|
||||
.menu-button {
|
||||
background-color: purple;
|
||||
display: inline-block;
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
line-height: 2.5em;
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
div.menu-button > span {
|
||||
color:white;
|
||||
}
|
||||
|
||||
.menu {
|
||||
max-height: 100vh;
|
||||
//transition: max-height 0.2s;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 20px rgba(0,0,0,.3);
|
||||
position: absolute;
|
||||
top: 3rem;
|
||||
right:0;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding:0.5rem;
|
||||
min-width: 10rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.username {
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.2rem;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
max-height: 0;
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UserMenuComponent } from './user-menu.component';
|
||||
|
||||
describe('UserMenuComponent', () => {
|
||||
let component: UserMenuComponent;
|
||||
let fixture: ComponentFixture<UserMenuComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ UserMenuComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(UserMenuComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,37 @@
|
||||
import { Component, OnInit,Input } from '@angular/core';
|
||||
import { OAuthService} from 'angular-oauth2-oidc'
|
||||
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-user-menu',
|
||||
templateUrl: './user-menu.component.html',
|
||||
styleUrls: ['./user-menu.component.scss']
|
||||
})
|
||||
export class UserMenuComponent implements OnInit {
|
||||
|
||||
@Input() user:IUser;
|
||||
@Input() showMenu:boolean;
|
||||
|
||||
constructor(private oauthService:OAuthService, private store: Store<appReducers.State>) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
getLetter():string {
|
||||
return this.user.name ? this.user.name.substr(0,1).toUpperCase():"";
|
||||
}
|
||||
|
||||
logout(event:MouseEvent) {
|
||||
event.preventDefault();
|
||||
this.store.dispatch(new appActions.Logout());
|
||||
}
|
||||
|
||||
|
||||
toggle(event:MouseEvent) {
|
||||
event.stopPropagation();
|
||||
this.store.dispatch(new appActions.ToggleAccountMenu());
|
||||
}
|
||||
}
|
@@ -1,9 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { OAuthService,UserInfo } from 'angular-oauth2-oidc';
|
||||
import { Store, Action } from '@ngrx/store';
|
||||
import { Effect, Actions,ofType } from '@ngrx/effects';
|
||||
import { Observable , defer , of } from 'rxjs';
|
||||
import { Observable , defer , of,from } from 'rxjs';
|
||||
import { withLatestFrom,mergeMap,switchMap,map,catchError} from 'rxjs/operators';
|
||||
import * as appCommonActions from '../actions/app-common.actions';
|
||||
import * as appCommonReducers from '../reducers/app-common.reducer';
|
||||
@@ -25,7 +25,15 @@ export class AppCommonEffects {
|
||||
withLatestFrom(this.store$.select(appCommonReducers.selectGetInitialized)),
|
||||
mergeMap(([action, initialized]) => {
|
||||
var a = (action as appCommonActions.Login);
|
||||
this.oauthService$.initCodeFlow(a.url);
|
||||
this.oauthService$.initCodeFlow(a.url,{"prompt":"login"});
|
||||
return [];
|
||||
}));
|
||||
|
||||
@Effect({ dispatch: false })
|
||||
logout$: Observable<Action> = this.actions$.pipe(
|
||||
ofType(appCommonActions.LOGOUT),
|
||||
mergeMap((action) => {
|
||||
this.oauthService$.logOut(true);
|
||||
return [];
|
||||
}));
|
||||
|
||||
@@ -46,7 +54,8 @@ export class AppCommonEffects {
|
||||
switchMap(([action, initialized]) => {
|
||||
if(!initialized) {
|
||||
return this.userService$.getCurrentUser().pipe(
|
||||
map((user: IUser) => new appCommonActions.InitUserSuccess(user)),
|
||||
withLatestFrom(from(this.oauthService$.loadUserProfile())),
|
||||
switchMap(([user,userInfo]) => {return of(new appCommonActions.InitUserSuccess(user,userInfo as UserInfo))} ),
|
||||
catchError(error => of(new appCommonActions.Fail(error))))
|
||||
} else {
|
||||
return [];
|
||||
@@ -100,8 +109,11 @@ export class AppCommonEffects {
|
||||
withLatestFrom(this.store$.select(appCommonReducers.selectGetItemTypes)),
|
||||
switchMap(([action, itemtypes]) => {
|
||||
var a = action as appCommonActions.EditItem;
|
||||
var editor = "property";
|
||||
if(a.item.itemType) {
|
||||
var itemType = itemtypes[a.item.itemType];
|
||||
var editor = itemType.editor ? itemType.editor : "property";
|
||||
var editor = itemType && itemType.editor ? itemType.editor : editor;
|
||||
}
|
||||
this.router$.navigate(['/editor',editor,'item', a.item.code])
|
||||
return [];
|
||||
}
|
||||
|
10
projects/common/src/fm/models/WeatherData.ts
Normal file
10
projects/common/src/fm/models/WeatherData.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface WeatherData {
|
||||
time: Date;
|
||||
minTemp: number;
|
||||
maxTemp: number;
|
||||
relativeHumidity: number;
|
||||
rain: number;
|
||||
wspd?: number;
|
||||
wdir_cardinal?: string;
|
||||
wdir?: number;
|
||||
}
|
7
projects/common/src/fm/models/data.layer.ts
Normal file
7
projects/common/src/fm/models/data.layer.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface IDataLayer {
|
||||
name: string,
|
||||
unit: string,
|
||||
index: number,
|
||||
indexKey?: string,
|
||||
scale: number,
|
||||
}
|
@@ -15,9 +15,10 @@ export class Item implements IItem {
|
||||
public geometry?:any;
|
||||
public url?: string;
|
||||
public name?: string;
|
||||
public created?: Date;
|
||||
public updated?: Date;
|
||||
public dataDate?: Date;
|
||||
public created?: string;
|
||||
public updated?: string;
|
||||
public dataDate?: string;
|
||||
public dataEndDate?: string;
|
||||
public itemType?: string;
|
||||
public sourceTask?: string;
|
||||
public size?: number;
|
||||
|
@@ -4,5 +4,6 @@ export interface IItemType {
|
||||
editor?: string;
|
||||
isFolder?: boolean;
|
||||
iconColor?: string;
|
||||
schema?: string;
|
||||
extraAttributes?: string;
|
||||
}
|
||||
|
5
projects/common/src/fm/models/json-line.ts
Normal file
5
projects/common/src/fm/models/json-line.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface IJsonline {
|
||||
time: string;
|
||||
type: string;
|
||||
data: any;
|
||||
}
|
@@ -2,9 +2,10 @@ export interface IListItem {
|
||||
url?: string;
|
||||
code?: string;
|
||||
name?: string;
|
||||
created?: Date;
|
||||
updated?: Date;
|
||||
dataDate?: Date;
|
||||
created?: string;
|
||||
updated?: string;
|
||||
dataDate?: string;
|
||||
dataEndDate?: string;
|
||||
itemType?: string;
|
||||
sourceTask?: string;
|
||||
size?: number;
|
||||
|
5
projects/common/src/fm/models/senml-item.ts
Normal file
5
projects/common/src/fm/models/senml-item.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface ISenMLItem {
|
||||
u?: string;
|
||||
v?: string;
|
||||
n?: string;
|
||||
}
|
@@ -2,4 +2,5 @@ export interface IUser {
|
||||
code?: string;
|
||||
name?: string;
|
||||
email?: string;
|
||||
claims: any;
|
||||
}
|
||||
|
@@ -17,7 +17,8 @@ export interface State {
|
||||
fullScreen: boolean,
|
||||
routeLoading:boolean,
|
||||
menuVisible: boolean,
|
||||
userPackages: IPackages
|
||||
userPackages: IPackages,
|
||||
accountMenuVisible: boolean
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
@@ -29,14 +30,25 @@ export const initialState: State = {
|
||||
fullScreen: true,
|
||||
routeLoading: false,
|
||||
menuVisible: false,
|
||||
userPackages: {}
|
||||
userPackages: {},
|
||||
accountMenuVisible: false
|
||||
}
|
||||
|
||||
export function reducer(state = initialState, action: appCommonActions.Actions ): State {
|
||||
switch (action.type) {
|
||||
case appCommonActions.INITUSERSUCCESS: {
|
||||
let a = action as appCommonActions.InitUserSuccess;
|
||||
return tassign(state, { user: a.user,initialized: true });
|
||||
let claims = {}
|
||||
Object.getOwnPropertyNames(a.userinfo).forEach((k) => {
|
||||
claims[k] = a.userinfo[k];
|
||||
});
|
||||
var user:IUser = {
|
||||
code:a.user.code,
|
||||
email:a.userinfo["email"],
|
||||
name:a.userinfo["name"],
|
||||
claims:claims
|
||||
};
|
||||
return tassign(state, { user: user,initialized: true });
|
||||
}
|
||||
case appCommonActions.INITROOTSUCCESS: {
|
||||
let a = action as appCommonActions.InitRootSuccess;
|
||||
@@ -73,14 +85,17 @@ export function reducer(state = initialState, action: appCommonActions.Actions )
|
||||
});
|
||||
}
|
||||
case appCommonActions.TOGGLEMENU: {
|
||||
return tassign(state, { menuVisible: !state.menuVisible });
|
||||
return tassign(state, { menuVisible: !state.menuVisible,accountMenuVisible:!state.menuVisible?false:state.accountMenuVisible });
|
||||
}
|
||||
case appCommonActions.TOGGLEACCOUNTMENU: {
|
||||
return tassign(state, { accountMenuVisible: !state.accountMenuVisible });
|
||||
}
|
||||
case appCommonActions.ESCAPE: {
|
||||
return tassign(state, { menuVisible: false });
|
||||
return tassign(state, { menuVisible: false,accountMenuVisible:false });
|
||||
}
|
||||
case appCommonActions.SETMENUVISIBLE: {
|
||||
let a = action as appCommonActions.SetMenuVisible;
|
||||
return tassign(state, { menuVisible: a.visible });
|
||||
return tassign(state, { menuVisible: a.visible,accountMenuVisible:a.visible?false:state.accountMenuVisible });
|
||||
}
|
||||
case appCommonActions.INITUSERPACKAGESSUCCESS:{
|
||||
let a = action as appCommonActions.InitUserPackagesSuccess;
|
||||
@@ -91,6 +106,12 @@ export function reducer(state = initialState, action: appCommonActions.Actions )
|
||||
|
||||
return tassign(state,{userPackages:packages});
|
||||
}
|
||||
case appCommonActions.LOGOUT:{
|
||||
return tassign(state,{user:null,initialized:false});
|
||||
}
|
||||
case appCommonActions.CLOSEALL: {
|
||||
return tassign(state,{accountMenuVisible:false,menuVisible:false });
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
@@ -106,6 +127,7 @@ export const getRouteLoading = (state: State) => state.routeLoading;
|
||||
export const getMenuVisible = (state: State) => state.menuVisible;
|
||||
export const getUser = (state: State) => state.user;
|
||||
export const getUserPackages = (state: State) => state.userPackages;
|
||||
export const getAccountMenuVisible = (state: State) => state.accountMenuVisible;
|
||||
|
||||
export const selectAppCommonState = createFeatureSelector<State>(MODULE_NAME);
|
||||
|
||||
@@ -118,4 +140,5 @@ export const selectGetRouteLoading = createSelector(selectAppCommonState, getRou
|
||||
export const SelectGetMenuVisible = createSelector(selectAppCommonState,getMenuVisible);
|
||||
export const SelectGetUser = createSelector(selectAppCommonState,getUser);
|
||||
export const SelectGetUserPackages = createSelector(selectAppCommonState,getUserPackages);
|
||||
export const SelectGetAccountMenuVisible = createSelector(selectAppCommonState,getAccountMenuVisible);
|
||||
|
||||
|
@@ -18,39 +18,32 @@ export class FolderService {
|
||||
return this.appConfig.getConfig("apiEndPoint");
|
||||
}
|
||||
|
||||
parseDates(item: any): IListItem {
|
||||
item.created = new Date(Date.parse(item.created));
|
||||
item.updated = new Date(Date.parse(item.updated));
|
||||
item.dataDate = new Date(Date.parse(item.dataDate));
|
||||
return item;
|
||||
}
|
||||
|
||||
getFolder(code: string): Observable<IListItem> {
|
||||
return this.httpClient.get<IListItem>(`${this.ApiEndpoint()}/api/v1/folders/${code}`).pipe(map(i => this.parseDates(i)));
|
||||
return this.httpClient.get<IListItem>(`${this.ApiEndpoint()}/api/v1/folders/${code}`);
|
||||
}
|
||||
|
||||
getMyRoots(): Observable<IListItem[]> {
|
||||
return this.httpClient.get<IListItem[]>(`${this.ApiEndpoint()}/api/v1/folders/my_roots`).pipe(map(ia => ia.map(i => this.parseDates(i))));
|
||||
return this.httpClient.get<IListItem[]>(`${this.ApiEndpoint()}/api/v1/folders/my_roots`);
|
||||
}
|
||||
|
||||
getFolderParents(code: string): Observable<IListItem[]> {
|
||||
return this.httpClient.get<IListItem[]>(`${this.ApiEndpoint()}/api/v1/folders/${code}/parents`).pipe(map(ia => ia.map(i => this.parseDates(i))));
|
||||
return this.httpClient.get<IListItem[]>(`${this.ApiEndpoint()}/api/v1/folders/${code}/parents`);
|
||||
}
|
||||
|
||||
getChildFolders(code: string): Observable<IListItem[]> {
|
||||
return this.httpClient.get<IListItem[]>(`${this.ApiEndpoint()}/api/v1/folders/${code}/listfolders`).pipe(map(ia => ia.map(i => this.parseDates(i))));
|
||||
return this.httpClient.get<IListItem[]>(`${this.ApiEndpoint()}/api/v1/folders/${code}/listfolders`);
|
||||
}
|
||||
|
||||
getItems(code: string,skip:number, take:number): Observable<IListItem[]> {
|
||||
return this.httpClient.get<IListItem[]>(`${this.ApiEndpoint()}/api/v1/folders/${code}/list?skip=${skip}&take=${take}`).pipe(map(ia => ia.map(i => this.parseDates(i))));
|
||||
return this.httpClient.get<IListItem[]>(`${this.ApiEndpoint()}/api/v1/folders/${code}/list?skip=${skip}&take=${take}`);
|
||||
}
|
||||
|
||||
moveItem(itemCode: string, newParentCode: string): Observable<IListItem> {
|
||||
const body = { itemCode: itemCode,newParentCode: newParentCode };
|
||||
return this.httpClient.post<IListItem>(`${this.ApiEndpoint()}/api/v1/items/move`, body).pipe(map(i => this.parseDates(i)));
|
||||
return this.httpClient.post<IListItem>(`${this.ApiEndpoint()}/api/v1/items/move`, body);
|
||||
}
|
||||
|
||||
createFolder(folder: IItem): Observable<IListItem> {
|
||||
return this.httpClient.post<IListItem>(`${this.ApiEndpoint()}/api/v1/folders/`, folder).pipe(map(i => this.parseDates(i)));
|
||||
return this.httpClient.post<IListItem>(`${this.ApiEndpoint()}/api/v1/folders/`, folder);
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { IItemType } from '../models/item.type';
|
||||
import { IItem } from '../models/item';
|
||||
import { IJsonline } from '../models/json-line';
|
||||
import { IItemTask } from '../models/itemTask';
|
||||
import { HttpClient, HttpParams } from "@angular/common/http";
|
||||
import { AppConfig } from "../shared/app.config";
|
||||
@@ -19,13 +20,6 @@ export class ItemService {
|
||||
return this.appConfig.getConfig("apiEndPoint");
|
||||
}
|
||||
|
||||
parseDates(item: any): IItem {
|
||||
item.created = new Date(Date.parse(item.created));
|
||||
item.updated = new Date(Date.parse(item.updated));
|
||||
item.dataDate = new Date(Date.parse(item.dataDate));
|
||||
return item;
|
||||
}
|
||||
|
||||
getItemTypes(): Observable<{ [id: string]: IItemType }> {
|
||||
return this.httpClient.get<{ [id: string]: IItemType }>(`${this.ApiEndpoint()}/api/v1/itemtypes/`);
|
||||
}
|
||||
@@ -58,21 +52,21 @@ export class ItemService {
|
||||
}
|
||||
|
||||
getItem(code: string): Observable<IItem> {
|
||||
return this.httpClient.get<IItem>(`${this.ApiEndpoint()}/api/v1/items/${code}`).pipe(map(i => this.parseDates(i)));
|
||||
return this.httpClient.get<IItem>(`${this.ApiEndpoint()}/api/v1/items/${code}`);
|
||||
}
|
||||
|
||||
getItemByCodeAndType(code: string, itemType: string): Observable<IItem> {
|
||||
return this.httpClient.get<IItem>(`${this.ApiEndpoint()}/api/v1/items/${code}/${itemType}`);
|
||||
}
|
||||
|
||||
getItemList(itemType: string, dataFilter?: any, level: number = 1): Observable<IItem[]> {
|
||||
getItemList(itemType?: string, dataFilter?: any, level?:number ,atItemLocationItemCode?:string,indexed?:boolean): Observable<IItem[]> {
|
||||
var params = new HttpParams();
|
||||
params = params.append("it", itemType);
|
||||
if(dataFilter != null){
|
||||
params = params.append("df", JSON.stringify(dataFilter));
|
||||
}
|
||||
params = params.append("lvl", itemType);
|
||||
return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/`, { params: params }).pipe(map(ia => ia.map(i => this.parseDates(i))));
|
||||
if(itemType) params = params.append("it", itemType);
|
||||
if(dataFilter) params = params.append("df", JSON.stringify(dataFilter));
|
||||
if(atItemLocationItemCode) params = params.append("ail",atItemLocationItemCode);
|
||||
if(indexed) params = params.append("ind",indexed?"true":"false");
|
||||
if(level) params = params.append("lvl", level.toFixed());
|
||||
return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/`, { params: params });
|
||||
}
|
||||
|
||||
getChildItemList(parentcode: string, itemType: string, dataFilter?: any, level: number = 1, deep: boolean = true): Observable<IItem[]> {
|
||||
@@ -85,7 +79,7 @@ export class ItemService {
|
||||
}
|
||||
params = params.append("lvl", level.toString());
|
||||
params = params.append("deep", deep.toString());
|
||||
return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/${parentcode}/children`, { params: params }).pipe(map(ia => ia.map(i => this.parseDates(i))));
|
||||
return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/${parentcode}/children`, { params: params });
|
||||
}
|
||||
|
||||
getChildItemListCount(parentcode: string, itemType: string): Observable<Number> {
|
||||
@@ -103,7 +97,7 @@ export class ItemService {
|
||||
params = params.append("df", JSON.stringify(dataFilter));
|
||||
}
|
||||
params = params.append("lvl", level.toString());
|
||||
return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/${parentcode}/children`, { params: params }).pipe(map(ia => ia.map(i => this.parseDates(i))));
|
||||
return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/${parentcode}/children`, { params: params });
|
||||
}
|
||||
|
||||
getItemFeatures(code: string, extent: number[], crs: string, layerIndex?:number): Observable<any> {
|
||||
@@ -134,7 +128,7 @@ export class ItemService {
|
||||
return this.httpClient.post<any>(`${this.ApiEndpoint()}/api/v1/items/delete`, itemCodes);
|
||||
}
|
||||
|
||||
getTemporalLast(code: string): Observable<any> {
|
||||
getTemporalLast(code: string): Observable<IJsonline> {
|
||||
return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/items/${code}/temporal/last`);
|
||||
}
|
||||
|
||||
@@ -152,6 +146,6 @@ export class ItemService {
|
||||
getItemTaskList(itemcode: string, unfinishedOnly?: boolean): Observable<IItemTask[]> {
|
||||
var params = new HttpParams();
|
||||
if (unfinishedOnly) params = params.append("unfinishedOnly", unfinishedOnly.toString());
|
||||
return this.httpClient.get<IItemTask[]>(`${this.ApiEndpoint()}/api/v1/items/${itemcode}/tasks`, { params: params }).pipe(map(ia => ia.map(i => this.parseDates(i))));
|
||||
return this.httpClient.get<IItemTask[]>(`${this.ApiEndpoint()}/api/v1/items/${itemcode}/tasks`, { params: params });
|
||||
}
|
||||
}
|
@@ -31,6 +31,12 @@ export class ItemTypeService {
|
||||
return extraAttributes;
|
||||
}
|
||||
|
||||
getSchema(itemType: string): string {
|
||||
let schema = null;
|
||||
if (this.itemTypes[itemType]) schema = this.itemTypes[itemType].schema;
|
||||
return schema;
|
||||
}
|
||||
|
||||
hasViewer(item: IItem) {
|
||||
let itemType: string = item.itemType;
|
||||
if (this.itemTypes[itemType]) return this.itemTypes[itemType].viewer !== undefined;
|
||||
|
43
projects/common/src/fm/services/schema.service.ts
Normal file
43
projects/common/src/fm/services/schema.service.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {AppConfig} from '../shared/app.config';
|
||||
import {Observable, of} from 'rxjs';
|
||||
import {catchError, switchMap} from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SchemaService {
|
||||
constructor(private httpClient: HttpClient, private appConfig: AppConfig,
|
||||
@Inject(LOCALE_ID) private locale) {
|
||||
}
|
||||
|
||||
ApiEndpoint() {
|
||||
return this.appConfig.getConfig('apiEndPoint');
|
||||
}
|
||||
|
||||
/** Takes decoded schema url id */
|
||||
public getSchema(id): Observable<any> {
|
||||
const encodedId = encodeURIComponent(id);
|
||||
return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/schema/${encodedId}`);
|
||||
}
|
||||
|
||||
public getSchemaLayout(schemaUrl: string, locale: string): Observable<any> {
|
||||
const encodedId = encodeURIComponent(schemaUrl);
|
||||
return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/schema/${encodedId}/layout/${locale}`);
|
||||
}
|
||||
|
||||
public getSchemaAndLayout(schemaUrl: string, locale: string = this.locale):
|
||||
Observable<{schemaJson: any, schemaLayout: any}> {
|
||||
return this.getSchema(schemaUrl).pipe(
|
||||
switchMap(
|
||||
schemaJson => this.getSchemaLayout(schemaUrl, locale)
|
||||
.pipe(catchError(err => {
|
||||
return of(undefined);
|
||||
})),
|
||||
(schemaJson, schemaLayout) => {
|
||||
return ({schemaJson, schemaLayout});
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
31
projects/common/src/fm/services/senml-service.ts
Normal file
31
projects/common/src/fm/services/senml-service.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { IJsonline } from '../models/json-line';
|
||||
import { ISenMLItem } from '../models/senml-item';
|
||||
import { IDataLayer } from '../models/data.layer';
|
||||
import { IItem } from '../models/item';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SenmlService {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getSenMLItem(layer:IDataLayer,jsonLine:IJsonline): ISenMLItem {
|
||||
if (jsonLine) {
|
||||
var senmlPack = jsonLine.data as ISenMLItem[];
|
||||
var temp = senmlPack.filter((i) => i.u == layer.indexKey);
|
||||
if (temp.length == 1) return temp[0];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
getFirstLayer(item:IItem):IDataLayer {
|
||||
if(item && item.data && item.data["layers"] && item.data["layers"].length > 0 ) {
|
||||
return item.data["layers"][0] as IDataLayer;
|
||||
} else {
|
||||
let retVal:IDataLayer = { name:"Soil moisture",index:0,scale:1,unit:"%",indexKey:"%vol" };
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,21 +3,86 @@ import {HttpClient} from '@angular/common/http';
|
||||
import {AppConfig} from '../shared/app.config';
|
||||
import {Observable} from 'rxjs';
|
||||
import {WeatherCurrentObservation} from '../models/weatherCurrentObservation';
|
||||
import {DatePipe} from '@angular/common';
|
||||
import {WeatherData} from '../models/WeatherData';
|
||||
import {GeoJSON} from 'ol/format';
|
||||
import {map, switchMap} from 'rxjs/operators';
|
||||
import {getCenter} from 'ol/extent';
|
||||
import {IItem} from '../models/item';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class WeatherService {
|
||||
private apiUrl = '/api/v1/weather/currentobservation';
|
||||
private apiCurrentObservationUrl = 'currentobservation';
|
||||
private apiObservation = 'observation';
|
||||
private apiForecast = 'forecast';
|
||||
|
||||
constructor(public httpClient: HttpClient, public appConfig: AppConfig) {
|
||||
private format: GeoJSON;
|
||||
|
||||
constructor(public httpClient: HttpClient, public appConfig: AppConfig, private datePipe: DatePipe) {
|
||||
this.format = new GeoJSON();
|
||||
}
|
||||
|
||||
public GetCurrentObservation(centroid: number[]): Observable<WeatherCurrentObservation> {
|
||||
const endpoint = this.appConfig.getConfig('weatherApiEndPoint');
|
||||
const apiKey = this.appConfig.getConfig('weatherApiKey');
|
||||
const observationUrl = `${endpoint}${this.apiUrl}/?c=${centroid[0]},${centroid[1]}&key=${apiKey}`;
|
||||
const observationUrl = `${endpoint}${this.apiCurrentObservationUrl}/?c=${centroid[0]},${centroid[1]}&key=${apiKey}`;
|
||||
|
||||
return this.httpClient.get<WeatherCurrentObservation>(observationUrl);
|
||||
}
|
||||
|
||||
public getWeatherRangeForItem(item: IItem, daysBefore = 10, daysAfter = 10): Observable<WeatherData[]> {
|
||||
const geometry = this.format.readGeometry(item.geometry);
|
||||
const centroid = getCenter(geometry.getExtent());
|
||||
|
||||
const currentDate = new Date(Date.now());
|
||||
const sd = new Date(Date.now());
|
||||
const ed = new Date(Date.now());
|
||||
sd.setDate((currentDate.getDate() - daysBefore));
|
||||
ed.setDate((currentDate.getDate() + daysAfter));
|
||||
|
||||
return this.getWeatherRange(centroid, this.datePipe.transform(sd, 'yyyy-MM-ddThh:mm:ss'),
|
||||
this.datePipe.transform(ed, 'yyyy-MM-ddThh:mm:ss'));
|
||||
}
|
||||
|
||||
public getWeatherRange(centroid: number[], startDate: string, endDate: string): Observable<WeatherData[]> {
|
||||
const endpoint = this.appConfig.getConfig('weatherApiEndPoint');
|
||||
const apiKey = this.appConfig.getConfig('weatherApiKey');
|
||||
|
||||
// weather does not support UTC format, also remove Z
|
||||
const sd = encodeURIComponent(this.removeUTCZ(startDate));
|
||||
const ed = encodeURIComponent(this.removeUTCZ(endDate));
|
||||
|
||||
const historical = `${endpoint}${this.apiObservation}/?c=${centroid[0]},${centroid[1]}&sd=${sd}&ed=${ed}&interval=daily&key=${apiKey}`;
|
||||
const forecast = `${endpoint}${this.apiForecast}/?c=${centroid[0]},${centroid[1]}&interval=daily&key=${apiKey}`;
|
||||
|
||||
return this.httpClient.get<any[]>(historical).pipe(
|
||||
map(h => h.map(this.createWeatherDataFromHistorical)),
|
||||
switchMap(h => {
|
||||
return this.httpClient.get<any[]>(forecast)
|
||||
.pipe(
|
||||
map(f => [...h, ...f.filter(fd => fd.date <= endDate)
|
||||
.map(this.createWeatherDataFromForecast)]));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private createWeatherDataFromHistorical(hd): WeatherData {
|
||||
return {time: hd.date, minTemp: hd.minimumTemperature,
|
||||
maxTemp: hd.maximumTemperature, relativeHumidity: hd.relativeHumidity, rain: hd.precipitation};
|
||||
}
|
||||
|
||||
private createWeatherDataFromForecast(fd): WeatherData {
|
||||
return {time: fd.date, minTemp: fd.minimumTemperature,
|
||||
maxTemp: fd.maximumTemperature, relativeHumidity: fd.relativeHumidity, rain: fd.rain};
|
||||
}
|
||||
|
||||
private removeUTCZ(dateFormat: string): string {
|
||||
if (dateFormat[dateFormat.length - 1] === 'Z') {
|
||||
return dateFormat.substring(0, dateFormat.length - 1);
|
||||
}
|
||||
|
||||
return dateFormat;
|
||||
}
|
||||
}
|
||||
|
@@ -14,10 +14,10 @@ export function appConfigFactory(injector:Injector, appConfig: AppConfig, oauthS
|
||||
appConfig.load().then(() => {
|
||||
oauthService.events.subscribe((event) => {
|
||||
console.debug(event.type);
|
||||
if (event.type == 'token_error' || event.type == 'silent_refresh_timeout') {
|
||||
if (event.type == 'token_error' || event.type == 'silent_refresh_timeout' || event.type == 'logout') {
|
||||
let e = event as OAuthErrorEvent;
|
||||
let p = e.params as any;
|
||||
if (event.type == 'silent_refresh_timeout' || (p.error && p.error == 'login_required')) {
|
||||
if (event.type == 'silent_refresh_timeout' || event.type == 'logout' || (p.error && p.error == 'login_required')) {
|
||||
let router = injector.get(Router);
|
||||
console.debug("Session expired");
|
||||
router.navigate(['loggedout'], { queryParams: { redirectTo: router.url } });
|
||||
|
@@ -14,7 +14,7 @@ export class Id4AuthconfigFactory implements IAuthconfigFactory {
|
||||
authConfig.redirectUri = window.location.origin + "/cb";
|
||||
authConfig.clientId = appConfig.getConfig("clientId");
|
||||
authConfig.customQueryParams = { audience: appConfig.getConfig("audience") };
|
||||
authConfig.scope = "profile api offline_access";
|
||||
authConfig.scope = "openid profile api offline_access";
|
||||
authConfig.disableAtHashCheck = true;
|
||||
authConfig.responseType = "code";
|
||||
authConfig.requireHttps = appConfig.getConfig("requireHttps");
|
||||
|
Reference in New Issue
Block a user