Browse Source

Merge branch 'dev' of https://github.com/volosoft/abp into dev

pull/1774/head
Yunus Emre Kalkan 7 years ago
parent
commit
57c5627f4c
  1. 51
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs
  2. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs
  3. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/IApiKeyService.cs
  4. 7
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ProjectBuildPipelineBuilder.cs
  5. 23
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/LicenseCodeReplaceStep.cs
  6. 1
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs
  7. 13
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuilder.cs
  8. 3
      npm/ng-packs/packages/core/src/lib/core.module.ts
  9. 1
      npm/ng-packs/packages/core/src/lib/pipes/index.ts
  10. 13
      npm/ng-packs/packages/core/src/lib/pipes/sort.pipe.ts
  11. 50
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html
  12. 6
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts
  13. 64
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.html
  14. 6
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  15. 70
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html
  16. 9
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts
  17. 1
      npm/ng-packs/packages/theme-basic/src/lib/components/index.ts
  18. 0
      npm/ng-packs/packages/theme-basic/src/lib/components/validation-error/validation-error.component.ts
  19. 9
      npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts
  20. 15
      npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts
  21. 23
      npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
  22. 4
      npm/ng-packs/packages/theme-shared/src/lib/components/change-password/change-password.component.html
  23. 1
      npm/ng-packs/packages/theme-shared/src/lib/components/index.ts
  24. 4
      npm/ng-packs/packages/theme-shared/src/lib/components/profile/profile.component.html
  25. 27
      npm/ng-packs/packages/theme-shared/src/lib/components/table-empty-message/table-empty-message.component.ts
  26. 26
      npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts

51
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs

@ -40,18 +40,29 @@ namespace Volo.Abp.Cli.Commands
Logger.LogInformation("Creating your project..."); Logger.LogInformation("Creating your project...");
Logger.LogInformation("Project name: " + commandLineArgs.Target); Logger.LogInformation("Project name: " + commandLineArgs.Target);
commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command); var template = commandLineArgs.Options.GetOrNull(Options.Template.Short, Options.Template.Long);
if (template != null)
{
Logger.LogInformation("Template: " + template);
}
var result = await ProjectBuilder.BuildAsync( var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long);
new ProjectBuildArgs( if (version != null)
SolutionName.Parse(commandLineArgs.Target), {
commandLineArgs.Options.GetOrNull(Options.Template.Short, Options.Template.Long), Logger.LogInformation("Version: " + version);
commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long), }
GetDatabaseProvider(commandLineArgs),
GetUiFramework(commandLineArgs), var databaseProvider = GetDatabaseProvider(commandLineArgs);
commandLineArgs.Options if (databaseProvider != DatabaseProvider.NotSpecified)
) {
); Logger.LogInformation("Database provider: " + databaseProvider);
}
var uiFramework = GetUiFramework(commandLineArgs);
if (uiFramework != UiFramework.NotSpecified)
{
Logger.LogInformation("UI Framework: " + uiFramework);
}
var outputFolder = commandLineArgs.Options.GetOrNull(Options.OutputFolder.Short, Options.OutputFolder.Long); var outputFolder = commandLineArgs.Options.GetOrNull(Options.OutputFolder.Short, Options.OutputFolder.Long);
if (outputFolder != null) if (outputFolder != null)
@ -68,6 +79,21 @@ namespace Volo.Abp.Cli.Commands
outputFolder = Directory.GetCurrentDirectory(); outputFolder = Directory.GetCurrentDirectory();
} }
Logger.LogInformation("Output folder: " + outputFolder);
commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command);
var result = await ProjectBuilder.BuildAsync(
new ProjectBuildArgs(
SolutionName.Parse(commandLineArgs.Target),
template,
version,
databaseProvider,
uiFramework,
commandLineArgs.Options
)
);
using (var templateFileStream = new MemoryStream(result.ZipContent)) using (var templateFileStream = new MemoryStream(result.ZipContent))
{ {
using (var zipInputStream = new ZipInputStream(templateFileStream)) using (var zipInputStream = new ZipInputStream(templateFileStream))
@ -101,8 +127,7 @@ namespace Volo.Abp.Cli.Commands
} }
} }
Logger.LogInformation($"Successfully created the project '{commandLineArgs.Target}'"); Logger.LogInformation($"'{commandLineArgs.Target}' has been successfully created to '{outputFolder}'");
Logger.LogInformation($"The output folder is: '{outputFolder}'");
} }
public string GetUsageInfo() public string GetUsageInfo()

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs

@ -15,7 +15,7 @@ namespace Volo.Abp.Cli.Licensing
protected IJsonSerializer JsonSerializer { get; } protected IJsonSerializer JsonSerializer { get; }
public async Task<string> GetApiKeyOrNullAsync() public async Task<DeveloperApiKeyResult> GetApiKeyOrNullAsync()
{ {
using (var client = new CliHttpClient()) using (var client = new CliHttpClient())
{ {
@ -29,7 +29,7 @@ namespace Volo.Abp.Cli.Licensing
} }
var responseContent = await response.Content.ReadAsStringAsync(); var responseContent = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<DeveloperApiKeyResult>(responseContent).ApiKey; return JsonSerializer.Deserialize<DeveloperApiKeyResult>(responseContent);
} }
} }
} }

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/IApiKeyService.cs

@ -5,6 +5,6 @@ namespace Volo.Abp.Cli.Licensing
{ {
public interface IApiKeyService public interface IApiKeyService
{ {
Task<string> GetApiKeyOrNullAsync(); Task<DeveloperApiKeyResult> GetApiKeyOrNullAsync();
} }
} }

7
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ProjectBuildPipelineBuilder.cs

@ -1,4 +1,5 @@
using Volo.Abp.Cli.ProjectBuilding.Building.Steps; using Volo.Abp.Cli.ProjectBuilding.Building.Steps;
using Volo.Abp.Cli.ProjectBuilding.Templates.App;
namespace Volo.Abp.Cli.ProjectBuilding.Building namespace Volo.Abp.Cli.ProjectBuilding.Building
{ {
@ -19,6 +20,12 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building
pipeline.Steps.Add(new TemplateCodeDeleteStep()); pipeline.Steps.Add(new TemplateCodeDeleteStep());
pipeline.Steps.Add(new SolutionRenameStep()); pipeline.Steps.Add(new SolutionRenameStep());
if (context.Template.Name == AppProTemplate.TemplateName)
{
pipeline.Steps.Add(new LicenseCodeReplaceStep());
}
pipeline.Steps.Add(new CreateProjectResultZipStep()); pipeline.Steps.Add(new CreateProjectResultZipStep());
return pipeline; return pipeline;

23
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/LicenseCodeReplaceStep.cs

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Files;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class LicenseCodeReplaceStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
var licenseCode = context.BuildArgs.ExtraProperties.GetOrDefault("license-code");
var appSettingsJsonFiles = context.Files.Where(f =>
f.Name.EndsWith("appsettings.json", StringComparison.OrdinalIgnoreCase));
foreach (var appSettingsJson in appSettingsJsonFiles)
{
appSettingsJson.ReplaceText(@"<LICENSE_CODE/>", licenseCode);
}
}
}
}

1
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Files; using Volo.Abp.Cli.ProjectBuilding.Files;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps

13
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuilder.cs

@ -53,10 +53,15 @@ namespace Volo.Abp.Cli.ProjectBuilding
args.Version args.Version
); );
var apiKey = await ApiKeyService.GetApiKeyOrNullAsync(); var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync();
if (apiKey != null) if (apiKeyResult?.ApiKey != null)
{ {
args.ExtraProperties["api-key"] = apiKey; args.ExtraProperties["api-key"] = apiKeyResult.ApiKey;
}
if (apiKeyResult?.LicenseCode != null)
{
args.ExtraProperties["license-code"] = apiKeyResult.LicenseCode;
} }
var context = new ProjectBuildContext( var context = new ProjectBuildContext(
@ -69,7 +74,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
if (!templateInfo.DocumentUrl.IsNullOrEmpty()) if (!templateInfo.DocumentUrl.IsNullOrEmpty())
{ {
Logger.LogInformation("Check out the documents: " + templateInfo.DocumentUrl); Logger.LogInformation("Check out the documents at " + templateInfo.DocumentUrl);
} }
// Exclude unwanted or known options. // Exclude unwanted or known options.

3
npm/ng-packs/packages/core/src/lib/core.module.ts

@ -18,6 +18,7 @@ import { VisibilityDirective } from './directives/visibility.directive';
import { ApiInterceptor } from './interceptors/api.interceptor'; import { ApiInterceptor } from './interceptors/api.interceptor';
import { ABP } from './models/common'; import { ABP } from './models/common';
import { LocalizationPipe } from './pipes/localization.pipe'; import { LocalizationPipe } from './pipes/localization.pipe';
import { SortPipe } from './pipes/sort.pipe';
import { LocaleProvider } from './providers/locale.provider'; import { LocaleProvider } from './providers/locale.provider';
import { ConfigState } from './states/config.state'; import { ConfigState } from './states/config.state';
import { ProfileState } from './states/profile.state'; import { ProfileState } from './states/profile.state';
@ -46,6 +47,7 @@ import { AbstractNgModelComponent } from './abstracts/ng-model.component';
ForDirective, ForDirective,
FormSubmitDirective, FormSubmitDirective,
LocalizationPipe, LocalizationPipe,
SortPipe,
PermissionDirective, PermissionDirective,
VisibilityDirective, VisibilityDirective,
InputEventDebounceDirective, InputEventDebounceDirective,
@ -65,6 +67,7 @@ import { AbstractNgModelComponent } from './abstracts/ng-model.component';
ForDirective, ForDirective,
FormSubmitDirective, FormSubmitDirective,
LocalizationPipe, LocalizationPipe,
SortPipe,
PermissionDirective, PermissionDirective,
VisibilityDirective, VisibilityDirective,
InputEventDebounceDirective, InputEventDebounceDirective,

1
npm/ng-packs/packages/core/src/lib/pipes/index.ts

@ -1 +1,2 @@
export * from './localization.pipe'; export * from './localization.pipe';
export * from "./sort.pipe";

13
npm/ng-packs/packages/core/src/lib/pipes/sort.pipe.ts

@ -0,0 +1,13 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'abpSort',
pure: false
})
export class SortPipe implements PipeTransform {
transform(value: any[], sortOrder: string): any {
sortOrder = sortOrder.toLowerCase();
if(sortOrder === "desc") return value.reverse();
else return value;
}
}

50
npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html

@ -1,16 +1,17 @@
<div id="identity-roles-wrapper" class="card"> <div class="row entry-row">
<div class="card-header"> <div class="col-auto">
<div class="row"> <h1 class="content-header-title">{{ 'AbpIdentity::Roles' | abpLocalization }}</h1>
<div class="col col-md-6"> </div>
<h5 class="card-title">{{ 'AbpIdentity::Roles' | abpLocalization }}</h5> <div class="col">
</div> <div class="text-lg-right pt-2" id="AbpContentToolbar">
<div class="text-right col col-md-6"> <button id="create-role" class="btn btn-primary" type="button" (click)="onAdd()">
<button id="create-role" class="btn btn-primary" type="button" (click)="onAdd()"> <i class="fa fa-plus mr-1"></i> <span>{{ 'AbpIdentity::NewRole' | abpLocalization }}</span>
<i class="fa fa-plus mr-1"></i> <span>{{ 'AbpIdentity::NewRole' | abpLocalization }}</span> </button>
</button>
</div>
</div> </div>
</div> </div>
</div>
<div id="identity-roles-wrapper" class="card">
<div class="card-body"> <div class="card-body">
<div id="data-tables-table-filter" class="data-tables-filter"> <div id="data-tables-table-filter" class="data-tables-filter">
<label <label
@ -22,6 +23,7 @@
/></label> /></label>
</div> </div>
<p-table <p-table
*ngIf="[65, 200] as columnWidths"
[value]="data$ | async" [value]="data$ | async"
[lazy]="true" [lazy]="true"
[lazyLoadOnInit]="false" [lazyLoadOnInit]="false"
@ -29,18 +31,38 @@
[rows]="10" [rows]="10"
[totalRecords]="totalCount$ | async" [totalRecords]="totalCount$ | async"
[loading]="loading" [loading]="loading"
[resizableColumns]="true"
[scrollable]="true"
(onLazyLoad)="onPageChange($event)" (onLazyLoad)="onPageChange($event)"
> >
<ng-template pTemplate="header"> <ng-template pTemplate="colgroup">
<colgroup>
<col *ngFor="let width of columnWidths" [ngStyle]="{ 'width.px': width }" />
</colgroup>
</ng-template>
<ng-template pTemplate="emptymessage" let-columns>
<tr
abp-table-empty-message
[attr.colspan]="columnWidths.length"
localizationResource="AbpIdentityServer"
localizationProp="NoDataAvailableInDatatable"
></tr>
</ng-template>
<ng-template pTemplate="header" let-columns>
<tr> <tr>
<th>{{ 'AbpIdentity::Actions' | abpLocalization }}</th> <th>{{ 'AbpIdentity::Actions' | abpLocalization }}</th>
<th>{{ 'AbpIdentity::RoleName' | abpLocalization }}</th> <th pResizableColumn (click)="changeSortOrder()">
{{ 'AbpIdentity::RoleName' | abpLocalization }}
<span class="float-right"
><i [ngClass]="['fa', sortOrder === 'desc' ? 'fa-sort-desc' : 'fa-sort-asc']"></i
></span>
</th>
</tr> </tr>
</ng-template> </ng-template>
<ng-template pTemplate="body" let-data> <ng-template pTemplate="body" let-data>
<tr> <tr>
<td> <td>
<div ngbDropdown class="d-inline-block"> <div ngbDropdown container="body" class="d-inline-block">
<button <button
class="btn btn-primary btn-sm dropdown-toggle" class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown" data-toggle="dropdown"

6
npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts

@ -38,6 +38,8 @@ export class RolesComponent {
modalBusy: boolean = false; modalBusy: boolean = false;
sortOrder: string = 'asc';
@ViewChild('modalContent', { static: false }) @ViewChild('modalContent', { static: false })
modalContent: TemplateRef<any>; modalContent: TemplateRef<any>;
@ -121,4 +123,8 @@ export class RolesComponent {
.pipe(finalize(() => (this.loading = false))) .pipe(finalize(() => (this.loading = false)))
.subscribe(); .subscribe();
} }
changeSortOrder() {
this.sortOrder = this.sortOrder.toLowerCase() === 'asc' ? 'desc' : 'asc';
}
} }

64
npm/ng-packs/packages/identity/src/lib/components/users/users.component.html

@ -1,22 +1,23 @@
<div id="identity-roles-wrapper" class="card"> <div class="row entry-row">
<div class="card-header"> <div class="col-auto">
<div class="row"> <h1 class="content-header-title">{{ 'AbpIdentity::Users' | abpLocalization }}</h1>
<div class="col col-md-6"> </div>
<h5 class="card-title">{{ 'AbpIdentity::Users' | abpLocalization }}</h5> <div class="col">
</div> <div class="text-lg-right pt-2" id="AbpContentToolbar">
<div class="text-right col col-md-6"> <button
<button [abpPermission]="'AbpIdentity.Users.Create'"
[abpPermission]="'AbpIdentity.Users.Create'" id="create-role"
id="create-role" class="btn btn-primary"
class="btn btn-primary" type="button"
type="button" (click)="onAdd()"
(click)="onAdd()" >
> <i class="fa fa-plus mr-1"></i> <span>{{ 'AbpIdentity::NewUser' | abpLocalization }}</span>
<i class="fa fa-plus mr-1"></i> <span>{{ 'AbpIdentity::NewUser' | abpLocalization }}</span> </button>
</button>
</div>
</div> </div>
</div> </div>
</div>
<div id="identity-roles-wrapper" class="card">
<div class="card-body"> <div class="card-body">
<div id="data-tables-table-filter" class="data-tables-filter"> <div id="data-tables-table-filter" class="data-tables-filter">
<label <label
@ -28,6 +29,7 @@
/></label> /></label>
</div> </div>
<p-table <p-table
*ngIf="[80, 200, 200, 200] as columnWidths"
[value]="data$ | async" [value]="data$ | async"
[lazy]="true" [lazy]="true"
[lazyLoadOnInit]="false" [lazyLoadOnInit]="false"
@ -35,20 +37,40 @@
[rows]="10" [rows]="10"
[totalRecords]="totalCount$ | async" [totalRecords]="totalCount$ | async"
[loading]="loading" [loading]="loading"
[resizableColumns]="true"
[scrollable]="true"
(onLazyLoad)="onPageChange($event)" (onLazyLoad)="onPageChange($event)"
> >
<ng-template pTemplate="colgroup">
<colgroup>
<col *ngFor="let width of columnWidths" [ngStyle]="{ 'width.px': width }" />
</colgroup>
</ng-template>
<ng-template pTemplate="emptymessage" let-columns>
<tr
abp-table-empty-message
[attr.colspan]="columnWidths.length"
localizationResource="AbpIdentityServer"
localizationProp="NoDataAvailableInDatatable"
></tr>
</ng-template>
<ng-template pTemplate="header"> <ng-template pTemplate="header">
<tr> <tr>
<th>{{ 'AbpIdentity::Actions' | abpLocalization }}</th> <th>{{ 'AbpIdentity::Actions' | abpLocalization }}</th>
<th>{{ 'AbpIdentity::UserName' | abpLocalization }}</th> <th pResizableColumn (click)="changeSortOrder()">
<th>{{ 'AbpIdentity::EmailAddress' | abpLocalization }}</th> {{ 'AbpIdentity::UserName' | abpLocalization }}
<th>{{ 'AbpIdentity::PhoneNumber' | abpLocalization }}</th> <span class="float-right"
><i [ngClass]="['fa', sortOrder === 'desc' ? 'fa-sort-desc' : 'fa-sort-asc']"></i
></span>
</th>
<th pResizableColumn>{{ 'AbpIdentity::EmailAddress' | abpLocalization }}</th>
<th pResizableColumn>{{ 'AbpIdentity::PhoneNumber' | abpLocalization }}</th>
</tr> </tr>
</ng-template> </ng-template>
<ng-template pTemplate="body" let-data> <ng-template pTemplate="body" let-data>
<tr> <tr>
<td> <td>
<div ngbDropdown class="d-inline-block"> <div ngbDropdown container="body" class="d-inline-block">
<button <button
class="btn btn-primary btn-sm dropdown-toggle" class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown" data-toggle="dropdown"

6
npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts

@ -52,6 +52,8 @@ export class UsersComponent {
modalBusy: boolean = false; modalBusy: boolean = false;
sortOrder: string = 'asc';
trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index; trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index;
get roleGroups(): FormGroup[] { get roleGroups(): FormGroup[] {
@ -169,4 +171,8 @@ export class UsersComponent {
.pipe(finalize(() => (this.loading = false))) .pipe(finalize(() => (this.loading = false)))
.subscribe(); .subscribe();
} }
changeSortOrder() {
this.sortOrder = this.sortOrder.toLowerCase() === 'asc' ? 'desc' : 'asc';
}
} }

70
npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html

@ -1,25 +1,24 @@
<div id="wrapper" class="card"> <div class="row entry-row">
<div class="card-header"> <div class="col-auto">
<div class="row"> <h1 class="content-header-title">{{ 'AbpTenantManagement::Tenants' | abpLocalization }}</h1>
<div class="col col-md-6"> </div>
<h5 class="card-title"> <div class="col">
{{ 'AbpTenantManagement::Tenants' | abpLocalization }} <div class="text-lg-right pt-2" id="AbpContentToolbar">
</h5> <button
</div> [abpPermission]="'AbpTenantManagement.Tenants.Create'"
<div class="text-right col col-md-6"> id="create-tenants"
<button class="btn btn-primary"
[abpPermission]="'AbpTenantManagement.Tenants.Create'" type="button"
id="create-tenants" (click)="onAddTenant()"
class="btn btn-primary" >
type="button" <i class="fa fa-plus mr-1"></i>
(click)="onAddTenant()" <span>{{ 'AbpTenantManagement::NewTenant' | abpLocalization }}</span>
> </button>
<i class="fa fa-plus mr-1"></i>
<span>{{ 'AbpTenantManagement::NewTenant' | abpLocalization }}</span>
</button>
</div>
</div> </div>
</div> </div>
</div>
<div id="wrapper" class="card">
<div class="card-body"> <div class="card-body">
<div id="data-tables-table-filter" class="data-tables-filter"> <div id="data-tables-table-filter" class="data-tables-filter">
<label <label
@ -31,25 +30,46 @@
/></label> /></label>
</div> </div>
<p-table <p-table
[value]="data$ | async" *ngIf="[65, 200] as columnWidths"
[value]="data$ | async | abpSort: sortOrder"
[lazy]="true" [lazy]="true"
[lazyLoadOnInit]="false" [lazyLoadOnInit]="false"
[paginator]="true" [paginator]="true"
[rows]="10" [rows]="10"
[totalRecords]="totalCount$ | async" [totalRecords]="totalCount$ | async"
[loading]="loading" [loading]="loading"
[resizableColumns]="true"
[scrollable]="true"
(onLazyLoad)="onPageChange($event)" (onLazyLoad)="onPageChange($event)"
> >
<ng-template pTemplate="header"> <ng-template pTemplate="colgroup">
<colgroup>
<col *ngFor="let width of columnWidths" [ngStyle]="{ 'width.px': width }" />
</colgroup>
</ng-template>
<ng-template pTemplate="emptymessage" let-columns>
<tr
abp-table-empty-message
[attr.colspan]="columnWidths.length"
localizationResource="AbpTenantManagement"
localizationProp="NoDataAvailableInDatatable"
></tr>
</ng-template>
<ng-template pTemplate="header" let-columns>
<tr> <tr>
<th>{{ 'AbpTenantManagement::Actions' | abpLocalization }}</th> <th>{{ 'AbpTenantManagement::Actions' | abpLocalization }}</th>
<th>{{ 'AbpTenantManagement::TenantName' | abpLocalization }}</th> <th pResizableColumn (click)="changeSortOrder()">
{{ 'AbpTenantManagement::TenantName' | abpLocalization }}
<span class="float-right"
><i [ngClass]="['fa', sortOrder === 'desc' ? 'fa-sort-desc' : 'fa-sort-asc']"></i
></span>
</th>
</tr> </tr>
</ng-template> </ng-template>
<ng-template pTemplate="body" let-data> <ng-template pTemplate="body" let-data>
<tr> <tr>
<td> <td>
<div ngbDropdown class="d-inline-block"> <div ngbDropdown container="body" class="d-inline-block">
<button <button
class="btn btn-primary btn-sm dropdown-toggle" class="btn btn-primary btn-sm dropdown-toggle"
data-toggle="dropdown" data-toggle="dropdown"
@ -97,7 +117,7 @@
</div> </div>
</div> </div>
<abp-modal [(visible)]="isModalVisible" [busy]="modalBusy"> <abp-modal size="md" [(visible)]="isModalVisible" [busy]="modalBusy">
<ng-template #abpHeader> <ng-template #abpHeader>
<h3>{{ selectedModalContent.title | abpLocalization }}</h3> <h3>{{ selectedModalContent.title | abpLocalization }}</h3>
</ng-template> </ng-template>

9
npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts

@ -58,6 +58,8 @@ export class TenantsComponent {
modalBusy: boolean = false; modalBusy: boolean = false;
sortOrder: string = 'asc';
get useSharedDatabase(): boolean { get useSharedDatabase(): boolean {
return this.defaultConnectionStringForm.get('useSharedDatabase').value; return this.defaultConnectionStringForm.get('useSharedDatabase').value;
} }
@ -184,8 +186,8 @@ export class TenantsComponent {
? new UpdateTenant({ ...this.tenantForm.value, id: this.selected.id }) ? new UpdateTenant({ ...this.tenantForm.value, id: this.selected.id })
: new CreateTenant(this.tenantForm.value), : new CreateTenant(this.tenantForm.value),
) )
.pipe(finalize(()=> (this.modalBusy = false)))
.subscribe(() => { .subscribe(() => {
this.modalBusy = false;
this.isModalVisible = false; this.isModalVisible = false;
}); });
} }
@ -198,7 +200,6 @@ export class TenantsComponent {
.subscribe((status: Toaster.Status) => { .subscribe((status: Toaster.Status) => {
if (status === Toaster.Status.confirm) { if (status === Toaster.Status.confirm) {
this.store.dispatch(new DeleteTenant(id)); this.store.dispatch(new DeleteTenant(id));
this.modalBusy = false;
} }
}); });
} }
@ -217,4 +218,8 @@ export class TenantsComponent {
.pipe(finalize(() => (this.loading = false))) .pipe(finalize(() => (this.loading = false)))
.subscribe(); .subscribe();
} }
changeSortOrder() {
this.sortOrder = this.sortOrder.toLowerCase() === "asc" ? "desc" : "asc";
}
} }

1
npm/ng-packs/packages/theme-basic/src/lib/components/index.ts

@ -1,3 +1,4 @@
export * from './account-layout/account-layout.component'; export * from './account-layout/account-layout.component';
export * from './application-layout/application-layout.component'; export * from './application-layout/application-layout.component';
export * from './empty-layout/empty-layout.component'; export * from './empty-layout/empty-layout.component';
export * from './validation-error/validation-error.component';

0
npm/ng-packs/packages/theme-shared/src/lib/components/errors/validation-error.component.ts → npm/ng-packs/packages/theme-basic/src/lib/components/validation-error/validation-error.component.ts

9
npm/ng-packs/packages/theme-basic/src/lib/constants/styles.ts

@ -0,0 +1,9 @@
export default `
.content-header-title {
font-size: 24px;
}
.entry-row {
margin-bottom: 15px;
}
`;

15
npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts

@ -0,0 +1,15 @@
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { LazyLoadService } from '@abp/ng.core';
import styles from '../constants/styles';
@Injectable({ providedIn: 'root' })
export class InitialService {
constructor(private lazyLoadService: LazyLoadService) {
this.appendStyle().subscribe();
}
appendStyle() {
return this.lazyLoadService.load(null, 'style', styles, 'head', 'afterbegin');
}
}

23
npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts

@ -10,11 +10,13 @@ import { ApplicationLayoutComponent } from './components/application-layout/appl
import { EmptyLayoutComponent } from './components/empty-layout/empty-layout.component'; import { EmptyLayoutComponent } from './components/empty-layout/empty-layout.component';
import { LayoutComponent } from './components/layout/layout.component'; import { LayoutComponent } from './components/layout/layout.component';
import { LayoutState } from './states/layout.state'; import { LayoutState } from './states/layout.state';
import { ValidationErrorComponent } from './components/validation-error/validation-error.component';
import { InitialService } from './services/initial.service';
export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent]; export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent];
@NgModule({ @NgModule({
declarations: [...LAYOUTS, LayoutComponent], declarations: [...LAYOUTS, LayoutComponent, ValidationErrorComponent],
imports: [ imports: [
CoreModule, CoreModule,
ThemeSharedModule, ThemeSharedModule,
@ -23,8 +25,23 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
ToastModule, ToastModule,
NgxValidateCoreModule, NgxValidateCoreModule,
NgxsModule.forFeature([LayoutState]), NgxsModule.forFeature([LayoutState]),
NgxValidateCoreModule.forRoot({
targetSelector: '.form-group',
blueprints: {
email: `AbpAccount::ThisFieldIsNotAValidEmailAddress.`,
max: `AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]`,
maxlength: `AbpAccount::ThisFieldMustBeAStringWithAMaximumLengthOf{1}[{{ requiredLength }}]`,
min: `AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]`,
minlength: `AbpAccount::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf[{{ min }},{{ max }}]`,
required: `AbpAccount::ThisFieldIsRequired.`,
passwordMismatch: `AbpIdentity::Identity.PasswordConfirmationFailed`,
},
errorTemplate: ValidationErrorComponent,
}),
], ],
exports: [...LAYOUTS], exports: [...LAYOUTS],
entryComponents: [...LAYOUTS], entryComponents: [...LAYOUTS, ValidationErrorComponent],
}) })
export class ThemeBasicModule {} export class ThemeBasicModule {
constructor(private initialService: InitialService) {}
}

4
npm/ng-packs/packages/theme-shared/src/lib/components/change-password/change-password.component.html

@ -24,9 +24,9 @@
</form> </form>
</ng-template> </ng-template>
<ng-template #abpFooter> <ng-template #abpFooter>
<button type="button" class="btn btn-secondary" #abpClose> <button type="button" class="btn btn-secondary color-white" #abpClose>
{{ 'AbpIdentity::Cancel' | abpLocalization }} {{ 'AbpIdentity::Cancel' | abpLocalization }}
</button> </button>
<abp-button iconClass="fa fa-check" (click)="onSubmit()">{{ 'AbpIdentity::Save' | abpLocalization }}</abp-button> <abp-button iconClass="fa fa-check" buttonClass="btn btn-primary color-white" (click)="onSubmit()">{{ 'AbpIdentity::Save' | abpLocalization }}</abp-button>
</ng-template> </ng-template>
</abp-modal> </abp-modal>

1
npm/ng-packs/packages/theme-shared/src/lib/components/index.ts

@ -6,4 +6,5 @@ export * from './confirmation/confirmation.component';
export * from './loader-bar/loader-bar.component'; export * from './loader-bar/loader-bar.component';
export * from './modal/modal.component'; export * from './modal/modal.component';
export * from './profile/profile.component'; export * from './profile/profile.component';
export * from './table-empty-message/table-empty-message.component';
export * from './toast/toast.component'; export * from './toast/toast.component';

4
npm/ng-packs/packages/theme-shared/src/lib/components/profile/profile.component.html

@ -33,9 +33,9 @@
</form> </form>
</ng-template> </ng-template>
<ng-template #abpFooter> <ng-template #abpFooter>
<button #abpClose type="button" class="btn btn-secondary"> <button #abpClose type="button" class="btn btn-secondary color-white">
{{ 'AbpIdentity::Cancel' | abpLocalization }} {{ 'AbpIdentity::Cancel' | abpLocalization }}
</button> </button>
<abp-button iconClass="fa fa-check" (click)="submit()">{{ 'AbpIdentity::Save' | abpLocalization }}</abp-button> <abp-button iconClass="fa fa-check" buttonClass="btn btn-primary color-white" (click)="submit()">{{ 'AbpIdentity::Save' | abpLocalization }}</abp-button>
</ng-template> </ng-template>
</abp-modal> </abp-modal>

27
npm/ng-packs/packages/theme-shared/src/lib/components/table-empty-message/table-empty-message.component.ts

@ -0,0 +1,27 @@
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: '[abp-table-empty-message]',
template: `
<td class="text-center" [attr.colspan]="colspan">
{{ emptyMessage | abpLocalization }}
</td>
`,
})
export class TableEmptyMessageComponent {
@Input()
colspan = 2;
@Input()
message: string;
@Input()
localizationResource: string = 'AbpAccount';
@Input()
localizationProp: string = 'NoDataAvailableInDatatable';
get emptyMessage(): string {
return this.message || `${this.localizationResource}::${this.localizationProp}`;
}
}

26
npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts

@ -1,6 +1,5 @@
import { CoreModule, LazyLoadService } from '@abp/ng.core'; import { CoreModule, LazyLoadService } from '@abp/ng.core';
import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core'; import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import { MessageService } from 'primeng/components/common/messageservice'; import { MessageService } from 'primeng/components/common/messageservice';
import { ToastModule } from 'primeng/toast'; import { ToastModule } from 'primeng/toast';
import { forkJoin } from 'rxjs'; import { forkJoin } from 'rxjs';
@ -11,7 +10,6 @@ import { ChangePasswordComponent } from './components/change-password/change-pas
import { ChartComponent } from './components/chart/chart.component'; import { ChartComponent } from './components/chart/chart.component';
import { ConfirmationComponent } from './components/confirmation/confirmation.component'; import { ConfirmationComponent } from './components/confirmation/confirmation.component';
import { ErrorComponent } from './components/errors/error.component'; import { ErrorComponent } from './components/errors/error.component';
import { ValidationErrorComponent } from './components/errors/validation-error.component';
import { LoaderBarComponent } from './components/loader-bar/loader-bar.component'; import { LoaderBarComponent } from './components/loader-bar/loader-bar.component';
import { ModalComponent } from './components/modal/modal.component'; import { ModalComponent } from './components/modal/modal.component';
import { ProfileComponent } from './components/profile/profile.component'; import { ProfileComponent } from './components/profile/profile.component';
@ -19,6 +17,7 @@ import { ToastComponent } from './components/toast/toast.component';
import styles from './contants/styles'; import styles from './contants/styles';
import { ErrorHandler } from './handlers/error.handler'; import { ErrorHandler } from './handlers/error.handler';
import { chartJsLoaded$ } from './utils/widget-utils'; import { chartJsLoaded$ } from './utils/widget-utils';
import { TableEmptyMessageComponent } from './components/table-empty-message/table-empty-message.component';
export function appendScript(injector: Injector) { export function appendScript(injector: Injector) {
const fn = function() { const fn = function() {
@ -41,23 +40,7 @@ export function appendScript(injector: Injector) {
} }
@NgModule({ @NgModule({
imports: [ imports: [CoreModule, ToastModule],
CoreModule,
ToastModule,
NgxValidateCoreModule.forRoot({
targetSelector: '.form-group',
blueprints: {
email: `AbpAccount::ThisFieldIsNotAValidEmailAddress.`,
max: `AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]`,
maxlength: `AbpAccount::ThisFieldMustBeAStringWithAMaximumLengthOf{1}[{{ requiredLength }}]`,
min: `AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]`,
minlength: `AbpAccount::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf[{{ min }},{{ max }}]`,
required: `AbpAccount::ThisFieldIsRequired.`,
passwordMismatch: `AbpIdentity::Identity.PasswordConfirmationFailed`,
},
errorTemplate: ValidationErrorComponent,
}),
],
declarations: [ declarations: [
BreadcrumbComponent, BreadcrumbComponent,
ButtonComponent, ButtonComponent,
@ -68,8 +51,8 @@ export function appendScript(injector: Injector) {
LoaderBarComponent, LoaderBarComponent,
ModalComponent, ModalComponent,
ProfileComponent, ProfileComponent,
TableEmptyMessageComponent,
ToastComponent, ToastComponent,
ValidationErrorComponent,
], ],
exports: [ exports: [
BreadcrumbComponent, BreadcrumbComponent,
@ -80,9 +63,10 @@ export function appendScript(injector: Injector) {
LoaderBarComponent, LoaderBarComponent,
ModalComponent, ModalComponent,
ProfileComponent, ProfileComponent,
TableEmptyMessageComponent,
ToastComponent, ToastComponent,
], ],
entryComponents: [ErrorComponent, ValidationErrorComponent], entryComponents: [ErrorComponent],
}) })
export class ThemeSharedModule { export class ThemeSharedModule {
static forRoot(): ModuleWithProviders { static forRoot(): ModuleWithProviders {

Loading…
Cancel
Save