Browse Source

Minor refactorings.

pull/282/head
Sebastian Stehle 8 years ago
parent
commit
72f92f21bc
  1. 2
      src/Squidex/app/features/rules/pages/rules/rules-page.component.html
  2. 4
      src/Squidex/app/features/rules/pages/rules/rules-page.component.ts
  3. 36
      src/Squidex/app/features/settings/pages/clients/clients-page.component.html
  4. 42
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html
  5. 4
      src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts
  6. 38
      src/Squidex/app/features/settings/pages/plans/plans-page.component.html
  7. 74
      src/Squidex/app/features/settings/pages/plans/plans-page.component.ts
  8. 1
      src/Squidex/app/shared/internal.ts
  9. 2
      src/Squidex/app/shared/module.ts
  10. 9
      src/Squidex/app/shared/state/clients.state.spec.ts
  11. 27
      src/Squidex/app/shared/state/clients.state.ts
  12. 11
      src/Squidex/app/shared/state/contributors.state.spec.ts
  13. 24
      src/Squidex/app/shared/state/contributors.state.ts
  14. 10
      src/Squidex/app/shared/state/patterns.state.ts
  15. 131
      src/Squidex/app/shared/state/plans.state.ts

2
src/Squidex/app/features/rules/pages/rules/rules-page.component.html

@ -30,7 +30,7 @@
<table class="table table-items table-fixed" *ngIf="rules.length > 0">
<tbody>
<ng-template ngFor let-rule [ngForOf]="rules">
<ng-template ngFor let-rule [ngForOf]="rules" [ngForTrackBy]="trackByRule">
<tr>
<td class="cell-separator">
<h3>If</h3>

4
src/Squidex/app/features/rules/pages/rules/rules-page.component.ts

@ -80,4 +80,8 @@ export class RulesPageComponent implements OnInit {
this.addRuleDialog.show();
}
public trackByRule(index: number, rule: RuleDto) {
return rule.id;
}
}

36
src/Squidex/app/features/settings/pages/clients/clients-page.component.html

@ -10,26 +10,26 @@
<div class="table-items-row table-items-row-empty" *ngIf="clients.length === 0">
No client created yet.
</div>
<sqx-client *ngFor="let client of clients; trackBy: trackByClient" [client]="client"></sqx-client>
</ng-container>
<div class="table-items-footer" *ngIf="clientsState.isLoaded | async">
<form [formGroup]="addClientForm.form" (ngSubmit)="attachClient()">
<div class="row no-gutters">
<div class="col">
<sqx-control-errors for="name" [submitted]="addClientForm.submitted | async"></sqx-control-errors>
<input type="text" class="form-control" formControlName="name" maxlength="40" placeholder="Enter client name" autocomplete="off" sqxLowerCaseInput />
</div>
<div class="col col-auto pl-1">
<button type="submit" class="btn btn-success" [disabled]="addClientForm.hasNoName | async">Add Client</button>
<div class="table-items-footer">
<form [formGroup]="addClientForm.form" (ngSubmit)="attachClient()">
<div class="row no-gutters">
<div class="col">
<sqx-control-errors for="name" [submitted]="addClientForm.submitted | async"></sqx-control-errors>
<input type="text" class="form-control" formControlName="name" maxlength="40" placeholder="Enter client name" autocomplete="off" sqxLowerCaseInput />
</div>
<div class="col col-auto pl-1">
<button type="submit" class="btn btn-success" [disabled]="addClientForm.hasNoName | async">Add Client</button>
</div>
<div class="col col-auto pl-1">
<button type="reset" class="btn btn-secondary" (click)="cancelAttachClient()">Cancel</button>
</div>
</div>
<div class="col col-auto pl-1">
<button type="reset" class="btn btn-secondary" (click)="cancelAttachClient()">Cancel</button>
</div>
</div>
</form>
</div>
</form>
</div>
</ng-container>
</ng-container>
</sqx-panel>

42
src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html

@ -38,27 +38,27 @@
</ng-template>
</tbody>
</table>
</ng-container>
<div class="table-items-footer" *ngIf="(contributorsState.isMaxReached | async) === false">
<form [formGroup]="assignContributorForm.form" (ngSubmit)="assignContributor()">
<div class="row no-gutters">
<div class="col">
<sqx-autocomplete [source]="usersDataSource" formControlName="user" [inputName]="'contributor'" placeholder="Find existing user" displayProperty="displayName">
<ng-template let-user="$implicit">
<span class="autocomplete-user">
<img class="user-picture autocomplete-user-picture" [attr.src]="user | sqxUserDtoPicture" />
<div class="table-items-footer" *ngIf="(contributorsState.isMaxReached | async) === false">
<form [formGroup]="assignContributorForm.form" (ngSubmit)="assignContributor()">
<div class="row no-gutters">
<div class="col">
<sqx-autocomplete [source]="usersDataSource" formControlName="user" [inputName]="'contributor'" placeholder="Find existing user" displayProperty="displayName">
<ng-template let-user="$implicit">
<span class="autocomplete-user">
<img class="user-picture autocomplete-user-picture" [attr.src]="user | sqxUserDtoPicture" />
<span class="user-name autocomplete-user-name">{{user.displayName}}</span>
</span>
</ng-template>
</sqx-autocomplete>
</div>
<div class="col col-auto pl-1">
<button type="submit" class="btn btn-success" [disabled]="assignContributorForm.hasNoUser | async">Add Contributor</button>
</div>
</div>
</form>
</div>
<span class="user-name autocomplete-user-name">{{user.displayName}}</span>
</span>
</ng-template>
</sqx-autocomplete>
</div>
<div class="col col-auto pl-1">
<button type="submit" class="btn btn-success" [disabled]="assignContributorForm.hasNoUser | async">Add Contributor</button>
</div>
</div>
</form>
</div>
</ng-container>
</ng-container>
</sqx-panel>

4
src/Squidex/app/features/settings/pages/contributors/contributors-page.component.ts

@ -29,11 +29,11 @@ export class UsersDataSource implements AutocompleteSource {
public find(query: string): Observable<any[]> {
return this.usersService.getUsers(query)
.withLatestFrom(this.contributorsState.contributors, (users, contributors) => {
.withLatestFrom(this.contributorsState.contributors.filter(x => !!x), (users, contributors) => {
const results: any[] = [];
for (let user of users) {
if (!contributors.find(t => t.contributor.contributorId === user.id)) {
if (!contributors!.find(t => t.contributor.contributorId === user.id)) {
results.push(user);
}
}

38
src/Squidex/app/features/settings/pages/plans/plans-page.component.html

@ -6,71 +6,71 @@
</ng-container>
<ng-container menu>
<button class="btn btn-link btn-secondary" (click)="load(true)" title="Refresh Plans (CTRL + SHIFT + R)">
<button class="btn btn-link btn-secondary" (click)="reload()" title="Refresh Plans (CTRL + SHIFT + R)">
<i class="icon-reset"></i> Refresh
</button>
<sqx-shortcut keys="ctrl+shift+r" (trigger)="load(true)"></sqx-shortcut>
<sqx-shortcut keys="ctrl+shift+r" (trigger)="reload()"></sqx-shortcut>
</ng-container>
<ng-container content>
<ng-container *ngIf="plans">
<div class="panel-alert panel-alert-danger" *ngIf="!planOwned">
You have not created the subscription. Therefore you cannot change the plan.
<ng-container *ngIf="plansState.plans | async; let plans">
<div class="panel-alert panel-alert-danger" *ngIf="(plansState.isOwner | async) === false">
You have not created the subscription. Therefore you cannot change the planInfo.plan.
</div>
<div class="text-muted text-center empty" *ngIf="plans.plans.length === 0">
<div class="text-muted text-center empty" *ngIf="plans.length === 0">
No plan configured, this app has unlimited usage.
</div>
<div class="clearfix">
<div class="card plan float-left" *ngFor="let plan of plans.plans">
<div class="card plan float-left" *ngFor="let planInfo of plans; trackBy: trackByPlan">
<div class="card-header text-center">
<h4 class="card-title">{{plan.name}}</h4>
<h5 class="plan-price">{{plan.costs}}</h5>
<h4 class="card-title">{{planInfo.plan.name}}</h4>
<h5 class="plan-price">{{planInfo.plan.costs}}</h5>
<small class="text-muted">Per Month</small>
</div>
<div class="card-body">
<div class="plan-fact text-center">
<div>
<strong>{{plan.maxApiCalls | sqxKNumber}}</strong> API Calls
<strong>{{planInfo.plan.maxApiCalls | sqxKNumber}}</strong> API Calls
</div>
<div>
{{plan.maxAssetSize | sqxFileSize}} Storage
{{planInfo.plan.maxAssetSize | sqxFileSize}} Storage
</div>
<div>
{{plan.maxContributors}} Contributors
{{planInfo.plan.maxContributors}} Contributors
</div>
</div>
<button *ngIf="plan.id === plans.currentPlanId" class="btn btn-block btn-link btn-success plan-selected">
<button *ngIf="planInfo.isSelected" class="btn btn-block btn-link btn-success plan-selected">
&#10003; Selected
</button>
<button *ngIf="plan.id !== plans.currentPlanId" class="btn btn-block btn-success" [disabled]="isDisabled || !planOwned" (click)="changePlan(plan.id)">
<button *ngIf="!planInfo.isSelected" class="btn btn-block btn-success" [disabled]="plansState.isDisabled | async" (click)="change(planInfo.plan.id)">
Change
</button>
</div>
<div class="card-footer" *ngIf="plan.yearlyId">
<div class="card-footer" *ngIf="planInfo.plan.yearlyId">
<div class="text-center">
<h5 class="plan-price">{{plan.yearlyCosts}}</h5>
<h5 class="plan-price">{{planInfo.plan.yearlyCosts}}</h5>
<small class="text-muted">Per Year</small>
</div>
<button *ngIf="plan.yearlyId === plans.currentPlanId" class="btn btn-block btn-link btn-success plan-selected">
<button *ngIf="planInfo.isYearlySelected" class="btn btn-block btn-link btn-success plan-selected">
&#10003; Selected
</button>
<button *ngIf="plan.yearlyId !== plans.currentPlanId" class="btn btn-block btn-success" [disabled]="isDisabled || !planOwned" (click)="changePlan(plan.yearlyId)">
<button *ngIf="!planInfo.isYearlySelected" class="btn btn-block btn-success" [disabled]="plansState.isDisabled | async" (click)="change(planInfo.plan.yearlyId)">
Change
</button>
</div>
</div>
</div>
<div *ngIf="plans.hasPortal" class="billing-portal-link">
<div *ngIf="plansState.hasPortal | async" class="billing-portal-link">
Go to <a target="_blank" href="{{portalUrl}}">Billing Portal</a> for payment history and subscription overview.
</div>
</ng-container>

74
src/Squidex/app/features/settings/pages/plans/plans-page.component.ts

@ -5,18 +5,14 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import {
ApiUrlConfig,
AppPlansDto,
AppsState,
AuthService,
ChangePlanDto,
DialogService,
PlansService
PlansState,
PlanDto
} from '@app/shared';
@Component({
@ -24,75 +20,37 @@ import {
styleUrls: ['./plans-page.component.scss'],
templateUrl: './plans-page.component.html'
})
export class PlansPageComponent implements OnDestroy, OnInit {
private queryParamsSubscription: Subscription;
export class PlansPageComponent implements OnInit {
private overridePlanId: string;
public portalUrl = this.apiUrl.buildUrl('/portal/');
public plans: AppPlansDto;
public planOwned = false;
public isDisabled = false;
constructor(
public readonly appsState: AppsState,
public readonly plansState: PlansState,
private readonly apiUrl: ApiUrlConfig,
private readonly authState: AuthService,
private readonly dialogs: DialogService,
private readonly plansService: PlansService,
private readonly route: ActivatedRoute
) {
}
public ngOnDestroy() {
this.queryParamsSubscription.unsubscribe();
}
public ngOnInit() {
this.queryParamsSubscription =
this.route.queryParams.subscribe(params => {
this.overridePlanId = params['planId'];
});
this.route.queryParams.subscribe(params => {
this.overridePlanId = params['planId'];
}).unsubscribe();
this.load();
this.plansState.load(false, this.overridePlanId).onErrorResumeNext().subscribe();
}
public load(notifyLoad = false) {
this.plansService.getPlans(this.appsState.appName)
.subscribe(dto => {
if (this.overridePlanId) {
this.plans = dto.changePlanId(this.overridePlanId);
} else {
this.plans = dto;
}
this.planOwned = !dto.planOwner || (dto.planOwner === this.authState.user!.id);
if (notifyLoad) {
this.dialogs.notifyInfo('Plans reloaded.');
}
}, error => {
this.dialogs.notifyError(error);
});
public reload() {
this.plansState.load(true, this.overridePlanId).onErrorResumeNext().subscribe();
}
public changePlan(planId: string) {
this.isDisabled = true;
public change(planId: string) {
this.plansState.change(planId).onErrorResumeNext().subscribe();
}
this.plansService.putPlan(this.appsState.appName, new ChangePlanDto(planId), this.plans.version)
.do(() => {
this.isDisabled = false;
})
.subscribe(dto => {
if (dto.payload.redirectUri && dto.payload.redirectUri.length > 0) {
window.location.href = dto.payload.redirectUri;
} else {
this.plans = this.plans.changePlanId(planId, dto.version);
}
}, error => {
this.dialogs.notifyError(error);
});
public trackByPlan(index: number, plan: PlanDto) {
return plan.id;
}
}

1
src/Squidex/app/shared/internal.ts

@ -44,6 +44,7 @@ export * from './state/backups.state';
export * from './state/clients.state';
export * from './state/contributors.state';
export * from './state/patterns.state';
export * from './state/plans.state';
export * from './state/rules.state';
export * from './state/schemas.state';

2
src/Squidex/app/shared/module.ts

@ -51,6 +51,7 @@ import {
MustBeNotAuthenticatedGuard,
PatternsState,
PlansService,
PlansState,
ResolveAppLanguagesGuard,
ResolveContentGuard,
RichEditorComponent,
@ -155,6 +156,7 @@ export class SqxSharedModule {
MustBeNotAuthenticatedGuard,
PatternsState,
PlansService,
PlansState,
ResolveAppLanguagesGuard,
ResolveContentGuard,
RulesService,

9
src/Squidex/app/shared/state/clients.state.spec.ts

@ -54,8 +54,7 @@ describe('ClientsState', () => {
});
it('should load clients', () => {
expect(clientsState.snapshot.clients.values).toEqual(oldClients);
expect(clientsState.snapshot.isLoaded).toBeTruthy();
expect(clientsState.snapshot.clients!.values).toEqual(oldClients);
expect(clientsState.snapshot.version).toEqual(version);
});
@ -69,7 +68,7 @@ describe('ClientsState', () => {
clientsState.attach(request).subscribe();
expect(clientsState.snapshot.clients.values).toEqual([...oldClients, newClient]);
expect(clientsState.snapshot.clients!.values).toEqual([...oldClients, newClient]);
expect(clientsState.snapshot.version).toEqual(newVersion);
});
@ -81,7 +80,7 @@ describe('ClientsState', () => {
clientsState.update(oldClients[0], request).subscribe();
const client_1 = clientsState.snapshot.clients.at(0);
const client_1 = clientsState.snapshot.clients!.at(0);
expect(client_1.name).toBe('NewName');
expect(client_1.permission).toBe('NewPermission');
@ -94,7 +93,7 @@ describe('ClientsState', () => {
clientsState.revoke(oldClients[0]).subscribe();
expect(clientsState.snapshot.clients.values).toEqual([oldClients[1]]);
expect(clientsState.snapshot.clients!.values).toEqual([oldClients[1]]);
expect(clientsState.snapshot.version).toEqual(newVersion);
});
});

27
src/Squidex/app/shared/state/clients.state.ts

@ -58,11 +58,9 @@ export class AttachClientForm extends Form<FormGroup> {
}
interface Snapshot {
clients: ImmutableArray<AppClientDto>;
clients?: ImmutableArray<AppClientDto>;
isLoaded: boolean;
version: Version;
version?: Version;
}
@Injectable()
@ -70,15 +68,12 @@ export class ClientsState extends State<Snapshot> {
public clients =
this.changes.map(x => x.clients);
public isLoaded =
this.changes.map(x => x.isLoaded);
constructor(
private readonly appClientsService: AppClientsService,
private readonly appsState: AppsState,
private readonly dialogs: DialogService
) {
super({ clients: ImmutableArray.empty(), version: new Version(''), isLoaded: false });
super({});
}
public load(): Observable<any> {
@ -94,10 +89,10 @@ export class ClientsState extends State<Snapshot> {
}
public attach(request: CreateAppClientDto): Observable<any> {
return this.appClientsService.postClient(this.appName, request, this.snapshot.version)
return this.appClientsService.postClient(this.appName, request, this.version)
.do(dto => {
this.next(s => {
const clients = s.clients.push(dto.payload);
const clients = s.clients!.push(dto.payload);
return { ...s, clients, version: dto.version };
});
@ -106,10 +101,10 @@ export class ClientsState extends State<Snapshot> {
}
public revoke(client: AppClientDto): Observable<any> {
return this.appClientsService.deleteClient(this.appName, client.id, this.snapshot.version)
return this.appClientsService.deleteClient(this.appName, client.id, this.version)
.do(dto => {
this.next(s => {
const clients = s.clients.filter(c => c.id !== client.id);
const clients = s.clients!.filter(c => c.id !== client.id);
return { ...s, clients, version: dto.version };
});
@ -118,10 +113,10 @@ export class ClientsState extends State<Snapshot> {
}
public update(client: AppClientDto, request: UpdateAppClientDto): Observable<any> {
return this.appClientsService.putClient(this.appName, client.id, request, this.snapshot.version)
return this.appClientsService.putClient(this.appName, client.id, request, this.version)
.do(dto => {
this.next(s => {
const clients = s.clients.replaceBy('id', update(client, request));
const clients = s.clients!.replaceBy('id', update(client, request));
return { ...s, clients, version: dto.version };
});
@ -132,6 +127,10 @@ export class ClientsState extends State<Snapshot> {
private get appName() {
return this.appsState.appName;
}
private get version() {
return this.snapshot.version!;
}
}
const update = (client: AppClientDto, request: UpdateAppClientDto) =>

11
src/Squidex/app/shared/state/contributors.state.spec.ts

@ -59,8 +59,7 @@ describe('ContributorsState', () => {
});
it('should load contributors', () => {
expect(contributorsState.snapshot.contributors.values).toEqual(oldContributors.map(x => c(x)));
expect(contributorsState.snapshot.isLoaded).toBeTruthy();
expect(contributorsState.snapshot.contributors!.values).toEqual(oldContributors.map(x => c(x)));
expect(contributorsState.snapshot.isMaxReached).toBeFalsy();
expect(contributorsState.snapshot.maxContributors).toBe(3);
expect(contributorsState.snapshot.version).toEqual(version);
@ -76,8 +75,7 @@ describe('ContributorsState', () => {
contributorsState.assign(request).subscribe();
expect(contributorsState.snapshot.contributors.values).toEqual([...oldContributors.map(x => c(x)), c(newContributor)]);
expect(contributorsState.snapshot.isLoaded).toBeTruthy();
expect(contributorsState.snapshot.contributors!.values).toEqual([...oldContributors.map(x => c(x)), c(newContributor)]);
expect(contributorsState.snapshot.isMaxReached).toBeTruthy();
expect(contributorsState.snapshot.maxContributors).toBe(3);
expect(contributorsState.snapshot.version).toEqual(newVersion);
@ -93,8 +91,7 @@ describe('ContributorsState', () => {
contributorsState.assign(request).subscribe();
expect(contributorsState.snapshot.contributors.values).toEqual([c(oldContributors[0]), c(newContributor)]);
expect(contributorsState.snapshot.isLoaded).toBeTruthy();
expect(contributorsState.snapshot.contributors!.values).toEqual([c(oldContributors[0]), c(newContributor)]);
expect(contributorsState.snapshot.isMaxReached).toBeFalsy();
expect(contributorsState.snapshot.maxContributors).toBe(3);
expect(contributorsState.snapshot.version).toEqual(newVersion);
@ -106,7 +103,7 @@ describe('ContributorsState', () => {
contributorsState.revoke(oldContributors[0]).subscribe();
expect(contributorsState.snapshot.contributors.values).toEqual([c(oldContributors[1])]);
expect(contributorsState.snapshot.contributors!.values).toEqual([c(oldContributors[1])]);
expect(contributorsState.snapshot.version).toEqual(newVersion);
});

24
src/Squidex/app/shared/state/contributors.state.ts

@ -45,14 +45,13 @@ interface SnapshotContributor {
}
interface Snapshot {
contributors: ImmutableArray<SnapshotContributor>;
contributors?: ImmutableArray<SnapshotContributor>;
isLoaded: boolean;
isMaxReached: boolean;
isMaxReached?: boolean;
maxContributors: number;
version: Version;
version?: Version;
}
@Injectable()
@ -60,9 +59,6 @@ export class ContributorsState extends State<Snapshot> {
public contributors =
this.changes.map(x => x.contributors);
public isLoaded =
this.changes.map(x => x.isLoaded);
public isMaxReached =
this.changes.map(x => x.isMaxReached);
@ -75,7 +71,7 @@ export class ContributorsState extends State<Snapshot> {
private readonly authState: AuthService,
private readonly dialogs: DialogService
) {
super({ contributors: ImmutableArray.empty(), version: new Version(''), isLoaded: false, isMaxReached: true, maxContributors: -1 });
super({ maxContributors: -1 });
}
public load(): Observable<any> {
@ -89,9 +85,9 @@ export class ContributorsState extends State<Snapshot> {
}
public revoke(contributor: AppContributorDto): Observable<any> {
return this.appContributorsService.deleteContributor(this.appName, contributor.contributorId, this.snapshot.version)
return this.appContributorsService.deleteContributor(this.appName, contributor.contributorId, this.version)
.do(dto => {
const contributors = this.snapshot.contributors.filter(x => x.contributor.contributorId !== contributor.contributorId);
const contributors = this.snapshot.contributors!.filter(x => x.contributor.contributorId !== contributor.contributorId);
this.replaceContributors(contributors, dto.version);
})
@ -99,11 +95,11 @@ export class ContributorsState extends State<Snapshot> {
}
public assign(request: AppContributorDto): Observable<any> {
return this.appContributorsService.postContributor(this.appName, request, this.snapshot.version)
return this.appContributorsService.postContributor(this.appName, request, this.version)
.do(dto => {
const contributor = this.createContributor(new AppContributorDto(dto.payload.contributorId, request.permission));
let contributors = this.snapshot.contributors;
let contributors = this.snapshot.contributors!;
if (contributors.find(x => x.contributor.contributorId === dto.payload.contributorId)) {
contributors = contributors.map(c => c.contributor.contributorId === dto.payload.contributorId ? contributor : c);
@ -131,6 +127,10 @@ export class ContributorsState extends State<Snapshot> {
return this.appsState.appName;
}
private get version() {
return this.snapshot.version!;
}
private createContributor(contributor: AppContributorDto): SnapshotContributor {
return { contributor, isCurrentUser: contributor.contributorId === this.authState.user!.id };
}

10
src/Squidex/app/shared/state/patterns.state.ts

@ -89,7 +89,7 @@ export class PatternsState extends State<Snapshot> {
}
public create(request: EditAppPatternDto): Observable<any> {
return this.appPatternsService.postPattern(this.appName, request, this.snapshot.version)
return this.appPatternsService.postPattern(this.appName, request, this.version)
.do(dto => {
this.next(s => {
const patterns = s.patterns.push(dto.payload).sortByStringAsc(x => x.name);
@ -101,7 +101,7 @@ export class PatternsState extends State<Snapshot> {
}
public update(pattern: AppPatternDto, request: EditAppPatternDto): Observable<any> {
return this.appPatternsService.putPattern(this.appName, pattern.id, request, this.snapshot.version)
return this.appPatternsService.putPattern(this.appName, pattern.id, request, this.version)
.do(dto => {
this.next(s => {
const patterns = s.patterns.replaceBy('id', update(pattern, request)).sortByStringAsc(x => x.name);
@ -113,7 +113,7 @@ export class PatternsState extends State<Snapshot> {
}
public delete(pattern: AppPatternDto): Observable<any> {
return this.appPatternsService.deletePattern(this.appName, pattern.id, this.snapshot.version)
return this.appPatternsService.deletePattern(this.appName, pattern.id, this.version)
.do(dto => {
this.next(s => {
const patterns = s.patterns.filter(c => c.id !== pattern.id);
@ -127,6 +127,10 @@ export class PatternsState extends State<Snapshot> {
private get appName() {
return this.appsState.appName;
}
private get version() {
return this.snapshot.version;
}
}
const update = (pattern: AppPatternDto, request: EditAppPatternDto) =>

131
src/Squidex/app/shared/state/plans.state.ts

@ -0,0 +1,131 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import '@app/framework/utils/rxjs-extensions';
import {
DialogService,
ImmutableArray,
State,
Version
} from '@app/framework';
import { AppsState } from './apps.state';
import { AuthService } from './../services/auth.service';
import {
ChangePlanDto,
PlanDto,
PlansService
} from './../services/plans.service';
interface PlanInfo {
plan: PlanDto;
isYearlySelected?: boolean;
isSelected?: boolean;
}
interface Snapshot {
plans?: ImmutableArray<PlanInfo>;
version?: Version;
isOwner?: boolean;
isDisabled?: boolean;
hasPortal?: boolean;
}
@Injectable()
export class PlansState extends State<Snapshot> {
public plans =
this.changes.map(x => x.plans);
public isOwner =
this.changes.map(x => x.isOwner);
public isDisabled =
this.changes.map(x => x.isDisabled || !x.isOwner);
public hasPortal =
this.changes.map(x => x.hasPortal);
public window = window;
constructor(
private readonly appsState: AppsState,
private readonly authState: AuthService,
private readonly dialogs: DialogService,
private readonly plansService: PlansService
) {
super({});
}
public load(notifyLoad = false, overridePlanId?: string): Observable<any> {
return this.plansService.getPlans(this.appName)
.do(dto => {
if (notifyLoad) {
this.dialogs.notifyInfo('Plans reloaded.');
}
this.next(s => {
const planId = overridePlanId || dto.currentPlanId;
return {
...s,
plans: ImmutableArray.of(dto.plans.map(x => this.createPlan(x, planId))),
isOwner: !dto.planOwner || dto.planOwner === this.userId,
isDisabled: false,
hasPortal: dto.hasPortal
};
});
})
.notify(this.dialogs);
}
public change(planId: string): Observable<any> {
this.next(s => ({ ...s, isDisabled: true }));
return this.plansService.putPlan(this.appName, new ChangePlanDto(planId), this.version)
.do(dto => {
if (dto.payload.redirectUri && dto.payload.redirectUri.length > 0) {
this.window.location.href = dto.payload.redirectUri;
} else {
this.next(s => {
return {
...s,
plans: s.plans!.map(x => this.createPlan(x.plan, planId)),
isOwner: true,
isDisabled: false
};
});
}
})
.notify(this.dialogs);
}
private createPlan(plan: PlanDto, id: string) {
return { plan, isYearlySelected: plan.yearlyId === id, isSelected: plan.id === id };
}
private get appName() {
return this.appsState.appName;
}
private get userId() {
return this.authState.user!.id;
}
private get version() {
return this.snapshot.version!;
}
}
Loading…
Cancel
Save