16 Commits

Author SHA1 Message Date
4527276254 Changed schema service.
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-24 11:52:05 +02:00
Willem Dantuma
6f52302875 Fix build
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-24 08:40:28 +02:00
Willem Dantuma
cbe27c2add Refactor template selection logic add forpackage decorator
Some checks failed
FarmMaps.Develop/FarmMapsLib/pipeline/head There was a failure building this commit
2020-06-24 08:35:34 +02:00
Willem Dantuma
cd156ab1bc Export packageservice
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-24 07:56:28 +02:00
Willem Dantuma
f9d0e2aee0 Implemented hasclaim directive
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-23 17:51:47 +02:00
Willem Dantuma
253b3d3c90 Fix build
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-23 15:44:14 +02:00
Willem Dantuma
28d4adc571 AW-1330
Some checks failed
FarmMaps.Develop/FarmMapsLib/pipeline/head There was a failure building this commit
2020-06-23 15:39:30 +02:00
Willem Dantuma
925af1e645 Update dependency
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-23 14:18:49 +02:00
Willem Dantuma
4130e0a796 Merge branch 'develop' of https://git.akkerweb.nl/FarmMaps/FarmMapsLib into develop
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-23 13:36:29 +02:00
Willem Dantuma
01933b1602 AW-1330 add atitemlocationitem parameter 2020-06-23 13:36:03 +02:00
0482aa7124 Added provided in root for schema service
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-22 13:37:38 +02:00
75015f6d22 Added schema service
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-22 13:12:02 +02:00
aa3707aa56 Added getSchema method to itemtypes service.
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-22 12:20:02 +02:00
Willem Dantuma
ff06b419f2 Fix top in fullscreen mode
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-12 12:53:43 +02:00
Willem Dantuma
c1c0bd2596 Add start of user/account menu
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-12 12:24:08 +02:00
Willem Dantuma
978cbdabfc Read both farmmaps currentuser and authenticate userinfo
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
2020-06-10 21:53:54 +02:00
29 changed files with 315 additions and 84 deletions

17
package-lock.json generated
View File

@@ -2692,14 +2692,14 @@
} }
}, },
"@farmmaps/common": { "@farmmaps/common": {
"version": "0.0.1-prerelease.267", "version": "0.0.1-prerelease.289",
"resolved": "https://repository.akkerweb.nl/repository/npm-group/@farmmaps/common/-/common-0.0.1-prerelease.267.tgz", "resolved": "https://repository.akkerweb.nl/repository/npm-group/@farmmaps/common/-/common-0.0.1-prerelease.289.tgz",
"integrity": "sha512-U2D6IhxIzpZVtExnRHSP8oNyva9eYCGnZEBy7jWFCY83X4R54w/+PxCB8sK8STf14IJFJcmaSXpHc7Wyd7GrbA==" "integrity": "sha512-TlgNLEpagOtgC24X/olIrK+9ijLbh1gqLKEw4FgoyRV/T4iYBuZewfGvrPmoeKxY6lNdx2nIAhwOmOoRMcH5qQ=="
}, },
"@farmmaps/common-map": { "@farmmaps/common-map": {
"version": "0.0.1-prerelease.267", "version": "0.0.1-prerelease.289",
"resolved": "https://repository.akkerweb.nl/repository/npm-group/@farmmaps/common-map/-/common-map-0.0.1-prerelease.267.tgz", "resolved": "https://repository.akkerweb.nl/repository/npm-group/@farmmaps/common-map/-/common-map-0.0.1-prerelease.289.tgz",
"integrity": "sha512-lZG9abbuVNtFNPKLddYfBRD6qhc6fMslL4wTIKjX8P7yfBM6/W5FAlkcQEJqcTj9k/0fzRlzzKQ2dJouGkctcQ==" "integrity": "sha512-HOECDkP7xwBQqbGx2WmaKgtyalwgcw/7K4CW5eTMT0kSJXc+2JJbCDcQlso5a1DwzaF24bzpR3L1sEGJiPof4w=="
}, },
"@istanbuljs/schema": { "@istanbuljs/schema": {
"version": "0.1.2", "version": "0.1.2",
@@ -9669,6 +9669,11 @@
"deepmerge": "^3.2.0" "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": { "ngx-openlayers": {
"version": "1.0.0-next.13", "version": "1.0.0-next.13",
"resolved": "https://registry.npmjs.org/ngx-openlayers/-/ngx-openlayers-1.0.0-next.13.tgz", "resolved": "https://registry.npmjs.org/ngx-openlayers/-/ngx-openlayers-1.0.0-next.13.tgz",

View File

@@ -19,26 +19,27 @@
"@angular/platform-browser": "~9.1.0", "@angular/platform-browser": "~9.1.0",
"@angular/platform-browser-dynamic": "~9.1.0", "@angular/platform-browser-dynamic": "~9.1.0",
"@angular/router": "~9.1.0", "@angular/router": "~9.1.0",
"@farmmaps/common": ">=0.0.1-prerelease.289 <0.0.1",
"@farmmaps/common-map": ">=0.0.1-prerelease.289 <0.0.1",
"@microsoft/signalr": "^3.1.3", "@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", "@ng-bootstrap/ng-bootstrap": "^6.0",
"@ngrx/effects": "^9.0", "@ngrx/effects": "^9.0",
"@ngrx/router-store": "^9.0", "@ngrx/router-store": "^9.0",
"@ngrx/store": "^9.0", "@ngrx/store": "^9.0",
"ngx-uploadx": "^3.3.4",
"angular-oauth2-oidc": "^9.1", "angular-oauth2-oidc": "^9.1",
"bootstrap": "^4.4.1", "bootstrap": "^4.4.1",
"core-js": "^2.6.11", "core-js": "^2.6.11",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"ngrx-store-localstorage": "^9.0", "ngrx-store-localstorage": "^9.0",
"ngx-bootstrap": "^5.6.1",
"ngx-openlayers": "1.0.0-next.13",
"ngx-uploadx": "^3.3.4",
"ol": "6.1.1",
"resumablejs": "^1.1.0", "resumablejs": "^1.1.0",
"rxjs": "^6.5.4", "rxjs": "^6.5.4",
"tassign": "^1.0.0", "tassign": "^1.0.0",
"tslib": "^1.10.0", "tslib": "^1.10.0",
"zone.js": "~0.10.2", "zone.js": "~0.10.2"
"ngx-openlayers": "1.0.0-next.13",
"ol": "6.1.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.901.0", "@angular-devkit/build-angular": "~0.901.0",

View File

@@ -11,7 +11,7 @@
"@ngrx/router-store": "^9.0", "@ngrx/router-store": "^9.0",
"@ngrx/store": "^9.0", "@ngrx/store": "^9.0",
"tassign": "^1.0.0", "tassign": "^1.0.0",
"@farmmaps/common": ">=0.0.1-prerelease.265 <0.0.1", "@farmmaps/common": ">=0.0.1-prerelease.284 <0.0.1",
"ngx-openlayers": "1.0.0-next.13", "ngx-openlayers": "1.0.0-next.13",
"ol": "6.1.1" "ol": "6.1.1"
} }

View File

@@ -64,6 +64,7 @@ import { WidgetStatusComponent } from './components/widget-status/widget-status.
import { ForChild} from './components/for-item/for-child.decorator'; import { ForChild} from './components/for-item/for-child.decorator';
import {ForItemType } from './components/for-item/for-itemtype.decorator'; import {ForItemType } from './components/for-item/for-itemtype.decorator';
import { ForSourceTask} from './components/for-item/for-sourcetask.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 { PanToLocation} from './components/aol/pan-to-location/pan-to-location.component';
import {LayerSwitcher} from './components/layer-switcher/layer-switcher.component'; import {LayerSwitcher} from './components/layer-switcher/layer-switcher.component';
@@ -143,7 +144,8 @@ export {
IPeriodState, IPeriodState,
ForChild, ForChild,
ForItemType, ForItemType,
ForSourceTask ForSourceTask,
ForPackage
} }
@NgModule({ @NgModule({

View File

@@ -2,7 +2,7 @@ import { Component, Input, OnInit, ComponentFactoryResolver, ViewChild, SimpleCh
import { Feature } from 'ol'; import { Feature } from 'ol';
import { FeatureListComponent,AbstractFeatureListComponent } from '../feature-list/feature-list.component'; import { FeatureListComponent,AbstractFeatureListComponent } from '../feature-list/feature-list.component';
import { WidgetHostDirective } from '../widget-host/widget-host.directive'; 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 mapReducers from '../../reducers/map.reducer';
import * as mapActions from '../../actions/map.actions'; import * as mapActions from '../../actions/map.actions';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@@ -16,7 +16,7 @@ import { Observable } from 'rxjs';
}) })
export class FeatureListContainerComponent { 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> @Input() features: Array<Feature>
@@ -28,30 +28,37 @@ export class FeatureListContainerComponent {
componentRef:any; componentRef:any;
loadComponent(queryState:IQueryState) { loadComponent(queryState:IQueryState) {
var componentFactory: ComponentFactory<AbstractFeatureListComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListComponent); // default let componentFactory: ComponentFactory<AbstractFeatureListComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListComponent); // default
var selected = -1; let selected = -1;
for (var i = 0; i < this.featureLists.length; i++) { let maxMatches =0;
if (this.featureLists[i]['forItemType'] == queryState.itemType && this.featureLists[i]['forChild'] && queryState.parentCode && queryState.parentCode != "") { let showItem = true;
selected = i; for (let i = 0; i < this.featureLists.length; i++) {
break; let matches=0;
} else if (this.featureLists[i]['forItemType'] == queryState.itemType) { if (this.featureLists[i]['forItemType'] && this.featureLists[i]['forItemType'].indexOf(queryState.itemType) >= 0) {
selected = i; matches++;
break; }
if(this.featureLists[i]['forChild'] && queryState.parentCode && queryState.parentCode != "") {
matches++;
}
if(matches > maxMatches) {
selected=i;
maxMatches = matches;
} }
} }
if (selected >= 0) { 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) { if (this.featureLists[selected]['collapseSearch'] === true) {
this.store.dispatch(new mapActions.CollapseSearch()); this.store.dispatch(new mapActions.CollapseSearch());
} }
} }
const viewContainerRef = this.widgetHost.viewContainerRef; const viewContainerRef = this.widgetHost.viewContainerRef;
viewContainerRef.clear(); viewContainerRef.clear();
if(showItem) {
this.componentRef = viewContainerRef.createComponent(componentFactory); this.componentRef = viewContainerRef.createComponent(componentFactory);
(<AbstractFeatureListComponent>this.componentRef.instance).features = null; (<AbstractFeatureListComponent>this.componentRef.instance).features = null;
(<AbstractFeatureListComponent>this.componentRef.instance).queryState = queryState; (<AbstractFeatureListComponent>this.componentRef.instance).queryState = queryState;
(<AbstractFeatureListComponent>this.componentRef.instance).selectedFeature = null; (<AbstractFeatureListComponent>this.componentRef.instance).selectedFeature = null;
}
} }
ngOnInit() { ngOnInit() {

View File

@@ -23,11 +23,23 @@ export class FeatureListFeatureContainerComponent {
loadComponent() { loadComponent() {
var componentFactory: ComponentFactory<AbstractFeatureListFeatureComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListFeatureComponent); // default var componentFactory: ComponentFactory<AbstractFeatureListFeatureComponent> = this.componentFactoryResolver.resolveComponentFactory(FeatureListFeatureComponent); // default
for (var i = 0; i < this.featureLists.length; i++) {
let selected = -1;
let maxMatches =0;
for (let i = 0; i < this.featureLists.length; i++) {
let matches=0;
if (this.featureLists[i]['forItemType'] == this.feature.get("itemType")) { if (this.featureLists[i]['forItemType'] == this.feature.get("itemType")) {
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.featureLists[i]['constructor'] as any); matches++;
}
if(matches > maxMatches) {
selected=i;
maxMatches = matches;
} }
} }
if (selected >= 0) {
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.featureLists[selected]['constructor'] as any);
}
const viewContainerRef = this.widgetHost.viewContainerRef; const viewContainerRef = this.widgetHost.viewContainerRef;
viewContainerRef.clear(); viewContainerRef.clear();

View File

@@ -0,0 +1,5 @@
export function ForPackage(packageCode: string) {
return function (constructor:Function) {
constructor.prototype.forPackage = packageCode;
};
}

View File

@@ -23,15 +23,28 @@ export class ItemListItemContainerComponent {
loadComponent() { loadComponent() {
var componentFactory: ComponentFactory<AbstractItemListItemComponent> = this.componentFactoryResolver.resolveComponentFactory(ItemListItemComponent); // default var componentFactory: ComponentFactory<AbstractItemListItemComponent> = this.componentFactoryResolver.resolveComponentFactory(ItemListItemComponent); // default
for (var i = 0; i < this.itemComponentList.length; i++) {
if (this.itemComponentList[i]['forItemType'] && let selected = -1;
this.itemComponentList[i]['forItemType'].indexOf(this.item.itemType) >= 0 && let maxMatches =0;
this.itemComponentList[i]['forSourceTask'] && let showItem = true;
this.itemComponentList[i]['forSourceTask'].indexOf(this.item.sourceTask) >= 0 ) for (let i = 0; i < this.itemComponentList.length; i++) {
{ let matches=0;
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.itemComponentList[i]['constructor'] as any); if (this.itemComponentList[i]['forItemType'] && this.itemComponentList[i]['forItemType'].indexOf(this.item.itemType) >= 0) {
matches++;
} }
} if (this.itemComponentList[i]['forSourceTask'] && this.itemComponentList[i]['forSourceTask'].indexOf(this.item.sourceTask) >= 0) {
matches++;
}
if(matches > maxMatches) {
selected=i;
maxMatches = matches;
}
}
if (selected >= 0) {
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.itemComponentList[selected]['constructor'] as any);
}
const viewContainerRef = this.widgetHost.viewContainerRef; const viewContainerRef = this.widgetHost.viewContainerRef;
viewContainerRef.clear(); viewContainerRef.clear();

View File

@@ -23,22 +23,28 @@ export class SelectedItemContainerComponent {
loadComponent() { loadComponent() {
let componentFactory: ComponentFactory<AbstractSelectedItemComponent> = this.componentFactoryResolver.resolveComponentFactory(SelectedItemComponent); // default 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) { let selected = -1;
componentFactory = this.componentFactoryResolver.resolveComponentFactory(firstComponentWithTypeAndTask['constructor'] as any); let maxMatches =0;
} else { let showItem = true;
let firstComponentWithType = this.selectedItemComponents for (let i = 0; i < this.selectedItemComponents.length; i++) {
.find(value => value['forSourceTask'] == null && let matches=0;
value['forItemType'] == this.item.itemType); if (this.selectedItemComponents[i]['forItemType'] && this.selectedItemComponents[i]['forItemType'].indexOf(this.item.itemType) >= 0) {
matches++;
if (firstComponentWithType) { }
componentFactory = this.componentFactoryResolver.resolveComponentFactory(firstComponentWithType['constructor'] as any); if (this.selectedItemComponents[i]['forSourceTask'] && this.selectedItemComponents[i]['forSourceTask'].indexOf(this.item.sourceTask) >= 0) {
matches++;
}
if(matches > maxMatches) {
selected=i;
maxMatches = matches;
} }
} }
if (selected >= 0) {
componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.selectedItemComponents[selected]['constructor'] as any);
}
const viewContainerRef = this.widgetHost.viewContainerRef; const viewContainerRef = this.widgetHost.viewContainerRef;
viewContainerRef.clear(); viewContainerRef.clear();

View File

@@ -7,9 +7,10 @@ import { commonReducers, ItemTypeService, IItem, Item, ItemService, FolderServic
import { Router, ActivatedRoute, ParamMap, Event } from '@angular/router'; import { Router, ActivatedRoute, ParamMap, Event } from '@angular/router';
import { ForItemType } from '../for-item/for-itemtype.decorator'; import { ForItemType } from '../for-item/for-itemtype.decorator';
import { AbstractSelectedItemComponent } from '../selected-item/selected-item.component'; import { AbstractSelectedItemComponent } from '../selected-item/selected-item.component';
import { Observable } from 'rxjs'; import { Observable,of } from 'rxjs';
import {GeoJSON} from 'ol/format'; import {GeoJSON} from 'ol/format';
import {getArea} from 'ol/sphere'; import {getArea} from 'ol/sphere';
import { withLatestFrom,switchMap,combineLatest } from 'rxjs/operators';
@ForItemType("vnd.farmmaps.itemtype.cropfield") @ForItemType("vnd.farmmaps.itemtype.cropfield")
@@ -38,6 +39,25 @@ export class SelectedItemCropfieldComponent extends AbstractSelectedItemComponen
} }
ngOnInit() { 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);
}));
} }
} }

View File

@@ -4,6 +4,7 @@ import { IItemTypes } from '../models/item.types';
import { IListItem } from '../models/list.item'; import { IListItem } from '../models/list.item';
import { IUser } from '../models/user'; import { IUser } from '../models/user';
import { IItem } from '../models/item'; import { IItem } from '../models/item';
import { UserInfo } from 'angular-oauth2-oidc';
export const INITUSER = '[AppCommon] InitUser'; export const INITUSER = '[AppCommon] InitUser';
export const INITUSERSUCCESS = '[AppCommon] InitUserSuccess'; export const INITUSERSUCCESS = '[AppCommon] InitUserSuccess';
@@ -62,7 +63,7 @@ export class InitUser implements Action {
export class InitUserSuccess implements Action { export class InitUserSuccess implements Action {
readonly type = INITUSERSUCCESS; readonly type = INITUSERSUCCESS;
constructor(public user:IUser ) { } constructor(public user:IUser,public userinfo:UserInfo ) { }
} }
export class InitUserPackagesSuccess implements Action { export class InitUserPackagesSuccess implements Action {

View File

@@ -9,6 +9,7 @@ import { OAuthModule, OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
//components //components
import { ItemTypeService } from './services/itemtype.service'; import { ItemTypeService } from './services/itemtype.service';
import { SchemaService } from './services/schema.service';
import { FolderService } from './services/folder.service'; import { FolderService } from './services/folder.service';
import { TimespanService } from './services/timespan.service'; import { TimespanService } from './services/timespan.service';
import { ItemService } from './services/item.service'; import { ItemService } from './services/item.service';
@@ -28,6 +29,7 @@ import { ResumableFileUploadService } from './components/resumable-file-upload/r
import { NgbDateNativeAdapter } from './services/date-adapter.service' import { NgbDateNativeAdapter } from './services/date-adapter.service'
import { AuthConfigFactory } from './shared/authconfigFactory'; import { AuthConfigFactory } from './shared/authconfigFactory';
import { StateSerializerService } from './services/state-serializer.service'; import { StateSerializerService } from './services/state-serializer.service';
import { PackageService } from './services/package.service';
export { export {
FolderService, FolderService,
@@ -47,7 +49,9 @@ export {
AuthCallbackGuard, AuthCallbackGuard,
ResumableFileUploadService, ResumableFileUploadService,
NgbDateNativeAdapter, NgbDateNativeAdapter,
StateSerializerService StateSerializerService,
SchemaService,
PackageService
}; };
@NgModule({ @NgModule({
@@ -71,7 +75,7 @@ export class AppCommonServiceModule {
{ {
provide: APP_INITIALIZER, provide: APP_INITIALIZER,
useFactory: appConfigFactory, useFactory: appConfigFactory,
deps: [Injector, AppConfig, OAuthService, AuthConfigFactory, OAuthStorage,ItemTypeService], deps: [Injector, AppConfig, OAuthService, AuthConfigFactory, OAuthStorage, ItemTypeService],
multi: true multi: true
}, },
{ {

View File

@@ -31,6 +31,8 @@ import { TimespanComponent } from './components/timespan/timespan.component';
import { TagInputComponent } from './components/tag-input/tag-input.component'; import { TagInputComponent } from './components/tag-input/tag-input.component';
import { MenuBackgroundComponent } from './components/menu-background/menu-background.component'; import { MenuBackgroundComponent } from './components/menu-background/menu-background.component';
import { HasPackageDirective} from './components/has-package/has-package.directive'; 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 { Alert } from './enumerations/alert.enum';
import { IEventMessage } from './models/event.message'; import { IEventMessage } from './models/event.message';
import { IItem, Item } from './models/item'; import { IItem, Item } from './models/item';
@@ -60,7 +62,9 @@ export {
SidePanelComponent, SidePanelComponent,
TimespanComponent, TimespanComponent,
TagInputComponent, TagInputComponent,
UserMenuComponent,
HasPackageDirective, HasPackageDirective,
HasClaimDirective,
Alert, Alert,
IEventMessage, IEventMessage,
IItem, IItem,
@@ -109,7 +113,9 @@ export {
TagInputComponent, TagInputComponent,
SessionClearedComponent, SessionClearedComponent,
MenuBackgroundComponent, MenuBackgroundComponent,
HasPackageDirective HasPackageDirective,
HasClaimDirective,
UserMenuComponent
], ],
exports: [ exports: [
NgbModule, NgbModule,
@@ -127,7 +133,9 @@ export {
TagInputComponent, TagInputComponent,
SessionClearedComponent, SessionClearedComponent,
MenuBackgroundComponent, MenuBackgroundComponent,
HasPackageDirective HasPackageDirective,
HasClaimDirective,
UserMenuComponent
] ]
}) })
export class AppCommonModule { export class AppCommonModule {

View File

@@ -23,4 +23,7 @@
<ng-container *ngIf="showUploadProgress"> <ng-container *ngIf="showUploadProgress">
<fm-resumable-file-upload></fm-resumable-file-upload> <fm-resumable-file-upload></fm-resumable-file-upload>
</ng-container> </ng-container>
<div class="user-menu">
<fm-user-menu [user]="user|async"></fm-user-menu>
</div>
</div> </div>

View File

@@ -76,3 +76,14 @@ body { background: #f1f1f1; line-height: 18px; user-select:none;}
.logo { .logo {
margin-left: 1rem; margin-left: 1rem;
} }
.user-menu {
transition: top 0.5s ease-out;
position: absolute;
top:0.25em;
right:1em;
}
.fullscreen > .user-menu {
top:1em;
}

View File

@@ -3,6 +3,7 @@ import { Router, NavigationStart, NavigationEnd, RouteConfigLoadStart, RouteConf
import { Meta, Title, MetaDefinition } from '@angular/platform-browser';import { DOCUMENT } from "@angular/common"; import { Meta, Title, MetaDefinition } from '@angular/platform-browser';import { DOCUMENT } from "@angular/common";
import { Subscription , Observable } from 'rxjs'; import { Subscription , Observable } from 'rxjs';
import { Store, Action } from '@ngrx/store'; import { Store, Action } from '@ngrx/store';
import { IUser } from '../../models/user';
//AppCommon //AppCommon
import { IEventMessage } from '../../models/event.message'; import { IEventMessage } from '../../models/event.message';
@@ -34,6 +35,7 @@ export class AppComponent implements OnInit, OnDestroy {
public fullScreen: Observable<boolean>; public fullScreen: Observable<boolean>;
public routeLoading: Observable<boolean>; public routeLoading: Observable<boolean>;
public menuVisible: Observable<boolean>; public menuVisible: Observable<boolean>;
public user:Observable<IUser>;
@Input() showUploadProgress: boolean =true; @Input() showUploadProgress: boolean =true;
constructor( constructor(
@@ -88,6 +90,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.fullScreen = this.store.select(appReducers.selectGetFullScreen); this.fullScreen = this.store.select(appReducers.selectGetFullScreen);
this.routeLoading = this.store.select(appReducers.selectGetRouteLoading); this.routeLoading = this.store.select(appReducers.selectGetRouteLoading);
this.menuVisible = this.store.select(appReducers.SelectGetMenuVisible); this.menuVisible = this.store.select(appReducers.SelectGetMenuVisible);
this.user = this.store.select(appReducers.SelectGetUser);
this.InstallRouteEventHandler(); this.InstallRouteEventHandler();
this.InstallEventServiceEventHandler(); this.InstallEventServiceEventHandler();
} }

View File

@@ -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;
}
});
}
}

View File

@@ -0,0 +1,3 @@
<div *ngIf="user">
<span class="rounded-circle menu-button" [title]="user.name">{{getLetter()}}</span>
</div>

View File

@@ -0,0 +1,10 @@
.menu-button {
background-color: purple;
color:white;
display: inline-block;
width: 2.5em;
height: 2.5em;
line-height: 2.5em;
text-align: center;
font-size: 1rem;
}

View File

@@ -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();
});
});

View File

@@ -0,0 +1,21 @@
import { Component, OnInit,Input } from '@angular/core';
import { IUser } from '../../models/user';
@Component({
selector: 'fm-user-menu',
templateUrl: './user-menu.component.html',
styleUrls: ['./user-menu.component.scss']
})
export class UserMenuComponent implements OnInit {
@Input() user:IUser;
constructor() { }
ngOnInit(): void {
}
getLetter():string {
return this.user.name ? this.user.name.substr(0,1).toUpperCase():"";
}
}

View File

@@ -1,9 +1,9 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Router } from '@angular/router'; 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 { Store, Action } from '@ngrx/store';
import { Effect, Actions,ofType } from '@ngrx/effects'; 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 { withLatestFrom,mergeMap,switchMap,map,catchError} from 'rxjs/operators';
import * as appCommonActions from '../actions/app-common.actions'; import * as appCommonActions from '../actions/app-common.actions';
import * as appCommonReducers from '../reducers/app-common.reducer'; import * as appCommonReducers from '../reducers/app-common.reducer';
@@ -44,9 +44,10 @@ export class AppCommonEffects {
ofType(appCommonActions.INITUSER), ofType(appCommonActions.INITUSER),
withLatestFrom(this.store$.select(appCommonReducers.selectGetInitialized)), withLatestFrom(this.store$.select(appCommonReducers.selectGetInitialized)),
switchMap(([action, initialized]) => { switchMap(([action, initialized]) => {
if(!initialized) { if(!initialized) {
return this.userService$.getCurrentUser().pipe( 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)))) catchError(error => of(new appCommonActions.Fail(error))))
} else { } else {
return []; return [];

View File

@@ -4,5 +4,6 @@ export interface IItemType {
editor?: string; editor?: string;
isFolder?: boolean; isFolder?: boolean;
iconColor?: string; iconColor?: string;
schema?: string;
extraAttributes?: string; extraAttributes?: string;
} }

View File

@@ -1,5 +1,6 @@
export interface IUser { export interface IUser {
code?: string; code?: string;
name?: string; name?: string;
email?: string; email?: string;
} claims: any;
}

View File

@@ -36,7 +36,17 @@ export function reducer(state = initialState, action: appCommonActions.Actions )
switch (action.type) { switch (action.type) {
case appCommonActions.INITUSERSUCCESS: { case appCommonActions.INITUSERSUCCESS: {
let a = action as 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: { case appCommonActions.INITROOTSUCCESS: {
let a = action as appCommonActions.InitRootSuccess; let a = action as appCommonActions.InitRootSuccess;

View File

@@ -65,13 +65,13 @@ export class ItemService {
return this.httpClient.get<IItem>(`${this.ApiEndpoint()}/api/v1/items/${code}/${itemType}`); 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(); var params = new HttpParams();
params = params.append("it", itemType); if(itemType) params = params.append("it", itemType);
if(dataFilter != null){ if(dataFilter) params = params.append("df", JSON.stringify(dataFilter));
params = params.append("df", JSON.stringify(dataFilter)); if(atItemLocationItemCode) params = params.append("ail",atItemLocationItemCode);
} if(indexed) params = params.append("ind",indexed?"true":"false");
params = params.append("lvl", itemType); if(level) params = params.append("lvl", level.toFixed());
return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/`, { params: params }).pipe(map(ia => ia.map(i => this.parseDates(i)))); return this.httpClient.get<IItem[]>(`${this.ApiEndpoint()}/api/v1/items/`, { params: params }).pipe(map(ia => ia.map(i => this.parseDates(i))));
} }

View File

@@ -9,9 +9,9 @@ export class ItemTypeService {
public itemTypes: IItemTypes; public itemTypes: IItemTypes;
private httpClient: HttpClient; private httpClient: HttpClient;
constructor(xhrBackend: HttpXhrBackend) { constructor(xhrBackend: HttpXhrBackend) {
this.httpClient = new HttpClient(xhrBackend); this.httpClient = new HttpClient(xhrBackend);
} }
getIcon(itemType: string) { getIcon(itemType: string) {
var icon = "fa fa-file-o"; var icon = "fa fa-file-o";
@@ -31,6 +31,12 @@ export class ItemTypeService {
return extraAttributes; return extraAttributes;
} }
getSchema(itemType: string): string {
let schema = null;
if (this.itemTypes[itemType]) schema = this.itemTypes[itemType].schema;
return schema;
}
hasViewer(item: IItem) { hasViewer(item: IItem) {
let itemType: string = item.itemType; let itemType: string = item.itemType;
if (this.itemTypes[itemType]) return this.itemTypes[itemType].viewer !== undefined; if (this.itemTypes[itemType]) return this.itemTypes[itemType].viewer !== undefined;
@@ -49,7 +55,7 @@ export class ItemTypeService {
} }
public load(config:AppConfig): Promise<any> { public load(config:AppConfig): Promise<any> {
var url = `${ config.getConfig("apiEndPoint")}/api/v1/itemtypes/` var url = `${ config.getConfig("apiEndPoint")}/api/v1/itemtypes/`
return this.httpClient.get(url) return this.httpClient.get(url)
.toPromise() .toPromise()
@@ -59,4 +65,4 @@ export class ItemTypeService {
}) })
.catch(error => this.itemTypes = null); .catch(error => this.itemTypes = null);
}; };
} }

View File

@@ -0,0 +1,22 @@
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {AppConfig} from '../shared/app.config';
import {Observable} from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class SchemaService {
constructor(private httpClient: HttpClient, private appConfig: AppConfig) {
}
ApiEndpoint() {
return this.appConfig.getConfig('apiEndPoint');
}
/** Takes decoded schema url id */
public getSchema(id): Observable<string> {
const encodedId = encodeURIComponent(id);
return this.httpClient.get<any>(`${this.ApiEndpoint()}/api/v1/schema/${encodedId}`);
}
}

View File

@@ -14,7 +14,7 @@ export class Id4AuthconfigFactory implements IAuthconfigFactory {
authConfig.redirectUri = window.location.origin + "/cb"; authConfig.redirectUri = window.location.origin + "/cb";
authConfig.clientId = appConfig.getConfig("clientId"); authConfig.clientId = appConfig.getConfig("clientId");
authConfig.customQueryParams = { audience: appConfig.getConfig("audience") }; authConfig.customQueryParams = { audience: appConfig.getConfig("audience") };
authConfig.scope = "profile api offline_access"; authConfig.scope = "openid profile api offline_access";
authConfig.disableAtHashCheck = true; authConfig.disableAtHashCheck = true;
authConfig.responseType = "code"; authConfig.responseType = "code";
authConfig.requireHttps = appConfig.getConfig("requireHttps"); authConfig.requireHttps = appConfig.getConfig("requireHttps");