From 825eaa74afdaed65eb347519a577dd6795d54dc4 Mon Sep 17 00:00:00 2001 From: Giancarlo Corredor Catino Date: Wed, 25 Sep 2019 02:38:57 -0500 Subject: [PATCH 01/48] added spanish translation --- docs/es/Index.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/es/Index.md diff --git a/docs/es/Index.md b/docs/es/Index.md new file mode 100644 index 0000000000..772a0afc13 --- /dev/null +++ b/docs/es/Index.md @@ -0,0 +1,31 @@ +# Documentación de ABP + +ABP es un **marco de desarrollo de código abierto** enfocado en el desarrollo de aplicaciones web basadas en ASP.NET Core, pero tambien soporta el desarrollo de otro tipo de aplicaciones. + +Explora el menú de navegación de la izquierda para profundizar en la documentación. + +## Estado del proyecto + +ABP es la **próxima generación** del marco de desarrollo de código abierto [ASP.NET Boilerplate](https://aspnetboilerplate.com/). Actualmente se encuentra en una fase preliminar y no está listo para su uso en producción. La documentación todavía está en progreso y se encuentra lejos de estar completa. + +Para aplicaciones en fase de producción o que lo vayan a estar en el corto plazo, se sugiere usar el marco de desarrollo [ASP.NET Boilerplate](https://aspnetboilerplate.com/) el cual tiene un completo conjunto de funciones, es maduro, mantenido y actualizado activamente. + +## Primeros pasos + +La manera más facil para iniciar un proyecto con ABP es usar las plantillas de inicio: + +* [Plantilla ASP.NET Core MVC (Razor Pages) UI](Getting-Started-AspNetCore-MVC-Template.md) +* [Plantilla Angular UI](Getting-Started-Angular-Template.md) + +Si quieres iniciar desde cero (con un proyecto vacío), entonces instala manualmente el marco de desarrollo ABP y usa los siguientes tutoriales: + +* [Aplicación de Consola](Getting-Started-Console-Application.md) +* [Aplicación web con ASP.NET Core](Getting-Started-AspNetCore-Application.md) + +## Código fuente + +ABP está hospedado en GitHub. Mira el [código fuente](https://github.com/abpframework/abp). + +## ¿Quieres contribuir? + +ABP es un proyecto de código abierto impulsado por la comunidad. Mira la [guía de contribución](Contribution/Index.md) si quieres formar parte de este proyecto. \ No newline at end of file From 2eef238d87ba27221a396a635f9e109c5f6b20b2 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Wed, 25 Sep 2019 13:29:34 +0300 Subject: [PATCH 02/48] Update AbpInputTagHelperService.cs --- .../TagHelpers/Form/AbpInputTagHelperService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index fb549d3067..75fe4f23e7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -227,17 +227,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form if (string.IsNullOrEmpty(TagHelper.Label)) { - return await GetLabelAsHtmlUsingTagHelperAsync(context, output, isCheckbox) + GetRequiredSymbol(context, output, inputTag); + return await GetLabelAsHtmlUsingTagHelperAsync(context, output, isCheckbox) + GetRequiredSymbol(context, output); } var checkboxClass = isCheckbox ? "class=\"custom-control-label\" " : ""; return "" + GetRequiredSymbol(context, output, inputTag); + "" + GetRequiredSymbol(context, output); } - protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) + protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output) { if (!TagHelper.DisplayRequiredSymbol) { From 3175914bfe7a45e933b8a1c088466b14910c4c64 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Wed, 25 Sep 2019 16:04:30 +0300 Subject: [PATCH 03/48] Update Acme.BookStore.Web.csproj --- .../BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/samples/BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj b/samples/BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj index fd2a489d47..5dab7d1cfe 100644 --- a/samples/BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj +++ b/samples/BookStore/src/Acme.BookStore.Web/Acme.BookStore.Web.csproj @@ -5,8 +5,6 @@ netcoreapp3.0 OutOfProcess - 8.0 - enable $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; true true From 389efdb6c3a5c0585d1424da1d9e860d537dcc41 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 26 Sep 2019 09:04:21 +0300 Subject: [PATCH 04/48] feature(setting-management-config): create library and move settings config to here --- npm/ng-packs/angular.json | 35 +++++++++++ npm/ng-packs/package.json | 12 ++-- .../packages/core/src/lib/enums/common.ts | 3 + .../packages/core/src/lib/models/common.ts | 4 ++ .../src/lib/plugins/config/config.plugin.ts | 19 +++--- .../src/lib/identity-routing.module.ts | 19 +++--- .../setting-management-config/README.md | 24 ++++++++ .../setting-management-config/karma.conf.js | 32 ++++++++++ .../setting-management-config/ng-package.json | 7 +++ .../setting-management-config/package.json | 7 +++ .../setting-management-config.service.ts | 18 ++++++ .../lib/setting-management-config.module.ts | 8 +++ .../src/public-api.ts | 1 + .../setting-management-config/src/test.ts | 21 +++++++ .../tsconfig.lib.json | 26 ++++++++ .../tsconfig.spec.json | 17 ++++++ .../setting-management-config/tslint.json | 17 ++++++ .../setting-management/ng-package.json | 2 +- .../packages/setting-management/package.json | 3 +- .../components/setting-layout.component.ts | 29 --------- ...html => setting-management.component.html} | 23 +++---- .../setting-management.component.ts | 52 ++++++++++++++++ .../src/lib/constants/index.ts | 1 - .../src/lib/constants/routes.ts | 14 ----- .../services/setting-management.service.ts | 61 ------------------- .../lib/setting-management-routing.module.ts | 10 ++- .../src/lib/setting-management.module.ts | 7 +-- .../setting-management/src/public-api.ts | 3 +- .../theme-shared/src/lib/contants/styles.ts | 2 +- .../src/lib/models/setting-management.ts | 4 +- templates/app/angular/angular.json | 27 ++++++-- templates/app/angular/package.json | 24 ++++---- 32 files changed, 349 insertions(+), 183 deletions(-) create mode 100644 npm/ng-packs/packages/setting-management-config/README.md create mode 100644 npm/ng-packs/packages/setting-management-config/karma.conf.js create mode 100644 npm/ng-packs/packages/setting-management-config/ng-package.json create mode 100644 npm/ng-packs/packages/setting-management-config/package.json create mode 100644 npm/ng-packs/packages/setting-management-config/src/lib/services/setting-management-config.service.ts create mode 100644 npm/ng-packs/packages/setting-management-config/src/lib/setting-management-config.module.ts create mode 100644 npm/ng-packs/packages/setting-management-config/src/public-api.ts create mode 100644 npm/ng-packs/packages/setting-management-config/src/test.ts create mode 100644 npm/ng-packs/packages/setting-management-config/tsconfig.lib.json create mode 100644 npm/ng-packs/packages/setting-management-config/tsconfig.spec.json create mode 100644 npm/ng-packs/packages/setting-management-config/tslint.json delete mode 100644 npm/ng-packs/packages/setting-management/src/lib/components/setting-layout.component.ts rename npm/ng-packs/packages/setting-management/src/lib/components/{setting-layout.component.html => setting-management.component.html} (59%) create mode 100644 npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts delete mode 100644 npm/ng-packs/packages/setting-management/src/lib/constants/index.ts delete mode 100644 npm/ng-packs/packages/setting-management/src/lib/constants/routes.ts delete mode 100644 npm/ng-packs/packages/setting-management/src/lib/services/setting-management.service.ts diff --git a/npm/ng-packs/angular.json b/npm/ng-packs/angular.json index 617e907f3f..773d9794f7 100644 --- a/npm/ng-packs/angular.json +++ b/npm/ng-packs/angular.json @@ -288,6 +288,41 @@ } } } + }, + "setting-management-config": { + "projectType": "library", + "root": "packages/setting-management-config", + "sourceRoot": "packages/setting-management-config/src", + "prefix": "abp", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "packages/setting-management-config/tsconfig.lib.json", + "project": "packages/setting-management-config/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "packages/setting-management-config/src/test.ts", + "tsConfig": "packages/setting-management-config/tsconfig.spec.json", + "karmaConfig": "packages/setting-management-config/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "packages/setting-management-config/tsconfig.lib.json", + "packages/setting-management-config/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } } }, "defaultProject": "core" diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index b647954502..009bc9d5f5 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -5,10 +5,10 @@ "abpng": "abpng" }, "devDependencies": { - "@abp/ng.core": "^0.8.3", - "@abp/ng.feature-management": "^0.8.3", - "@abp/ng.permission-management": "^0.8.3", - "@abp/ng.theme.shared": "^0.8.3", + "@abp/ng.core": "^0.9.0", + "@abp/ng.feature-management": "^0.9.0", + "@abp/ng.permission-management": "^0.9.0", + "@abp/ng.theme.shared": "^0.9.0", "@angular-devkit/build-angular": "~0.803.5", "@angular-devkit/build-ng-packagr": "~0.803.5", "@angular/animations": "~8.2.7", @@ -55,9 +55,11 @@ "symlink-manager": "^1.3.0", "ts-node": "~7.0.0", "tsickle": "^0.35.0", - "tslib": "^1.9.0", "tslint": "~5.15.0", "typescript": "~3.5.3", "zone.js": "~0.9.1" + }, + "dependencies": { + "tslib": "^1.10.0" } } diff --git a/npm/ng-packs/packages/core/src/lib/enums/common.ts b/npm/ng-packs/packages/core/src/lib/enums/common.ts index 3b953b8ac7..1ecc29406c 100644 --- a/npm/ng-packs/packages/core/src/lib/enums/common.ts +++ b/npm/ng-packs/packages/core/src/lib/enums/common.ts @@ -2,5 +2,8 @@ export const enum eLayoutType { account = 'account', application = 'application', empty = 'empty', + /** + * @deprecated since version 0.9.0 + */ setting = 'setting', } diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index a5089760f0..95bf490e91 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -43,4 +43,8 @@ export namespace ABP { id: string; name: string; } + + export interface Dictionary { + [key: string]: T; + } } diff --git a/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts b/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts index 5add16c31e..42e8003abe 100644 --- a/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts +++ b/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts @@ -8,6 +8,8 @@ import clone from 'just-clone'; export const NGXS_CONFIG_PLUGIN_OPTIONS = new InjectionToken('NGXS_CONFIG_PLUGIN_OPTIONS'); +export const ABP_ROUTES = [] as ABP.FullRoute[]; + @Injectable() export class ConfigPlugin implements NgxsPlugin { private initialized: boolean = false; @@ -38,27 +40,20 @@ export class ConfigPlugin implements NgxsPlugin { } function transformRoutes(routes: Routes = [], wrappers: ABP.FullRoute[] = []): any { - const abpRoutes: ABP.FullRoute[] = routes - .filter(route => { - return snq(() => route.data.routes.routes.find(r => r.path === route.path), false); - }) - .reduce((acc, val) => [...acc, ...val.data.routes.routes], []); - - wrappers = abpRoutes.filter(ar => ar.wrapper); + wrappers = ABP_ROUTES.filter(ar => ar.wrapper); const transformed = [] as ABP.FullRoute[]; routes - .filter(route => (route.data || {}).routes && (route.component || route.loadChildren)) + .filter(route => route.component || route.loadChildren) .forEach(route => { - const abpPackage = abpRoutes.find( - abp => abp.path.toLowerCase() === route.path.toLowerCase() && snq(() => route.data.routes.routes.length, false), - ); + const abpPackage = ABP_ROUTES.find(abp => abp.path.toLowerCase() === route.path.toLowerCase()); + const { length } = transformed; if (abpPackage) { transformed.push(abpPackage); } - if (transformed.length === length) { + if (transformed.length === length && (route.data || {}).routes) { transformed.push({ ...route.data.routes, path: route.path, diff --git a/npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts b/npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts index fbbecffc9b..ffe155a94f 100644 --- a/npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts +++ b/npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts @@ -9,21 +9,20 @@ import { UserResolver } from './resolvers/users.resolver'; const routes: Routes = [ { path: '', redirectTo: 'roles', pathMatch: 'full' }, { - path: 'roles', + path: '', component: DynamicLayoutComponent, canActivate: [AuthGuard, PermissionGuard], - data: { requiredPolicy: 'AbpIdentity.Roles' }, - children: [{ path: '', component: RolesComponent, resolve: [RoleResolver] }], - }, - { - path: 'users', - component: DynamicLayoutComponent, - canActivate: [AuthGuard, PermissionGuard], - data: { requiredPolicy: 'AbpIdentity.Users' }, children: [ { - path: '', + path: 'roles', + component: RolesComponent, + resolve: [RoleResolver], + data: { requiredPolicy: 'AbpIdentity.Roles' }, + }, + { + path: 'users', component: UsersComponent, + data: { requiredPolicy: 'AbpIdentity.Users' }, resolve: [RoleResolver, UserResolver], }, ], diff --git a/npm/ng-packs/packages/setting-management-config/README.md b/npm/ng-packs/packages/setting-management-config/README.md new file mode 100644 index 0000000000..9e69e2dce1 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/README.md @@ -0,0 +1,24 @@ +# SettingManagementConfig + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.7. + +## Code scaffolding + +Run `ng generate component component-name --project setting-management-config` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project setting-management-config`. +> Note: Don't forget to add `--project setting-management-config` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build setting-management-config` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build setting-management-config`, go to the dist folder `cd dist/setting-management-config` and run `npm publish`. + +## Running unit tests + +Run `ng test setting-management-config` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/npm/ng-packs/packages/setting-management-config/karma.conf.js b/npm/ng-packs/packages/setting-management-config/karma.conf.js new file mode 100644 index 0000000000..7ff4863cb0 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/karma.conf.js @@ -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-config'), + 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 + }); +}; diff --git a/npm/ng-packs/packages/setting-management-config/ng-package.json b/npm/ng-packs/packages/setting-management-config/ng-package.json new file mode 100644 index 0000000000..0d24be4f85 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/setting-management-config", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/npm/ng-packs/packages/setting-management-config/package.json b/npm/ng-packs/packages/setting-management-config/package.json new file mode 100644 index 0000000000..9a9f49aa0a --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/package.json @@ -0,0 +1,7 @@ +{ + "name": "@abp/ng.setting-management.config", + "version": "0.0.1", + "publishConfig": { + "access": "public" + } +} diff --git a/npm/ng-packs/packages/setting-management-config/src/lib/services/setting-management-config.service.ts b/npm/ng-packs/packages/setting-management-config/src/lib/services/setting-management-config.service.ts new file mode 100644 index 0000000000..851f435449 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/src/lib/services/setting-management-config.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { ABP_ROUTES, eLayoutType } from '@abp/ng.core'; + +@Injectable({ + providedIn: 'root', +}) +export class SettingManagementConfigService { + constructor() { + ABP_ROUTES.push({ + name: 'Settings', + path: 'setting-management', + parentName: 'AbpUiNavigation::Menu:Administration', + layout: eLayoutType.application, + order: 6, + iconClass: 'fa fa-cog', + }); + } +} diff --git a/npm/ng-packs/packages/setting-management-config/src/lib/setting-management-config.module.ts b/npm/ng-packs/packages/setting-management-config/src/lib/setting-management-config.module.ts new file mode 100644 index 0000000000..c11e712fa4 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/src/lib/setting-management-config.module.ts @@ -0,0 +1,8 @@ +import { NgModule, APP_INITIALIZER } from '@angular/core'; +import { SettingManagementConfigService } from './services/setting-management-config.service'; +import { noop } from '@abp/ng.core'; + +@NgModule({ + providers: [{ provide: APP_INITIALIZER, deps: [SettingManagementConfigService], useFactory: noop, multi: true }], +}) +export class SettingManagementConfigModule {} diff --git a/npm/ng-packs/packages/setting-management-config/src/public-api.ts b/npm/ng-packs/packages/setting-management-config/src/public-api.ts new file mode 100644 index 0000000000..236ed82079 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/src/public-api.ts @@ -0,0 +1 @@ +export * from './lib/setting-management-config.module'; diff --git a/npm/ng-packs/packages/setting-management-config/src/test.ts b/npm/ng-packs/packages/setting-management-config/src/test.ts new file mode 100644 index 0000000000..978c64fb83 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/src/test.ts @@ -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); diff --git a/npm/ng-packs/packages/setting-management-config/tsconfig.lib.json b/npm/ng-packs/packages/setting-management-config/tsconfig.lib.json new file mode 100644 index 0000000000..bd23948e59 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/tsconfig.lib.json @@ -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" + ] +} diff --git a/npm/ng-packs/packages/setting-management-config/tsconfig.spec.json b/npm/ng-packs/packages/setting-management-config/tsconfig.spec.json new file mode 100644 index 0000000000..16da33db07 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/npm/ng-packs/packages/setting-management-config/tslint.json b/npm/ng-packs/packages/setting-management-config/tslint.json new file mode 100644 index 0000000000..8c3919ea62 --- /dev/null +++ b/npm/ng-packs/packages/setting-management-config/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "abp", + "camelCase" + ], + "component-selector": [ + true, + "element", + "abp", + "kebab-case" + ] + } +} diff --git a/npm/ng-packs/packages/setting-management/ng-package.json b/npm/ng-packs/packages/setting-management/ng-package.json index e5ba9f97fc..7a08dda36b 100644 --- a/npm/ng-packs/packages/setting-management/ng-package.json +++ b/npm/ng-packs/packages/setting-management/ng-package.json @@ -4,5 +4,5 @@ "lib": { "entryFile": "src/public-api.ts" }, - "whitelistedNonPeerDependencies": ["@abp/ng.theme.shared"] + "whitelistedNonPeerDependencies": ["@abp/ng.theme.shared", "@abp/ng.setting-management.config"] } diff --git a/npm/ng-packs/packages/setting-management/package.json b/npm/ng-packs/packages/setting-management/package.json index f02d0f33b2..f0ebfe66c8 100644 --- a/npm/ng-packs/packages/setting-management/package.json +++ b/npm/ng-packs/packages/setting-management/package.json @@ -2,7 +2,8 @@ "name": "@abp/ng.setting-management", "version": "0.9.0", "dependencies": { - "@abp/ng.theme.shared": "^0.9.0" + "@abp/ng.theme.shared": "^0.9.0", + "@abp/ng.setting-management.config": "^0.0.1" }, "publishConfig": { "access": "public" diff --git a/npm/ng-packs/packages/setting-management/src/lib/components/setting-layout.component.ts b/npm/ng-packs/packages/setting-management/src/lib/components/setting-layout.component.ts deleted file mode 100644 index 1c9d702a01..0000000000 --- a/npm/ng-packs/packages/setting-management/src/lib/components/setting-layout.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -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 = (_, 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() {} -} diff --git a/npm/ng-packs/packages/setting-management/src/lib/components/setting-layout.component.html b/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.html similarity index 59% rename from npm/ng-packs/packages/setting-management/src/lib/components/setting-layout.component.html rename to npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.html index 379e368e9d..030a020418 100644 --- a/npm/ng-packs/packages/setting-management/src/lib/components/setting-layout.component.html +++ b/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.html @@ -13,20 +13,15 @@
-
+
-
-
- +
+
+
diff --git a/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts b/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts new file mode 100644 index 0000000000..8b485e87c8 --- /dev/null +++ b/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts @@ -0,0 +1,52 @@ +import { SettingTab } from '@abp/ng.theme.shared'; +import { Component, TrackByFunction } from '@angular/core'; +import { Router } from '@angular/router'; +import { ABP, ConfigState } from '@abp/ng.core'; +import { Store } from '@ngxs/store'; + +@Component({ + selector: 'abp-setting-management', + templateUrl: './setting-management.component.html', +}) +export class SettingManagementComponent { + settings: SettingTab[] = []; + + selected = {} as SettingTab; + + trackByFn: TrackByFunction = (_, item) => item.name; + + constructor(private router: Router, private store: Store) {} + + ngOnInit() { + this.setSettings(); + } + + setSettings() { + const { data } = this.router.config.find(r => r.path === 'setting-management') as { + data: ABP.Dictionary; + }; + + if (data) { + Object.keys(data).forEach(key => { + const element = data[key]; + if (element && element.component) { + if ( + element.requiredPolicy && + !this.store.selectSnapshot(ConfigState.getGrantedPolicy(element.requiredPolicy)) + ) { + return; + } + + this.settings.push(element); + } + }); + + if (this.settings.length) { + this.settings = this.settings.sort((a, b) => a.order - b.order); + this.selected = this.settings[0]; + } + } + } + + ngOnDestroy() {} +} diff --git a/npm/ng-packs/packages/setting-management/src/lib/constants/index.ts b/npm/ng-packs/packages/setting-management/src/lib/constants/index.ts deleted file mode 100644 index a3820983e2..0000000000 --- a/npm/ng-packs/packages/setting-management/src/lib/constants/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './routes'; diff --git a/npm/ng-packs/packages/setting-management/src/lib/constants/routes.ts b/npm/ng-packs/packages/setting-management/src/lib/constants/routes.ts deleted file mode 100644 index 3f47c95eb7..0000000000 --- a/npm/ng-packs/packages/setting-management/src/lib/constants/routes.ts +++ /dev/null @@ -1,14 +0,0 @@ -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[], -}; diff --git a/npm/ng-packs/packages/setting-management/src/lib/services/setting-management.service.ts b/npm/ng-packs/packages/setting-management/src/lib/services/setting-management.service.ts deleted file mode 100644 index 79878b1717..0000000000 --- a/npm/ng-packs/packages/setting-management/src/lib/services/setting-management.service.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { SettingTab } from '@abp/ng.theme.shared'; -import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; -import { Navigate } from '@ngxs/router-plugin'; -import { Store, Actions, ofActionSuccessful } from '@ngxs/store'; -import { Subject } from 'rxjs'; -import { ConfigState, GetAppConfiguration } from '@abp/ng.core'; -import { OAuthService } from 'angular-oauth2-oidc'; -import { takeUntil } from 'rxjs/operators'; - -@Injectable({ providedIn: 'root' }) -export class SettingManagementService { - settings: SettingTab[] = []; - - selected = {} as SettingTab; - - private destroy$ = new Subject(); - - constructor( - private actions: Actions, - private router: Router, - private store: Store, - private oAuthService: OAuthService, - ) { - setTimeout(() => this.setSettings(), 0); - - this.actions - .pipe(ofActionSuccessful(GetAppConfiguration)) - .pipe(takeUntil(this.destroy$)) - .subscribe(() => { - if (this.oAuthService.hasValidAccessToken()) { - this.setSettings(); - } - }); - } - - ngOnDestroy() { - this.destroy$.next(); - } - - setSettings() { - const route = this.router.config.find(r => r.path === 'setting-management'); - this.settings = (route.data.settings as SettingTab[]) - .filter(setting => this.store.selectSnapshot(ConfigState.getGrantedPolicy(setting.requiredPolicy))) - .sort((a, b) => a.order - b.order); - this.checkSelected(); - } - - 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])); - } -} diff --git a/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts b/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts index e401df16de..d1cb780777 100644 --- a/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts +++ b/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts @@ -1,15 +1,13 @@ -import { DynamicLayoutComponent } from '@abp/ng.core'; import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { SETTING_MANAGEMENT_ROUTES } from './constants/routes'; -import { SettingLayoutComponent } from './components/setting-layout.component'; +import { SettingManagementComponent } from './components/setting-management.component'; +import { DynamicLayoutComponent } from '@abp/ng.core'; const routes: Routes = [ { - path: 'setting-management', + path: '', component: DynamicLayoutComponent, - children: [{ path: '', component: SettingLayoutComponent }], - data: { routes: SETTING_MANAGEMENT_ROUTES, settings: [] }, + children: [{ path: '', component: SettingManagementComponent }], }, ]; diff --git a/npm/ng-packs/packages/setting-management/src/lib/setting-management.module.ts b/npm/ng-packs/packages/setting-management/src/lib/setting-management.module.ts index b3959e6650..397c581587 100644 --- a/npm/ng-packs/packages/setting-management/src/lib/setting-management.module.ts +++ b/npm/ng-packs/packages/setting-management/src/lib/setting-management.module.ts @@ -1,14 +1,11 @@ import { CoreModule } from '@abp/ng.core'; import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { NgModule } from '@angular/core'; -import { SettingLayoutComponent } from './components/setting-layout.component'; import { SettingManagementRoutingModule } from './setting-management-routing.module'; - -export const SETTING_LAYOUT = SettingLayoutComponent; +import { SettingManagementComponent } from './components/setting-management.component'; @NgModule({ - declarations: [SETTING_LAYOUT], + declarations: [SettingManagementComponent], imports: [SettingManagementRoutingModule, CoreModule, ThemeSharedModule], - entryComponents: [SETTING_LAYOUT], }) export class SettingManagementModule {} diff --git a/npm/ng-packs/packages/setting-management/src/public-api.ts b/npm/ng-packs/packages/setting-management/src/public-api.ts index 5343d9e457..8027d769f9 100644 --- a/npm/ng-packs/packages/setting-management/src/public-api.ts +++ b/npm/ng-packs/packages/setting-management/src/public-api.ts @@ -1,3 +1,2 @@ export * from './lib/setting-management.module'; -export * from './lib/constants'; -export * from './lib/components/setting-layout.component'; +export * from './lib/components/setting-management.component'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts b/npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts index 0388f3b51c..e971887270 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts @@ -172,7 +172,7 @@ export default ` } to { - transform: translateY(5px); + transform: translateY(0px); opacity: 1; } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/setting-management.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/setting-management.ts index 1b8c36412e..427fa54e41 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/setting-management.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/setting-management.ts @@ -1,6 +1,8 @@ +import { Type } from '@angular/core'; + export interface SettingTab { + component: Type; name: string; order: number; requiredPolicy?: string; - url?: string; } diff --git a/templates/app/angular/angular.json b/templates/app/angular/angular.json index 6b5e7df965..8a844d2562 100644 --- a/templates/app/angular/angular.json +++ b/templates/app/angular/angular.json @@ -23,7 +23,10 @@ "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", "aot": false, - "assets": ["src/favicon.ico", "src/assets"], + "assets": [ + "src/favicon.ico", + "src/assets" + ], "styles": [ "src/styles.scss", "node_modules/bootstrap/dist/css/bootstrap.min.css", @@ -97,7 +100,10 @@ "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.spec.json", "karmaConfig": "karma.conf.js", - "assets": ["src/favicon.ico", "src/assets"], + "assets": [ + "src/favicon.ico", + "src/assets" + ], "styles": [ "src/styles.scss", "node_modules/bootstrap/dist/css/bootstrap.min.css", @@ -112,8 +118,14 @@ "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { - "tsConfig": ["tsconfig.app.json", "tsconfig.spec.json", "e2e/tsconfig.json"], - "exclude": ["**/node_modules/**"] + "tsConfig": [ + "tsconfig.app.json", + "tsconfig.spec.json", + "e2e/tsconfig.json" + ], + "exclude": [ + "**/node_modules/**" + ] } }, "e2e": { @@ -131,5 +143,8 @@ } } }, - "defaultProject": "myProjectName" -} + "defaultProject": "myProjectName", + "cli": { + "analytics": "07ef29be-2b85-4919-9f78-44994f63b8b7" + } +} \ No newline at end of file diff --git a/templates/app/angular/package.json b/templates/app/angular/package.json index e409934329..0ec7111eb6 100644 --- a/templates/app/angular/package.json +++ b/templates/app/angular/package.json @@ -17,14 +17,14 @@ "@abp/ng.identity": "^0.9.0", "@abp/ng.tenant-management": "^0.9.0", "@abp/ng.theme.basic": "^0.9.0", - "@angular/animations": "~8.2.2", - "@angular/common": "~8.2.2", - "@angular/compiler": "~8.2.2", - "@angular/core": "~8.2.2", - "@angular/forms": "~8.2.2", - "@angular/platform-browser": "~8.2.2", - "@angular/platform-browser-dynamic": "~8.2.2", - "@angular/router": "~8.2.2", + "@angular/animations": "~8.2.8", + "@angular/common": "~8.2.8", + "@angular/compiler": "~8.2.8", + "@angular/core": "~8.2.8", + "@angular/forms": "~8.2.8", + "@angular/platform-browser": "~8.2.8", + "@angular/platform-browser-dynamic": "~8.2.8", + "@angular/router": "~8.2.8", "@angularclass/hmr": "^2.1.3", "@ngxs/devtools-plugin": "^3.5.0", "@ngxs/hmr-plugin": "^3.5.0", @@ -33,10 +33,10 @@ "zone.js": "~0.9.1" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.802.2", - "@angular/cli": "~8.2.2", - "@angular/compiler-cli": "~8.2.2", - "@angular/language-service": "~8.2.2", + "@angular-devkit/build-angular": "~0.803.6", + "@angular/cli": "~8.3.6", + "@angular/compiler-cli": "~8.2.8", + "@angular/language-service": "~8.2.8", "@types/jasmine": "~3.3.8", "@types/jasminewd2": "~2.0.3", "@types/node": "~8.9.4", From b722a152372067316d96caf4e9852381713acbd2 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Thu, 26 Sep 2019 12:58:42 +0300 Subject: [PATCH 05/48] identity settings isVisibleToClients --- .../AbpIdentitySettingDefinitionProvider.cs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs index c5cbb16a1f..188cc4d48c 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentitySettingDefinitionProvider.cs @@ -8,23 +8,22 @@ namespace Volo.Abp.Identity public override void Define(ISettingDefinitionContext context) { context.Add( + new SettingDefinition(IdentitySettingNames.Password.RequiredLength, null, null, null, true), + new SettingDefinition(IdentitySettingNames.Password.RequiredUniqueChars, null, null, null, true), + new SettingDefinition(IdentitySettingNames.Password.RequireNonAlphanumeric, null, null, null, true), + new SettingDefinition(IdentitySettingNames.Password.RequireLowercase, null, null, null, true), + new SettingDefinition(IdentitySettingNames.Password.RequireUppercase, null, null, null, true), + new SettingDefinition(IdentitySettingNames.Password.RequireDigit, null, null, null, true), - new SettingDefinition(IdentitySettingNames.Password.RequiredLength), - new SettingDefinition(IdentitySettingNames.Password.RequiredUniqueChars), - new SettingDefinition(IdentitySettingNames.Password.RequireNonAlphanumeric), - new SettingDefinition(IdentitySettingNames.Password.RequireLowercase), - new SettingDefinition(IdentitySettingNames.Password.RequireUppercase), - new SettingDefinition(IdentitySettingNames.Password.RequireDigit), + new SettingDefinition(IdentitySettingNames.Lockout.AllowedForNewUsers, null, null, null, true), + new SettingDefinition(IdentitySettingNames.Lockout.LockoutDuration, null, null, null, true), + new SettingDefinition(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, null, null, null, true), - new SettingDefinition(IdentitySettingNames.Lockout.AllowedForNewUsers), - new SettingDefinition(IdentitySettingNames.Lockout.LockoutDuration), - new SettingDefinition(IdentitySettingNames.Lockout.MaxFailedAccessAttempts), + new SettingDefinition(IdentitySettingNames.SignIn.RequireConfirmedEmail, null, null, null, true), + new SettingDefinition(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, null, null, null, true), - new SettingDefinition(IdentitySettingNames.SignIn.RequireConfirmedEmail), - new SettingDefinition(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber), - - new SettingDefinition(IdentitySettingNames.User.IsUserNameUpdateEnabled, "true"), - new SettingDefinition(IdentitySettingNames.User.IsEmailUpdateEnabled, "true") + new SettingDefinition(IdentitySettingNames.User.IsUserNameUpdateEnabled, "true", null, null, true), + new SettingDefinition(IdentitySettingNames.User.IsEmailUpdateEnabled, "true", null, null, true) ); } From 3fe2250234716e3e3e7f728041c79d1216c0c469 Mon Sep 17 00:00:00 2001 From: Xeevis Date: Tue, 24 Sep 2019 12:56:28 +0200 Subject: [PATCH 06/48] Copy new files for translation --- .../Best-Practices/PostgreSQL-Integration.md | 35 +++++ .../postgresql-delete-initial-migrations.png | Bin 0 -> 10255 bytes .../images/postgresql-update-database.png | Bin 0 -> 5625 bytes docs/cs/Dapper.md | 61 +++++++++ docs/cs/Getting-Started-Angular-Template.md | 126 ++++++++++++++++++ docs/cs/docs-nav.json | 14 +- 6 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 docs/cs/Best-Practices/PostgreSQL-Integration.md create mode 100644 docs/cs/Best-Practices/images/postgresql-delete-initial-migrations.png create mode 100644 docs/cs/Best-Practices/images/postgresql-update-database.png create mode 100644 docs/cs/Dapper.md create mode 100644 docs/cs/Getting-Started-Angular-Template.md diff --git a/docs/cs/Best-Practices/PostgreSQL-Integration.md b/docs/cs/Best-Practices/PostgreSQL-Integration.md new file mode 100644 index 0000000000..9b0bf40dc2 --- /dev/null +++ b/docs/cs/Best-Practices/PostgreSQL-Integration.md @@ -0,0 +1,35 @@ +## Entity Framework Core PostgreSQL Integration + +> See [Entity Framework Core Integration document](../Entity-Framework-Core.md) for the basics of the EF Core integration. + +### EntityFrameworkCore Project Update + +- In `Acme.BookStore.EntityFrameworkCore` project replace package `Volo.Abp.EntityFrameworkCore.SqlServer` with `Volo.Abp.EntityFrameworkCore.PostgreSql` +- Update to use PostgreSQL in `BookStoreEntityFrameworkCoreModule` + - Replace the `AbpEntityFrameworkCoreSqlServerModule` with the `AbpEntityFrameworkCorePostgreSqlModule` + - Replace the `options.UseSqlServer()` with the `options.UsePostgreSql()` +- In other projects update the PostgreSQL connection string in necessary `appsettings.json` files + +#### Delete Existing Migrations + +Delete all existing migration files (including `DbContextModelSnapshot`) + +![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png) + +#### Regenerate Initial Migration & Update the Database + +Set the correct startup project (usually a web project), +Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), select the `Acme.BookStore.EntityFrameworkCore.DbMigrations` as the **Default project** and execute the following command: + +Run `Add-Migration` command. +```` +PM> Add-Migration Initial +```` + +Then execute the `Update-Database` command to update the database schema: + +```` +PM> Update-Database +```` + +![postgresql-update-database](images/postgresql-update-database.png) diff --git a/docs/cs/Best-Practices/images/postgresql-delete-initial-migrations.png b/docs/cs/Best-Practices/images/postgresql-delete-initial-migrations.png new file mode 100644 index 0000000000000000000000000000000000000000..39d9e6dedf7545d7f88c024d4521132ee3410289 GIT binary patch literal 10255 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 asHJzxQB9P)&yWxCp(x91ysQDf4*fqV2II~E literal 0 HcmV?d00001 diff --git a/docs/cs/Best-Practices/images/postgresql-update-database.png b/docs/cs/Best-Practices/images/postgresql-update-database.png new file mode 100644 index 0000000000000000000000000000000000000000..02b61ef6a3a5edc0d4cebf7bb2a5a2442b9e71c9 GIT binary patch literal 5625 zcmbVQXH-+)mcLj~njl38MIiL9M8$xB(o5(yNEZl-z@Jcp2mz&ufP`)!5CQ3(P^F`k z00t={ML?<&nsn(C-~%8*)n5OA)%TofMmV$J{k~6D zbH1=Z4^*T$S!vuSQ3%@q7hwVEH@lDLk9aFh03; zXOXb%$Q4SrKl6-Po=mimv9a{I@n}Z`kcxi{GD?8-fz4xyEWVP^=e7HSzQvq%-%W$} zi2j`+IHLRo6!p$MO20+YD$q|~wz-*EvLep5a&o>+ zIPo#)=9D8OGdT<^xwl;(QY+^7et58{4Jq*KE4|r|`(2)$(r?p4D~@sPyT|CXPE~ z@r1H>tk1DsyKd_Iui(99CF&Ca&oWJK+2}&Pi$94{HoKXAgL#9$!zCAPY-M}-wtK-! zK|m+k)QT>IL1b7qyLK$*Qy`%xbIH<~Ww9iKA)&Uj#*sxk*#RQ2piN;nqRzC`Cp<6C)Ho*p;X#B%kp(xI7r29k^}Vtt zy`k41j2bn}A;`xAfH37I9N|a}w;>N>f~mO(GtkCLQEcu)T(~-~Oj?Qpzg31701zm; zSXtdE3;_MA|C_oK;pP-;FJ`0|#+S<&2ykEEKFQ^0q;eoz2zcC(>QT3v(zf?A;0{Yl< z?v$9Q{3rHlH49zy1L}p6a|=&x`4I1VFt|d~3swmSf~(dxHf)s??@Ev` zuT93v>C~Z(|9A(VEv0Y%{uCwWxjqwo)<4sk;ZIwwV?^31zM1y2@F|14yq5$z?v5Zr z>E`3f=KkvuchRTRG0gwW0HIKM_<6{~1>7FR!E8P{jd z=9W(MYxxjdT1F(W{M8)LI2MAi3t0A~nHa=!X7t7=nn4N2#*ZgkPw70F1_|E=4C12( z52~vCJN$ko5DLrO;XF6*1VI(HmBhwZ4(+5~;N1CCk$zhXjMBDE1--dee&i8lmLk_8 zFQ*@8vOlnDq(7LSN^+#sJWhy{V@XwsWM;)wIC1=7#o;2S63ZLjGn&uS)fgq(q3e}# zZ&ajO7_94`A2gR`8P?;cvr1?@$CH!Jjb^NTBc||}AHQus;8NZG0wd|;{4;!GlA?dQ z^5UTFy%(Ww$@r7i*!?Mu$juQ9F5bRVuLibnHt1tlSCTDTh$CX88C*z8pygV=&&Y}d znN$Om@5#sjDKie+=TTFkTN&WE$9zwZ_E&y6n|YNUc%z#7wv|T7D;yiO_Y=@+>5a+_ zwkzLqedaD`Z@<~gu4WL<+XsQ~2@0`GARdT?CLtRF8$`pI!I!2o7}!uKg6L6=%Dbtr zRT6ITwQ8*krao_P>+mWZti>n=IVg|JUORF^E`57jT^`I7f~#Smfm2*51~(|a^}WG+ zw^JC@-#F%^E}C!PfnBt}ZCCYSiC;=`!RGc&x~qF8RU;nw@r4qUV%9-5%Mn#n=0#u8 zZ{mIMIq}dXuMxWM4+<9pk>+lL^NX;NqQ;xmYa78{FAz^KgxE(~q$Hy=*0x9odiDs^ z%BAHlflEmg40_$=C``@9>L6_}f!$Zsu%jGp`R?>^Y0MR!$#Nbr8dyE^|eU zpu`vD*PjdS$*>zoXBbS+b|4EL6P=dwS?mrUD(EOkp$cBkCTrHULMfIrDw8L&*wk523AxT(%M8t zXU2-X3x2j~M_1D^Quikxm`Lb!ku$g>6_*mgg(R%VSu@Iq-ZI^YypwsNFN|QfEPk3> z_$z<~S^I)@5eAw^RHNyS+6VHh+E=NAq29#@D#KTy$w7$EGly> zHO#&olZv-M`51zLYS|6!KV`zUB;XZ25&oPJ>fC#q-`K64Mky6{GFfN$2VWk1GBBWc z39zISb(lFW_H>TACj#jm|1Id|vXnqLJLxNT&bSCzdY$eZ+c{CjhI_HnQUtb5mAAU2 zDvxtO$wfF=?xW*^q{NJ9!6hou1cv0?;lPe3b*d!570;k;*#iRB2>dj3(DUzt?g%>c zA^ldzP~=b3#9k^uq9;O7a)CZ%ZyXcm4kwXp$4}-%i}P#WI4>3xM@L&{4nEE|dY-A8 zUuiooQSTrP%q_x(wjO`KKGVFjHCkC(SJ032jdt$p4eF#dRhTfy+$#@mI_i$ZpZeFc zy&-Ql*V$!SZR{}5?foFf$%fMNo-rY9g6mPsyaXh$l%G%`bu$46xALgW{-@Ste0rTk zlG0x$Sk$8Y_O4GIElND>7AAVD+^bStqih}72YPpcW_g*6QrgYrT6Jab<)2`E{Haj*-+b+bh|@nGY4~5AhD- z92bSK&?uZXn}q#G6L{29e(J3!LLXV=WDpm4wSBQ+5v6wE^sePl(+8=T>u7SBNSw%s zP}8KxG+CuPo6Y~nK-Z8I@a;( z6YPxNe>_V62fGwz&iY1hN%^^s3&Qjy{%*e{L>3xdilTnHDf;BK+EWk60U7k88k@;5@Cj~rPq zEOI1|C+XxX8}~Gha^t@R6$zb-?|1y;<2zpL?;Iat>BStMFzSo1@XN*#Z@aQ@t`A$2 zK83hN^STvyW7V@I3~6}murI)WMOh?b3#fAo^bvD~{C6L^&o7E6Yn_Xfg0;XZ>KCSS z&n{;Zk>K#8->rwS*OolYE@X(gd)2&+hpR_!0o{QkvS#up=gYnbg|Jb_@S9 z-04{%SoI|*;GCiMSc+v6jt7Jr@hH3ua5%Ct?_CbTQGHP=##Cqme+>*C9;SG1)RF?s zS*reHjQj|odf-1M82)z&S3-q^2x7gR7=@mfZY|*BJdswr z>7H*%hgS?lzhruW{+h6}+Ztc4dTB2(t zSLRU6Ph0h|M2$+>y0k3%f}eD8+MGassZwq9`3S`@EwBlL)Q6&D8){_k=0PI=6}_=L z9J-|G58I8;d4uxeSX}ajA9xJ?0@tYdF!9RMva87b*u_+luZqNVy?acQoy8BOmdx)A zBRW-lzw(^DZKjPCEK-!$C@nNViVXyNS|&lBPF^3m;wN+@^~&JFH;v)%fc2>KR!aX@(&@(1?eu&&>=nRZ<~@mK(1f2qbNj zrz5|ustyEyKbUnDV2ZDfVwxj2vAz8MP1bKyTGU&l}}Sr?tY*7Z_~ z$H5hlmsAy$!E!fm81<+sg+O2a2>bDHkjryQD$%e(ZPNSUzF2m5yKJF;x`fC=kqfrr z8%r&yD;|=W?v)=o>v29!qX9di)sJ;Z6vXFWb=pxM)%uB~NmqM46>Uk{A5+t8%%4_9)CusXCdX`4$6DD-RoftAl# z55S^rFWQ;>a&OjSR64ouiNShdZQey7io`|k&a9>s+)!-MC2W21d;%tNdE^p>*wfAp z-7YFy?nKUS@ps3M)5j}=RS?vvvo^_D4C5V|T7{U&_=lr4-upvbNJTQXFI14hp-$xc zsK10OK5b;vyjn74r0*oesDP#i9^TmphcQq8oNOmvW6^N`6=JMntV;hJB~6G!bUxeC zk=+QZ5NMcbk`YKo-E#Oe5eGH!aSj#cCc_mHUXwL1r8Fe z9P{$G(8EVHjbzu?GJpq?s~Olw9*{yxR-W^EI}o} zPkT3%sYPP;VKItrh(!Z=MJEwF&dcqb}_Vf$=^HKY`!dG=hx4w2pmvOt} z-?5xLbG-91w^mQ?y*ys~P>KP`e9Iv_P*e%&CW2cl^%ft+S46Ew^STUDc;X?u*xdj*#IO`BWFMw29ED@|s|e zw3xtfq)@AIuitU)aLD4ZIUT#{DX;fRDxfaIc~4&xr6OFBE$guoX!T-4&MR@<;ME)7 zIyfWhcc0=y=@V=d$dU9?a`syf2aou6emMusa_Nk9aV#281v&W( z5u~K6kLPw5mJEYZlz_gRJ_+ zxE@e&zg||BdX;_u;*LCB+u#lNjxsSfK7`jSQ!4-P+|r+Fp3@TwQjtz<)eou3tK&#@ z|BRUVyA4teNex(nDN%@$FHay;nXe(K?;kzY>QMRL@g%zpVtJtsJ4*R25EtY4g3H2bzb0*x*l95@O8}Umm)Y!zelXeIbX3jy}+Ny8-1da>wB! z167ic^FJJyv9IbepVz5d#}1mE;! zHR`Cp(F@v0YL!iV#wF|q!1Vrd!wn_)f};%N^tKldJz}zPyZ3xNWifN`>8lsoB24}r z=cxem*#8Nv|2vkiHvPRnfhskR7|`OX!GJQ}mj$rjB{DbMbV(whS`I#!qyvBiDL81J zi-O#{VkpyrV(NcYD56sde+C@ME*t0OE+rkS>YJ}ioCDhK#RwwyM2!Q1#NItWl%Gds zSVnVIGl8(LbqYrsLw|7s_WUuDh-`$QrSebq+qMn0K}Tz;c8yg*KXcrCdXRb4g8upM zT!D}S4mhc!5297A)jIvh|7bK4?>>{Ve-TPE|8+U-Eaw0S$%X8p5PQ^C$pni(tgU*X zXJ{-Bn7BFht}3LwxyY b<{` base class based on Abp EntityFrameworkCore, which provides the `IDbConnection` and `IDbTransaction` properties required by Dapper. + +These two properties can work well with [Unit-Of-Work](Unit-Of-Work.md). + +## Installation + +Please install and configure EF Core according to [EF Core's integrated documentation](Entity-Framework-Core.md). + +`Volo.Abp.Dapper` is the main nuget package for the Dapper integration. Install it to your project (for a layered application, to your data/infrastructure layer): + +```shell +Install-Package Volo.Abp.Dapper +``` + +Then add `AbpDapperModule` module dependency (`DependsOn` attribute) to your [module](Module-Development-Basics.md): + +````C# +using Volo.Abp.Dapper; +using Volo.Abp.Modularity; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpDapperModule))] + public class MyModule : AbpModule + { + //... + } +} +```` + +## Implement Dapper Repository + +The following code implements the `Person` repository, which requires EF Core's `DbContext` (MyAppDbContext). You can inject `PersonDapperRepository` to call its methods. + +`DbConnection` and `DbTransaction` are from the `DapperRepository` base class. + +```C# +public class PersonDapperRepository : DapperRepository, ITransientDependency +{ + public PersonDapperRepository(IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public virtual async Task> GetAllPersonNames() + { + return (await DbConnection.QueryAsync("select Name from People", transaction: DbTransaction)) + .ToList(); + } + + public virtual async Task UpdatePersonNames(string name) + { + return await DbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name }, + DbTransaction); + } +} +``` diff --git a/docs/cs/Getting-Started-Angular-Template.md b/docs/cs/Getting-Started-Angular-Template.md new file mode 100644 index 0000000000..1bd605cd65 --- /dev/null +++ b/docs/cs/Getting-Started-Angular-Template.md @@ -0,0 +1,126 @@ +## Getting Started With the Angular Application Template + +This tutorial explain how to create a new Angular application using the startup template, configure and run it. + +### Creating a New Project + +This tutorial uses **ABP CLI** to create a new project. See the [Get Started](https://abp.io/get-started) page for other options. + +Install the ABP CLI using a command line window, if you've not installed before: + +````bash +dotnet tool install -g Volo.Abp.Cli +```` + +Use `abp new` command in an empty folder to create your project: + +````bash +abp new Acme.BookStore -u angular +```` + +> You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore. + +`-u angular` option specifies the UI framework to be Angular. Default database provider is EF Core. See the [CLI documentation](CLI.md) for all available options. + +#### Pre Requirements + +The created solution requires; + +* [Visual Studio 2017 (v15.9.0+)](https://visualstudio.microsoft.com/tr/downloads/) +* [.NET Core 2.2+](https://www.microsoft.com/net/download/dotnet-core/) +* [Node v10.16+](https://nodejs.org) +* [Yarn v1.17+](https://yarnpkg.com/) + +### The Solution Structure + +Open the solution in **Visual Studio**: + +![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-for-spa.png) + +The solution has a layered structure (based on [Domain Driven Design](Domain-Driven-Design.md)) and contains unit & integration test projects properly configured to work with **EF Core** & **SQLite in-memory** database. + +> See the [Application Template Document](Startup-Templates/Application.md) to understand the solution structure in details. + +### Database Connection String + +Check the **connection string** in the `appsettings.json` file under the `.HttpApi.Host` project: + +````json +{ + "ConnectionStrings": { + "Default": "Server=localhost;Database=BookStore;Trusted_Connection=True" + } +} +```` + +The solution is configured to use **Entity Framework Core** with **MS SQL Server**. EF Core supports [various](https://docs.microsoft.com/en-us/ef/core/providers/) database providers, so you can use another DBMS if you want. Change the connection string if you need. + +### Create Database & Apply Database Migrations + +You have two options to create the database. + +#### Using the DbMigrator Application + +The solution contains a console application (named `Acme.BookStore.DbMigrator` in this sample) that can create database, apply migrations and seed initial data. It is useful on development as well as on production environment. + +> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one. + +Right click to the `.DbMigrator` project and select **Set as StartUp Project**: + +![set-as-startup-project](images/set-as-startup-project.png) + +Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown below: + +![set-as-startup-project](images/db-migrator-app.png) + +#### Using EF Core Update-Database Command + +Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations. Right click to the `.Web` project and select **Set as StartUp Project**: + +![set-as-startup-project](images/set-as-startup-project.png) + +Open the **Package Manager Console**, select `.EntityFrameworkCore.DbMigrations` project as the **Default Project** and run the `Update-Database` command: + +![pcm-update-database](images/pcm-update-database-v2.png) + +This will create a new database based on the configured connection string. + +> Using the `.Migrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application. + +### Running the Application + +#### Run the API Host (Server Side) + +Ensure that the `.HttpApi.Host` project is the startup project and un the application which will open a Swagger UI: + +![bookstore-homepage](images/bookstore-swagger-ui-host.png) + +You can see the application APIs and test them here. Get [more info](https://swagger.io/tools/swagger-ui/) about the Swagger UI. + +##### Authorization for the Swagger UI + +Most of the application APIs require authentication & authorization. If you want to test authorized APIs, manually go to the `/Account/Login` page, enter `admin` as the username and `1q2w3E*` as the password to login to the application. Then you will be able to execute authorized APIs too. + +#### Run the Angular Application (Client Side) + +Go to the `angular` folder, open a command line terminal, type the `yarn` command (we suggest to the [yarn](https://yarnpkg.com) package manager while npm install will also work in most cases): + +````bash +yarn +```` + +Once all node modules are loaded, execute `yarn start` or `npm start` command: + +````bash +yarn start +```` + +Open your favorite browser and go to `localhost:4200` URL. Initial username is `admin` and password is `1q2w3E*`. + +The startup template includes the **identity management** and **tenant management** modules. Once you login, the Administration menu will be available where you can manage **tenants**, **roles**, **users** and their **permissions**. + +> We recommend [Visual Studio Code](https://code.visualstudio.com/) as the editor for the Angular project, but you are free to use your favorite editor. + +### What's Next? + +* [Application development tutorial](Tutorials/Angular/Part-I.md) diff --git a/docs/cs/docs-nav.json b/docs/cs/docs-nav.json index 8560190492..91badc73e9 100644 --- a/docs/cs/docs-nav.json +++ b/docs/cs/docs-nav.json @@ -202,7 +202,7 @@ "items": [ { "text": "API", - "items": [ + "items": [ { "text": "Automatické API řadiče", "path": "AspNetCore/Auto-API-Controllers.md" @@ -245,11 +245,21 @@ "items": [ { "text": "Entity Framework Core integrace", - "path": "Entity-Framework-Core.md" + "path": "Entity-Framework-Core.md", + "items": [ + { + "text": "PostgreSQL integrace", + "path": "Best-Practices/PostgreSQL-Integration.md" + } + ] }, { "text": "MongoDB integrace", "path": "MongoDB.md" + }, + { + "text": "Dapper integrace", + "path": "Dapper.md" } ] }, From 81125d692f9936e64b0d14184ac5aab3f1357b99 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 26 Sep 2019 16:32:58 +0300 Subject: [PATCH 07/48] feature(identity-config): create module --- .../packages/identity-config/README.md | 1 + .../packages/identity-config/karma.conf.js | 32 +++++++++++++++++++ .../packages/identity-config/ng-package.json | 7 ++++ .../packages/identity-config/package.json | 7 ++++ .../src/lib/identity-config.module.ts | 10 ++++++ .../lib/services/identity-config.service.ts | 32 +++++++++++++++++++ .../identity-config/src/public-api.ts | 2 ++ .../packages/identity-config/src/test.ts | 21 ++++++++++++ .../identity-config/tsconfig.lib.json | 26 +++++++++++++++ .../identity-config/tsconfig.spec.json | 17 ++++++++++ .../packages/identity-config/tslint.json | 17 ++++++++++ .../identity/src/lib/constants/routes.ts | 4 +++ .../identity/src/lib/identity.module.ts | 4 +++ 13 files changed, 180 insertions(+) create mode 100644 npm/ng-packs/packages/identity-config/README.md create mode 100644 npm/ng-packs/packages/identity-config/karma.conf.js create mode 100644 npm/ng-packs/packages/identity-config/ng-package.json create mode 100644 npm/ng-packs/packages/identity-config/package.json create mode 100644 npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts create mode 100644 npm/ng-packs/packages/identity-config/src/lib/services/identity-config.service.ts create mode 100644 npm/ng-packs/packages/identity-config/src/public-api.ts create mode 100644 npm/ng-packs/packages/identity-config/src/test.ts create mode 100644 npm/ng-packs/packages/identity-config/tsconfig.lib.json create mode 100644 npm/ng-packs/packages/identity-config/tsconfig.spec.json create mode 100644 npm/ng-packs/packages/identity-config/tslint.json diff --git a/npm/ng-packs/packages/identity-config/README.md b/npm/ng-packs/packages/identity-config/README.md new file mode 100644 index 0000000000..8754748f6a --- /dev/null +++ b/npm/ng-packs/packages/identity-config/README.md @@ -0,0 +1 @@ +# @abp/ng.identity.config \ No newline at end of file diff --git a/npm/ng-packs/packages/identity-config/karma.conf.js b/npm/ng-packs/packages/identity-config/karma.conf.js new file mode 100644 index 0000000000..47f6e498d2 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/karma.conf.js @@ -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/identity-config'), + 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 + }); +}; diff --git a/npm/ng-packs/packages/identity-config/ng-package.json b/npm/ng-packs/packages/identity-config/ng-package.json new file mode 100644 index 0000000000..d72870cd39 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/identity-config", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/npm/ng-packs/packages/identity-config/package.json b/npm/ng-packs/packages/identity-config/package.json new file mode 100644 index 0000000000..e7989e56de --- /dev/null +++ b/npm/ng-packs/packages/identity-config/package.json @@ -0,0 +1,7 @@ +{ + "name": "@abp/ng.identity.config", + "version": "0.0.1", + "publishConfig": { + "access": "public" + } +} diff --git a/npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts b/npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts new file mode 100644 index 0000000000..9753ed0d08 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts @@ -0,0 +1,10 @@ +import { NgModule, APP_INITIALIZER } from '@angular/core'; +import { noop, CoreModule } from '@abp/ng.core'; +import { IdentityConfigService } from './services/identity-config.service'; +import { ThemeSharedModule } from '@abp/ng.theme.shared'; + +@NgModule({ + imports: [CoreModule, ThemeSharedModule], + providers: [{ provide: APP_INITIALIZER, deps: [IdentityConfigService], useFactory: noop, multi: true }], +}) +export class IdentityConfigModule {} diff --git a/npm/ng-packs/packages/identity-config/src/lib/services/identity-config.service.ts b/npm/ng-packs/packages/identity-config/src/lib/services/identity-config.service.ts new file mode 100644 index 0000000000..fe78f8e810 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/src/lib/services/identity-config.service.ts @@ -0,0 +1,32 @@ +import { ABP_ROUTES, eLayoutType, RestService } from '@abp/ng.core'; +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class IdentityConfigService { + constructor(private router: Router, private restService: RestService) { + ABP_ROUTES.push( + { + name: 'AbpUiNavigation::Menu:Administration', + path: '', + order: 1, + wrapper: true, + }, + { + name: 'AbpIdentity::Menu:IdentityManagement', + path: 'identity', + order: 1, + parentName: 'AbpUiNavigation::Menu:Administration', + layout: eLayoutType.application, + iconClass: 'fa fa-id-card-o', + children: [ + { path: 'roles', name: 'AbpIdentity::Roles', order: 2, requiredPolicy: 'AbpIdentity.Roles' }, + { path: 'users', name: 'AbpIdentity::Users', order: 1, requiredPolicy: 'AbpIdentity.Users' }, + ], + }, + ); + } +} diff --git a/npm/ng-packs/packages/identity-config/src/public-api.ts b/npm/ng-packs/packages/identity-config/src/public-api.ts new file mode 100644 index 0000000000..e702653211 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/src/public-api.ts @@ -0,0 +1,2 @@ +export * from './lib/services/identity-config.service'; +export * from './lib/identity-config.module'; diff --git a/npm/ng-packs/packages/identity-config/src/test.ts b/npm/ng-packs/packages/identity-config/src/test.ts new file mode 100644 index 0000000000..978c64fb83 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/src/test.ts @@ -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); diff --git a/npm/ng-packs/packages/identity-config/tsconfig.lib.json b/npm/ng-packs/packages/identity-config/tsconfig.lib.json new file mode 100644 index 0000000000..bd23948e59 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/tsconfig.lib.json @@ -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" + ] +} diff --git a/npm/ng-packs/packages/identity-config/tsconfig.spec.json b/npm/ng-packs/packages/identity-config/tsconfig.spec.json new file mode 100644 index 0000000000..16da33db07 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/npm/ng-packs/packages/identity-config/tslint.json b/npm/ng-packs/packages/identity-config/tslint.json new file mode 100644 index 0000000000..8c3919ea62 --- /dev/null +++ b/npm/ng-packs/packages/identity-config/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "abp", + "camelCase" + ], + "component-selector": [ + true, + "element", + "abp", + "kebab-case" + ] + } +} diff --git a/npm/ng-packs/packages/identity/src/lib/constants/routes.ts b/npm/ng-packs/packages/identity/src/lib/constants/routes.ts index cece75ad63..1dfc53245e 100644 --- a/npm/ng-packs/packages/identity/src/lib/constants/routes.ts +++ b/npm/ng-packs/packages/identity/src/lib/constants/routes.ts @@ -1,5 +1,9 @@ import { eLayoutType, ABP } from '@abp/ng.core'; +/** + * + * @deprecated + */ export const IDENTITY_ROUTES = { routes: [ { diff --git a/npm/ng-packs/packages/identity/src/lib/identity.module.ts b/npm/ng-packs/packages/identity/src/lib/identity.module.ts index d94ba410d9..15b1b1c7cb 100644 --- a/npm/ng-packs/packages/identity/src/lib/identity.module.ts +++ b/npm/ng-packs/packages/identity/src/lib/identity.module.ts @@ -27,6 +27,10 @@ import { NgxValidateCoreModule } from '@ngx-validate/core'; }) export class IdentityModule {} +/** + * + * @deprecated + */ export function IdentityProviders(): Provider[] { return []; } From d7610350c68852496c43fdd3bfee540733015646 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 27 Sep 2019 14:06:22 +0800 Subject: [PATCH 08/48] The CLI update command updates the test project. Resolve #1808 --- .../Cli/ProjectModification/ProjectFinder.cs | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs index 548290df5c..4a313e784d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectFinder.cs @@ -83,8 +83,11 @@ namespace Volo.Abp.Cli.ProjectModification public static string[] GetProjectFiles(string solutionFile) { - var baseProjectFolder = GetBaseProjectFolder(solutionFile); - return Directory.GetFiles(baseProjectFolder, "*.csproj", SearchOption.AllDirectories); + return GetBaseProjectFolders(solutionFile) + .Select(baseProjectFolder => + Directory.GetFiles(baseProjectFolder, "*.csproj", SearchOption.AllDirectories)) + .SelectMany(files => files) + .ToArray(); } public static string[] GetAssemblyNames(string[] projectFiles) @@ -118,16 +121,33 @@ namespace Volo.Abp.Cli.ProjectModification return null; } - private static string GetBaseProjectFolder(string solutionFile) + private static string[] GetBaseProjectFolders(string solutionFile) { + var projectFolders = new List(); var baseFolder = Path.GetDirectoryName(solutionFile); + if (baseFolder == null) + { + return projectFolders.ToArray(); + } + var srcFolder = Path.Combine(baseFolder, "src"); if (Directory.Exists(srcFolder)) { - baseFolder = srcFolder; + projectFolders.Add(srcFolder); + } + + var testFolder = Path.Combine(baseFolder, "test"); + if (Directory.Exists(testFolder)) + { + projectFolders.Add(testFolder); + } + + if (!projectFolders.Any()) + { + projectFolders.Add(baseFolder); } - return baseFolder; + return projectFolders.ToArray(); } } } From 6178aeb900c2a4848a6cbc9810e78655f64b0ebf Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Sep 2019 10:01:00 +0300 Subject: [PATCH 09/48] feature(account-config): create module --- .../packages/account-config/README.md | 1 + .../packages/account-config/karma.conf.js | 32 ++++++++++++++++ .../packages/account-config/ng-package.json | 7 ++++ .../packages/account-config/package.json | 7 ++++ .../src/lib/account-config.module.ts | 37 +++++++++++++++++++ .../lib/services/account-config.service.ts | 21 +++++++++++ .../packages/account-config/src/public-api.ts | 2 + .../packages/account-config/src/test.ts | 21 +++++++++++ .../packages/account-config/tsconfig.lib.json | 26 +++++++++++++ .../account-config/tsconfig.spec.json | 17 +++++++++ .../packages/account-config/tslint.json | 17 +++++++++ .../account/src/lib/account.module.ts | 4 ++ .../account/src/lib/constants/routes.ts | 4 ++ .../src/lib/plugins/config/config.plugin.ts | 13 ++++++- .../packages/identity/ng-package.json | 2 +- npm/ng-packs/packages/identity/package.json | 4 +- 16 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 npm/ng-packs/packages/account-config/README.md create mode 100644 npm/ng-packs/packages/account-config/karma.conf.js create mode 100644 npm/ng-packs/packages/account-config/ng-package.json create mode 100644 npm/ng-packs/packages/account-config/package.json create mode 100644 npm/ng-packs/packages/account-config/src/lib/account-config.module.ts create mode 100644 npm/ng-packs/packages/account-config/src/lib/services/account-config.service.ts create mode 100644 npm/ng-packs/packages/account-config/src/public-api.ts create mode 100644 npm/ng-packs/packages/account-config/src/test.ts create mode 100644 npm/ng-packs/packages/account-config/tsconfig.lib.json create mode 100644 npm/ng-packs/packages/account-config/tsconfig.spec.json create mode 100644 npm/ng-packs/packages/account-config/tslint.json diff --git a/npm/ng-packs/packages/account-config/README.md b/npm/ng-packs/packages/account-config/README.md new file mode 100644 index 0000000000..9ace70206e --- /dev/null +++ b/npm/ng-packs/packages/account-config/README.md @@ -0,0 +1 @@ +# @abp/ng.account.config \ No newline at end of file diff --git a/npm/ng-packs/packages/account-config/karma.conf.js b/npm/ng-packs/packages/account-config/karma.conf.js new file mode 100644 index 0000000000..e74978b4ca --- /dev/null +++ b/npm/ng-packs/packages/account-config/karma.conf.js @@ -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/account-config'), + 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 + }); +}; diff --git a/npm/ng-packs/packages/account-config/ng-package.json b/npm/ng-packs/packages/account-config/ng-package.json new file mode 100644 index 0000000000..de9885883c --- /dev/null +++ b/npm/ng-packs/packages/account-config/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/account-config", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/npm/ng-packs/packages/account-config/package.json b/npm/ng-packs/packages/account-config/package.json new file mode 100644 index 0000000000..4113d6e984 --- /dev/null +++ b/npm/ng-packs/packages/account-config/package.json @@ -0,0 +1,7 @@ +{ + "name": "@abp/ng.account.config", + "version": "0.0.1", + "publishConfig": { + "access": "public" + } +} diff --git a/npm/ng-packs/packages/account-config/src/lib/account-config.module.ts b/npm/ng-packs/packages/account-config/src/lib/account-config.module.ts new file mode 100644 index 0000000000..a94997e846 --- /dev/null +++ b/npm/ng-packs/packages/account-config/src/lib/account-config.module.ts @@ -0,0 +1,37 @@ +import { CoreModule, noop } from '@abp/ng.core'; +import { ThemeSharedModule } from '@abp/ng.theme.shared'; +import { APP_INITIALIZER, InjectionToken, ModuleWithProviders, NgModule } from '@angular/core'; +import { AccountConfigService } from './services/account-config.service'; + +export interface AccountConfigOptions { + redirectUrl?: string; +} + +export function accountOptionsFactory(options: AccountConfigOptions) { + return { + redirectUrl: '/', + ...options, + }; +} + +export const ACCOUNT_OPTIONS = new InjectionToken('ACCOUNT_OPTIONS'); + +@NgModule({ + imports: [CoreModule, ThemeSharedModule], + providers: [{ provide: APP_INITIALIZER, multi: true, deps: [AccountConfigService], useFactory: noop }], +}) +export class AccountConfigModule { + static forRoot(options = {} as AccountConfigOptions): ModuleWithProviders { + return { + ngModule: AccountConfigModule, + providers: [ + { provide: ACCOUNT_OPTIONS, useValue: options }, + { + provide: 'ACCOUNT_OPTIONS', + useFactory: accountOptionsFactory, + deps: [ACCOUNT_OPTIONS], + }, + ], + }; + } +} diff --git a/npm/ng-packs/packages/account-config/src/lib/services/account-config.service.ts b/npm/ng-packs/packages/account-config/src/lib/services/account-config.service.ts new file mode 100644 index 0000000000..7af86a49c9 --- /dev/null +++ b/npm/ng-packs/packages/account-config/src/lib/services/account-config.service.ts @@ -0,0 +1,21 @@ +import { ABP_ROUTES, eLayoutType, RestService } from '@abp/ng.core'; +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +@Injectable({ + providedIn: 'root', +}) +export class AccountConfigService { + constructor(private router: Router, private restService: RestService) { + ABP_ROUTES.push({ + name: 'AbpAccount::Menu:Account', + path: 'account', + invisible: true, + layout: eLayoutType.application, + children: [ + { path: 'login', name: 'AbpAccount::Login', order: 1 }, + { path: 'register', name: 'AbpAccount::Register', order: 2 }, + ], + }); + } +} diff --git a/npm/ng-packs/packages/account-config/src/public-api.ts b/npm/ng-packs/packages/account-config/src/public-api.ts new file mode 100644 index 0000000000..83270614c0 --- /dev/null +++ b/npm/ng-packs/packages/account-config/src/public-api.ts @@ -0,0 +1,2 @@ +export * from './lib/services/account-config.service'; +export * from './lib/account-config.module'; diff --git a/npm/ng-packs/packages/account-config/src/test.ts b/npm/ng-packs/packages/account-config/src/test.ts new file mode 100644 index 0000000000..978c64fb83 --- /dev/null +++ b/npm/ng-packs/packages/account-config/src/test.ts @@ -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); diff --git a/npm/ng-packs/packages/account-config/tsconfig.lib.json b/npm/ng-packs/packages/account-config/tsconfig.lib.json new file mode 100644 index 0000000000..bd23948e59 --- /dev/null +++ b/npm/ng-packs/packages/account-config/tsconfig.lib.json @@ -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" + ] +} diff --git a/npm/ng-packs/packages/account-config/tsconfig.spec.json b/npm/ng-packs/packages/account-config/tsconfig.spec.json new file mode 100644 index 0000000000..16da33db07 --- /dev/null +++ b/npm/ng-packs/packages/account-config/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/npm/ng-packs/packages/account-config/tslint.json b/npm/ng-packs/packages/account-config/tslint.json new file mode 100644 index 0000000000..8c3919ea62 --- /dev/null +++ b/npm/ng-packs/packages/account-config/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "abp", + "camelCase" + ], + "component-selector": [ + true, + "element", + "abp", + "kebab-case" + ] + } +} diff --git a/npm/ng-packs/packages/account/src/lib/account.module.ts b/npm/ng-packs/packages/account/src/lib/account.module.ts index 8a790a21c1..d6b97fec84 100644 --- a/npm/ng-packs/packages/account/src/lib/account.module.ts +++ b/npm/ng-packs/packages/account/src/lib/account.module.ts @@ -18,6 +18,10 @@ import { ACCOUNT_OPTIONS, optionsFactory } from './tokens/options.token'; }) export class AccountModule {} +/** + * + * @deprecated since version 0.9 + */ export function AccountProviders(options = {} as Options): Provider[] { return [ { provide: ACCOUNT_OPTIONS, useValue: options }, diff --git a/npm/ng-packs/packages/account/src/lib/constants/routes.ts b/npm/ng-packs/packages/account/src/lib/constants/routes.ts index 762d10c313..119bde1e7f 100644 --- a/npm/ng-packs/packages/account/src/lib/constants/routes.ts +++ b/npm/ng-packs/packages/account/src/lib/constants/routes.ts @@ -1,5 +1,9 @@ import { ABP, eLayoutType } from '@abp/ng.core'; +/** + * + * @deprecated since version 0.9 + */ export const ACCOUNT_ROUTES = { routes: [ { diff --git a/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts b/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts index 42e8003abe..acecc36fb3 100644 --- a/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts +++ b/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts @@ -8,7 +8,7 @@ import clone from 'just-clone'; export const NGXS_CONFIG_PLUGIN_OPTIONS = new InjectionToken('NGXS_CONFIG_PLUGIN_OPTIONS'); -export const ABP_ROUTES = [] as ABP.FullRoute[]; +export let ABP_ROUTES = [] as ABP.FullRoute[]; @Injectable() export class ConfigPlugin implements NgxsPlugin { @@ -40,6 +40,17 @@ export class ConfigPlugin implements NgxsPlugin { } function transformRoutes(routes: Routes = [], wrappers: ABP.FullRoute[] = []): any { + /** + * + * @deprecated since version 0.9.0 + */ + const abpRoutes: ABP.FullRoute[] = routes + .filter(route => { + return snq(() => route.data.routes.routes.find(r => r.path === route.path), false); + }) + .reduce((acc, val) => [...acc, ...val.data.routes.routes], []); + ABP_ROUTES = [...ABP_ROUTES, ...abpRoutes]; + wrappers = ABP_ROUTES.filter(ar => ar.wrapper); const transformed = [] as ABP.FullRoute[]; routes diff --git a/npm/ng-packs/packages/identity/ng-package.json b/npm/ng-packs/packages/identity/ng-package.json index aa178ed0d5..5f547dee2b 100644 --- a/npm/ng-packs/packages/identity/ng-package.json +++ b/npm/ng-packs/packages/identity/ng-package.json @@ -4,5 +4,5 @@ "lib": { "entryFile": "src/public-api.ts" }, - "whitelistedNonPeerDependencies": ["@abp/ng.theme.shared", "@abp/ng.permission-management"] + "whitelistedNonPeerDependencies": ["@abp/ng.theme.shared", "@abp/ng.permission-management", "@abp/ng.identity.config"] } diff --git a/npm/ng-packs/packages/identity/package.json b/npm/ng-packs/packages/identity/package.json index f139753679..7f0c47ef61 100644 --- a/npm/ng-packs/packages/identity/package.json +++ b/npm/ng-packs/packages/identity/package.json @@ -2,7 +2,9 @@ "name": "@abp/ng.identity", "version": "0.9.0", "dependencies": { - "@abp/ng.permission-management": "^0.9.0" + "@abp/ng.theme.shared": "^0.9.0", + "@abp/ng.permission-management": "^0.9.0", + "@abp/ng.identity.config": "0.0.1" }, "publishConfig": { "access": "public" From 16d02447f6d9ed38b2290da1ea25855deae593e7 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Sep 2019 10:47:02 +0300 Subject: [PATCH 10/48] feature(tenant-management-config): create module --- npm/ng-packs/angular.json | 105 ++++++++++++++++++ .../src/lib/identity-config.module.ts | 6 +- .../setting-management.component.ts | 42 ++----- .../tenant-management-config/README.md | 1 + .../tenant-management-config/karma.conf.js | 32 ++++++ .../tenant-management-config/ng-package.json | 7 ++ .../tenant-management-config/package.json | 7 ++ .../tenant-management-config.service.ts | 25 +++++ .../lib/tenant-management-config.module.ts | 8 ++ .../src/public-api.ts | 7 ++ .../tenant-management-config/src/test.ts | 21 ++++ .../tsconfig.lib.json | 26 +++++ .../tsconfig.spec.json | 17 +++ .../tenant-management-config/tslint.json | 17 +++ .../tenant-management/ng-package.json | 6 +- .../packages/tenant-management/package.json | 3 +- .../src/lib/constants/routes.ts | 4 + .../src/lib/tenant-management.module.ts | 4 + .../src/lib/models/setting-management.ts | 2 + 19 files changed, 301 insertions(+), 39 deletions(-) create mode 100644 npm/ng-packs/packages/tenant-management-config/README.md create mode 100644 npm/ng-packs/packages/tenant-management-config/karma.conf.js create mode 100644 npm/ng-packs/packages/tenant-management-config/ng-package.json create mode 100644 npm/ng-packs/packages/tenant-management-config/package.json create mode 100644 npm/ng-packs/packages/tenant-management-config/src/lib/services/tenant-management-config.service.ts create mode 100644 npm/ng-packs/packages/tenant-management-config/src/lib/tenant-management-config.module.ts create mode 100644 npm/ng-packs/packages/tenant-management-config/src/public-api.ts create mode 100644 npm/ng-packs/packages/tenant-management-config/src/test.ts create mode 100644 npm/ng-packs/packages/tenant-management-config/tsconfig.lib.json create mode 100644 npm/ng-packs/packages/tenant-management-config/tsconfig.spec.json create mode 100644 npm/ng-packs/packages/tenant-management-config/tslint.json diff --git a/npm/ng-packs/angular.json b/npm/ng-packs/angular.json index 773d9794f7..0aa1c106a5 100644 --- a/npm/ng-packs/angular.json +++ b/npm/ng-packs/angular.json @@ -323,6 +323,111 @@ } } } + }, + "identity-config": { + "projectType": "library", + "root": "packages/identity-config", + "sourceRoot": "packages/identity-config/src", + "prefix": "abp", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "packages/identity-config/tsconfig.lib.json", + "project": "packages/identity-config/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "packages/identity-config/src/test.ts", + "tsConfig": "packages/identity-config/tsconfig.spec.json", + "karmaConfig": "packages/identity-config/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "packages/identity-config/tsconfig.lib.json", + "packages/identity-config/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "account-config": { + "projectType": "library", + "root": "packages/account-config", + "sourceRoot": "packages/account-config/src", + "prefix": "abp", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "packages/account-config/tsconfig.lib.json", + "project": "packages/account-config/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "packages/account-config/src/test.ts", + "tsConfig": "packages/account-config/tsconfig.spec.json", + "karmaConfig": "packages/account-config/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "packages/account-config/tsconfig.lib.json", + "packages/account-config/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "tenant-management-config": { + "projectType": "library", + "root": "packages/tenant-management-config", + "sourceRoot": "packages/tenant-management-config/src", + "prefix": "abp", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "packages/tenant-management-config/tsconfig.lib.json", + "project": "packages/tenant-management-config/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "packages/tenant-management-config/src/test.ts", + "tsConfig": "packages/tenant-management-config/tsconfig.spec.json", + "karmaConfig": "packages/tenant-management-config/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "packages/tenant-management-config/tsconfig.lib.json", + "packages/tenant-management-config/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } } }, "defaultProject": "core" diff --git a/npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts b/npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts index 9753ed0d08..a354cd6a46 100644 --- a/npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts +++ b/npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts @@ -1,10 +1,8 @@ -import { NgModule, APP_INITIALIZER } from '@angular/core'; -import { noop, CoreModule } from '@abp/ng.core'; +import { noop } from '@abp/ng.core'; +import { APP_INITIALIZER, NgModule } from '@angular/core'; import { IdentityConfigService } from './services/identity-config.service'; -import { ThemeSharedModule } from '@abp/ng.theme.shared'; @NgModule({ - imports: [CoreModule, ThemeSharedModule], providers: [{ provide: APP_INITIALIZER, deps: [IdentityConfigService], useFactory: noop, multi: true }], }) export class IdentityConfigModule {} diff --git a/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts b/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts index 8b485e87c8..562f312eca 100644 --- a/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts +++ b/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts @@ -1,14 +1,14 @@ -import { SettingTab } from '@abp/ng.theme.shared'; -import { Component, TrackByFunction } from '@angular/core'; +import { Component, TrackByFunction, OnInit } from '@angular/core'; +import { SettingTab, SETTING_TABS } from '@abp/ng.theme.shared'; import { Router } from '@angular/router'; -import { ABP, ConfigState } from '@abp/ng.core'; import { Store } from '@ngxs/store'; +import { ConfigState } from '@abp/ng.core'; @Component({ selector: 'abp-setting-management', templateUrl: './setting-management.component.html', }) -export class SettingManagementComponent { +export class SettingManagementComponent implements OnInit { settings: SettingTab[] = []; selected = {} as SettingTab; @@ -18,35 +18,11 @@ export class SettingManagementComponent { constructor(private router: Router, private store: Store) {} ngOnInit() { - this.setSettings(); - } - - setSettings() { - const { data } = this.router.config.find(r => r.path === 'setting-management') as { - data: ABP.Dictionary; - }; - - if (data) { - Object.keys(data).forEach(key => { - const element = data[key]; - if (element && element.component) { - if ( - element.requiredPolicy && - !this.store.selectSnapshot(ConfigState.getGrantedPolicy(element.requiredPolicy)) - ) { - return; - } - - this.settings.push(element); - } - }); - - if (this.settings.length) { - this.settings = this.settings.sort((a, b) => a.order - b.order); - this.selected = this.settings[0]; - } + if (this.settings.length) { + this.settings = SETTING_TABS.filter(setting => + this.store.selectSnapshot(ConfigState.getGrantedPolicy(setting.requiredPolicy)), + ).sort((a, b) => a.order - b.order); + this.selected = this.settings[0]; } } - - ngOnDestroy() {} } diff --git a/npm/ng-packs/packages/tenant-management-config/README.md b/npm/ng-packs/packages/tenant-management-config/README.md new file mode 100644 index 0000000000..77548feaf9 --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/README.md @@ -0,0 +1 @@ +# @abp/ng.tenant-management.config \ No newline at end of file diff --git a/npm/ng-packs/packages/tenant-management-config/karma.conf.js b/npm/ng-packs/packages/tenant-management-config/karma.conf.js new file mode 100644 index 0000000000..850929cc06 --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/karma.conf.js @@ -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/tenant-management-config'), + 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 + }); +}; diff --git a/npm/ng-packs/packages/tenant-management-config/ng-package.json b/npm/ng-packs/packages/tenant-management-config/ng-package.json new file mode 100644 index 0000000000..834556113c --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/tenant-management-config", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/npm/ng-packs/packages/tenant-management-config/package.json b/npm/ng-packs/packages/tenant-management-config/package.json new file mode 100644 index 0000000000..43b4392733 --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/package.json @@ -0,0 +1,7 @@ +{ + "name": "@abp/ng.tenant-management.config", + "version": "0.0.1", + "publishConfig": { + "access": "public" + } +} diff --git a/npm/ng-packs/packages/tenant-management-config/src/lib/services/tenant-management-config.service.ts b/npm/ng-packs/packages/tenant-management-config/src/lib/services/tenant-management-config.service.ts new file mode 100644 index 0000000000..8d77d1005f --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/src/lib/services/tenant-management-config.service.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { ABP_ROUTES, eLayoutType } from '@abp/ng.core'; + +@Injectable({ + providedIn: 'root', +}) +export class TenantManagementConfigService { + constructor() { + ABP_ROUTES.push({ + name: 'AbpTenantManagement::Menu:TenantManagement', + path: 'tenant-management', + parentName: 'AbpUiNavigation::Menu:Administration', + layout: eLayoutType.application, + iconClass: 'fa fa-users', + children: [ + { + path: 'tenants', + name: 'AbpTenantManagement::Tenants', + order: 1, + requiredPolicy: 'AbpTenantManagement.Tenants', + }, + ], + }); + } +} diff --git a/npm/ng-packs/packages/tenant-management-config/src/lib/tenant-management-config.module.ts b/npm/ng-packs/packages/tenant-management-config/src/lib/tenant-management-config.module.ts new file mode 100644 index 0000000000..7f59d28be4 --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/src/lib/tenant-management-config.module.ts @@ -0,0 +1,8 @@ +import { NgModule, APP_INITIALIZER } from '@angular/core'; +import { TenantManagementConfigService } from './services/tenant-management-config.service'; +import { noop } from '@abp/ng.core'; + +@NgModule({ + providers: [{ provide: APP_INITIALIZER, deps: [TenantManagementConfigService], useFactory: noop, multi: true }], +}) +export class TenantManagementConfigModule {} diff --git a/npm/ng-packs/packages/tenant-management-config/src/public-api.ts b/npm/ng-packs/packages/tenant-management-config/src/public-api.ts new file mode 100644 index 0000000000..2067a98b7e --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/src/public-api.ts @@ -0,0 +1,7 @@ +/* + * Public API Surface of tenant-management-config + */ + +export * from './lib/services/tenant-management-config.service'; +export * from './lib/tenant-management-config.component'; +export * from './lib/tenant-management-config.module'; diff --git a/npm/ng-packs/packages/tenant-management-config/src/test.ts b/npm/ng-packs/packages/tenant-management-config/src/test.ts new file mode 100644 index 0000000000..978c64fb83 --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/src/test.ts @@ -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); diff --git a/npm/ng-packs/packages/tenant-management-config/tsconfig.lib.json b/npm/ng-packs/packages/tenant-management-config/tsconfig.lib.json new file mode 100644 index 0000000000..bd23948e59 --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/tsconfig.lib.json @@ -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" + ] +} diff --git a/npm/ng-packs/packages/tenant-management-config/tsconfig.spec.json b/npm/ng-packs/packages/tenant-management-config/tsconfig.spec.json new file mode 100644 index 0000000000..16da33db07 --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/npm/ng-packs/packages/tenant-management-config/tslint.json b/npm/ng-packs/packages/tenant-management-config/tslint.json new file mode 100644 index 0000000000..8c3919ea62 --- /dev/null +++ b/npm/ng-packs/packages/tenant-management-config/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "abp", + "camelCase" + ], + "component-selector": [ + true, + "element", + "abp", + "kebab-case" + ] + } +} diff --git a/npm/ng-packs/packages/tenant-management/ng-package.json b/npm/ng-packs/packages/tenant-management/ng-package.json index 07fbab773b..959eae44ab 100644 --- a/npm/ng-packs/packages/tenant-management/ng-package.json +++ b/npm/ng-packs/packages/tenant-management/ng-package.json @@ -4,5 +4,9 @@ "lib": { "entryFile": "src/public-api.ts" }, - "whitelistedNonPeerDependencies": ["@abp/ng.theme.shared", "@abp/ng.feature-management"] + "whitelistedNonPeerDependencies": [ + "@abp/ng.theme.shared", + "@abp/ng.feature-management", + "@abp/ng.tenant-management.config" + ] } diff --git a/npm/ng-packs/packages/tenant-management/package.json b/npm/ng-packs/packages/tenant-management/package.json index 8f59b9179d..c1b3909534 100644 --- a/npm/ng-packs/packages/tenant-management/package.json +++ b/npm/ng-packs/packages/tenant-management/package.json @@ -3,7 +3,8 @@ "version": "0.9.0", "dependencies": { "@abp/ng.theme.shared": "^0.9.0", - "@abp/ng.feature-management": "^0.9.0" + "@abp/ng.feature-management": "^0.9.0", + "@abp/ng.tenant-management.config": "^0.0.1" }, "publishConfig": { "access": "public" diff --git a/npm/ng-packs/packages/tenant-management/src/lib/constants/routes.ts b/npm/ng-packs/packages/tenant-management/src/lib/constants/routes.ts index 5aad33a3c4..ad919c8ee1 100644 --- a/npm/ng-packs/packages/tenant-management/src/lib/constants/routes.ts +++ b/npm/ng-packs/packages/tenant-management/src/lib/constants/routes.ts @@ -1,5 +1,9 @@ import { ABP, eLayoutType } from '@abp/ng.core'; +/** + * + * @deprecated since version 0.9.0 + */ export const TENANT_MANAGEMENT_ROUTES = { routes: [ { diff --git a/npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts b/npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts index f8a258da3b..5ab4f20716 100644 --- a/npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts +++ b/npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts @@ -25,6 +25,10 @@ import { NgxValidateCoreModule } from '@ngx-validate/core'; }) export class TenantManagementModule {} +/** + * + * @deprecated since version 0.9.0 + */ export function TenantManagementProviders(): Provider[] { return []; } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/setting-management.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/setting-management.ts index 427fa54e41..b9778da11f 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/setting-management.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/setting-management.ts @@ -6,3 +6,5 @@ export interface SettingTab { order: number; requiredPolicy?: string; } + +export const SETTING_TABS = [] as SettingTab[]; From cecdbfc44ae9186db99cf38ae24d01b15ae4af46 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Sep 2019 10:48:50 +0300 Subject: [PATCH 11/48] fix(tenant-management-config): exports --- .../packages/tenant-management-config/src/public-api.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/npm/ng-packs/packages/tenant-management-config/src/public-api.ts b/npm/ng-packs/packages/tenant-management-config/src/public-api.ts index 2067a98b7e..a6d21694db 100644 --- a/npm/ng-packs/packages/tenant-management-config/src/public-api.ts +++ b/npm/ng-packs/packages/tenant-management-config/src/public-api.ts @@ -1,7 +1,2 @@ -/* - * Public API Surface of tenant-management-config - */ - export * from './lib/services/tenant-management-config.service'; -export * from './lib/tenant-management-config.component'; export * from './lib/tenant-management-config.module'; From 6bc33f0ab4c868aa5e73be6f53dfb7460d52e185 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Sep 2019 11:19:20 +0300 Subject: [PATCH 12/48] feature(template): implement config modules --- .../core/src/lib/plugins/config/config.plugin.ts | 2 +- templates/app/angular/src/app/app-routing.module.ts | 10 ++-------- templates/app/angular/src/app/app.module.ts | 11 +++++++---- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts b/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts index acecc36fb3..c65955f877 100644 --- a/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts +++ b/npm/ng-packs/packages/core/src/lib/plugins/config/config.plugin.ts @@ -56,7 +56,7 @@ function transformRoutes(routes: Routes = [], wrappers: ABP.FullRoute[] = []): a routes .filter(route => route.component || route.loadChildren) .forEach(route => { - const abpPackage = ABP_ROUTES.find(abp => abp.path.toLowerCase() === route.path.toLowerCase()); + const abpPackage = ABP_ROUTES.find(abp => abp.path.toLowerCase() === route.path.toLowerCase() && !abp.wrapper); const { length } = transformed; diff --git a/templates/app/angular/src/app/app-routing.module.ts b/templates/app/angular/src/app/app-routing.module.ts index eac8712bad..d6fa06f853 100644 --- a/templates/app/angular/src/app/app-routing.module.ts +++ b/templates/app/angular/src/app/app-routing.module.ts @@ -1,9 +1,6 @@ -import { IDENTITY_ROUTES } from '@abp/ng.identity'; -import { ACCOUNT_ROUTES } from '@abp/ng.account'; -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; import { ABP } from '@abp/ng.core'; -import { TENANT_MANAGEMENT_ROUTES } from '@abp/ng.tenant-management'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { @@ -18,18 +15,15 @@ const routes: Routes = [ { path: 'account', loadChildren: () => import('./lazy-libs/account-wrapper.module').then(m => m.AccountWrapperModule), - data: { routes: ACCOUNT_ROUTES }, }, { path: 'identity', loadChildren: () => import('./lazy-libs/identity-wrapper.module').then(m => m.IdentityWrapperModule), - data: { routes: IDENTITY_ROUTES }, }, { path: 'tenant-management', loadChildren: () => import('./lazy-libs/tenant-management-wrapper.module').then(m => m.TenantManagementWrapperModule), - data: { routes: TENANT_MANAGEMENT_ROUTES }, }, ]; diff --git a/templates/app/angular/src/app/app.module.ts b/templates/app/angular/src/app/app.module.ts index 9613016256..9c5f3416de 100644 --- a/templates/app/angular/src/app/app.module.ts +++ b/templates/app/angular/src/app/app.module.ts @@ -11,9 +11,9 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { SharedModule } from './shared/shared.module'; import { ThemeSharedModule } from '@abp/ng.theme.shared'; -import { AccountProviders } from '@abp/ng.account'; -import { IdentityProviders } from '@abp/ng.identity'; -import { TenantManagementProviders } from '@abp/ng.tenant-management'; +import { AccountConfigModule } from '@abp/ng.account.config'; +import { IdentityConfigModule } from '@abp/ng.identity.config'; +import { TenantManagementConfigModule } from '@abp/ng.tenant-management.config'; @NgModule({ declarations: [AppComponent], @@ -27,13 +27,16 @@ import { TenantManagementProviders } from '@abp/ng.tenant-management'; }), OAuthModule.forRoot(), NgxsModule.forRoot([]), + AccountConfigModule.forRoot({ redirectUrl: '/' }), + IdentityConfigModule, + TenantManagementConfigModule, BrowserModule, BrowserAnimationsModule, AppRoutingModule, SharedModule, + NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production }), ], - providers: [...AccountProviders({ redirectUrl: '/' }), ...IdentityProviders(), ...TenantManagementProviders()], bootstrap: [AppComponent], }) export class AppModule {} From c4bb269f3ed7410c8c291b544a1d57b3fc240776 Mon Sep 17 00:00:00 2001 From: Xeevis Date: Fri, 27 Sep 2019 16:07:45 +0200 Subject: [PATCH 13/48] Translate documents to Czech --- .../Best-Practices/PostgreSQL-Integration.md | 30 +++---- docs/cs/Dapper.md | 22 ++--- docs/cs/Getting-Started-Angular-Template.md | 86 +++++++++---------- docs/en/Getting-Started-Angular-Template.md | 4 +- 4 files changed, 71 insertions(+), 71 deletions(-) diff --git a/docs/cs/Best-Practices/PostgreSQL-Integration.md b/docs/cs/Best-Practices/PostgreSQL-Integration.md index 9b0bf40dc2..6bf8224f1e 100644 --- a/docs/cs/Best-Practices/PostgreSQL-Integration.md +++ b/docs/cs/Best-Practices/PostgreSQL-Integration.md @@ -1,32 +1,32 @@ -## Entity Framework Core PostgreSQL Integration +## Entity Framework Core PostgreSQL integrace -> See [Entity Framework Core Integration document](../Entity-Framework-Core.md) for the basics of the EF Core integration. +> Podívejte se na [Entity Framework Core integrační dokument](../Entity-Framework-Core.md) pro základy integrace EF Core. -### EntityFrameworkCore Project Update +### Aktualizace projektu EntityFrameworkCore -- In `Acme.BookStore.EntityFrameworkCore` project replace package `Volo.Abp.EntityFrameworkCore.SqlServer` with `Volo.Abp.EntityFrameworkCore.PostgreSql` -- Update to use PostgreSQL in `BookStoreEntityFrameworkCoreModule` - - Replace the `AbpEntityFrameworkCoreSqlServerModule` with the `AbpEntityFrameworkCorePostgreSqlModule` - - Replace the `options.UseSqlServer()` with the `options.UsePostgreSql()` -- In other projects update the PostgreSQL connection string in necessary `appsettings.json` files +- V projektu `Acme.BookStore.EntityFrameworkCore` nahraďte balík `Volo.Abp.EntityFrameworkCore.SqlServer` za `Volo.Abp.EntityFrameworkCore.PostgreSql` +- Aktualizace pro použití PostgreSQL v `BookStoreEntityFrameworkCoreModule` + - Nahraďte `AbpEntityFrameworkCoreSqlServerModule` za `AbpEntityFrameworkCorePostgreSqlModule` + - Nahraďte `options.UseSqlServer()` za `options.UsePostgreSql()` +- V jiných projektech aktualizujte PostgreSQL connection string v nezbytných `appsettings.json` souborech -#### Delete Existing Migrations +#### Odstranění stávajících migrací -Delete all existing migration files (including `DbContextModelSnapshot`) +Smažte všechny stavající migrační soubory (včetně `DbContextModelSnapshot`) ![postgresql-delete-initial-migrations](images/postgresql-delete-initial-migrations.png) -#### Regenerate Initial Migration & Update the Database +#### Znovu vygenerujte počáteční migraci & aktualizujte databázi -Set the correct startup project (usually a web project), -Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), select the `Acme.BookStore.EntityFrameworkCore.DbMigrations` as the **Default project** and execute the following command: +Nastavte správný spouštěcí projekt (obvykle web projekt), +Otevřete **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console), zvolte `Acme.BookStore.EntityFrameworkCore.DbMigrations` jako **Default project** a proveďte následující příkaz: -Run `Add-Migration` command. +Proveďte příkaz `Add-Migration`: ```` PM> Add-Migration Initial ```` -Then execute the `Update-Database` command to update the database schema: +Poté proveďte příkaz `Update-Database` k aktualizaci schématu databáze: ```` PM> Update-Database diff --git a/docs/cs/Dapper.md b/docs/cs/Dapper.md index d8b17838eb..94e40347f0 100644 --- a/docs/cs/Dapper.md +++ b/docs/cs/Dapper.md @@ -1,22 +1,22 @@ -# Dapper Integration +# Dapper integrace -Because Dapper's idea is that the sql statement takes precedence, and mainly provides some extension methods for the `IDbConnection` interface. +Jelikož myšlenka Dapper je taková, že sql příkaz má přednost, tak hlavně poskytuje metody rozšíření pro `IDbConnection` rozhraní. -Abp does not encapsulate too many functions for Dapper. Abp Dapper provides a `DapperRepository` base class based on Abp EntityFrameworkCore, which provides the `IDbConnection` and `IDbTransaction` properties required by Dapper. +Abp nezapouzdřuje přílíš mnoho funkcí pro Dapper. Abp Dapper poskytuje základní třídu `DapperRepository` založenou na Abp EntityFrameworkCore, který poskytuje vlastnosti `IDbConnection` a `IDbTransaction` vyžadované v Dapper. -These two properties can work well with [Unit-Of-Work](Unit-Of-Work.md). +Tyto dvě vlastnosti fungují dobře s [jednotkou práce](Unit-Of-Work.md). -## Installation +## Instalace -Please install and configure EF Core according to [EF Core's integrated documentation](Entity-Framework-Core.md). +Nainstalujte a nakonfigurujte EF Core podle [EF Core integrační dokumentace](Entity-Framework-Core.md). -`Volo.Abp.Dapper` is the main nuget package for the Dapper integration. Install it to your project (for a layered application, to your data/infrastructure layer): +`Volo.Abp.Dapper` je hlavní NuGet balík pro Dapper integraci. Nainstalujte jej proto do vašeho projektu (pro strukturovanou aplikaci do datové/infrastrukturní vrstvy): ```shell Install-Package Volo.Abp.Dapper ``` -Then add `AbpDapperModule` module dependency (`DependsOn` attribute) to your [module](Module-Development-Basics.md): +Poté přidejte závislost na `AbpDapperModule` modulu (atribut `DependsOn`) do Vašeho [modulu](Module-Development-Basics.md): ````C# using Volo.Abp.Dapper; @@ -32,11 +32,11 @@ namespace MyCompany.MyProject } ```` -## Implement Dapper Repository +## Implementace Dapper repozitáře -The following code implements the `Person` repository, which requires EF Core's `DbContext` (MyAppDbContext). You can inject `PersonDapperRepository` to call its methods. +Následující kód implementuje repozitář `Person`, který vyžaduje `DbContext` z EF Core (MyAppDbContext). Můžete vložit `PersonDapperRepository` k volání jeho metod. -`DbConnection` and `DbTransaction` are from the `DapperRepository` base class. +`DbConnection` a `DbTransaction` jsou ze základní třídy `DapperRepository`. ```C# public class PersonDapperRepository : DapperRepository, ITransientDependency diff --git a/docs/cs/Getting-Started-Angular-Template.md b/docs/cs/Getting-Started-Angular-Template.md index 1bd605cd65..6accc637e8 100644 --- a/docs/cs/Getting-Started-Angular-Template.md +++ b/docs/cs/Getting-Started-Angular-Template.md @@ -1,49 +1,49 @@ -## Getting Started With the Angular Application Template +## Začínáme s Angular aplikační šablonou -This tutorial explain how to create a new Angular application using the startup template, configure and run it. +Tento tutoriál vysvětluje, jak vytvořit novou Angular aplikaci pomocí spouštěcí šablony, jak ji nakonfigurovat a spustit. -### Creating a New Project +### Tvorba nového projektu -This tutorial uses **ABP CLI** to create a new project. See the [Get Started](https://abp.io/get-started) page for other options. +Tento tutorial používá k vytvoření nového projektu **ABP CLI**. Podívejte se na stránku [začínáme](https://abp.io/get-started) pro více možností. -Install the ABP CLI using a command line window, if you've not installed before: +Pokud jste tak dosud neučinili, nainstalujte ABP CLI pomocí okna příkazového řádku: ````bash dotnet tool install -g Volo.Abp.Cli ```` -Use `abp new` command in an empty folder to create your project: +Použíjte příkaz `abp new` v prázdné složce k vytvoření Vašeho projektu: ````bash abp new Acme.BookStore -u angular ```` -> You can use different level of namespaces; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore. +> Můžete použít různé úrovně jmenných prostorů; např. BookStore, Acme.BookStore nebo Acme.Retail.BookStore. -`-u angular` option specifies the UI framework to be Angular. Default database provider is EF Core. See the [CLI documentation](CLI.md) for all available options. +`-u angular` volba specifikuje Angular jako UI framework. Výchozí poskytovatel databáze je EF Core. Podívejte se na [CLI dokumentaci](CLI.md) pro všechny dostupné možnosti. -#### Pre Requirements +#### Předběžné požadavky -The created solution requires; +Vytvořené řešení vyžaduje; * [Visual Studio 2017 (v15.9.0+)](https://visualstudio.microsoft.com/tr/downloads/) * [.NET Core 2.2+](https://www.microsoft.com/net/download/dotnet-core/) * [Node v10.16+](https://nodejs.org) * [Yarn v1.17+](https://yarnpkg.com/) -### The Solution Structure +### Struktura řešení -Open the solution in **Visual Studio**: +Otevřete řešení ve **Visual Studio**: ![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-for-spa.png) -The solution has a layered structure (based on [Domain Driven Design](Domain-Driven-Design.md)) and contains unit & integration test projects properly configured to work with **EF Core** & **SQLite in-memory** database. +Řešení má vrstvenou strukturu (založenou na [domain driven designu](Domain-Driven-Design.md)) a obsahuje projekty testů jednotek a integrace správně nakonfigurované pro práci s **EF Core** & **SQLite in-memory** databází. -> See the [Application Template Document](Startup-Templates/Application.md) to understand the solution structure in details. +> Podívejte se na [dokument šablony aplikace](Startup-Templates/Application.md) k detailnímu pochopení struktury řešení. -### Database Connection String +### Databázový connection string -Check the **connection string** in the `appsettings.json` file under the `.HttpApi.Host` project: +Zkontrolujte **connection string** v souboru `appsettings.json` u projektu `.HttpApi.Host`: ````json { @@ -53,74 +53,74 @@ Check the **connection string** in the `appsettings.json` file under the `.HttpA } ```` -The solution is configured to use **Entity Framework Core** with **MS SQL Server**. EF Core supports [various](https://docs.microsoft.com/en-us/ef/core/providers/) database providers, so you can use another DBMS if you want. Change the connection string if you need. +Řešení je nakonfigurováno pro použití **Entity Framework Core** s **MS SQL Server**. EF Core podporuje [různé](https://docs.microsoft.com/en-us/ef/core/providers/) poskytovatele databáze, takže pokud chcete můžete použít jiný DBMS. V případě potřeby změňte connection string. -### Create Database & Apply Database Migrations +### Tvorba databáze & aplikace migrací databáze -You have two options to create the database. +K vytvoření databáze máte dvě možnosti. -#### Using the DbMigrator Application +#### Použití aplikace DbMigrator -The solution contains a console application (named `Acme.BookStore.DbMigrator` in this sample) that can create database, apply migrations and seed initial data. It is useful on development as well as on production environment. +Řešení obsahuje konzolovou aplikaci (v tomto příkladu nazvanou `Acme.BookStore.DbMigrator`), která dokáže vytvořit databázi, aplikovat migrace a vložit počáteční data. Ta je užitečná jak pro vývojové tak pro produkční prostředí. -> `.DbMigrator` project has its own `appsettings.json`. So, if you have changed the connection string above, you should also change this one. +> `.DbMigrator` má vlastní `appsettings.json`. Pokud jste změnili connection string výše, měli byste změnit i tento. -Right click to the `.DbMigrator` project and select **Set as StartUp Project**: +Klikněte pravým na projekt `.DbMigrator` zvolte **Set as StartUp Project**: ![set-as-startup-project](images/set-as-startup-project.png) -Hit F5 (or Ctrl+F5) to run the application. It will have an output like shown below: +Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup by měl být podobný vyobrazení níže: ![set-as-startup-project](images/db-migrator-app.png) -#### Using EF Core Update-Database Command +#### Použití příkazu EF Core Update-Database -Ef Core has `Update-Database` command which creates database if necessary and applies pending migrations. Right click to the `.Web` project and select **Set as StartUp Project**: +Ef Core máš příkaz `Update-Database`, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.Web` a zvolte **Set as StartUp Project**: ![set-as-startup-project](images/set-as-startup-project.png) -Open the **Package Manager Console**, select `.EntityFrameworkCore.DbMigrations` project as the **Default Project** and run the `Update-Database` command: +Otevřete **Package Manager Console**, zvolte `.EntityFrameworkCore.DbMigrations` jako **Default Project** a proveďte příkaz `Update-Database`: ![pcm-update-database](images/pcm-update-database-v2.png) -This will create a new database based on the configured connection string. +Tímto vytvoříte novou databáze podle nakonfigurovaného connection string. -> Using the `.Migrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application. +> Je doporučeno užití nástroje `.DbMigrator`, protože zároveň vloží i počáteční data ke správnému běhu webové aplikace. -### Running the Application +### Spuštění aplikace -#### Run the API Host (Server Side) +#### Spuštění API Host (na straně serveru) -Ensure that the `.HttpApi.Host` project is the startup project and un the application which will open a Swagger UI: +Ujistěte se že je projekt `.HttpApi.Host` nastaven jako startovací a spusťte aplikaci což otevře Swagger UI: ![bookstore-homepage](images/bookstore-swagger-ui-host.png) -You can see the application APIs and test them here. Get [more info](https://swagger.io/tools/swagger-ui/) about the Swagger UI. +Tady můžete vidět API aplikace a zároveň je i otestovat. Získejte [více informací](https://swagger.io/tools/swagger-ui/) o Swagger UI. -##### Authorization for the Swagger UI +##### Autorizace pro Swagger UI -Most of the application APIs require authentication & authorization. If you want to test authorized APIs, manually go to the `/Account/Login` page, enter `admin` as the username and `1q2w3E*` as the password to login to the application. Then you will be able to execute authorized APIs too. +Vetšina API aplikace vyžaduje autentizaci & autorizaci. Pokud chcete otestovat autorizované API, manuálně přejděte na stránku `/Account/Login`, vložte `admin` jako uživatelské jméno a `1q2w3E*` jako heslo k příhlášení do aplikace. Poté budete moci provádět autorizované požadavky API. -#### Run the Angular Application (Client Side) +#### Spuštění Angular aplikace (na straně klienta) -Go to the `angular` folder, open a command line terminal, type the `yarn` command (we suggest to the [yarn](https://yarnpkg.com) package manager while npm install will also work in most cases): +Přejděte do složky `angular`, otevřete terminál příkazového řádku, proveďte příkaz `yarn` (doporučujeme používat správce balíků [yarn](https://yarnpkg.com), npm install bude v mnoha případech také fungovat): ````bash yarn ```` -Once all node modules are loaded, execute `yarn start` or `npm start` command: +Jakmile jsou načteny všechny node moduly, proveďte příkaz `yarn start` nebo `npm start`: ````bash yarn start ```` -Open your favorite browser and go to `localhost:4200` URL. Initial username is `admin` and password is `1q2w3E*`. +Otevřete Váš oblíbený prohlížeč a přejděte na adresu `localhost:4200`. Počáteční uživatelské jméno je `admin` a heslo `1q2w3E*`. -The startup template includes the **identity management** and **tenant management** modules. Once you login, the Administration menu will be available where you can manage **tenants**, **roles**, **users** and their **permissions**. +Startovací šablona obsahuje moduly **správa identit** a **správa tenantů**. Jakmile se přihlásíte, zprístupní se administrační menu kde můžete spravovat **tenanty**, **role**, **uživatele** a jejich **oprávnění**. -> We recommend [Visual Studio Code](https://code.visualstudio.com/) as the editor for the Angular project, but you are free to use your favorite editor. +> Doporučujeme [Visual Studio Code](https://code.visualstudio.com/) jako editor pro Angular projekt, ale klidně použijte Váš oblíbený editor. -### What's Next? +### Co dále? -* [Application development tutorial](Tutorials/Angular/Part-I.md) +* [Tutoriál vývoje aplikace](Tutorials/Angular/Part-I.md) diff --git a/docs/en/Getting-Started-Angular-Template.md b/docs/en/Getting-Started-Angular-Template.md index 1bd605cd65..31186eaa35 100644 --- a/docs/en/Getting-Started-Angular-Template.md +++ b/docs/en/Getting-Started-Angular-Template.md @@ -85,13 +85,13 @@ Open the **Package Manager Console**, select `.EntityFrameworkCore.DbMigrations` This will create a new database based on the configured connection string. -> Using the `.Migrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application. +> Using the `.DbMigrator` tool is the suggested way, because it also seeds the initial data to be able to properly run the web application. ### Running the Application #### Run the API Host (Server Side) -Ensure that the `.HttpApi.Host` project is the startup project and un the application which will open a Swagger UI: +Ensure that the `.HttpApi.Host` project is the startup project and run the application which will open a Swagger UI: ![bookstore-homepage](images/bookstore-swagger-ui-host.png) From cd67360bb753b370ba0236eba158993f9afca215 Mon Sep 17 00:00:00 2001 From: Xeevis Date: Fri, 27 Sep 2019 21:56:53 +0200 Subject: [PATCH 14/48] Fix case of misleading CLI update advisory --- .../Volo/Abp/Cli/CliService.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs index d7dbb70d14..1264580e17 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs @@ -169,8 +169,16 @@ namespace Volo.Abp.Cli } } + private static bool IsGlobalTool(string toolPath) + { + var globalPaths = new[] { @"%USERPROFILE%\.dotnet\tools\", "%HOME%/.dotnet/tools/", }; + return globalPaths.Select(path => Environment.ExpandEnvironmentVariables(path)).Contains(toolPath); + } + private void LogNewVersionInfo(UpdateChannel updateChannel, SemanticVersion latestVersion, string toolPath) { + var toolPathArg = IsGlobalTool(toolPath) ? "-g" : $"--tool-path {toolPath}"; + Logger.LogWarning($"ABP CLI has a newer {updateChannel.ToString().ToLowerInvariant()} version {latestVersion}, please update to get the latest features and fixes."); Logger.LogWarning(string.Empty); Logger.LogWarning("Update Command: "); @@ -179,18 +187,18 @@ namespace Volo.Abp.Cli switch (updateChannel) { case UpdateChannel.Stable: - Logger.LogWarning("dotnet tool update -g Volo.Abp.Cli"); + Logger.LogWarning($"dotnet tool update {toolPathArg} Volo.Abp.Cli"); break; case UpdateChannel.Prerelease: - Logger.LogWarning("dotnet tool uninstall -g Volo.Abp.Cli"); - Logger.LogWarning($"dotnet tool install -g Volo.Abp.Cli --version {latestVersion}"); + Logger.LogWarning($"dotnet tool uninstall {toolPathArg} Volo.Abp.Cli"); + Logger.LogWarning($"dotnet tool install {toolPathArg} Volo.Abp.Cli --version {latestVersion}"); break; case UpdateChannel.Nightly: case UpdateChannel.Development: - Logger.LogWarning("dotnet tool uninstall -g Volo.Abp.Cli"); - Logger.LogWarning($"dotnet tool install -g Volo.Abp.Cli --add-source https://www.myget.org/F/abp-nightly/api/v3/index.json --version {latestVersion}"); + Logger.LogWarning($"dotnet tool uninstall {toolPathArg} Volo.Abp.Cli"); + Logger.LogWarning($"dotnet tool install {toolPathArg} Volo.Abp.Cli --add-source https://www.myget.org/F/abp-nightly/api/v3/index.json --version {latestVersion}"); break; default: throw new ArgumentOutOfRangeException(nameof(updateChannel), updateChannel, null); From 8470b421d8ceb63921db9779b9fb8b8df9172da6 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Sat, 28 Sep 2019 00:03:00 +0300 Subject: [PATCH 15/48] feature(ng-packs): install @ngneat/spectator --- npm/ng-packs/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 009bc9d5f5..b40344ed62 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -24,6 +24,7 @@ "@angular/platform-browser-dynamic": "~8.2.7", "@angular/router": "~8.1.2", "@ng-bootstrap/ng-bootstrap": "^5.1.0", + "@ngneat/spectator": "^4.3.2", "@ngx-validate/core": "^0.0.5", "@ngxs/router-plugin": "^3.5.0", "@ngxs/storage-plugin": "^3.5.0", From 4dd1bddd41ef358624ba57fb3d31c2de9e6c98b3 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Sat, 28 Sep 2019 00:03:34 +0300 Subject: [PATCH 16/48] tests(theme-shared): add button component tests --- .../src/lib/tests/button.component.spec.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts new file mode 100644 index 0000000000..bfb70f9518 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts @@ -0,0 +1,54 @@ +import { CoreModule } from '@abp/ng.core'; +import { + createComponentFactory, + createHostFactory, + Spectator, + SpectatorHost, + createTestComponentFactory, +} from '@ngneat/spectator'; +import { ButtonComponent } from '../components'; + +describe('ButtonComponent', () => { + let host: SpectatorHost; + + const createHost = createHostFactory(ButtonComponent); + + beforeEach(() => (host = createHost(`Button`))); + + it('should display the button', () => { + expect(host.query('button')).toBeTruthy(); + }); + + it('should equal the default classes to btn btn-primary', () => { + expect(host.query('button')).toHaveClass('btn btn-primary'); + }); + + it('should equal the default type to button', () => { + expect(host.query('button')).toHaveAttribute('type', 'button'); + }); + + it('should enabled', () => { + expect(host.query('[disabled]')).toBeFalsy(); + }); + + it('should have the text content', () => { + expect(host.query('button')).toHaveText('Button'); + }); + + it('should display the icon', () => { + expect(host.query('i.d-none')).toBeFalsy(); + expect(host.query('i')).toHaveClass('fa'); + }); + + it('should display the spinner icon', () => { + host.component.loading = true; + host.detectComponentChanges(); + expect(host.query('i')).toHaveClass('fa-spinner'); + }); + + it('should disabled when the loading input is true', () => { + host.component.loading = true; + host.detectComponentChanges(); + expect(host.query('[disabled]')).toBeDefined(); + }); +}); From 0bcd977d1df796f6fed38ea2f40f87eaa6591237 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Sat, 28 Sep 2019 14:30:40 +0300 Subject: [PATCH 17/48] feature: error handler tests --- .../src/lib/handlers/error.handler.ts | 53 ++++++++------- .../src/lib/tests/error.handler.spec.ts | 64 +++++++++++++++++++ 2 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts index 0baff0da8f..d18cd45bf1 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts @@ -16,26 +16,31 @@ import { Toaster } from '../models/toaster'; import { ConfirmationService } from '../services/confirmation.service'; import snq from 'snq'; -const DEFAULTS = { +export const DEFAULT_ERROR_MESSAGES = { defaultError: { - message: 'An error has occurred!', + title: 'An error has occurred!', details: 'Error detail not sent by server.', }, - defaultError401: { - message: 'You are not authenticated!', + title: 'You are not authenticated!', details: 'You should be authenticated (sign in) in order to perform this operation.', }, - defaultError403: { - message: 'You are not authorized!', + title: 'You are not authorized!', details: 'You are not allowed to perform this operation.', }, - defaultError404: { - message: 'Resource not found!', + title: 'Resource not found!', details: 'The resource requested could not found on the server.', }, + defaultError500: { + title: '500', + details: 'AbpAccount::InternalServerErrorMessage', + }, + defaultErrorUnknown: { + title: 'Unknown Error', + details: 'AbpAccount::InternalServerErrorMessage', + }, }; @Injectable({ providedIn: 'root' }) @@ -51,7 +56,7 @@ export class ErrorHandler { ) { actions.pipe(ofActionSuccessful(RestOccurError)).subscribe(res => { const { payload: err = {} as HttpErrorResponse | any } = res; - const body = snq(() => (err as HttpErrorResponse).error.error, DEFAULTS.defaultError.message); + const body = snq(() => (err as HttpErrorResponse).error.error, DEFAULT_ERROR_MESSAGES.defaultError.title); if (err instanceof HttpErrorResponse && err.headers.get('_AbpErrorFormat')) { const confirmation$ = this.showError(null, null, body); @@ -64,35 +69,39 @@ export class ErrorHandler { } else { switch ((err as HttpErrorResponse).status) { case 401: - this.showError(DEFAULTS.defaultError401.details, DEFAULTS.defaultError401.message).subscribe(() => - this.navigateToLogin(), - ); + this.showError( + DEFAULT_ERROR_MESSAGES.defaultError401.details, + DEFAULT_ERROR_MESSAGES.defaultError401.title, + ).subscribe(() => this.navigateToLogin()); break; case 403: this.createErrorComponent({ - title: DEFAULTS.defaultError403.message, - details: DEFAULTS.defaultError403.details, + title: DEFAULT_ERROR_MESSAGES.defaultError403.title, + details: DEFAULT_ERROR_MESSAGES.defaultError403.details, }); break; case 404: - this.showError(DEFAULTS.defaultError404.details, DEFAULTS.defaultError404.message); + this.showError( + DEFAULT_ERROR_MESSAGES.defaultError404.details, + DEFAULT_ERROR_MESSAGES.defaultError404.title, + ); break; case 500: this.createErrorComponent({ - title: '500', - details: 'AbpAccount::InternalServerErrorMessage', + title: DEFAULT_ERROR_MESSAGES.defaultError500.title, + details: DEFAULT_ERROR_MESSAGES.defaultError500.details, }); break; case 0: if ((err as HttpErrorResponse).statusText === 'Unknown Error') { this.createErrorComponent({ - title: 'Unknown Error', - details: 'AbpAccount::InternalServerErrorMessage', + title: DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.title, + details: DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.details, }); } break; default: - this.showError(DEFAULTS.defaultError.details, DEFAULTS.defaultError.message); + this.showError(DEFAULT_ERROR_MESSAGES.defaultError.details, DEFAULT_ERROR_MESSAGES.defaultError.title); break; } } @@ -105,7 +114,7 @@ export class ErrorHandler { message = body.details; title = body.message; } else { - message = body.message || DEFAULTS.defaultError.message; + message = body.message || DEFAULT_ERROR_MESSAGES.defaultError.title; } } @@ -125,7 +134,7 @@ export class ErrorHandler { createErrorComponent(instance: Partial) { const renderer = this.rendererFactory.createRenderer(null, null); - const host = renderer.selectRootElement('app-root', true); + const host = renderer.selectRootElement(document.body, true); const componentRef = this.cfRes.resolveComponentFactory(ErrorComponent).create(this.injector); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts new file mode 100644 index 0000000000..0f64652cfe --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts @@ -0,0 +1,64 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator'; +import { Component } from '@angular/core'; +import { ErrorHandler, DEFAULT_ERROR_MESSAGES } from '../handlers'; +import { CoreModule, RestOccurError } from '@abp/ng.core'; +import { ThemeSharedModule } from '../theme-shared.module'; +import { NgxsModule, Store } from '@ngxs/store'; +import { RouterModule } from '@angular/router'; +import { HttpErrorResponse } from '@angular/common/http'; + +@Component({ selector: 'dummy', template: 'dummy works! ' }) +class DummyComponent { + constructor(public errorHandler: ErrorHandler, public store: Store) {} +} + +describe('With Custom Host Component', function() { + let host: SpectatorHost; + const createHost = createHostFactory({ + component: DummyComponent, + imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot([]), RouterModule.forRoot([])], + }); + + beforeEach(() => { + host = createHost(``); + const abpError = document.querySelector('abp-error'); + if (abpError) document.body.removeChild(abpError); + }); + + it('should display the error component when server error occurs', () => { + host.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 500 }))); + host.detectChanges(); + expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError500.title); + expect(document.querySelector('.error-details')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError500.details); + }); + + it('should display the error component when authorize error occurs', () => { + host.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 403 }))); + host.detectChanges(); + expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError403.title); + expect(document.querySelector('.error-details')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError403.details); + }); + + it('should display the error component when unknown error occurs', () => { + host.component.store.dispatch( + new RestOccurError(new HttpErrorResponse({ status: 0, statusText: 'Unknown Error' })), + ); + host.detectChanges(); + expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.title); + expect(document.querySelector('.error-details')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.details); + }); + + it('should display the confirmation when not found error occurs', () => { + host.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 404 }))); + host.detectChanges(); + expect(host.query('.abp-confirm-summary')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError404.title); + expect(host.query('.abp-confirm-body')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError404.details); + }); + + it('should display the confirmation when default error occurs', () => { + host.component.store.dispatch(new RestOccurError(new HttpErrorResponse({ status: 412 }))); + host.detectChanges(); + expect(host.query('.abp-confirm-summary')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError.title); + expect(host.query('.abp-confirm-body')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultError.details); + }); +}); From c762edc1498d03f97f8aabc476e166b78e1bd116 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Mon, 30 Sep 2019 09:42:04 +0300 Subject: [PATCH 18/48] feature: add 401 error tests fix: some for directive bugs --- .../core/src/lib/directives/for.directive.ts | 2 + .../theme-shared/src/lib/abstracts/toaster.ts | 2 +- .../confirmation/confirmation.component.ts | 9 ++- .../src/lib/tests/error.handler.spec.ts | 63 ++++++++++++++++--- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts index 604f7a8660..f9c5abeb56 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts @@ -113,8 +113,10 @@ export class ForDirective implements OnChanges { private projectItems(items: any[]): void { if (!items.length && this.emptyRef) { + this.vcRef.clear(); this.vcRef.createEmbeddedView(this.emptyRef).rootNodes; this.isShowEmptyRef = true; + this.differ = null; return; } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/abstracts/toaster.ts b/npm/ng-packs/packages/theme-shared/src/lib/abstracts/toaster.ts index 5dbba869f1..9172297039 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/abstracts/toaster.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/abstracts/toaster.ts @@ -2,7 +2,7 @@ import { MessageService } from 'primeng/components/common/messageservice'; import { Observable, Subject } from 'rxjs'; import { Toaster } from '../models/toaster'; -export class AbstractToaster { +export abstract class AbstractToaster { status$: Subject; key: string = 'abpToast'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts index 39cf9b73a2..398f975ff7 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts @@ -23,11 +23,18 @@ import { Toaster } from '../../models/toaster';
`, - styleUrls: ['./loader-bar.component.scss'], + styleUrls: ['./loader-bar.component.scss'] }) export class LoaderBarComponent implements OnDestroy { - @Input() - containerClass: string = 'abp-loader-bar'; - - @Input() - color: string = '#77b6ff'; - - @Input() - isLoading: boolean = false; - - @Input() - filter = (action: StartLoader | StopLoader) => action.payload.url.indexOf('openid-configuration') < 0; - - progressLevel: number = 0; - - interval: Subscription; - - timer: Subscription; - get boxShadow(): string { return `0 0 10px rgba(${this.color}, 0.5)`; } @@ -50,7 +32,7 @@ export class LoaderBarComponent implements OnDestroy { .pipe( ofActionSuccessful(StartLoader, StopLoader), filter(this.filter), - takeUntilDestroy(this), + takeUntilDestroy(this) ) .subscribe(action => { if (action instanceof StartLoader) this.startLoading(); @@ -61,15 +43,32 @@ export class LoaderBarComponent implements OnDestroy { .pipe( filter( event => - event instanceof NavigationStart || event instanceof NavigationEnd || event instanceof NavigationError, + event instanceof NavigationStart || event instanceof NavigationEnd || event instanceof NavigationError ), - takeUntilDestroy(this), + takeUntilDestroy(this) ) .subscribe(event => { if (event instanceof NavigationStart) this.startLoading(); else this.stopLoading(); }); } + @Input() + containerClass = 'abp-loader-bar'; + + @Input() + color = '#77b6ff'; + + @Input() + isLoading = false; + + progressLevel = 0; + + interval: Subscription; + + timer: Subscription; + + @Input() + filter = (action: StartLoader | StopLoader) => action.payload.url.indexOf('openid-configuration') < 0; ngOnDestroy() { this.interval.unsubscribe(); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts index e38ba270cb..5e6ebff228 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts @@ -9,7 +9,7 @@ import { Renderer2, TemplateRef, ViewChild, - ViewChildren, + ViewChildren } from '@angular/core'; import { fromEvent, Subject, timer } from 'rxjs'; import { filter, take, takeUntil, debounceTime } from 'rxjs/operators'; @@ -23,7 +23,7 @@ const ANIMATION_TIMEOUT = 200; @Component({ selector: 'abp-modal', - templateUrl: './modal.component.html', + templateUrl: './modal.component.html' }) export class ModalComponent implements OnDestroy { @Input() @@ -51,7 +51,7 @@ export class ModalComponent implements OnDestroy { this.renderer.addClass(this.modalContent.nativeElement, 'fade-out-top'); setTimeout(() => { this.setVisible(value); - this.ngOnDestroy(); + this.destroy$.next(); }, ANIMATION_TIMEOUT - 10); } } @@ -68,9 +68,9 @@ export class ModalComponent implements OnDestroy { this._busy = value; } - @Input() centered: boolean = false; + @Input() centered = false; - @Input() modalClass: string = ''; + @Input() modalClass = ''; @Input() size: ModalSize = 'lg'; @@ -78,9 +78,9 @@ export class ModalComponent implements OnDestroy { @Input() minHeight: number; - @Output() visibleChange = new EventEmitter(); + @Output() readonly visibleChange = new EventEmitter(); - @Output() init = new EventEmitter(); + @Output() readonly init = new EventEmitter(); @ContentChild('abpHeader', { static: false }) abpHeader: TemplateRef; @@ -88,29 +88,29 @@ export class ModalComponent implements OnDestroy { @ContentChild('abpFooter', { static: false }) abpFooter: TemplateRef; - @ContentChild('abpClose', { static: false, read: ElementRef }) abpClose: ElementRef; + @ContentChild('abpClose', { static: false, read: ElementRef }) + abpClose: ElementRef; - @ContentChild(ButtonComponent, { static: false, read: ButtonComponent }) abpSubmit: ButtonComponent; + @ContentChild(ButtonComponent, { static: false, read: ButtonComponent }) + abpSubmit: ButtonComponent; @ViewChild('abpModalContent', { static: false }) modalContent: ElementRef; @ViewChildren('abp-button') abpButtons; - @Output() - show = new EventEmitter(); + @Output() readonly appear = new EventEmitter(); - @Output() - hide = new EventEmitter(); + @Output() readonly disappear = new EventEmitter(); - _visible: boolean = false; + _visible = false; - _busy: boolean = false; + _busy = false; - showModal: boolean = false; + showModal = false; - isOpenConfirmation: boolean = false; + isOpenConfirmation = false; - closable: boolean = false; + closable = false; destroy$ = new Subject(); @@ -131,11 +131,11 @@ export class ModalComponent implements OnDestroy { .subscribe(_ => (this.closable = true)); this.renderer.addClass(document.body, 'modal-open'); - this.show.emit(); + this.appear.emit(); } else { this.closable = false; this.renderer.removeClass(document.body, 'modal-open'); - this.hide.emit(); + this.disappear.emit(); } } @@ -144,7 +144,7 @@ export class ModalComponent implements OnDestroy { .pipe( takeUntil(this.destroy$), debounceTime(150), - filter((key: KeyboardEvent) => key && key.code === 'Escape' && this.closable), + filter((key: KeyboardEvent) => key && key.code === 'Escape' && this.closable) ) .subscribe(_ => { this.close(); @@ -155,7 +155,7 @@ export class ModalComponent implements OnDestroy { fromEvent(this.abpClose.nativeElement, 'click') .pipe( takeUntil(this.destroy$), - filter(() => !!(this.closable && this.modalContent)), + filter(() => !!(this.closable && this.modalContent)) ) .subscribe(() => this.close()); }, 0); @@ -167,7 +167,7 @@ export class ModalComponent implements OnDestroy { if (!this.closable || this.busy) return; const nodes = getFlatNodes( - (this.modalContent.nativeElement.querySelector('#abp-modal-body') as HTMLElement).childNodes, + (this.modalContent.nativeElement.querySelector('#abp-modal-body') as HTMLElement).childNodes ); if (hasNgDirty(nodes)) { @@ -194,7 +194,7 @@ export class ModalComponent implements OnDestroy { function getFlatNodes(nodes: NodeList): HTMLElement[] { return Array.from(nodes).reduce( (acc, val) => [...acc, ...(val.childNodes && val.childNodes.length ? getFlatNodes(val.childNodes) : [val])], - [], + [] ); } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/profile/profile.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/profile/profile.component.ts index 0dc8ef2768..e7d110365b 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/profile/profile.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/profile/profile.component.ts @@ -9,7 +9,7 @@ const { maxLength, required, email } = Validators; @Component({ selector: 'abp-profile', - templateUrl: './profile.component.html', + templateUrl: './profile.component.html' }) export class ProfileComponent implements OnChanges { protected _visible; @@ -24,15 +24,14 @@ export class ProfileComponent implements OnChanges { this.visibleChange.emit(value); } - @Output() - visibleChange = new EventEmitter(); + @Output() readonly visibleChange = new EventEmitter(); @Select(ProfileState.getProfile) profile$: Observable; form: FormGroup; - modalBusy: boolean = false; + modalBusy = false; constructor(private fb: FormBuilder, private store: Store) {} @@ -41,7 +40,7 @@ export class ProfileComponent implements OnChanges { .dispatch(new GetProfile()) .pipe( withLatestFrom(this.profile$), - take(1), + take(1) ) .subscribe(([, profile]) => { this.form = this.fb.group({ @@ -49,7 +48,7 @@ export class ProfileComponent implements OnChanges { email: [profile.email, [required, email, maxLength(256)]], name: [profile.name || '', [maxLength(64)]], surname: [profile.surname || '', [maxLength(64)]], - phoneNumber: [profile.phoneNumber || '', [maxLength(16)]], + phoneNumber: [profile.phoneNumber || '', [maxLength(16)]] }); }); } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/table-empty-message/table-empty-message.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/table-empty-message/table-empty-message.component.ts index e53b90129e..5924a9f187 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/table-empty-message/table-empty-message.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/table-empty-message/table-empty-message.component.ts @@ -1,12 +1,13 @@ import { Component, OnInit, Input } from '@angular/core'; @Component({ + // tslint:disable-next-line: component-selector selector: '[abp-table-empty-message]', template: ` {{ emptyMessage | abpLocalization }} - `, + ` }) export class TableEmptyMessageComponent { @Input() @@ -16,10 +17,10 @@ export class TableEmptyMessageComponent { message: string; @Input() - localizationResource: string = 'AbpAccount'; + localizationResource = 'AbpAccount'; @Input() - localizationProp: string = 'NoDataAvailableInDatatable'; + localizationProp = 'NoDataAvailableInDatatable'; get emptyMessage(): string { return this.message || `${this.localizationResource}::${this.localizationProp}`; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.ts index 382b18974b..422c67f3b9 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/toast/toast.component.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'abp-toast', + // tslint:disable-next-line: component-max-inline-declarations template: ` @@ -20,6 +21,6 @@ import { Component } from '@angular/core';
- `, + ` }) export class ToastComponent {} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/contants/scripts.ts b/npm/ng-packs/packages/theme-shared/src/lib/contants/scripts.ts index 1bc3ad0fa9..08d725cd4e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/contants/scripts.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/contants/scripts.ts @@ -1 +1 @@ -export default ``; +export default ''; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts index f8338d95e8..69bb5eaf72 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts @@ -8,9 +8,9 @@ import { Toaster } from '../models/toaster'; @Injectable({ providedIn: 'root' }) export class ConfirmationService extends AbstractToaster { - key: string = 'abpConfirmation'; + key = 'abpConfirmation'; - sticky: boolean = true; + sticky = true; destroy$ = new Subject(); @@ -22,7 +22,7 @@ export class ConfirmationService extends AbstractToaster { message: string, title: string, severity: Toaster.Severity, - options?: Confirmation.Options, + options?: Confirmation.Options ): Observable { this.listenToEscape(); @@ -40,7 +40,7 @@ export class ConfirmationService extends AbstractToaster { .pipe( takeUntil(this.destroy$), debounceTime(150), - filter((key: KeyboardEvent) => key && key.code === 'Escape'), + filter((key: KeyboardEvent) => key && key.code === 'Escape') ) .subscribe(_ => { this.clear(); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts index bfb70f9518..b8682ae224 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts @@ -4,7 +4,7 @@ import { createHostFactory, Spectator, SpectatorHost, - createTestComponentFactory, + createTestComponentFactory } from '@ngneat/spectator'; import { ButtonComponent } from '../components'; @@ -13,7 +13,7 @@ describe('ButtonComponent', () => { const createHost = createHostFactory(ButtonComponent); - beforeEach(() => (host = createHost(`Button`))); + beforeEach(() => (host = createHost('Button'))); it('should display the button', () => { expect(host.query('button')).toBeTruthy(); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts index 835f4a33a9..26e3753609 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts @@ -9,18 +9,18 @@ import { NgxsResetPluginModule, StateOverwrite } from 'ngxs-reset-plugin'; import { DEFAULT_ERROR_MESSAGES, ErrorHandler } from '../handlers'; import { ThemeSharedModule } from '../theme-shared.module'; -@Component({ selector: 'dummy', template: 'dummy works! ' }) +@Component({ selector: 'abp-dummy', template: 'dummy works! ' }) class DummyComponent { constructor(public errorHandler: ErrorHandler, public store: Store) {} } -describe('With Custom Host Component', function() { +describe('With Custom Host Component', () => { let component: SpectatorRouting; const createComponent = createRoutingFactory({ component: DummyComponent, imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot([]), NgxsResetPluginModule.forRoot()], stubsEnabled: false, - routes: [{ path: '', component: DummyComponent }, { path: 'account/login', component: RouterOutletComponent }], + routes: [{ path: '', component: DummyComponent }, { path: 'account/login', component: RouterOutletComponent }] }); beforeEach(() => { @@ -45,7 +45,7 @@ describe('With Custom Host Component', function() { it('should display the error component when unknown error occurs', () => { component.component.store.dispatch( - new RestOccurError(new HttpErrorResponse({ status: 0, statusText: 'Unknown Error' })), + new RestOccurError(new HttpErrorResponse({ status: 0, statusText: 'Unknown Error' })) ); component.detectChanges(); expect(document.querySelector('.error-template')).toHaveText(DEFAULT_ERROR_MESSAGES.defaultErrorUnknown.title); @@ -97,9 +97,9 @@ describe('With Custom Host Component', function() { new HttpErrorResponse({ error: { error: { message: 'test message', details: 'test detail' } }, status: 412, - headers, - }), - ), + headers + }) + ) ); component.detectChanges(); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts index 58e2ab5bb4..a1839f6217 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts @@ -21,7 +21,7 @@ import { TableEmptyMessageComponent } from './components/table-empty-message/tab import { NgxValidateCoreModule } from '@ngx-validate/core'; export function appendScript(injector: Injector) { - const fn = function() { + const fn = () => { import('chart.js').then(() => chartJsLoaded$.next(true)); const lazyLoadService: LazyLoadService = injector.get(LazyLoadService); @@ -32,8 +32,8 @@ export function appendScript(injector: Injector) { 'style', styles, 'head', - 'afterbegin', - ) /* lazyLoadService.load(null, 'script', scripts) */, + 'afterbegin' + ) /* lazyLoadService.load(null, 'script', scripts) */ ).pipe(take(1)); }; @@ -53,7 +53,7 @@ export function appendScript(injector: Injector) { ModalComponent, ProfileComponent, TableEmptyMessageComponent, - ToastComponent, + ToastComponent ], exports: [ BreadcrumbComponent, @@ -65,9 +65,9 @@ export function appendScript(injector: Injector) { ModalComponent, ProfileComponent, TableEmptyMessageComponent, - ToastComponent, + ToastComponent ], - entryComponents: [ErrorComponent], + entryComponents: [ErrorComponent] }) export class ThemeSharedModule { static forRoot(): ModuleWithProviders { @@ -78,10 +78,10 @@ export class ThemeSharedModule { provide: APP_INITIALIZER, multi: true, deps: [Injector, ErrorHandler], - useFactory: appendScript, + useFactory: appendScript }, - { provide: MessageService, useClass: MessageService }, - ], + { provide: MessageService, useClass: MessageService } + ] }; } } diff --git a/npm/ng-packs/packages/theme-shared/tslint.json b/npm/ng-packs/packages/theme-shared/tslint.json index 124133f849..9d39c7dc74 100644 --- a/npm/ng-packs/packages/theme-shared/tslint.json +++ b/npm/ng-packs/packages/theme-shared/tslint.json @@ -1,17 +1,7 @@ { "extends": "../../tslint.json", "rules": { - "directive-selector": [ - true, - "attribute", - "lib", - "camelCase" - ], - "component-selector": [ - true, - "element", - "lib", - "kebab-case" - ] + "directive-selector": [true, "attribute", "abp", "camelCase"], + "component-selector": [true, "element", "abp", "kebab-case"] } } diff --git a/npm/ng-packs/tslint.json b/npm/ng-packs/tslint.json index 0888c34adb..348320008c 100644 --- a/npm/ng-packs/tslint.json +++ b/npm/ng-packs/tslint.json @@ -1,55 +1,100 @@ { "extends": "tslint:recommended", + "rulesDirectory": ["node_modules/codelyzer"], "rules": { "array-type": false, + "contextual-lifecycle": true, + "component-class-suffix": [true, "Component"], + "directive-class-suffix": [true, "Directive"], + "max-line-length": [true, 140], + "no-consecutive-blank-lines": false, + "no-redundant-jsdoc": true, + "no-var-requires": false, + "object-literal-key-quotes": [true, "as-needed"], + "ordered-imports": false, + "trailing-comma": false, + "component-max-inline-declarations": [true, { "animations": 20, "styles": 10, "template": 10 }], + "no-forward-ref": true, + "no-lifecycle-call": true, + "no-pipe-impure": true, + "no-queries-metadata-property": true, + "no-unused-css": true, + "prefer-output-readonly": true, + "template-conditional-complexity": [true, 4], + "use-component-selector": true, + "max-classes-per-file": false, "arrow-parens": false, + "arrow-return-shorthand": true, + "callable-types": true, + "class-name": true, + "component-selector": [true, "element", "abp", "kebab-case"], + "curly": false, "deprecation": { "severity": "warn" }, - "component-class-suffix": true, - "contextual-lifecycle": true, - "directive-class-suffix": true, "directive-selector": [true, "attribute", "abp", "camelCase"], - "component-selector": [true, "element", "abp", "kebab-case"], + "forin": true, "import-blacklist": [true, "rxjs/Rx"], - "interface-name": false, - "max-classes-per-file": false, - "max-line-length": [true, 140], - "member-access": false, + "interface-over-type-literal": true, + "interface-name": [true, "never-prefix"], + "member-access": [true, "no-public"], "member-ordering": [ true, { "order": ["static-field", "instance-field", "static-method", "instance-method"] } ], - "no-consecutive-blank-lines": false, + "no-arg": true, + "no-bitwise": true, + "no-conflicting-lifecycle": true, "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-empty-interface": true, "no-empty": false, - "no-inferrable-types": [false, "ignore-params"], - "no-non-null-assertion": true, - "no-redundant-jsdoc": true, - "no-switch-case-fall-through": true, - "no-use-before-declare": true, - "no-var-requires": false, - "curly": false, - "object-literal-key-quotes": [true, "as-needed"], - "object-literal-sort-keys": false, - "ordered-imports": false, - "quotemark": [true, "single"], - "trailing-comma": false, - "no-conflicting-lifecycle": true, + "no-eval": true, "no-host-metadata-property": true, - "no-input-rename": true, + "no-inferrable-types": [true, "ignore-params"], + "no-input-rename": false, "no-inputs-metadata-property": true, + "no-misused-new": true, + "no-namespace": false, + "no-non-null-assertion": true, "no-output-native": true, "no-output-on-prefix": true, - "no-output-rename": true, + "no-output-rename": false, "no-outputs-metadata-property": true, - "no-namespace": false, - "template-banana-in-box": true, - "template-no-negated-async": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-unnecessary-initializer": true, + "no-unnecessary-semicolons": false, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "prefer-const": true, + "quotemark": [true, "single", "avoid-escape", "avoid-template"], + "radix": true, + "semicolon": [true, "always", "ignore-bound-class-methods"], + // "template-accessibility-alt-text": true, + // "template-accessibility-elements-content": true, + // "template-accessibility-label-for": true, + // "template-accessibility-tabindex-no-positive": true, + // "template-accessibility-table-scope": true, + // "template-accessibility-valid-aria": true, + // "template-banana-in-box": true, + // "template-click-events-have-key-events": true, + // "template-mouse-events-have-key-events": true, + // "template-no-autofocus": true, + // "template-no-distracting-elements": true, + // "template-no-negated-async": true, + "triple-equals": [true, "allow-null-check"], + "unified-signatures": true, "use-lifecycle-interface": true, - "use-pipe-transform-interface": true - }, - "rulesDirectory": ["codelyzer"] + "use-pipe-transform-interface": true, + "variable-name": false, + "prefer-for-of": false + } } From b913396358650a1caf16556478fbbfcb538d8ead Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 1 Oct 2019 11:37:08 +0300 Subject: [PATCH 30/48] chore: update workspace settings --- npm/ng-packs/.vscode/settings.json | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/.vscode/settings.json b/npm/ng-packs/.vscode/settings.json index a768ac15eb..ba819b4f57 100644 --- a/npm/ng-packs/.vscode/settings.json +++ b/npm/ng-packs/.vscode/settings.json @@ -1,5 +1,22 @@ { "search.exclude": { "**/dist": true - } -} \ No newline at end of file + }, + "tslint.rulesDirectory": "../node_modules/codelyzer", + "typescript.tsdk": "../node_modules/typescript/lib", + "workbench.colorCustomizations": { + "activityBar.background": "#df7fa2", + "activityBar.foreground": "#15202b", + "activityBar.inactiveForeground": "#15202b99", + "activityBarBadge.background": "#c7ecb3", + "activityBarBadge.foreground": "#15202b", + "titleBar.activeBackground": "#d55685", + "titleBar.inactiveBackground": "#d5568599", + "titleBar.activeForeground": "#15202b", + "titleBar.inactiveForeground": "#15202b99", + "statusBar.background": "#d55685", + "statusBarItem.hoverBackground": "#c73169", + "statusBar.foreground": "#15202b" + }, + "peacock.color": "#d55685" +} From 1c484a2b8d11a1e5161b35b96eff6040915f9216 Mon Sep 17 00:00:00 2001 From: TheDiaval Date: Tue, 1 Oct 2019 11:38:03 +0300 Subject: [PATCH 31/48] bump: change build-angular and build-ng-packagr versions --- npm/ng-packs/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index b40344ed62..019aa90d26 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -9,8 +9,8 @@ "@abp/ng.feature-management": "^0.9.0", "@abp/ng.permission-management": "^0.9.0", "@abp/ng.theme.shared": "^0.9.0", - "@angular-devkit/build-angular": "~0.803.5", - "@angular-devkit/build-ng-packagr": "~0.803.5", + "@angular-devkit/build-angular": "~0.803.6", + "@angular-devkit/build-ng-packagr": "~0.803.6", "@angular/animations": "~8.2.7", "@angular/cdk": "^8.0.1", "@angular/cli": "~8.3.5", From bb6462e2c2dc8957a458ddf1e3a2bed5799b4530 Mon Sep 17 00:00:00 2001 From: TheDiaval Date: Tue, 1 Oct 2019 16:06:20 +0300 Subject: [PATCH 32/48] refactor(theme-shared): change collapse and fade animations --- .../src/lib/animations/collapse.animations.ts | 53 +++++++++++++------ .../src/lib/animations/fade.animations.ts | 30 +++++------ 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/animations/collapse.animations.ts b/npm/ng-packs/packages/theme-shared/src/lib/animations/collapse.animations.ts index af71b948df..ad6cf81e70 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/animations/collapse.animations.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/animations/collapse.animations.ts @@ -1,19 +1,40 @@ -import { trigger, state, style, transition, animate } from '@angular/animations'; +import { animate, animation, trigger, state, style, transition, useAnimation } from '@angular/animations'; + +export const collapseY = animation( + [ + style({ height: '*', overflow: 'hidden', 'box-sizing': 'border-box' }), + animate('{{ time }} {{ easing }}', style({ height: '0', padding: '0px' })) + ], + { params: { time: '350ms', easing: 'ease' } } +); + +export const collapseX = animation( + [ + style({ width: '*', overflow: 'hidden', 'box-sizing': 'border-box' }), + animate('{{ time }} {{ easing }}', style({ width: '0', padding: '0px' })) + ], + { params: { time: '350ms', easing: 'ease' } } +); + +export const expandY = animation( + [ + style({ height: '0', overflow: 'hidden', 'box-sizing': 'border-box' }), + animate('{{ time }} {{ easing }}', style({ height: '*', padding: '*' })) + ], + { params: { time: '350ms', easing: 'ease' } } +); + +export const expandX = animation( + [ + style({ width: '0', overflow: 'hidden', 'box-sizing': 'border-box' }), + animate('{{ time }} {{ easing }}', style({ width: '*', padding: '*' })) + ], + { params: { time: '350ms', easing: 'ease' } } +); export const collapse = trigger('collapse', [ - state( - 'open', - style({ - height: '*', - overflow: 'hidden' - }) - ), - state( - 'close', - style({ - height: '0px', - overflow: 'hidden' - }) - ), - transition('open <=> close', animate('{{duration}}ms'), { params: { duration: '350' } }) + state('collapsed', style({ height: '0', overflow: 'hidden' })), + state('expanded', style({ height: '*', overflow: 'hidden' })), + transition('expanded => collapsed', useAnimation(collapseY)), + transition('collapsed => expanded', useAnimation(expandY)) ]); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/animations/fade.animations.ts b/npm/ng-packs/packages/theme-shared/src/lib/animations/fade.animations.ts index fb523e0d56..60be602291 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/animations/fade.animations.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/animations/fade.animations.ts @@ -1,19 +1,15 @@ -import { animate, state, style, transition, trigger } from '@angular/animations'; +import { animate, animation, style } 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 }))), -]); +export const fadeIn = animation( + [style({ opacity: '0', display: '{{ display }}' }), animate('{{ time}} {{ easing }}', style({ opacity: '1' }))], + { params: { time: '350ms', easing: 'ease', display: 'block' } } +); -export const fadeWithStates = trigger('fadeInOut', [ - state('out', style({ opacity: 0 })), - state('in', style({ opacity: 1 })), - transition('in <=> out', [animate(250)]), -]); - -export const fadeIn = trigger('fadeIn', [ - state('*', style({ opacity: 1 })), - transition('* => *', [style({ opacity: 0 }), animate(250)]), - transition(':enter', [style({ opacity: 0 }), animate(250)]), -]); +export const fadeOut = animation( + [ + style({ opacity: '1' }), + animate('{{ time}} {{ easing }}', style({ opacity: '0' })), + style({ opacity: '0', display: 'none' }) + ], + { params: { time: '350ms', easing: 'ease' } } +); From 40513fbd1b06d176a5a1741dea57067820b8e3a3 Mon Sep 17 00:00:00 2001 From: TheDiaval Date: Tue, 1 Oct 2019 16:06:47 +0300 Subject: [PATCH 33/48] feature(theme-shared): add bounceIn animation --- .../src/lib/animations/bounce.animations.ts | 23 +++++++++++++++++++ .../theme-shared/src/lib/animations/index.ts | 1 + 2 files changed, 24 insertions(+) create mode 100644 npm/ng-packs/packages/theme-shared/src/lib/animations/bounce.animations.ts diff --git a/npm/ng-packs/packages/theme-shared/src/lib/animations/bounce.animations.ts b/npm/ng-packs/packages/theme-shared/src/lib/animations/bounce.animations.ts new file mode 100644 index 0000000000..ccdc62c491 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/animations/bounce.animations.ts @@ -0,0 +1,23 @@ +import { animation, animate, style, trigger, transition, state, useAnimation, keyframes } from '@angular/animations'; + +export const bounceIn = animation( + [ + style({ opacity: '0', display: '{{ display }}' }), + animate( + '{{ time}} {{ easing }}', + keyframes([ + style({ opacity: '0', transform: '{{ transform }} scale(0.0)', offset: 0 }), + style({ opacity: '0', transform: '{{ transform }} scale(0.8)', offset: 0.5 }), + style({ opacity: '1', transform: '{{ transform }} scale(1.0)', offset: 1 }) + ]) + ) + ], + { + params: { + time: '350ms', + easing: 'cubic-bezier(.7,.31,.72,1.47)', + display: 'block', + transform: 'translate(-50%, -50%)' + } + } +); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/animations/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/animations/index.ts index 50772ccedc..5a7009be17 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/animations/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/animations/index.ts @@ -1,3 +1,4 @@ export * from './collapse.animations'; export * from './fade.animations'; export * from './slide.animations'; +export * from './bounce.animations'; From 45ebb59a4908ef8db9e454da7ef4cae285a41845 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 2 Oct 2019 13:59:33 +0300 Subject: [PATCH 34/48] fix: some bugs --- .../application-configuration.service.ts | 3 +- .../src/lib/services/localization.service.ts | 13 +++---- .../core/src/lib/services/rest.service.ts | 7 ++-- .../core/src/lib/states/config.state.ts | 35 ++++++++++--------- .../core/src/lib/utils/initial-utils.ts | 3 +- .../setting-management.component.html | 3 -- .../setting-management.component.ts | 6 ++-- 7 files changed, 32 insertions(+), 38 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/application-configuration.service.ts b/npm/ng-packs/packages/core/src/lib/services/application-configuration.service.ts index d0a653e1e0..5081f94068 100644 --- a/npm/ng-packs/packages/core/src/lib/services/application-configuration.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/application-configuration.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { ApplicationConfiguration, Rest } from '../models'; +import { Rest } from '../models/rest'; +import { ApplicationConfiguration } from '../models/application-configuration'; import { RestService } from './rest.service'; @Injectable({ diff --git a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts index 2af99ee227..a26f1af06f 100644 --- a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts @@ -1,9 +1,7 @@ -import { Injectable, Optional, SkipSelf, NgZone } from '@angular/core'; +import { Injectable, NgZone, Optional, SkipSelf } from '@angular/core'; import { ActivatedRouteSnapshot, Router } from '@angular/router'; -import { Actions, Store } from '@ngxs/store'; +import { Store } from '@ngxs/store'; import { noop, Observable } from 'rxjs'; -import { ConfigState } from '../states/config.state'; -import { SessionState } from '../states/session.state'; import { registerLocale } from '../utils/initial-utils'; type ShouldReuseRoute = (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) => boolean; @@ -11,14 +9,13 @@ type ShouldReuseRoute = (future: ActivatedRouteSnapshot, curr: ActivatedRouteSna @Injectable({ providedIn: 'root' }) export class LocalizationService { get currentLang(): string { - return this.store.selectSnapshot(SessionState.getLanguage); + return this.store.selectSnapshot(state => state.SessionState.getLanguage); } constructor( private store: Store, private router: Router, private ngZone: NgZone, - private actions: Actions, @Optional() @SkipSelf() otherInstance: LocalizationService, @@ -45,10 +42,10 @@ export class LocalizationService { } get(keys: string, ...interpolateParams: string[]): Observable { - return this.store.select(ConfigState.getCopy(keys, ...interpolateParams)); + return this.store.select(state => state.ConfigState.getCopy(keys, ...interpolateParams)); } instant(keys: string, ...interpolateParams: string[]): string { - return this.store.selectSnapshot(ConfigState.getCopy(keys, ...interpolateParams)); + return this.store.selectSnapshot(state => state.ConfigState.getCopy(keys, ...interpolateParams)); } } diff --git a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts index 7ff1a42af0..5f402f896b 100644 --- a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts @@ -1,11 +1,10 @@ import { HttpClient, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Store } from '@ngxs/store'; -import { NEVER, Observable, throwError } from 'rxjs'; +import { Observable, throwError } from 'rxjs'; import { catchError, take } from 'rxjs/operators'; +import { RestOccurError } from '../actions/rest.actions'; import { Rest } from '../models/rest'; -import { ConfigState } from '../states'; -import { RestOccurError } from '../actions'; @Injectable({ providedIn: 'root', @@ -21,7 +20,7 @@ export class RestService { request(request: HttpRequest | Rest.Request, config: Rest.Config = {}, api?: string): Observable { const { observe = Rest.Observe.Body, skipHandleError } = config; - const url = api || this.store.selectSnapshot(ConfigState.getApiUrl()) + request.url; + const url = api || this.store.selectSnapshot(state => state.ConfigState).environment.apis.default.url + request.url; const { method, ...options } = request; return this.http.request(method, url, { observe, ...options } as any).pipe( observe === Rest.Observe.Body ? take(1) : null, diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts index 4f43a0bf65..29799a502b 100644 --- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts @@ -1,17 +1,18 @@ import { State, Selector, createSelector, Action, StateContext, Store } from '@ngxs/store'; -import { Config, ABP } from '../models'; +import { Config } from '../models/config'; +import { ABP } from '../models/common'; import { GetAppConfiguration, PatchRouteByName } from '../actions/config.actions'; import { ApplicationConfigurationService } from '../services/application-configuration.service'; import { tap, switchMap } from 'rxjs/operators'; import snq from 'snq'; -import { SetLanguage } from '../actions'; +import { SetLanguage } from '../actions/session.actions'; import { SessionState } from './session.state'; import { of } from 'rxjs'; import { setChildRoute, sortRoutes, organizeRoutes } from '../utils/route-utils'; @State({ name: 'ConfigState', - defaults: {} as Config.State + defaults: {} as Config.State, }) export class ConfigState { @Selector() @@ -29,7 +30,7 @@ export class ConfigState { [ConfigState], (state: Config.State) => { return state[key]; - } + }, ); return selector; @@ -54,7 +55,7 @@ export class ConfigState { return undefined; }, state); - } + }, ); return selector; @@ -72,7 +73,7 @@ export class ConfigState { return route; } }); - } + }, ); return selector; @@ -83,7 +84,7 @@ export class ConfigState { [ConfigState], (state: Config.State): string => { return state.environment.apis[key || 'default'].url; - } + }, ); return selector; @@ -94,7 +95,7 @@ export class ConfigState { [ConfigState], (state: Config.State) => { return snq(() => state.setting.values[key]); - } + }, ); return selector; @@ -106,7 +107,7 @@ export class ConfigState { (state: Config.State): boolean => { if (!key) return true; return snq(() => state.auth.grantedPolicies[key], false); - } + }, ); return selector; @@ -131,7 +132,7 @@ export class ConfigState { localization: { defaultResourceName: 'MyProjectName' } - }` + }`, ); } @@ -154,7 +155,7 @@ export class ConfigState { } return copy || key; - } + }, ); return selector; @@ -167,8 +168,8 @@ export class ConfigState { return this.appConfigurationService.getConfiguration().pipe( tap(configuration => patchState({ - ...configuration - }) + ...configuration, + }), ), switchMap(configuration => { let defaultLang: string = configuration.setting.values['Abp.Localization.DefaultLanguage']; @@ -178,7 +179,7 @@ export class ConfigState { } return this.store.selectSnapshot(SessionState.getLanguage) ? of(null) : dispatch(new SetLanguage(defaultLang)); - }) + }), ); } @@ -191,7 +192,7 @@ export class ConfigState { routes = patchRouteDeep(routes, name, newValue); return patchState({ - routes + routes, }); } } @@ -200,7 +201,7 @@ function patchRouteDeep( routes: ABP.FullRoute[], name: string, newValue: Partial, - parentUrl: string = null + parentUrl: string = null, ): ABP.FullRoute[] { routes = routes.map(route => { if (route.name === name) { @@ -211,7 +212,7 @@ function patchRouteDeep( if (newValue.children && newValue.children.length) { newValue.children = newValue.children.map(child => ({ ...child, - url: `${parentUrl}/${route.path}/${child.path}` + url: `${parentUrl}/${route.path}/${child.path}`, })); } diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index dc4ae36065..d1e703165e 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -3,7 +3,6 @@ import { Injector } from '@angular/core'; import { Store } from '@ngxs/store'; import { GetAppConfiguration } from '../actions/config.actions'; import differentLocales from '../constants/different-locales'; -import { SessionState } from '../states/session.state'; export function getInitialData(injector: Injector) { const fn = () => { @@ -19,7 +18,7 @@ export function localeInitializer(injector: Injector) { const fn = () => { const store: Store = injector.get(Store); - const lang = store.selectSnapshot(SessionState.getLanguage) || 'en'; + const lang = store.selectSnapshot(state => state.SessionState.getLanguage) || 'en'; return new Promise((resolve, reject) => { registerLocale(lang).then(() => resolve(), reject); diff --git a/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.html b/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.html index 030a020418..58659ff50b 100644 --- a/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.html +++ b/npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.html @@ -13,9 +13,6 @@
-
- -