Skip to content

Commit

Permalink
Support for configuring the format of the fields in Report CSV downlo…
Browse files Browse the repository at this point in the history
…ad (#1282)

* Added lodash template service and tests

* Updated dashboard component's template evaluations to use the lodash-template-utiltity service

* Made record-table use the new lodash template util service

* Removed ESM import for lodash in dashboard.
Added lodash wrapper that includes common lodash functions into loadsh template utiltiy

* Added support for formatting the output in the report CSV
Added default report configuration

* Added integration tests for csv exports
  • Loading branch information
andrewbrazzatti authored May 17, 2023
1 parent f3d8863 commit 206bb99
Show file tree
Hide file tree
Showing 11 changed files with 1,563 additions and 1,819 deletions.
1,854 changes: 413 additions & 1,441 deletions angular/package-lock.json

Large diffs are not rendered by default.

511 changes: 251 additions & 260 deletions angular/projects/researchdatabox/dashboard/src/app/dashboard.component.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright (c) 2022 Queensland Cyber Infrastructure Foundation (http://www.qcif.edu.au/)
//
// GNU GENERAL PUBLIC LICENSE
// Version 2, June 1991
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import { TestBed } from '@angular/core/testing';
import { APP_BASE_HREF } from '@angular/common';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { LoDashTemplateUtilityService } from './lodash-template-utility.service';




/**
* 'Lodash Template Utility Service Testing
*
* Based on recommendations at https://angular.io/guide/testing
*
* Note, as per above URL:
*
* It's a good idea to put unit test spec files in the same folder as the application source code files that they test:
* - Such tests are painless to find
* - You see at a glance if a part of your application lacks tests
* - Nearby tests can reveal how a part works in context
* - When you move the source (inevitable), you remember to move the test
* - When you rename the source file (inevitable), you remember to rename the test - file
*
*/
describe('Lodash Template Utility Service testing', () => {
let loDashTemplateUtilityService: LoDashTemplateUtilityService;

beforeEach(function () {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{
provide: APP_BASE_HREF,
useValue: ''
},
LoDashTemplateUtilityService
]
});

loDashTemplateUtilityService = TestBed.inject(LoDashTemplateUtilityService);
});

it('Should format 2023-05-11T00:00:00.000Z as 11/05/2023 (dd/MM/yyyy)', function (done: any) {
const dateString = "2023-05-11T00:00:00.000Z";
const sourceDate: Date = new Date(Date.parse(dateString));

const formattedString = loDashTemplateUtilityService.formatDate(sourceDate, "dd/MM/yyyy");
expect(formattedString).toBe("11/05/2023");
done()
}
)

it('Should format 2023-05-11T00:00:00.000Z using DATETIME_MED', function (done: any) {
const dateString = "2023-05-11T00:00:00.000Z";
const sourceDate: Date = new Date(Date.parse(dateString));

const formattedString = loDashTemplateUtilityService.formatDateLocale(sourceDate, "DATETIME_MED")
expect(formattedString).toBe("May 11, 2023, 12:00 AM");
done()
}
)

it('Run template', function (done: any) {
const data:any = {
sourceDateString: "2023-05-11T00:00:00.000Z",
sourceNumber: 12000
}
let config1 = {
template: '<%= "test" %>'
}

const evaluatedTemplate1 = loDashTemplateUtilityService.runTemplate(data,config1)
expect(evaluatedTemplate1).toBe("test");

let config2 = {
template: '<%= util.formatDate(util.parseDateString(data.sourceDateString), "dd/MM/yyyy") %>'
}

const evaluatedTemplate2 = loDashTemplateUtilityService.runTemplate(data,config2)
expect(evaluatedTemplate2).toBe("11/05/2023");

let config3 = {
template: '<%= util.numberFormat(data.sourceNumber) %>'
}

const evaluatedTemplate3 = loDashTemplateUtilityService.runTemplate(data,config3)
expect(evaluatedTemplate3).toBe("12,000");

done()
}
)

});




afterEach(() => {


});

Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright (c) 2017 Queensland Cyber Infrastructure Foundation (http://www.qcif.edu.au/)
//
// GNU GENERAL PUBLIC LICENSE
// Version 2, June 1991
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


import { Injectable } from '@angular/core';
import { DateTime } from 'luxon';
import { get as _get, set as _set, extend as _extend, isEmpty as _isEmpty, isUndefined as _isUndefined, merge as _merge, trim as _trim, isNull as _isNull, orderBy as _orderBy, map as _map, find as _find, indexOf as _indexOf, isArray as _isArray, forEach as _forEach, join as _join, first as _first, template as _template } from 'lodash-es';

/**
* Utility functions to run and render loadash templates
*
*
*/
@Injectable({
providedIn: 'platform'
})
export class LoDashTemplateUtilityService {
presetMap: Record<string, Intl.DateTimeFormatOptions> = {
DATE_SHORT: DateTime.DATE_SHORT,
DATE_MED: DateTime.DATE_MED,
DATE_MED_WITH_WEEKDAY: DateTime.DATE_MED_WITH_WEEKDAY,
DATE_FULL: DateTime.DATE_FULL,
DATE_HUGE: DateTime.DATE_HUGE,
TIME_SIMPLE: DateTime.TIME_SIMPLE,
TIME_WITH_SECONDS: DateTime.TIME_WITH_SECONDS,
TIME_WITH_SHORT_OFFSET: DateTime.TIME_WITH_SHORT_OFFSET,
TIME_WITH_LONG_OFFSET: DateTime.TIME_WITH_LONG_OFFSET,
TIME_24_SIMPLE: DateTime.TIME_24_SIMPLE,
TIME_24_WITH_SECONDS: DateTime.TIME_24_WITH_SECONDS,
TIME_24_WITH_SHORT_OFFSET: DateTime.TIME_24_WITH_SHORT_OFFSET,
TIME_24_WITH_LONG_OFFSET: DateTime.TIME_24_WITH_LONG_OFFSET,
DATETIME_SHORT: DateTime.DATETIME_SHORT,
DATETIME_MED: DateTime.DATETIME_MED,
DATETIME_FULL: DateTime.DATETIME_FULL,
DATETIME_HUGE: DateTime.DATETIME_HUGE,
DATETIME_SHORT_WITH_SECONDS: DateTime.DATETIME_SHORT_WITH_SECONDS,
DATETIME_MED_WITH_SECONDS: DateTime.DATETIME_MED_WITH_SECONDS,
DATETIME_FULL_WITH_SECONDS: DateTime.DATETIME_FULL_WITH_SECONDS,
DATETIME_HUGE_WITH_SECONDS: DateTime.DATETIME_HUGE_WITH_SECONDS
};

lodashWrapper: object = {
get: _get,
set: _set,
isEmpty: _isEmpty,
isUndefined: _isUndefined,
trim: _trim,
isNull: _isNull,
orderBy: _orderBy,
map: _map,
find: _find,
indexOf: _indexOf,
isArray: _isArray,
forEach: _forEach,
join: _join,
first: _first,
merge: _merge,
extend: _extend,
template: _template
}

public formatDate(date: Date, format: string): string {
let dateTime = DateTime.fromJSDate(date);
return dateTime.toFormat(format);
}

public formatDateLocale(date: Date, presetName?: string, locale?: string): string {
let dateTime = DateTime.fromJSDate(date);

if (locale != undefined) {
dateTime = dateTime.setLocale(locale);
} else {
dateTime = dateTime.setLocale(navigator.language);
}

if (presetName != undefined) {
const preset: Intl.DateTimeFormatOptions = this.presetMap[presetName]
return dateTime.toLocaleString(preset);
}
return dateTime.toLocaleString();
}

public parseDateString(dateString: string, format?: string): Date {
if (format != undefined) {
const dt = DateTime.fromFormat(dateString, format);
return dt.toJSDate();
}
return new Date(Date.parse(dateString));
}

public numberFormat(number: number, locale: string = '', options: any = undefined): string {
if (_isEmpty(locale)) {
return new Intl.NumberFormat().format(number);
} else {
return new Intl.NumberFormat(locale, options).format(number);
}
}

public runTemplate(data: any, config: any, additionalImports: any = {}, field: any = undefined) {
// TO-DO: deprecate numberFormat as it can be accessed via util
let imports = _extend({ data: data, config: config, DateTime: DateTime, numberFormat: this.numberFormat, field: field, util: this, _: this.lodashWrapper }, this);
imports = _merge(imports, additionalImports);
const templateData = { imports: imports };
const template = _template(config.template, templateData);
const templateRes = template();
// added ability to parse the string template result into JSON
// requirement: template must return a valid JSON string object
if (config.json == true && !_isEmpty(templateRes)) {
return JSON.parse(templateRes);
}
return templateRes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { UtilityService } from './utility.service';
import { isEmpty as _isEmpty, get as _get, merge as _merge, template as _template } from 'lodash-es';
import { RecordPropViewMeta, RecordSource, RecordPage } from './record.model';
import { DateTime } from 'luxon';
import { LoDashTemplateUtilityService } from './lodash-template-utility.service';
/**
* This component displays records in a table.
*
Expand Down Expand Up @@ -60,6 +61,7 @@ export class RecordTableComponent extends BaseComponent {
constructor(
@Inject(LoggerService) private loggerService: LoggerService,
@Inject(UtilityService) private utilService: UtilityService,
@Inject(LoDashTemplateUtilityService) private lodashTemplateUtilityService: LoDashTemplateUtilityService,
) {
super();
// no deps
Expand Down Expand Up @@ -95,7 +97,7 @@ export class RecordTableComponent extends BaseComponent {
},
optTemplateData: this.optTemplateData
});
retVal = this.utilService.runTemplate(data, {template: col.template}, null);
retVal = this.lodashTemplateUtilityService.runTemplate(data, {template: col.template});
} else {
retVal = _get(row, col.property, val);
}
Expand Down
Loading

0 comments on commit 206bb99

Please sign in to comment.