Skip to content

Commit

Permalink
Feat/729 refactor settings releases (#733)
Browse files Browse the repository at this point in the history
* refactor: settings release component
  • Loading branch information
StephGit committed Feb 6, 2024
1 parent 7f146f9 commit 6549fa5
Show file tree
Hide file tree
Showing 45 changed files with 1,267 additions and 514 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Observable } from 'rxjs';
import { AuditLogEntry } from '../auditview-entry';
import { AuditviewTableService } from './auditview-table.service';
import { SortableHeader, SortEvent } from './sortable.directive';
import { DATE_FORMAT } from '../../core/amw-constants';
import { DATE_TIME_FORMAT } from '../../core/amw-constants';
import { NewlineFilterPipe } from './newlineFilterPipe';
import { NgbHighlight } from '@ng-bootstrap/ng-bootstrap';
import { AsyncPipe, DatePipe, NgFor } from '@angular/common';
Expand All @@ -22,7 +22,7 @@ export class AuditviewTableComponent implements OnChanges {

auditlogEntries$: Observable<AuditLogEntry[]>;
@ViewChildren(SortableHeader) headers: QueryList<SortableHeader>;
dateFormat = DATE_FORMAT;
dateFormat = DATE_TIME_FORMAT;

constructor(public service: AuditviewTableService) {
this.auditlogEntries$ = service.result$;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { debounceTime, map, tap } from 'rxjs/operators';
import { DatePipe } from '@angular/common';
import { AuditLogEntry } from '../auditview-entry';
import { SortDirection } from './sortable.directive';
import { DATE_FORMAT } from '../../core/amw-constants';
import { DATE_TIME_FORMAT } from '../../core/amw-constants';

interface State {
searchTerm: string;
Expand All @@ -26,7 +26,7 @@ function sort(entries: AuditLogEntry[], column: string, direction: string): Audi
function matches(entry: AuditLogEntry, term: string, pipe: DatePipe): boolean {
const lowerCaseTerm = term.toLowerCase();
return (
pipe.transform(entry.timestamp, DATE_FORMAT).includes(term) ||
pipe.transform(entry.timestamp, DATE_TIME_FORMAT).includes(term) ||
nullSafeToLowerCase(entry.mode).includes(lowerCaseTerm) ||
nullSafeToLowerCase(entry.editContextName).includes(lowerCaseTerm) ||
nullSafeToLowerCase(entry.name).includes(lowerCaseTerm) ||
Expand Down
49 changes: 49 additions & 0 deletions AMW_angular/io/src/app/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Injectable } from '@angular/core';
import { BaseService } from '../base/base.service';
import { HttpClient } from '@angular/common/http';
import { filter, Observable, Subject } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Restriction } from '../settings/permission/restriction';
import { Release } from '../settings/releases/release';

@Injectable({ providedIn: 'root' })
export class AuthService extends BaseService {
private readonly _cachedUserRestrictions: Subject<Restriction[]>;
private readonly _userData: Observable<Restriction[]>;

constructor(private http: HttpClient) {
super();
if (!this._cachedUserRestrictions) {
this._cachedUserRestrictions = new Subject<Restriction[]>();
this.refreshData();
}
this._userData = this._cachedUserRestrictions.asObservable();
}

private refreshData() {
this.getRestrictions().subscribe({
next: (r) => this._cachedUserRestrictions.next(r),
error: (e) => console.log(e),
});
}

private getRestrictions(): Observable<Restriction[]> {
return this.http
.get<Restriction[]>(`${this.getBaseUrl()}/permissions/restrictions/ownRestrictions/`, {
headers: this.getHeaders(),
})
.pipe(catchError(this.handleError));
}

get userRestrictions() {
return this._userData;
}

getActionsForPermission(permissionName: string) {
return this._userData.pipe(
map((restrictions) => {
return restrictions.filter((entry) => entry.permission.name === permissionName).map((entry) => entry.action);
}),
);
}
}
8 changes: 8 additions & 0 deletions AMW_angular/io/src/app/auth/restriction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface Restriction {
role: string;
permission: string;
resourceType: string;
resourceTypePermission: string;
context: number;
action: boolean;
}
3 changes: 2 additions & 1 deletion AMW_angular/io/src/app/core/amw-constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const AMW_LOGOUT_URL = 'amw.logoutUrl';
// used for date-fns
export const DATE_FORMAT = 'dd.MM.yyyy HH:mm';
export const DATE_TIME_FORMAT = 'dd.MM.yyyy HH:mm';
export const DATE_FORMAT = 'dd.MM.yyyy';
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ResourceService } from '../resource/resource.service';
import * as _ from 'lodash';
import { DateTimeModel } from '../shared/date-time-picker/date-time.model';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { DATE_FORMAT } from '../core/amw-constants';
import { DATE_TIME_FORMAT } from '../core/amw-constants';
import { DateTimePickerComponent } from '../shared/date-time-picker/date-time-picker.component';
import { RouterLink } from '@angular/router';
import { IconComponent } from '../shared/icon/icon.component';
Expand Down Expand Up @@ -46,7 +46,7 @@ export class DeploymentsListComponent {
allSelected: boolean = false;
// TODO: show this error somewhere?
errorMessage = '';
dateFormat = DATE_FORMAT;
dateFormat = DATE_TIME_FORMAT;

failureReason: { [key: string]: string } = {
PRE_DEPLOYMENT_GENERATION: 'pre deployment generation failed',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<div class="modal-header">
<h5 class="modal-title" id="deleteReleaseTitle">{{ getTitle() }}</h5>
<button type="button" class="btn btn-light close" aria-label="Close" (click)="cancel()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-horizontal mx-2">
<div class="mb-3">
@if (!hasResources) {
<div class="text-body">Do you really want to delete the release {{ release.name }} ?</div>
} @else {
<div class="text-body">
The release {{ release.name }} is used by the following resources and can not be deleted:
<ul class="list-group mt-2">
@for (item of resources | keyvalue; track item) {
<li class="list-group-item">
<div class="d-flex justify-content-between align-items-start">
{{ item.key }} <span class="badge bg-primary rounded-pill ms-auto">{{ item.value.length }}</span>
</div>
<ul class="list-unstyled">
@for (rs of item.value; track rs) {
<li>
<small class="bi-dot">{{ rs.name }}</small>
</li>
}
</ul>
</li>
}
</ul>
</div>
}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" (click)="cancel()">Cancel</button>
<button type="button" class="btn btn-primary" [disabled]="hasResources" (click)="delete()">Delete</button>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { ReleaseDeleteComponent } from './release-delete.component';

describe('ReleaseDeleteComponent', () => {
let component: ReleaseDeleteComponent;
const activeModal = new NgbActiveModal();

beforeEach(async () => {
component = new ReleaseDeleteComponent(activeModal);
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Release } from './release';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { AsyncPipe, KeyValuePipe, NgFor, NgForOf, NgIf } from '@angular/common';
import { ResourceEntity } from './resourceEntity';

@Component({
selector: 'amw-release-delete',
standalone: true,
imports: [AsyncPipe, KeyValuePipe, NgIf, NgFor, NgForOf, FormsModule],
templateUrl: './release-delete.component.html',
})
export class ReleaseDeleteComponent implements OnInit {
@Input() release: Release;
@Input() resources: Map<string, ResourceEntity[]>;
@Output() deleteRelease: EventEmitter<Release> = new EventEmitter<Release>();

hasResources: boolean = false;

constructor(public activeModal: NgbActiveModal) {
this.activeModal = activeModal;
}

ngOnInit(): void {
if (this.resources.size > 0) {
this.hasResources = true;
}
}

getTitle(): string {
return 'Remove release';
}

cancel() {
this.activeModal.close();
}

delete() {
this.deleteRelease.emit(this.release);
this.activeModal.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<div class="modal-header">
<h5 class="modal-title" id="editReleaseTitle">{{ getTitle() }}</h5>
<button type="button" class="btn btn-light close" aria-label="Close" (click)="cancel()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-horizontal mx-2">
<div class="mb-3">
<label for="name" class="form-label">Release name</label>
<input type="text" class="form-control" id="name" [(ngModel)]="release.name" />
</div>
<div class="mb-3">
<div class="form-check">
<label for="main" class="form-check-label">Main release</label>
<input type="checkbox" class="form-check-input" id="main" [(ngModel)]="release.mainRelease" />
</div>
</div>
<div class="mb-3">
<label for="releaseDate" class="form-label">Installation date</label>
<div id="releaseDate" class="form-text input-group date mb-3" required>
<app-date-picker
[(ngModel)]="installationDate"
[dateStringFormat]="dateFormat"
name="installationDate"
id="datetimepicker"
class="w-100"
></app-date-picker>
</div>
@if (hasInvalidDate()) {
<div class="text-warning">The installation date is mandatory</div>
}
</div>
<div class="mb-3">
<label for="description" class="form-label">Release description</label>
<textarea type="text" class="form-control" id="description" [(ngModel)]="release.description"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" (click)="cancel()">Cancel</button>
<button type="button" class="btn btn-primary" [disabled]="hasInvalidDate()" (click)="save()">Save changes</button>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ReleaseEditComponent } from './release-edit.component';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';

describe('ReleasesEditComponent', () => {
let component: ReleaseEditComponent;
const activeModal = new NgbActiveModal();

beforeEach(async () => {
component = new ReleaseEditComponent(activeModal);
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
60 changes: 60 additions & 0 deletions AMW_angular/io/src/app/settings/releases/release-edit.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Release } from './release';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { DatePickerComponent } from '../../shared/date-picker/date-picker.component';
import { DATE_FORMAT } from '../../core/amw-constants';
import { DateModel } from '../../shared/date-picker/date.model';
import { NgIf } from '@angular/common';

@Component({
selector: 'amw-release-edit',
templateUrl: './release-edit.component.html',
standalone: true,
imports: [DatePickerComponent, NgIf, FormsModule],
})
export class ReleaseEditComponent implements OnInit {
@Input() release: Release;
@Output() saveRelease: EventEmitter<Release> = new EventEmitter<Release>();

dateFormat = DATE_FORMAT;
installationDate: DateModel = null;

constructor(public activeModal: NgbActiveModal) {
this.activeModal = activeModal;
}

ngOnInit(): void {
if (this.release) {
this.installationDate = DateModel.fromEpoch(this.release.installationInProductionAt);
}
}

getTitle(): string {
return this.release.id ? 'Edit release' : 'Add release';
}

hasInvalidDate(): boolean {
return this.installationDate == null || this.installationDate.toEpoch() == null;
}

cancel() {
this.activeModal.close();
}

save() {
if (this.installationDate.toEpoch() != null) {
const release: Release = {
name: this.release.name,
mainRelease: this.release.mainRelease,
description: this.release.description,
installationInProductionAt: this.installationDate.toEpoch(),
id: this.release.id ? this.release.id : null,
default: false,
v: this.release.v ? this.release.v : null,
};
this.saveRelease.emit(release);
this.activeModal.close();
}
}
}
9 changes: 9 additions & 0 deletions AMW_angular/io/src/app/settings/releases/release.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface Release {
name: string;
mainRelease: boolean;
description: string;
installationInProductionAt: number;
id: number;
v: number;
default: boolean;
}

0 comments on commit 6549fa5

Please sign in to comment.