mirror of https://github.com/abpframework/abp.git
47 changed files with 945 additions and 790 deletions
@ -0,0 +1,24 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.test.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net6.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.IdentityModel\Volo.Abp.IdentityModel.csproj" /> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<None Remove="appsettings.json" /> |
||||
|
<Content Include="appsettings.json"> |
||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
||||
|
</Content> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,51 @@ |
|||||
|
using System; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.IdentityModel |
||||
|
{ |
||||
|
public class AbpIdentityClientOptions_Tests : AbpIdentityModelTestBase |
||||
|
{ |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
private readonly AbpIdentityClientOptions _identityClientOptions; |
||||
|
|
||||
|
public AbpIdentityClientOptions_Tests() |
||||
|
{ |
||||
|
_currentTenant = GetRequiredService<ICurrentTenant>(); |
||||
|
_identityClientOptions = GetRequiredService<IOptions<AbpIdentityClientOptions>>().Value; |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void GetClientConfiguration_Test() |
||||
|
{ |
||||
|
var hostDefaultConfiguration = _identityClientOptions.GetClientConfiguration(_currentTenant); |
||||
|
hostDefaultConfiguration.UserName.ShouldBe("host_default_admin"); |
||||
|
|
||||
|
var hostIdentityConfiguration = _identityClientOptions.GetClientConfiguration(_currentTenant, "Identity"); |
||||
|
hostIdentityConfiguration.UserName.ShouldBe("host_identity_admin"); |
||||
|
|
||||
|
using (_currentTenant.Change(Guid.Parse("f72a344f-651e-49f0-85f6-be260a10e4df"), "Test_Tenant1")) |
||||
|
{ |
||||
|
var tenantDefaultConfiguration = _identityClientOptions.GetClientConfiguration(_currentTenant); |
||||
|
tenantDefaultConfiguration.UserName.ShouldBe("tenant_default_admin"); |
||||
|
} |
||||
|
|
||||
|
using (_currentTenant.Change(Guid.Parse("f72a344f-651e-49f0-85f6-be260a10e4df"))) |
||||
|
{ |
||||
|
var tenantIdentityConfiguration = _identityClientOptions.GetClientConfiguration(_currentTenant, "Identity"); |
||||
|
tenantIdentityConfiguration.UserName.ShouldBe("tenant_identity_admin"); |
||||
|
} |
||||
|
|
||||
|
using (_currentTenant.Change(Guid.NewGuid())) |
||||
|
{ |
||||
|
var configuration = _identityClientOptions.GetClientConfiguration(_currentTenant); |
||||
|
configuration.UserName.ShouldBe("host_default_admin"); |
||||
|
|
||||
|
configuration = _identityClientOptions.GetClientConfiguration(_currentTenant, "Identity"); |
||||
|
configuration.UserName.ShouldBe("host_identity_admin"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.Testing; |
||||
|
|
||||
|
namespace Volo.Abp.IdentityModel |
||||
|
{ |
||||
|
public abstract class AbpIdentityModelTestBase : AbpIntegratedTest<AbpIdentityModelTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.IdentityModel |
||||
|
{ |
||||
|
[DependsOn(typeof(AbpIdentityModelModule))] |
||||
|
public class AbpIdentityModelTestModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
{ |
||||
|
"IdentityClients": { |
||||
|
"Default": { |
||||
|
"GrantType": "password", |
||||
|
"ClientId": "Test_App", |
||||
|
"ClientSecret": "1q2w3e*", |
||||
|
"UserName": "host_default_admin", |
||||
|
"UserPassword": "1q2w3E*", |
||||
|
"Authority": "https://localhost:44395", |
||||
|
"Scope": "Test_Scope" |
||||
|
}, |
||||
|
"Default.Test_Tenant1": { |
||||
|
"GrantType": "password", |
||||
|
"ClientId": "Test_App", |
||||
|
"ClientSecret": "1q2w3e*", |
||||
|
"UserName": "tenant_default_admin", |
||||
|
"UserPassword": "1q2w3E*", |
||||
|
"Authority": "https://localhost:44395", |
||||
|
"Scope": "Test_Scope" |
||||
|
}, |
||||
|
"Identity": { |
||||
|
"GrantType": "password", |
||||
|
"ClientId": "Test_App", |
||||
|
"ClientSecret": "1q2w3e*", |
||||
|
"UserName": "host_identity_admin", |
||||
|
"UserPassword": "1q2w3E*", |
||||
|
"Authority": "https://localhost:44395", |
||||
|
"Scope": "Test_Scope" |
||||
|
}, |
||||
|
"Identity.f72a344f-651e-49f0-85f6-be260a10e4df": { |
||||
|
"GrantType": "password", |
||||
|
"ClientId": "Test_App", |
||||
|
"ClientSecret": "1q2w3e*", |
||||
|
"UserName": "tenant_identity_admin", |
||||
|
"UserPassword": "1q2w3E*", |
||||
|
"Authority": "https://localhost:44395", |
||||
|
"Scope": "Test_Scope" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../../dist/packages/components/chart.js", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,149 @@ |
|||||
|
import { |
||||
|
AfterViewInit, |
||||
|
ChangeDetectionStrategy, |
||||
|
ChangeDetectorRef, |
||||
|
Component, |
||||
|
ElementRef, |
||||
|
EventEmitter, |
||||
|
Input, |
||||
|
OnChanges, |
||||
|
OnDestroy, |
||||
|
Output, |
||||
|
SimpleChanges, |
||||
|
ViewChild, |
||||
|
} from '@angular/core'; |
||||
|
|
||||
|
let Chart: any; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'abp-chart', |
||||
|
template: ` |
||||
|
<div |
||||
|
style="position:relative" |
||||
|
[style.width]="responsive && !width ? null : width" |
||||
|
[style.height]="responsive && !height ? null : height" |
||||
|
> |
||||
|
<canvas |
||||
|
#canvas |
||||
|
[attr.width]="responsive && !width ? null : width" |
||||
|
[attr.height]="responsive && !height ? null : height" |
||||
|
(click)="onCanvasClick($event)" |
||||
|
></canvas> |
||||
|
</div> |
||||
|
`,
|
||||
|
changeDetection: ChangeDetectionStrategy.OnPush, |
||||
|
exportAs: 'abpChart', |
||||
|
}) |
||||
|
export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { |
||||
|
@Input() type: string; |
||||
|
|
||||
|
@Input() data: any = {}; |
||||
|
|
||||
|
@Input() options: any = {}; |
||||
|
|
||||
|
@Input() plugins: any[] = []; |
||||
|
|
||||
|
@Input() width: string; |
||||
|
|
||||
|
@Input() height: string; |
||||
|
|
||||
|
@Input() responsive = true; |
||||
|
|
||||
|
@Output() dataSelect = new EventEmitter(); |
||||
|
|
||||
|
@Output() initialized = new EventEmitter<boolean>(); |
||||
|
|
||||
|
@ViewChild('canvas') canvas: ElementRef<HTMLCanvasElement>; |
||||
|
|
||||
|
chart: any; |
||||
|
|
||||
|
constructor(public el: ElementRef, private cdr: ChangeDetectorRef) {} |
||||
|
|
||||
|
ngAfterViewInit() { |
||||
|
import('chart.js/auto').then(module => { |
||||
|
Chart = module.default; |
||||
|
this.initChart(); |
||||
|
this.initialized.emit(true); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
onCanvasClick(event) { |
||||
|
if (this.chart) { |
||||
|
const element = this.chart.getElementsAtEventForMode( |
||||
|
event, |
||||
|
'nearest', |
||||
|
{ intersect: true }, |
||||
|
false, |
||||
|
); |
||||
|
const dataset = this.chart.getElementsAtEventForMode( |
||||
|
event, |
||||
|
'dataset', |
||||
|
{ intersect: true }, |
||||
|
false, |
||||
|
); |
||||
|
|
||||
|
if (element && element[0] && dataset) { |
||||
|
this.dataSelect.emit({ originalEvent: event, element: element[0], dataset: dataset }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
initChart = () => { |
||||
|
const opts = this.options || {}; |
||||
|
opts.responsive = this.responsive; |
||||
|
|
||||
|
// allows chart to resize in responsive mode
|
||||
|
if (opts.responsive && (this.height || this.width)) { |
||||
|
opts.maintainAspectRatio = false; |
||||
|
} |
||||
|
|
||||
|
this.chart = new Chart(this.canvas.nativeElement, { |
||||
|
type: this.type as any, |
||||
|
data: this.data, |
||||
|
options: this.options, |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
getCanvas = () => { |
||||
|
return this.canvas.nativeElement; |
||||
|
}; |
||||
|
|
||||
|
getBase64Image = () => { |
||||
|
return this.chart.toBase64Image(); |
||||
|
}; |
||||
|
|
||||
|
generateLegend = () => { |
||||
|
if (this.chart) { |
||||
|
return this.chart.generateLegend(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
refresh = () => { |
||||
|
if (this.chart) { |
||||
|
this.chart.update(); |
||||
|
this.cdr.detectChanges(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
reinit = () => { |
||||
|
if (!this.chart) return; |
||||
|
this.chart.destroy(); |
||||
|
this.initChart(); |
||||
|
}; |
||||
|
|
||||
|
ngOnDestroy() { |
||||
|
if (this.chart) { |
||||
|
this.chart.destroy(); |
||||
|
this.chart = null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ngOnChanges(changes: SimpleChanges) { |
||||
|
if (!this.chart) return; |
||||
|
|
||||
|
if (changes.data?.currentValue || changes.options?.currentValue) { |
||||
|
this.chart.destroy(); |
||||
|
this.initChart(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
import { CommonModule } from '@angular/common'; |
||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { ChartComponent } from './chart.component'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [CommonModule], |
||||
|
exports: [ChartComponent], |
||||
|
declarations: [ChartComponent], |
||||
|
providers: [], |
||||
|
}) |
||||
|
export class ChartModule {} |
||||
@ -0,0 +1,4 @@ |
|||||
|
export * from './chart.component'; |
||||
|
export * from './chart.module'; |
||||
|
export * from './widget-utils'; |
||||
|
|
||||
@ -1 +1,3 @@ |
|||||
|
import 'jest-canvas-mock'; |
||||
import 'jest-preset-angular/setup-jest'; |
import 'jest-preset-angular/setup-jest'; |
||||
|
|
||||
|
|||||
@ -1,11 +0,0 @@ |
|||||
<div |
|
||||
style="position:relative" |
|
||||
[style.width]="responsive && !width ? null : width" |
|
||||
[style.height]="responsive && !height ? null : height" |
|
||||
> |
|
||||
<canvas |
|
||||
[attr.width]="responsive && !width ? null : width" |
|
||||
[attr.height]="responsive && !height ? null : height" |
|
||||
(click)="onCanvasClick($event)" |
|
||||
></canvas> |
|
||||
</div> |
|
||||
@ -1,141 +0,0 @@ |
|||||
import { |
|
||||
AfterViewInit, |
|
||||
ChangeDetectorRef, |
|
||||
Component, |
|
||||
ElementRef, |
|
||||
EventEmitter, |
|
||||
Input, |
|
||||
OnDestroy, |
|
||||
Output, |
|
||||
} from '@angular/core'; |
|
||||
import { BehaviorSubject } from 'rxjs'; |
|
||||
import { chartJsLoaded$ } from '../../utils/widget-utils'; |
|
||||
declare const Chart: any; |
|
||||
|
|
||||
@Component({ |
|
||||
selector: 'abp-chart', |
|
||||
templateUrl: './chart.component.html', |
|
||||
}) |
|
||||
export class ChartComponent implements AfterViewInit, OnDestroy { |
|
||||
@Input() type: string; |
|
||||
|
|
||||
@Input() options: any = {}; |
|
||||
|
|
||||
@Input() plugins: any[] = []; |
|
||||
|
|
||||
@Input() width: string; |
|
||||
|
|
||||
@Input() height: string; |
|
||||
|
|
||||
@Input() responsive = true; |
|
||||
|
|
||||
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
|
|
||||
@Output() readonly onDataSelect: EventEmitter<any> = new EventEmitter(); |
|
||||
|
|
||||
@Output() readonly initialized = new BehaviorSubject(this); |
|
||||
|
|
||||
private _initialized: boolean; |
|
||||
|
|
||||
_data: any; |
|
||||
|
|
||||
chart: any; |
|
||||
|
|
||||
constructor(public el: ElementRef, private cdRef: ChangeDetectorRef) {} |
|
||||
|
|
||||
@Input() get data(): any { |
|
||||
return this._data; |
|
||||
} |
|
||||
|
|
||||
set data(val: any) { |
|
||||
this._data = val; |
|
||||
this.reinit(); |
|
||||
} |
|
||||
|
|
||||
get canvas() { |
|
||||
return this.el.nativeElement.children[0].children[0]; |
|
||||
} |
|
||||
|
|
||||
get base64Image() { |
|
||||
return this.chart.toBase64Image(); |
|
||||
} |
|
||||
|
|
||||
ngAfterViewInit() { |
|
||||
chartJsLoaded$.subscribe(() => { |
|
||||
this.testChartJs(); |
|
||||
|
|
||||
this.initChart(); |
|
||||
this._initialized = true; |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
testChartJs() { |
|
||||
try { |
|
||||
Chart; |
|
||||
} catch (error) { |
|
||||
throw new Error(`Chart is not found. Import the Chart from app.module like shown below:
|
|
||||
import('chart.js'); |
|
||||
`);
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
onCanvasClick = event => { |
|
||||
if (this.chart) { |
|
||||
const element = this.chart.getElementAtEvent(event); |
|
||||
const dataset = this.chart.getDatasetAtEvent(event); |
|
||||
if (element && element.length && dataset) { |
|
||||
this.onDataSelect.emit({ |
|
||||
originalEvent: event, |
|
||||
element: element[0], |
|
||||
dataset, |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
initChart = () => { |
|
||||
const opts = this.options || {}; |
|
||||
opts.responsive = this.responsive; |
|
||||
|
|
||||
// allows chart to resize in responsive mode
|
|
||||
if (opts.responsive && (this.height || this.width)) { |
|
||||
opts.maintainAspectRatio = false; |
|
||||
} |
|
||||
|
|
||||
this.chart = new Chart(this.canvas, { |
|
||||
type: this.type, |
|
||||
data: this.data, |
|
||||
options: this.options, |
|
||||
plugins: this.plugins, |
|
||||
}); |
|
||||
|
|
||||
this.cdRef.detectChanges(); |
|
||||
}; |
|
||||
|
|
||||
generateLegend = () => { |
|
||||
if (this.chart) { |
|
||||
return this.chart.generateLegend(); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
refresh = () => { |
|
||||
if (this.chart) { |
|
||||
this.chart.update(); |
|
||||
this.cdRef.detectChanges(); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
reinit = () => { |
|
||||
if (this.chart) { |
|
||||
this.chart.destroy(); |
|
||||
this.initChart(); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
ngOnDestroy() { |
|
||||
if (this.chart) { |
|
||||
this.chart.destroy(); |
|
||||
this._initialized = false; |
|
||||
this.chart = null; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,2 +1,2 @@ |
|||||
import 'jest-canvas-mock'; |
|
||||
import 'jest-preset-angular/setup-jest'; |
import 'jest-preset-angular/setup-jest'; |
||||
|
|
||||
|
|||||
File diff suppressed because it is too large
Loading…
Reference in new issue