Merge pull request #7005 from abpframework/auto-merge/rel-4-1/35

Merge branch dev with rel-4.1
pull/7007/head
liangshiwei 4 years ago committed by GitHub
commit 5729afaf1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,23 +6,52 @@ Reactive forms in ABP Angular UI are validated by [ngx-validate](https://www.npm
## How to Add New Error Messages
You can add a new error message by providing the `VALIDATION_BLUEPRINTS` injection token from your root module.
You can add a new error message by passing validation options to the `ThemeSharedModule` in your root module.
```js
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core";
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
@NgModule({
imports: [
ThemeSharedModule.forRoot({
validation: {
blueprints: {
uniqueUsername: "::AlreadyExists[{%{{{ username }}}%}]",
},
},
// rest of theme shared config
}),
// other imports
],
// rest of the module metadata
})
export class AppModule {}
```
Alternatively, you may provide the `VALIDATION_BLUEPRINTS` token directly in your root module. Please do not forget to spread `DEFAULT_VALIDATION_BLUEPRINTS`. Otherwise, built-in ABP validation messages will not work.
```js
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core";
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
@NgModule({
providers: [
// other providers
{
provide: VALIDATION_BLUEPRINTS,
useValue: {
...DEFAULT_VALIDATION_BLUEPRINTS,
uniqueUsername: "::AlreadyExists[{%{{{ username }}}%}]",
},
},
// other providers
],
// rest of the module metadata
})
export class AppModule {}
```
@ -40,7 +69,7 @@ In this example;
## How to Change Existing Error Messages
You can overwrite an existing error message by providing `VALIDATION_BLUEPRINTS` injection token from your root module. Let's imagine you have a custom localization resource for required inputs.
You can overwrite an existing error message by passing validation options to the `ThemeSharedModule` in your root module. Let's imagine you have a custom localization resource for required inputs.
```json
"RequiredInput": "Oops! We need this input."
@ -50,19 +79,48 @@ To use this instead of the built-in required input message, all you need to do i
```js
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core";
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
@NgModule({
imports: [
ThemeSharedModule.forRoot({
validation: {
blueprints: {
required: "::RequiredInput",
},
},
// rest of theme shared config
}),
// other imports
],
// rest of the module metadata
})
export class AppModule {}
```
Alternatively, you may provide the `VALIDATION_BLUEPRINTS` token directly in your root module. Please do not forget to spread `DEFAULT_VALIDATION_BLUEPRINTS`. Otherwise, built-in ABP validation messages will not work.
```js
import { VALIDATION_BLUEPRINTS } from "@ngx-validate/core";
import { DEFAULT_VALIDATION_BLUEPRINTS } from "@abp/ng.theme.shared";
@NgModule({
providers: [
// other providers
{
provide: VALIDATION_BLUEPRINTS,
useValue: {
...DEFAULT_VALIDATION_BLUEPRINTS,
required: "::RequiredInput",
},
},
// other providers
],
// rest of the module metadata
})
export class AppModule {}
```

@ -205,9 +205,15 @@ namespace Volo.Abp.Cli.ProjectModification
string postFix)
{
var srcPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), targetFolder);
if (!Directory.Exists(srcPath))
{
return;
}
var projectFolderPath = Directory.GetDirectories(srcPath).FirstOrDefault(d=> d.EndsWith(postFix));
if(projectFolderPath == null)
if (projectFolderPath == null)
{
return;
}
@ -218,7 +224,6 @@ namespace Volo.Abp.Cli.ProjectModification
{
Directory.Delete(projectFolderPath, true);
}
}
private async Task ChangeDomainTestReferenceToMongoDB(ModuleWithMastersInfo module, string moduleSolutionFile)

@ -85,6 +85,7 @@ namespace Volo.Abp.Identity
(await UserManager.CreateAsync(user, input.Password)).CheckErrors();
await UpdateUserByInput(user, input);
(await UserManager.UpdateAsync(user)).CheckErrors();
await CurrentUnitOfWork.SaveChangesAsync();
@ -174,6 +175,7 @@ namespace Volo.Abp.Identity
user.Name = input.Name;
user.Surname = input.Surname;
(await UserManager.UpdateAsync(user)).CheckErrors();
if (input.RoleNames != null)
{

@ -2,18 +2,22 @@ import { CoreModule } from '@abp/ng.core';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { ModuleWithProviders, NgModule } from '@angular/core';
import { NgbCollapseModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import {
NgxValidateCoreModule,
VALIDATION_ERROR_TEMPLATE,
VALIDATION_TARGET_SELECTOR,
} from '@ngx-validate/core';
import { AccountLayoutComponent } from './components/account-layout/account-layout.component';
import { ApplicationLayoutComponent } from './components/application-layout/application-layout.component';
import { EmptyLayoutComponent } from './components/empty-layout/empty-layout.component';
import { LogoComponent } from './components/logo/logo.component';
import { CurrentUserComponent } from './components/nav-items/current-user.component';
import { LanguagesComponent } from './components/nav-items/languages.component';
import { NavItemsComponent } from './components/nav-items/nav-items.component';
import { RoutesComponent } from './components/routes/routes.component';
import { ValidationErrorComponent } from './components/validation-error/validation-error.component';
import { CurrentUserComponent } from './components/nav-items/current-user.component';
import { LanguagesComponent } from './components/nav-items/languages.component';
import { BASIC_THEME_STYLES_PROVIDERS } from './providers/styles.provider';
import { BASIC_THEME_NAV_ITEM_PROVIDERS } from './providers/nav-item.provider';
import { BASIC_THEME_STYLES_PROVIDERS } from './providers/styles.provider';
export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent];
@ -45,37 +49,28 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
],
entryComponents: [...LAYOUTS, ValidationErrorComponent, CurrentUserComponent, LanguagesComponent],
})
export class BaseThemeBasicModule {}
@NgModule({
exports: [BaseThemeBasicModule],
imports: [BaseThemeBasicModule],
})
export class ThemeBasicModule {
static forRoot(): ModuleWithProviders<ThemeBasicModule> {
return {
ngModule: RootThemeBasicModule,
providers: [BASIC_THEME_NAV_ITEM_PROVIDERS, BASIC_THEME_STYLES_PROVIDERS],
ngModule: ThemeBasicModule,
providers: [
BASIC_THEME_NAV_ITEM_PROVIDERS,
BASIC_THEME_STYLES_PROVIDERS,
{
provide: VALIDATION_ERROR_TEMPLATE,
useValue: ValidationErrorComponent,
},
{
provide: VALIDATION_TARGET_SELECTOR,
useValue: '.form-group',
},
],
};
}
}
@NgModule({
imports: [
NgxValidateCoreModule.forRoot({
targetSelector: '.form-group',
blueprints: {
creditCard: 'AbpValidation::ThisFieldIsNotAValidCreditCardNumber.',
email: 'AbpValidation::ThisFieldIsNotAValidEmailAddress.',
invalid: 'AbpValidation::ThisFieldIsNotValid.',
max: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
maxlength:
'AbpValidation::ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}[{{ requiredLength }}]',
min: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
minlength:
'AbpValidation::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}[{{ requiredLength }}]',
ngbDate: 'AbpValidation::ThisFieldIsNotValid.',
passwordMismatch: 'AbpIdentity::Volo.Abp.Identity:PasswordConfirmationFailed',
range: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
required: 'AbpValidation::ThisFieldIsRequired.',
url: 'AbpValidation::ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl',
},
errorTemplate: ValidationErrorComponent,
}),
],
})
export class RootThemeBasicModule {}

@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/theme-basic/testing",
"lib": {
"entryFile": "src/public-api.ts"
}
}

@ -0,0 +1,32 @@
import {
BaseThemeBasicModule,
BASIC_THEME_NAV_ITEM_PROVIDERS,
BASIC_THEME_STYLES_PROVIDERS,
ValidationErrorComponent,
} from '@abp/ng.theme.basic';
import { ModuleWithProviders, NgModule } from '@angular/core';
import { VALIDATION_ERROR_TEMPLATE, VALIDATION_TARGET_SELECTOR } from '@ngx-validate/core';
@NgModule({
exports: [BaseThemeBasicModule],
imports: [BaseThemeBasicModule],
})
export class ThemeBasicTestingModule {
static forRoot(): ModuleWithProviders<ThemeBasicTestingModule> {
return {
ngModule: ThemeBasicTestingModule,
providers: [
BASIC_THEME_NAV_ITEM_PROVIDERS,
BASIC_THEME_STYLES_PROVIDERS,
{
provide: VALIDATION_ERROR_TEMPLATE,
useValue: ValidationErrorComponent,
},
{
provide: VALIDATION_TARGET_SELECTOR,
useValue: '.form-group',
},
],
};
}
}

@ -0,0 +1 @@
export * from './lib/theme-basic-testing.module';

@ -0,0 +1,16 @@
export const DEFAULT_VALIDATION_BLUEPRINTS = {
creditCard: 'AbpValidation::ThisFieldIsNotAValidCreditCardNumber.',
email: 'AbpValidation::ThisFieldIsNotAValidEmailAddress.',
invalid: 'AbpValidation::ThisFieldIsNotValid.',
max: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
maxlength:
'AbpValidation::ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}[{{ requiredLength }}]',
min: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
minlength:
'AbpValidation::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}[{{ requiredLength }}]',
ngbDate: 'AbpValidation::ThisFieldIsNotValid.',
passwordMismatch: 'AbpIdentity::Volo.Abp.Identity:PasswordConfirmationFailed',
range: 'AbpValidation::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
required: 'AbpValidation::ThisFieldIsRequired.',
url: 'AbpValidation::ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl',
};

@ -1,7 +1,9 @@
import { Type } from '@angular/core';
import { Validation } from '@ngx-validate/core';
export interface RootParams {
httpErrorConfig: HttpErrorConfig;
validation?: Partial<Validation.Config>;
}
export type ErrorScreenErrorCodes = 401 | 403 | 404 | 500;

@ -2,7 +2,13 @@ import { CoreModule, noop } from '@abp/ng.core';
import { DatePipe } from '@angular/common';
import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { NgbDateParserFormatter, NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import {
defaultMapErrorsFn,
NgxValidateCoreModule,
VALIDATION_BLUEPRINTS,
VALIDATION_MAP_ERRORS_FN,
VALIDATION_VALIDATE_ON_SUBMIT,
} from '@ngx-validate/core';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
import { ButtonComponent } from './components/button/button.component';
@ -18,6 +24,7 @@ import { TableEmptyMessageComponent } from './components/table-empty-message/tab
import { TableComponent } from './components/table/table.component';
import { ToastContainerComponent } from './components/toast-container/toast-container.component';
import { ToastComponent } from './components/toast/toast.component';
import { DEFAULT_VALIDATION_BLUEPRINTS } from './constants/validation';
import { LoadingDirective } from './directives/loading.directive';
import { NgxDatatableDefaultDirective } from './directives/ngx-datatable-default.directive';
import { NgxDatatableListDirective } from './directives/ngx-datatable-list.directive';
@ -69,7 +76,9 @@ export class BaseThemeSharedModule {}
exports: [BaseThemeSharedModule],
})
export class ThemeSharedModule {
static forRoot(options = {} as RootParams): ModuleWithProviders<ThemeSharedModule> {
static forRoot(
{ httpErrorConfig, validation = {} } = {} as RootParams,
): ModuleWithProviders<ThemeSharedModule> {
return {
ngModule: ThemeSharedModule,
providers: [
@ -92,13 +101,28 @@ export class ThemeSharedModule {
deps: [Injector],
useFactory: initLazyStyleHandler,
},
{ provide: HTTP_ERROR_CONFIG, useValue: options.httpErrorConfig },
{ provide: HTTP_ERROR_CONFIG, useValue: httpErrorConfig },
{
provide: 'HTTP_ERROR_CONFIG',
useFactory: httpErrorConfigFactory,
deps: [HTTP_ERROR_CONFIG],
},
{ provide: NgbDateParserFormatter, useClass: DateParserFormatter },
{
provide: VALIDATION_BLUEPRINTS,
useValue: {
...DEFAULT_VALIDATION_BLUEPRINTS,
...(validation.blueprints || {}),
},
},
{
provide: VALIDATION_MAP_ERRORS_FN,
useValue: validation.mapErrorsFn || defaultMapErrorsFn,
},
{
provide: VALIDATION_VALIDATE_ON_SUBMIT,
useValue: validation.validateOnSubmit,
},
],
};
}

@ -5,6 +5,7 @@
export * from './lib/animations';
export * from './lib/components';
export { BOOTSTRAP } from './lib/constants/styles';
export * from './lib/constants/validation';
export * from './lib/directives';
export * from './lib/enums';
export { ErrorHandler } from './lib/handlers';

@ -0,0 +1,5 @@
import { Validation } from '@ngx-validate/core';
export interface Config {
validation?: Partial<Validation.Config>;
}

@ -1,11 +1,19 @@
import {
BaseThemeSharedModule,
DateParserFormatter,
DEFAULT_VALIDATION_BLUEPRINTS,
THEME_SHARED_ROUTE_PROVIDERS,
} from '@abp/ng.theme.shared';
import { ModuleWithProviders, NgModule } from '@angular/core';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap';
import {
defaultMapErrorsFn,
VALIDATION_BLUEPRINTS,
VALIDATION_MAP_ERRORS_FN,
VALIDATION_VALIDATE_ON_SUBMIT,
} from '@ngx-validate/core';
import { Config } from './models/config';
/**
* ThemeSharedTestingModule is the module that will be used in tests
@ -15,12 +23,29 @@ import { NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap';
imports: [RouterTestingModule, BaseThemeSharedModule],
})
export class ThemeSharedTestingModule {
static withConfig(): ModuleWithProviders<ThemeSharedTestingModule> {
static withConfig(
{ validation = {} } = {} as Config,
): ModuleWithProviders<ThemeSharedTestingModule> {
return {
ngModule: ThemeSharedTestingModule,
providers: [
THEME_SHARED_ROUTE_PROVIDERS,
{ provide: NgbDateParserFormatter, useClass: DateParserFormatter },
{
provide: VALIDATION_BLUEPRINTS,
useValue: {
...DEFAULT_VALIDATION_BLUEPRINTS,
...(validation.blueprints || {}),
},
},
{
provide: VALIDATION_MAP_ERRORS_FN,
useValue: validation.mapErrorsFn || defaultMapErrorsFn,
},
{
provide: VALIDATION_VALIDATE_ON_SUBMIT,
useValue: validation.validateOnSubmit,
},
],
};
}

@ -1 +1,3 @@
import * as ThemeSharedTesting from './lib/models';
export * from './lib/theme-shared-testing.module';
export { ThemeSharedTesting };

Loading…
Cancel
Save