From c18165caf1a16387d92c0ad6fb0eb687f8432a4f Mon Sep 17 00:00:00 2001 From: Mario Romano Date: Mon, 30 Jan 2017 19:06:00 +0000 Subject: [PATCH 01/40] #1576 fix npm build --- demo-shell-ng2/config/webpack.prod.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/demo-shell-ng2/config/webpack.prod.js b/demo-shell-ng2/config/webpack.prod.js index 14e0493451..3ee58620af 100644 --- a/demo-shell-ng2/config/webpack.prod.js +++ b/demo-shell-ng2/config/webpack.prod.js @@ -40,15 +40,15 @@ module.exports = webpackMerge(commonConfig, { // Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin // Minify all javascript, switch loaders to minimizing mode - new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618 - mangle: { - keep_fnames: true - }, - compressor: { - screw_ie8: true, - warnings: false - } - }), + // new webpack.optimize.UglifyJsPlugin({ + // mangle: { + // keep_fnames: true + // }, + // compressor: { + // screw_ie8: true, + // warnings: false + // } + // }), // Extract css files // Reference: https://github.com/webpack/extract-text-webpack-plugin From 6431d7c04f9c76cfdba9eb9a9f5efd8e9a2ce1dd Mon Sep 17 00:00:00 2001 From: Mario Romano Date: Fri, 3 Feb 2017 15:55:54 +0000 Subject: [PATCH 02/40] Update README.md --- ng2-components/ng2-alfresco-login/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ng2-components/ng2-alfresco-login/README.md b/ng2-components/ng2-alfresco-login/README.md index 86dd38ea25..4ecfbbb34e 100644 --- a/ng2-components/ng2-alfresco-login/README.md +++ b/ng2-components/ng2-alfresco-login/README.md @@ -177,7 +177,7 @@ platformBrowserDynamic().bootstrapModule(AppModule); ## Change footer content - + You can replace the entire content in the footer of the login component with your custom content. @@ -189,7 +189,7 @@ You can replace the entire content in the footer of the login component with you ## Change header content - + You can replace the entire content in the header of the login component with your custom content. From 30b4db816158d5265dcf045c5f31a5e70295528a Mon Sep 17 00:00:00 2001 From: Maurizio Vitale Date: Fri, 3 Feb 2017 16:12:17 +0000 Subject: [PATCH 03/40] Analytics - Improve look and feel and user experience (#1585) * #1583 Improve look and feel and user experience * #1583 Add layoutType property to report list Improve unit test Improve docs * #1583 Review changes --- .../ng2-activiti-analytics/README.md | 31 +++++- .../analytics-generator.component.css | 5 + .../analytics-generator.component.html | 96 +++++++++++-------- .../analytics-generator.component.spec.ts | 38 ++++++++ .../analytics-generator.component.ts | 16 ++++ .../analytics-report-list.component.css | 35 ++++++- .../analytics-report-list.component.html | 18 +++- .../analytics-report-list.component.spec.ts | 54 +++++++++++ .../analytics-report-list.component.ts | 28 +++++- .../analytics-report-parameters.component.css | 2 +- ...analytics-report-parameters.component.html | 21 ++-- .../ng2-activiti-analytics/src/i18n/en.json | 2 +- .../src/models/chart.model.ts | 33 +++++++ 13 files changed, 318 insertions(+), 61 deletions(-) diff --git a/ng2-components/ng2-activiti-analytics/README.md b/ng2-components/ng2-activiti-analytics/README.md index 108952f702..bc9bae8974 100644 --- a/ng2-components/ng2-activiti-analytics/README.md +++ b/ng2-components/ng2-activiti-analytics/README.md @@ -112,7 +112,7 @@ Follow the 3 steps below: The component shows the list of all the available reports ```html - + ``` Usage example of this component : @@ -132,7 +132,7 @@ import { AnalyticsModule } from 'ng2-activiti-analytics';
- +
` @@ -179,7 +179,9 @@ platformBrowserDynamic().bootstrapModule(AppModule); #### Options -No options. +| Name | Type | Required | Description | +| --- | --- | --- | --- | +| `layoutType` | {string} | required | Define the layout of the apps. There are two possible values: GRID or LIST. LIST is the default value| ## Basic usage example Activiti Analytics @@ -258,6 +260,29 @@ platformBrowserDynamic().bootstrapModule(AppModule); |`reportId` | The report id | |`debug` | Flag to enable or disable the Form values in the console log | +## Basic usage example Analytics Generator + +The component generate and show the charts + +```html + +``` + +#### Events + +| Name | Description | +| --- | --- | +|`onSuccess` | The event is emitted when the charts are loaded | +|`onError` | The event is emitted when an error occur during the loading | + +#### Options + +| Name | Description | +| --- | --- | +|`reportId` | The report id | +|`reportParamQuery` | The object contains all the parameters that the report needs | + + ## Build from sources Alternatively you can build component from sources with the following commands: diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.css b/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.css index e0c64c5d75..0f18f22972 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.css +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.css @@ -3,3 +3,8 @@ .analytics-row__entry { cursor: pointer; } + +.report-icons { + margin: 20px 20px 20px 20px; + float: right; +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.html b/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.html index 633e2d7c66..cf15b30497 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.html @@ -1,9 +1,18 @@
-
-

{{report.title}}

+
+ +
+
+
-
+
+

{{report.title}}

{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}
{{'ANALYTICS.MESSAGES.ZERO-DATA-FOUND' | translate}}
@@ -14,44 +23,51 @@
-
-
{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}
-
- - - - - - - -
{{label | translate}}
{{row | translate }}
+
+
+

{{report.title}}

+
{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}
+
+ + + + + + + +
{{label | translate}}
{{row | translate }}
+
-
-
{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}
-
- - - - - - - -
{{label | translate}}
{{row | translate }}
-
-
- - - - - - - -
{{label | translate}}
{{row | translate }}
+
+
+

{{report.title}}

+
{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}
+
+ + + + + + + +
{{label | translate}}
{{row | translate }}
+
+
+ + + + + + + +
{{label | translate}}
{{row | translate }}
+
-
+
+

{{report.title}}

{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}
-
+
+

{{report.title}}

{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}
- +
+

{{report.title}}

+ +
{{'ANALYTICS.MESSAGES.UNKNOWN-WIDGET-TYPE' | translate}}: {{report.type}} diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.spec.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.spec.ts index 77313de50d..e94809f961 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.spec.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.spec.ts @@ -135,6 +135,44 @@ describe('AnalyticsGeneratorComponent', () => { }); }); + it('Should render the Process definition overview report when onchanges is called ', (done) => { + component.onSuccess.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.reportId = 1001; + component.reportParamQuery = new ReportQuery({status: 'All'}); + component.ngOnChanges(); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticMock.chartProcessDefOverview + }); + }); + it('Should render the Task overview report ', (done) => { component.onSuccess.subscribe((res) => { expect(res).toBeDefined(); diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.ts index 09097365c8..9625ada99a 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-generator.component.ts @@ -44,6 +44,7 @@ export class AnalyticsGeneratorComponent implements OnChanges { reports: Chart[]; showDetails: boolean = false; + currentChartPosition: number; public barChartOptions: any = { responsive: true, @@ -83,6 +84,9 @@ export class AnalyticsGeneratorComponent implements OnChanges { this.analyticsService.getReportsByParams(reportId, reportParamQuery).subscribe( (res: Chart[]) => { this.reports = res; + if (this.reports) { + this.selectFirstReport(); + } this.onSuccess.emit(res); }, (err: any) => { @@ -116,4 +120,16 @@ export class AnalyticsGeneratorComponent implements OnChanges { isShowDetails(): boolean { return this.showDetails; } + + isCurrent(position: number) { + return position === this.currentChartPosition ? true : false; + } + + selectCurrent(position: number) { + this.currentChartPosition = position; + } + + selectFirstReport() { + this.selectCurrent(0); + } } 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 index 073fb82bbd..e9065e2264 100644 --- 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 @@ -16,4 +16,37 @@ .activiti-filters__entry.active .activiti-filters__entry-icon { color: rgb(68,138,255); -} \ No newline at end of file +} + +.application-title { + color: white; + z-index: 7; +} + +.logo { + position: absolute; + right: 20px; + top: 35px; + z-index: 6; +} +.logo i{ + font-size: 70px; +} + +.theme-1 { + background-color: #269abc; +} + +.theme-1 .logo i { + color: #168aac; +} +.theme-1 .mdl-card__actions i { + color: #168aac; +} +.theme-1 .mdl-card__actions i:hover { + color: #b7dfea; +} + +.selectedIcon{ + color: #e9f1f3!important; +} 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 38a6af1268..40a9ba9bf5 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,5 +1,5 @@ \ No newline at end of file +
+
+ +
+

{{report.name}}

+
+
+

{{report.description}}

+
+
+ done +
+
+
+
diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts index c437ab7342..7e31bd19b9 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts @@ -21,6 +21,7 @@ import { Observable } from 'rxjs/Rx'; import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core'; import { AnalyticsReportListComponent } from '../components/analytics-report-list.component'; import { AnalyticsService } from '../services/analytics.service'; +import { ReportParametersModel } from '../models/report.model'; declare let jasmine: any; @@ -166,6 +167,59 @@ describe('AnalyticsReportListComponent', () => { component.selectReport(reportSelected); }); + it('Should return true if the current report is selected', () => { + component.selectReport(reportSelected); + expect(component.isSelected(reportSelected)).toBe(true); + }); + + it('Should return false if the current report is different', () => { + component.selectReport(reportSelected); + let anotherReport = {'id': 111, 'name': 'Another Fake Test Process definition overview'}; + expect(component.isSelected(anotherReport)).toBe(false); + }); + + it('Should reload the report list', (done) => { + component.initObserver(); + let report = new ReportParametersModel({'id': 2002, 'name': 'Fake Test Process definition heat map'}); + component.reports = [report]; + expect(component.reports.length).toEqual(1); + component.reload(); + + component.onSuccess.subscribe(() => { + expect(component.reports.length).toEqual(5); + done(); + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: reportList + }); + }); + + }); + + describe('layout', () => { + + it('should display a list by default', () => { + fixture.detectChanges(); + expect(component.isGrid()).toBe(false); + expect(component.isList()).toBe(true); + }); + + it('should display a grid when configured to', () => { + component.layoutType = AnalyticsReportListComponent.LAYOUT_GRID; + fixture.detectChanges(); + expect(component.isGrid()).toBe(true); + expect(component.isList()).toBe(false); + }); + + it('should display a list when configured to', () => { + component.layoutType = AnalyticsReportListComponent.LAYOUT_LIST; + fixture.detectChanges(); + expect(component.isGrid()).toBe(false); + expect(component.isList()).toBe(true); + }); }); }); 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 ca2649f230..2563c0fb6c 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 @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, OnInit, Output, Input } from '@angular/core'; import { Observer, Observable } from 'rxjs/Rx'; import { LogService } from 'ng2-alfresco-core'; import { AnalyticsService } from '../services/analytics.service'; @@ -29,6 +29,12 @@ import { ReportParametersModel } from '../models/report.model'; }) export class AnalyticsReportListComponent implements OnInit { + public static LAYOUT_LIST: string = 'LIST'; + public static LAYOUT_GRID: string = 'GRID'; + + @Input() + layoutType: string = AnalyticsReportListComponent.LAYOUT_LIST; + @Output() reportClick: EventEmitter = new EventEmitter(); @@ -51,11 +57,15 @@ export class AnalyticsReportListComponent implements OnInit { } ngOnInit() { + this.initObserver(); + + this.getReportList(); + } + + initObserver() { this.report$.subscribe((report: ReportParametersModel) => { this.reports.push(report); }); - - this.getReportList(); } /** @@ -131,4 +141,16 @@ export class AnalyticsReportListComponent implements OnInit { this.currentReport = report; this.reportClick.emit(report); } + + isSelected(report: any) { + return this.currentReport === report ? true : false; + } + + isList() { + return this.layoutType === AnalyticsReportListComponent.LAYOUT_LIST; + } + + isGrid() { + return this.layoutType === AnalyticsReportListComponent.LAYOUT_GRID; + } } diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.css b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.css index 07f935cbb9..947c5d475a 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.css +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.css @@ -56,7 +56,7 @@ } .report-container { - border: solid 1px rgb(212, 212, 212); + border-bottom: solid 1px rgb(212, 212, 212); padding: 10px 10px 10px 10px; } diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.html b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.html index 98939ea442..91b38999f5 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.html @@ -1,11 +1,5 @@
- - - {{'ANALYTICS.MESSAGES.SETTING-TITLE' | translate}} - -
+
@@ -21,12 +15,15 @@ />
- + +
mode_edit -

{{reportParameters.name}}

- -

-
+

{{reportParameters.name}}

+
+
+

diff --git a/ng2-components/ng2-activiti-analytics/src/i18n/en.json b/ng2-components/ng2-activiti-analytics/src/i18n/en.json index 008eb48aff..9e5cd9ca95 100644 --- a/ng2-components/ng2-activiti-analytics/src/i18n/en.json +++ b/ng2-components/ng2-activiti-analytics/src/i18n/en.json @@ -6,7 +6,7 @@ "FILL-PARAMETER": "Fill in the parameters to generate your report", "NO-DATA-FOUND": "No data found", "ZERO-DATA-FOUND": "There are only zero values", - "SETTING-TITLE": "Change report setting" + "SETTING-TITLE": "Settings" } }, "__KEY_REPORTING": { diff --git a/ng2-components/ng2-activiti-analytics/src/models/chart.model.ts b/ng2-components/ng2-activiti-analytics/src/models/chart.model.ts index 5eaa1b3898..ba875e6e94 100644 --- a/ng2-components/ng2-activiti-analytics/src/models/chart.model.ts +++ b/ng2-components/ng2-activiti-analytics/src/models/chart.model.ts @@ -20,11 +20,13 @@ import * as moment from 'moment'; export class Chart { id: string; type: string; + icon: string; constructor(obj?: any) { this.id = obj && obj.id || null; if (obj && obj.type) { this.type = this.convertType(obj.type); + this.icon = this.getIconType(this.type); } } @@ -58,6 +60,37 @@ export class Chart { } return chartType; } + + private getIconType(type: string): string { + let typeIcon: string = ''; + switch (type) { + case 'pie': + typeIcon = 'pie_chart'; + break; + case 'table': + typeIcon = 'web'; + break; + case 'line': + typeIcon = 'show_chart'; + break; + case 'bar': + typeIcon = 'equalizer'; + break; + case 'multiBar': + typeIcon = 'poll'; + break; + case 'HeatMap': + typeIcon = 'share'; + break; + case 'masterDetailTable': + typeIcon = 'subtitles'; + break; + default: + typeIcon = 'web'; + break; + } + return typeIcon; + } } export class LineChart extends Chart { From 5c5911beefbb787504fd0d58f065c1ad62d1a9af Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 6 Feb 2017 09:54:35 +0000 Subject: [PATCH 04/40] Dev eromano tag example (#1596) * Update README.md * Readme update with tag example integration document list * add tag component in the document list demo --- .../app/components/files/files.component.html | 9 +++++++++ demo-shell-ng2/custom-translation/i18n/en.json | 1 + demo-shell-ng2/custom-translation/i18n/it.json | 1 + ng2-components/ng2-activiti-tasklist/README.md | 2 +- .../ng2-alfresco-documentlist/README.md | 16 ++++++++++++++-- .../docs/assets/document-list-tag-template.png | Bin 0 -> 85831 bytes 6 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 ng2-components/ng2-alfresco-documentlist/docs/assets/document-list-tag-template.png diff --git a/demo-shell-ng2/app/components/files/files.component.html b/demo-shell-ng2/app/components/files/files.component.html index f8b6e7e7ab..94b9382036 100644 --- a/demo-shell-ng2/app/components/files/files.component.html +++ b/demo-shell-ng2/app/components/files/files.component.html @@ -35,6 +35,15 @@ --> + + + + ``` #### Events diff --git a/ng2-components/ng2-alfresco-documentlist/README.md b/ng2-components/ng2-alfresco-documentlist/README.md index bb13408c71..ce6e74aff3 100644 --- a/ng2-components/ng2-alfresco-documentlist/README.md +++ b/ng2-components/ng2-alfresco-documentlist/README.md @@ -501,7 +501,7 @@ _You may want using **row** api to get raw value access. Use **data** api to get values with post-processing, like datetime/icon conversion._ -Final example, we'll name the context as `entry`: +In the Example below will prepend `Hi!` to each file and folder name in the list: ```html @@ -511,9 +511,21 @@ Final example, we'll name the context as `entry`: ``` -Example above will prepend `Hi!` to each file and folder name in the list. +In the Example below will add the [ng2-alfresco-tag](https://www.npmjs.com/package/ng2-alfresco-tag) component is integrate in the document list. +```html + + + +``` +![Tag component in document List](docs/assets/document-list-tag-template.png) ### Actions diff --git a/ng2-components/ng2-alfresco-documentlist/docs/assets/document-list-tag-template.png b/ng2-components/ng2-alfresco-documentlist/docs/assets/document-list-tag-template.png new file mode 100644 index 0000000000000000000000000000000000000000..769147a677c60207cec32014493982674971d6b4 GIT binary patch literal 85831 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ÐmL^c}K2uwqRG8qXRO|Wei52W()crvLm2-qmtMl$- zFG1@1v076JX}30x{N|fNIP+irHec?2m({HDI7mrQcnYw?abYakkIOTd{J1$j-C4Zs zC(9SLuW`n<(&#sal$XgQUk4M`Vl{AX;;xA~TJ#t95d+#MhA*AeK;hAR&6m-^KXJvP z20VQCfFqhSDis}3cQSN8rzJlbU-9Uh!8LcW04k}Zgj|C0OnQtb_INWNYVcF->kGrZx= zLSOn$Z6LWpI2-^}ydJ(S+u~~}d7@$PUbG^_8WV-CLIR>~cf!=ekMG>9-cb1ytH~iH z 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 Q)D1^fQR`{h6N{k#1;E`x-2eap literal 0 HcmV?d00001 From 7c54090deae6e97649311cad7fd18cef7f857e96 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 6 Feb 2017 09:55:12 +0000 Subject: [PATCH 05/40] ability to change position of the dropdown menu (left|right) (#1590) * ability to change position of the dropdown menu (left|right) * unit tests --- .../ng2-alfresco-datatable/README.md | 1 + .../datatable/datatable.component.html | 29 +++++++-- .../datatable/datatable.component.spec.ts | 62 +++++++++++++++++-- .../datatable/datatable.component.ts | 3 + .../ng2-alfresco-documentlist/README.md | 3 +- .../components/document-list.component.html | 1 + .../src/components/document-list.component.ts | 3 + 7 files changed, 93 insertions(+), 9 deletions(-) diff --git a/ng2-components/ng2-alfresco-datatable/README.md b/ng2-components/ng2-alfresco-datatable/README.md index b560bf048e..ad2754a8ef 100644 --- a/ng2-components/ng2-alfresco-datatable/README.md +++ b/ng2-components/ng2-alfresco-datatable/README.md @@ -177,6 +177,7 @@ platformBrowserDynamic().bootstrapModule(AppModule); | `data` | DataTableAdapter | instance of **ObjectDataTableAdapter** | data source | | `multiselect` | boolean | false | Toggles multiple row selection, renders checkboxes at the beginning of each row | | `actions` | boolean | false | Toggles data actions column | +| `actionsPosition` | string (left\|right) | right | Position of the actions dropdown menu. | | `fallbackThumbnail` | string | | Fallback image for row ehre thubnail is missing| ### Events diff --git a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html index 28bd176f42..be77cc8a4f 100644 --- a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html +++ b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html @@ -3,6 +3,10 @@ class="mdl-data-table mdl-js-data-table full-width mdl-data-table-fix-firefox"> + + + Actions +
-
-
- -
-
- -
-
- attachment - {{value}} +
+
+
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/display-value/display-value.widget.spec.ts b/ng2-components/ng2-activiti-form/src/components/widgets/display-value/display-value.widget.spec.ts index 17e3b896ef..207e51f4a1 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/display-value/display-value.widget.spec.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/display-value/display-value.widget.spec.ts @@ -20,6 +20,7 @@ import { CoreModule, LogServiceMock } from 'ng2-alfresco-core'; import { Observable } from 'rxjs/Rx'; import { DisplayValueWidget } from './display-value.widget'; import { FormService } from '../../../services/form.service'; +import { ActivitiContent } from '../../activiti-content.component'; import { EcmModelService } from '../../../services/ecm-model.service'; import { FormFieldModel } from './../core/form-field.model'; import { FormFieldTypes } from '../core/form-field-types'; @@ -688,7 +689,7 @@ describe('DisplayValueWidget', () => { window['componentHandler'] = componentHandler; TestBed.configureTestingModule({ imports: [CoreModule], - declarations: [DisplayValueWidget], + declarations: [DisplayValueWidget, ActivitiContent], providers: [ EcmModelService, FormService, diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.spec.ts b/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.spec.ts index 510b4c5b1f..1ffd67bebf 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.spec.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.spec.ts @@ -23,6 +23,7 @@ import { TabsWidget } from './tabs.widget'; import { TabModel } from '../core/tab.model'; import { WIDGET_DIRECTIVES } from '../index'; import { FormFieldComponent } from './../../form-field/form-field.component'; +import { ActivitiContent } from './../../activiti-content.component'; import { CoreModule } from 'ng2-alfresco-core'; describe('TabsWidget', () => { @@ -103,7 +104,7 @@ describe('TabsWidget', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [CoreModule], - declarations: [FormFieldComponent, WIDGET_DIRECTIVES] + declarations: [FormFieldComponent, ActivitiContent, WIDGET_DIRECTIVES] }).compileComponents().then(() => { fixture = TestBed.createComponent(TabsWidget); tabWidgetComponent = fixture.componentInstance; diff --git a/ng2-components/ng2-activiti-form/src/i18n/en.json b/ng2-components/ng2-activiti-form/src/i18n/en.json index 701b687e00..c05017b260 100644 --- a/ng2-components/ng2-activiti-form/src/i18n/en.json +++ b/ng2-components/ng2-activiti-form/src/i18n/en.json @@ -2,6 +2,9 @@ "FORM": { "START_FORM": { "TITLE": "Start Form" + }, + "PREVIEW": { + "IMAGE_NOT_AVAILABLE": "The preview image is not available." } } } diff --git a/ng2-components/ng2-activiti-form/src/i18n/it.json b/ng2-components/ng2-activiti-form/src/i18n/it.json new file mode 100644 index 0000000000..58d9aa460c --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/i18n/it.json @@ -0,0 +1,10 @@ +{ + "FORM": { + "START_FORM": { + "TITLE": "Inizia" + }, + "PREVIEW": { + "IMAGE_NOT_AVAILABLE": "Anteprima immagine non disponibile." + } + } +} diff --git a/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts b/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts index 28339b0ded..1e042a453f 100644 --- a/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts +++ b/ng2-components/ng2-activiti-form/src/services/form.service.spec.ts @@ -30,6 +30,7 @@ describe('FormService', () => { let service: FormService; let apiService: AlfrescoApiService; let logService: LogService; + let bpmCli: any; beforeEach(() => { TestBed.configureTestingModule({ @@ -44,6 +45,7 @@ describe('FormService', () => { }); service = TestBed.get(FormService); apiService = TestBed.get(AlfrescoApiService); + bpmCli = apiService.getInstance().bpmAuth; logService = TestBed.get(LogService); }); @@ -374,6 +376,81 @@ describe('FormService', () => { }); }); + it('should return the unsupported content when the file is an image', (done) => { + let contentId: number = 999; + responseBody = { + id: contentId, + name: 'fake-name.jpg', + created: '2017-01-23T12:12:53.219+0000', + createdBy: {id: 2, firstName: 'fake-admin', lastName: 'fake-last', 'email': 'fake-admin'}, + relatedContent: false, + contentAvailable: true, + link: false, + mimeType: 'image/jpeg', + simpleType: 'image', + previewStatus: 'unsupported', + thumbnailStatus: 'unsupported' + }; + + service.getFileContent(contentId).subscribe(result => { + expect(result.id).toEqual(contentId); + expect(result.name).toEqual('fake-name.jpg'); + expect(result.simpleType).toEqual('image'); + expect(result.thumbnailStatus).toEqual('unsupported'); + done(); + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + 'status': 200, + contentType: 'application/json', + responseText: JSON.stringify(responseBody) + }); + }); + + it('should return the supported content when the file is a pdf', (done) => { + let contentId: number = 888; + responseBody = { + id: contentId, + name: 'fake-name.pdf', + created: '2017-01-23T12:12:53.219+0000', + createdBy: {id: 2, firstName: 'fake-admin', lastName: 'fake-last', 'email': 'fake-admin'}, + relatedContent: false, + contentAvailable: true, + link: false, + mimeType: 'application/pdf', + simpleType: 'pdf', + previewStatus: 'created', + thumbnailStatus: 'created' + }; + + service.getFileContent(contentId).subscribe(result => { + expect(result.id).toEqual(contentId); + expect(result.name).toEqual('fake-name.pdf'); + expect(result.simpleType).toEqual('pdf'); + expect(result.thumbnailStatus).toEqual('created'); + done(); + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + 'status': 200, + contentType: 'application/json', + responseText: JSON.stringify(responseBody) + }); + }); + + it('should return the raw content URL', () => { + let contentId: number = 999; + let contentRawUrl = service.getFileRawContentUrl(contentId); + expect(contentRawUrl).toEqual(`${bpmCli.basePath}/api/enterprise/content/${contentId}/raw`); + }); + + it('should return the thumbnail URL', () => { + let contentId: number = 999; + + let contentRawUrl = service.getContentThumbnailUrl(contentId); + expect(contentRawUrl).toEqual(`${bpmCli.basePath}/app/rest/content/${contentId}/rendition/thumbnail`); + }); + it('should create a Form form a Node', (done) => { let nameForm = 'testNode'; diff --git a/ng2-components/ng2-activiti-form/src/services/form.service.ts b/ng2-components/ng2-activiti-form/src/services/form.service.ts index 0ffc0156d3..a142f492ad 100644 --- a/ng2-components/ng2-activiti-form/src/services/form.service.ts +++ b/ng2-components/ng2-activiti-form/src/services/form.service.ts @@ -252,6 +252,26 @@ export class FormService { return Observable.fromPromise(this.apiService.getInstance().activiti.contentApi.createTemporaryRawRelatedContent(file)); } + getFileContent(contentId: number): Observable { + let alfrescoApi = this.apiService.getInstance(); + return Observable.fromPromise(alfrescoApi.activiti.contentApi.getContent(contentId)); + } + + getFileRawContent(contentId: number): Observable { + let alfrescoApi = this.apiService.getInstance(); + return Observable.fromPromise(alfrescoApi.activiti.contentApi.getRawContent(contentId)); + } + + getFileRawContentUrl(contentId: number): string { + let alfrescoApi = this.apiService.getInstance(); + return alfrescoApi.activiti.contentApi.getRawContentUrl(contentId); + } + + getContentThumbnailUrl(contentId: number): string { + let alfrescoApi = this.apiService.getInstance(); + return alfrescoApi.activiti.contentApi.getContentThumbnailUrl(contentId); + } + getRestFieldValues(taskId: string, field: string): Observable { let alfrescoApi = this.apiService.getInstance(); return Observable.fromPromise(alfrescoApi.activiti.taskApi.getRestFieldValues(taskId, field)); From 8cd2dfa9c11ce28f07ea9bd145dcabd1aee3af55 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Tue, 7 Feb 2017 11:04:20 +0000 Subject: [PATCH 08/40] remove double build npm-build-bundle-all.sh (#1601) --- scripts/npm-build-bundle-all.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/scripts/npm-build-bundle-all.sh b/scripts/npm-build-bundle-all.sh index bb67f0931a..30a99cf06d 100755 --- a/scripts/npm-build-bundle-all.sh +++ b/scripts/npm-build-bundle-all.sh @@ -6,21 +6,18 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" echo "====== linking component: ng2-alfresco-core =====" cd "$DIR/../ng2-components/ng2-alfresco-core" npm link -npm run build #LINK FORM echo "====== linking component: ng2-activiti-form =====" cd "$DIR/../ng2-components/ng2-activiti-form" npm link ng2-alfresco-core npm link -npm run build #LINK DATATABLE echo "====== linking component: ng2-alfresco-datatable =====" cd "$DIR/../ng2-components/ng2-alfresco-datatable" npm link ng2-alfresco-core npm link -npm run build #LINK DOCUMENTLIST echo "====== linking component: ng2-alfresco-documentlist =====" @@ -28,7 +25,6 @@ cd "$DIR/../ng2-components/ng2-alfresco-documentlist" npm link ng2-alfresco-core npm link ng2-alfresco-datatable npm link -npm run build #LINK WEBSCRIPT echo "====== linking component: ng2-alfresco-webscript =====" @@ -36,7 +32,6 @@ cd "$DIR/../ng2-components/ng2-alfresco-webscript" npm link ng2-alfresco-core npm link ng2-alfresco-datatable npm link -npm run build #LINK TASKLIST echo "====== linking component: ng2-activiti-tasklist =====" @@ -45,7 +40,6 @@ npm link ng2-alfresco-core npm link ng2-alfresco-datatable npm link ng2-activiti-form npm link -npm run build #LINK PROCESSLIST echo "====== linking component: ng2-activiti-processlist =====" @@ -55,14 +49,12 @@ npm link ng2-alfresco-datatable npm link ng2-activiti-form npm link ng2-activiti-tasklist npm link -npm run build #LINK DIAGRAMS echo "====== linking component: ng2-activiti-diagrams =====" cd "$DIR/../ng2-components/ng2-activiti-diagrams" npm link ng2-alfresco-core npm link -npm run build #LINK ANALYTICS echo "====== linking component: ng2-activiti-analytics =====" @@ -70,7 +62,6 @@ cd "$DIR/../ng2-components/ng2-activiti-analytics" npm link ng2-alfresco-core npm link ng2-activiti-diagrams npm link -npm run build #LINK SEARCH echo "====== linking component: ng2-alfresco-search =====" @@ -79,7 +70,6 @@ npm link ng2-alfresco-core npm link ng2-alfresco-datatable npm link ng2-alfresco-documentlist npm link -npm run build #LINK ALL THE OTHERS COMPONENTS for PACKAGE in \ @@ -94,7 +84,6 @@ do cd "$DESTDIR" npm link ng2-alfresco-core npm link - npm run build done From 8bb00fdd008c4e805e5d6e7e0aaa51232d6d469b Mon Sep 17 00:00:00 2001 From: Vito Date: Tue, 7 Feb 2017 07:21:03 -0800 Subject: [PATCH 09/40] #1184 - Added option to reports : Save, Delete and Export to CSV (#1600) * #1184 - adding save export and delete to report * #1184 - added save button for report * #1184 - improved export file * 1184 - fix condition for save and export button * #1184 - added custom validator for dropdown to avoid wrong selection * #1184 -start fixing form model * #1184 - added dynamic build for formBuilder * #1184 - rebased to development * #1184 - little test refactoring * #1184 - added test and some fix * #1184 - added new events * #1184 - removed old changes to api service --- .../activiti/activiti-demo.component.html | 4 +- .../activiti/activiti-demo.component.ts | 25 ++- .../ng2-activiti-analytics/README.md | 2 + .../analytics-report-parameters.component.css | 26 +++ ...analytics-report-parameters.component.html | 163 ++++++++------ ...lytics-report-parameters.component.spec.ts | 162 +++++++++++++- .../analytics-report-parameters.component.ts | 206 ++++++++++++++---- .../src/components/analytics.component.html | 2 + .../src/components/analytics.component.ts | 14 ++ .../widgets/dropdown/dropdown.widget.ts | 17 +- .../ng2-activiti-analytics/src/i18n/en.json | 4 + .../src/models/report.model.ts | 5 + .../src/services/analytics.service.ts | 22 ++ 13 files changed, 535 insertions(+), 117 deletions(-) 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 4f00688632..8fdcae6d86 100644 --- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.html +++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.html @@ -119,7 +119,9 @@ + (editReport)="onEditReport($event)" + (reportSaved)="onReportSaved()" + (reportDeleted)="onReportDeleted()">
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 0fee1a1127..7c030da7f1 100644 --- a/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts +++ b/demo-shell-ng2/app/components/activiti/activiti-demo.component.ts @@ -104,8 +104,8 @@ export class ActivitiDemoComponent implements AfterViewInit { this.dataTasks = new ObjectDataTableAdapter( [], [ - {type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}, - {type: 'text', key: 'created', title: 'Created', cssClass: 'hidden', sortable: true} + { type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true }, + { type: 'text', key: 'created', title: 'Created', cssClass: 'hidden', sortable: true } ] ); this.dataTasks.setSorting(new DataSorting('created', 'desc')); @@ -113,8 +113,8 @@ export class ActivitiDemoComponent implements AfterViewInit { this.dataProcesses = new ObjectDataTableAdapter( [], [ - {type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}, - {type: 'text', key: 'started', title: 'Started', cssClass: 'hidden', sortable: true} + { type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true }, + { type: 'text', key: 'started', title: 'Started', cssClass: 'hidden', sortable: true } ] ); this.dataProcesses.setSorting(new DataSorting('started', 'desc')); @@ -154,7 +154,7 @@ export class ActivitiDemoComponent implements AfterViewInit { } onTaskFilterClick(event: FilterRepresentationModel) { - if(event){ + if (event) { this.taskFilter = event; } } @@ -202,6 +202,21 @@ export class ActivitiDemoComponent implements AfterViewInit { this.analyticsreportlist.reload(); } + onReportSaved() { + this.analyticsreportlist.reload(); + } + + onReportDeleted() { + this.analyticsreportlist.reload(); + this.selectFirstElementInReportList(); + } + + selectFirstElementInReportList(){ + if (! this.analyticsreportlist.isReportsEmpty()) { + this.analyticsreportlist.selectReport(this.analyticsreportlist.reports[0]); + } + } + navigateStartProcess() { this.resetProcessFilters(); this.reloadProcessFilters(); diff --git a/ng2-components/ng2-activiti-analytics/README.md b/ng2-components/ng2-activiti-analytics/README.md index bc9bae8974..9c7eb99a83 100644 --- a/ng2-components/ng2-activiti-analytics/README.md +++ b/ng2-components/ng2-activiti-analytics/README.md @@ -251,6 +251,8 @@ platformBrowserDynamic().bootstrapModule(AppModule); | --- | --- | |`onSuccess` | The event is emitted when the report parameters are loaded | |`onError` | The event is emitted when an error occur during the loading | +|`reportSaved` | The event is emitted when a report is saved | +|`reportDeleted` | The event is emitted when a report is deleted | #### Options diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.css b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.css index 947c5d475a..f703726852 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.css +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.css @@ -63,3 +63,29 @@ .report-container-setting { padding-left: 10px; } + +.option_button_details{ + padding-top: 20px; +} + +.mdl-dialog__title.choose_name{ + padding: 0px; +} + +.mdl-dialog.options-name-dialog { + width: 30%; +} + +.export-message{ + background-color: lightgray; +} + +.save-export-input{ + width:100%; +} + +.delete-parameter { + position: absolute; + margin-left: 60%; + padding-top: 5px; +} diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.html b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.html index 91b38999f5..f2bfcdcbe2 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.html @@ -2,8 +2,8 @@
-
- + -
-
-
+
+ +
+ mode_edit +

{{reportParameters.name}}

+
+
+ -
- mode_edit -

{{reportParameters.name}}

-
-
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
- {{'ANALYTICS.MESSAGES.UNKNOWN-WIDGET-TYPE' | translate}}: {{field.type}} +
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ {{'ANALYTICS.MESSAGES.UNKNOWN-WIDGET-TYPE' | translate}}: {{field.type}} +
-
-
-

ReportForm valid : {{ reportForm.valid }}

-

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

-

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

-
+
+
+ + +
+
+ +
{{action}} report
+
+
{{'DIALOG.SAVE_MESSAGE' | translate}}
+
+ + +
+
+
+ + +
+
+
+

ReportForm valid : {{ reportForm.valid }}

+

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

+

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

+
diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.spec.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.spec.ts index 4354d1bb25..6d46a4ac98 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.spec.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.spec.ts @@ -55,7 +55,9 @@ describe('AnalyticsReportParametersComponent', () => { let translateService = TestBed.get(AlfrescoTranslationService); spyOn(translateService, 'addTranslationFolder').and.stub(); - spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); }); + spyOn(translateService, 'get').and.callFake((key) => { + return Observable.of(key); + }); componentHandler = jasmine.createSpyObj('componentHandler', [ 'upgradeAllRegistered' @@ -80,17 +82,22 @@ describe('AnalyticsReportParametersComponent', () => { 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 initialize the Report form with a Form Group ', (done) => { + let fakeReportParam = new ReportParametersModel(analyticParamsMock.reportDefParamTask); + component.onSuccessReportParams.subscribe(() => { + fixture.detectChanges(); + expect(component.reportForm.get('taskGroup')).toBeDefined(); + expect(component.reportForm.get('taskGroup').get('taskName')).toBeDefined(); + done(); + }); + component.onSuccessReportParams.emit(fakeReportParam); }); it('Should render a dropdown with all the status when the definition parameter type is \'status\' ', (done) => { component.onSuccessReportParams.subscribe(() => { fixture.detectChanges(); let dropDown: any = element.querySelector('#select-status'); - expect(element.querySelector('h4').innerHTML).toEqual('Fake Task overview status'); + expect(element.querySelector('h4').textContent.trim()).toEqual('Fake Task overview status'); expect(dropDown).toBeDefined(); expect(dropDown.length).toEqual(4); expect(dropDown[0].innerHTML).toEqual('Choose One'); @@ -400,5 +407,148 @@ describe('AnalyticsReportParametersComponent', () => { let numberConvert = component.convertNumber('2'); expect(numberConvert).toEqual(2); }); + + describe('When the form is rendered correctly', () => { + let values: any = { + dateRange: { + startDate: '2016-09-01', endDate: '2016-10-05' + }, + statusGroup: { + status: 'All' + }, + processDefGroup: { + processDefinitionId: 'FakeProcess:1:22' + }, + taskGroup: { + taskName: 'FakeTaskName' + }, + durationGroup: { + duration: 22 + }, + dateIntervalGroup: { + dateRangeInterval: 120 + }, + processInstanceGroup: { + slowProcessInstanceInteger: 2 + }, + typeFilteringGroup: { + typeFiltering: true + } + }; + + beforeEach(async(() => { + let reportId = 1; + let change = new SimpleChange(null, reportId); + component.ngOnChanges({ 'reportId': change }); + fixture.detectChanges(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticParamsMock.reportDefParamStatus + }); + fixture.whenStable().then(() => { + component.toggleParameters(); + component.reportId = '1'; + spyOn(component, 'isFormValid').and.returnValue(true); + fixture.detectChanges(); + }); + })); + + it('Should be able to change the report title', async(() => { + let title: HTMLElement = element.querySelector('h4'); + title.click(); + fixture.detectChanges(); + let reportName: HTMLInputElement = element.querySelector('#reportName'); + expect(reportName).not.toBeNull(); + reportName.focus(); + component.reportParameters.name = 'FAKE_TEST_NAME'; + reportName.value = 'FAKE_TEST_NAME'; + reportName.blur(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: analyticParamsMock.reportDefParamStatus + }); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + let titleChanged: HTMLElement = element.querySelector('h4'); + expect(titleChanged.textContent.trim()).toEqual('FAKE_TEST_NAME'); + }); + })); + + it('Should show a dialog to allowing report save', async(() => { + component.saveReportSuccess.subscribe(() => { + let reportDialogTitle: HTMLElement = element.querySelector('#report-dialog'); + expect(reportDialogTitle.getAttribute('open')).toBeNull(); + }); + + component.submit(values); + fixture.detectChanges(); + let saveButton: HTMLButtonElement = element.querySelector('#save-button'); + expect(saveButton).toBeDefined(); + expect(saveButton).not.toBeNull(); + saveButton.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + let reportDialogTitle: HTMLElement = element.querySelector('#report-dialog-title'); + let saveTitleSubMessage: HTMLElement = element.querySelector('#save-title-submessage'); + let inputSaveName: HTMLInputElement = element.querySelector('#repName'); + let performActionButton: HTMLButtonElement = element.querySelector('#action-dialog-button'); + let todayDate = component.getTodayDate(); + expect(reportDialogTitle).not.toBeNull(); + expect(saveTitleSubMessage).not.toBeNull(); + expect(inputSaveName.value.trim()).toEqual(analyticParamsMock.reportDefParamStatus.name + ' ( ' + todayDate + ' )'); + expect(performActionButton).not.toBeNull(); + performActionButton.click(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json' + }); + }); + })); + + it('Should show a dialog to allowing report export', async(() => { + component.submit(values); + spyOn(component, 'generateDownloadElement').and.stub(); + fixture.detectChanges(); + let exportButton: HTMLButtonElement = element.querySelector('#export-button'); + expect(exportButton).toBeDefined(); + expect(exportButton).not.toBeNull(); + exportButton.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + let reportDialogTitle: HTMLElement = element.querySelector('#report-dialog-title'); + let inputSaveName: HTMLInputElement = element.querySelector('#repName'); + let performActionButton: HTMLButtonElement = element.querySelector('#action-dialog-button'); + let todayDate = component.getTodayDate(); + expect(reportDialogTitle).not.toBeNull(); + expect(inputSaveName.value.trim()).toEqual(analyticParamsMock.reportDefParamStatus.name + ' ( ' + todayDate + ' )'); + expect(performActionButton).not.toBeNull(); + performActionButton.click(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json' + }); + }); + })); + + it('Should raise an event for report deleted', async(() => { + let deleteButton: HTMLButtonElement = element.querySelector('#delete-button'); + expect(deleteButton).toBeDefined(); + expect(deleteButton).not.toBeNull(); + + component.deleteReportSuccess.subscribe((reportId) => { + expect(reportId).not.toBeNull(); + }); + deleteButton.click(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json' + }); + })); + }); }); }); diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.ts index b1e3297328..b7c5e45386 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.ts @@ -24,7 +24,8 @@ import { Output, SimpleChanges, OnDestroy, - AfterViewChecked + AfterViewChecked, + ViewChild } from '@angular/core'; import { FormGroup, FormBuilder, FormControl } from '@angular/forms'; import * as moment from 'moment'; @@ -38,6 +39,7 @@ import { } from '../models/report.model'; declare var componentHandler; +declare let dialogPolyfill: any; @Component({ moduleId: module.id, @@ -47,7 +49,7 @@ declare var componentHandler; }) export class AnalyticsReportParametersComponent implements OnInit, OnChanges, OnDestroy, AfterViewChecked { - public static FORMAT_DATE_ACTIVITI: string = 'YYYY-MM-DD'; + public static FORMAT_DATE_ACTIVITI: string = 'YYYY-MM-DD'; @Input() appId: string; @@ -70,6 +72,15 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On @Output() onFormValueChanged = new EventEmitter(); + @Output() + saveReportSuccess = new EventEmitter(); + + @Output() + deleteReportSuccess = new EventEmitter(); + + @ViewChild('reportNameDialog') + reportNameDialog: any; + onDropdownChanged = new EventEmitter(); onSuccessReportParams = new EventEmitter(); @@ -84,6 +95,9 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On private reportParamsSub; private paramOpts; private isEditable: boolean = false; + private action: string; + private reportParamQuery: ReportQuery; + private reportName: string; private hideParameters: boolean = true; constructor(private translateService: AlfrescoTranslationService, @@ -96,8 +110,6 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On } ngOnInit() { - this.initForm(); - this.dropDownSub = this.onDropdownChanged.subscribe((field) => { let paramDependOn: ReportParameterDetailsModel = this.reportParameters.definition.parameters.find(p => p.dependsOn === field.id); if (paramDependOn) { @@ -108,10 +120,9 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On this.paramOpts = this.onSuccessReportParams.subscribe((report: ReportParametersModel) => { if (report.hasParameters()) { this.retrieveParameterOptions(report.definition.parameters, this.appId); + this.generateFormGroupFromParameter(report.definition.parameters); } }); - - this.reportForm.valueChanges.subscribe(data => this.onValueChanged(data)); } ngOnChanges(changes: SimpleChanges) { @@ -127,31 +138,54 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On } } - initForm() { - this.reportForm = this.formBuilder.group({ - dateRange: new FormGroup({}), - statusGroup: new FormGroup({ - status: new FormControl() - }), - processInstanceGroup: new FormGroup({ - slowProcessInstanceInteger: new FormControl() - }), - taskGroup: new FormGroup({ - taskName: new FormControl() - }), - typeFilteringGroup: new FormGroup({ - typeFiltering: new FormControl() - }), - dateIntervalGroup: new FormGroup({ - dateRangeInterval: new FormControl() - }), - durationGroup: new FormGroup({ - duration: new FormControl() - }), - processDefGroup: new FormGroup({ - processDefinitionId: new FormControl() - }) + private generateFormGroupFromParameter(parameters: ReportParameterDetailsModel[]) { + let formBuilderGroup: any = {}; + parameters.forEach((param: ReportParameterDetailsModel) => { + switch (param.type) { + case 'dateRange' : + formBuilderGroup.dateRange = new FormGroup({}); + break; + case 'processDefinition': + formBuilderGroup.processDefGroup = new FormGroup({ + processDefinitionId: new FormControl() + }); + break; + case 'duration': + formBuilderGroup.durationGroup = new FormGroup({ + duration: new FormControl() + }); + break; + case 'dateInterval': + formBuilderGroup.dateIntervalGroup = new FormGroup({ + dateRangeInterval: new FormControl() + }); + break; + case 'boolean': + formBuilderGroup.typeFilteringGroup = new FormGroup({ + typeFiltering: new FormControl() + }); + break; + case 'task': + formBuilderGroup.taskGroup = new FormGroup({ + taskName: new FormControl() + }); + break; + case 'integer': + formBuilderGroup.processInstanceGroup = new FormGroup({ + slowProcessInstanceInteger: new FormControl() + }); + break; + case 'status': + formBuilderGroup.statusGroup = new FormGroup({ + status: new FormControl() + }); + break; + default: + return; + } }); + this.reportForm = this.formBuilder.group(formBuilderGroup); + this.reportForm.valueChanges.subscribe(data => this.onValueChanged(data)); } public getReportParams(reportId: string) { @@ -193,8 +227,8 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On } public submit(values: any) { - let reportParamQuery = this.convertFormValuesToReportParamQuery(values); - this.onSuccess.emit(reportParamQuery); + this.reportParamQuery = this.convertFormValuesToReportParamQuery(values); + this.onSuccess.emit(this.reportParamQuery); } onValueChanged(values: any) { @@ -209,21 +243,41 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On .format(AnalyticsReportParametersComponent.FORMAT_DATE_ACTIVITI) + 'T00:00:00.000Z'; } + public getTodayDate() { + return moment().format(AnalyticsReportParametersComponent.FORMAT_DATE_ACTIVITI); + } + public convertNumber(value: string): number { return value != null ? parseInt(value, 10) : 0; } convertFormValuesToReportParamQuery(values: any): ReportQuery { let reportParamQuery: ReportQuery = new ReportQuery(); - reportParamQuery.dateRange.startDate = this.convertMomentDate(values.dateRange.startDate); - reportParamQuery.dateRange.endDate = this.convertMomentDate(values.dateRange.endDate); - reportParamQuery.status = values.statusGroup.status; - reportParamQuery.processDefinitionId = values.processDefGroup.processDefinitionId; - reportParamQuery.taskName = values.taskGroup.taskName; - reportParamQuery.duration = values.durationGroup.duration; - reportParamQuery.dateRangeInterval = values.dateIntervalGroup.dateRangeInterval; - reportParamQuery.slowProcessInstanceInteger = this.convertNumber(values.processInstanceGroup.slowProcessInstanceInteger); - reportParamQuery.typeFiltering = values.typeFilteringGroup.typeFiltering; + if (values.dateRange) { + reportParamQuery.dateRange.startDate = this.convertMomentDate(values.dateRange.startDate); + reportParamQuery.dateRange.endDate = this.convertMomentDate(values.dateRange.endDate); + } + if (values.statusGroup) { + reportParamQuery.status = values.statusGroup.status; + } + if (values.processDefGroup) { + reportParamQuery.processDefinitionId = values.processDefGroup.processDefinitionId; + } + if (values.taskGroup) { + reportParamQuery.taskName = values.taskGroup.taskName; + } + if (values.durationGroup) { + reportParamQuery.duration = values.durationGroup.duration; + } + if (values.dateIntervalGroup) { + reportParamQuery.dateRangeInterval = values.dateIntervalGroup.dateRangeInterval; + } + if (values.processInstanceGroup) { + reportParamQuery.slowProcessInstanceInteger = this.convertNumber(values.processInstanceGroup.slowProcessInstanceInteger); + } + if (values.typeFilteringGroup) { + reportParamQuery.typeFiltering = values.typeFilteringGroup.typeFiltering; + } return reportParamQuery; } @@ -236,7 +290,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On } public editEnable() { - this.isEditable = true; + this.isEditable = true; } public editDisable() { @@ -256,6 +310,74 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges, On ); } + public showDialog(event: string) { + if (!this.reportNameDialog.nativeElement.showModal) { + dialogPolyfill.registerDialog(this.reportNameDialog.nativeElement); + } + this.reportNameDialog.nativeElement.showModal(); + this.action = event; + this.reportName = this.reportParameters.name + ' ( ' + this.getTodayDate() + ' )'; + } + + closeDialog() { + if (this.reportNameDialog) { + this.reportNameDialog.nativeElement.close(); + } + } + + performAction(action: string, reportParamQuery: ReportQuery) { + reportParamQuery.reportName = this.reportName; + this.closeDialog(); + if (action === 'Save') { + this.doSave(reportParamQuery); + } else if (action === 'Export') { + this.doExport(reportParamQuery); + } + this.resetActions(); + } + + resetActions() { + this.action = ''; + this.reportName = ''; + } + + isFormValid() { + return this.reportForm && this.reportForm.valid && this.reportForm.dirty; + } + + isSaveAction() { + return this.action === 'Save'; + } + + doExport(paramQuery: ReportQuery) { + this.analyticsService.exportReportToCsv(this.reportId, paramQuery).subscribe( + (data: any) => { + let blob: Blob = new Blob([data], { type: 'text/csv' }); + let downloadUrl = window.URL.createObjectURL(blob); + this.generateDownloadElement(downloadUrl, paramQuery); + }); + } + + private generateDownloadElement(downloadUrl: string, paramQuery: ReportQuery) { + let downloadElement = window.document.createElement('a'); + downloadElement.setAttribute('id', 'export-download'); + downloadElement.setAttribute('href', downloadUrl); + downloadElement.setAttribute('download', paramQuery.reportName); + downloadElement.click(); + } + + doSave(paramQuery: ReportQuery) { + this.analyticsService.saveReport(this.reportId, paramQuery).subscribe(() => { + this.saveReportSuccess.emit(); + }); + } + + deleteReport(reportId: string) { + this.analyticsService.deleteReport(reportId).subscribe(() => { + this.deleteReportSuccess.emit(reportId); + }, error => this.logService.error(error)); + } + ngAfterViewChecked() { // workaround for MDL issues with dynamic components if (componentHandler) { 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 0cfae9ccdc..3f16077c5c 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.html @@ -2,6 +2,8 @@ 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 21572dd43e..959d82329a 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics.component.ts @@ -41,6 +41,12 @@ export class AnalyticsComponent implements OnChanges { @Output() editReport = new EventEmitter(); + @Output() + reportSaved = new EventEmitter(); + + @Output() + reportDeleted = new EventEmitter(); + @ViewChild('analyticsgenerator') analyticsgenerator: AnalyticsGeneratorComponent; @@ -71,4 +77,12 @@ export class AnalyticsComponent implements OnChanges { this.editReport.emit(name); } + public onSaveReportSuccess() { + this.reportSaved.emit(); + } + + public onDeleteReportSuccess() { + this.reportDeleted.emit(); + } + } 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 index 4e9450b361..9f6ca1434f 100644 --- 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 @@ -16,7 +16,7 @@ */ import { Component, Input, Output, EventEmitter } from '@angular/core'; -import { FormGroup, Validators } from '@angular/forms'; +import { FormGroup, Validators, FormControl } from '@angular/forms'; import { WidgetComponent } from './../widget.component'; @Component({ @@ -54,7 +54,20 @@ export class DropdownWidget extends WidgetComponent { ngOnInit() { if (this.required) { - this.formGroup.get(this.controllerName).setValidators(Validators.required); + this.formGroup.get(this.controllerName).setValidators(Validators.compose(this.buildValidatorList())); } } + + validateDropDown(controller: FormControl) { + return controller.value !== 'null' ? null : { controllerName: false }; + } + + buildValidatorList() { + let validatorList = []; + validatorList.push(Validators.required); + if (this.showDefaultOption) { + validatorList.push(this.validateDropDown); + } + return validatorList; + } } diff --git a/ng2-components/ng2-activiti-analytics/src/i18n/en.json b/ng2-components/ng2-activiti-analytics/src/i18n/en.json index 9e5cd9ca95..19d67e515d 100644 --- a/ng2-components/ng2-activiti-analytics/src/i18n/en.json +++ b/ng2-components/ng2-activiti-analytics/src/i18n/en.json @@ -43,5 +43,9 @@ }, "PROCESS-STATUS": "Process status", "TASK-STATUS": "Task status" + }, + "DIALOG":{ + "SAVE_MESSAGE" : "The current parameter settings will be stored, and a new report will be shown in the reports list. When that particular report is clicked, the report will be generated using these saved parameter values.", + "EXPORT_MESSAGE":"" } } diff --git a/ng2-components/ng2-activiti-analytics/src/models/report.model.ts b/ng2-components/ng2-activiti-analytics/src/models/report.model.ts index df82947ac2..5014a3c0e3 100644 --- a/ng2-components/ng2-activiti-analytics/src/models/report.model.ts +++ b/ng2-components/ng2-activiti-analytics/src/models/report.model.ts @@ -106,6 +106,7 @@ export class ParameterValueModel { } export class ReportQuery { + reportName: string; processDefinitionId: string; status: string; taskName: string; @@ -116,6 +117,7 @@ export class ReportQuery { duration: number; constructor(obj?: any) { + this.reportName = obj && obj.reportName || null; this.processDefinitionId = obj && obj.processDefinitionId || null; this.status = obj && obj.status || null; this.taskName = obj && obj.taskName || null; @@ -125,15 +127,18 @@ export class ReportQuery { this.duration = obj && obj.duration || 0; this.dateRange = new ReportDateRange(obj); } + } export class ReportDateRange { startDate: string; endDate: string; + rangeId: string; constructor(obj?: any) { this.startDate = obj && obj.startDate || null; this.endDate = obj && obj.endDate || null; + this.rangeId = obj && obj.rangeId || 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 index c1b3242e4d..50ac073941 100644 --- a/ng2-components/ng2-activiti-analytics/src/services/analytics.service.ts +++ b/ng2-components/ng2-activiti-analytics/src/services/analytics.service.ts @@ -184,6 +184,28 @@ export class AnalyticsService { }).catch(err => this.handleError(err)); } + exportReportToCsv(reportId: string, paramsQuery: any): Observable { + return Observable.fromPromise(this.apiService.getInstance().activiti.reportApi.exportToCsv(reportId, paramsQuery)) + .map((res: any) => { + this.logService.info('export'); + return res; + }).catch(err => this.handleError(err)); + } + + saveReport(reportId: string, paramsQuery: any): Observable { + return Observable.fromPromise(this.apiService.getInstance().activiti.reportApi.saveReport(reportId, paramsQuery)) + .map(() => { + this.logService.info('save'); + }).catch(err => this.handleError(err)); + } + + deleteReport(reportId: string): Observable { + return Observable.fromPromise(this.apiService.getInstance().activiti.reportApi.deleteReport(reportId)) + .map(() => { + this.logService.info('delete'); + }).catch(err => this.handleError(err)); + } + private handleError(error: Response) { this.logService.error(error); return Observable.throw(error.json().error || 'Server error'); From b8c500682c3e768892a0bd8cde13a15293464fff Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Tue, 7 Feb 2017 15:34:08 +0000 Subject: [PATCH 10/40] Demo shell build problem with Node 5 #1602 (#1603) --- demo-shell-ng2/config/webpack.common.js | 6 +++--- demo-shell-ng2/config/webpack.test.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/demo-shell-ng2/config/webpack.common.js b/demo-shell-ng2/config/webpack.common.js index 21c6fc688b..fb5bc51860 100644 --- a/demo-shell-ng2/config/webpack.common.js +++ b/demo-shell-ng2/config/webpack.common.js @@ -9,13 +9,13 @@ var CopyWebpackPlugin = require('copy-webpack-plugin'); const rootPath = helpers.root('node_modules'); -let pattern = '+(alfresco-js-api|ng2-alfresco|ng2-activiti)*'; -let options = { +var pattern = '+(alfresco-js-api|ng2-alfresco|ng2-activiti)*'; +var options = { cwd: rootPath, realpath: true }; -let alfrescoLibs = glob.sync(pattern, options); +var alfrescoLibs = glob.sync(pattern, options); // console.dir(alfrescoLibs); module.exports = { diff --git a/demo-shell-ng2/config/webpack.test.js b/demo-shell-ng2/config/webpack.test.js index f2fe2870e0..c9bcd38d21 100644 --- a/demo-shell-ng2/config/webpack.test.js +++ b/demo-shell-ng2/config/webpack.test.js @@ -4,13 +4,13 @@ var glob = require('glob'); const rootPath = helpers.root('node_modules'); -let pattern = '+(alfresco-js-api|ng2-alfresco|ng2-activiti)*'; -let options = { +var pattern = '+(alfresco-js-api|ng2-alfresco|ng2-activiti)*'; +var options = { cwd: rootPath, realpath: true }; -let alfrescoLibs = glob.sync(pattern, options); +var alfrescoLibs = glob.sync(pattern, options); module.exports = { devtool: 'inline-source-map', From 8edd2a2d237e1b6d62de1ba312b77914d44d1073 Mon Sep 17 00:00:00 2001 From: Ole Hejlskov Date: Wed, 8 Feb 2017 11:58:12 +0100 Subject: [PATCH 11/40] Fix spelling in ISSUE_TEMPLATE and PULL_REQUEST_TEMPLATE (#1607) --- .github/ISSUE_TEMPLATE.md | 6 +++--- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 8c972237bb..97fbc69f69 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -12,11 +12,11 @@ Please ask before on our gitter channel https://gitter.im/Alfresco/alfresco-ng2- - [ ] Support request - [ ] Documentation ``` -**Current behavior:** - +**Current behaviour:** + **Expected behavior:** - + **Steps to reproduce the issue:** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 76d5ed14b4..f2d0a967c7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -20,11 +20,11 @@ [ ] Other... Please describe: ``` -**What is the current behavior?** (You can also link to an open issue here) +**What is the current behaviour?** (You can also link to an open issue here) -**What is the new behavior?** +**What is the new behaviour?** From 07bad7754735f7ca29690010f31cbb15081006f2 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 10 Feb 2017 11:22:25 +0000 Subject: [PATCH 12/40] i18n fixes (#1614) * i18n fixes - fix issue with default (fallback) language set to browser language - fix issue with fallback language loading when browser language set to non-English locale * code and UI fixes - move document list i18n strings into own scope - replace MDL menu with @angular/material menu (fixes issue with menu items translation, not supported by MDL) - minor improvements * fix unit tests * improve i18n docs and code - provide basic documentation for Translation service - remove custom Login component localisation in favour of documentation sample - simplified i18n setup for demo shell (single path for dev/prod env) * remove unnecessary comments --- demo-shell-ng2/app/app.component.html | 8 +- demo-shell-ng2/app/app.component.ts | 10 +-- demo-shell-ng2/config/webpack.prod.js | 4 +- .../alfresco-login/i18n/en.json | 29 ------- .../alfresco-login/i18n/it.json | 28 ------ .../i18n/en.json | 0 .../i18n/it.json | 0 .../activiti-checklist.component.spec.ts | 2 +- .../activiti-people-search.component.spec.ts | 2 +- .../activiti-people.component.spec.ts | 2 +- .../activiti-start-task.component.spec.ts | 2 +- .../activiti-task-details.component.spec.ts | 2 +- .../activiti-task-header.component.spec.ts | 2 +- ng2-components/ng2-alfresco-core/README.md | 85 ++++++++++++++----- .../alfresco-translate-loader.service.ts | 5 +- .../services/alfresco-translation.service.ts | 27 ++++-- .../document-menu-action.component.css | 66 -------------- .../document-menu-action.component.html | 29 +++---- .../src/i18n/en.json | 26 ++---- .../src/i18n/ru.json | 26 ++---- 20 files changed, 127 insertions(+), 228 deletions(-) delete mode 100644 demo-shell-ng2/custom-translation/alfresco-login/i18n/en.json delete mode 100644 demo-shell-ng2/custom-translation/alfresco-login/i18n/it.json rename demo-shell-ng2/{custom-translation => resources}/i18n/en.json (100%) rename demo-shell-ng2/{custom-translation => resources}/i18n/it.json (100%) diff --git a/demo-shell-ng2/app/app.component.html b/demo-shell-ng2/app/app.component.html index aeee137ec9..467a68c3d0 100644 --- a/demo-shell-ng2/app/app.component.html +++ b/demo-shell-ng2/app/app.component.html @@ -39,14 +39,14 @@ - - - - + + + + Components
- BPM host URL configuration + Process Services host URL configuration