From f40de41f90679718a93adf862b2f0c7da5e59c0f Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 6 Oct 2016 11:39:10 +0100 Subject: [PATCH 01/11] Analytics component Angular2 Upgrade --- .../ng2-activiti-analytics/index.ts | 25 ++- .../ng2-activiti-analytics/karma-test-shim.js | 1 - .../ng2-activiti-analytics/karma.conf.js | 9 +- .../ng2-activiti-analytics/package.json | 70 ++++---- .../src/components/analytics.component.html | 121 +++++++++++-- .../src/components/analytics.component.ts | 163 ++++++++++++++++-- 6 files changed, 309 insertions(+), 80 deletions(-) diff --git a/ng2-components/ng2-activiti-analytics/index.ts b/ng2-components/ng2-activiti-analytics/index.ts index 279de053d7..c06595d22a 100644 --- a/ng2-components/ng2-activiti-analytics/index.ts +++ b/ng2-components/ng2-activiti-analytics/index.ts @@ -17,13 +17,27 @@ import { NgModule, ModuleWithProviders } from '@angular/core'; import { CoreModule } from 'ng2-alfresco-core'; -import { AnalyticsComponent } from './src/components/analytics.component'; + +import { AnalyticsReportListComponent } from './src/components/analytics-report-list.component'; +import { AnalyticsComponent } from './src/components/analytics.component'; +import { AnalyticsService } from './src/services/analytics.service'; import { CHART_DIRECTIVES } from 'ng2-charts/ng2-charts'; +import { WIDGET_DIRECTIVES } from './src/components/widgets/index'; + export * from './src/components/analytics.component'; +export * from './src/components/analytics-report-list.component'; +export * from './src/services/analytics.service'; +export * from './src/components/widgets/index'; export const ANALYTICS_DIRECTIVES: any[] = [ - AnalyticsComponent + AnalyticsComponent, + AnalyticsReportListComponent, + WIDGET_DIRECTIVES +]; + +export const ANALYTICS_PROVIDERS: any[] = [ + AnalyticsService ]; @NgModule({ @@ -32,7 +46,10 @@ export const ANALYTICS_DIRECTIVES: any[] = [ ], declarations: [ ...ANALYTICS_DIRECTIVES, - CHART_DIRECTIVES + ...CHART_DIRECTIVES + ], + providers: [ + ...ANALYTICS_PROVIDERS ], exports: [ ...ANALYTICS_DIRECTIVES @@ -43,7 +60,7 @@ export class AnalyticsModule { return { ngModule: AnalyticsModule, providers: [ - ...ANALYTICS_DIRECTIVES + ...ANALYTICS_PROVIDERS ] }; } diff --git a/ng2-components/ng2-activiti-analytics/karma-test-shim.js b/ng2-components/ng2-activiti-analytics/karma-test-shim.js index 688f465ff2..4702804ae0 100644 --- a/ng2-components/ng2-activiti-analytics/karma-test-shim.js +++ b/ng2-components/ng2-activiti-analytics/karma-test-shim.js @@ -52,7 +52,6 @@ var map = { // other libraries 'rxjs': 'npm:rxjs', 'ng2-translate': 'npm:ng2-translate', - 'ng2-charts' : 'npm:ng2-charts', 'alfresco-js-api': 'npm:alfresco-js-api/dist', diff --git a/ng2-components/ng2-activiti-analytics/karma.conf.js b/ng2-components/ng2-activiti-analytics/karma.conf.js index 2e7c9d4430..1f5f12c324 100644 --- a/ng2-components/ng2-activiti-analytics/karma.conf.js +++ b/ng2-components/ng2-activiti-analytics/karma.conf.js @@ -39,9 +39,12 @@ module.exports = function (config) { 'karma-test-shim.js', // paths loaded via module imports - {pattern: 'dist/**/*.js', included: false, watched: true}, - {pattern: 'dist/**/*.html', included: true, served: true, watched: true}, - {pattern: 'dist/**/*.css', included: true, served: true, watched: true}, + {pattern: 'dist/**/*.*', included: false, watched: true}, + + // ng2-components + + { pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false }, + { pattern: 'node_modules/ng2-charts/**/*.js', included: false, served: true, watched: false }, // ng2-components {pattern: 'node_modules/ng2-alfresco-core/dist/**/*.*', included: false, served: true, watched: false}, diff --git a/ng2-components/ng2-activiti-analytics/package.json b/ng2-components/ng2-activiti-analytics/package.json index 76ae3079e9..8a77a7d52e 100644 --- a/ng2-components/ng2-activiti-analytics/package.json +++ b/ng2-components/ng2-activiti-analytics/package.json @@ -3,6 +3,8 @@ "description": "Activiti Angular2 Analytics Component", "version": "0.3.3", "author": "Alfresco Software, Ltd.", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", "scripts": { "clean": "npm install rimraf && rimraf dist node_modules typings", "build": "npm run tslint && rimraf dist && tsc && npm run copy-dist && license-check", @@ -21,8 +23,16 @@ "prepublish": "npm run build", "travis": "echo 'placeholder'" }, - "main": "./dist/index.js", - "typings": "./dist/index.d.ts", + "contributors": [ + { + "name": "Mario Romano", + "email": "mario.romnao@alfresco.com" + }, + { + "name": "Maurizio Vitale", + "email": "maurizio.vitale84@gmail.com" + } + ], "repository": { "type": "git", "url": "https://github.com/Alfresco/alfresco-ng2-components.git" @@ -30,21 +40,6 @@ "bugs": { "url": "https://github.com/Alfresco/alfresco-ng2-components/issues" }, - "license": "Apache-2.0", - "contributors": [ - { - "name": "Mario Romano", - "email": "mario.romnao@alfresco.com" - } - ], - "keywords": [ - "ng2", - "angular", - "angular2", - "analytics", - "alfresco-component", - "alfresco" - ], "dependencies": { "@angular/common": "2.0.0", "@angular/compiler": "2.0.0", @@ -56,38 +51,43 @@ "@angular/router": "3.0.0", "@angular/upgrade": "2.0.0", "@types/node": "^6.0.42", + "alfresco-js-api": "^0.3.0", + "chart.js": "^2.1.4", "core-js": "^2.4.1", + "ng2-alfresco-core": "0.3.2", + "ng2-charts": "1.1.0", + "ng2-translate": "2.5.0", "reflect-metadata": "^0.1.3", "rxjs": "5.0.0-beta.12", "systemjs": "0.19.27", - "zone.js": "^0.6.23", - "ng2-translate": "2.5.0", - "alfresco-js-api": "^0.3.0", - "ng2-alfresco-core": "0.3.2", - "ng2-charts": "1.1.0", - "chart.js": "^2.1.4" + "zone.js": "^0.6.23" }, "devDependencies": { "@types/core-js": "^0.9.32", "@types/jasmine": "^2.2.33", "concurrently": "^2.2.0", - "cpx": "1.3.1", + "cpx": "^1.3.1", + "jasmine-ajax": "^3.2.0", "jasmine-core": "2.4.1", - "karma": "0.13.22", - "karma-chrome-launcher": "1.0.1", - "karma-coverage": "1.0.0", - "karma-jasmine": "1.0.2", - "karma-jasmine-ajax": "0.1.13", - "karma-mocha-reporter": "2.0.3", - "karma-jasmine-html-reporter": "0.2.0", - "license-check": "1.1.5", + "karma": "~0.13.22", + "karma-chrome-launcher": "~1.0.1", + "karma-coverage": "^1.0.0", + "karma-jasmine": "~1.0.2", + "karma-jasmine-ajax": "^0.1.13", + "karma-jasmine-html-reporter": "^0.2.0", + "karma-mocha-reporter": "^2.0.3", + "license-check": "^1.0.4", + "remap-istanbul": "^0.6.3", "rimraf": "2.5.2", - "remap-istanbul": "0.6.3", - "traceur": "0.0.91", - "tslint": "3.8.1", + "traceur": "^0.0.91", + "tslint": "^3.8.1", "typescript": "^2.0.3", "wsrv": "^0.1.5" }, + "keywords": [ + "tag", + "alfresco-component" + ], "license-check-config": { "src": [ "./dist/**/*.js" 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 5bb81bc756..01b14984b7 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html @@ -1,21 +1,104 @@
+
+
+

{{reportDetails.name}}

+
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+ UNKNOWN WIDGET TYPE: {{field.type}} +
+
+
+

+ +
- -
-
- -
-
- -
+
+

{{report.title}}

+
+
+
+ +
+
+
+ + + + + + + +
{{label | translate}}
{{row | translate }}
+
+
+ + + + + + + +
{{label | translate}}
{{row | translate }}
+
+
+
+ +
+
+
+ UNKNOWN WIDGET TYPE: {{report.type}} +
+
+
+
+ \ No newline at end of file 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 92f4aa7c40..1fe4d00070 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts @@ -15,35 +15,158 @@ * limitations under the License. */ -import { Component } from '@angular/core'; +import { Component, EventEmitter, OnInit, OnChanges, Input, Output, SimpleChanges, ViewChild } from '@angular/core'; +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'; + @Component({ moduleId: module.id, selector: 'activiti-analytics', - templateUrl: './analytics.component.html' + templateUrl: './analytics.component.html', + styleUrls: ['./analytics.component.css'] }) -export class AnalyticsComponent { +export class AnalyticsComponent implements OnInit, OnChanges { - constructor() { + @ViewChild('processDefinition') + processDefinition: any; + + @Input() + reportId: string; + + @Output() + onSuccess = new EventEmitter(); + + @Output() + onError = new EventEmitter(); + + reportDetails: ReportModel; + + reportParamQuery = new ReportQuery(); + + reports: any[]; + + constructor(private translate: AlfrescoTranslationService, + private analyticsService: AnalyticsService) { console.log('AnalyticsComponent'); + if (translate) { + translate.addTranslationFolder('node_modules/ng2-activiti-analytics/src'); + } } - // lineChart - public lineChartData: Array = [ - [65, 59, 80, 81, 56, 55, 40], - [28, 48, 40, 19, 86, 27, 90] - ]; - public lineChartLabels: Array = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; - public lineChartType: string = 'line'; - public pieChartType: string = 'pie'; + ngOnInit() { - // Pie - public pieChartLabels: string[] = ['Download Sales', 'In-Store Sales', 'Mail Sales']; - public pieChartData: number[] = [300, 500, 100]; + } - public randomizeType(): void { - this.lineChartType = this.lineChartType === 'line' ? 'bar' : 'line'; - this.pieChartType = this.pieChartType === 'doughnut' ? 'pie' : 'doughnut'; + ngOnChanges(changes: SimpleChanges) { + let reportId = changes['reportId']; + if (reportId && reportId.currentValue) { + this.getParamsReports(reportId.currentValue); + return; + } + } + + public getParamsReports(reportId: string) { + this.reset(); + this.analyticsService.getParamsReports(reportId).subscribe( + (res: ReportModel) => { + this.reportDetails = res; + this.retriveParameterOptions(); + this.onSuccess.emit(res); + }, + (err: any) => { + this.onError.emit(err); + console.log(err); + }, + () => console.log('Login done') + ); + } + + private retriveParameterOptions() { + this.reportDetails.definition.parameters.forEach((param) => { + this.analyticsService.getParamValuesByType(param.type).subscribe( + (opts: ParameterValueModel[]) => { + param.options = opts; + }, + (err: any) => { + console.log(err); + }, + () => console.log(`${param.type} options loaded`) + ); + }); + } + + public createReport() { + this.analyticsService.getReportsByParams(this.reportDetails.id, this.reportParamQuery).subscribe( + (res: Chart[]) => { + this.reports = res; + this.onSuccess.emit(res); + }, + (err: any) => { + this.onError.emit(err); + console.log(err); + }, + () => console.log('Login done') + ); + } + + onNumberChanges(field: any) { + this.reset(); + this.reportParamQuery.slowProcessInstanceInteger = parseInt(field.value, 10); + } + + onDurationChanges(field: any) { + this.reset(); + if (field && field.value) { + this.reportParamQuery.duration = parseInt(field.value, 10); + } + } + + onTypeFilteringChanges(field: any) { + this.reset(); + this.reportParamQuery.typeFiltering = field.value; + } + + onStatusChanges(field: any) { + this.reset(); + this.reportParamQuery.status = field.value; + } + + onProcessDefinitionChanges(field: any) { + 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; + } + }); + } + } + + onTaskChanges(field: any) { + this.reset(); + this.reportParamQuery.taskName = field.value; + } + + onDateRangeChange(dateRange: any) { + this.reset(); + this.reportParamQuery.dateRange.startDate = dateRange.startDate; + this.reportParamQuery.dateRange.endDate = dateRange.endDate; + } + + + onDateRangeIntervalChange(field: any) { + this.reset(); + this.reportParamQuery.dateRangeInterval = field.value; + } + + public reset() { + this.reports = null; } public chartClicked(e: any): void { @@ -53,4 +176,8 @@ export class AnalyticsComponent { public chartHovered(e: any): void { console.log(e); } + + public convertNumber(value: string): number { + return parseInt(value, 10); + } } From d54b318efdf05a540c002d9c6aecaa80de67b497 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 6 Oct 2016 11:40:27 +0100 Subject: [PATCH 02/11] Analitycs component demoshell integration --- demo-shell-ng2/app/app.module.ts | 4 +++- .../activiti/activiti-demo.component.html | 11 ++++++++++- .../components/activiti/activiti-demo.component.ts | 5 +++++ demo-shell-ng2/index.html | 1 + demo-shell-ng2/systemjs.config.js | 14 ++++++++++++-- 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/demo-shell-ng2/app/app.module.ts b/demo-shell-ng2/app/app.module.ts index 1726859603..a1d7fcf93e 100644 --- a/demo-shell-ng2/app/app.module.ts +++ b/demo-shell-ng2/app/app.module.ts @@ -31,6 +31,7 @@ import { ActivitiFormModule } from 'ng2-activiti-form'; import { ActivitiTaskListModule } from 'ng2-activiti-tasklist'; import { ActivitiProcessListModule } from 'ng2-activiti-processlist'; import { UserInfoComponentModule } from 'ng2-alfresco-userinfo'; +import { AnalyticsModule } from 'ng2-activiti-analytics'; import { AppComponent } from './app.component'; import { routing } from './app.routes'; @@ -65,7 +66,8 @@ import { ActivitiFormModule.forRoot(), ActivitiTaskListModule.forRoot(), ActivitiProcessListModule.forRoot(), - UserInfoComponentModule.forRoot() + UserInfoComponentModule.forRoot(), + AnalyticsModule.forRoot() ], declarations: [ AppComponent, 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 fd462fa8bd..a9a9a45019 100644 --- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html +++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html @@ -63,7 +63,16 @@
-
+
+
+
+ +
+
+ +
+
+
diff --git a/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts b/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts index 107d8d525a..19fcc8b356 100644 --- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts +++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts @@ -79,6 +79,7 @@ export class ActivitiDemoComponent implements AfterViewChecked { processSchemaColumns: any [] = []; taskFilter: any; + report: any; processFilter: any; sub: Subscription; @@ -140,6 +141,10 @@ export class ActivitiDemoComponent implements AfterViewChecked { this.taskFilter = event; } + onReportClick(event: any) { + this.report = event; + } + onSuccessTaskFilterList(event: any) { this.taskFilter = this.activitifilter.getCurrentFilter(); } diff --git a/demo-shell-ng2/index.html b/demo-shell-ng2/index.html index f108c3dfa6..ba09be82ca 100644 --- a/demo-shell-ng2/index.html +++ b/demo-shell-ng2/index.html @@ -34,6 +34,7 @@ + diff --git a/demo-shell-ng2/systemjs.config.js b/demo-shell-ng2/systemjs.config.js index 8726219617..213c73af70 100644 --- a/demo-shell-ng2/systemjs.config.js +++ b/demo-shell-ng2/systemjs.config.js @@ -23,6 +23,8 @@ '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', // other libraries 'rxjs': 'npm:rxjs', + 'moment': 'npm:moment', + 'ng2-charts' : 'npm:ng2-charts', 'ng2-translate': 'npm:ng2-translate', 'ng2-alfresco-core': 'npm:ng2-alfresco-core/dist', 'ng2-alfresco-datatable': 'npm:ng2-alfresco-datatable/dist', @@ -37,7 +39,13 @@ 'ng2-activiti-tasklist': 'npm:ng2-activiti-tasklist/dist', 'alfresco-js-api': 'npm:alfresco-js-api/dist', 'ng2-activiti-processlist': 'npm:ng2-activiti-processlist/dist', - 'ng2-alfresco-userinfo': 'npm:ng2-alfresco-userinfo/dist' + 'ng2-alfresco-userinfo': 'npm:ng2-alfresco-userinfo/dist', + 'ng2-activiti-analytics': 'npm:ng2-activiti-analytics/dist' + }, + meta: { + moment: { + exports: 'moment' + } }, // packages tells the System loader how to load when no filename and/or no extension packages: { @@ -49,6 +57,7 @@ defaultExtension: 'js' }, 'ng2-translate': { defaultExtension: 'js' }, + 'ng2-charts': { defaultExtension: 'js' }, 'ng2-alfresco-core': { main: './index.js', defaultExtension: 'js'}, 'ng2-alfresco-datatable': { main: './index.js', defaultExtension: 'js'}, @@ -63,7 +72,8 @@ 'ng2-alfresco-webscript': { main: './index.js', defaultExtension: 'js'}, 'ng2-alfresco-tag': { main: './index.js', defaultExtension: 'js'}, 'alfresco-js-api': { main: './alfresco-js-api.js', defaultExtension: 'js'}, - 'ng2-alfresco-userinfo': { main: './index.js', defaultExtension: 'js'} + 'ng2-alfresco-userinfo': { main: './index.js', defaultExtension: 'js'}, + 'ng2-activiti-analytics': { main: './index.js', defaultExtension: 'js'} } }); })(this); From 0912b7465f39990aef069dd71ff54c4783979733 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 6 Oct 2016 12:10:30 +0100 Subject: [PATCH 03/11] report list component --- .../analytics-report-list.component.css | 0 .../analytics-report-list.component.html | 10 ++ .../analytics-report-list.component.ts | 91 +++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.css create mode 100644 ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.html create mode 100644 ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.ts diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.css b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.html b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.html new file mode 100644 index 0000000000..c5a70dea46 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.html @@ -0,0 +1,10 @@ + \ No newline at end of file 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 new file mode 100644 index 0000000000..103e77b41e --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.ts @@ -0,0 +1,91 @@ +/*! + * @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, EventEmitter, OnInit, Output } from '@angular/core'; +import { AlfrescoAuthenticationService } from 'ng2-alfresco-core'; +import { AnalyticsService } from '../services/analytics.service'; +import { ReportModel } from '../models/report.model'; +import { Observer } from 'rxjs/Observer'; +import { Observable } from 'rxjs/Observable'; + + +@Component({ + moduleId: module.id, + selector: 'analytics-report-list', + templateUrl: './analytics-report-list.component.html', + styleUrls: ['./analytics-report-list.component.css'] +}) +export class AnalyticsReportListComponent implements OnInit { + + @Output() + reportClick: EventEmitter = new EventEmitter(); + + @Output() + onSuccess = new EventEmitter(); + + @Output() + onError = new EventEmitter(); + + private reportObserver: Observer; + report$: Observable; + + currentReport: any; + + reports: ReportModel[] = []; + + constructor(private auth: AlfrescoAuthenticationService, + private analyticsService: AnalyticsService) { + + this.report$ = new Observable(observer => this.reportObserver = observer).share(); + } + + ngOnInit() { + this.report$.subscribe((report: ReportModel) => { + this.reports.push(report); + }); + + this.getReportListByAppId(); + } + + + getReportListByAppId() { + this.analyticsService.getReportList().subscribe( + (res: ReportModel[]) => { + this.reports = res; + this.onSuccess.emit(res); + }, + (err: any) => { + this.onError.emit(err); + console.log(err); + }, + () => console.log('Reports loaded') + ); + } + + isReportsEmpty(): boolean { + return this.reports === undefined || (this.reports && this.reports.length === 0); + } + + /** + * Select the current report + * @param report + */ + public selectReport(report: any) { + this.currentReport = report; + this.reportClick.emit(report); + } +} From 474e6cdfc674a7fc900f973400e515ae7f3c0d4b Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 6 Oct 2016 12:10:53 +0100 Subject: [PATCH 04/11] Analytics reports --- .../src/components/analytics.component.css | 25 +++ .../widgets/checkbox/checkbox.widget.html | 9 + .../widgets/checkbox/checkbox.widget.ts | 34 +++ .../widgets/date-range/date-range.widget.css | 0 .../widgets/date-range/date-range.widget.html | 16 ++ .../widgets/date-range/date-range.widget.ts | 49 ++++ .../components/widgets/date/date.widget.css | 19 ++ .../components/widgets/date/date.widget.html | 10 + .../components/widgets/date/date.widget.ts | 51 +++++ .../widgets/dropdown/dropdown.widget.css | 23 ++ .../widgets/dropdown/dropdown.widget.html | 8 + .../widgets/dropdown/dropdown.widget.ts | 50 +++++ .../widgets/duration/duration.widget.css | 19 ++ .../widgets/duration/duration.widget.html | 19 ++ .../widgets/duration/duration.widget.ts | 59 +++++ .../src/components/widgets/index.ts | 40 ++++ .../widgets/number/number.widget.css | 19 ++ .../widgets/number/number.widget.html | 9 + .../widgets/number/number.widget.ts | 48 ++++ .../components/widgets/widget.component.ts | 68 ++++++ .../ng2-activiti-analytics/src/i18n/en.json | 33 +++ .../src/models/chart.model.ts | 160 +++++++++++++ .../src/models/report.model.ts | 136 +++++++++++ .../src/services/analytics.service.ts | 211 ++++++++++++++++++ 24 files changed, 1115 insertions(+) create mode 100644 ng2-components/ng2-activiti-analytics/src/components/analytics.component.css create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/checkbox/checkbox.widget.html create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/checkbox/checkbox.widget.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.css create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.css create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.html create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.css create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.html create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.css create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.html create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/index.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.css create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.html create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/components/widgets/widget.component.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/models/chart.model.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/models/report.model.ts create mode 100644 ng2-components/ng2-activiti-analytics/src/services/analytics.service.ts diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.css b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.css new file mode 100644 index 0000000000..096757598a --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.css @@ -0,0 +1,25 @@ +.chart {display: block; width: 100%;} + +.dropdown-widget { + width: 100%; +} + +.dropdown-widget__select { + width: 100%; +} + +.dropdown-widget__invalid .dropdown-widget__select { + border-color: #d50000; +} + +.dropdown-widget__invalid .dropdown-widget__label { + color: #d50000; +} + +.dropdown-widget__invalid .dropdown-widget__label:after { + background-color: #d50000; +} + +.dropdown-widget__invalid .mdl-textfield__error { + visibility: visible !important; +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/checkbox/checkbox.widget.html b/ng2-components/ng2-activiti-analytics/src/components/widgets/checkbox/checkbox.widget.html new file mode 100644 index 0000000000..b9841dae1b --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/checkbox/checkbox.widget.html @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/checkbox/checkbox.widget.ts b/ng2-components/ng2-activiti-analytics/src/components/widgets/checkbox/checkbox.widget.ts new file mode 100644 index 0000000000..67a6081e1c --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/checkbox/checkbox.widget.ts @@ -0,0 +1,34 @@ +/*! + * @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 } from '@angular/core'; +import { WidgetComponent } from './../widget.component'; + +declare var componentHandler; + +@Component({ + moduleId: module.id, + selector: 'checkbox-widget', + templateUrl: './checkbox.widget.html' +}) +export class CheckboxWidget extends WidgetComponent { + + constructor() { + super(); + } + +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.css b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html new file mode 100644 index 0000000000..a674d0fe5d --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html @@ -0,0 +1,16 @@ + +
+
+ + +
+
+ + +
\ No newline at end of file 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 new file mode 100644 index 0000000000..d1821d4251 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.ts @@ -0,0 +1,49 @@ +/*! + * @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, Input, Output, EventEmitter } from '@angular/core'; +import * as moment from 'moment'; + +@Component({ + moduleId: module.id, + selector: 'date-range-widget', + templateUrl: './date-range.widget.html', + styleUrls: ['./date-range.widget.css'] +}) +export class DateRangeWidget { + + @Input() + field: any; + + @Output() + dateRangeChanged: EventEmitter = new EventEmitter(); + + constructor() {} + + public onDateRangeChanged(startDate: HTMLInputElement, endDate: HTMLInputElement) { + if (startDate.validity.valid && endDate.validity.valid) { + let dateStart = this.convertMomentDate(startDate.value); + let endStart = this.convertMomentDate(endDate.value); + this.dateRangeChanged.emit({startDate: dateStart, endDate: endStart}); + } + } + + public convertMomentDate(date: string) { + return moment(date, 'DD/MM/YYYY', true).format('YYYY-MM-DD') + 'T00:00:00.000Z'; + } + +} 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 new file mode 100644 index 0000000000..48a6b82b45 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.css @@ -0,0 +1,19 @@ +.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 new file mode 100644 index 0000000000..1312f7ebc8 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.html @@ -0,0 +1,10 @@ +
+ + + {{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 new file mode 100644 index 0000000000..08447f456a --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date/date.widget.ts @@ -0,0 +1,51 @@ +/*! + * @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.css b/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.css new file mode 100644 index 0000000000..ae995ca854 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.css @@ -0,0 +1,23 @@ +.dropdown-widget { + width: 100%; +} + +.dropdown-widget__select { + width: 100%; +} + +.dropdown-widget__invalid .dropdown-widget__select { + border-color: #d50000; +} + +.dropdown-widget__invalid .dropdown-widget__label { + color: #d50000; +} + +.dropdown-widget__invalid .dropdown-widget__label:after { + background-color: #d50000; +} + +.dropdown-widget__invalid .mdl-textfield__error { + visibility: visible !important; +} 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 new file mode 100644 index 0000000000..0066152f30 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.ts b/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.ts new file mode 100644 index 0000000000..b22edf556e --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/dropdown/dropdown.widget.ts @@ -0,0 +1,50 @@ +/*! + * @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, Input, Output, EventEmitter } from '@angular/core'; +import { WidgetComponent } from './../widget.component'; + + +@Component({ + moduleId: module.id, + selector: 'dropdown-widget', + templateUrl: './dropdown.widget.html', + styleUrls: ['./dropdown.widget.css'] +}) +export class DropdownWidget extends WidgetComponent { + + @Input() + field: any; + + @Output() + fieldChanged: EventEmitter = new EventEmitter(); + + @Input() + showDefaultOption: boolean = true; + + @Input() + defaultOptionText: string = 'Choose One'; + + constructor() { + super(); + } + + handleError(error: any) { + console.error(error); + } + +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.css b/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.css new file mode 100644 index 0000000000..3e4f6952f3 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.css @@ -0,0 +1,19 @@ +.number-widget { + width: 100%; +} + +.number-widget__invalid .mdl-textfield__input { + border-color: #d50000; +} + +.number-widget__invalid .mdl-textfield__label { + color: #d50000; +} + +.number-widget__invalid .mdl-textfield__label:after { + background-color: #d50000; +} + +.number-widget__invalid .mdl-textfield__error { + visibility: visible !important; +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.html b/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.html new file mode 100644 index 0000000000..2db7992288 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.html @@ -0,0 +1,19 @@ +
+
+
+ + +
+
+
+
+ +
+
+
\ No newline at end of file diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.ts b/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.ts new file mode 100644 index 0000000000..11ab9ccb46 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/duration/duration.widget.ts @@ -0,0 +1,59 @@ +/*! + * @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, OnInit } from '@angular/core'; +import { NumberWidget } from './../number/number.widget'; +import { ReportParameterModel, ParameterValueModel } from './../../../models/report.model'; + + +@Component({ + moduleId: module.id, + selector: 'duration-widget', + templateUrl: './duration.widget.html', + styleUrls: ['./duration.widget.css'] +}) +export class DurationWidget extends NumberWidget implements OnInit { + duration: ReportParameterModel; + currentValue: number; + + constructor(public elementRef: ElementRef) { + super(elementRef); + } + + ngOnInit() { + if (this.field.value === null) { + this.field.value = 0; + } + + let paramOptions: ParameterValueModel[] = []; + paramOptions.push(new ParameterValueModel({id: '1', name: 'Seconds'})); + paramOptions.push(new ParameterValueModel({id: '60', name: 'Minutes'})); + paramOptions.push(new ParameterValueModel({id: '3600', name: 'Hours'})); + paramOptions.push(new ParameterValueModel({id: '86400', name: 'Days', selected: true})); + + this.duration = new ReportParameterModel({id: 'duration', name: 'duration', options: paramOptions}); + this.duration.value = paramOptions[0].id; + } + + public calculateDuration() { + if (this.field && this.duration.value ) { + this.currentValue = parseInt(this.field.value, 10) * parseInt(this.duration.value, 10); + this.fieldChanged.emit({value: this.currentValue}); + } + } + +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/index.ts b/ng2-components/ng2-activiti-analytics/src/components/widgets/index.ts new file mode 100644 index 0000000000..efc2d86d5f --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/index.ts @@ -0,0 +1,40 @@ +/*! + * @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 { DropdownWidget } from './dropdown/dropdown.widget'; +import { NumberWidget } from './number/number.widget'; +import { DurationWidget } from './duration/duration.widget'; +import { CheckboxWidget } from './checkbox/checkbox.widget'; +import { DateWidget } from './date/date.widget'; +import { DateRangeWidget } from './date-range/date-range.widget'; + +// primitives +export * from './dropdown/dropdown.widget'; +export * from './number/number.widget'; +export * from './duration/duration.widget'; +export * from './checkbox/checkbox.widget'; +export * from './date/date.widget'; +export * from './date-range/date-range.widget'; + +export const WIDGET_DIRECTIVES: any[] = [ + DropdownWidget, + NumberWidget, + DurationWidget, + CheckboxWidget, + DateWidget, + DateRangeWidget +]; diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.css b/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.css new file mode 100644 index 0000000000..3e4f6952f3 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.css @@ -0,0 +1,19 @@ +.number-widget { + width: 100%; +} + +.number-widget__invalid .mdl-textfield__input { + border-color: #d50000; +} + +.number-widget__invalid .mdl-textfield__label { + color: #d50000; +} + +.number-widget__invalid .mdl-textfield__label:after { + background-color: #d50000; +} + +.number-widget__invalid .mdl-textfield__error { + visibility: visible !important; +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.html b/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.html new file mode 100644 index 0000000000..64acbf818e --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.html @@ -0,0 +1,9 @@ +
+ + +
\ No newline at end of file diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.ts b/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.ts new file mode 100644 index 0000000000..ca5dab97d3 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/number/number.widget.ts @@ -0,0 +1,48 @@ +/*! + * @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: 'number-widget', + templateUrl: './number.widget.html', + styleUrls: ['./number.widget.css'] +}) +export class NumberWidget extends WidgetComponent { + + constructor(public elementRef: ElementRef) { + super(); + } + + setupMaterialComponents(handler: any): boolean { + // workaround for MDL issues with dynamic components + if (handler) { + handler.upgradeAllRegistered(); + if (this.elementRef && this.hasValue()) { + let container = this.elementRef.nativeElement.querySelector('.mdl-textfield'); + if (container) { + container.MaterialTextfield.change(this.field.value.toString()); + } + } + return true; + } + return false; + } +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/widget.component.ts b/ng2-components/ng2-activiti-analytics/src/components/widgets/widget.component.ts new file mode 100644 index 0000000000..eafd8cdca2 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/widget.component.ts @@ -0,0 +1,68 @@ +/*! + * @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 { Input, AfterViewInit, Output, EventEmitter, SimpleChanges, OnChanges } from '@angular/core'; + +declare var componentHandler; + +/** + * Base widget component. + */ +export class WidgetComponent implements AfterViewInit, OnChanges { + + @Input() + field: any; + + @Output() + fieldChanged: EventEmitter = new EventEmitter(); + + ngOnChanges(changes: SimpleChanges) { + let field = changes['field']; + if (field && field.currentValue) { + this.fieldChanged.emit(field.currentValue.value); + return; + } + } + + hasField() { + return this.field ? true : false; + } + + hasValue(): boolean { + return this.field && + this.field.value !== null && + this.field.value !== undefined; + } + + changeValue(field: any) { + this.fieldChanged.emit(field); + } + + ngAfterViewInit() { + this.setupMaterialComponents(componentHandler); + } + + setupMaterialComponents(handler?: any): boolean { + // workaround for MDL issues with dynamic components + if (handler) { + handler.upgradeAllRegistered(); + return true; + } + return false; + } + +} diff --git a/ng2-components/ng2-activiti-analytics/src/i18n/en.json b/ng2-components/ng2-activiti-analytics/src/i18n/en.json index 3afc878e36..9d9cf9aa42 100644 --- a/ng2-components/ng2-activiti-analytics/src/i18n/en.json +++ b/ng2-components/ng2-activiti-analytics/src/i18n/en.json @@ -1,5 +1,38 @@ { "ANALYTICS": { "TTILE": "ANALYTICS" + }, + "__KEY_REPORTING": { + "DEFAULT-REPORTS": { + "PROCESS-DEFINITION-OVERVIEW": { + "GENERAL-TABLE-TOTAL-PROCESS-DEFINITIONS": "Total number of process definitions", + "GENERAL-TABLE-TOTAL-PROCESS-INSTANCES": "Total number of process instances", + "GENERAL-TABLE-ACTIVE-PROCESS-INSTANCES": "Total number of active process instances", + "GENERAL-TABLE-COMPLETED-PROCESS-INSTANCES": "Total number of completed process instances" + } + } + }, + "REPORTING": { + "DEFAULT-REPORTS": { + "PROCESS-HEAT-MAP": { + "TYPE-FILTERING": "Include all process steps (Unchecking this, will remove pass through steps like start events, gateways, etc.)?" + }, + "PROCESS-INSTANCES-OVERVIEW": { + "PROCESS-DEFINITION": "Process definition", + "DATE-RANGE": "Date range", + "SLOW-PROC-INST-NUMBER": "How many of the slowest process instances should be displayed?" + }, + "TASK-OVERVIEW": { + "PROCESS-DEFINITION": "Process definition", + "DATE-RANGE": "Date range", + "DATE-RANGE-INTERVAL": "Aggregate dates by" + }, + "TASK-SLA": { + "PROCESS-DEFINITION": "Process definition", + "DATE-RANGE": "Date range" + } + }, + "PROCESS-STATUS": "Process status", + "TASK-STATUS": "Task status" } } diff --git a/ng2-components/ng2-activiti-analytics/src/models/chart.model.ts b/ng2-components/ng2-activiti-analytics/src/models/chart.model.ts new file mode 100644 index 0000000000..30f7db5ba9 --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/models/chart.model.ts @@ -0,0 +1,160 @@ +/*! + * @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. + */ + +export class Chart { + id: string; + type: string; + + constructor(obj?: any) { + this.id = obj && obj.id || null; + if (obj && obj.type) { + this.type = this.convertType(obj.type); + } + } + + private convertType(type: string) { + let chartType = ''; + switch (type) { + case 'pieChart': + chartType = 'pie'; + break; + case 'table': + chartType = 'table'; + break; + case 'line': + chartType = 'line'; + break; + case 'barChart': + chartType = 'bar'; + break; + default: + chartType = 'table'; + break; + } + return chartType; + } +} + +export class LineChart extends Chart { + title: string; + titleKey: string; + labels: string[] = []; + datasets: any[] = []; + + constructor(obj?: any) { + super(obj); + this.title = obj && obj.title || null; + this.titleKey = obj && obj.titleKey || null; + this.labels = obj && obj.columnNames.slice(1, obj.columnNames.length); + + obj.rows.forEach((value: any) => { + this.datasets.push({data: value.slice(1, value.length), label: value[0]}); + }); + } +} + +export class BarChart extends Chart { + title: string; + titleKey: string; + labels: string[] = []; + datasets: any[] = []; + data: any[] = []; + options: any = { + scales: { + yAxes: [{ + ticks: { + beginAtZero: true, + stepSize: 1 + } + }] + } + }; + + constructor(obj?: any) { + super(obj); + this.title = obj && obj.title || null; + this.titleKey = obj && obj.titleKey || null; + obj.values.forEach((params: any) => { + let dataValue = []; + params.values.forEach((info: any) => { + info.forEach((value: any, index: any) => { + if (index % 2 === 0) { + this.labels.push(value); + } else { + dataValue.push(value); + } + }); + }); + this.datasets.push({data: dataValue, label: params.key}); + + }); + } +} + +export class TableChart extends Chart { + title: string; + titleKey: string; + labels: string[] = []; + datasets: any[] = []; + + constructor(obj?: any) { + super(obj); + this.title = obj && obj.title || null; + this.titleKey = obj && obj.titleKey || null; + this.labels = obj && obj.columnNames; + this.datasets = obj && obj.rows; + } +} + + +export class HeatMapChart extends Chart { + title: string; + titleKey: string; + labels: string[] = []; + datasets: any[] = []; + + constructor(obj?: any) { + super(obj); + this.title = obj && obj.title || null; + this.titleKey = obj && obj.titleKey || null; + this.labels = obj && obj.columnNames; + this.datasets = obj && obj.rows; + } +} + +export class PieChart extends Chart { + title: string; + titleKey: string; + labels: string[] = []; + data: string[] = []; + + constructor(obj?: any) { + super(obj); + this.title = obj && obj.title || null; + this.titleKey = obj && obj.titleKey || null; + if (obj.values) { + obj.values.forEach((value: any) => { + this.add(value.key, value.y); + }); + } + } + + add(label: string, data: string) { + this.labels.push(label); + this.data.push(data); + } +} diff --git a/ng2-components/ng2-activiti-analytics/src/models/report.model.ts b/ng2-components/ng2-activiti-analytics/src/models/report.model.ts new file mode 100644 index 0000000000..d13f61bbcb --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/models/report.model.ts @@ -0,0 +1,136 @@ +/*! + * @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. + */ + +/** + * + * This object represent the report definition. + * + * + * @returns {ReportModel} . + */ +export class ReportModel { + id: number; + name: string; + definition: ReportParametersModel; + created: string; + + constructor(obj?: any) { + this.id = obj && obj.id; + this.name = obj && obj.name || null; + if (obj && obj.definition) { + this.definition = new ReportParametersModel(JSON.parse(obj.definition)); + } + this.created = obj && obj.created || null; + } +} + +export class ReportParametersModel { + parameters: ReportParameterModel[] = []; + + constructor(obj?: any) { + obj.parameters.forEach((params: any) => { + let reportParamsModel = new ReportParameterModel(params); + this.parameters.push(reportParamsModel); + }); + } + + findParam(name: string): ReportParameterModel { + this.parameters.forEach((param) => { + return param.type === name ? param : null; + }); + return null; + } +} + +/** + * + * This object represent the report parameter definition. + * + * + * @returns {ReportParameterModel} . + */ +export class ReportParameterModel { + id: string; + name: string; + nameKey: string; + type: string; + value: string; + options: ParameterValueModel[]; + dependsOn: string; + + constructor(obj?: any) { + this.id = obj && obj.id; + this.name = obj && obj.name || null; + this.nameKey = obj && obj.nameKey || null; + this.type = obj && obj.type || null; + this.value = obj && obj.value || null; + this.options = obj && obj.options || null; + this.dependsOn = obj && obj.dependsOn || null; + } +} + +export class ParameterValueModel { + id: string; + name: string; + version: string; + value: string; + + constructor(obj?: any) { + this.id = obj && obj.id; + this.name = obj && obj.name || null; + this.value = obj && obj.value || null; + this.version = obj && obj.version || null; + } + + get label () { + return this.version ? `${this.name} (v ${this.version}) ` : this.name; + } +} + + +export class ReportQuery { + processDefinitionId: string; + status: string; + taskName: string; + typeFiltering: boolean; + dateRange: ReportDateRange; + dateRangeInterval: string; + slowProcessInstanceInteger: number; + duration: number; + + constructor(obj?: any) { + this.processDefinitionId = obj && obj.processDefinitionId || null; + this.status = obj && obj.status || null; + this.taskName = obj && obj.taskName || null; + this.dateRangeInterval = obj && obj.dateRangeInterval || null; + this.typeFiltering = obj && obj.typeFiltering || false; + this.slowProcessInstanceInteger = obj && obj.slowProcessInstanceInteger || 0; + this.duration = obj && obj.duration || 0; + this.dateRange = new ReportDateRange(obj); + } +} + +export class ReportDateRange { + startDate: string; + endDate: string; + + constructor(obj?: any) { + this.startDate = obj && obj.startDate || null; + this.endDate = obj && obj.endDate || null; + } + +} diff --git a/ng2-components/ng2-activiti-analytics/src/services/analytics.service.ts b/ng2-components/ng2-activiti-analytics/src/services/analytics.service.ts new file mode 100644 index 0000000000..01f6b161ad --- /dev/null +++ b/ng2-components/ng2-activiti-analytics/src/services/analytics.service.ts @@ -0,0 +1,211 @@ +/*! + * @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 { Injectable } from '@angular/core'; +import { AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core'; +import { Observable } from 'rxjs/Rx'; +import { Response, Http, Headers, RequestOptions, URLSearchParams } from '@angular/http'; +import { ReportModel, ParameterValueModel } from '../models/report.model'; +import { Chart, PieChart, TableChart, BarChart } from '../models/chart.model'; + +@Injectable() +export class AnalyticsService { + + constructor(private authService: AlfrescoAuthenticationService, + private http: Http, + private alfrescoSettingsService: AlfrescoSettingsService) { + } + + /** + * Retrive all the Deployed app + * @returns {Observable} + */ + getReportList(): Observable { + let url = `${this.alfrescoSettingsService.getBPMApiBaseUrl()}/app/rest/reporting/reports`; + let options = this.getRequestOptions(); + return this.http + .get(url, options) + .map((res: any) => { + let reports: ReportModel[] = []; + let body = res.json(); + body.forEach((report: ReportModel) => { + let reportModel = new ReportModel(report); + reports.push(reportModel); + }); + if (body && body.length === 0) { + return this.createDefaultReports(); + } + return reports; + }).catch(this.handleError); + } + + getParamsReports(reportId: string): Observable { + let url = `${this.alfrescoSettingsService.getBPMApiBaseUrl()}/app/rest/reporting/report-params/${reportId}`; + let options = this.getRequestOptions(); + return this.http + .get(url, options) + .map((res: any) => { + let body = res.json(); + return new ReportModel(body); + }).catch(this.handleError); + } + + getParamValuesByType(type: string, reportId?: string, processDefinitionId?: string) { + if (type === 'status') { + return this.getProcessStatusValues(); + } else if (type === 'processDefinition') { + return this.getProcessDefinitionsValues(); + } else if (type === 'dateInterval') { + return this.getDateIntervalValues(); + } else if (type === 'task') { + return this.getTasksByProcessDefinitionId(reportId, processDefinitionId); + } else { + return Observable.create(observer => { + observer.next(null); + observer.complete(); + }); + } + } + + getProcessStatusValues(): Observable { + let paramOptions: ParameterValueModel[] = []; + + paramOptions.push(new ParameterValueModel({id: 'All', name: 'All'})); + paramOptions.push(new ParameterValueModel({id: 'Active', name: 'Active'})); + paramOptions.push(new ParameterValueModel({id: 'Complete', name: 'Complete'})); + + return Observable.create(observer => { + observer.next(paramOptions); + observer.complete(); + }); + } + + getDateIntervalValues(): Observable { + let paramOptions: ParameterValueModel[] = []; + + paramOptions.push(new ParameterValueModel({id: 'byHour', name: 'By hour'})); + paramOptions.push(new ParameterValueModel({id: 'byDay', name: 'By day'})); + paramOptions.push(new ParameterValueModel({id: 'byWeek', name: 'By week'})); + paramOptions.push(new ParameterValueModel({id: 'byMonth', name: 'By month'})); + paramOptions.push(new ParameterValueModel({id: 'byYear', name: 'By year'})); + + return Observable.create(observer => { + observer.next(paramOptions); + observer.complete(); + }); + } + + getProcessDefinitionsValues(appId?: string): Observable { + let url = `${this.alfrescoSettingsService.getBPMApiBaseUrl()}/app/rest/reporting/process-definitions`; + let params: URLSearchParams; + if (appId) { + params = new URLSearchParams(); + params.set('appDefinitionId', appId); + } + let options = this.getRequestOptions(params); + return this.http + .get(url, options) + .map((res: any) => { + let paramOptions: ParameterValueModel[] = []; + let body = res.json(); + body.forEach((opt) => { + paramOptions.push(new ParameterValueModel(opt)); + }); + return paramOptions; + }).catch(this.handleError); + } + + getTasksByProcessDefinitionId(reportId: string, processDefinitionId: string): Observable { + if (processDefinitionId) { + let url = `${this.alfrescoSettingsService.getBPMApiBaseUrl()}/app/rest/reporting/report-params/${reportId}/tasks`; + let params: URLSearchParams; + if (processDefinitionId) { + params = new URLSearchParams(); + params.set('processDefinitionId', processDefinitionId); + } + let options = this.getRequestOptions(params); + return this.http + .get(url, options) + .map((res: any) => { + let paramOptions: ParameterValueModel[] = []; + let body = res.json(); + body.forEach((opt) => { + paramOptions.push(new ParameterValueModel({id: opt, name: opt})); + }); + return paramOptions; + }).catch(this.handleError); + } else { + return Observable.create(observer => { + observer.next(null); + observer.complete(); + }); + } + } + + getReportsByParams(reportId: number, paramsQuery: any): Observable { + let url = `${this.alfrescoSettingsService.getBPMApiBaseUrl()}/app/rest/reporting/report-params/${reportId}`; + let body = JSON.stringify(paramsQuery); + let options = this.getRequestOptions(); + return this.http + .post(url, body, options) + .map((res: any) => { + let elements: Chart[] = []; + let bodyRes = res.json(); + bodyRes.elements.forEach((chartData) => { + if (chartData.type === 'pieChart') { + elements.push(new PieChart(chartData)); + } else if (chartData.type === 'table') { + elements.push(new TableChart(chartData)); + } else if (chartData.type === 'processDefinitionHeatMap') { + elements.push(new TableChart(chartData)); + } else if (chartData.type === 'masterDetailTable') { + elements.push(new TableChart(chartData)); + } else if (chartData.type === 'barChart') { + elements.push(new BarChart(chartData)); + } + }); + + return elements; + }).catch(this.handleError); + } + + public createDefaultReports(): ReportModel[] { + let reports: ReportModel[] = []; + return reports; + } + + public getHeaders(): Headers { + return new Headers({ + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': this.authService.getTicketBpm() + }); + } + + public getRequestOptions(param?: any): RequestOptions { + let headers = this.getHeaders(); + return new RequestOptions({headers: headers, withCredentials: true, search: param}); + } + + private handleError(error: Response) { + console.error(error); + return Observable.throw(error.json().error || 'Server error'); + } + + + +} From a9d16881b12a1c87c02c99aaff00eaac8b13503c Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 6 Oct 2016 12:11:25 +0100 Subject: [PATCH 05/11] Fix import moment js --- demo-shell-ng2/systemjs.config.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/demo-shell-ng2/systemjs.config.js b/demo-shell-ng2/systemjs.config.js index 213c73af70..73016570b9 100644 --- a/demo-shell-ng2/systemjs.config.js +++ b/demo-shell-ng2/systemjs.config.js @@ -23,7 +23,7 @@ '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', // other libraries 'rxjs': 'npm:rxjs', - 'moment': 'npm:moment', + 'moment': 'npm:moment/min/moment.min.js', 'ng2-charts' : 'npm:ng2-charts', 'ng2-translate': 'npm:ng2-translate', 'ng2-alfresco-core': 'npm:ng2-alfresco-core/dist', @@ -42,11 +42,6 @@ 'ng2-alfresco-userinfo': 'npm:ng2-alfresco-userinfo/dist', 'ng2-activiti-analytics': 'npm:ng2-activiti-analytics/dist' }, - meta: { - moment: { - exports: 'moment' - } - }, // packages tells the System loader how to load when no filename and/or no extension packages: { app: { From ea7e2b9c3923c83ae060b0a91f380f62ea99bca8 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Thu, 6 Oct 2016 12:11:59 +0100 Subject: [PATCH 06/11] Fix import moment js inside the component --- .../ng2-activiti-analytics/karma-test-shim.js | 28 ++++++++++--------- .../ng2-activiti-analytics/karma.conf.js | 1 + 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/ng2-components/ng2-activiti-analytics/karma-test-shim.js b/ng2-components/ng2-activiti-analytics/karma-test-shim.js index 4702804ae0..a9c385d263 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', + 'moment' : 'npm:moment/min/moment.min.js', 'alfresco-js-api': 'npm:alfresco-js-api/dist', 'ng2-alfresco-core': 'npm:ng2-alfresco-core/dist' @@ -62,8 +63,9 @@ var packages = { 'app': { main: 'main.js', defaultExtension: 'js' }, 'rxjs': { defaultExtension: 'js' }, 'ng2-translate': { defaultExtension: 'js' }, + 'ng2-charts': { defaultExtension: 'js' }, + 'moment': { defaultExtension: 'js' }, - 'ng2-charts' : '/base/node_modules/ng2-charts', 'alfresco-js-api': { main: './alfresco-js-api.js', defaultExtension: 'js'}, 'ng2-alfresco-core': { main: './index.js', defaultExtension: 'js'} }; @@ -82,17 +84,17 @@ System.import('@angular/core/testing') function initTestBed(){ return Promise.all([ - System.import('@angular/core/testing'), - System.import('@angular/platform-browser-dynamic/testing') - ]) - .then(function (providers) { - var coreTesting = providers[0]; - var browserTesting = providers[1]; + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ]) + .then(function (providers) { + var coreTesting = providers[0]; + var browserTesting = providers[1]; - coreTesting.TestBed.initTestEnvironment( - browserTesting.BrowserDynamicTestingModule, - browserTesting.platformBrowserDynamicTesting()); - }) + coreTesting.TestBed.initTestEnvironment( + browserTesting.BrowserDynamicTestingModule, + browserTesting.platformBrowserDynamicTesting()); + }) } // Import all spec files and start karma @@ -101,6 +103,6 @@ function initTesting () { allSpecFiles.map(function (moduleName) { return System.import(moduleName); }) - ) - .then(__karma__.start, __karma__.error); + ) + .then(__karma__.start, __karma__.error); } diff --git a/ng2-components/ng2-activiti-analytics/karma.conf.js b/ng2-components/ng2-activiti-analytics/karma.conf.js index 1f5f12c324..5d4459ff78 100644 --- a/ng2-components/ng2-activiti-analytics/karma.conf.js +++ b/ng2-components/ng2-activiti-analytics/karma.conf.js @@ -45,6 +45,7 @@ module.exports = function (config) { { pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false }, { pattern: 'node_modules/ng2-charts/**/*.js', included: false, served: true, watched: false }, + { pattern: 'node_modules/moment/**/*.js', included: false, served: true, watched: false }, // ng2-components {pattern: 'node_modules/ng2-alfresco-core/dist/**/*.*', included: false, served: true, watched: false}, From 8f3dbb0d7db1608f730e07ff7e8428a7d67fa3bd Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Fri, 7 Oct 2016 16:50:53 +0100 Subject: [PATCH 07/11] Use mdl-date-picker --- .../ng2-activiti-analytics/package.json | 1 + .../src/components/analytics.component.html | 5 +- .../widgets/date-range/date-range.widget.css | 3 + .../widgets/date-range/date-range.widget.html | 60 +++++++-- .../widgets/date-range/date-range.widget.ts | 123 ++++++++++++++++-- .../ng2-activiti-analytics/src/i18n/en.json | 4 +- 6 files changed, 172 insertions(+), 24 deletions(-) diff --git a/ng2-components/ng2-activiti-analytics/package.json b/ng2-components/ng2-activiti-analytics/package.json index 8a77a7d52e..6aa9bfd540 100644 --- a/ng2-components/ng2-activiti-analytics/package.json +++ b/ng2-components/ng2-activiti-analytics/package.json @@ -54,6 +54,7 @@ "alfresco-js-api": "^0.3.0", "chart.js": "^2.1.4", "core-js": "^2.4.1", + "md-date-time-picker": "^2.2.0", "ng2-alfresco-core": "0.3.2", "ng2-charts": "1.1.0", "ng2-translate": "2.5.0", 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 01b14984b7..1f81ae1637 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html @@ -40,6 +40,7 @@ (dateRangeChanged)="onDateRangeChange($event)">
+
@@ -49,7 +50,9 @@

- +
diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.css b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.css index e69de29bb2..384c81f215 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.css +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.css @@ -0,0 +1,3 @@ +.date-picker-mdl { + margin-left: 20px; +} \ No newline at end of file diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html index a674d0fe5d..3754f5a3ab 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html @@ -1,16 +1,48 @@ -
-
- - -
-
- - +
+
+ Error: startDate is greater than + endDate +
+
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ +
+
+
+
+
+

Form : {{ dataForm.value | json }}

+ +

FormGroup : {{ dataForm.get('dateRange').value | json }}

+ +

FormGroup valid : {{ dataForm.get('dateRange').valid }}

+ +

FormGroup status : {{ dataForm.get('dateRange').errors | json }}

\ No newline at end of file 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 d1821d4251..e9f60df975 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 @@ -15,16 +15,35 @@ * limitations under the License. */ -import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; +import { AbstractControl, FormGroup, FormBuilder, Validators } from '@angular/forms'; +import { WidgetComponent } from './../widget.component'; import * as moment from 'moment'; +declare let mdDateTimePicker: any; + +function dateCheck(c: AbstractControl) { + let startDate = moment(c.get('startDate').value); + let endDate = moment(c.get('endDate').value); + let result = startDate.isAfter(endDate); + return result ? {'greaterThan': true} : null; +} + @Component({ moduleId: module.id, selector: 'date-range-widget', templateUrl: './date-range.widget.html', styleUrls: ['./date-range.widget.css'] }) -export class DateRangeWidget { +export class DateRangeWidget extends WidgetComponent { + + public static FORMAT_DATE_ACTIVITI: string = 'YYYY-MM-DD'; + + @ViewChild('startElement') + startElement: any; + + @ViewChild('endElement') + endElement: any; @Input() field: any; @@ -32,18 +51,106 @@ export class DateRangeWidget { @Output() dateRangeChanged: EventEmitter = new EventEmitter(); - constructor() {} + dataForm: FormGroup; - public onDateRangeChanged(startDate: HTMLInputElement, endDate: HTMLInputElement) { - if (startDate.validity.valid && endDate.validity.valid) { - let dateStart = this.convertMomentDate(startDate.value); - let endStart = this.convertMomentDate(endDate.value); + dialogStart: any = new mdDateTimePicker.default({ + type: 'date', + future: moment().add(21, 'years') + }); + + dialogEnd: any = new mdDateTimePicker.default({ + type: 'date', + future: moment().add(21, 'years') + }); + + debug: boolean = false; + + constructor(public elementRef: ElementRef, + private formBuilder: FormBuilder) { + super(); + } + + ngOnInit() { + this.initForm(); + this.initSartDateDialog(); + this.initEndDateDialog(); + } + + initForm() { + let today = moment().format(DateRangeWidget.FORMAT_DATE_ACTIVITI); + this.dataForm = this.formBuilder.group({ + dateRange: this.formBuilder.group({ + startDate: [today, Validators.required], + endDate: [today, Validators.required] + }, {validator: dateCheck}) + }); + this.dataForm.valueChanges.subscribe(data => this.onValueChanged(data)); + this.dataForm.controls['dateRange'].valueChanges.subscribe(data => this.onGroupValueChanged(data)); + } + + initSartDateDialog() { + this.dialogStart.trigger = this.startElement.nativeElement; + + let startDateButton = document.getElementById('startDateButton'); + startDateButton.addEventListener('click', () => { + this.dialogStart.toggle(); + }); + } + + initEndDateDialog() { + this.dialogEnd.trigger = this.endElement.nativeElement; + + let endDateButton = document.getElementById('endDateButton'); + endDateButton.addEventListener('click', () => { + this.dialogEnd.toggle(); + }); + } + + onOkStart(inputEl: HTMLInputElement) { + let date = this.dialogStart.time.format(DateRangeWidget.FORMAT_DATE_ACTIVITI); + let dateRange: any = this.dataForm.controls['dateRange']; + dateRange.patchValue({ + startDate: date + }); + let materialElemen: any = inputEl.parentElement; + if (materialElemen) { + materialElemen.MaterialTextfield.change(date); + } + } + + onOkEnd(inputEl: HTMLInputElement) { + let date = this.dialogEnd.time.format(DateRangeWidget.FORMAT_DATE_ACTIVITI); + let dateRange: any = this.dataForm.controls['dateRange']; + dateRange.patchValue({ + endDate: date + }); + + let materialElemen: any = inputEl.parentElement; + if (materialElemen) { + materialElemen.MaterialTextfield.change(date); + } + } + + onGroupValueChanged(data: any) { + if (this.dataForm.controls['dateRange'].valid) { + let dateRange: any = this.dataForm.controls['dateRange']; + let dateStart = this.convertMomentDate(dateRange.controls['startDate'].value); + // let endStart = this.convertMomentDate(this.dataForm.controls['endDate'].value); + console.log(dateStart); + } + } + + onValueChanged(data: any) { + if (this.dataForm.valid) { + let dateRange: any = this.dataForm.controls['dateRange']; + let dateStart = this.convertMomentDate(dateRange.controls['startDate'].value); + let endStart = this.convertMomentDate(dateRange.controls['endDate'].value); this.dateRangeChanged.emit({startDate: dateStart, endDate: endStart}); } } public convertMomentDate(date: string) { - return moment(date, 'DD/MM/YYYY', true).format('YYYY-MM-DD') + 'T00:00:00.000Z'; + return moment(date, DateRangeWidget.FORMAT_DATE_ACTIVITI, true).format(DateRangeWidget.FORMAT_DATE_ACTIVITI) + 'T00:00:00.000Z'; } } diff --git a/ng2-components/ng2-activiti-analytics/src/i18n/en.json b/ng2-components/ng2-activiti-analytics/src/i18n/en.json index 9d9cf9aa42..fd01ebcd42 100644 --- a/ng2-components/ng2-activiti-analytics/src/i18n/en.json +++ b/ng2-components/ng2-activiti-analytics/src/i18n/en.json @@ -28,8 +28,10 @@ "DATE-RANGE-INTERVAL": "Aggregate dates by" }, "TASK-SLA": { + "TASK": "Task", "PROCESS-DEFINITION": "Process definition", - "DATE-RANGE": "Date range" + "DATE-RANGE": "Date range", + "SLA-DURATION": "What is the time this task needs to be completed in to be within the SLA?" } }, "PROCESS-STATUS": "Process status", From ec66cdff893232b2d0ebbd196a3150ab39e74ffb Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Fri, 7 Oct 2016 16:51:09 +0100 Subject: [PATCH 08/11] Add mdl-date-picker dependency --- demo-shell-ng2/index.html | 5 +++++ ng2-components/ng2-alfresco-login/demo/package.json | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/demo-shell-ng2/index.html b/demo-shell-ng2/index.html index ba09be82ca..3294099a58 100644 --- a/demo-shell-ng2/index.html +++ b/demo-shell-ng2/index.html @@ -14,6 +14,9 @@ + + @@ -35,6 +38,8 @@ + + diff --git a/ng2-components/ng2-alfresco-login/demo/package.json b/ng2-components/ng2-alfresco-login/demo/package.json index ace2ffc107..8029dde58b 100644 --- a/ng2-components/ng2-alfresco-login/demo/package.json +++ b/ng2-components/ng2-alfresco-login/demo/package.json @@ -60,7 +60,8 @@ "rxjs": "5.0.0-beta.12", "systemjs": "0.19.27", "zone.js": "^0.6.23", - + "md-date-time-picker": "^2.2.0", + "moment": "2.15.1", "material-design-icons": "2.2.3", "material-design-lite": "1.2.1", "ng2-translate": "2.5.0", From d5f37f3e5cf8152690318ae7ee6db3bdd5e8e8fc Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Mon, 10 Oct 2016 10:07:27 +0100 Subject: [PATCH 09/11] Use an external formGroup instead of a new form in the dateRange component --- .../src/components/analytics.component.html | 10 ++- .../src/components/analytics.component.ts | 18 +++- .../widgets/date-range/date-range.widget.html | 86 +++++++++---------- .../widgets/date-range/date-range.widget.ts | 43 +++------- 4 files changed, 78 insertions(+), 79 deletions(-) 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 1f81ae1637..9409f13586 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html @@ -1,6 +1,6 @@
-
+

{{reportDetails.name}}

@@ -36,7 +36,7 @@

-
@@ -53,6 +53,12 @@ +
+

ReportForm : {{ reportForm.value | json }}

+

ReportForm valid : {{ reportForm.valid }}

+

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

+

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

+
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 1fe4d00070..cb897fe774 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts @@ -20,7 +20,8 @@ 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'; @Component({ moduleId: module.id, @@ -48,8 +49,13 @@ export class AnalyticsComponent implements OnInit, OnChanges { reports: any[]; + reportForm: FormGroup; + + debug: boolean = true; + constructor(private translate: AlfrescoTranslationService, - private analyticsService: AnalyticsService) { + private analyticsService: AnalyticsService, + private formBuilder: FormBuilder ) { console.log('AnalyticsComponent'); if (translate) { translate.addTranslationFolder('node_modules/ng2-activiti-analytics/src'); @@ -57,7 +63,13 @@ 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] + }) + }); } ngOnChanges(changes: SimpleChanges) { diff --git a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html index 3754f5a3ab..bade2bc528 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html +++ b/ng2-components/ng2-activiti-analytics/src/components/widgets/date-range/date-range.widget.html @@ -1,48 +1,48 @@
-
-
- Error: startDate is greater than - endDate -
-
-
- - -
-
-
- -
-
-
- - -
-
-
- +
+ + Start date must be less than End date + +
+
+
+ + + + Start is required +
-
-
+
+ +
+
+
+ + +
+
+
+ +
+
+
-

Form : {{ dataForm.value | json }}

- -

FormGroup : {{ dataForm.get('dateRange').value | json }}

- -

FormGroup valid : {{ dataForm.get('dateRange').valid }}

- -

FormGroup status : {{ dataForm.get('dateRange').errors | json }}

+

FormGroup : {{ dateRange.value | json }}

+

FormGroup valid : {{ dateRange.valid }}

+

FormGroup status : {{ dateRange.errors | json }}

+

FormGroup start status : {{ dateRange.controls.startDate.errors | json }}

+

FormGroup end status: {{ dateRange.controls.endDate.errors | json }}

\ No newline at end of file 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 e9f60df975..315c2ca109 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, Validators } from '@angular/forms'; +import { AbstractControl, FormGroup, FormBuilder } from '@angular/forms'; import { WidgetComponent } from './../widget.component'; import * as moment from 'moment'; @@ -45,13 +45,16 @@ export class DateRangeWidget extends WidgetComponent { @ViewChild('endElement') endElement: any; + @Input('group') + public dateRange: FormGroup; + @Input() field: any; @Output() dateRangeChanged: EventEmitter = new EventEmitter(); - dataForm: FormGroup; + debug: boolean = true; dialogStart: any = new mdDateTimePicker.default({ type: 'date', @@ -63,8 +66,6 @@ export class DateRangeWidget extends WidgetComponent { future: moment().add(21, 'years') }); - debug: boolean = false; - constructor(public elementRef: ElementRef, private formBuilder: FormBuilder) { super(); @@ -77,15 +78,8 @@ export class DateRangeWidget extends WidgetComponent { } initForm() { - let today = moment().format(DateRangeWidget.FORMAT_DATE_ACTIVITI); - this.dataForm = this.formBuilder.group({ - dateRange: this.formBuilder.group({ - startDate: [today, Validators.required], - endDate: [today, Validators.required] - }, {validator: dateCheck}) - }); - this.dataForm.valueChanges.subscribe(data => this.onValueChanged(data)); - this.dataForm.controls['dateRange'].valueChanges.subscribe(data => this.onGroupValueChanged(data)); + this.dateRange.setValidators(dateCheck); + this.dateRange.valueChanges.subscribe(data => this.onGroupValueChanged(data)); } initSartDateDialog() { @@ -108,8 +102,7 @@ export class DateRangeWidget extends WidgetComponent { onOkStart(inputEl: HTMLInputElement) { let date = this.dialogStart.time.format(DateRangeWidget.FORMAT_DATE_ACTIVITI); - let dateRange: any = this.dataForm.controls['dateRange']; - dateRange.patchValue({ + this.dateRange.patchValue({ startDate: date }); let materialElemen: any = inputEl.parentElement; @@ -120,8 +113,7 @@ export class DateRangeWidget extends WidgetComponent { onOkEnd(inputEl: HTMLInputElement) { let date = this.dialogEnd.time.format(DateRangeWidget.FORMAT_DATE_ACTIVITI); - let dateRange: any = this.dataForm.controls['dateRange']; - dateRange.patchValue({ + this.dateRange.patchValue({ endDate: date }); @@ -132,19 +124,9 @@ export class DateRangeWidget extends WidgetComponent { } onGroupValueChanged(data: any) { - if (this.dataForm.controls['dateRange'].valid) { - let dateRange: any = this.dataForm.controls['dateRange']; - let dateStart = this.convertMomentDate(dateRange.controls['startDate'].value); - // let endStart = this.convertMomentDate(this.dataForm.controls['endDate'].value); - console.log(dateStart); - } - } - - onValueChanged(data: any) { - if (this.dataForm.valid) { - let dateRange: any = this.dataForm.controls['dateRange']; - let dateStart = this.convertMomentDate(dateRange.controls['startDate'].value); - let endStart = this.convertMomentDate(dateRange.controls['endDate'].value); + if (this.dateRange.valid) { + let dateStart = this.convertMomentDate(this.dateRange.controls['startDate'].value); + let endStart = this.convertMomentDate(this.dateRange.controls['endDate'].value); this.dateRangeChanged.emit({startDate: dateStart, endDate: endStart}); } } @@ -152,5 +134,4 @@ export class DateRangeWidget extends WidgetComponent { public convertMomentDate(date: string) { return moment(date, DateRangeWidget.FORMAT_DATE_ACTIVITI, true).format(DateRangeWidget.FORMAT_DATE_ACTIVITI) + 'T00:00:00.000Z'; } - } From 9dc673af089e9beb416bd46ccf6e4838cadde6c3 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Mon, 10 Oct 2016 10:34:31 +0100 Subject: [PATCH 10/11] Basic unit test setting --- .../ng2-activiti-analytics/karma-test-shim.js | 2 + .../ng2-activiti-analytics/karma.conf.js | 1 + .../components/analytics.component.spec.ts | 43 +++++++++++++------ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/ng2-components/ng2-activiti-analytics/karma-test-shim.js b/ng2-components/ng2-activiti-analytics/karma-test-shim.js index a9c385d263..c9d37f3aa2 100644 --- a/ng2-components/ng2-activiti-analytics/karma-test-shim.js +++ b/ng2-components/ng2-activiti-analytics/karma-test-shim.js @@ -56,6 +56,7 @@ var map = { 'moment' : 'npm:moment/min/moment.min.js', 'alfresco-js-api': 'npm:alfresco-js-api/dist', + 'ng2-activiti-analytics': 'npm:ng2-activiti-analytics/dist', 'ng2-alfresco-core': 'npm:ng2-alfresco-core/dist' }; @@ -67,6 +68,7 @@ var packages = { 'moment': { defaultExtension: 'js' }, 'alfresco-js-api': { main: './alfresco-js-api.js', defaultExtension: 'js'}, + 'ng2-activiti-analytics': { main: './index.js', defaultExtension: 'js'}, 'ng2-alfresco-core': { main: './index.js', defaultExtension: 'js'} }; diff --git a/ng2-components/ng2-activiti-analytics/karma.conf.js b/ng2-components/ng2-activiti-analytics/karma.conf.js index 5d4459ff78..153f4ad816 100644 --- a/ng2-components/ng2-activiti-analytics/karma.conf.js +++ b/ng2-components/ng2-activiti-analytics/karma.conf.js @@ -44,6 +44,7 @@ module.exports = function (config) { // ng2-components { pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false }, + { pattern: 'node_modules/ng2-activiti-analytics/dist/**/*.js', included: false, served: true, watched: false }, { pattern: 'node_modules/ng2-charts/**/*.js', included: false, served: true, watched: false }, { pattern: 'node_modules/moment/**/*.js', included: false, served: true, watched: false }, 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 7f61019dd0..52ff7da466 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 @@ -16,16 +16,30 @@ */ import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { AnalyticsComponent } from './analytics.component'; -import { DebugElement } from '@angular/core'; import { - AlfrescoAuthenticationService, - AlfrescoSettingsService, - AlfrescoApiService, CoreModule } from 'ng2-alfresco-core'; -describe('Test ng2-alfresco-analytics analytics component ', () => { +import { AnalyticsReportListComponent } from '../components/analytics-report-list.component'; +import { AnalyticsComponent } from '../components/analytics.component'; +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'; + +export const ANALYTICS_DIRECTIVES: any[] = [ + AnalyticsComponent, + AnalyticsReportListComponent, + WIDGET_DIRECTIVES +]; +export const ANALYTICS_PROVIDERS: any[] = [ + AnalyticsService +]; + + +describe('Show component HTML', () => { let component: any; let fixture: ComponentFixture; @@ -37,25 +51,26 @@ describe('Test ng2-alfresco-analytics analytics component ', () => { imports: [ CoreModule ], - declarations: [AnalyticsComponent], + declarations: [ + ...ANALYTICS_DIRECTIVES, + ...CHART_DIRECTIVES + ], providers: [ - AlfrescoSettingsService, - AlfrescoAuthenticationService, - AlfrescoApiService + ...ANALYTICS_PROVIDERS ] }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(AnalyticsComponent); - + component = fixture.componentInstance; debug = fixture.debugElement; element = fixture.nativeElement; - component = fixture.componentInstance; fixture.detectChanges(); }); - xit('No test', () => { + it('Display component tag base-chart', () => { + expect(true).toBe(true); }); -}); +}); From 92ec83cfd6985c237a6305cc5f3c948b4ab233ec Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Mon, 10 Oct 2016 14:34:27 +0100 Subject: [PATCH 11/11] Add analytics report list unit tests --- .../ng2-activiti-analytics/karma.conf.js | 14 +- .../analytics-report-list.component.html | 6 +- .../analytics-report-list.component.spec.ts | 131 ++++++++++++++++++ .../analytics-report-list.component.ts | 4 +- 4 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts diff --git a/ng2-components/ng2-activiti-analytics/karma.conf.js b/ng2-components/ng2-activiti-analytics/karma.conf.js index 153f4ad816..49636788ba 100644 --- a/ng2-components/ng2-activiti-analytics/karma.conf.js +++ b/ng2-components/ng2-activiti-analytics/karma.conf.js @@ -34,25 +34,19 @@ module.exports = function (config) { 'node_modules/alfresco-js-api/dist/alfresco-js-api.js', {pattern: 'node_modules/ng2-translate/**/*.js', included: false, watched: false}, - {pattern: 'node_modules/ng2-translate/**/*.js.map', included: false, watched: false}, 'karma-test-shim.js', // paths loaded via module imports - {pattern: 'dist/**/*.*', included: false, watched: true}, + {pattern: 'dist/**/*.js', included: false, watched: true}, + {pattern: 'dist/**/*.html', included: true, served: true, watched: true}, + {pattern: 'dist/**/*.css', included: true, served: true, watched: true}, // ng2-components - - { pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false }, - { pattern: 'node_modules/ng2-activiti-analytics/dist/**/*.js', included: false, served: true, watched: false }, + { 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/moment/**/*.js', included: false, served: true, watched: false }, - // 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}, - // paths to support debugging with source maps in dev tools {pattern: 'src/**/*.ts', included: false, watched: false}, {pattern: 'dist/**/*.js.map', included: false, watched: false} diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.html b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.html index c5a70dea46..fd2d30deaa 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.html @@ -1,9 +1,9 @@