diff --git a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html index a9a9a45019..eb25883a76 100644 --- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html +++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html @@ -69,7 +69,7 @@
- +
diff --git a/ng2-components/ng2-activiti-analytics/karma-test-shim.js b/ng2-components/ng2-activiti-analytics/karma-test-shim.js index c9d37f3aa2..e109df798c 100644 --- a/ng2-components/ng2-activiti-analytics/karma-test-shim.js +++ b/ng2-components/ng2-activiti-analytics/karma-test-shim.js @@ -53,6 +53,7 @@ var map = { 'rxjs': 'npm:rxjs', 'ng2-translate': 'npm:ng2-translate', 'ng2-charts' : 'npm:ng2-charts', + 'md-date-time-picker' : 'npm:md-date-time-picker', 'moment' : 'npm:moment/min/moment.min.js', 'alfresco-js-api': 'npm:alfresco-js-api/dist', @@ -65,6 +66,7 @@ var packages = { 'rxjs': { defaultExtension: 'js' }, 'ng2-translate': { defaultExtension: 'js' }, 'ng2-charts': { defaultExtension: 'js' }, + 'md-date-time-picker': { defaultExtension: 'js' }, 'moment': { defaultExtension: 'js' }, 'alfresco-js-api': { main: './alfresco-js-api.js', defaultExtension: 'js'}, diff --git a/ng2-components/ng2-activiti-analytics/karma.conf.js b/ng2-components/ng2-activiti-analytics/karma.conf.js index 49636788ba..db5a72000c 100644 --- a/ng2-components/ng2-activiti-analytics/karma.conf.js +++ b/ng2-components/ng2-activiti-analytics/karma.conf.js @@ -33,6 +33,9 @@ module.exports = function (config) { {pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false}, 'node_modules/alfresco-js-api/dist/alfresco-js-api.js', + 'node_modules/moment/min/moment.min.js', + 'node_modules/md-date-time-picker/dist/js/mdDateTimePicker.js', + 'node_modules/chart.js/dist/Chart.bundle.min.js', {pattern: 'node_modules/ng2-translate/**/*.js', included: false, watched: false}, 'karma-test-shim.js', @@ -45,6 +48,7 @@ module.exports = function (config) { // ng2-components { pattern: 'node_modules/ng2-alfresco-core/dist/**/*.*', included: false, served: true, watched: false }, { pattern: 'node_modules/ng2-charts/**/*.js', included: false, served: true, watched: false }, + { pattern: 'node_modules/md-date-time-picker/**/*.js', included: false, served: true, watched: false }, { pattern: 'node_modules/moment/**/*.js', included: false, served: true, watched: false }, // paths to support debugging with source maps in dev tools diff --git a/ng2-components/ng2-activiti-analytics/src/assets/analyticsComponent.mock.ts b/ng2-components/ng2-activiti-analytics/src/assets/analyticsComponent.mock.ts new file mode 100644 index 0000000000..606fca6c11 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/assets/analyticsComponent.mock.ts @@ -0,0 +1,255 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ReportParameterModel } from '../models/report.model'; + +export var reportDefParamStatus = { + 'id': 2005, + 'name': 'Fake Task overview status', + 'created': '2016-10-05T15:39:40.222+0000', + 'definition': '{ "parameters" :[{"id":"status","name":null,"nameKey":null,"type":"status","value":null,"dependsOn":null}]}' +}; + +export var reportDefParamNumber = { + 'id': 2005, + 'name': 'Fake Process instances overview', + 'created': '2016-10-05T15:39:40.222+0000', + 'definition': '{ "parameters"' + + ' :[{"id":"slowProcessInstanceInteger","name":null,"nameKey":null,"type":"integer","value":10,"dependsOn":null}]}' +}; + +export var reportDefParamDuration = { + 'id': 2005, + 'name': 'Fake Task service level agreement', + 'created': '2016-10-05T15:39:40.222+0000', + 'definition': '{ "parameters"' + + ' :[{"id":"duration","name":null,"nameKey":null,"type":"duration","value":null,"dependsOn":null}]}' +}; + +export var reportDefParamCheck = { + 'id': 2005, + 'name': 'Fake Task service level agreement', + 'created': '2016-10-05T15:39:40.222+0000', + 'definition': '{ "parameters"' + + ' :[{"id":"typeFiltering","name":null,"nameKey":null,"type":"boolean","value":true,"dependsOn":null}]}' +}; + +export var reportDefParamDateRange = { + 'id': 2005, + 'name': 'Fake Process instances overview', + 'created': '2016-10-05T15:39:40.222+0000', + 'definition': '{ "parameters" :[{"id":"dateRange","name":null,"nameKey":null,"type":"dateRange","value":null,"dependsOn":null}]}' +}; + +export var reportDefParamRangeInterval = { + 'id': 2006, + 'name': 'Fake Task overview RangeInterval', + 'created': '2016-10-05T15:39:40.222+0000', + 'definition': '{ "parameters" :[{"id":"dateRangeInterval","name":null,"nameKey":null,"type":"dateInterval","value":null,"dependsOn":null}]}' +}; + +export var reportDefParamProcessDef = { + 'id': 2006, + 'name': 'Fake Task overview ProcessDefinition', + 'created': '2016-10-05T15:39:40.222+0000', + 'definition': '{ "parameters" :[{"id":"processDefinitionId","name":null,"nameKey":null,"type":"processDefinition","value":null,"dependsOn":null}]}' +}; + +export var reportDefParamProcessDefOptions = { + 'size': 4, 'total': 4, 'start': 0, 'data': [ + { + 'id': 'FakeProcessTest 1:1:1', + 'name': 'Fake Process Test 1 Name ', + 'version': 1 + }, + { + 'id': 'FakeProcessTest 1:2:1', + 'name': 'Fake Process Test 1 Name ', + 'version': 2 + }, + { + 'id': 'FakeProcessTest 2:1:1', + 'name': 'Fake Process Test 2 Name ', + 'version': 1 + }, + { + 'id': 'FakeProcessTest 3:1:1', + 'name': 'Fake Process Test 3 Name ', + 'version': 1 + } + ] +}; + +export var reportDefParamProcessDefOptionsApp = { + 'size': 2, 'total': 2, 'start': 2, 'data': [ + { + 'id': 'FakeProcessTest 1:1:1', + 'name': 'Fake Process Test 1 Name ', + 'version': 1 + }, + { + 'id': 'FakeProcessTest 1:2:1', + 'name': 'Fake Process Test 1 Name ', + 'version': 2 + } + ] +}; + +export var reportDefParamTask = { + 'id': 2006, + 'name': 'Fake Task service level agreement', + 'created': '2016-10-05T15:39:40.222+0000', + 'definition': '{ "parameters" :[{"id":"taskName","name":null,"nameKey":null,"type":"task","value":null,"dependsOn":"processDefinitionId"}]}' +}; + +export var reportDefParamTaskOptions = ['Fake task name 1', 'Fake task name 2']; + +export var chartProcessDefOverview = { + 'elements': [{ + 'id': 'id1585876275153', + 'type': 'table', + 'rows': [ + ['__KEY_REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.GENERAL-TABLE-TOTAL-PROCESS-DEFINITIONS', '9'], + ['__KEY_REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.GENERAL-TABLE-TOTAL-PROCESS-INSTANCES', '41'], + ['__KEY_REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.GENERAL-TABLE-ACTIVE-PROCESS-INSTANCES', '3'], + ['__KEY_REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.GENERAL-TABLE-COMPLETED-PROCESS-INSTANCES', '38'] + ] + }, { + 'id': 'id1585876413072', + 'type': 'pieChart', + 'title': 'Total process instances overview', + 'titleKey': 'REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.PROC-INST-CHART-TITLE', + 'values': [{ + 'key': 'Second Process', + 'y': 4, + 'keyAndValue': ['Second Process', '4'] + }, { + 'key': 'Simple process', + 'y': 30, + 'keyAndValue': ['Simple process', '30'] + }, { + 'key': 'Third Process', + 'y': 7, + 'keyAndValue': ['Third Process', '7'] + }] + }, { + 'id': 'id1585877659181', + 'type': 'table', + 'title': 'Process definition details', + 'titleKey': 'REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.DETAIL-TABLE', + 'columnNames': ['Process definition', 'Total', 'Active', 'Completed'], + 'columnNameKeys': ['REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.DETAIL-TABLE-PROCESS', + 'REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.DETAIL-TABLE-TOTAL', + 'REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.DETAIL-TABLE-ACTIVE', + 'REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.DETAIL-TABLE-COMPLETED'], + 'columnsCentered': [false, false, false, false], + 'rows': [ + ['Second Process', '4', '0', '4'], + ['Simple process', '30', '3', '27'], + ['Third Process', '7', '0', '7'] + ] + }] +}; + +export var chartTaskOverview = { + 'elements': [{ + 'id': 'id792351752194', + 'type': 'barChart', + 'title': 'title', + 'titleKey': 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.TASK-HISTOGRAM-TITLE', + 'values': [{ + 'key': 'series1', + 'values': [['2016-09-30T00:00:00.000+0000', 3], ['2016-10-04T00:00:00.000+0000', 1]] + }], + 'xAxisType': 'date_month', + 'yAxisType': 'count' + }, { + 'id': 'id792349721129', + 'type': 'masterDetailTable', + 'title': 'Detailed task statistics', + 'titleKey': 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.DETAILED-TASK-STATS-TITLE', + 'columnNames': ['Task', 'Count', 'Sum', 'Min duration', 'Max duration', 'Average duration', 'Stddev duration'], + 'columnNameKeys': [ + 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.DETAILED-TASK-STATS-TASK', + 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.COUNT', + 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.SUM', + 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.MIN-DURATION', + 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.MAX-DURATION', + 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.AVERAGE', + 'REPORTING.DEFAULT-REPORTS.TASK-OVERVIEW.STDDE'], + 'columnsCentered': [false, false, false, false], + 'rows': [ + ['fake 1 user task', '1', '2.0', '3.0', '4.0', '5.0', '6.0'], + ['fake 2 user task', '1', '2.0', '3.0', '4.0', '5.0', '6.0'] + ] + }] +}; + +export var fieldNumber = new ReportParameterModel( + { + id: 'slowProcessInstanceInteger', + type: 'integer', + value: '102' + } +); + +export var fieldStatus = new ReportParameterModel( + { + id: 'status', + type: 'status', + value: 'fake-value' + } +); + +export var fieldTypeFiltering = new ReportParameterModel( + { + id: 'typeFiltering', + type: 'boolean', + value: false + } +); + +export var fieldTask = new ReportParameterModel( + { + id: 'taskName', + type: 'task', + value: 'fake-task-name' + } +); + +export var fieldDateRange = { + startDate: '2016-10-12T00:00:00.000Z', + endDate: '2016-10-14T00:00:00.000Z' +}; + +export var fieldDateRangeInterval = new ReportParameterModel( + { + id: 'dateRangeInterval', + type: 'dateInterval', + value: 'fake-date-interval' + } +); + +export var fieldProcessDef = new ReportParameterModel( + { + id: 'processDefinitionId', + type: 'processDefinition', + value: 'fake-process-name:1:15027' + } +); + +export var fieldDuration = {value: 30}; diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.ts index a80a98d4ff..2445989824 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.ts @@ -71,8 +71,7 @@ export class AnalyticsReportListComponent implements OnInit { (err: any) => { this.onError.emit(err); console.log(err); - }, - () => console.log('Reports loaded') + } ); } diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html index 9409f13586..93f958d5e5 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html @@ -50,11 +50,10 @@

-
-

ReportForm : {{ reportForm.value | json }}

ReportForm valid : {{ reportForm.valid }}

ReportForm status : {{ reportForm.errors | json }}

ReportForm FormGroup valid : {{ reportForm.controls.dateRange.valid | json }}

@@ -70,11 +69,11 @@ [data]="report.data" [datasets]="report.datasets" [labels]="report.labels" - [chartType]="report.type" - (chartClick)="chartClicked($event)"> + [chartType]="report.type">
+
@@ -83,6 +82,7 @@
{{label | translate}}{{row | translate }}
+
@@ -100,8 +100,7 @@ [datasets]="report.datasets" [labels]="report.labels" [options]="report.options" - [chartType]="report.type" - (chartClick)="chartClicked($event)"> + [chartType]="report.type">
diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.spec.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.spec.ts index f1bf40c4a9..47ff595574 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.spec.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.spec.ts @@ -26,8 +26,11 @@ import { WIDGET_DIRECTIVES } from '../components/widgets/index'; import { CHART_DIRECTIVES } from 'ng2-charts/ng2-charts'; import { AnalyticsService } from '../services/analytics.service'; - -import { DebugElement } from '@angular/core'; +import { ReportModel, ReportQuery } from '../models/report.model'; +import { Chart } from '../models/chart.model'; +import * as moment from 'moment'; +import { DebugElement, SimpleChange } from '@angular/core'; +import * as analyticMock from '../assets/analyticsComponent.mock'; export const ANALYTICS_DIRECTIVES: any[] = [ AnalyticsComponent, @@ -38,13 +41,18 @@ export const ANALYTICS_PROVIDERS: any[] = [ AnalyticsService ]; -describe('Show component HTML', () => { +declare let jasmine: any; +declare let mdDateTimePicker: any; + +describe('Test ng2-activiti-analytics Report ', () => { let component: any; let fixture: ComponentFixture; let debug: DebugElement; let element: HTMLElement; + let componentHandler: any; + beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ @@ -66,10 +74,483 @@ describe('Show component HTML', () => { debug = fixture.debugElement; element = fixture.nativeElement; fixture.detectChanges(); + componentHandler = jasmine.createSpyObj('componentHandler', [ + 'upgradeAllRegistered' + ]); + window['componentHandler'] = componentHandler; }); - it('Display component tag base-chart', () => { - expect(true).toBe(true); - }); + describe('Rendering tests', () => { + beforeEach(() => { + jasmine.Ajax.install(); + }); + afterEach(() => { + jasmine.Ajax.uninstall(); + }); + + it('Should initialize the Report form with a Form Group ', () => { + expect(component.reportForm.get('dateRange')).toBeDefined(); + expect(component.reportForm.get('dateRange').get('startDate')).toBeDefined(); + expect(component.reportForm.get('dateRange').get('endDate')).toBeDefined(); + }); + + it('Should render a dropdown with all the status when the definition parameter type is \'status\' ', (done) => { + component.onSuccessParamsReport.subscribe(() => { + fixture.detectChanges(); + let dropDown: any = element.querySelector('#select-status'); + expect(element.querySelector('h1').innerHTML).toEqual('Fake Task overview status'); + expect(dropDown).toBeDefined(); + expect(dropDown.length).toEqual(4); + expect(dropDown[0].innerHTML).toEqual('Choose One'); + expect(dropDown[1].innerHTML).toEqual('All'); + expect(dropDown[2].innerHTML).toEqual('Active'); + expect(dropDown[3].innerHTML).toEqual('Complete'); + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamStatus + }); + }); + + it('Should render a number with the default value when the definition parameter type is \'integer\' ', (done) => { + component.onSuccessParamsReport.subscribe(() => { + fixture.detectChanges(); + let numberElement: any = element.querySelector('#slowProcessInstanceInteger'); + expect(numberElement.value).toEqual('10'); + + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamNumber + }); + }); + + it('Should render a duration component when the definition parameter type is \'duration\' ', (done) => { + component.onSuccessParamsReport.subscribe(() => { + fixture.detectChanges(); + let numberElement: any = element.querySelector('#duration'); + expect(numberElement.value).toEqual('0'); + + let dropDown: any = element.querySelector('#select-duration'); + expect(dropDown).toBeDefined(); + expect(dropDown.length).toEqual(4); + expect(dropDown[0].innerHTML).toEqual('Seconds'); + expect(dropDown[1].innerHTML).toEqual('Minutes'); + expect(dropDown[2].innerHTML).toEqual('Hours'); + expect(dropDown[3].innerHTML).toEqual('Days'); + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamDuration + }); + }); + + it('Should render a checkbox with the value true when the definition parameter type is \'boolean\' ', (done) => { + component.onSuccessParamsReport.subscribe(() => { + fixture.detectChanges(); + let checkElement: any = element.querySelector('#typeFiltering'); + expect(checkElement.checked).toBeTruthy(); + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamCheck + }); + }); + + it('Should render a date range components when the definition parameter type is \'dateRange\' ', (done) => { + component.onSuccessParamsReport.subscribe(() => { + fixture.detectChanges(); + let today = moment().format('YYYY-MM-DD'); + + const startDate: any = element.querySelector('#startDateInput'); + const endDate: any = element.querySelector('#endDateInput'); + + expect(startDate.value).toEqual(today); + expect(endDate.value).toEqual(today); + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamDateRange + }); + }); + + it('Should render a dropdown with all the RangeInterval when the definition parameter type is \'dateRangeInterval\' ', (done) => { + component.onSuccessParamsReport.subscribe(() => { + fixture.detectChanges(); + let dropDown: any = element.querySelector('#select-dateRangeInterval'); + expect(dropDown).toBeDefined(); + expect(dropDown.length).toEqual(5); + expect(dropDown[0].innerHTML).toEqual('By hour'); + expect(dropDown[1].innerHTML).toEqual('By day'); + expect(dropDown[2].innerHTML).toEqual('By week'); + expect(dropDown[3].innerHTML).toEqual('By month'); + expect(dropDown[4].innerHTML).toEqual('By year'); + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamRangeInterval + }); + }); + + it('Should render a dropdown with all the process definition when the definition parameter type is \'processDefinition\' and the' + + ' reportId change', (done) => { + component.onSuccessParamOpt.subscribe(() => { + fixture.detectChanges(); + let dropDown: any = element.querySelector('#select-processDefinitionId'); + expect(dropDown).toBeDefined(); + expect(dropDown.length).toEqual(5); + expect(dropDown[0].innerHTML).toEqual('Choose One'); + expect(dropDown[1].innerHTML).toEqual('Fake Process Test 1 Name (v 1) '); + expect(dropDown[2].innerHTML).toEqual('Fake Process Test 1 Name (v 2) '); + expect(dropDown[3].innerHTML).toEqual('Fake Process Test 2 Name (v 1) '); + expect(dropDown[4].innerHTML).toEqual('Fake Process Test 3 Name (v 1) '); + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.first().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamProcessDef + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamProcessDefOptions + }); + }); + + it('Should render a dropdown with all the process definition when the definition parameter type is \'processDefinition\' and the' + + ' appId change', (done) => { + component.onSuccessParamOpt.subscribe(() => { + fixture.detectChanges(); + let dropDown: any = element.querySelector('#select-processDefinitionId'); + expect(dropDown).toBeDefined(); + expect(dropDown.length).toEqual(3); + expect(dropDown[0].innerHTML).toEqual('Choose One'); + expect(dropDown[1].innerHTML).toEqual('Fake Process Test 1 Name (v 1) '); + expect(dropDown[2].innerHTML).toEqual('Fake Process Test 1 Name (v 2) '); + done(); + }); + + let appId = 1; + component.appId = appId; + let change = new SimpleChange(null, appId); + component.ngOnChanges({ 'appId': change }); + + jasmine.Ajax.requests.first().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamProcessDef + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamProcessDefOptionsApp + }); + }); + + it('Should render the Process definition overview report ', (done) => { + component.onShowReport.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toEqual(3); + + expect(res[0]).toBeDefined(); + expect(res[0].type).toEqual('table'); + expect(res[0].datasets).toBeDefined(); + expect(res[0].datasets.length).toEqual(4); + expect(res[0].datasets[0][0]).toEqual('__KEY_REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.GENERAL-TABLE-TOTAL-PROCESS-DEFINITIONS'); + expect(res[0].datasets[0][1]).toEqual('9'); + expect(res[0].datasets[1][0]).toEqual('__KEY_REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.GENERAL-TABLE-TOTAL-PROCESS-INSTANCES'); + expect(res[0].datasets[1][1]).toEqual('41'); + expect(res[0].datasets[2][0]).toEqual('__KEY_REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.GENERAL-TABLE-ACTIVE-PROCESS-INSTANCES'); + expect(res[0].datasets[2][1]).toEqual('3'); + expect(res[0].datasets[3][0]).toEqual('__KEY_REPORTING.DEFAULT-REPORTS.PROCESS-DEFINITION-OVERVIEW.GENERAL-TABLE-COMPLETED-PROCESS-INSTANCES'); + expect(res[0].datasets[3][1]).toEqual('38'); + + expect(res[1]).toBeDefined(); + expect(res[1].type).toEqual('pie'); + + expect(res[2]).toBeDefined(); + expect(res[2].type).toEqual('table'); + + done(); + }); + + component.reportDetails = new ReportModel({ + id: 1, + definition: + '{ "parameters" :[{"id":"status","type":"status", "options": [{"id": "all", "name" :"all"}],"value":null}]}' + }); + + component.reportParamQuery = new ReportQuery({status: 'All'}); + component.showReport(); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.chartProcessDefOverview + }); + }); + + it('Should render the Task overview report ', (done) => { + component.onShowReport.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toEqual(2); + + expect(res[0]).toBeDefined(); + expect(res[0].type).toEqual('bar'); + expect(res[0].labels).toBeDefined(); + expect(res[0].labels.length).toEqual(2); + expect(res[0].labels[0]).toEqual('2016-09-30T00:00:00.000+0000'); + expect(res[0].labels[1]).toEqual('2016-10-04T00:00:00.000+0000'); + expect(res[0].datasets[0].label).toEqual('series1'); + expect(res[0].datasets[0].data[0]).toEqual(3); + expect(res[0].datasets[0].data[1]).toEqual(1); + + expect(res[1]).toBeDefined(); + expect(res[1].type).toEqual('table'); + expect(res[1].datasets).toBeDefined(); + expect(res[1].datasets.length).toEqual(2); + expect(res[1].datasets[0][0]).toEqual('fake 1 user task'); + expect(res[1].datasets[0][1]).toEqual('1'); + expect(res[1].datasets[0][2]).toEqual('2.0'); + expect(res[1].datasets[0][3]).toEqual('3.0'); + expect(res[1].datasets[0][4]).toEqual('4.0'); + expect(res[1].datasets[0][5]).toEqual('5.0'); + expect(res[1].datasets[0][6]).toEqual('6.0'); + expect(res[1].datasets[1][0]).toEqual('fake 2 user task'); + expect(res[1].datasets[1][1]).toEqual('1'); + expect(res[1].datasets[1][2]).toEqual('2.0'); + expect(res[1].datasets[1][3]).toEqual('3.0'); + expect(res[1].datasets[1][4]).toEqual('4.0'); + expect(res[1].datasets[1][5]).toEqual('5.0'); + expect(res[1].datasets[1][6]).toEqual('6.0'); + + done(); + }); + + component.reportDetails = new ReportModel({ + id: 1, + definition: + '{ "parameters" :[{"id":"status","type":"status", "options": [{"id": "all", "name" :"all"}],"value":null}]}' + }); + + component.reportParamQuery = new ReportQuery({status: 'All'}); + component.showReport(); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.chartTaskOverview + }); + }); + + it('Should reset the report and save the number value onNumberChanges method', () => { + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.onNumberChanges(analyticMock.fieldNumber); + + expect(component.reports).toBeNull(); + expect(component.reportParamQuery.slowProcessInstanceInteger).toEqual(102); + }); + + it('Should reset the report and save the duration value onDurationChanges method', () => { + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.onDurationChanges(analyticMock.fieldDuration); + + expect(component.reports).toBeNull(); + expect(component.reportParamQuery.duration).toEqual(30); + }); + + it('Should reset the report and save the status value onStatusChanges method', () => { + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.onStatusChanges(analyticMock.fieldStatus); + + expect(component.reports).toBeNull(); + expect(component.reportParamQuery.status).toEqual('fake-value'); + }); + + it('Should reset the report and save the typeFiltering value onTypeFilteringChanges method', () => { + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.onTypeFilteringChanges(analyticMock.fieldTypeFiltering); + + expect(component.reports).toBeNull(); + expect(component.reportParamQuery.typeFiltering).toBeFalsy(); + }); + + it('Should reset the report and save the taskName value onTaskChanges method', () => { + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.onTaskChanges(analyticMock.fieldTask); + + expect(component.reports).toBeNull(); + expect(component.reportParamQuery.taskName).toEqual('fake-task-name'); + }); + + it('Should reset the report and save the dateRange value onDateRangeChange method', () => { + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.onDateRangeChange(analyticMock.fieldDateRange); + + expect(component.reports).toBeNull(); + expect(component.reportParamQuery.dateRange.startDate).toEqual('2016-10-12T00:00:00.000Z'); + expect(component.reportParamQuery.dateRange.endDate).toEqual('2016-10-14T00:00:00.000Z'); + }); + + it('Should reset the report and save the dateRangeInterval value onDateRangeIntervalChange method', () => { + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.onDateRangeIntervalChange(analyticMock.fieldDateRangeInterval); + + expect(component.reports).toBeNull(); + expect(component.reportParamQuery.dateRangeInterval).toEqual('fake-date-interval'); + }); + + it('Should reset the report and save the processDefinitionId value onProcessDefinitionChanges method', () => { + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.reportDetails = new ReportModel({ + id: 1, + definition: + '{ "parameters" :[{"id":"processDefinitionId","type":"processDefinition","value":null}]}' + }); + component.onProcessDefinitionChanges(analyticMock.fieldProcessDef); + + expect(component.reports).toBeNull(); + expect(component.reportParamQuery.processDefinitionId).toEqual('fake-process-name:1:15027'); + }); + + it('Should load the task list when a process definition is selected', () => { + component.onSuccessParamsReport.subscribe((res) => { + expect(res).toBeDefined(); + expect(res.length).toEqual(2); + expect(res[0].id).toEqual('Fake task name 1'); + expect(res[0].name).toEqual('Fake task name 1'); + expect(res[1].id).toEqual('Fake task name 2'); + expect(res[1].name).toEqual('Fake task name 2'); + }); + + component.reportId = 100; + component.reports = [ new Chart({id: 'fake', type: 'fake-type'})]; + component.reportDetails = new ReportModel(analyticMock.reportDefParamTask); + component.onProcessDefinitionChanges(analyticMock.fieldProcessDef); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamTaskOptions + }); + }); + + it('Should convert a string in number', () => { + let numberConvert = component.convertNumber('2'); + expect(numberConvert).toEqual(2); + }); + + it('Should emit an error with a 404 response when the options response is not found', (done) => { + component.onError.subscribe((err) => { + expect(err).toBeDefined(); + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.first().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.reportDefParamProcessDef + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 404, + contentType: 'json', + responseText: [] + }); + }); + + it('Should emit an error with a 404 response when the Process definition overview response is not found ', (done) => { + component.onError.subscribe((err) => { + expect(err).toBeDefined(); + done(); + }); + + component.reportDetails = new ReportModel({ + id: 1, + definition: + '{ "parameters" :[{"id":"status","type":"status", "options": [{"id": "all", "name" :"all"}],"value":null}]}' + }); + + component.reportParamQuery = new ReportQuery({status: 'All'}); + component.showReport(); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 404, + contentType: 'json', + responseText: [] + }); + }); + + it('Should emit an error with a 404 response when the report parameters response is not found', (done) => { + component.onError.subscribe((err) => { + expect(err).toBeDefined(); + done(); + }); + + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 404, + contentType: 'json', + responseText: [] + }); + }); + }); }); diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts index 4ceb45da21..86ae04a74d 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts @@ -20,8 +20,7 @@ import { AlfrescoTranslationService } from 'ng2-alfresco-core'; import { AnalyticsService } from '../services/analytics.service'; import { ReportModel, ReportQuery, ParameterValueModel, ReportParameterModel } from '../models/report.model'; import { Chart } from '../models/chart.model'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import * as moment from 'moment'; +import { FormGroup, FormBuilder } from '@angular/forms'; @Component({ moduleId: module.id, @@ -34,6 +33,9 @@ export class AnalyticsComponent implements OnInit, OnChanges { @ViewChild('processDefinition') processDefinition: any; + @Input() + appId: string; + @Input() reportId: string; @@ -43,6 +45,18 @@ export class AnalyticsComponent implements OnInit, OnChanges { @Output() onError = new EventEmitter(); + @Output() + onDropdownChanged = new EventEmitter(); + + @Output() + onShowReport = new EventEmitter(); + + @Output() + onSuccessParamsReport = new EventEmitter(); + + @Output() + onSuccessParamOpt = new EventEmitter(); + reportDetails: ReportModel; reportParamQuery = new ReportQuery(); @@ -51,7 +65,11 @@ export class AnalyticsComponent implements OnInit, OnChanges { reportForm: FormGroup; - debug: boolean = true; + debug: boolean = false; + + private dropDownSub; + private paramsReportSub; + private paramOpts; constructor(private translate: AlfrescoTranslationService, private analyticsService: AnalyticsService, @@ -63,12 +81,21 @@ export class AnalyticsComponent implements OnInit, OnChanges { } ngOnInit() { - let today = moment().format('YYYY-MM-DD'); this.reportForm = this.formBuilder.group({ - dateRange: this.formBuilder.group({ - startDate: [today, Validators.required], - endDate: [today, Validators.required] - }) + dateRange: new FormGroup({}) + }); + + this.dropDownSub = this.onDropdownChanged.subscribe((field) => { + let paramDependOn: ReportParameterModel = this.reportDetails.definition.parameters.find(p => p.dependsOn === field.id); + if (paramDependOn) { + this.retrieveParameterOptions(this.reportDetails.definition.parameters, this.appId, this.reportId, field.value); + } + }); + + this.paramOpts = this.onSuccessParamsReport.subscribe((report: ReportModel) => { + if (report.hasParameters()) { + this.retrieveParameterOptions(report.definition.parameters, this.appId); + } }); } @@ -76,51 +103,53 @@ export class AnalyticsComponent implements OnInit, OnChanges { let reportId = changes['reportId']; if (reportId && reportId.currentValue) { this.getParamsReports(reportId.currentValue); - return; + } + + let appId = changes['appId']; + if (appId && (appId.currentValue || appId.currentValue === null)) { + this.getParamsReports(this.reportId); } } public getParamsReports(reportId: string) { this.reset(); - this.analyticsService.getParamsReports(reportId).subscribe( + this.paramsReportSub = this.analyticsService.getParamsReports(reportId).subscribe( (res: ReportModel) => { this.reportDetails = res; - this.retriveParameterOptions(); - this.onSuccess.emit(res); + this.onSuccessParamsReport.emit(res); }, (err: any) => { - this.onError.emit(err); console.log(err); - }, - () => console.log('Login done') + this.onError.emit(err); + } ); } - private retriveParameterOptions() { - this.reportDetails.definition.parameters.forEach((param) => { - this.analyticsService.getParamValuesByType(param.type).subscribe( + private retrieveParameterOptions(parameters: ReportParameterModel[], appId: string, reportId?: string, processDefinitionId?: string) { + parameters.forEach((param) => { + this.analyticsService.getParamValuesByType(param.type, appId, reportId, processDefinitionId).subscribe( (opts: ParameterValueModel[]) => { param.options = opts; + this.onSuccessParamOpt.emit(opts); }, (err: any) => { console.log(err); - }, - () => console.log(`${param.type} options loaded`) + this.onError.emit(err); + } ); }); } - public createReport() { + public showReport() { this.analyticsService.getReportsByParams(this.reportDetails.id, this.reportParamQuery).subscribe( (res: Chart[]) => { this.reports = res; - this.onSuccess.emit(res); + this.onShowReport.emit(res); }, (err: any) => { this.onError.emit(err); console.log(err); - }, - () => console.log('Login done') + } ); } @@ -150,13 +179,7 @@ export class AnalyticsComponent implements OnInit, OnChanges { this.reset(); if (field.value) { this.reportParamQuery.processDefinitionId = field.value; - this.analyticsService.getTasksByProcessDefinitionId(this.reportId, this.reportParamQuery.processDefinitionId).subscribe( - (res: any) => { - let paramTask: ReportParameterModel = this.reportDetails.definition.parameters.find(p => p.type === 'task'); - if (paramTask) { - paramTask.options = res; - } - }); + this.onDropdownChanged.emit(field); } } @@ -180,15 +203,15 @@ export class AnalyticsComponent implements OnInit, OnChanges { this.reports = null; } - public chartClicked(e: any): void { - console.log(e); - } - - public chartHovered(e: any): void { - console.log(e); - } - public convertNumber(value: string): number { return parseInt(value, 10); } + + ngOnDestroy() { + this.dropDownSub.unsubscribe(); + this.paramOpts.unsubscribe(); + if (this.paramsReportSub) { + this.paramsReportSub.unsubscribe(); + } + } } diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.ts b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.ts index 315c2ca109..6dcbcf9513 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.ts @@ -16,7 +16,7 @@ */ import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; -import { AbstractControl, FormGroup, FormBuilder } from '@angular/forms'; +import { AbstractControl, FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms'; import { WidgetComponent } from './../widget.component'; import * as moment from 'moment'; @@ -54,7 +54,7 @@ export class DateRangeWidget extends WidgetComponent { @Output() dateRangeChanged: EventEmitter = new EventEmitter(); - debug: boolean = true; + debug: boolean = false; dialogStart: any = new mdDateTimePicker.default({ type: 'date', @@ -78,6 +78,16 @@ export class DateRangeWidget extends WidgetComponent { } initForm() { + let today = moment().format('YYYY-MM-DD'); + + let startDateControl = new FormControl(today); + startDateControl.setValidators(Validators.required); + this.dateRange.addControl('startDate', startDateControl); + + let endDateControl = new FormControl(today); + endDateControl.setValidators(Validators.required); + this.dateRange.addControl('endDate', endDateControl); + this.dateRange.setValidators(dateCheck); this.dateRange.valueChanges.subscribe(data => this.onGroupValueChanged(data)); } diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.css b/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.css deleted file mode 100644 index 48a6b82b45..0000000000 --- a/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.css +++ /dev/null @@ -1,19 +0,0 @@ -.date-widget { - width: 100%; -} - -.date-widget__invalid .mdl-textfield__input { - border-color: #d50000; -} - -.date-widget__invalid .mdl-textfield__label { - color: #d50000; -} - -.date-widget__invalid .mdl-textfield__label:after { - background-color: #d50000; -} - -.date-widget__invalid .mdl-textfield__error { - visibility: visible !important; -} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.html b/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.html deleted file mode 100644 index 1312f7ebc8..0000000000 --- a/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.html +++ /dev/null @@ -1,10 +0,0 @@ -
- - - {{field.validationSummary}} -
diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.ts b/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.ts deleted file mode 100644 index 78bf35a398..0000000000 --- a/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.ts +++ /dev/null @@ -1,50 +0,0 @@ -/*! - * @license - * Copyright 2016 Alfresco Software, Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, ElementRef } from '@angular/core'; -import { WidgetComponent } from './../widget.component'; - -@Component({ - moduleId: module.id, - selector: 'date-widget', - templateUrl: './date.widget.html', - styleUrls: ['./date.widget.css'] -}) -export class DateWidget extends WidgetComponent { - - constructor(private elementRef: ElementRef) { - super(); - } - - setupMaterialComponents(componentHandler: any): boolean { - // workaround for MDL issues with dynamic components - if (componentHandler) { - componentHandler.upgradeAllRegistered(); - if (this.elementRef && this.hasValue()) { - let el = this.elementRef.nativeElement; - let container = el.querySelector('.mdl-textfield'); - if (container) { - container.MaterialTextfield.change(this.field.value); - } - } - - return true; - } - return false; - } - -} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.html b/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.html index 0066152f30..3cad3a1852 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.html +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.html @@ -1,6 +1,6 @@