Skip to content

Commit

Permalink
Merge pull request #69 from UCI-IN4MATX-191-Token-ATM/feature-token-o…
Browse files Browse the repository at this point in the history
…ption-grid-view

Feature: grid view for token options
  • Loading branch information
yongkanm authored Aug 28, 2023
2 parents 6a111de + 827e1da commit 7a428dd
Show file tree
Hide file tree
Showing 41 changed files with 1,187 additions and 93 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ jobs:
- name: Build Angular project
run: |
npm run build
cp dist/token-atm-spa/index.html dist/token-atm-spa/404.html
- name: Deploy to GitHub Pages
uses: JamesIves/github-pages-deploy-action@v4
Expand Down
61 changes: 61 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"private": true,
"dependencies": {
"@angular/animations": "^15.2.0",
"@angular/cdk": "^15.2.9",
"@angular/common": "^15.2.0",
"@angular/compiler": "^15.2.0",
"@angular/core": "^15.2.0",
Expand All @@ -29,6 +30,8 @@
"@angular/platform-browser-dynamic": "^15.2.0",
"@angular/router": "^15.2.0",
"@popperjs/core": "^2.11.6",
"ag-grid-angular": "^30.0.6",
"ag-grid-community": "^30.0.6",
"axios": "^1.3.5",
"bootstrap": "^5.2.3",
"bootstrap-icons": "^1.10.5",
Expand Down
2 changes: 2 additions & 0 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { getDashboardRoutes } from './components/dashboard/dashboard-routing';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { LoginComponent } from './components/login/login.component';
import { AUTH_GUARD } from './utils/auth-guard';
import { GridViewExternalAccessComponent } from './components/grid-view-external-access/grid-view-external-access.component';

const routes: Routes = [
{ path: 'grid-view', component: GridViewExternalAccessComponent },
{ path: 'login', component: LoginComponent },
{
path: 'dashboard',
Expand Down
12 changes: 10 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ import {
import { CreateTokenOptionModalComponent } from './components/create-token-option-modal/create-token-option-modal.component';
import { MultipleSectionDateFieldComponent } from './components/form-fields/multiple-section-date-field/multiple-section-date-field.component';
import { ErrorMessageFieldComponent } from './components/form-fields/error-message-field/error-message-field.component';
import { AgGridModule } from 'ag-grid-angular';
import { GridViewDisplayComponent } from './components/grid-view-display/grid-view-display.component';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { GridViewExternalAccessComponent } from './components/grid-view-external-access/grid-view-external-access.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -98,7 +102,9 @@ import { ErrorMessageFieldComponent } from './components/form-fields/error-messa
ListFieldComponent,
CreateTokenOptionModalComponent,
MultipleSectionDateFieldComponent,
ErrorMessageFieldComponent
ErrorMessageFieldComponent,
GridViewDisplayComponent,
GridViewExternalAccessComponent
],
imports: [
BrowserModule,
Expand All @@ -110,7 +116,9 @@ import { ErrorMessageFieldComponent } from './components/form-fields/error-messa
ModalModule.forRoot(),
BsDatepickerModule.forRoot(),
TimepickerModule.forRoot(),
TooltipModule.forRoot()
TooltipModule.forRoot(),
AgGridModule,
DragDropModule
],
providers: [
{ provide: ErrorHandler, useClass: GlobalErrorHandler },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<ag-grid-angular
*ngIf="gridViewData && gridViewColDef"
class="ag-theme-alpine w-100 h-100"
[rowData]="gridViewData"
[columnDefs]="gridViewColDef"
[enableCellTextSelection]="true"
(firstDataRendered)="onFirstDataRendered($event)"
(displayedColumnsChanged)="columnChange.emit($event)"
></ag-grid-angular>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// import { ComponentFixture, TestBed } from '@angular/core/testing';

// import { GridViewDisplayComponent } from './grid-view-display.component';

// describe('GridViewDisplayComponent', () => {
// let component: GridViewDisplayComponent;
// let fixture: ComponentFixture<GridViewDisplayComponent>;

// beforeEach(async () => {
// await TestBed.configureTestingModule({
// declarations: [GridViewDisplayComponent]
// }).compileComponents();

// fixture = TestBed.createComponent(GridViewDisplayComponent);
// component = fixture.componentInstance;
// fixture.detectChanges();
// });

// it('should create', () => {
// expect(component).toBeTruthy();
// });
// });
103 changes: 103 additions & 0 deletions src/app/components/grid-view-display/grid-view-display.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import type {
ColDef,
DisplayedColumnsChangedEvent,
FirstDataRenderedEvent,
ICellRendererParams,
ValueFormatterParams
} from 'ag-grid-community';
import type { GridViewData, GridViewDataPoint } from 'app/token-options/mixins/grid-view-data-source-mixin';
import { format } from 'date-fns';

type AGGridDataSource = {
[key in string]: GridViewDataPoint['value'];
};

@Component({
selector: 'app-grid-view-display',
templateUrl: './grid-view-display.component.html',
styleUrls: ['./grid-view-display.component.sass']
})
export class GridViewDisplayComponent {
gridViewColDef?: ColDef<AGGridDataSource, GridViewDataPoint['value']>[];
gridViewData?: AGGridDataSource[];
@Output() columnChange = new EventEmitter<DisplayedColumnsChangedEvent>();

@Input() set data(data: [GridViewData[], string[]] | undefined) {
this.gridViewColDef = undefined;
this.gridViewData = undefined;
if (!data) return;
const [dataArray, colPreferences] = data;
const columns: [string, string][] = [],
colSet = new Set<string>();
this.gridViewData = [];
for (const data of dataArray) {
const dataObj: AGGridDataSource = {};
for (const entry of data.data) {
const colIdentifier = JSON.stringify([entry.colName, entry.type]);
dataObj[colIdentifier] = entry.value;
if (colSet.has(colIdentifier)) continue;
colSet.add(colIdentifier);
columns.push([entry.colName, entry.type]);
}
this.gridViewData.push(dataObj);
}
this.gridViewColDef = columns.map(([name, type]) => {
const colDef: ColDef<AGGridDataSource, GridViewDataPoint['value']> = {
headerName: name,
field: JSON.stringify([name, type]),
resizable: true,
wrapHeaderText: true,
wrapText: true,
autoHeaderHeight: true,
autoHeight: true,
sortable: true,
filter: true
};
switch (type) {
case 'number': {
colDef.cellDataType = 'number';
break;
}
case 'percentage': {
colDef.cellDataType = 'number';
// TODO: custom formatting & sorting
break;
}
case 'string': {
colDef.cellDataType = 'text';
break;
}
case 'html': {
colDef.cellRenderer = (params: ICellRendererParams) => params.value ?? '';
delete colDef.wrapText;
delete colDef.sortable;
delete colDef.filter;
break;
}
case 'date': {
colDef.cellDataType = 'date';
colDef.valueFormatter = (
params: ValueFormatterParams<AGGridDataSource, GridViewDataPoint['value']>
) => (params.value instanceof Date ? format(params.value, 'MMM dd, yyyy HH:mm:ss') : '');
}
}
return colDef;
});
const colOrdering = new Map<string, number>(),
colPrefSet = new Set(colPreferences);
for (const [ind, v] of colPreferences.entries()) {
colOrdering.set(v, ind);
}
this.gridViewColDef.sort(
(a, b) => (colOrdering.get(a.headerName as string) ?? -1) - (colOrdering.get(b.headerName as string) ?? -1)
);
for (const colDef of this.gridViewColDef) {
if (!colPrefSet.has(colDef.headerName as string)) colDef.hide = true;
}
}

onFirstDataRendered(event: FirstDataRenderedEvent) {
event.columnApi.autoSizeAllColumns();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="vw-100 vh-100">
<app-grid-view-display [data]="data"></app-grid-view-display>
</div>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// import { ComponentFixture, TestBed } from '@angular/core/testing';

// import { GridViewExternalAccessComponent } from './grid-view-external-access.component';

// describe('GridViewExternalAccessComponent', () => {
// let component: GridViewExternalAccessComponent;
// let fixture: ComponentFixture<GridViewExternalAccessComponent>;

// beforeEach(async () => {
// await TestBed.configureTestingModule({
// declarations: [GridViewExternalAccessComponent]
// }).compileComponents();

// fixture = TestBed.createComponent(GridViewExternalAccessComponent);
// component = fixture.componentInstance;
// fixture.detectChanges();
// });

// it('should create', () => {
// expect(component).toBeTruthy();
// });
// });
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Component, Inject, OnDestroy } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import type { GridViewData } from 'app/token-options/mixins/grid-view-data-source-mixin';
import type { Subscription } from 'rxjs';

@Component({
selector: 'app-grid-view-external-access',
templateUrl: './grid-view-external-access.component.html',
styleUrls: ['./grid-view-external-access.component.sass']
})
export class GridViewExternalAccessComponent implements OnDestroy {
private isListenerActive = false;
data?: [GridViewData[], string[]];
subscription?: Subscription;

messageListener = (
event: MessageEvent<{
type: 'GRID_VIEW_DATA';
value: [GridViewData[], string[]];
}>
) => {
if (event.origin != window.location.origin) return;
if (event.data.type != 'GRID_VIEW_DATA') return;
this.data = event.data.value;
window.removeEventListener('message', this.messageListener);
this.isListenerActive = false;
};

constructor(@Inject(Router) private router: Router) {
this.subscription = this.router.events.subscribe((event) => {
if (!(event instanceof NavigationEnd)) return;
if (!(event.url == '/grid-view')) return;
if (this.isListenerActive) return;
window.addEventListener('message', this.messageListener);
this.isListenerActive = true;
});
}

ngOnDestroy(): void {
if (!this.isListenerActive) window.removeEventListener('message', this.messageListener);
if (this.subscription) this.subscription.unsubscribe();
}
}
Loading

0 comments on commit 7a428dd

Please sign in to comment.