Compare commits

...

7 Commits

Author SHA1 Message Date
Developer 02
b66c2f67da feat: Hinzufügen einer erweiterten Ansicht für die Tabelle im Envelope Generator
- In der Tabelle für Umschläge wurde ein versteckter Abschnitt unter den Zeilen hinzugefügt.
- Beim Klicken auf eine Zeile wird nun ein Detailbereich angezeigt, der Informationen zu Empfänger und Historie des Umschlags zeigt.
2024-09-09 17:30:36 +02:00
Developer 02
d084a4cd81 feat(component): initialisieren des HistoryTableComponent 2024-09-07 01:48:04 +02:00
Developer 02
5d2bf56493 feat(service): Unterstützung von Query-Parametern im HistoryService hinzugefügt
- Methode `getHistory` hinzugefügt, um das Abrufen von History-Daten mit optionalen Query-Parametern wie `envelopeId`, `referenceType`, `userReference`, `withSender` und `withReceiver` zu ermöglichen.
- Methode `getHistoryAsync` implementiert, um History-Daten mit async/await abzurufen.
- `Options`-Interface eingeführt, um optionale Query-Parameter für History-Anfragen zu definieren.
2024-09-07 01:41:19 +02:00
Developer 02
cd88f5c833 refactor(controller): Optimierung der Handhabung von Referenztypen im HistoryController
- `GetAllAsync`-Methode angepasst, um `withSender` oder `withReceiver` automatisch basierend auf dem `ReferenceType` zu setzen.
- Unnötigen `status`-Query-Parameter entfernt, um die API zu vereinfachen.
2024-09-07 01:32:09 +02:00
Developer 02
ab41e25071 feat: Referenztypen zwischen Backend und Frontend standardisieren
- `GetReferenceTypes`-Endpunkt im `HistoryController` hinzugefügt, um Key-Value-Paare des `ReferenceType`-Enums im camelCase-Format bereitzustellen.
- `ConfigurationService` in Angular erweitert, um die `ReferenceType`-Werte vom neuen API-Endpunkt abzurufen und zu speichern.
2024-09-07 01:12:50 +02:00
Developer 02
eb775da7d4 feat(service): HistoryService für API-Interaktionen erstellen 2024-09-07 00:37:54 +02:00
Developer 02
7bc2695da4 feat(controller): add GetAllAsync endpoint to HistoryController
- Added a new `GetAllAsync` method to HistoryController to retrieve envelope histories.
- Included query parameters for filtering by envelopeId, userReference, referenceType, status, and boolean flags for sender and receiver.
- Implemented validation of `referenceType` with `ReferenceType` enum, throwing an error for invalid values.
2024-09-07 00:08:55 +02:00
15 changed files with 227 additions and 7 deletions

View File

@@ -10,6 +10,7 @@ namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
int EnvelopeId,
string UserReference,
int Status,
string? StatusName,
DateTime AddedWhen,
DateTime? ActionDate,
UserCreateDto? Sender,

View File

@@ -26,6 +26,7 @@
MessageCompletionSent = 3005
End Enum
'TODO: standardize in xwiki
Public Enum ReferenceType
Receiver
Sender

View File

@@ -19,7 +19,7 @@ namespace EnvelopeGenerator.Domain.Entities
[Required]
[Column("USER_REFERENCE", TypeName = "nvarchar(128)")]
public string UserReference { get; set; }
public required string UserReference { get; init; }
[Required]
[Column("STATUS")]
@@ -43,11 +43,17 @@ namespace EnvelopeGenerator.Domain.Entities
public virtual Receiver? Receiver { get; set; }
[NotMapped]
public ReferenceType ReferenceType => (Status / 3) switch
public ReferenceType ReferenceType => (Status / 1000) switch
{
1 => ReferenceType.Sender,
2 or 3 => ReferenceType.Receiver,
_ => ReferenceType.Unknown,
};
[NotMapped]
public string? StatusName
=> (Enum.IsDefined(typeof(EnvelopeStatus), Status))
? Enum.GetName(typeof(EnvelopeStatus), Status)
: null;
}
}

View File

@@ -0,0 +1,23 @@
<table mat-table [dataSource]="receiverData" class="mat-elevation-z8">
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef> Email </th>
<td mat-cell *matCellDef="let element; let i = index">
<receiver-input [options]="receiver_mails" [filter]="receiver_filter"></receiver-input>
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Anrede Email </th>
<td mat-cell *matCellDef="let element">
<clearable-input [label]="'Anrede Email'" [value]="element.name"></clearable-input>
</td>
</ng-container>
<ng-container matColumnDef="accessCode">
<th mat-header-cell *matHeaderCellDef> Zugriffscode </th>
<td mat-cell *matCellDef="let element"> {{element.accessCode}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

View File

@@ -6,6 +6,7 @@
<receiver-status-table></receiver-status-table>
</mat-tab>
<mat-tab label="History">
<history-table></history-table>
</mat-tab>
</mat-tab-group>
</dd-table>

View File

@@ -6,12 +6,14 @@ import { DDTable } from "../dd-table/dd-table.component";
import { ClearableInputComponent } from '../../clearable-input/clearable-input.component'
import { MatTabsModule } from '@angular/material/tabs';
import { ReceiverStatusTableComponent } from "../receiver-status-table/receiver-status-table.component";
import { HistoryTableComponent } from "../history-table/history-table.component";
import { EnvelopeReceiverService } from '../../../services/envelope-receiver.service';
import { HistoryService } from '../../../services/history.service';
@Component({
selector: 'envelope-table',
standalone: true,
imports: [DDTable, ClearableInputComponent, MatTabsModule, ReceiverStatusTableComponent],
imports: [DDTable, ClearableInputComponent, MatTabsModule, ReceiverStatusTableComponent, HistoryTableComponent],
templateUrl: './envelope-table.component.html',
animations: [
trigger('detailExpand', [
@@ -51,12 +53,19 @@ export class EnvelopeTableComponent implements AfterViewInit {
@ViewChild(ReceiverStatusTableComponent) rsTable!: ReceiverStatusTableComponent
@ViewChild(HistoryTableComponent) histTable!: HistoryTableComponent
onToggleExpandedRow: (envelope: any, event: Event) => Promise<void> = async (envelope, event) => {
if (envelope === null || envelope === undefined)
return;
var uuid: string = envelope.uuid;
this.rsTable.data = await this.erService.getSecretAsync(uuid);
var id: number = envelope.id;
var refType: number = this.config.referenceType.receiver;
const histories = await this.histService.getHistoryAsync({ envelopeId: id, referenceType: refType, withReceiver: true })
this.histTable.data = histories;
}
private eService: EnvelopeService = inject(EnvelopeService);
@@ -65,6 +74,8 @@ export class EnvelopeTableComponent implements AfterViewInit {
private readonly erService: EnvelopeReceiverService = inject(EnvelopeReceiverService);
private readonly histService: HistoryService = inject(HistoryService);
async ngAfterViewInit() {
this.data = await this.eService.getEnvelopeAsync(this.options);
}

View File

@@ -0,0 +1 @@
<dd-table [data]="data" [columnsToDisplay]="columnsToDisplay" [schema]="schema" [isSortable]="true"></dd-table>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HistoryTableComponent } from './history-table.component';
describe('HistoryTableComponent', () => {
let component: HistoryTableComponent;
let fixture: ComponentFixture<HistoryTableComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HistoryTableComponent]
})
.compileComponents();
fixture = TestBed.createComponent(HistoryTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,30 @@
import { Component } from '@angular/core';
import { DDTable } from '../dd-table/dd-table.component'
@Component({
selector: 'history-table',
standalone: true,
imports: [DDTable],
templateUrl: './history-table.component.html',
styleUrl: './history-table.component.scss'
})
export class HistoryTableComponent {
data: any[] = [];
schema: Record<string, { header: string; field: (element: any) => any; }> = {
"status": {
"header": "Status",
"field": hist => hist.statusName
},
"user": {
"header": "Benutzer",
"field": hist => hist.userReference
},
"date": {
"header": "Datum",
"field": hist => hist.actionDate
}
}
columnsToDisplay: string[] = ["status", "user", "date"];
}

View File

@@ -1,4 +1,4 @@
import { Component, inject } from '@angular/core';
import { Component } from '@angular/core';
import { DDTable } from '../dd-table/dd-table.component'
@Component({

View File

@@ -14,6 +14,8 @@ export class ConfigurationService implements OnInit {
private _envelopeTypeTitles! : any[];
private _referenceType!: any;
constructor(private http: HttpClient) {
const api_url = inject(API_URL);
this.url = `${api_url}`;
@@ -25,6 +27,10 @@ export class ConfigurationService implements OnInit {
this._envelopeTypes = res;
this._envelopeTypeTitles = res.map(e => e.title);
}});
this.http.get<any>(`${this.url}/History/reference-type`).subscribe({
next: res => this._referenceType = res
})
}
public get envelopeTypes() {
@@ -33,5 +39,9 @@ export class ConfigurationService implements OnInit {
public get envelopeTypeTitles() {
return this._envelopeTypeTitles;
}
}
}
public get referenceType() {
return this._referenceType;
}
}

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { HistoryService } from './history.service';
describe('HistoryService', () => {
let service: HistoryService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(HistoryService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,46 @@
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, firstValueFrom } from 'rxjs';
import { API_URL } from '../tokens/index';
@Injectable({
providedIn: 'root'
})
export class HistoryService {
protected url: string;
constructor(private http: HttpClient) {
const api_url = inject(API_URL);
this.url = `${api_url}/history`;
}
public getHistory(options?: Options): Observable<any> {
let params = new HttpParams();
if (options) {
if (options.envelopeId)
params = params.set('envelopeId', options.envelopeId);
if (options.referenceType != null)
params = params.set('referenceType', options.referenceType);
if (options.userReference)
params = params.set('userReference', options.userReference);
if (options.withReceiver)
params = params.set('withReceiver', options.withReceiver);
if (options.withSender)
params = params.set('withSender', options.withSender);
}
return this.http.get(this.url, { params });
}
public async getHistoryAsync(options?: Options): Promise<any> {
return firstValueFrom(this.getHistory(options));
}
}
class Options {
envelopeId?: number;
userReference?: string;
referenceType: number | null = null;
withSender?: boolean;
withReceiver?: boolean;
}

View File

@@ -1,6 +1,8 @@
using EnvelopeGenerator.Application.Contracts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.GeneratorAPI.Controllers
{
@@ -18,5 +20,54 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
_logger = logger;
_service = service;
}
[HttpGet("reference-type")]
[Authorize]
public IActionResult GetReferenceTypes()
{
// Enum to Key-Value pair
var referenceTypes = Enum.GetValues(typeof(ReferenceType))
.Cast<ReferenceType>()
.ToDictionary(rt =>
{
var key = rt.ToString();
var keyAsCamelCase = char.ToLower(key[0]) + key[1..];
return keyAsCamelCase;
}, rt => (int)rt);
return Ok(referenceTypes);
}
[HttpGet]
[Authorize]
public async Task<IActionResult> GetAllAsync([FromQuery] int? envelopeId = null, [FromQuery] string? userReference = null, [FromQuery] int? referenceType = null, [FromQuery] bool withSender = false, [FromQuery] bool withReceiver = false)
{
ReferenceType? refTypEnum = null;
if (referenceType is int refTypInt)
if (Enum.IsDefined(typeof(ReferenceType), refTypInt))
refTypEnum = (ReferenceType)refTypInt;
else
throw new ArgumentException($"The provided referenceType '{referenceType}' is not valid. It must correspond to a valid value in the {nameof(ReferenceType)} enum.");
switch(referenceType)
{
case (int)ReferenceType.Receiver:
withReceiver = true;
break;
case (int)ReferenceType.Sender:
withSender = true;
break;
}
var histories = await _service.ReadAsync(
envelopeId: envelopeId,
userReference: userReference,
referenceType: refTypEnum,
withSender: withSender,
withReceiver: withReceiver);
return Ok(histories);
}
}
}
}