diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.html
new file mode 100644
index 00000000..6bdca454
--- /dev/null
+++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.html
@@ -0,0 +1,59 @@
+@if(isFilterable) {
+
+ {{filter.label}}
+
+
+}
+
+
+ @for (column of __columnsToDisplay; track column) {
+
+ @if(isSortable) {
+ | {{schema[column].header}} |
+ }
+ @else {
+ {{schema[column].header}} |
+ }
+ {{schema[column].field(element)}} |
+
+ }
+
+
+ @if(isExpandable) {
+
+ |
+
+
+ |
+
+
+
+
+ @if(__expandedElement === element){
+
+ }
+
+ |
+
+ }
+ @if(isExpandable) {
+
+
+
+
+ }
+ @else {
+
+
+ }
+
+@if(paginatorSizeOptions && paginatorSizeOptions.length > 0) {
+
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.scss b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.scss
new file mode 100644
index 00000000..155617b3
--- /dev/null
+++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.scss
@@ -0,0 +1,52 @@
+table {
+ width: 100%;
+}
+
+tr.example-detail-row {
+ height: 0;
+}
+
+tr.example-element-row:not(.example-expanded-row):hover {
+ background: whitesmoke;
+}
+
+tr.example-element-row:not(.example-expanded-row):active {
+ background: #efefef;
+}
+
+.example-element-row td {
+ border-bottom-width: 0;
+}
+
+.example-element-detail {
+ overflow: hidden;
+ display: flex;
+}
+
+.example-element-diagram {
+ min-width: 80px;
+ border: 2px solid black;
+ padding: 8px;
+ font-weight: lighter;
+ margin: 8px 0;
+ height: 104px;
+}
+
+.example-element-symbol {
+ font-weight: bold;
+ font-size: 40px;
+ line-height: normal;
+}
+
+.example-element-description {
+ padding: 16px;
+}
+
+.example-element-description-attribution {
+ opacity: 0.5;
+}
+
+.mat-mdc-form-field {
+ font-size: 14px;
+ width: 100%;
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.spec.ts
new file mode 100644
index 00000000..0c704ba9
--- /dev/null
+++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DDTable } from './dd-table.component';
+
+describe('TableExpandableRowsExampleComponent', () => {
+ let component: DDTable;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [DDTable]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(DDTable);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.ts
new file mode 100644
index 00000000..7e2fa4fc
--- /dev/null
+++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/dd-table/dd-table.component.ts
@@ -0,0 +1,103 @@
+import { AfterViewInit, Component, Input, ViewChild, inject } from '@angular/core';
+import { animate, state, style, transition, trigger } from '@angular/animations';
+import { MatIconModule } from '@angular/material/icon';
+import { MatButtonModule } from '@angular/material/button';
+import { MatTable, MatTableDataSource, MatTableModule } from '@angular/material/table';
+import { ConfigurationService } from '../../services/configuration.service';
+import { MatInputModule } from '@angular/material/input';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSort, MatSortModule } from '@angular/material/sort';
+import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
+
+/**
+ * @title Table with expandable rows
+ */
+@Component({
+ selector: 'dd-table',
+ styleUrl: 'dd-table.component.scss',
+ templateUrl: 'dd-table.component.html',
+ animations: [
+ trigger('detailExpand', [
+ state('collapsed,void', style({ height: '0px', minHeight: '0' })),
+ state('expanded', style({ height: '*' })),
+ transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
+ ]),
+ ],
+ standalone: true,
+ imports: [
+ MatTableModule,
+ MatButtonModule,
+ MatIconModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MatTableModule,
+ MatSort,
+ MatSortModule,
+ MatPaginator,
+ MatPaginatorModule
+ ],
+})
+export class DDTable implements AfterViewInit {
+ public readonly dataSource: any = new MatTableDataSource();
+ @Input() public set columnsToDisplay(value: string[]) {
+ this.__columnsToDisplay = value;
+ this.__columnsToDisplayWithExpand = [...value, 'expand'];
+ }
+ @Input() public set data(value: any[]) {
+ this.dataSource.data = value;
+ }
+ @Input() schema: Record any; }> = {}
+
+ @Input() paginatorSizeOptions?: number[];
+
+ @Input() filter: { label: string, placeholder: string } = { label: '', placeholder: '' }
+
+ @Input() isFilterable: boolean = false;
+
+ @Input() isExpandable: boolean = false;
+
+ @Input() isSortable: boolean = false;
+
+ @Input() onToggleExpandedRow: (element: any, event: Event) => void = (element: any, event: Event) => { }
+
+ public get data(): any[] {
+ return this.dataSource.data;
+ }
+ __columnsToDisplay: string[] = [];
+ __columnsToDisplayWithExpand: string[] = [];
+ __expandedElement!: any;
+
+ config: ConfigurationService = inject(ConfigurationService);
+
+ @ViewChild(MatSort) sort!: MatSort;
+ @ViewChild(MatPaginator) paginator!: MatPaginator;
+ @ViewChild(MatTable) table!: MatTable;
+
+ ngAfterViewInit(): void {
+ if (this.isSortable)
+ this.dataSource.sort = this.sort;
+ if (this.paginatorSizeOptions && this.paginatorSizeOptions.length > 0)
+ this.dataSource.paginator = this.paginator;
+ }
+
+ applyFilter(event: Event) {
+ const filterValue = (event.target as HTMLInputElement).value;
+ this.dataSource.filter = filterValue.trim().toLowerCase();
+ }
+
+ update() {
+ this.table.renderRows();
+ }
+
+ toggleExpandedRow(element: any, event: Event): void {
+ // first determine the new expanded element, thus it would be possible to use up-to-date
+ const newExpandedElement = this.__expandedElement === element ? null : element;
+
+ // before update the expanded element call the call-back method to show up-to-date component
+ this.onToggleExpandedRow(newExpandedElement, event);
+
+ // assign expanded element
+ this.__expandedElement = newExpandedElement;
+ event.stopPropagation();
+ }
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.html
index f3e30cc5..331a5270 100644
--- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.html
+++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.html
@@ -1,39 +1,4 @@
-
- Filter
-
-
-
-
-
- @for (colId of displayedColumns; track colId) {
-
- | {{schema[colId].header}} |
- {{schema[colId].field(element)}} |
-
- }
-
-
- |
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.scss b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.scss
index 25f0e5a8..1272cd53 100644
--- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.scss
+++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.scss
@@ -7,4 +7,53 @@ table {
font-size: 14px;
width: 100%;
margin-top: 10px;
+}
+
+/* For expanding table */
+table {
+ width: 100%;
+}
+
+tr.example-detail-row {
+ height: 0;
+}
+
+tr.example-element-row:not(.example-expanded-row):hover {
+ background: whitesmoke;
+}
+
+tr.example-element-row:not(.example-expanded-row):active {
+ background: #efefef;
+}
+
+.example-element-row td {
+ border-bottom-width: 0;
+}
+
+.example-element-detail {
+ overflow: hidden;
+ display: flex;
+}
+
+.example-element-diagram {
+ min-width: 80px;
+ border: 2px solid black;
+ padding: 8px;
+ font-weight: lighter;
+ margin: 8px 0;
+ height: 104px;
+}
+
+.example-element-symbol {
+ font-weight: bold;
+ font-size: 40px;
+ line-height: normal;
+}
+
+.example-element-description {
+ padding: 16px;
+}
+
+.example-element-description-attribution {
+ opacity: 0.5;
}
\ No newline at end of file
diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.ts
index 43a8d6bf..f32a0455 100644
--- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.ts
+++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.ts
@@ -1,20 +1,14 @@
-import { AfterViewInit, Component, Input, ViewChild } from '@angular/core';
+import { AfterViewInit, Component, Input, ViewChild, inject, viewChild } from '@angular/core';
import { EnvelopeReceiverService } from '../../services/envelope-receiver.service';
-import { MatTable, MatTableModule, MatTableDataSource } from '@angular/material/table';
-import { CommonModule } from '@angular/common'
-import { MatIconModule } from '@angular/material/icon';
-import { MatButtonModule } from '@angular/material/button';
import { animate, state, style, transition, trigger } from '@angular/animations';
-import { MatInputModule } from '@angular/material/input';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import {MatPaginator, MatPaginatorModule} from '@angular/material/paginator';
-import {MatSort, MatSortModule} from '@angular/material/sort';
import { ConfigurationService } from '../../services/configuration.service';
+import { DDTable } from "../dd-table/dd-table.component";
+import { ClearableInputComponent } from '../clearable-input/clearable-input.component'
@Component({
selector: 'app-envelope-table',
standalone: true,
- imports: [MatTableModule, CommonModule, MatTableModule, MatButtonModule, MatIconModule, MatFormFieldModule, MatInputModule, MatTableModule, MatPaginator, MatPaginatorModule, MatSort, MatSortModule],
+ imports: [DDTable, ClearableInputComponent],
templateUrl: './envelope-table.component.html',
animations: [
trigger('detailExpand', [
@@ -25,13 +19,13 @@ import { ConfigurationService } from '../../services/configuration.service';
],
styleUrl: './envelope-table.component.scss'
})
-export class EnvelopeTableComponent implements AfterViewInit {
+export class EnvelopeTableComponent implements AfterViewInit {
@Input() options?: { min_status?: number; max_status?: number; ignore_status?: number[] }
- @Input() displayedColumns: string[] = ['title', 'status', 'type', 'privateMessage', 'addedWhen'];
+ displayedColumns: string[] = ['title', 'status', 'type', 'privateMessage', 'addedWhen'];
- @Input() schema: Record any; }> = {
+ schema: Record any; }> = {
'title': {
header: 'Title',
field: (element: any) => element.envelope.title
@@ -51,50 +45,20 @@ export class EnvelopeTableComponent implements AfterViewInit {
'addedWhen': {
header: 'Added When',
field: (element: any) => element.addedWhen
- },
- }
-
- columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
-
- expandedElement: any | null;
-
- @ViewChild(MatTable) table!: MatTable;
-
- @ViewChild(MatPaginator) paginator!: MatPaginator;
-
- @ViewChild(MatSort) sort!: MatSort;
-
- dataSource = new MatTableDataSource();
-
- constructor(private erService: EnvelopeReceiverService, private config: ConfigurationService) {
- this.dataSource.filterPredicate = (data: any, filter: string): boolean => {
- const dataStr = Object.values(data as { [key: string]: any }).reduce((currentTerm, key) => {
- return currentTerm + (key ? key.toString().toLowerCase() : '');
- }, '').trim().toLowerCase();
- return dataStr.indexOf(filter) !== -1;
- };
- }
-
- async ngAfterViewInit() {
- this.dataSource.paginator = this.paginator;
- this.dataSource.data = await this.erService.getEnvelopeReceiverAsync(this.options);
- this.dataSource.sort = this.sort;
- }
-
- public updateTable() {
- this.table.renderRows();
- }
-
- isExpandedRow(index: number, row: any): boolean {
- return (row?.envelopeId === this.expandedElement?.envelopeId) && (row?.receiverId === this.expandedElement?.receiverId);
- }
-
- applyFilter(event: Event) {
- const filterValue = (event.target as HTMLInputElement).value;
- this.dataSource.filter = filterValue.trim().toLowerCase();
-
- if (this.dataSource.paginator) {
- this.dataSource.paginator.firstPage();
}
}
+
+ data: any[] = [];
+
+ @ViewChild(ClearableInputComponent) input!: ClearableInputComponent
+
+ onToggleExpandedRow(element: any, event: Event) { }
+
+ private erService: EnvelopeReceiverService = inject(EnvelopeReceiverService);
+
+ private config: ConfigurationService = inject(ConfigurationService);
+
+ async ngAfterViewInit() {
+ this.data = await this.erService.getEnvelopeReceiverAsync(this.options);
+ }
}
\ No newline at end of file