mirror of https://github.com/abpframework/abp.git
31 changed files with 548 additions and 51 deletions
@ -1,11 +1,14 @@ |
|||||
import { ABP, eLayoutType } from '@abp/ng.core'; |
import { ABP, eLayoutType } from '@abp/ng.core'; |
||||
|
|
||||
export const ACCOUNT_ROUTES = [ |
export const ACCOUNT_ROUTES = { |
||||
{ |
routes: [ |
||||
name: 'Account', |
{ |
||||
path: 'account', |
name: 'Account', |
||||
invisible: true, |
path: 'account', |
||||
layout: eLayoutType.application, |
invisible: true, |
||||
children: [{ path: 'login', name: 'Login', order: 1 }, { path: 'register', name: 'Register', order: 2 }], |
layout: eLayoutType.application, |
||||
}, |
children: [{ path: 'login', name: 'Login', order: 1 }, { path: 'register', name: 'Register', order: 2 }], |
||||
] as ABP.FullRoute[]; |
}, |
||||
|
] as ABP.FullRoute[], |
||||
|
settings: [], |
||||
|
}; |
||||
|
|||||
@ -0,0 +1,4 @@ |
|||||
|
export function noop() { |
||||
|
const fn = function() {}; |
||||
|
return fn; |
||||
|
} |
||||
@ -1,22 +1,25 @@ |
|||||
import { eLayoutType, ABP } from '@abp/ng.core'; |
import { eLayoutType, ABP } from '@abp/ng.core'; |
||||
|
|
||||
export const IDENTITY_ROUTES = [ |
export const IDENTITY_ROUTES = { |
||||
{ |
routes: [ |
||||
name: 'AbpUiNavigation::Menu:Administration', |
{ |
||||
path: '', |
name: 'AbpUiNavigation::Menu:Administration', |
||||
order: 1, |
path: '', |
||||
wrapper: true, |
order: 1, |
||||
}, |
wrapper: true, |
||||
{ |
}, |
||||
name: 'AbpIdentity::Menu:IdentityManagement', |
{ |
||||
path: 'identity', |
name: 'AbpIdentity::Menu:IdentityManagement', |
||||
order: 1, |
path: 'identity', |
||||
parentName: 'AbpUiNavigation::Menu:Administration', |
order: 1, |
||||
layout: eLayoutType.application, |
parentName: 'AbpUiNavigation::Menu:Administration', |
||||
iconClass: 'fa fa-id-card-o', |
layout: eLayoutType.application, |
||||
children: [ |
iconClass: 'fa fa-id-card-o', |
||||
{ path: 'roles', name: 'AbpIdentity::Roles', order: 2, requiredPolicy: 'AbpIdentity.Roles' }, |
children: [ |
||||
{ path: 'users', name: 'AbpIdentity::Users', order: 1, requiredPolicy: 'AbpIdentity.Users' }, |
{ path: 'roles', name: 'AbpIdentity::Roles', order: 2, requiredPolicy: 'AbpIdentity.Roles' }, |
||||
], |
{ path: 'users', name: 'AbpIdentity::Users', order: 1, requiredPolicy: 'AbpIdentity.Users' }, |
||||
}, |
], |
||||
] as ABP.FullRoute[]; |
}, |
||||
|
] as ABP.FullRoute[], |
||||
|
settings: [], |
||||
|
}; |
||||
|
|||||
@ -0,0 +1 @@ |
|||||
|
<h1> @abp/ng.setting-management </h1> |
||||
@ -0,0 +1,32 @@ |
|||||
|
// Karma configuration file, see link for more information
|
||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
|
||||
|
module.exports = function (config) { |
||||
|
config.set({ |
||||
|
basePath: '', |
||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'], |
||||
|
plugins: [ |
||||
|
require('karma-jasmine'), |
||||
|
require('karma-chrome-launcher'), |
||||
|
require('karma-jasmine-html-reporter'), |
||||
|
require('karma-coverage-istanbul-reporter'), |
||||
|
require('@angular-devkit/build-angular/plugins/karma') |
||||
|
], |
||||
|
client: { |
||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
|
}, |
||||
|
coverageIstanbulReporter: { |
||||
|
dir: require('path').join(__dirname, '../../coverage/setting-management'), |
||||
|
reports: ['html', 'lcovonly', 'text-summary'], |
||||
|
fixWebpackSourcePaths: true |
||||
|
}, |
||||
|
reporters: ['progress', 'kjhtml'], |
||||
|
port: 9876, |
||||
|
colors: true, |
||||
|
logLevel: config.LOG_INFO, |
||||
|
autoWatch: true, |
||||
|
browsers: ['Chrome'], |
||||
|
singleRun: false, |
||||
|
restartOnFileChange: true |
||||
|
}); |
||||
|
}; |
||||
@ -0,0 +1,8 @@ |
|||||
|
{ |
||||
|
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../dist/setting-management", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
}, |
||||
|
"whitelistedNonPeerDependencies": ["@abp/ng.theme.shared"] |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
{ |
||||
|
"name": "@abp/ng.setting-management", |
||||
|
"version": "0.0.1", |
||||
|
"dependencies": { |
||||
|
"@abp/ng.theme.shared": "^0.8.3" |
||||
|
}, |
||||
|
"publishConfig": { |
||||
|
"access": "public" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './setting/setting.component'; |
||||
@ -0,0 +1,17 @@ |
|||||
|
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,176 @@ |
|||||
|
<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"> |
||||
|
<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"></ng-container> |
||||
|
</div> |
||||
|
<div |
||||
|
class="tab-pane fade " |
||||
|
id="T515ccf3324254f41a4a9a6b34b0dae56_1" |
||||
|
role="tabpanel" |
||||
|
aria-labelledby="T515ccf3324254f41a4a9a6b34b0dae56_1-tab" |
||||
|
> |
||||
|
<h2>Lepton theme settings</h2> |
||||
|
<hr class="my-4" /> |
||||
|
|
||||
|
<form id="LeptonThemeSettingsForm" novalidate="novalidate"> |
||||
|
<div class="row"> |
||||
|
<div class="col col-md-12"> |
||||
|
<div> |
||||
|
<div class="form-group"> |
||||
|
<label for="MenuPlacement">Menu placement</label> |
||||
|
<select |
||||
|
class="custom-select form-control" |
||||
|
data-val="true" |
||||
|
data-val-required="The Menu placement field is required." |
||||
|
id="MenuPlacement" |
||||
|
name="MenuPlacement" |
||||
|
><option selected="selected" value="0">Left</option> |
||||
|
<option value="1">Top</option> |
||||
|
</select> |
||||
|
|
||||
|
<span |
||||
|
class="text-danger field-validation-valid" |
||||
|
data-valmsg-for="MenuPlacement" |
||||
|
data-valmsg-replace="true" |
||||
|
></span> |
||||
|
</div> |
||||
|
<div class="form-group"> |
||||
|
<label for="MenuStatus">Menu status</label> |
||||
|
<select |
||||
|
class="custom-select form-control" |
||||
|
data-val="true" |
||||
|
data-val-required="The Menu status field is required." |
||||
|
id="MenuStatus" |
||||
|
name="MenuStatus" |
||||
|
><option selected="selected" value="0">Always opened</option> |
||||
|
<option value="1">Open on hover</option> |
||||
|
</select> |
||||
|
|
||||
|
<span |
||||
|
class="text-danger field-validation-valid" |
||||
|
data-valmsg-for="MenuStatus" |
||||
|
data-valmsg-replace="true" |
||||
|
></span> |
||||
|
</div> |
||||
|
<div class="custom-checkbox custom-control mb-2"> |
||||
|
<input |
||||
|
type="checkbox" |
||||
|
data-val="true" |
||||
|
data-val-required="The Boxed layout field is required." |
||||
|
id="BoxedLayout" |
||||
|
name="BoxedLayout" |
||||
|
value="true" |
||||
|
class="custom-control-input " |
||||
|
/><label class="custom-control-label" for="BoxedLayout">Boxed layout</label> |
||||
|
</div> |
||||
|
</div> |
||||
|
<hr class="my-4" /> |
||||
|
<div> |
||||
|
<button type="submit" class="btn btn-primary" data-busy-text="Processing..."> |
||||
|
<i class="fa fa-save"></i> Save |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<input name="BoxedLayout" type="hidden" value="false" /> |
||||
|
</form> |
||||
|
</div> |
||||
|
<div |
||||
|
class="tab-pane fade " |
||||
|
id="T515ccf3324254f41a4a9a6b34b0dae56_2" |
||||
|
role="tabpanel" |
||||
|
aria-labelledby="T515ccf3324254f41a4a9a6b34b0dae56_2-tab" |
||||
|
> |
||||
|
<h2>Account</h2> |
||||
|
<hr class="my-4" /> |
||||
|
|
||||
|
<form id="AccountSettingsForm" novalidate="novalidate"> |
||||
|
<div class="row"> |
||||
|
<div class="col-md-12"> |
||||
|
<div> |
||||
|
<div class="custom-checkbox custom-control mb-2"> |
||||
|
<input |
||||
|
type="checkbox" |
||||
|
checked="checked" |
||||
|
data-val="true" |
||||
|
data-val-required="The Is self registration enabled field is required." |
||||
|
id="IsSelfRegistrationEnabled" |
||||
|
name="IsSelfRegistrationEnabled" |
||||
|
value="true" |
||||
|
class="custom-control-input " |
||||
|
/><label class="custom-control-label" for="IsSelfRegistrationEnabled" |
||||
|
>Is self registration enabled</label |
||||
|
> |
||||
|
</div> |
||||
|
</div> |
||||
|
<hr class="my-4" /> |
||||
|
<div> |
||||
|
<h4>Two factor login settings</h4> |
||||
|
<div class="custom-checkbox custom-control mb-2"> |
||||
|
<input |
||||
|
type="checkbox" |
||||
|
checked="checked" |
||||
|
data-val="true" |
||||
|
data-val-required="The Is remember browser enabled field is required." |
||||
|
id="IsRememberBrowserEnabled" |
||||
|
name="IsRememberBrowserEnabled" |
||||
|
value="true" |
||||
|
class="custom-control-input " |
||||
|
/><label class="custom-control-label" for="IsRememberBrowserEnabled" |
||||
|
>Is remember browser enabled</label |
||||
|
> |
||||
|
</div> |
||||
|
</div> |
||||
|
<hr class="my-4" /> |
||||
|
<div> |
||||
|
<button type="submit" class="btn btn-primary" data-busy-text="Processing..."> |
||||
|
<i class="fa fa-save"></i> Save |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<input name="IsSelfRegistrationEnabled" type="hidden" value="false" /><input |
||||
|
name="IsRememberBrowserEnabled" |
||||
|
type="hidden" |
||||
|
value="false" |
||||
|
/> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,20 @@ |
|||||
|
import { Component, OnInit } from '@angular/core'; |
||||
|
import { SettingTab } 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]; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './routes'; |
||||
@ -0,0 +1,15 @@ |
|||||
|
import { ABP, eLayoutType } from '@abp/ng.core'; |
||||
|
|
||||
|
export const SETTING_MANAGEMENT_ROUTES = { |
||||
|
routes: [ |
||||
|
{ |
||||
|
name: 'Settings', |
||||
|
path: 'setting-management', |
||||
|
parentName: 'AbpUiNavigation::Menu:Administration', |
||||
|
layout: eLayoutType.application, |
||||
|
order: 6, |
||||
|
iconClass: 'fa fa-cog', |
||||
|
}, |
||||
|
] as ABP.FullRoute[], |
||||
|
settings: [], |
||||
|
}; |
||||
@ -0,0 +1,18 @@ |
|||||
|
import { DynamicLayoutComponent } from '@abp/ng.core'; |
||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { RouterModule, Routes } from '@angular/router'; |
||||
|
import { SettingComponent } from './components/setting/setting.component'; |
||||
|
|
||||
|
const routes: Routes = [ |
||||
|
{ |
||||
|
path: '', |
||||
|
component: DynamicLayoutComponent, |
||||
|
children: [{ path: '', component: SettingComponent }], |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [RouterModule.forChild(routes)], |
||||
|
exports: [RouterModule], |
||||
|
}) |
||||
|
export class SettingManagementRoutingModule {} |
||||
@ -0,0 +1,15 @@ |
|||||
|
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 { ThemeSharedModule } from '@abp/ng.theme.shared'; |
||||
|
import { InitialService } from './components/services/initial.service'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
declarations: [SettingComponent], |
||||
|
imports: [SettingManagementRoutingModule, CoreModule, ThemeSharedModule], |
||||
|
providers: [InitialService], |
||||
|
}) |
||||
|
export class SettingManagementModule { |
||||
|
constructor(@Self() initialService: InitialService) {} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
export * from './lib/setting-management.module'; |
||||
|
export * from './lib/components'; |
||||
|
export * from './lib/constants'; |
||||
@ -0,0 +1,21 @@ |
|||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
|
||||
|
import 'zone.js/dist/zone'; |
||||
|
import 'zone.js/dist/zone-testing'; |
||||
|
import { getTestBed } from '@angular/core/testing'; |
||||
|
import { |
||||
|
BrowserDynamicTestingModule, |
||||
|
platformBrowserDynamicTesting |
||||
|
} from '@angular/platform-browser-dynamic/testing'; |
||||
|
|
||||
|
declare const require: any; |
||||
|
|
||||
|
// First, initialize the Angular testing environment.
|
||||
|
getTestBed().initTestEnvironment( |
||||
|
BrowserDynamicTestingModule, |
||||
|
platformBrowserDynamicTesting() |
||||
|
); |
||||
|
// Then we find all the tests.
|
||||
|
const context = require.context('./', true, /\.spec\.ts$/); |
||||
|
// And load the modules.
|
||||
|
context.keys().map(context); |
||||
@ -0,0 +1,26 @@ |
|||||
|
{ |
||||
|
"extends": "../../tsconfig.json", |
||||
|
"compilerOptions": { |
||||
|
"outDir": "../../out-tsc/lib", |
||||
|
"target": "es2015", |
||||
|
"declaration": true, |
||||
|
"inlineSources": true, |
||||
|
"types": [], |
||||
|
"lib": [ |
||||
|
"dom", |
||||
|
"es2018" |
||||
|
] |
||||
|
}, |
||||
|
"angularCompilerOptions": { |
||||
|
"annotateForClosureCompiler": true, |
||||
|
"skipTemplateCodegen": true, |
||||
|
"strictMetadataEmit": true, |
||||
|
"fullTemplateTypeCheck": true, |
||||
|
"strictInjectionParameters": true, |
||||
|
"enableResourceInlining": true |
||||
|
}, |
||||
|
"exclude": [ |
||||
|
"src/test.ts", |
||||
|
"**/*.spec.ts" |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"extends": "../../tsconfig.json", |
||||
|
"compilerOptions": { |
||||
|
"outDir": "../../out-tsc/spec", |
||||
|
"types": [ |
||||
|
"jasmine", |
||||
|
"node" |
||||
|
] |
||||
|
}, |
||||
|
"files": [ |
||||
|
"src/test.ts" |
||||
|
], |
||||
|
"include": [ |
||||
|
"**/*.spec.ts", |
||||
|
"**/*.d.ts" |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"extends": "../../tslint.json", |
||||
|
"rules": { |
||||
|
"directive-selector": [ |
||||
|
true, |
||||
|
"attribute", |
||||
|
"abp", |
||||
|
"camelCase" |
||||
|
], |
||||
|
"component-selector": [ |
||||
|
true, |
||||
|
"element", |
||||
|
"abp", |
||||
|
"kebab-case" |
||||
|
] |
||||
|
} |
||||
|
} |
||||
@ -1,19 +1,22 @@ |
|||||
import { ABP, eLayoutType } from '@abp/ng.core'; |
import { ABP, eLayoutType } from '@abp/ng.core'; |
||||
|
|
||||
export const TENANT_MANAGEMENT_ROUTES = [ |
export const TENANT_MANAGEMENT_ROUTES = { |
||||
{ |
routes: [ |
||||
name: 'AbpTenantManagement::Menu:TenantManagement', |
{ |
||||
path: 'tenant-management', |
name: 'AbpTenantManagement::Menu:TenantManagement', |
||||
parentName: 'AbpUiNavigation::Menu:Administration', |
path: 'tenant-management', |
||||
layout: eLayoutType.application, |
parentName: 'AbpUiNavigation::Menu:Administration', |
||||
iconClass: 'fa fa-users', |
layout: eLayoutType.application, |
||||
children: [ |
iconClass: 'fa fa-users', |
||||
{ |
children: [ |
||||
path: 'tenants', |
{ |
||||
name: 'AbpTenantManagement::Tenants', |
path: 'tenants', |
||||
order: 1, |
name: 'AbpTenantManagement::Tenants', |
||||
requiredPolicy: 'AbpTenantManagement.Tenants', |
order: 1, |
||||
}, |
requiredPolicy: 'AbpTenantManagement.Tenants', |
||||
], |
}, |
||||
}, |
], |
||||
] as ABP.FullRoute[]; |
}, |
||||
|
] as ABP.FullRoute[], |
||||
|
settings: [], |
||||
|
}; |
||||
|
|||||
@ -0,0 +1,7 @@ |
|||||
|
import { animate, state, style, transition, trigger } from '@angular/animations'; |
||||
|
|
||||
|
export const fade = trigger('fade', [ |
||||
|
state('void', style({ opacity: 1 })), |
||||
|
transition(':enter', [style({ opacity: 0 }), animate(250)]), |
||||
|
transition(':leave', animate(250, style({ opacity: 0 }))), |
||||
|
]); |
||||
@ -1 +1,2 @@ |
|||||
export * from './slide.animation'; |
export * from './fade.animations'; |
||||
|
export * from './slide.animations'; |
||||
|
|||||
@ -1,2 +1,3 @@ |
|||||
export * from './confirmation'; |
export * from './confirmation'; |
||||
export * from './toaster'; |
export * from './toaster'; |
||||
|
export * from './setting-management'; |
||||
|
|||||
@ -0,0 +1,8 @@ |
|||||
|
import { Type } from '@angular/core'; |
||||
|
|
||||
|
export interface SettingTab { |
||||
|
name: string; |
||||
|
order: number; |
||||
|
component: Type<any>; |
||||
|
requiredPolicy?: string; |
||||
|
} |
||||
Loading…
Reference in new issue