WIP Usermanagement
parent
f98ca428f2
commit
226b4bff2e
@ -1,171 +1,216 @@
|
||||
<mat-spinner
|
||||
*ngIf="isLoading"
|
||||
[diameter]="32"
|
||||
class="page-loading-spinner"
|
||||
></mat-spinner>
|
||||
<div class="page-wrapper" *ngIf="!isLoading && !data">
|
||||
<h1>Seite konnte nicht gefunden werden :(</h1>
|
||||
|
||||
<mat-toolbar color="primary">
|
||||
<span>Admin Table</span>
|
||||
<span class="spacer"></span>
|
||||
Reload data:
|
||||
<button mat-icon-button (click)="refresh()">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
|
||||
<div class="container mat-elevation-z8">
|
||||
|
||||
<div class="form">
|
||||
<mat-form-field floatPlaceholder="never" color="accent">
|
||||
<input matInput #filter placeholder="Filter issues">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="data-page-wrapper" *ngIf="data && !isLoading">
|
||||
<h1 class="headline">
|
||||
{{ getHeadline !== undefined ? getHeadline(data) : data[headlineDataPath] }}
|
||||
<mat-icon>{{ headlineIconName }}</mat-icon>
|
||||
</h1>
|
||||
<ng-container *ngFor="let object of propertiesInfo">
|
||||
<mat-card
|
||||
class="inline-card"
|
||||
*ngIf="
|
||||
object.type === 'Group' &&
|
||||
(!object.hideCondition || !object.hideCondition(data))
|
||||
"
|
||||
>
|
||||
<mat-card-title class="card-header">
|
||||
<h2>{{ object.title }}</h2>
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="data?.isLockedByMe && object.possibleObjects"
|
||||
(click)="openSelectObjectDialog(object)"
|
||||
>
|
||||
<mat-icon>expand_more</mat-icon>
|
||||
<mat-table #table [dataSource]="dataSource" matSort class="mat-cell">
|
||||
|
||||
<!-- normal shit -->
|
||||
<ng-container matColumnDef="name">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" >{{row.name}}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="email">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>E-Mail</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row"> {{row.email}}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="password">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Passwort</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row"> {{row.password}}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="roles">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Rollen</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row"> {{row.roles}}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- actions -->
|
||||
<ng-container matColumnDef="actions">
|
||||
<mat-header-cell *matHeaderCellDef>
|
||||
<button mat-icon-button color="primary" (click)="addNew()">
|
||||
<mat-icon aria-label="Example icon-button with a heart icon">add</mat-icon>
|
||||
</button>
|
||||
</mat-card-title>
|
||||
<ng-container *ngFor="let prop of object.properties">
|
||||
<app-cell
|
||||
*ngIf="
|
||||
prop.type !== 'NumRange' &&
|
||||
prop.type !== 'Link' &&
|
||||
prop.type !== 'DateRange'
|
||||
"
|
||||
[isList]="prop.list"
|
||||
[editable]="data?.isLockedByMe && prop.acceptedForUpdating"
|
||||
[required]="prop.requiredForUpdating && data?.isLockedByMe"
|
||||
(validityChange)="validityChange(prop.dataPath, $event)"
|
||||
[(value)]="data[prop.dataPath]"
|
||||
[label]="prop.translation || prop.dataPath"
|
||||
[inputType]="prop.type"
|
||||
></app-cell>
|
||||
<app-number-range-cell
|
||||
*ngIf="prop.type === 'NumRange'"
|
||||
[editable]="data?.isLockedByMe && prop.acceptedForUpdating"
|
||||
(validityChange)="validityChange(prop.dataPath, $event)"
|
||||
[(min)]="data[prop.dataPath + '.min']"
|
||||
[(max)]="data[prop.dataPath + '.max']"
|
||||
[label]="prop.translation || prop.dataPath"
|
||||
></app-number-range-cell>
|
||||
<app-date-range-cell
|
||||
*ngIf="prop.type === 'DateRange'"
|
||||
[editable]="data?.isLockedByMe && prop.acceptedForUpdating"
|
||||
[required]="prop.requiredForUpdating && data?.isLockedByMe"
|
||||
(validityChange)="validityChange(prop.dataPath, $event)"
|
||||
[(from)]="data[prop.dataPath + '.from']"
|
||||
[(to)]="data[prop.dataPath + '.to']"
|
||||
></app-date-range-cell>
|
||||
<a
|
||||
mat-button
|
||||
class="link-button"
|
||||
color="primary"
|
||||
*ngIf="prop.type === 'Link'"
|
||||
[routerLink]="prop.link(data)"
|
||||
>{{ prop.linkText }}
|
||||
</a>
|
||||
</mat-header-cell>
|
||||
|
||||
<mat-cell *matCellDef="let row; let i=index;">
|
||||
<button mat-icon-button color="accent" (click)="startEdit(row)">
|
||||
<mat-icon aria-label="Edit">edit</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button color="accent" (click)="deleteItem(i, row.id, row.title, row.state, row.url)">
|
||||
<mat-icon aria-label="Delete">delete</mat-icon>
|
||||
</button>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
</mat-card>
|
||||
|
||||
<mat-card
|
||||
class="inline-card"
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
||||
</mat-table>
|
||||
<mat-paginator #paginator
|
||||
[length]="dataSource.filteredData.length"
|
||||
[pageIndex]="0"
|
||||
[pageSize]="10"
|
||||
[pageSizeOptions]="[5, 10, 25, 100]">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
|
||||
|
||||
<!--<div *ngIf="dataLoaded">
|
||||
<app-editable-table
|
||||
[columns]="['name','email','password', 'Actions']"
|
||||
[editableColumns] = "['name', 'email', 'password']"
|
||||
[dateColumns] ="[]"
|
||||
[data]="tableData"
|
||||
[pageSizeOptions]="[5,20,50,100]"
|
||||
[searchable]="true"
|
||||
(action)="action($event)"
|
||||
[notification]="yourMessage"
|
||||
[maxChar]="23">
|
||||
</app-editable-table>
|
||||
</div>-->
|
||||
|
||||
|
||||
|
||||
<!--<div style="overflow: auto;" *ngIf="dataLoaded">
|
||||
<table mat-table [dataSource]="dataSource" matSort class="example-container">
|
||||
Checkbox Column
|
||||
<ng-container matColumnDef="select" sticky>
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox
|
||||
(change)="$event ? masterToggle() : null"
|
||||
[checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</th>
|
||||
<td
|
||||
mat-cell
|
||||
*matCellDef="let element"
|
||||
[ngClass]="{ 'highlighted-column': column.highlighted }"
|
||||
>
|
||||
<ng-container
|
||||
*ngIf="
|
||||
object.type === 'ReferenceTable' &&
|
||||
(!object.hideCondition || !object.hideCondition(data))
|
||||
column.type !== 'DateRange' &&
|
||||
column.type !== 'NumRange' &&
|
||||
column.possibleObjects === undefined
|
||||
"
|
||||
>
|
||||
<mat-card-title
|
||||
><h2>{{ object.title }}</h2>
|
||||
<app-cell
|
||||
[editable]="
|
||||
(element.newObject && column.acceptedForCreation) ||
|
||||
(column.acceptedForUpdating && element.isLockedByMe)
|
||||
"
|
||||
[required]="true"
|
||||
(validityChange)="
|
||||
validityChange(element, column.dataPath, $event)
|
||||
"
|
||||
[(value)]="element[column.dataPath]"
|
||||
[isList]="false"
|
||||
[inputType]="column.type"
|
||||
[link]="column.link ? column.link(element) : null"
|
||||
></app-cell>
|
||||
<ng-template #stringValue>
|
||||
<span *ngIf="!column.link">{{ element[column.dataPath] }}</span>
|
||||
<a
|
||||
mat-button
|
||||
*ngIf="object.linkToTable"
|
||||
color="primary"
|
||||
[routerLink]="object.linkToTable(data)"
|
||||
[queryParams]="
|
||||
object.linkToTableParams ? object.linkToTableParams(data) : {}
|
||||
"
|
||||
matTooltip="Zur Tabelle"
|
||||
*ngIf="column.link"
|
||||
[routerLink]="column.link(element)"
|
||||
>{{ element[column.dataPath] }}</a
|
||||
>
|
||||
<mat-icon>subdirectory_arrow_right</mat-icon>
|
||||
<mat-icon>table_chart</mat-icon>
|
||||
</a>
|
||||
</mat-card-title>
|
||||
<app-reference-table
|
||||
[dataServiceThatProvidesThePossibleData]="object.dataService"
|
||||
[nameToShowInSelection]="object.nameToShowInSelection"
|
||||
[columnInfo]="object.columnInfo"
|
||||
[data]="data[object.dataPath]"
|
||||
[editable]="data?.isLockedByMe"
|
||||
[tableDataGQLType]="object.tableDataGQLType"
|
||||
(referenceIds)="addReferenceIdsToObject($event, object)"
|
||||
[editableReferences]="object.editableReferences"
|
||||
></app-reference-table>
|
||||
</mat-card>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngFor="let column of columnInfo"
|
||||
[matColumnDef]="column.def"
|
||||
[sticky]="isStickyColumn(column.dataPath)"
|
||||
><th mat-header-cell *matHeaderCellDef>
|
||||
</th>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="operations" stickyEnd>
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<button
|
||||
mat-mini-fab
|
||||
(click)="reloadPageData()"
|
||||
class="floating-fab-button-top"
|
||||
[disabled]="isSavingOrLocking || isLoading"
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
matTooltip="Daten aktualisieren. Achtung! Alle ungespeicherten Änderungen gehen verloren."
|
||||
aria-label="Example icon button with a home icon"
|
||||
(click)="edit(element)"
|
||||
>
|
||||
<mat-icon>sync</mat-icon>
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
|
||||
<div id="floating-fab-button-box">
|
||||
<button
|
||||
mat-fab
|
||||
(click)="lock()"
|
||||
*ngIf="!data?.isLockedByMe && !data?.isLocked"
|
||||
class="floating-fab-button"
|
||||
color="primary"
|
||||
[disabled]="isSavingOrLocking || isLoading"
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
aria-label="Example icon button with a menu icon"
|
||||
(click)="delete(element)"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</td></ng-container
|
||||
>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<mat-card
|
||||
*ngIf="isLoading"
|
||||
style="display: flex; justify-content: center; align-items: center"
|
||||
>
|
||||
<mat-progress-spinner color="primary" mode="indeterminate">
|
||||
</mat-progress-spinner>
|
||||
</mat-card>
|
||||
|
||||
<div class="button-container-explorer">
|
||||
<button
|
||||
mat-mini-fab
|
||||
(click)="cancel()"
|
||||
*ngIf="data?.isLockedByMe"
|
||||
class="floating-fab-button"
|
||||
[disabled]="isSavingOrLocking || isLoading"
|
||||
mat-raised-button
|
||||
class="button-actions"
|
||||
color="primary"
|
||||
(click)="export()"
|
||||
>
|
||||
<mat-icon>cancel</mat-icon>
|
||||
Export
|
||||
</button>
|
||||
<div
|
||||
*ngIf="data?.isLockedByMe"
|
||||
[matTooltip]="
|
||||
countUnvalidProperties() > 0
|
||||
? 'Ungültige oder nicht ausgefüllte Pflichtfelder (rot): ' +
|
||||
countUnvalidProperties()
|
||||
: 'Abspeichern'
|
||||
"
|
||||
>
|
||||
<button
|
||||
mat-fab
|
||||
(click)="save()"
|
||||
class="floating-fab-button"
|
||||
[disabled]="
|
||||
isSavingOrLocking || isLoading || countUnvalidProperties() > 0
|
||||
"
|
||||
mat-raised-button
|
||||
class="button-actions"
|
||||
color="warn"
|
||||
(click)="deleteArray()"
|
||||
>
|
||||
<mat-icon>save</mat-icon>
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<a routerLink="/create/C_APPLICATION_COMPONENT">
|
||||
<button
|
||||
mat-fab
|
||||
*ngIf="data?.isLocked"
|
||||
matTooltip="Dieser Eintrag wird gerade von einem anderen Bearbeiter editiert. Aktualisieren Sie die Seite, um den neuen Status abzurufen."
|
||||
class="floating-fab-button"
|
||||
mat-raised-button
|
||||
class="button-actions"
|
||||
color="accent"
|
||||
>
|
||||
<mat-icon>locked</mat-icon>
|
||||
Neue Applikations-Komponente
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
using .csv only works with csv specifically, google other types if needed
|
||||
<input hidden (change)="onFileSelected()" #fileInput type="file" accept=".csv" id="file">
|
||||
<button class="button-actions" color="primary" type="button" mat-raised-button (click)="fileInput.click()">Importieren</button>
|
||||
|
||||
|
||||
</div> -->
|
||||
|
@ -1,246 +1,187 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { deepen } from '../../helperFunctions/deepenObject';
|
||||
import { flatten } from '../../helperFunctions/flattenObject';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
import { SelectObjectDialogComponent } from '../select-object-dialog/select-object-dialog.component';
|
||||
|
||||
interface PropertyTypeInfo {
|
||||
dataPath: string;
|
||||
translation: string;
|
||||
acceptedForUpdating?: boolean;
|
||||
requiredForUpdating?: boolean;
|
||||
required?: boolean;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
interface PropertyGroupInfo {
|
||||
type: string;
|
||||
title: string;
|
||||
properties: PropertyTypeInfo[];
|
||||
}
|
||||
interface ReferenceTableInfo {
|
||||
type: string;
|
||||
title: string;
|
||||
dataPath: string;
|
||||
dataService: any;
|
||||
columnInfo: PropertyTypeInfo[];
|
||||
nameToShowInSelection: any;
|
||||
propertyNameOfUpdateInput: string;
|
||||
referenceIds: Array<string>;
|
||||
}
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { fromEvent } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { User } from '../../models/user';
|
||||
import {UserService} from '../../services/user.service';
|
||||
import {DeleteDialogComponent} from '../../components/dialogs/delete/delete.dialog.component';
|
||||
import {AddDialogComponent} from '../../components/dialogs/add/add.dialog.component';
|
||||
import {EditDialogComponent} from '../../components/dialogs/edit/edit.dialog.component';
|
||||
|
||||
import {deepCopy} from '../../helperFunctions/deepCopy';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-data-page',
|
||||
templateUrl: './admin-data-page.component.html',
|
||||
styleUrls: ['./admindata-page.component.scss'],
|
||||
styleUrls: ['./admin-data-page.component.scss'],
|
||||
})
|
||||
export class DataPageComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
propertiesInfo: Array<any> = [];
|
||||
|
||||
@Input()
|
||||
dataService: any;
|
||||
|
||||
/** specifies which property should be shown in the headline */
|
||||
@Input()
|
||||
headlineDataPath: string;
|
||||
/** specifies which string should be shown in the headline. If this is provided headlineDataPath is ignored*/
|
||||
@Input()
|
||||
getHeadline: (any) => string;
|
||||
@Input()
|
||||
headlineIconName: string = 'help_outline';
|
||||
@Input()
|
||||
pageDataGQLType: string;
|
||||
@Input()
|
||||
pageDataGQLUpdateInputType: string;
|
||||
@Input()
|
||||
propertyNameOfUpdateInput: string;
|
||||
|
||||
relockingInterval = null;
|
||||
@Input()
|
||||
relockingIntervalDuration = 1000 * 60 * 1;
|
||||
|
||||
@Output() lockEvent = new EventEmitter();
|
||||
@Output() saveEvent = new EventEmitter();
|
||||
@Output() cancelEvent = new EventEmitter();
|
||||
|
||||
id: string;
|
||||
data: any = null;
|
||||
isLoading: boolean = false;
|
||||
isSavingOrLocking: boolean = false;
|
||||
|
||||
propertyValidity = {};
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private schemaService: SchemaService,
|
||||
public dialog: MatDialog
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.addPropertiesFromGQLSchemaToObject(this.propertiesInfo);
|
||||
this.id = this.route.snapshot.paramMap.get('id');
|
||||
this.reloadPageData();
|
||||
this.dataService.pageData.subscribe((data) => {
|
||||
if (data == null) {
|
||||
this.data = null;
|
||||
} else if (this.data?.isLockedByMe && data?.isLockedByMe) {
|
||||
// dont overwrite data when in edit mode and relock is performed
|
||||
return;
|
||||
} else {
|
||||
this.data = flatten(data);
|
||||
export class AdminDataPageComponent implements OnInit {
|
||||
|
||||
|
||||
displayedColumns = ['name', 'email', 'password', 'roles', 'actions'];
|
||||
dataSource : MatTableDataSource<User>;
|
||||
index: number;
|
||||
id: number;
|
||||
|
||||
constructor(public httpClient: HttpClient,
|
||||
public dialog: MatDialog,
|
||||
private userService: UserService) {}
|
||||
|
||||
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
|
||||
@ViewChild(MatSort, {static: true}) sort: MatSort;
|
||||
@ViewChild('filter', {static: true}) filter: ElementRef;
|
||||
|
||||
ngOnInit() {
|
||||
this.loadData();
|
||||
}
|
||||
});
|
||||
this.dataService.isLoadingPageData.subscribe(
|
||||
(isLoading) => (this.isLoading = isLoading)
|
||||
);
|
||||
this.dataService.loadingRowIds.subscribe((loadingRowIds) => {
|
||||
this.isSavingOrLocking = loadingRowIds.includes(this.id);
|
||||
|
||||
refresh() {
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
|
||||
addNew() {
|
||||
const dialogRef = this.dialog.open(AddDialogComponent, {
|
||||
data: {user: User }
|
||||
});
|
||||
|
||||
this.relockingInterval = setInterval(() => {
|
||||
if (this.data?.isLockedByMe) {
|
||||
this.lock();
|
||||
}
|
||||
}, this.relockingIntervalDuration);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
clearInterval(this.relockingInterval);
|
||||
}
|
||||
|
||||
addPropertiesFromGQLSchemaToObject(infoObject: any) {
|
||||
for (const prop of infoObject) {
|
||||
if (prop.type === 'Link') {
|
||||
continue;
|
||||
}
|
||||
if (prop.type === 'Group') {
|
||||
this.addPropertiesFromGQLSchemaToObject(prop.properties);
|
||||
} else if (prop.type === 'ReferenceTable') {
|
||||
prop.tableDataGQLType =
|
||||
prop.tableDataGQLType ||
|
||||
this.schemaService.getTypeInformation(
|
||||
this.pageDataGQLType,
|
||||
prop.dataPath
|
||||
).type;
|
||||
if (!prop.type) {
|
||||
console.error(
|
||||
"Didn't found type for: " +
|
||||
prop.dataPath +
|
||||
' on ' +
|
||||
this.pageDataGQLType
|
||||
);
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result === 1) {
|
||||
|
||||
|
||||
this.dataSource.data.push(this.userService.getDialogData());
|
||||
|
||||
this.refreshTable();
|
||||
}
|
||||
prop.referenceIds = [];
|
||||
} else {
|
||||
const typeInformation = this.schemaService.getTypeInformation(
|
||||
this.pageDataGQLType,
|
||||
prop.dataPath
|
||||
);
|
||||
prop.type = prop.type || typeInformation.type;
|
||||
prop.list = typeInformation.isList;
|
||||
if (!prop.type) {
|
||||
console.error(
|
||||
"Didn't found type for: " +
|
||||
prop.dataPath +
|
||||
' on ' +
|
||||
this.pageDataGQLType
|
||||
);
|
||||
});
|
||||
}
|
||||
prop.required =
|
||||
prop.required != null ? prop.required : typeInformation.isRequired;
|
||||
|
||||
const updateTypeInformation = this.schemaService.getTypeInformation(
|
||||
this.pageDataGQLUpdateInputType,
|
||||
prop.dataPath
|
||||
);
|
||||
prop.acceptedForUpdating =
|
||||
prop.acceptedForUpdating != null
|
||||
? prop.acceptedForUpdating
|
||||
: updateTypeInformation.isPartOfType;
|
||||
startEdit(user : User) {
|
||||
const dialogRef = this.dialog.open(EditDialogComponent, {
|
||||
data: deepCopy(user)
|
||||
});
|
||||
|
||||
prop.requiredForUpdating =
|
||||
prop.requiredForUpdating != null
|
||||
? prop.requiredForUpdating
|
||||
: prop.required || typeInformation.isRequired;
|
||||
}
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result === 1) {
|
||||
console.log("editing done");
|
||||
|
||||
const foundIndex = this.dataSource.data.findIndex(x => x.email === this.userService.getDialogData().email);
|
||||
|
||||
this.dataSource.data[foundIndex] = this.userService.getDialogData();
|
||||
|
||||
this.refreshTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
lock() {
|
||||
this.lockEvent.emit(deepen(this.data));
|
||||
deleteItem(i: number, id: number, title: string, state: string, url: string) {
|
||||
this.index = i;
|
||||
this.id = id;
|
||||
const dialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: {id: id, title: title, state: state, url: url}
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result === 1) {
|
||||
const foundIndex = this.dataSource.data.findIndex(x => x.id === this.id);
|
||||
|
||||
this.dataSource.data.splice(foundIndex, 1);
|
||||
this.refreshTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
validityChange(propName: string, isValid: Event) {
|
||||
this.propertyValidity[propName] = isValid;
|
||||
|
||||
private refreshTable() {
|
||||
//this.paginator._changePageSize(this.paginator.pageSize);
|
||||
this.dataSource._updateChangeSubscription();
|
||||
}
|
||||
|
||||
countUnvalidProperties() {
|
||||
let unvalidFieldsCount = 0;
|
||||
for (const prop in this.propertyValidity) {
|
||||
if (!this.propertyValidity[prop]) {
|
||||
unvalidFieldsCount++;
|
||||
public loadData() {
|
||||
this.userService.getAllUsers().pipe(first()).subscribe((data: User[]) => {
|
||||
this.dataSource = new MatTableDataSource(data);
|
||||
});
|
||||
fromEvent(this.filter.nativeElement, 'keyup')
|
||||
// .debounceTime(150)
|
||||
// .distinctUntilChanged()
|
||||
.subscribe(() => {
|
||||
if (!this.dataSource) {
|
||||
return;
|
||||
}
|
||||
this.dataSource.filter = this.filter.nativeElement.value;
|
||||
});
|
||||
}
|
||||
return unvalidFieldsCount;
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
|
||||
save() {
|
||||
this.saveEvent.emit(
|
||||
this.schemaService.filterObject(
|
||||
this.pageDataGQLUpdateInputType,
|
||||
deepen(this.data)
|
||||
)
|
||||
);
|
||||
orderData(id: string, start?: "asc" | "desc") {
|
||||
const matSort = this.dataSource.sort;
|
||||
const disableClear = false;
|
||||
|
||||
matSort.sort({ id: null, start, disableClear });
|
||||
matSort.sort({ id, start, disableClear });
|
||||
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.cancelEvent.emit(deepen(this.data));
|
||||
|
||||
private load() {
|
||||
console.log("trying to load");
|
||||
|
||||
}
|
||||
|
||||
openSelectObjectDialog(object: any) {
|
||||
const dialogRef = this.dialog.open(SelectObjectDialogComponent, {
|
||||
width: 'auto',
|
||||
autoFocus: false,
|
||||
data: {
|
||||
nameToShowInSelection: object.nameToShowInSelection,
|
||||
currentlySelectedObjectId: object.currentlySelectedObjectId(this.data),
|
||||
possibleObjects: object.possibleObjects,
|
||||
delete(user: User) {
|
||||
let ownPassword : string;
|
||||
this.userService.deleteUser(user.email, ownPassword)
|
||||
.pipe(first())
|
||||
.subscribe(
|
||||
data => {
|
||||
//this.loadAllObjects();
|
||||
},
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((selectedObject) => {
|
||||
if (selectedObject) {
|
||||
this.data[object.propertyNameOfReferenceId] = selectedObject.id;
|
||||
const newObjectFlattened = flatten(selectedObject);
|
||||
for (const newProperty in newObjectFlattened) {
|
||||
this.data[object.propertyPrefixToOverwrite + '.' + newProperty] =
|
||||
newObjectFlattened[newProperty];
|
||||
}
|
||||
} else if (selectedObject === null) {
|
||||
this.data[object.propertyNameOfReferenceId] = null;
|
||||
for (const prop in this.data) {
|
||||
if (prop.startsWith(object.propertyPrefixToOverwrite)) {
|
||||
this.data[prop] = null;
|
||||
error => {
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
edit(user: User) {
|
||||
let ownPassword : string;
|
||||
this.userService.updateUser(user, ownPassword)
|
||||
.pipe(first())
|
||||
.subscribe(
|
||||
data => {
|
||||
//this.loadAllObjects();
|
||||
},
|
||||
error => {
|
||||
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
addReferenceIdsToObject(ids: string[], object) {
|
||||
this.data[object.propertyNameOfUpdateInput] = ids;
|
||||
/*findActualData(_id: string) {
|
||||
for (let data of this.actualData) {
|
||||
if (data._id === _id) {
|
||||
return data;
|
||||
}
|
||||
|
||||
reloadPageData() {
|
||||
this.dataService.loadPageData({ id: this.id });
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {UserService} from '../../../services/user.service';
|
||||
import {FormControl, Validators} from '@angular/forms';
|
||||
import {User} from '../../../models/user';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add.dialog',
|
||||
templateUrl: '../../dialogs/add/add.dialog.html',
|
||||
styleUrls: ['../../dialogs/add/add.dialog.css']
|
||||
})
|
||||
|
||||
export class AddDialogComponent {
|
||||
constructor(public dialogRef: MatDialogRef<AddDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: User,
|
||||
public userService: UserService) { }
|
||||
|
||||
formControl = new FormControl('', [
|
||||
Validators.required
|
||||
// Validators.email,
|
||||
]);
|
||||
|
||||
getErrorMessage() {
|
||||
return this.formControl.hasError('required') ? 'Required field' :
|
||||
this.formControl.hasError('email') ? 'Not a valid email' :
|
||||
'';
|
||||
}
|
||||
|
||||
submit() {
|
||||
// emppty stuff
|
||||
}
|
||||
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
public confirmAdd(): void {
|
||||
this.userService.addUser(this.data);
|
||||
//this.dataService.addIssue(this.data);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 450px;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
font-size: 16px;
|
||||
flex-grow: 1;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<div class="container">
|
||||
<h3 mat-dialog-title>Add new Issue</h3>
|
||||
|
||||
<form class="mat-dialog-content" (ngSubmit)="submit" #formControl="ngForm">
|
||||
|
||||
<div class="form">
|
||||
<mat-form-field color="accent">
|
||||
<input matInput #input class="form-control" placeholder="Name" [(ngModel)]="data.name" name="name" required >
|
||||
<mat-error *ngIf="formControl.invalid">{{getErrorMessage()}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<mat-form-field color="accent">
|
||||
<input matInput #input class="form-control" placeholder="E-Mail" [(ngModel)]="data.email" name="email" required >
|
||||
<mat-error *ngIf="formControl.invalid">{{getErrorMessage()}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<mat-form-field color="accent">
|
||||
<input matInput placeholder="Passwort" [(ngModel)]="data.password" name="password">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button [type]="submit" [disabled]="!formControl.valid" [mat-dialog-close]="1" (click)="confirmAdd()">Save</button>
|
||||
<button mat-button (click)="onNoClick()" tabindex="-1">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -0,0 +1,24 @@
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {UserService} from '../../../services/user.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-delete.dialog',
|
||||
templateUrl: '../../dialogs/delete/delete.dialog.html',
|
||||
styleUrls: ['../../dialogs/delete/delete.dialog.css']
|
||||
})
|
||||
export class DeleteDialogComponent {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<DeleteDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any, public userService: UserService) { }
|
||||
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
confirmDelete(): void {
|
||||
this.userService.deleteUser(this.data.mail, this.data.ownPassword);
|
||||
//this.dataService.deleteIssue(this.data.id);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
width: 100%;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<div class="container">
|
||||
<h3 mat-dialog-title>Are you sure?</h3>
|
||||
<div mat-dialog-content>
|
||||
Name: {{data.name}}
|
||||
<p></p>
|
||||
E-Mail: {{data.email}}
|
||||
<p></p>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button [mat-dialog-close]="1" (click)="confirmDelete()">Delete</button>
|
||||
<button mat-button (click)="onNoClick()" tabindex="-1">Cancel</button>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,53 @@
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {UserService} from '../../../services/user.service';
|
||||
import {FormControl, Validators} from '@angular/forms';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { SnackBarService } from 'src/app/services/snackbar.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-baza.dialog',
|
||||
templateUrl: '../../dialogs/edit/edit.dialog.html',
|
||||
styleUrls: ['../../dialogs/edit/edit.dialog.css']
|
||||
})
|
||||
export class EditDialogComponent {
|
||||
|
||||
hide = true;
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<EditDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any, public userService: UserService, public snackbarService : SnackBarService) { }
|
||||
|
||||
formControl = new FormControl('', [
|
||||
Validators.required
|
||||
// Validators.email,
|
||||
]);
|
||||
|
||||
getErrorMessage() {
|
||||
return this.formControl.hasError('required') ? 'Required field' :
|
||||
this.formControl.hasError('email') ? 'Not a valid email' :
|
||||
'';
|
||||
}
|
||||
|
||||
submit() {
|
||||
// emppty stuff
|
||||
}
|
||||
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
stopEdit(): void {
|
||||
this.data.roles = [];
|
||||
this.userService.updateUser(this.data).pipe(first())
|
||||
.subscribe(
|
||||
data => {
|
||||
this.snackbarService.openSnackBar("Der Nutzer wurde erfolgreich verändert!");
|
||||
//this.loadAllObjects();
|
||||
},
|
||||
error => {
|
||||
console.log("Eroor while editing: " + JSON.stringify(error));
|
||||
this.snackbarService.openSnackBar(error, "Ok", true);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 450px;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
font-size: 16px;
|
||||
flex-grow: 1;
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
<div class="container">
|
||||
<h3 mat-dialog-title>Issue id: {{data.id}}</h3>
|
||||
|
||||
<form class="mat-dialog-content" (ngSubmit)="submit" #formControl="ngForm">
|
||||
|
||||
<div class="form">
|
||||
<mat-form-field color="accent">
|
||||
<input matInput #input class="form-control" placeholder="Name" [(ngModel)]="data.name" name="name" required >
|
||||
<mat-error *ngIf="formControl.invalid">{{getErrorMessage()}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<mat-form-field color="accent">
|
||||
<input matInput #input class="form-control" placeholder="E-Mail" [(ngModel)]="data.email" name="email" required >
|
||||
<mat-error *ngIf="formControl.invalid">{{getErrorMessage()}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<mat-form-field color="accent">
|
||||
<input matInput placeholder="Passwort" [(ngModel)]="data.password" name="password">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form">
|
||||
<mat-form-field>
|
||||
<mat-label>Eigenes Passwort</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[type]="hide ? 'password' : 'text'"
|
||||
name="ownPassword"
|
||||
[(ngModel)]="data.own_password"
|
||||
/>
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
(click)="hide = !hide"
|
||||
[attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide"
|
||||
>
|
||||
<mat-icon>{{ hide ? "visibility_off" : "visibility" }}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button [type]="submit" [disabled]="!formControl.valid" [mat-dialog-close]="1" (click)="stopEdit()">Save</button>
|
||||
<button mat-button (click)="onNoClick()" tabindex="-1">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -0,0 +1,9 @@
|
||||
<mat-form-field>
|
||||
<mat-label>
|
||||
{{label}}
|
||||
</mat-label>
|
||||
<mat-select [ngModel]="selectedOptions" (ngModelChange)="selectedOptions" [formControl]="formCtrl" [multiple]="multiple">
|
||||
<mat-select-search [formControl]="searchCtrl"></mat-select-search>
|
||||
<mat-option *ngFor="let risk of filteredInterfacesBMulti | async" [value]="risk">{{risk.NAME}}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
@ -0,0 +1,40 @@
|
||||
.mat-stepper-horizontal {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
|
||||
.right-align {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
input.right-align::-webkit-outer-spin-button,
|
||||
input.right-align::-webkit-inner-spin-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input.right-align {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.form-field-less-top-margin{
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.anti-margin{
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.mat-form-field{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,134 @@
|
||||
import { Component, OnInit, OnDestroy, Input, OnChanges, SimpleChanges } from "@angular/core";
|
||||
import { Subscription, ReplaySubject, Subject } from "rxjs";
|
||||
import { FormGroup, FormControl, FormBuilder } from '@angular/forms';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
|
||||
@Component({ selector: "select-search", templateUrl: "form-select-search.component.html", styleUrls: ["./form-select-search.component.scss"] })
|
||||
export class FormSelectSearchComponent implements OnInit, OnDestroy, OnChanges {
|
||||
|
||||
|
||||
//@Input() group: FormGroup;
|
||||
//@Input() controlName: string;
|
||||
@Input() formCtrl: FormControl;
|
||||
|
||||
@Input() data: any[];
|
||||
@Input() preSelectedData: any[];
|
||||
@Input() label: string;
|
||||
@Input() multiple: boolean;
|
||||
|
||||
selectedOptions: any[] = [];
|
||||
|
||||
public filteredInterfacesBMulti: ReplaySubject<any[]> = new ReplaySubject<any[]>(1);
|
||||
|
||||
|
||||
public searchCtrl: FormControl = new FormControl();
|
||||
|
||||
|
||||
constructor(private _formBuilder: FormBuilder) {
|
||||
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
// only run when property "data" changed
|
||||
|
||||
if (changes['data']) {
|
||||
|
||||
if (this.preSelectedData !== undefined){
|
||||
//console.log( this.label + " is not undefined :D");
|
||||
//console.log(this.label + " preselected: " + this.preSelectedData);
|
||||
//console.log(JSON.stringify(this.preSelectedData))
|
||||
this.riskListGeneratorB(this.preSelectedData);
|
||||
console.log(this.label + " selected options: "+ JSON.stringify(this.selectedOptions) + " all options: " + JSON.stringify(this.data));
|
||||
}
|
||||
|
||||
//this.listenInterfacesSearchable();
|
||||
this.filterInterfacesBMulti();
|
||||
}
|
||||
if (changes['preSelectedData']) {
|
||||
|
||||
if (this.preSelectedData !== undefined){
|
||||
/*console.log(this.label + " preselect data change");
|
||||
console.log(this.label + " preselected: " + this.preSelectedData);
|
||||
console.log(JSON.stringify(this.preSelectedData))*/
|
||||
this.riskListGeneratorB(this.preSelectedData);
|
||||
console.log(this.label + " selected options: "+ JSON.stringify(this.selectedOptions) + " all options: " + JSON.stringify(this.data));
|
||||
}
|
||||
|
||||
//this.listenInterfacesSearchable();
|
||||
this.filterInterfacesBMulti();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
//this.group.addControl('searchCtrl', this.searchCtrl);
|
||||
//this.formCtrl = this.group[this.controlName];
|
||||
if (this.preSelectedData !== undefined){
|
||||
/*console.log("preselected is not undefined :D");
|
||||
console.log("preselected: " + this.preSelectedData);*/
|
||||
this.riskListGeneratorB(this.preSelectedData);
|
||||
console.log("selected options: "+ JSON.stringify(this.selectedOptions) + " all options: " + JSON.stringify(this.data));
|
||||
}
|
||||
|
||||
this.listenInterfacesSearchable();
|
||||
}
|
||||
|
||||
private listenInterfacesSearchable(){
|
||||
this.filteredInterfacesBMulti.next(this.data.slice());
|
||||
|
||||
this.searchCtrl.valueChanges
|
||||
.pipe(takeUntil(this._onDestroy))
|
||||
.subscribe(() => {
|
||||
this.filterInterfacesBMulti();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private _onDestroy = new Subject<void>();
|
||||
|
||||
ngOnDestroy() {
|
||||
this._onDestroy.next();
|
||||
this._onDestroy.complete();
|
||||
}
|
||||
|
||||
|
||||
private filterInterfacesBMulti() {
|
||||
if (!this.data) {
|
||||
return;
|
||||
}
|
||||
// get the search keyword
|
||||
let search = this.searchCtrl.value;
|
||||
if (!search) {
|
||||
this.filteredInterfacesBMulti.next(this.data.slice());
|
||||
return;
|
||||
} else {
|
||||
search = search.toLowerCase();
|
||||
}
|
||||
// filter the banks
|
||||
this.filteredInterfacesBMulti.next(
|
||||
this.data.filter(interf => interf.NAME.toLowerCase().indexOf(search) > -1)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private riskListGeneratorB(risks: any[]) {
|
||||
for (let risk of risks) {
|
||||
for (let riskItem of this.data) {
|
||||
if (risk._id === riskItem._id) {
|
||||
console.log(this.label + " added id actual data: " + risk._id + " id background data: " + riskItem._id);
|
||||
if (this.multiple === undefined){
|
||||
this.selectedOptions = riskItem;
|
||||
console.log("set instead of add");
|
||||
} else if (this.selectedOptions.find(e => e._id === risk._id) == undefined){ // only add it to the list if its not added already
|
||||
this.selectedOptions.push(riskItem);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue