[APPS-2108] migrate analytics report to date-fns (#8985)

* migrate analytics report to date-fns

* migrate bar chart model
This commit is contained in:
Denys Vuika
2023-10-10 16:14:31 +01:00
committed by GitHub
parent f6d48cb85c
commit a86b9e625c
4 changed files with 166 additions and 108 deletions

View File

@@ -19,7 +19,7 @@ import { SimpleChange } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
import { ReportParametersModel } from '../../diagram/models/report/report-parameters.model';
import * as analyticParamsMock from '../../mock';
import { AnalyticsReportParametersComponent } from '../components/analytics-report-parameters.component';
import { AnalyticsReportParametersComponent, ReportFormValues } from '../components/analytics-report-parameters.component';
import { InsightsTestingModule } from '../../testing/insights.testing.module';
import { AnalyticsService } from '../services/analytics.service';
import { of } from 'rxjs';
@@ -61,7 +61,7 @@ describe('AnalyticsReportParametersComponent', () => {
it('Should initialize the Report form with a Form Group ', async () => {
const fakeReportParam = new ReportParametersModel(analyticParamsMock.reportDefParamTask);
await component.successReportParams.subscribe(() => {
component.successReportParams.subscribe(() => {
fixture.detectChanges();
expect(component.reportForm.get('taskGroup')).toBeDefined();
expect(component.reportForm.get('taskGroup').get('taskName')).toBeDefined();
@@ -70,7 +70,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should render a dropdown with all the status when the definition parameter type is \'status\' ', async () => {
await component.successReportParams.subscribe(() => {
component.successReportParams.subscribe(() => {
fixture.detectChanges();
const dropDown: any = element.querySelector('#select-status');
expect(element.querySelector('h4').textContent.trim()).toEqual('Fake Task overview status');
@@ -94,7 +94,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should render a number with the default value when the definition parameter type is \'integer\' ', async () => {
await component.successReportParams.subscribe(() => {
component.successReportParams.subscribe(() => {
fixture.detectChanges();
const numberElement: any = element.querySelector('#slowProcessInstanceInteger');
expect(numberElement.value).toEqual('10');
@@ -112,7 +112,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should render a duration component when the definition parameter type is "duration"', async () => {
await component.successReportParams.subscribe(() => {
component.successReportParams.subscribe(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
const numberElement: any = element.querySelector('#duration');
@@ -147,12 +147,12 @@ describe('AnalyticsReportParametersComponent', () => {
expect(res.processDefinitionId).toEqual('FakeProcess:1:22');
expect(res.taskName).toEqual('FakeTaskName');
expect(res.duration).toEqual(22);
expect(res.dateRangeInterval).toEqual(120);
expect(res.dateRangeInterval).toEqual('120');
expect(res.slowProcessInstanceInteger).toEqual(2);
expect(res.typeFiltering).toEqual(true);
});
const values: any = {
const values: ReportFormValues = {
dateRange: {
startDate: '2016-09-01', endDate: '2016-10-05'
},
@@ -169,10 +169,10 @@ describe('AnalyticsReportParametersComponent', () => {
duration: 22
},
dateIntervalGroup: {
dateRangeInterval: 120
dateRangeInterval: '120'
},
processInstanceGroup: {
slowProcessInstanceInteger: 2
slowProcessInstanceInteger: '2'
},
typeFilteringGroup: {
typeFiltering: true
@@ -183,7 +183,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should render a checkbox with the value true when the definition parameter type is \'boolean\' ', async () => {
await component.successReportParams.subscribe(() => {
component.successReportParams.subscribe(() => {
fixture.detectChanges();
const checkElement: any = element.querySelector('#typeFiltering-input');
expect(checkElement.checked).toBeTruthy();
@@ -201,7 +201,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should render a date range components when the definition parameter type is \'dateRange\' ', async () => {
await component.successReportParams.subscribe(() => {
component.successReportParams.subscribe(() => {
const dateElement: any = element.querySelector('adf-date-range-widget');
expect(dateElement).toBeDefined();
});
@@ -219,7 +219,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should render a dropdown with all the RangeInterval when the definition parameter type is \'dateRangeInterval\' ', async () => {
await component.successReportParams.subscribe(() => {
component.successReportParams.subscribe(() => {
fixture.detectChanges();
const dropDown: any = element.querySelector('#select-dateRangeInterval');
expect(dropDown).toBeDefined();
@@ -244,7 +244,7 @@ describe('AnalyticsReportParametersComponent', () => {
it('Should render a dropdown with all the process definition when the definition parameter type is \'processDefinition\' and the' +
' reportId change', async () => {
await component.successParamOpt.subscribe(() => {
component.successParamOpt.subscribe(() => {
fixture.detectChanges();
const dropDown: any = element.querySelector('#select-processDefinitionId');
expect(dropDown).toBeDefined();
@@ -276,7 +276,7 @@ describe('AnalyticsReportParametersComponent', () => {
it('Should render a dropdown with all the process definition when the definition parameter type is \'processDefinition\' and the' +
' appId change', async () => {
await component.successParamOpt.subscribe(() => {
component.successParamOpt.subscribe(() => {
fixture.detectChanges();
const dropDown: any = element.querySelector('#select-processDefinitionId');
expect(dropDown).toBeDefined();
@@ -347,7 +347,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should emit an error with a 404 response when the options response is not found', async () => {
await component.error.subscribe((err) => {
component.error.subscribe((err) => {
expect(err).toBeDefined();
});
@@ -370,7 +370,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should emit an error with a 404 response when the report parameters response is not found', async () => {
await component.error.subscribe((err) => {
component.error.subscribe((err) => {
expect(err).toBeDefined();
});
@@ -386,7 +386,7 @@ describe('AnalyticsReportParametersComponent', () => {
});
it('Should convert a string in number', () => {
const numberConvert = component.convertNumber('2');
const numberConvert = component.parseNumber('2');
expect(numberConvert).toEqual(2);
});

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { DownloadService, LogService } from '@alfresco/adf-core';
import { AdfDateFnsAdapter, DownloadService, LogService } from '@alfresco/adf-core';
import {
AfterContentChecked,
Component,
@@ -29,10 +29,8 @@ import {
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import moment from 'moment';
import { ParameterValueModel } from '../../diagram/models/report/parameter-value.model';
import { ReportParameterDetailsModel } from '../../diagram/models/report/report-parameter-details.model';
import { ReportParametersModel } from '../../diagram/models/report/report-parameters.model';
import { ReportQuery } from '../../diagram/models/report/report-query.model';
@@ -42,6 +40,62 @@ import { takeUntil } from 'rxjs/operators';
const FORMAT_DATE_ACTIVITI = 'YYYY-MM-DD';
export interface ReportFormProps {
taskGroup?: FormGroup<{
taskName: FormControl<string | null>;
}>;
processDefGroup?: FormGroup<{
processDefinitionId: FormControl<string | null>;
}>;
dateIntervalGroup?: FormGroup<{
dateRangeInterval: FormControl<string | null>;
}>;
dateRange?: FormGroup<{
startDate?: FormControl<string | null>;
endDate?: FormControl<string | null>;
}>;
statusGroup?: FormGroup<{
status: FormControl<string | null>;
}>;
typeFilteringGroup?: FormGroup<{
typeFiltering: FormControl<boolean | null>;
}>;
durationGroup?: FormGroup<{
duration: FormControl<number | null>;
}>;
processInstanceGroup?: FormGroup<{
slowProcessInstanceInteger: FormControl<string | null>;
}>;
}
export interface ReportFormValues {
taskGroup?: {
taskName?: string;
};
processDefGroup?: {
processDefinitionId?: string;
};
dateIntervalGroup?: {
dateRangeInterval?: string;
};
dateRange?: {
startDate?: string;
endDate?: string;
};
statusGroup?: {
status?: string;
};
typeFilteringGroup?: {
typeFiltering?: boolean;
};
durationGroup?: {
duration?: number;
};
processInstanceGroup?: {
slowProcessInstanceInteger?: string;
};
}
@Component({
selector: 'adf-analytics-report-parameters',
templateUrl: './analytics-report-parameters.component.html',
@@ -63,7 +117,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
/** success. */
@Output()
success = new EventEmitter();
success = new EventEmitter<ReportQuery>();
/** error. */
@Output()
@@ -88,12 +142,12 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
@ViewChild('reportNameDialog')
reportNameDialog: any;
onDropdownChanged = new EventEmitter();
onDropdownChanged = new EventEmitter<ReportParameterDetailsModel>();
successReportParams = new EventEmitter<ReportParametersModel>();
successParamOpt = new EventEmitter();
reportParameters: ReportParametersModel;
reportForm: UntypedFormGroup;
reportForm: FormGroup<ReportFormProps>;
action: string;
isEditable: boolean = false;
reportName: string;
@@ -105,10 +159,11 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
constructor(
private analyticsService: AnalyticsService,
private formBuilder: UntypedFormBuilder,
private formBuilder: FormBuilder,
private logService: LogService,
private downloadService: DownloadService,
private dialog: MatDialog
private dialog: MatDialog,
private dateAdapter: AdfDateFnsAdapter
) {}
ngOnInit() {
@@ -152,7 +207,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
if (this.reportParameters.hasParameters()) {
this.successReportParams.emit(res);
} else {
this.reportForm = this.formBuilder.group({});
this.reportForm = this.formBuilder.group<ReportFormProps>({});
this.success.emit();
}
},
@@ -162,18 +217,18 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
);
}
onProcessDefinitionChanges(field: any) {
onProcessDefinitionChanges(field: ReportParameterDetailsModel) {
if (field.value) {
this.onDropdownChanged.emit(field);
}
}
public submit(values: any) {
public submit(values: ReportFormValues) {
this.reportParamQuery = this.convertFormValuesToReportParamQuery(values);
this.success.emit(this.reportParamQuery);
}
onValueChanged(values: any) {
onValueChanged(values: ReportFormValues) {
this.formValueChanged.emit(values);
if (this.reportForm?.valid) {
this.submit(values);
@@ -186,23 +241,20 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
}
}
convertMomentDate(date: string) {
return moment(date, FORMAT_DATE_ACTIVITI, true).format(FORMAT_DATE_ACTIVITI) + 'T00:00:00.000Z';
private parseDate(input: string) {
const date = this.dateAdapter.parse(input, FORMAT_DATE_ACTIVITI);
return this.dateAdapter.format(date, FORMAT_DATE_ACTIVITI) + 'T00:00:00.000Z';
}
getTodayDate() {
return moment().format(FORMAT_DATE_ACTIVITI);
}
convertNumber(value: string): number {
parseNumber(value: string): number {
return value != null ? parseInt(value, 10) : 0;
}
convertFormValuesToReportParamQuery(values: any): ReportQuery {
const reportParamQuery: ReportQuery = new ReportQuery();
private convertFormValuesToReportParamQuery(values: ReportFormValues): ReportQuery {
const reportParamQuery = new ReportQuery();
if (values.dateRange) {
reportParamQuery.dateRange.startDate = this.convertMomentDate(values.dateRange.startDate);
reportParamQuery.dateRange.endDate = this.convertMomentDate(values.dateRange.endDate);
reportParamQuery.dateRange.startDate = this.parseDate(values.dateRange.startDate);
reportParamQuery.dateRange.endDate = this.parseDate(values.dateRange.endDate);
}
if (values.statusGroup) {
reportParamQuery.status = values.statusGroup.status;
@@ -220,7 +272,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
reportParamQuery.dateRangeInterval = values.dateIntervalGroup.dateRangeInterval;
}
if (values.processInstanceGroup) {
reportParamQuery.slowProcessInstanceInteger = this.convertNumber(values.processInstanceGroup.slowProcessInstanceInteger);
reportParamQuery.slowProcessInstanceInteger = this.parseNumber(values.processInstanceGroup.slowProcessInstanceInteger);
}
if (values.typeFilteringGroup) {
reportParamQuery.typeFiltering = values.typeFilteringGroup.typeFiltering;
@@ -256,7 +308,9 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
showDialog(event: string) {
this.dialog.open(this.reportNameDialog, { width: '500px' });
this.action = event;
this.reportName = this.reportParameters.name + ' ( ' + this.getTodayDate() + ' )';
const date = this.dateAdapter.format(new Date(), FORMAT_DATE_ACTIVITI);
this.reportName = `${this.reportParameters.name} ( ${date} )`;
}
closeDialog() {
@@ -274,23 +328,23 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
this.resetActions();
}
resetActions() {
private resetActions() {
this.action = '';
this.reportName = '';
}
isSaveAction() {
isSaveAction(): boolean {
return this.action === 'Save';
}
doExport(paramQuery: ReportQuery) {
private doExport(paramQuery: ReportQuery) {
this.analyticsService.exportReportToCsv(this.reportId, paramQuery).subscribe((data: any) => {
const blob: Blob = new Blob([data], { type: 'text/csv' });
this.downloadService.downloadBlob(blob, paramQuery.reportName + '.csv');
});
}
doSave(paramQuery: ReportQuery) {
private doSave(paramQuery: ReportQuery) {
this.analyticsService.saveReport(this.reportId, paramQuery).subscribe(() => {
this.saveReportSuccess.emit(this.reportId);
});
@@ -315,105 +369,106 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
this.hideParameters = !this.hideParameters;
}
isParametersHide() {
isParametersHide(): boolean {
return this.hideParameters;
}
isFormValid() {
isFormValid(): boolean {
return this.reportForm?.dirty && this.reportForm.valid;
}
get taskGroup(): UntypedFormGroup {
return this.reportForm.controls.taskGroup as UntypedFormGroup;
get taskGroup(): FormGroup {
return this.reportForm.controls.taskGroup;
}
get processDefGroup(): UntypedFormGroup {
return this.reportForm.controls.processDefGroup as UntypedFormGroup;
get processDefGroup(): FormGroup {
return this.reportForm.controls.processDefGroup;
}
get dateIntervalGroup(): UntypedFormGroup {
return this.reportForm.controls.dateIntervalGroup as UntypedFormGroup;
get dateIntervalGroup(): FormGroup {
return this.reportForm.controls.dateIntervalGroup;
}
get dateRange(): UntypedFormGroup {
return this.reportForm.controls.dateRange as UntypedFormGroup;
get dateRange(): FormGroup {
return this.reportForm.controls.dateRange;
}
get statusGroup(): UntypedFormGroup {
return this.reportForm.controls.statusGroup as UntypedFormGroup;
get statusGroup(): FormGroup {
return this.reportForm.controls.statusGroup;
}
get typeFilteringGroup(): UntypedFormGroup {
return this.reportForm.controls.typeFilteringGroup as UntypedFormGroup;
get typeFilteringGroup(): FormGroup {
return this.reportForm.controls.typeFilteringGroup;
}
get durationGroup(): UntypedFormGroup {
return this.reportForm.controls.durationGroup as UntypedFormGroup;
get durationGroup(): FormGroup {
return this.reportForm.controls.durationGroup;
}
get processInstanceGroup(): UntypedFormGroup {
return this.reportForm.controls.processInstanceGroup as UntypedFormGroup;
get processInstanceGroup(): FormGroup {
return this.reportForm.controls.processInstanceGroup;
}
private generateFormGroupFromParameter(parameters: ReportParameterDetailsModel[]) {
const formBuilderGroup: any = {};
parameters.forEach((param: ReportParameterDetailsModel) => {
const formBuilderGroup: ReportFormProps = {};
parameters.forEach((param) => {
switch (param.type) {
case 'dateRange':
formBuilderGroup.dateRange = new UntypedFormGroup({}, Validators.required);
formBuilderGroup.dateRange = new FormGroup({}, Validators.required);
break;
case 'processDefinition':
formBuilderGroup.processDefGroup = new UntypedFormGroup(
formBuilderGroup.processDefGroup = new FormGroup(
{
processDefinitionId: new UntypedFormControl(null, Validators.required, null)
processDefinitionId: new FormControl(null, Validators.required, null)
},
Validators.required
);
break;
case 'duration':
formBuilderGroup.durationGroup = new UntypedFormGroup(
formBuilderGroup.durationGroup = new FormGroup(
{
duration: new UntypedFormControl(null, Validators.required, null)
duration: new FormControl(null, Validators.required, null)
},
Validators.required
);
break;
case 'dateInterval':
formBuilderGroup.dateIntervalGroup = new UntypedFormGroup(
formBuilderGroup.dateIntervalGroup = new FormGroup(
{
dateRangeInterval: new UntypedFormControl(null, Validators.required, null)
dateRangeInterval: new FormControl(null, Validators.required, null)
},
Validators.required
);
break;
case 'boolean':
formBuilderGroup.typeFilteringGroup = new UntypedFormGroup(
formBuilderGroup.typeFilteringGroup = new FormGroup(
{
typeFiltering: new UntypedFormControl(null, Validators.required, null)
typeFiltering: new FormControl(null, Validators.required, null)
},
Validators.required
);
break;
case 'task':
formBuilderGroup.taskGroup = new UntypedFormGroup(
formBuilderGroup.taskGroup = new FormGroup(
{
taskName: new UntypedFormControl(null, Validators.required, null)
taskName: new FormControl(null, Validators.required, null)
},
Validators.required
);
break;
case 'integer':
formBuilderGroup.processInstanceGroup = new UntypedFormGroup(
formBuilderGroup.processInstanceGroup = new FormGroup(
{
slowProcessInstanceInteger: new UntypedFormControl(null, Validators.required, null)
slowProcessInstanceInteger: new FormControl(null, Validators.required, null)
},
Validators.required
);
break;
case 'status':
formBuilderGroup.statusGroup = new UntypedFormGroup(
formBuilderGroup.statusGroup = new FormGroup(
{
status: new UntypedFormControl(null, Validators.required, null)
status: new FormControl(null, Validators.required, null)
},
Validators.required
);
@@ -422,7 +477,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
return;
}
});
this.reportForm = this.formBuilder.group(formBuilderGroup);
this.reportForm = this.formBuilder.group<ReportFormProps>(formBuilderGroup);
this.reportForm.valueChanges.subscribe((data) => this.onValueChanged(data));
this.reportForm.statusChanges.subscribe(() => this.onStatusChanged());
}
@@ -430,7 +485,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On
private retrieveParameterOptions(parameters: ReportParameterDetailsModel[], appId: number, reportId?: string, processDefinitionId?: string) {
parameters.forEach((param) => {
this.analyticsService.getParamValuesByType(param.type, appId, reportId, processDefinitionId).subscribe(
(opts: ParameterValueModel[]) => {
(opts) => {
param.options = opts;
this.successParamOpt.emit(opts);
},

View File

@@ -15,8 +15,8 @@
* limitations under the License.
*/
import moment from 'moment';
import { Chart } from './chart.model';
import { format } from 'date-fns';
export class BarChart extends Chart {
xAxisType: string;
@@ -24,17 +24,20 @@ export class BarChart extends Chart {
options: any = {
responsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
yAxes: [
{
ticks: {
beginAtZero: true,
stepSize: 1
}
}
}],
xAxes: [{
ticks: {
},
stacked: false
}]
],
xAxes: [
{
ticks: {},
stacked: false
}
]
}
};
@@ -59,30 +62,30 @@ export class BarChart extends Chart {
});
});
if (dataValue && dataValue.length > 0) {
this.datasets.push({data: dataValue, label: params.key});
this.datasets.push({ data: dataValue, label: params.key });
}
});
}
}
xAxisTickFormatFunction(xAxisType) {
return (value) => {
if (xAxisType !== null && xAxisType !== undefined) {
xAxisTickFormatFunction(xAxisType: string) {
return (value: string) => {
if (xAxisType) {
if ('date_day' === xAxisType) {
return moment(new Date(value)).format('DD');
return format(new Date(value), 'dd');
} else if ('date_month' === xAxisType) {
return moment(new Date(value)).format('MMMM');
return format(new Date(value), 'MMMM');
} else if ('date_year' === xAxisType) {
return moment(new Date(value)).format('YYYY');
return format(new Date(value), 'yyyy');
}
}
return value;
};
};
}
yAxisTickFormatFunction(yAxisType) {
return (value) => {
if (yAxisType !== null && yAxisType !== undefined) {
yAxisTickFormatFunction(yAxisType: string) {
return (value: string) => {
if (yAxisType) {
if ('count' === yAxisType) {
const label = '' + value;
if (label.indexOf('.') !== -1) {
@@ -92,5 +95,5 @@ export class BarChart extends Chart {
}
return value;
};
};
}
}

View File

@@ -33,7 +33,7 @@ import {
imports: [
NoopAnimationsModule,
TranslateModule,
CoreModule,
CoreModule.forRoot(),
InsightsModule
],
providers: [