mirror of https://github.com/Squidex/squidex.git
Browse Source
* Variable naming fixed. * Tests improved and contributor import dialog.pull/407/head
committed by
GitHub
30 changed files with 446 additions and 147 deletions
@ -1,6 +1,6 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
texarea { |
|||
textarea { |
|||
resize: none; |
|||
} |
|||
@ -1,29 +1,2 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
$circle-size: 2.8rem; |
|||
|
|||
.backup-status { |
|||
& { |
|||
@include circle($circle-size); |
|||
line-height: $circle-size + .1rem; |
|||
text-align: center; |
|||
font-size: .4 * $circle-size; |
|||
font-weight: normal; |
|||
background: $color-border; |
|||
color: $color-dark-foreground; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
&-pending { |
|||
color: inherit; |
|||
} |
|||
|
|||
&-failed { |
|||
background: $color-theme-error; |
|||
} |
|||
|
|||
&-success { |
|||
background: $color-theme-green; |
|||
} |
|||
} |
|||
@import '_mixins'; |
|||
@ -0,0 +1,43 @@ |
|||
<form [formGroup]="importForm.form" (ngSubmit)="import()"> |
|||
<sqx-modal-dialog (close)="emitClose()"> |
|||
<ng-container title> |
|||
Import contributors |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<div class="content"> |
|||
<ng-container *ngIf="importStatus; else noStatus"> |
|||
<div class="row pb-2" *ngFor="let status of importStatus"> |
|||
<div class="col truncate"> |
|||
{{status.email}} |
|||
</div> |
|||
|
|||
<div class="col-auto"> |
|||
<sqx-status-icon size="sm" |
|||
[status]="status.result" |
|||
[statusText]="status.resultText"> |
|||
</sqx-status-icon> |
|||
</div> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-template #noStatus> |
|||
<textarea class="form-control content" placeholder="user1@squidex.io;user2.squidex.io" formControlName="import"></textarea> |
|||
</ng-template> |
|||
</div> |
|||
|
|||
<sqx-form-hint> |
|||
<ng-container *ngIf="importForm.numberOfEmails | async; let emails"> |
|||
Emails detected: {{emails}} |
|||
</ng-container> |
|||
|
|||
|
|||
</sqx-form-hint> |
|||
</ng-container> |
|||
|
|||
<ng-container footer> |
|||
<button type="reset" class="float-left btn btn-secondary" (click)="emitClose()">Cancel</button> |
|||
<button type="submit" class="float-right btn btn-success" [disabled]="importStatus || (importForm.hasNoUser | async)">Add Contributors</button> |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
</form> |
|||
@ -0,0 +1,10 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
textarea { |
|||
resize: none; |
|||
} |
|||
|
|||
.content { |
|||
min-height: 300px; |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { Component, EventEmitter, Output } from '@angular/core'; |
|||
import { FormBuilder } from '@angular/forms'; |
|||
import { empty, of } from 'rxjs'; |
|||
import { catchError, mergeMap, tap } from 'rxjs/operators'; |
|||
|
|||
import { |
|||
ContributorsState, |
|||
ErrorDto, |
|||
ImportContributorsForm |
|||
} from '@app/shared'; |
|||
|
|||
interface ImportStatus { |
|||
email: string; |
|||
result: 'Pending' | 'Failed' | 'Success'; |
|||
resultText: string; |
|||
} |
|||
|
|||
@Component({ |
|||
selector: 'sqx-import-contributors-dialog', |
|||
styleUrls: ['./import-contributors-dialog.component.scss'], |
|||
templateUrl: './import-contributors-dialog.component.html' |
|||
}) |
|||
export class ImportContributorsDialogComponent { |
|||
@Output() |
|||
public close = new EventEmitter(); |
|||
|
|||
public importForm = new ImportContributorsForm(this.formBuilder); |
|||
public importStatus: ImportStatus[]; |
|||
|
|||
constructor( |
|||
private readonly formBuilder: FormBuilder, |
|||
private readonly contributorsState: ContributorsState |
|||
) { |
|||
} |
|||
|
|||
public import() { |
|||
const contributors = this.importForm.submit(); |
|||
|
|||
if (contributors && contributors.length > 0) { |
|||
this.importStatus = []; |
|||
|
|||
for (let contributor of contributors) { |
|||
this.importStatus.push({ |
|||
email: contributor.contributorId, |
|||
result: 'Pending', |
|||
resultText: 'Pending' |
|||
}); |
|||
} |
|||
|
|||
of(...contributors).pipe( |
|||
mergeMap(c => |
|||
this.contributorsState.assign(c, { silent: true }).pipe( |
|||
tap(created => { |
|||
let status = this.importStatus.find(x => x.email === c.contributorId); |
|||
|
|||
if (status) { |
|||
status.resultText = getSuccess(created); |
|||
status.result = 'Success'; |
|||
} |
|||
}), |
|||
catchError((error: ErrorDto) => { |
|||
let status = this.importStatus.find(x => x.email === c.contributorId); |
|||
|
|||
if (status) { |
|||
status.resultText = getError(error); |
|||
status.result = 'Failed'; |
|||
} |
|||
|
|||
return empty(); |
|||
}) |
|||
), 1) |
|||
).subscribe(); |
|||
} |
|||
} |
|||
|
|||
public emitClose() { |
|||
this.close.emit(); |
|||
} |
|||
} |
|||
|
|||
function getError(error: ErrorDto): string { |
|||
return error.details[0]; |
|||
} |
|||
|
|||
function getSuccess(created: boolean | undefined): string { |
|||
return created ? |
|||
'User has been invited and assigned.' : |
|||
'User has been assigned'; |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
<ng-container [ngSwitch]="status"> |
|||
<div *ngSwitchCase="'Failed'" class="status status-failed {{size}}" [title]="statusText"> |
|||
<i class="icon-exclamation"></i> |
|||
</div> |
|||
<div *ngSwitchCase="'Success'" class="status status-success {{size}}" [title]="statusText"> |
|||
<i class="icon-checkmark"></i> |
|||
</div> |
|||
<div *ngSwitchCase="'Completed'" class="status status-success {{size}}" [title]="statusText"> |
|||
<i class="icon-checkmark"></i> |
|||
</div> |
|||
<div *ngSwitchDefault class="status status-pending spin {{size}}" [title]="statusText"> |
|||
<i class="icon-hour-glass"></i> |
|||
</div> |
|||
</ng-container> |
|||
@ -0,0 +1,41 @@ |
|||
@import '_mixins'; |
|||
@import '_vars'; |
|||
|
|||
$circle-size-sm: 1.6rem; |
|||
|
|||
$circle-size-lg: 2.8rem; |
|||
|
|||
.status { |
|||
& { |
|||
text-align: center; |
|||
background: $color-border; |
|||
color: $color-dark-foreground; |
|||
vertical-align: middle; |
|||
} |
|||
|
|||
&.sm { |
|||
@include circle($circle-size-sm); |
|||
line-height: $circle-size-sm + .1rem; |
|||
font-size: .5 * $circle-size-sm; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
&.lg { |
|||
@include circle($circle-size-lg); |
|||
line-height: $circle-size-lg + .1rem; |
|||
font-size: .5 * $circle-size-lg; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
&-pending { |
|||
color: inherit; |
|||
} |
|||
|
|||
&-failed { |
|||
background: $color-theme-error; |
|||
} |
|||
|
|||
&-success { |
|||
background: $color-theme-green; |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-status-icon', |
|||
styleUrls: ['./status-icon.component.scss'], |
|||
templateUrl: './status-icon.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush |
|||
}) |
|||
export class StatusIconComponent { |
|||
@Input() |
|||
public status: 'Started' | 'Failed' | 'Success' | 'Completed' | 'Failed' | 'Pending'; |
|||
|
|||
@Input() |
|||
public statusText: string; |
|||
|
|||
@Input() |
|||
public size: 'lg' | 'sm' = 'lg'; |
|||
} |
|||
Loading…
Reference in new issue