mirror of https://github.com/abpframework/abp
				
				
				
			Merge branch 'dev' of https://github.com/volosoft/abp into dev
	
		
	
				
					
				
			
						commit
						f32ebc84cb
					
				| @ -1,20 +0,0 @@ | ||||
| import { ModuleWithProviders, NgModule } from '@angular/core'; | ||||
| import { Options } from './models/options'; | ||||
| import { ACCOUNT_OPTIONS, optionsFactory } from './tokens/options.token'; | ||||
| 
 | ||||
| @NgModule({}) | ||||
| export class RootAccountModule { | ||||
|   static forRoot(options = {} as Options): ModuleWithProviders { | ||||
|     return { | ||||
|       ngModule: RootAccountModule, | ||||
|       providers: [ | ||||
|         { provide: ACCOUNT_OPTIONS, useValue: options }, | ||||
|         { | ||||
|           provide: 'ACCOUNT_OPTIONS', | ||||
|           useFactory: optionsFactory, | ||||
|           deps: [ACCOUNT_OPTIONS], | ||||
|         }, | ||||
|       ], | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,174 @@ | ||||
| import { | ||||
|   Directive, | ||||
|   EmbeddedViewRef, | ||||
|   Input, | ||||
|   IterableChangeRecord, | ||||
|   IterableChanges, | ||||
|   IterableDiffer, | ||||
|   IterableDiffers, | ||||
|   OnChanges, | ||||
|   TemplateRef, | ||||
|   TrackByFunction, | ||||
|   ViewContainerRef, | ||||
| } from '@angular/core'; | ||||
| import compare from 'just-compare'; | ||||
| 
 | ||||
| export type CompareFn<T = any> = (value: T, comparison: T) => boolean; | ||||
| 
 | ||||
| class AbpForContext { | ||||
|   constructor(public $implicit: any, public index: number, public count: number, public list: any[]) {} | ||||
| } | ||||
| 
 | ||||
| class RecordView { | ||||
|   constructor(public record: IterableChangeRecord<any>, public view: EmbeddedViewRef<AbpForContext>) {} | ||||
| } | ||||
| 
 | ||||
| @Directive({ | ||||
|   selector: '[abpFor]', | ||||
| }) | ||||
| export class ForDirective implements OnChanges { | ||||
|   @Input('abpForOf') | ||||
|   items: any[]; | ||||
| 
 | ||||
|   @Input('abpForOrderBy') | ||||
|   orderBy: string; | ||||
| 
 | ||||
|   @Input('abpForOrderDir') | ||||
|   orderDir: 'ASC' | 'DESC'; | ||||
| 
 | ||||
|   @Input('abpForFilterBy') | ||||
|   filterBy: string; | ||||
| 
 | ||||
|   @Input('abpForFilterVal') | ||||
|   filterVal: any; | ||||
| 
 | ||||
|   @Input('abpForTrackBy') | ||||
|   trackBy; | ||||
| 
 | ||||
|   @Input('abpForCompareBy') | ||||
|   compareBy: CompareFn; | ||||
| 
 | ||||
|   @Input('abpForEmptyRef') | ||||
|   emptyRef: TemplateRef<any>; | ||||
| 
 | ||||
|   private differ: IterableDiffer<any>; | ||||
| 
 | ||||
|   private isShowEmptyRef: boolean; | ||||
| 
 | ||||
|   get compareFn(): CompareFn { | ||||
|     return this.compareBy || compare; | ||||
|   } | ||||
| 
 | ||||
|   get trackByFn(): TrackByFunction<any> { | ||||
|     return this.trackBy || ((index: number, item: any) => (item as any).id || index); | ||||
|   } | ||||
| 
 | ||||
|   constructor( | ||||
|     private tempRef: TemplateRef<AbpForContext>, | ||||
|     private vcRef: ViewContainerRef, | ||||
|     private differs: IterableDiffers, | ||||
|   ) {} | ||||
| 
 | ||||
|   private iterateOverAppliedOperations(changes: IterableChanges<any>) { | ||||
|     const rw: RecordView[] = []; | ||||
| 
 | ||||
|     changes.forEachOperation((record: IterableChangeRecord<any>, previousIndex: number, currentIndex: number) => { | ||||
|       if (record.previousIndex == null) { | ||||
|         const view = this.vcRef.createEmbeddedView( | ||||
|           this.tempRef, | ||||
|           new AbpForContext(null, -1, -1, this.items), | ||||
|           currentIndex, | ||||
|         ); | ||||
| 
 | ||||
|         rw.push(new RecordView(record, view)); | ||||
|       } else if (currentIndex == null) { | ||||
|         this.vcRef.remove(previousIndex); | ||||
|       } else { | ||||
|         const view = this.vcRef.get(previousIndex); | ||||
|         this.vcRef.move(view, currentIndex); | ||||
| 
 | ||||
|         rw.push(new RecordView(record, view as EmbeddedViewRef<AbpForContext>)); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     for (let i = 0, l = rw.length; i < l; i++) { | ||||
|       rw[i].view.context.$implicit = rw[i].record.item; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private iterateOverAttachedViews(changes: IterableChanges<any>) { | ||||
|     for (let i = 0, l = this.vcRef.length; i < l; i++) { | ||||
|       const viewRef = this.vcRef.get(i) as EmbeddedViewRef<AbpForContext>; | ||||
|       viewRef.context.index = i; | ||||
|       viewRef.context.count = l; | ||||
|       viewRef.context.list = this.items; | ||||
|     } | ||||
| 
 | ||||
|     changes.forEachIdentityChange((record: IterableChangeRecord<any>) => { | ||||
|       const viewRef = this.vcRef.get(record.currentIndex) as EmbeddedViewRef<AbpForContext>; | ||||
|       viewRef.context.$implicit = record.item; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   private projectItems(items: any[]): void { | ||||
|     if (!items.length && this.emptyRef) { | ||||
|       this.vcRef.createEmbeddedView(this.emptyRef).rootNodes; | ||||
|       this.isShowEmptyRef = true; | ||||
| 
 | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (this.emptyRef && this.isShowEmptyRef) { | ||||
|       this.vcRef.clear(); | ||||
|       this.isShowEmptyRef = false; | ||||
|     } | ||||
| 
 | ||||
|     if (!this.differ && items) { | ||||
|       this.differ = this.differs.find(items).create(this.trackByFn); | ||||
|     } | ||||
| 
 | ||||
|     if (this.differ) { | ||||
|       const changes = this.differ.diff(items); | ||||
| 
 | ||||
|       if (changes) { | ||||
|         this.iterateOverAppliedOperations(changes); | ||||
|         this.iterateOverAttachedViews(changes); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private sortItems(items: any[]) { | ||||
|     if (this.orderBy) { | ||||
|       items.sort((a, b) => (a[this.orderBy] > b[this.orderBy] ? 1 : a[this.orderBy] < b[this.orderBy] ? -1 : 0)); | ||||
|     } else { | ||||
|       items.sort(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ngOnChanges() { | ||||
|     let items = [...this.items] as any[]; | ||||
|     if (!Array.isArray(items)) return; | ||||
| 
 | ||||
|     const compareFn = this.compareFn; | ||||
| 
 | ||||
|     if (typeof this.filterBy !== 'undefined') { | ||||
|       items = items.filter(item => compareFn(item[this.filterBy], this.filterVal)); | ||||
|     } | ||||
| 
 | ||||
|     switch (this.orderDir) { | ||||
|       case 'ASC': | ||||
|         this.sortItems(items); | ||||
|         this.projectItems(items); | ||||
|         break; | ||||
| 
 | ||||
|       case 'DESC': | ||||
|         this.sortItems(items); | ||||
|         items.reverse(); | ||||
|         this.projectItems(items); | ||||
|         break; | ||||
| 
 | ||||
|       default: | ||||
|         this.projectItems(items); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| export * from './autofocus.directive'; | ||||
| export * from './ellipsis.directive'; | ||||
| export * from './for.directive'; | ||||
| export * from './form-submit.directive'; | ||||
| export * from './permission.directive'; | ||||
| export * from './visibility.directive'; | ||||
|  | ||||
| @ -1,11 +0,0 @@ | ||||
| import { ModuleWithProviders, NgModule } from '@angular/core'; | ||||
| 
 | ||||
| @NgModule({}) | ||||
| export class RootFeatureManagementModule { | ||||
|   static forRoot(): ModuleWithProviders { | ||||
|     return { | ||||
|       ngModule: RootFeatureManagementModule, | ||||
|       providers: [], | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| @ -1,3 +1,2 @@ | ||||
| export * from './lib/root-feature-management.module'; | ||||
| export * from './lib/feature-management.module'; | ||||
| export * from './lib/components'; | ||||
|  | ||||
| @ -1,11 +0,0 @@ | ||||
| import { ModuleWithProviders, NgModule } from '@angular/core'; | ||||
| 
 | ||||
| @NgModule({}) | ||||
| export class RootIdentityModule { | ||||
|   static forRoot(): ModuleWithProviders { | ||||
|     return { | ||||
|       ngModule: RootIdentityModule, | ||||
|       providers: [], | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| @ -1,11 +0,0 @@ | ||||
| import { ModuleWithProviders, NgModule } from '@angular/core'; | ||||
| 
 | ||||
| @NgModule({}) | ||||
| export class RootPermissionManagementModule { | ||||
|   static forRoot(): ModuleWithProviders { | ||||
|     return { | ||||
|       ngModule: RootPermissionManagementModule, | ||||
|       providers: [], | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| @ -1 +0,0 @@ | ||||
| export * from './setting/setting.component'; | ||||
| @ -1,17 +0,0 @@ | ||||
| import { SettingTab } from '@abp/ng.theme.shared'; | ||||
| import { Injectable, OnInit } from '@angular/core'; | ||||
| import { Router } from '@angular/router'; | ||||
| import snq from 'snq'; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class InitialService { | ||||
|   public settings: SettingTab[]; | ||||
| 
 | ||||
|   constructor(private router: Router) { | ||||
|     this.settings = this.router.config | ||||
|       .map(route => snq(() => route.data.routes.settings)) | ||||
|       .filter(settings => settings && settings.length) | ||||
|       .reduce((acc, val) => [...acc, ...val], []) | ||||
|       .sort((a, b) => a.order - b.order); | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| <div class="row entry-row"> | ||||
|   <div class="col-auto"> | ||||
|     <h1 class="content-header-title">{{ 'AbpSettingManagement::Settings' | abpLocalization }}</h1> | ||||
|   </div> | ||||
|   <!-- <div id="breadcrumb" class="col-md-auto pl-md-0"> | ||||
|     <abp-breadcrumb></abp-breadcrumb> | ||||
|   </div> --> | ||||
|   <div class="col"> | ||||
|     <div class="text-lg-right pt-2" id="AbpContentToolbar"></div> | ||||
|   </div> | ||||
| </div> | ||||
| 
 | ||||
| <div id="SettingManagementWrapper"> | ||||
|   <div class="card"> | ||||
|     <div class="card-body"> | ||||
|       <div *ngIf="!settingManagementService.settings.length" class="text-center"> | ||||
|         <i class="fa fa-spinner fa-spin"></i> | ||||
|       </div> | ||||
|       <div class="row"> | ||||
|         <div class="col-3"> | ||||
|           <ul class="nav flex-column nav-pills" id="nav-tab" role="tablist"> | ||||
|             <li | ||||
|               *abpFor=" | ||||
|                 let setting of settingManagementService.settings; | ||||
|                 trackBy: trackByFn; | ||||
|                 orderBy: 'order'; | ||||
|                 orderDir: 'ASC' | ||||
|               " | ||||
|               (click)="settingManagementService.setSelected(setting)" | ||||
|               class="nav-item" | ||||
|               [abpPermission]="setting.requiredPolicy" | ||||
|             > | ||||
|               <a | ||||
|                 class="nav-link" | ||||
|                 [id]="setting.name + '-tab'" | ||||
|                 role="tab" | ||||
|                 [class.active]="setting.name === settingManagementService.selected.name" | ||||
|                 >{{ setting.name | abpLocalization }}</a | ||||
|               > | ||||
|             </li> | ||||
|           </ul> | ||||
|         </div> | ||||
|         <div class="col-9"> | ||||
|           <div *ngIf="settingManagementService.settings.length" class="tab-content"> | ||||
|             <div | ||||
|               class="tab-pane fade show active" | ||||
|               [id]="settingManagementService.selected.name + '-tab'" | ||||
|               role="tabpanel" | ||||
|             > | ||||
|               <h2>{{ settingManagementService.selected.name | abpLocalization }}</h2> | ||||
|               <hr class="my-4" /> | ||||
|               <router-outlet></router-outlet> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| @ -0,0 +1,37 @@ | ||||
| import { eLayoutType } from '@abp/ng.core'; | ||||
| import { SettingTab } from '@abp/ng.theme.shared'; | ||||
| import { Component, TrackByFunction } from '@angular/core'; | ||||
| import { Router } from '@angular/router'; | ||||
| import { timer } from 'rxjs'; | ||||
| import { SettingManagementService } from '../services/setting-management.service'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'abp-setting-layout', | ||||
|   templateUrl: './setting-layout.component.html', | ||||
| }) | ||||
| export class SettingLayoutComponent { | ||||
|   // required for dynamic component
 | ||||
|   static type = eLayoutType.setting; | ||||
| 
 | ||||
|   trackByFn: TrackByFunction<SettingTab> = (_, item) => item.name; | ||||
| 
 | ||||
|   constructor(public settingManagementService: SettingManagementService, private router: Router) { | ||||
|     if ( | ||||
|       settingManagementService.selected && | ||||
|       this.router.url !== settingManagementService.selected.url && | ||||
|       settingManagementService.settings.length | ||||
|     ) { | ||||
|       settingManagementService.setSelected(settingManagementService.settings[0]); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ngOnDestroy() {} | ||||
| 
 | ||||
|   ngAfterViewInit() { | ||||
|     timer(250).subscribe(() => { | ||||
|       if (!this.settingManagementService.settings.length) { | ||||
|         this.settingManagementService.setSettings(); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| @ -1,51 +0,0 @@ | ||||
| <div class="row entry-row"> | ||||
|   <div class="col-auto"> | ||||
|     <h1 class="content-header-title">{{ 'AbpSettingManagement::Settings' | abpLocalization }}</h1> | ||||
|   </div> | ||||
|   <div id="breadcrumb" class="col-md-auto pl-md-0"> | ||||
|     <abp-breadcrumb></abp-breadcrumb> | ||||
|   </div> | ||||
|   <div class="col"> | ||||
|     <div class="text-lg-right pt-2" id="AbpContentToolbar"></div> | ||||
|   </div> | ||||
| </div> | ||||
| 
 | ||||
| <div id="SettingManagementWrapper"> | ||||
|   <div class="card"> | ||||
|     <div class="card-body"> | ||||
|       <div class="row"> | ||||
|         <div class="col-3"> | ||||
|           <ul class="nav flex-column nav-pills" id="T515ccf3324254f41a4a9a6b34b0dae56" role="tablist"> | ||||
|             <li | ||||
|               *ngFor="let setting of settings" | ||||
|               (click)="selected = setting" | ||||
|               class="nav-item" | ||||
|               [abpPermission]="setting.requiredPolicy" | ||||
|             > | ||||
|               <a | ||||
|                 class="nav-link" | ||||
|                 [id]="setting.name + '-tab'" | ||||
|                 role="tab" | ||||
|                 [class.active]="setting.name === selected.name" | ||||
|                 >{{ setting.name | abpLocalization }}</a | ||||
|               > | ||||
|             </li> | ||||
|           </ul> | ||||
|         </div> | ||||
|         <div class="col-9"> | ||||
|           <div class="tab-content"> | ||||
|             <div class="tab-pane fade show active" [id]="selected.name + '-tab'" role="tabpanel"> | ||||
|               <h2>{{ selected.name | abpLocalization }}</h2> | ||||
|               <hr class="my-4" /> | ||||
| 
 | ||||
|               <ng-container | ||||
|                 *ngComponentOutlet="selected.component" | ||||
|                 [abpPermission]="selected.requiredPolicy" | ||||
|               ></ng-container> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| @ -1,20 +0,0 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { SettingTab, fade } from '@abp/ng.theme.shared'; | ||||
| import { InitialService } from '../services/initial.service'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'abp-setting', | ||||
|   templateUrl: './setting.component.html', | ||||
| }) | ||||
| export class SettingComponent implements OnInit { | ||||
|   settings: SettingTab[]; | ||||
| 
 | ||||
|   selected = {} as SettingTab; | ||||
| 
 | ||||
|   constructor(private initialService: InitialService) {} | ||||
| 
 | ||||
|   ngOnInit() { | ||||
|     this.settings = this.initialService.settings; | ||||
|     this.selected = this.settings[0]; | ||||
|   } | ||||
| } | ||||
| @ -1,11 +0,0 @@ | ||||
| import { ModuleWithProviders, NgModule } from '@angular/core'; | ||||
| 
 | ||||
| @NgModule({}) | ||||
| export class RootSettingManagementModule { | ||||
|   static forRoot(): ModuleWithProviders { | ||||
|     return { | ||||
|       ngModule: RootSettingManagementModule, | ||||
|       providers: [], | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,53 @@ | ||||
| import { SettingTab } from '@abp/ng.theme.shared'; | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { Router, RouteConfigLoadEnd, NavigationEnd } from '@angular/router'; | ||||
| import { Navigate } from '@ngxs/router-plugin'; | ||||
| import { Store } from '@ngxs/store'; | ||||
| import { filter } from 'rxjs/operators'; | ||||
| import { takeUntilDestroy } from '@abp/ng.core'; | ||||
| import { Subscription, timer } from 'rxjs'; | ||||
| 
 | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class SettingManagementService { | ||||
|   settings: SettingTab[] = []; | ||||
| 
 | ||||
|   selected = {} as SettingTab; | ||||
| 
 | ||||
|   constructor(private router: Router, private store: Store) { | ||||
|     let timeout: Subscription; | ||||
|     this.router.events | ||||
|       .pipe( | ||||
|         filter(event => event instanceof RouteConfigLoadEnd), | ||||
|         takeUntilDestroy(this), | ||||
|       ) | ||||
|       .subscribe(event => { | ||||
|         if (timeout) timeout.unsubscribe(); | ||||
|         timeout = timer(150).subscribe(() => { | ||||
|           this.setSettings(); | ||||
|         }); | ||||
|       }); | ||||
|   } | ||||
| 
 | ||||
|   ngOnDestroy() {} | ||||
| 
 | ||||
|   setSettings() { | ||||
|     setTimeout(() => { | ||||
|       const route = this.router.config.find(r => r.path === 'setting-management'); | ||||
|       this.settings = route.data.settings.sort((a, b) => a.order - b.order); | ||||
|       this.checkSelected(); | ||||
|     }, 0); | ||||
|   } | ||||
| 
 | ||||
|   checkSelected() { | ||||
|     this.selected = this.settings.find(setting => setting.url === this.router.url) || ({} as SettingTab); | ||||
| 
 | ||||
|     if (!this.selected.name && this.settings.length) { | ||||
|       this.setSelected(this.settings[0]); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   setSelected(selected: SettingTab) { | ||||
|     this.selected = selected; | ||||
|     this.store.dispatch(new Navigate([selected.url])); | ||||
|   } | ||||
| } | ||||
| @ -1,15 +1,14 @@ | ||||
| import { CoreModule, noop } from '@abp/ng.core'; | ||||
| import { NgModule, ModuleWithProviders, APP_INITIALIZER, Self } from '@angular/core'; | ||||
| import { SettingComponent } from './components/setting/setting.component'; | ||||
| import { SettingManagementRoutingModule } from './setting-management-routing.module'; | ||||
| import { CoreModule } from '@abp/ng.core'; | ||||
| import { ThemeSharedModule } from '@abp/ng.theme.shared'; | ||||
| import { InitialService } from './components/services/initial.service'; | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { SettingLayoutComponent } from './components/setting-layout.component'; | ||||
| import { SettingManagementRoutingModule } from './setting-management-routing.module'; | ||||
| 
 | ||||
| export const SETTING_LAYOUT = SettingLayoutComponent; | ||||
| 
 | ||||
| @NgModule({ | ||||
|   declarations: [SettingComponent], | ||||
|   declarations: [SETTING_LAYOUT], | ||||
|   imports: [SettingManagementRoutingModule, CoreModule, ThemeSharedModule], | ||||
|   providers: [InitialService], | ||||
|   entryComponents: [SETTING_LAYOUT], | ||||
| }) | ||||
| export class SettingManagementModule { | ||||
|   constructor(@Self() initialService: InitialService) {} | ||||
| } | ||||
| export class SettingManagementModule {} | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| export * from './lib/root-setting-management.module'; | ||||
| export * from './lib/setting-management.module'; | ||||
| export * from './lib/components'; | ||||
| export * from './lib/constants'; | ||||
| export * from './lib/components/setting-layout.component'; | ||||
|  | ||||
| @ -1,11 +0,0 @@ | ||||
| import { ModuleWithProviders, NgModule } from '@angular/core'; | ||||
| 
 | ||||
| @NgModule({}) | ||||
| export class RootTenantManagementModule { | ||||
|   static forRoot(): ModuleWithProviders { | ||||
|     return { | ||||
|       ngModule: RootTenantManagementModule, | ||||
|       providers: [], | ||||
|     }; | ||||
|   } | ||||
| } | ||||
| @ -1,8 +1,6 @@ | ||||
| import { Type } from '@angular/core'; | ||||
| 
 | ||||
| export interface SettingTab { | ||||
|   name: string; | ||||
|   order: number; | ||||
|   component: Type<any>; | ||||
|   requiredPolicy?: string; | ||||
|   url?: string; | ||||
| } | ||||
|  | ||||
					Loading…
					
					
				
		Reference in new issue
	
	 Yunus Emre Kalkan
						Yunus Emre Kalkan