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 '_vars'; |
||||
@import '_mixins'; |
@import '_mixins'; |
||||
|
|
||||
texarea { |
textarea { |
||||
resize: none; |
resize: none; |
||||
} |
} |
||||
@ -1,29 +1,2 @@ |
|||||
@import '_vars'; |
@import '_vars'; |
||||
@import '_mixins'; |
@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; |
|
||||
} |
|
||||
} |
|
||||
@ -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