Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
Config-editor-ui: Application manager (#278)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmv13 authored Sep 8, 2021
1 parent 046c85c commit 0608d76
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 36 deletions.
2 changes: 1 addition & 1 deletion config-editor/config-editor-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rule-editor.ui",
"version": "1.3.9-dev",
"version": "1.3.10-dev",
"license": "MIT",
"scripts": {
"ng": "ng",
Expand Down
2 changes: 2 additions & 0 deletions config-editor/config-editor-ui/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
SubmitDialogComponent,
LandingPageComponent,
ImporterDialogComponent,
ApplicationDialogComponent,
SearchComponent,
} from '@app/components';
import { ConfigTileComponent } from '@app/components/tile/config-tile.component';
Expand Down Expand Up @@ -109,6 +110,7 @@ const DEV_PROVIDERS = [...PROD_PROVIDERS];
DeployDialogComponent,
SubmitDialogComponent,
ImporterDialogComponent,
ApplicationDialogComponent,
LandingPageComponent,
SearchComponent,
ConfigTileComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<mat-card>
<mat-card-title>
<div class="rule-title">{{serviceName | titlecase}} Admin Config</div>
<button
class="button"
mat-raised-button color="accent"
*ngIf="(applications$ | async)?.length > 0"
(click)="openApplicationDialog()"
>
Manage Applications
</button>
</mat-card-title>
<mat-card-subtitle>
<p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { EditorService } from '@services/editor.service';
import { ConfigData, PullRequestInfo } from '@app/model';
import { Type, AdminConfig } from '@app/model/config-model';
import { Type, AdminConfig, Application } from '@app/model/config-model';
import { PopupService } from '@app/services/popup.service';
import { FormlyFieldConfig, FormlyFormOptions } from '@ngx-formly/core';
import { cloneDeep } from 'lodash';
Expand All @@ -13,6 +13,7 @@ import { Router } from '@angular/router';
import { SubmitDialogComponent } from '../submit-dialog/submit-dialog.component';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
import { AppConfigService } from '@app/services/app-config.service';
import { ApplicationDialogComponent } from '..';

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
Expand All @@ -32,6 +33,7 @@ export class AdminComponent implements OnInit, OnDestroy {
config: AdminConfig;
serviceName: string;
adminPullRequestPending$: Observable<PullRequestInfo>;
applications$: Observable<Application[]>;
private markHistoryChange = false;
private readonly PR_OPEN_MESSAGE = 'A pull request is already open';

Expand Down Expand Up @@ -61,6 +63,7 @@ export class AdminComponent implements OnInit, OnDestroy {
}
this.markHistoryChange = false;
});
this.applications$ = this.editorService.configLoader.getApplications();
}

ngOnDestroy() {
Expand Down Expand Up @@ -107,6 +110,10 @@ export class AdminComponent implements OnInit, OnDestroy {
this.form.updateValueAndValidity();
}

openApplicationDialog() {
this.dialog.open(ApplicationDialogComponent, { data: this.applications$});
}

private updateAndWrapConfig(config: AdminConfig) {
//NOTE: in the form we are using wrapping config to handle optionals, unions
const configData = this.editorService.adminSchema.wrapConfig(config.configData);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<h1 mat-dialog-title>Application Manager</h1>
<mat-form-field [ngStyle]="{display: (applications$ | async)?.length > 1 ? 'block' : 'none'}"
class="filter" appearance="standard">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. siembol" #input>
</mat-form-field>
<div class="container">
<table mat-table [dataSource]="dataSource">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<th mat-header-cell *matHeaderCellDef>
{{column.header}}
</th>
<td mat-cell *matCellDef="let row">
{{column.cell(row)}}
</td>
</ng-container>
<ng-container matColumnDef="attributes">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let row">
<button mat-raised-button color="primary" (click)="onViewAttributes(row.attributes[0], attributesViewer)">View attributes</button>
</td>
</ng-container>
<ng-container matColumnDef="restart">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let row">
<button mat-raised-button color="primary" (click)="onRestartApplication(row.topology_name)">Restart</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<div mat-dialog-actions>
<button mat-raised-button class="button-layout" color="accent" (click)="onClickClose()">CLOSE</button>
</div>

<ng-template #attributesViewer let-data>
<div class="attributes">
<re-json-tree
[json]="data"
[prevKey]="'$'"
[copyOnClick]="false"
>
</re-json-tree>
</div>
<div mat-dialog-actions>
<button mat-raised-button class="button-layout" color="accent" (click)="onClickCloseAttributes()">CLOSE</button>
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.container {
font-size: 70%;
display: flex;
justify-content: space-between;
align-items: stretch;
padding: 10px 10px;
padding-right: 30px;
max-width: 70vw;
max-height: 70vh;
overflow-y: auto;
}

.button-layout {
margin-right: 0px;
margin-left: auto;
}

.mat-header-cell, .mat-cell {
padding: 10px;
}

.scrollbar {
--scrollbar-thumb-color: #868686;
--scrollbar-thumb-hover-color: #a1a1a1;
}

.attributes {
max-height: 60vh;
overflow-y: auto;
}

.filter {
width: 100%;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, TemplateRef } from "@angular/core";
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { MatTableDataSource } from "@angular/material/table";
import { Application, applicationManagerColumns, displayedApplicationManagerColumns } from "@app/model/config-model";
import { EditorService } from "@app/services/editor.service";
import { Observable } from "rxjs";

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 're-application-dialog',
styleUrls: ['application-dialog.component.scss'],
templateUrl: 'application-dialog.component.html',
})
export class ApplicationDialogComponent {
dialogrefAttributes: MatDialogRef<any>;
applications$: Observable<Application[]>;
dataSource: MatTableDataSource<Application>;
columns = applicationManagerColumns;
displayedColumns = displayedApplicationManagerColumns;

constructor(
private dialogref: MatDialogRef<ApplicationDialogComponent>,
@Inject(MAT_DIALOG_DATA) private data: Observable<Application[]>,
private service: EditorService,
private dialog: MatDialog,
private cd: ChangeDetectorRef
) {
this.applications$ = data;
this.applications$.subscribe(a => {
this.createTable(a);
})
}

onClickClose() {
this.dialogref.close();
}

onRestartApplication(applicationName: string) {
this.applications$ = this.service.configLoader.restartApplication(applicationName);
this.applications$.subscribe(a => {
this.createTable(a);
})
}

onViewAttributes(attributes: string, templateRef: TemplateRef<any>) {
this.dialogrefAttributes = this.dialog.open(
templateRef,
{
data: JSON.parse(atob(attributes)),
});
}

onClickCloseAttributes() {
this.dialogrefAttributes.close();
}

applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}

private createTable(a: Application[]) {
const filter = this.dataSource?.filter;
this.dataSource = new MatTableDataSource(a);
this.dataSource.filter = filter;
this.cd.markForCheck();
}
}
3 changes: 2 additions & 1 deletion config-editor/config-editor-ui/src/app/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export { DeployDialogComponent } from './deploy-dialog/deploy-dialog.component';
export { ErrorDialogComponent } from './error-dialog/error-dialog.component';
export { LandingPageComponent } from './landing-page/landing-page.component';
export { SearchComponent } from './search/search.component';
export { ImporterDialogComponent } from './importer-dialog/importer-dialog.component';
export { ImporterDialogComponent } from './importer-dialog/importer-dialog.component';
export { ApplicationDialogComponent } from './application-dialog/application-dialog.component';
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ export class JsonTreeComponent implements OnChanges {

private parseKeyValue(key: any, value: any): Segment {
const segment: Segment = {
key: key,
value: value,
key,
value,
type: undefined,
description: '' + value,
expanded: this.expanded,
Expand Down Expand Up @@ -91,12 +91,12 @@ export class JsonTreeComponent implements OnChanges {
segment.description = 'null';
} else if (Array.isArray(segment.value)) {
segment.type = 'array';
segment.description = 'Array[' + segment.value.length + '] ' + JSON.stringify(segment.value);
segment.description = 'Array[' + segment.value.length + '] ';
} else if (segment.value instanceof Date) {
segment.type = 'date';
} else {
segment.type = 'object';
segment.description = 'Object ' + JSON.stringify(segment.value);
segment.description = 'Object ';
}
break;
}
Expand Down Expand Up @@ -124,8 +124,8 @@ export class JsonTreeComponent implements OnChanges {

if (isIndex) {
return part1 + part2;
} else {
}
return part1 + '.' + part2;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,26 @@ <h1>{{serviceName$ | async | titlecase}}</h1><mat-icon>arrow_drop_down</mat-icon
</div>
</div>
<div>
<mat-slide-toggle
class="right-element"
*ngIf="!isHome && userRoles.length > 1"
[(ngModel)]="isAdminChecked"
(change)="onToggleAdmin()"
labelPosition="before"
>
<h3>Admin</h3>
</mat-slide-toggle>
<button
mat-icon-button
class="right-element"
*ngIf="!isHome && (repositoryLinks$ | async)"
[matMenuTriggerFor]="repoMenu"
[matTooltip]="'Repositories'"
>
<mat-icon>book</mat-icon>
</button>
<div *ngIf="!isHome">
<mat-slide-toggle
class="right-element"
*ngIf="userRoles.length > 1"
[(ngModel)]="isAdminChecked"
(change)="onToggleAdmin()"
labelPosition="before"
>
<h3>Admin</h3>
</mat-slide-toggle>
<button
mat-icon-button
class="right-element"
*ngIf="(repositoryLinks$ | async)"
[matMenuTriggerFor]="repoMenu"
[matTooltip]="'Repositories'"
>
<mat-icon>book</mat-icon>
</button>
</div>
<mat-menu #repoMenu="matMenu" >
<a mat-menu-item
[href]="(repositoryLinks$ | async)?.rule_store_directory_url"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Component, OnInit} from '@angular/core';
import { ChangeDetectionStrategy } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnInit} from '@angular/core';
import { AppConfigService } from '@app/services/app-config.service';
import { Observable } from 'rxjs';
import { MatDialog } from '@angular/material/dialog';
Expand All @@ -16,7 +15,7 @@ import { UserRole, RepositoryLinks, repoNames } from '@app/model/config-model';
templateUrl: './nav-bar.component.html',
})
export class NavBarComponent implements OnInit {
user: String;
user: string;
userRoles: string[];
serviceName$: Observable<string>;
serviceName: string;
Expand Down Expand Up @@ -54,19 +53,19 @@ export class NavBarComponent implements OnInit {
});
}

public showAboutApp() {
showAboutApp() {
this.dialog.open(BuildInfoDialogComponent, { data: this.config.buildInfo }).afterClosed().subscribe();
}

public onToggleAdmin() {
let path = this.isAdminChecked ? this.config.adminPath : "";
onToggleAdmin() {
const path = this.isAdminChecked ? this.config.adminPath : "";
this.router.navigate([this.serviceName + path]);
}

public getPath(service: string): string {
getPath(service: string): string {
let path = service;
const roles = this.appService.getUserServiceRoles(service);
let hasMultipleUserRoles = roles.length > 1;
const hasMultipleUserRoles = roles.length > 1;
if ((hasMultipleUserRoles && this.isAdminChecked) || (!hasMultipleUserRoles && roles.includes(UserRole.SERVICE_ADMIN))) {
path += this.config.adminPath;
}
Expand Down
Loading

0 comments on commit 0608d76

Please sign in to comment.