feat(console): codemirror code editor for actions (#2736)

* feat: codemirror code editor

* cleanup

* lint

* mat import

* lint
This commit is contained in:
Max Peintner
2021-12-08 10:48:23 +01:00
committed by GitHub
parent 211dc7c21f
commit 7bf7379a05
11 changed files with 492 additions and 571 deletions

View File

@@ -20,7 +20,7 @@ import { AddActionDialogComponent } from '../add-action-dialog/add-action-dialog
@Component({
selector: 'cnsl-action-table',
templateUrl: './action-table.component.html',
styleUrls: ['./action-table.component.scss']
styleUrls: ['./action-table.component.scss'],
})
export class ActionTableComponent implements OnInit {
@ViewChild(PaginatorComponent) public paginator!: PaginatorComponent;
@@ -34,8 +34,12 @@ export class ActionTableComponent implements OnInit {
@Output() public changedSelection: EventEmitter<Array<Action.AsObject>> = new EventEmitter();
public ActionState: any = ActionState;
constructor(public translate: TranslateService, private mgmtService: ManagementService, private dialog: MatDialog,
private toast: ToastService) {
constructor(
public translate: TranslateService,
private mgmtService: ManagementService,
private dialog: MatDialog,
private toast: ToastService,
) {
this.selection.changed.subscribe(() => {
this.changedSelection.emit(this.selection.selected);
});
@@ -45,7 +49,6 @@ export class ActionTableComponent implements OnInit {
this.getData(10, 0);
}
public isAllSelected(): boolean {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
@@ -53,39 +56,42 @@ export class ActionTableComponent implements OnInit {
}
public masterToggle(): void {
this.isAllSelected() ?
this.selection.clear() :
this.dataSource.data.forEach(row => this.selection.select(row));
this.isAllSelected() ? this.selection.clear() : this.dataSource.data.forEach((row) => this.selection.select(row));
}
public changePage(event: PageEvent): void {
this.getData(event.pageSize, event.pageIndex * event.pageSize);
}
public deleteKey(action: Action.AsObject): void {
this.mgmtService.deleteAction(action.id).then(() => {
this.selection.clear();
this.toast.showInfo('FLOWS.TOAST.SELECTEDKEYSDELETED', true);
this.getData(10, 0);
}).catch(error => {
this.toast.showError(error);
});
this.mgmtService
.deleteAction(action.id)
.then(() => {
this.selection.clear();
this.toast.showInfo('FLOWS.TOAST.SELECTEDKEYSDELETED', true);
this.getData(10, 0);
})
.catch((error) => {
this.toast.showError(error);
});
}
public openAddAction(): void {
const dialogRef = this.dialog.open(AddActionDialogComponent, {
data: {},
width: '400px',
width: '500px',
});
dialogRef.afterClosed().subscribe((req: CreateActionRequest) => {
if (req) {
this.mgmtService.createAction(req).then(resp => {
this.refreshPage();
}).catch((error: any) => {
this.toast.showError(error);
});
this.mgmtService
.createAction(req)
.then((resp) => {
this.refreshPage();
})
.catch((error: any) => {
this.toast.showError(error);
});
}
});
}
@@ -95,31 +101,37 @@ export class ActionTableComponent implements OnInit {
data: {
action: action,
},
width: '400px',
width: '500px',
});
dialogRef.afterClosed().subscribe((req: UpdateActionRequest) => {
if (req) {
this.mgmtService.updateAction(req).then(resp => {
this.refreshPage();
}).catch((error: any) => {
this.toast.showError(error);
});
this.mgmtService
.updateAction(req)
.then((resp) => {
this.refreshPage();
})
.catch((error: any) => {
this.toast.showError(error);
});
}
});
}
private async getData(limit: number, offset: number): Promise<void> {
this.loadingSubject.next(true);
this.mgmtService.listActions(limit, offset).then(resp => {
this.actionsResult = resp;
this.dataSource.data = this.actionsResult.resultList;
this.loadingSubject.next(false);
}).catch((error: any) => {
this.toast.showError(error);
this.loadingSubject.next(false);
});
this.mgmtService
.listActions(limit, offset)
.then((resp) => {
this.actionsResult = resp;
this.dataSource.data = this.actionsResult.resultList;
this.loadingSubject.next(false);
})
.catch((error: any) => {
this.toast.showError(error);
this.loadingSubject.next(false);
});
}
public refreshPage(): void {

View File

@@ -9,6 +9,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatSelectModule } from '@angular/material/select';
import { MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from '@angular/material/tooltip';
import { CodemirrorModule } from '@ctrl/ngx-codemirror';
import { TranslateModule } from '@ngx-translate/core';
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
import { FormFieldModule } from 'src/app/modules/form-field/form-field.module';
@@ -55,6 +56,7 @@ import { AddFlowDialogComponent } from './add-flow-dialog/add-flow-dialog.compon
DragDropModule,
InfoSectionModule,
HasFeaturePipeModule,
CodemirrorModule,
],
})
export class ActionsModule {}

View File

@@ -2,17 +2,16 @@
<span *ngIf="id" class="title" mat-dialog-title>{{'FLOWS.DIALOG.UPDATE.TITLE' | translate}}</span>
<div mat-dialog-content>
<!-- <p class="desc"> {{'FLOWS.DIALOG.ADD.DESCRIPTION' | translate}}</p> -->
<cnsl-form-field class="form-field" appearance="outline">
<cnsl-label>{{'FLOWS.NAME' | translate}}</cnsl-label>
<input cnslInput [(ngModel)]="name">
</cnsl-form-field>
<cnsl-form-field class="form-field" appearance="outline">
<cnsl-label>{{'FLOWS.SCRIPT' | translate}}</cnsl-label>
<textarea class="script" cnslInput [(ngModel)]="script"></textarea>
</cnsl-form-field>
<ngx-codemirror *ngIf="opened$ | async" [(ngModel)]="script" [options]="{
lineNumbers: true,
theme: 'material',
mode: 'javascript'
}"></ngx-codemirror>
<cnsl-form-field class="form-field" appearance="outline">
<cnsl-label>{{'FLOWS.TIMEOUTINSEC' | translate}}</cnsl-label>

View File

@@ -1,3 +1,5 @@
@use '@angular/material' as mat;
.title {
font-size: 1.2rem;
margin-top: 0;
@@ -8,8 +10,11 @@
font-size: .9rem;
}
.script {
min-height: 200px;
@mixin action-dialog-theme($theme) {
$primary: map-get($theme, primary);
$primary-color: mat.get-color-from-palette($primary, 500);
$is-dark-theme: map-get($theme, is-dark);
$foreground: map-get($theme, foreground);
}
.action {

View File

@@ -1,99 +1,104 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
import { mapTo } from 'rxjs';
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
import { Action } from 'src/app/proto/generated/zitadel/action_pb';
import { CreateActionRequest, UpdateActionRequest } from 'src/app/proto/generated/zitadel/management_pb';
import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service';
@Component({
selector: 'cnsl-add-action-dialog',
templateUrl: './add-action-dialog.component.html',
styleUrls: ['./add-action-dialog.component.scss'],
selector: 'cnsl-add-action-dialog',
templateUrl: './add-action-dialog.component.html',
styleUrls: ['./add-action-dialog.component.scss'],
})
export class AddActionDialogComponent {
public name: string = '';
public script: string = '';
public durationInSec: number = 10;
public allowedToFail: boolean = false;
public name: string = '';
public script: string = '';
public durationInSec: number = 10;
public allowedToFail: boolean = false;
public id: string = '';
constructor(
private toast: ToastService,
private mgmtService: ManagementService,
private dialog: MatDialog,
public dialogRef: MatDialogRef<AddActionDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
) {
if (data && data.action) {
const action: Action.AsObject = data.action;
this.name = action.name;
this.script = action.script;
if (action.timeout?.seconds) {
this.durationInSec = action.timeout?.seconds;
}
this.allowedToFail = action.allowedToFail;
this.id = action.id;
}
}
public id: string = '';
public closeDialog(): void {
this.dialogRef.close(false);
}
public opened$ = this.dialogRef.afterOpened().pipe(mapTo(true));
public closeDialogWithSuccess(): void {
if (this.id) {
const req = new UpdateActionRequest();
req.setId(this.id);
req.setName(this.name);
req.setScript(this.script);
const duration = new Duration();
duration.setNanos(0);
duration.setSeconds(this.durationInSec);
req.setAllowedToFail(this.allowedToFail);
req.setTimeout(duration)
this.dialogRef.close(req);
} else {
const req = new CreateActionRequest();
req.setName(this.name);
req.setScript(this.script);
const duration = new Duration();
duration.setNanos(0);
duration.setSeconds(this.durationInSec);
req.setAllowedToFail(this.allowedToFail);
req.setTimeout(duration)
this.dialogRef.close(req);
constructor(
private toast: ToastService,
private mgmtService: ManagementService,
private dialog: MatDialog,
public dialogRef: MatDialogRef<AddActionDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
) {
if (data && data.action) {
const action: Action.AsObject = data.action;
this.name = action.name;
this.script = action.script;
if (action.timeout?.seconds) {
this.durationInSec = action.timeout?.seconds;
}
this.allowedToFail = action.allowedToFail;
this.id = action.id;
}
}
public deleteAndCloseDialog(): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.CLEAR',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'FLOWS.DIALOG.DELETEACTION.TITLE',
descriptionKey: 'FLOWS.DIALOG.DELETEACTION.DESCRIPTION',
},
width: '400px',
});
public closeDialog(): void {
this.dialogRef.close(false);
}
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
this.mgmtService.deleteAction(this.id).then(resp => {
public closeDialogWithSuccess(): void {
if (this.id) {
const req = new UpdateActionRequest();
req.setId(this.id);
req.setName(this.name);
req.setScript(this.script);
const duration = new Duration();
duration.setNanos(0);
duration.setSeconds(this.durationInSec);
req.setAllowedToFail(this.allowedToFail);
req.setTimeout(duration);
this.dialogRef.close(req);
} else {
const req = new CreateActionRequest();
req.setName(this.name);
req.setScript(this.script);
const duration = new Duration();
duration.setNanos(0);
duration.setSeconds(this.durationInSec);
req.setAllowedToFail(this.allowedToFail);
req.setTimeout(duration);
this.dialogRef.close(req);
}
}
public deleteAndCloseDialog(): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.DELETE',
cancelKey: 'ACTIONS.CANCEL',
titleKey: 'FLOWS.DIALOG.DELETEACTION.TITLE',
descriptionKey: 'FLOWS.DIALOG.DELETEACTION.DESCRIPTION',
},
width: '400px',
});
dialogRef.afterClosed().subscribe((resp) => {
if (resp) {
this.mgmtService
.deleteAction(this.id)
.then((resp) => {
this.dialogRef.close();
}).catch((error: any) => {
})
.catch((error: any) => {
this.toast.showError(error);
});
}
});
}
}
});
}
}