Merge pull request #1573 from Alfresco/development

1.1.0
This commit is contained in:
Denys Vuika
2017-01-30 16:50:08 +00:00
committed by GitHub
384 changed files with 6997 additions and 4811 deletions
+1
View File
@@ -10,6 +10,7 @@ Please ask before on our gitter channel https://gitter.im/Alfresco/alfresco-ng2-
- [ ] New feature request
- [ ] Bug
- [ ] Support request
- [ ] Documentation
```
**Current behavior:**
<!-- Describe the current behavior. -->
+14 -7
View File
@@ -32,24 +32,31 @@ env:
before_script:
- if ([ "$MODULE" != "ng2-alfresco-core" ]); then
(cd ng2-components/ng2-alfresco-core; if [ ! -d "dist" ]; then npm install; fi; npm link);
(cd ng2-components/ng2-alfresco-core; if [ ! -d "bundles" ]; then npm link; fi);
fi
- if ([ "$MODULE" == "ng2-alfresco-documentlist" ] || [ "$MODULE" == "ng2-alfresco-webscript" ] || [ "$MODULE" == "ng2-activiti-processlist" ] || [ "$MODULE" == "ng2-activiti-tasklist" ]); then
(cd ng2-components/ng2-alfresco-datatable; npm link ng2-alfresco-core; if [ ! -d "dist" ]; then npm install; fi; npm link);
(cd ng2-components/ng2-alfresco-datatable; npm link ng2-alfresco-core; if [ ! -d "bundles" ]; then npm link; fi);
fi
- if ([ "$MODULE" == "ng2-activiti-tasklist" ] || [ "$MODULE" == "ng2-activiti-processlist" ]); then
(cd ng2-components/ng2-activiti-form; npm link ng2-alfresco-core; if [ ! -d "dist" ]; then npm install; fi; npm link);
(cd ng2-components/ng2-alfresco-datatable; npm link ng2-alfresco-core; if [ ! -d "bundles" ]; then npm link; fi);
(cd ng2-components/ng2-activiti-form; npm link ng2-alfresco-core; if [ ! -d "bundles" ]; then npm link; fi);
fi
- if ([ "$MODULE" == "ng2-activiti-processlist" ]); then
(cd ng2-components/ng2-activiti-tasklist; npm link ng2-alfresco-core; npm link ng2-alfresco-datatable; npm link ng2-activiti-form; if [ ! -d "dist" ]; then npm install; fi; npm link);
(cd ng2-components/ng2-alfresco-datatable; npm link ng2-alfresco-core; if [ ! -d "bundles" ]; then npm link; fi);
(cd ng2-components/ng2-activiti-form; npm link ng2-alfresco-core; if [ ! -d "bundles" ]; then npm link; fi);
(cd ng2-components/ng2-activiti-tasklist; npm link ng2-alfresco-core; npm link ng2-alfresco-datatable; npm link ng2-activiti-form; if [ ! -d "bundles" ]; then npm link; fi);
fi
- if ([ "$MODULE" == "ng2-activiti-analytics" ]); then
(cd ng2-components/ng2-activiti-diagrams; npm link ng2-alfresco-core; if [ ! -d "dist" ]; then npm install; fi; npm link);
(cd ng2-components/ng2-activiti-diagrams; npm link ng2-alfresco-core; if [ ! -d "bundles" ]; then npm link; fi);
fi
- if ([ "$MODULE" == "ng2-alfresco-search" ]); then
(cd ng2-components/ng2-alfresco-datatable; npm link ng2-alfresco-core; if [ ! -d "bundles" ]; then npm link; fi);
(cd ng2-components/ng2-alfresco-documentlist; npm link ng2-alfresco-core; npm link ng2-alfresco-datatable; if [ ! -d "bundles" ]; then npm link; fi);
fi
- cd ng2-components/$MODULE;
- npm run travis;
- npm install;
script: npm run test
#npm insall run install, build and tests
script: npm install
# Send coverage data to Coveralls
after_success:
bash <(curl -s https://codecov.io/bash) -X gcov
+4 -2
View File
@@ -6,6 +6,8 @@
"**/.hg": true,
"**/.DS_Store": true,
"**/*.js": { "when": "$(basename).ts"},
"**/*.js.map": { "when": "$(basename)"}
}
"**/*.js.map": { "when": "$(basename)"},
"**/*.d.ts": { "when": "$(basename).ts"}
},
"editor.renderIndentGuides": true
}
+6
View File
@@ -56,6 +56,12 @@ To view the complete list of all the components that you can use to build your c
You can browse all the components at the following [page](http://devproducts.alfresco.com/).
## Demo Application
A separate application showcasing integration of components can be found [here](https://github.com/Alfresco/alfresco-ng2-components/tree/master/demo-shell-ng2).
You will find examples of basic interaction for both BPM and ECM sets of widgets.
## Yeoman generators
To speed up the development of your Alfresco Angular 2 application, or Alfresco Angular 2 component, use one of the Yeoman generators.
+17 -15
View File
@@ -1,4 +1,9 @@
# Test against this version of Node.js
branches:
only:
- master
- development
- dev-build-test
environment:
nodejs_version: "5"
@@ -25,22 +30,19 @@ install:
# Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version
# install module
- IF %COMPONENT_NAME% NEQ ng2-alfresco-core (cd ng2-components/ng2-alfresco-core && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-alfresco-documentlist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-activiti-form && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-activiti-tasklist && npm link ng2-alfresco-core && npm link ng2-alfresco-datatable && npm link ng2-activiti-form && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-tasklist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-tasklist (cd ng2-components/ng2-activiti-form && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-alfresco-webscript (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-analytics (cd ng2-components/ng2-activiti-diagrams && npm link link ng2-alfresco-core && npm install && npm link && cd ../../)
- IF %COMPONENT_NAME% NEQ ng2-alfresco-core (cd ng2-components/ng2-alfresco-core && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-alfresco-documentlist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-alfresco-search (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-alfresco-search (cd ng2-components/ng2-alfresco-documentlist && npm link ng2-alfresco-core && npm link ng2-alfresco-datatable && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-activiti-form && npm link ng2-alfresco-core && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (cd ng2-components/ng2-activiti-tasklist && npm link ng2-alfresco-core && npm link ng2-alfresco-datatable && npm link ng2-activiti-form && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-tasklist (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-tasklist (cd ng2-components/ng2-activiti-form && npm link ng2-alfresco-core && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-alfresco-webscript (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm link && cd ../../)
- IF %COMPONENT_NAME% EQU ng2-activiti-analytics (cd ng2-components/ng2-activiti-diagrams && npm link link ng2-alfresco-core && npm link && cd ../../)
- cd ng2-components/%COMPONENT_NAME%
- IF %COMPONENT_NAME% NEQ ng2-alfresco-core (npm link ng2-alfresco-core)
- IF %COMPONENT_NAME% EQU ng2-alfresco-documentlist (npm link ng2-alfresco-datatable)
- IF %COMPONENT_NAME% EQU ng2-activiti-processlist (npm link ng2-alfresco-datatable && npm link ng2-activiti-form && npm link ng2-activiti-tasklist)
- IF %COMPONENT_NAME% EQU ng2-activiti-tasklist (npm link ng2-alfresco-datatable && npm link ng2-activiti-form)
- IF %COMPONENT_NAME% EQU ng2-alfresco-webscript (npm link ng2-alfresco-datatable)
- IF %COMPONENT_NAME% EQU ng2-activiti-analytics (npm link ng2-activiti-diagrams)
- npm run travis
# Post-install test scripts.
test_script:
+12 -6
View File
@@ -12,9 +12,11 @@
## Installing
To correctly use this demo check that on your machine is running Node version 6.9.2 LTS or higher.
To correctly use this demo check that on your machine is running [Node](https://nodejs.org/en/) version 6.9.2 LTS or higher.
```sh
git clone https://github.com/Alfresco/alfresco-ng2-components.git
cd alfresco-ng2-components/demo-shell-ng2/
npm install
```
@@ -28,22 +30,26 @@ This command compiles and starts the project in watch mode.
Browser will automatically reload upon changes.
Upon start you can navigate to `http://localhost:3000` with your preferred browser.
### Important notes
This script is recommended for development environment and not suited for headless servers and network access.
## Production build
```sh
npm run build
npm run start:dist
```
This command builds broject in `production` mode.
All output is placed to `dist` folder and can be served your preferred web server.
You should need no additional files outside the `dist` folder.
In order to quickly test the output you can use the [wsrv](https://www.npmjs.com/package/wsrv) tool (lightweight web server):
### Important notes
```sh
npm install -g wsrv
wsrv -s -o dist/
```
By default demo application is configured to use [wsrv](https://www.npmjs.com/package/wsrv) tool (lightweight web server)
to serve production build output. It will be running at `0.0.0.0` address with port `3000` and allow you accessing your application
via network. However you can use any web server of your choice in production.
## Development branch build
+1 -1
View File
@@ -1,6 +1,6 @@
<!-- Always shows a header, even in smaller screens. -->
<div mdl class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header main_header_adf" [ngClass]="{hide: isLoginPage()}">
<header class="mdl-layout__header main_header_adf" [ngClass]="{hide: isAPageWithHeaderBar()}">
<div class="mdl-button-padding mdl-layout__header-row">
<!-- User Info -->
+21 -37
View File
@@ -17,13 +17,7 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import {
AlfrescoTranslationService,
AlfrescoAuthenticationService,
AlfrescoSettingsService,
StorageService
} from 'ng2-alfresco-core';
import { AlfrescoTranslationService, AlfrescoAuthenticationService, AlfrescoSettingsService, StorageService, LogService } from 'ng2-alfresco-core';
declare var document: any;
@@ -38,44 +32,34 @@ export class AppComponent {
ecmHost: string = 'http://' + window.location.hostname + ':8080';
bpmHost: string = 'http://' + window.location.hostname + ':9999';
constructor(public auth: AlfrescoAuthenticationService,
public router: Router,
public alfrescoSettingsService: AlfrescoSettingsService,
private translate: AlfrescoTranslationService,
private storage: StorageService) {
constructor(private authService: AlfrescoAuthenticationService,
private router: Router,
private settingsService: AlfrescoSettingsService,
private translateService: AlfrescoTranslationService,
private storage: StorageService,
private logService: LogService) {
this.setEcmHost();
this.setBpmHost();
this.setProvider();
if (translate) {
if (translateService) {
if (process.env.ENV === 'production') {
translate.addTranslationFolder('custom', 'i18n/custom-translation');
translate.addTranslationFolder('ng2-alfresco-login', 'i18n/custom-translation/alfresco-login');
translateService.addTranslationFolder('custom', 'i18n/custom-translation');
translateService.addTranslationFolder('ng2-alfresco-login', 'i18n/custom-translation/alfresco-login');
} else {
translate.addTranslationFolder('custom', 'custom-translation');
translate.addTranslationFolder('ng2-alfresco-login', 'custom-translation/alfresco-login');
translateService.addTranslationFolder('custom', 'custom-translation');
translateService.addTranslationFolder('ng2-alfresco-login', 'custom-translation/alfresco-login');
}
}
}
isLoggedIn(): boolean {
this.redirectToLoginPageIfNotLoggedIn();
return this.auth.isLoggedIn();
}
redirectToLoginPageIfNotLoggedIn(): void {
if (!this.isLoginPage() && !this.auth.isLoggedIn()) {
this.router.navigate(['/login']);
}
}
isLoginPage(): boolean {
isAPageWithHeaderBar(): boolean {
return location.pathname === '/login' || location.pathname === '/settings';
}
onLogout(event) {
event.preventDefault();
this.auth.logout()
this.authService.logout()
.subscribe(
() => {
this.navigateToLogin();
@@ -84,7 +68,7 @@ export class AppComponent {
if (error && error.response && error.response.status === 401) {
this.navigateToLogin();
} else {
console.error('An unknown error occurred while logging out', error);
this.logService.error('An unknown error occurred while logging out', error);
this.navigateToLogin();
}
}
@@ -107,7 +91,7 @@ export class AppComponent {
}
changeLanguage(lang: string) {
this.translate.use(lang);
this.translateService.use(lang);
this.hideDrawer();
}
@@ -118,25 +102,25 @@ export class AppComponent {
private setEcmHost() {
if (this.storage.hasItem(`ecmHost`)) {
this.alfrescoSettingsService.ecmHost = this.storage.getItem(`ecmHost`);
this.settingsService.ecmHost = this.storage.getItem(`ecmHost`);
this.ecmHost = this.storage.getItem(`ecmHost`);
} else {
this.alfrescoSettingsService.ecmHost = this.ecmHost;
this.settingsService.ecmHost = this.ecmHost;
}
}
private setBpmHost() {
if (this.storage.hasItem(`bpmHost`)) {
this.alfrescoSettingsService.bpmHost = this.storage.getItem(`bpmHost`);
this.settingsService.bpmHost = this.storage.getItem(`bpmHost`);
this.bpmHost = this.storage.getItem(`bpmHost`);
} else {
this.alfrescoSettingsService.bpmHost = this.bpmHost;
this.settingsService.bpmHost = this.bpmHost;
}
}
private setProvider() {
if (this.storage.hasItem(`providers`)) {
this.alfrescoSettingsService.setProviders(this.storage.getItem(`providers`));
this.settingsService.setProviders(this.storage.getItem(`providers`));
}
}
}
+3 -4
View File
@@ -32,7 +32,6 @@ 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';
import { CustomEditorsModule } from './components/activiti/custom-editor/custom-editor.component';
@@ -59,13 +58,13 @@ import {
BrowserModule,
routing,
CoreModule.forRoot(),
LoginModule,
LoginModule.forRoot(),
SearchModule.forRoot(),
DataTableModule,
DataTableModule.forRoot(),
DocumentListModule.forRoot(),
UploadModule.forRoot(),
TagModule.forRoot(),
WebScriptModule,
WebScriptModule.forRoot(),
ViewerModule.forRoot(),
ActivitiFormModule.forRoot(),
ActivitiTaskListModule.forRoot(),
@@ -18,6 +18,7 @@
import { Component, OnInit } from '@angular/core';
import { Http } from '@angular/http';
import { ObjectDataTableAdapter } from 'ng2-alfresco-datatable';
import { LogService } from 'ng2-alfresco-core';
@Component({
selector: 'about-page',
@@ -27,31 +28,31 @@ export class AboutComponent implements OnInit {
data: ObjectDataTableAdapter;
constructor(private http: Http) {
constructor(private http: Http,
private logService: LogService) {
}
ngOnInit() {
this.http.get('/versions.json').subscribe(response => {
var regexp = new RegExp("^(ng2-activiti|ng2-alfresco|alfresco-)", 'g');
let regexp = new RegExp('^(ng2-activiti|ng2-alfresco|alfresco-)', 'g');
var alfrescoPackages = Object.keys(response.json().dependencies).filter(function (val) {
console.log(val);
let alfrescoPackages = Object.keys(response.json().dependencies).filter((val) => {
this.logService.log(val);
return regexp.test(val);
});
let alfrescoPackagesTableRappresentation = [];
alfrescoPackages.forEach((val)=> {
console.log(response.json().dependencies[val]);
alfrescoPackagesTableRappresentation.push({name:val,version:response.json().dependencies[val].version});
let alfrescoPackagesTableRappresentation = [];
alfrescoPackages.forEach((val) => {
this.logService.log(response.json().dependencies[val]);
alfrescoPackagesTableRappresentation.push({name: val, version: response.json().dependencies[val].version});
});
console.log(alfrescoPackagesTableRappresentation);
this.logService.log(alfrescoPackagesTableRappresentation);
this.data = new ObjectDataTableAdapter(alfrescoPackagesTableRappresentation, [
{type: 'text', key: 'name', title: 'Name', sortable: true},
{type: 'text', key: 'version', title: 'Version', sortable: true}
]);
});
}
}
@@ -5,9 +5,9 @@
<!-- TABS -->
<div class="mdl-layout__tab-bar mdl-js-ripple-effect">
<a id="tasks-header" href="#tasks" class="mdl-layout__tab is-active">TASKS</a>
<a id="processes-header" href="#processes" class="mdl-layout__tab" (click)="activeProcess()">PROCESSES</a>
<a id="report-header" href="#report" class="mdl-layout__tab" (click)="activeReports()">REPORTS</a>
<a id="tasks-header" href="#tasks" class="mdl-layout__tab" [class.is-active]="activeTab === 'tasks'" (click)="activeTab = 'tasks'">TASKS</a>
<a id="processes-header" href="#processes" class="mdl-layout__tab" [class.is-active]="activeTab === 'processes'" (click)="activeTab = 'processes'">PROCESSES</a>
<a id="report-header" href="#report" class="mdl-layout__tab" [class.is-active]="activeTab === 'reports'" (click)="activeTab = 'reports'">REPORTS</a>
</div>
</header>
@@ -15,7 +15,7 @@
<!-- TASKS COMPONENT -->
<section class="mdl-layout__tab-panel is-active" id="tasks">
<section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'tasks'" id="tasks">
<div class="page-content">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp">
@@ -36,6 +36,7 @@
[state]="taskFilter.filter.state"
[sort]="taskFilter.filter.sort"
[data]="dataTasks"
[landingTaskId]="currentTaskId"
(rowClick)="onTaskRowClick($event)" (onSuccess)="onSuccessTaskList($event)"
#activititasklist></activiti-tasklist>
</div>
@@ -43,6 +44,7 @@
<span><h5>Task Details</h5></span>
<hr>
<activiti-task-details [taskId]="currentTaskId" (formCompleted)="onFormCompleted($event)"
(taskCreated)="onTaskCreated($event)"
#activitidetails></activiti-task-details>
</div>
</div>
@@ -52,8 +54,8 @@
<!-- PROCESS COMPONENT -->
<section class="mdl-layout__tab-panel" id="processes">
<div class="page-content" *ngIf="processTabActivie">
<section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'processes'" id="processes">
<div class="page-content" *ngIf="activeTab === 'processes'">
<div class="page-content">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp">
@@ -66,7 +68,7 @@
(filterClick)="onProcessFilterClick($event)"
(onSuccess)="onSuccessProcessFilterList($event)"></activiti-process-instance-filters>
</div>
<div class="mdl-cell mdl-cell--3-col task-column list-column mdl-shadow--2dp">
<div class="mdl-cell mdl-cell--3-col task-column list-column mdl-shadow--2dp" *ngIf="processFilter && !isStartProcessMode()">
<span><h5>Process List</h5></span>
<hr>
<activiti-process-instance-list *ngIf="processFilter?.hasFilter()" [appId]="processFilter.appId"
@@ -78,15 +80,19 @@
(rowClick)="onProcessRowClick($event)"
(onSuccess)="onSuccessProcessList($event)"></activiti-process-instance-list>
</div>
<div class="mdl-cell mdl-cell--7-col task-column mdl-shadow--2dp" *ngIf="!isStartProcessMode()">
<div class="mdl-cell task-column mdl-shadow--2dp" *ngIf="!isStartProcessMode()"
[class.mdl-cell--7-col]="processFilter && !isStartProcessMode()"
[class.mdl-cell--10-col]="!processFilter || isStartProcessMode()">
<span><h5>Process Details</h5></span>
<hr>
<activiti-process-instance-details [processInstanceId]="currentProcessInstanceId"
(activitiprocesslist)="taskFormCompleted()"
(processCancelled)="processCancelled()"></activiti-process-instance-details>
<activiti-process-instance-details
[processInstanceId]="currentProcessInstanceId"
(processCancelled)="processCancelled()"
(taskClick)="onProcessDetailsTaskClick($event)">
</activiti-process-instance-details>
</div>
<div class="mdl-cell mdl-cell--7-col task-column" *ngIf="isStartProcessMode()">
<span>Start Process</span>
<div class="mdl-cell mdl-cell--10-col task-column mdl-shadow--2dp" *ngIf="isStartProcessMode()">
<span><h5>Start Process</h5></span>
<hr>
<activiti-start-process [appId]="appId" (start)="onStartProcessInstance($event)"></activiti-start-process>
</div>
@@ -98,8 +104,8 @@
<!-- ANALYTICS COMPONENT -->
<section class="mdl-layout__tab-panel" id="report">
<div class="page-content" *ngIf="reportsTabActivie">
<section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'reports'" id="report">
<div class="page-content" *ngIf="activeTab === 'reports'">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col task-column mdl-shadow--2dp">
<span><h5>Report List</h5></span>
@@ -19,15 +19,16 @@ import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular
import {
ActivitiApps,
ActivitiFilters,
ActivitiTaskDetails,
ActivitiTaskList,
FilterRepresentationModel
FilterRepresentationModel,
TaskDetailsEvent
} from 'ng2-activiti-tasklist';
import {
ActivitiProcessFilters,
ActivitiProcessInstanceDetails,
ActivitiProcessInstanceListComponent,
ActivitiStartProcessInstance,
FilterProcessRepresentationModel,
ProcessInstance
} from 'ng2-activiti-processlist';
import { AnalyticsReportListComponent } from 'ng2-activiti-analytics';
@@ -35,10 +36,11 @@ import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Rx';
import {
ObjectDataTableAdapter,
ObjectDataRow,
DataSorting
} from 'ng2-alfresco-datatable';
import { AlfrescoApiService } from 'ng2-alfresco-core';
import { FormRenderingService } from 'ng2-activiti-form';
import { FormService, FormRenderingService, FormEvent, FormFieldEvent } from 'ng2-activiti-form';
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
declare var componentHandler;
@@ -52,18 +54,12 @@ const currentProcessIdNew = '__NEW__';
})
export class ActivitiDemoComponent implements AfterViewInit {
@ViewChild(ActivitiApps)
activitiapps: ActivitiApps;
@ViewChild(ActivitiFilters)
activitifilter: ActivitiFilters;
@ViewChild(ActivitiTaskList)
activititasklist: ActivitiTaskList;
@ViewChild(ActivitiTaskDetails)
activitidetails: ActivitiTaskDetails;
@ViewChild(ActivitiProcessFilters)
activitiprocessfilter: ActivitiProcessFilters;
@@ -80,7 +76,7 @@ export class ActivitiDemoComponent implements AfterViewInit {
analyticsreportlist: AnalyticsReportListComponent;
@Input()
appId: number;
appId: number = null;
layoutType: string;
currentTaskId: string;
@@ -89,13 +85,11 @@ export class ActivitiDemoComponent implements AfterViewInit {
taskSchemaColumns: any [] = [];
processSchemaColumns: any [] = [];
processTabActivie: boolean = false;
reportsTabActivie: boolean = false;
activeTab: string = 'tasks'; // tasks|processes|reports
taskFilter: FilterRepresentationModel;
report: any;
processFilter: FilterRepresentationModel;
processFilter: FilterProcessRepresentationModel;
sub: Subscription;
@@ -105,7 +99,8 @@ export class ActivitiDemoComponent implements AfterViewInit {
constructor(private elementRef: ElementRef,
private route: ActivatedRoute,
private apiService: AlfrescoApiService,
private formRenderingService: FormRenderingService) {
private formRenderingService: FormRenderingService,
private formService: FormService) {
this.dataTasks = new ObjectDataTableAdapter(
[],
[
@@ -122,12 +117,21 @@ export class ActivitiDemoComponent implements AfterViewInit {
{type: 'text', key: 'started', title: 'Started', cssClass: 'hidden', sortable: true}
]
);
this.dataProcesses.setSorting(new DataSorting('started', 'desc'));
// Uncomment this line to replace all 'text' field editors with custom component
// formRenderingService.setComponentTypeResolver('text', () => CustomEditorComponent, true);
// Uncomment this line to map 'custom_stencil_01' to local editor component
formRenderingService.setComponentTypeResolver('custom_stencil_01', () => CustomStencil01, true);
formService.formLoaded.subscribe((e: FormEvent) => {
console.log(`Form loaded: ${e.form.id}`);
});
formService.formFieldValueChanged.subscribe((e: FormFieldEvent) => {
console.log(`Field value changed. Form: ${e.form.id}, Field: ${e.field.id}, Value: ${e.field.value}`);
});
}
ngOnInit() {
@@ -150,7 +154,9 @@ export class ActivitiDemoComponent implements AfterViewInit {
}
onTaskFilterClick(event: FilterRepresentationModel) {
this.taskFilter = event;
if(event){
this.taskFilter = event;
}
}
onReportClick(event: any) {
@@ -171,11 +177,12 @@ export class ActivitiDemoComponent implements AfterViewInit {
this.currentTaskId = this.activititasklist.getCurrentId();
}
onProcessFilterClick(event: FilterRepresentationModel) {
onProcessFilterClick(event: FilterProcessRepresentationModel) {
this.currentProcessInstanceId = null;
this.processFilter = event;
}
onSuccessProcessFilterList(event: any) {
onSuccessProcessFilterList() {
this.processFilter = this.activitiprocessfilter.getCurrentFilter();
}
@@ -196,13 +203,15 @@ export class ActivitiDemoComponent implements AfterViewInit {
}
navigateStartProcess() {
this.resetProcessFilters();
this.reloadProcessFilters();
this.currentProcessInstanceId = currentProcessIdNew;
}
onStartProcessInstance(instance: ProcessInstance) {
this.currentProcessInstanceId = instance.id;
this.activitiStartProcess.reset();
this.activitiprocesslist.reload();
this.resetProcessFilters();
}
isStartProcessMode() {
@@ -218,15 +227,16 @@ export class ActivitiDemoComponent implements AfterViewInit {
this.activitiprocesslist.reload();
}
taskFormCompleted(data: any) {
this.activitiprocesslist.reload();
}
onFormCompleted(form) {
this.activititasklist.reload();
this.currentTaskId = null;
}
onTaskCreated(data: any) {
this.currentTaskId = data.parentTaskId;
this.activititasklist.reload();
}
ngAfterViewInit() {
// workaround for MDL issues with dynamic components
if (componentHandler) {
@@ -236,14 +246,6 @@ export class ActivitiDemoComponent implements AfterViewInit {
this.loadStencilScriptsInPageFromActiviti();
}
activeProcess() {
this.processTabActivie = true;
}
activeReports() {
this.reportsTabActivie = true;
}
loadStencilScriptsInPageFromActiviti() {
this.apiService.getInstance().activiti.scriptFileApi.getControllers().then(response => {
if (response) {
@@ -255,4 +257,26 @@ export class ActivitiDemoComponent implements AfterViewInit {
});
}
onProcessDetailsTaskClick(event: TaskDetailsEvent) {
event.preventDefault();
this.activeTab = 'tasks';
let processTaskDataRow = new ObjectDataRow({
id: event.value.id,
name: event.value.name || 'No name',
created: event.value.created
});
this.activitifilter.selectFilter(null);
this.dataTasks.setRows([processTaskDataRow]);
this.activititasklist.selectTask(event.value.id);
this.currentTaskId = event.value.id;
}
private resetProcessFilters() {
this.processFilter = null;
}
private reloadProcessFilters() {
this.activitiprocessfilter.selectFilter(null);
}
}
@@ -1,12 +1,11 @@
<div class="container">
<alfresco-upload-drag-area
[rootFolderId]="uploadRootFolderId"
[currentFolderPath]="uploadFolderPath"
[rootFolderId]="documentList.currentFolderId"
[versioning] = "versioning"
(onSuccess)="documentList.reload()">
<alfresco-document-list-breadcrumb
[currentFolderPath]="currentPath"
(pathChanged)="onBreadcrumbPathChanged($event)" *ngIf="!currentFolderId">
[target]="documentList"
[folderNode]="documentList.folderNode">
</alfresco-document-list-breadcrumb>
<div *ngIf="errorMessage" class="error-message">
<button (click)="resetError()" class="mdl-button mdl-js-button mdl-button--icon">
@@ -16,22 +15,12 @@
</div>
<alfresco-document-list
#documentList
[rootFolderId]="rootFolderId"
[currentFolderPath]="currentPath"
[currentFolderId]="currentFolderId"
[contextMenuActions]="true"
[contentActions]="true"
(error)="onNavigationError($event)"
(success)="resetError()"
(preview)="showFile($event)"
(folderChange)="onFolderChanged($event)">
<!--
<empty-folder-content>
<template>
<h1>Sorry, no content here</h1>
</template>
</empty-folder-content>
-->
(preview)="showFile($event)">
<content-columns>
<content-column key="$thumbnail" type="image"></content-column>
<content-column
@@ -39,13 +28,13 @@
key="name"
sortable="true"
class="full-width ellipsis-cell">
<!-- Example of using custom column template -->
<!--
<template let-entry="$implicit">
<span>Hi! {{entry.data.getValue(entry.row, entry.col)}}</span>
</template>
-->
</content-column>
<!--
<content-column
title="Type"
source="content.mimeType">
</content-column>
-->
<content-column
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_BY' | translate}}"
key="createdByUser.displayName"
@@ -107,43 +96,11 @@
</content-action>
</content-actions>
</alfresco-document-list>
<alfresco-pagination
[provider]="documentList.data"
[supportedPageSizes]="[5, 10, 15, 20]">
</alfresco-pagination>
</alfresco-upload-drag-area>
</div>
<context-menu-holder></context-menu-holder>
<div class="p-10">
<ul>
<li>Current path: {{currentPath}}</li>
<li>
<button (click)="currentPath = '/'">Go to root</button>
</li>
<li>
<button (click)="currentPath = '/Sites'">Go to Sites</button>
</li>
<li>
<button (click)="currentPath = '/Sites/swsdp';">Go to Web Site Design Project site</button>
</li>
<li>
<button (click)="currentPath = '/Sites/swsdp/documentLibrary';">Go to Document Library</button>
</li>
<li>
<button (click)="currentPath = '/Sites/swsdp/documentLibrary/Agency Files/Contracts'">Go to Agency Contracts</button>
</li>
<li>
<button (click)="currentPath = '!@£$%^&*()'">Go to the wrong path</button>
</li>
<li>
<button (click)="fileDialog.toggleShowDialog()">Show/Hide File Dialog</button>
</li>
</ul>
</div>
<p style="width:250px;margin: 20px;">
<label for="switch-multiple-file" class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input type="checkbox" id="switch-multiple-file" class="mdl-switch__input" (change)="toggleMultipleFileUpload()" >
@@ -183,8 +140,7 @@
</div>
<div *ngIf="!acceptedFilesTypeShow">
<alfresco-upload-button data-automation-id="multiple-file-upload"
[rootFolderId]="uploadRootFolderId"
[currentFolderPath]="uploadFolderPath"
[rootFolderId]="documentList.currentFolderId"
[multipleFiles]="multipleFileUpload"
[uploadFolders]="folderUpload"
[versioning] = "versioning"
@@ -194,9 +150,8 @@
</div>
<div *ngIf="acceptedFilesTypeShow">
<alfresco-upload-button data-automation-id="multiple-file-upload"
[rootFolderId]="uploadRootFolderId"
[currentFolderPath]="uploadFolderPath"
acceptedFilesType="{{acceptedFilesType}}"
[rootFolderId]="documentList.currentFolderId"
[acceptedFilesType]="acceptedFilesType"
[multipleFiles]="multipleFileUpload"
[uploadFolders]="folderUpload"
[versioning] = "versioning"
@@ -15,16 +15,10 @@
* limitations under the License.
*/
import { Component, OnInit, Optional, ViewChild } from '@angular/core';
import { Component, OnInit, Optional, ViewChild, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import {
DocumentActionsService,
DocumentList,
ContentActionHandler,
DocumentActionModel,
FolderActionModel
} from 'ng2-alfresco-documentlist';
import { AlfrescoAuthenticationService, LogService } from 'ng2-alfresco-core';
import { DocumentActionsService, DocumentListComponent, ContentActionHandler, DocumentActionModel, FolderActionModel } from 'ng2-alfresco-documentlist';
import { FormService } from 'ng2-activiti-form';
@Component({
@@ -33,9 +27,8 @@ import { FormService } from 'ng2-activiti-form';
styleUrls: ['./files.component.css']
})
export class FilesComponent implements OnInit {
currentPath: string = '/Sites/swsdp/documentLibrary';
rootFolderId: string = '-root-';
currentFolderId: string = null;
// The identifier of a node. You can also use one of these well-known aliases: -my- | -shared- | -root-
currentFolderId: string = '-my-';
errorMessage: string = null;
fileNodeId: any;
@@ -44,23 +37,16 @@ export class FilesComponent implements OnInit {
folderUpload: boolean = false;
acceptedFilesTypeShow: boolean = false;
versioning: boolean = false;
acceptedFilesType: string = '.jpg,.pdf,.js';
get uploadRootFolderId(): string {
return this.currentFolderId || this.rootFolderId;
}
get uploadFolderPath(): string {
return this.currentFolderId ? '/' : this.currentPath;
}
@ViewChild(DocumentList)
documentList: DocumentList;
@ViewChild(DocumentListComponent)
documentList: DocumentListComponent;
constructor(private documentActions: DocumentActionsService,
public auth: AlfrescoAuthenticationService,
private authService: AlfrescoAuthenticationService,
private formService: FormService,
private logService: LogService,
private changeDetector: ChangeDetectorRef,
private router: Router,
@Optional() private route: ActivatedRoute) {
documentActions.setHandler('my-handler', this.myDocumentActionHandler.bind(this));
@@ -87,18 +73,6 @@ export class FilesComponent implements OnInit {
}
}
onFolderChanged(event?: any) {
if (event) {
this.currentPath = event.path;
}
}
onBreadcrumbPathChanged(event?: any) {
if (event) {
this.currentPath = event.value;
}
}
toggleMultipleFileUpload() {
this.multipleFileUpload = !this.multipleFileUpload;
return this.multipleFileUpload;
@@ -123,16 +97,19 @@ export class FilesComponent implements OnInit {
ngOnInit() {
if (this.route) {
this.route.params.forEach((params: Params) => {
this.currentFolderId = params.hasOwnProperty('id') ? params['id'] : null;
if (params['id']) {
this.currentFolderId = params['id'];
this.changeDetector.detectChanges();
}
});
}
if (this.auth.isBpmLoggedIn()) {
if (this.authService.isBpmLoggedIn()) {
this.formService.getProcessDefinitions().subscribe(
defs => this.setupBpmActions(defs || []),
err => console.log(err)
err => this.logService.error(err)
);
} else {
console.log('You are not logged in');
this.logService.warn('You are not logged in to BPM');
}
}
@@ -7,11 +7,11 @@
</h2>
</div>
<div class="mdl-card__supporting-text">
Demonstrates multiple Alfresco ECM components used together to show the files of you ECM instance :
Demonstrates multiple Alfresco ECM components used together to display the files of your ECM instance:
<ul class="home--feature-list">
<li>
<i class="material-icons home--feature-list__icon">brightness_1</i>
<span class="home--feature-list__text">Comunication with the Rest Api and core services</span>
<span class="home--feature-list__text">Communication with the Rest Api and core services</span>
<a href="https://www.npmjs.com/package/ng2-alfresco-core" target="_blank">ng2-alfresco-core</a>
</li>
<li>
@@ -43,11 +43,11 @@
</h2>
</div>
<div class="mdl-card__supporting-text">
Demonstrates multiple Alfresco BPM components used together to show your BPM prorcess and tasks:
Demonstrates multiple Alfresco BPM components used together to show your BPM process and tasks:
<ul class="home--feature-list">
<li>
<i class="material-icons home--feature-list__icon">brightness_1</i>
<span class="home--feature-list__text">Comunication with the Rest Api and core services</span>
<span class="home--feature-list__text">Communication with the Rest Api and core services</span>
<a href="https://www.npmjs.com/package/ng2-alfresco-core" target="_blank">ng2-alfresco-core</a>
</li>
<li>
@@ -99,7 +99,7 @@
<ul class="home--feature-list">
<li>
<i class="material-icons home--feature-list__icon">brightness_1</i>
<span class="home--feature-list__text">Comunication with the Rest Api and core services</span>
<span class="home--feature-list__text">Communication with the Rest Api and core services</span>
<a href="https://www.npmjs.com/package/ng2-alfresco-core" target="_blank">ng2-alfresco-core</a>
</li>
</ul>
@@ -119,7 +119,7 @@
<ul class="home--feature-list">
<li>
<i class="material-icons home--feature-list__icon">brightness_1</i>
<span class="home--feature-list__text">Comunication with the Rest Api and core services</span>
<span class="home--feature-list__text">Communication with the Rest Api and core services</span>
<a href="https://www.npmjs.com/package/ng2-alfresco-core" target="_blank">ng2-alfresco-core</a>
</li>
</ul>
@@ -139,7 +139,7 @@
<ul class="home--feature-list">
<li>
<i class="material-icons home--feature-list__icon">brightness_1</i>
<span class="home--feature-list__text">Comunication with the Rest Api and core services</span>
<span class="home--feature-list__text">Communication with the Rest Api and core services</span>
<a href="https://www.npmjs.com/package/ng2-alfresco-core" target="_blank">ng2-alfresco-core</a>
</li>
</ul>
@@ -155,11 +155,11 @@
</h2>
</div>
<div class="mdl-card__supporting-text">
Shows and create webscripts in your ECM instance:
Displays and creates webscripts in your ECM instance:
<ul class="home--feature-list">
<li>
<i class="material-icons home--feature-list__icon">brightness_1</i>
<span class="home--feature-list__text">Comunication with the Rest Api and core services</span>
<span class="home--feature-list__text">Communication with the Rest Api and core services</span>
<a href="https://www.npmjs.com/package/ng2-alfresco-core" target="_blank">ng2-alfresco-core</a>
</li>
</ul>
@@ -175,11 +175,11 @@
</h2>
</div>
<div class="mdl-card__supporting-text">
Shows and add tags to the node of your ECM instance:
Displays and adds tags to the node of your ECM instance:
<ul class="home--feature-list">
<li>
<i class="material-icons home--feature-list__icon">brightness_1</i>
<span class="home--feature-list__text">Comunication with Rest</span>
<span class="home--feature-list__text">Communication with Rest</span>
<a href="https://www.npmjs.com/package/ng2-alfresco-core" target="_blank">ng2-alfresco-core</a>
</li>
</ul>
@@ -18,7 +18,7 @@
import { Component, ViewChild, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Validators } from '@angular/forms';
import { StorageService } from 'ng2-alfresco-core';
import { StorageService, LogService } from 'ng2-alfresco-core';
@Component({
selector: 'login-demo',
@@ -37,17 +37,20 @@ export class LoginDemoComponent implements OnInit {
disableCsrf: boolean = false;
isECM: boolean = true;
isBPM: boolean = false;
customMinLenght: number = 2;
constructor(public router: Router, private storage: StorageService) {
constructor(private router: Router,
private storage: StorageService,
private logService: LogService) {
this.customValidation = {
username: ['', Validators.compose([Validators.required, Validators.minLength(4)])],
username: ['', Validators.compose([Validators.required, Validators.minLength(this.customMinLenght)])],
password: ['', Validators.required]
};
}
ngOnInit() {
this.alfrescologin.addCustomValidationError('username', 'required', 'LOGIN.MESSAGES.USERNAME-REQUIRED');
this.alfrescologin.addCustomValidationError('username', 'minlength', 'LOGIN.MESSAGES.USERNAME-MIN');
this.alfrescologin.addCustomValidationError('username', 'minlength', 'LOGIN.MESSAGES.USERNAME-MIN', {customMinLenght: this.customMinLenght});
this.alfrescologin.addCustomValidationError('password', 'required', 'LOGIN.MESSAGES.PASSWORD-REQUIRED');
if (this.storage.hasItem('providers')) {
@@ -75,7 +78,7 @@ export class LoginDemoComponent implements OnInit {
}
onError($event) {
console.log($event);
this.logService.error($event);
}
toggleECM() {
@@ -92,7 +95,7 @@ export class LoginDemoComponent implements OnInit {
this.disableCsrf = !this.disableCsrf;
}
updateProvider(){
updateProvider() {
if (this.isBPM && this.isECM) {
this.providers = 'ALL';
return this.providers;
@@ -34,11 +34,11 @@ export class SearchBarComponent {
expand = new EventEmitter();
constructor(public router: Router,
public auth: AlfrescoAuthenticationService) {
public authService: AlfrescoAuthenticationService) {
}
isLoggedIn(): boolean {
return this.auth.isLoggedIn();
return this.authService.isLoggedIn();
}
/**
@@ -1,8 +1,12 @@
<div class="search-results-container">
<h1>Search results</h1>
<alfresco-search (navigate)="onNavigateItem($event)"></alfresco-search>
<alfresco-search (preview)="showFile($event)"></alfresco-search>
</div>
<alfresco-viewer *ngIf="fileShowed" [(showViewer)]="fileShowed" [fileNodeId]="fileNodeId" [overlayMode]="true">
<div class="mdl-spinner mdl-js-spinner is-active"></div>
</alfresco-viewer>
<div *ngIf="fileShowed">
<alfresco-viewer [(showViewer)]="fileShowed"
[fileNodeId]="fileNodeId"
[overlayMode]="true">
<div class="mdl-spinner mdl-js-spinner is-active"></div>
</alfresco-viewer>
</div>
@@ -47,18 +47,18 @@ import { MinimalNodeEntity } from 'alfresco-js-api';
})
export class SearchComponent {
fileShowed: boolean = false;
fileNodeId: string;
fileShowed: boolean = false;
constructor(public router: Router) {
}
onNavigateItem(event: MinimalNodeEntity) {
if (event.entry.isFile) {
this.fileNodeId = event.entry.id;
showFile(event) {
if (event.value.entry.isFile) {
this.fileNodeId = event.value.entry.id;
this.fileShowed = true;
} else if (event.entry.isFolder) {
this.router.navigate(['/files', event.entry.id]);
} else {
this.fileShowed = false;
}
}
}
@@ -16,7 +16,7 @@
*/
import { Component } from '@angular/core';
import { AlfrescoSettingsService, StorageService } from 'ng2-alfresco-core';
import { AlfrescoSettingsService, StorageService, LogService } from 'ng2-alfresco-core';
@Component({
selector: 'alfresco-setting-demo',
@@ -28,24 +28,31 @@ export class SettingComponent {
ecmHost: string;
bpmHost: string;
constructor(public alfrescoSettingsService: AlfrescoSettingsService,
private storage: StorageService) {
this.ecmHost = this.alfrescoSettingsService.ecmHost;
this.bpmHost = this.alfrescoSettingsService.bpmHost;
constructor(private settingsService: AlfrescoSettingsService,
private storage: StorageService,
private logService: LogService) {
this.ecmHost = this.settingsService.ecmHost;
this.bpmHost = this.settingsService.bpmHost;
}
public onChangeECMHost(event: KeyboardEvent): void {
console.log((<HTMLInputElement>event.target).value);
this.ecmHost = (<HTMLInputElement>event.target).value;
this.alfrescoSettingsService.ecmHost = this.ecmHost;
this.storage.setItem(`ecmHost`, this.ecmHost);
let value = (<HTMLInputElement>event.target).value.trim();
if (value) {
this.logService.info(`ECM host: ${value}`);
this.ecmHost = value;
this.settingsService.ecmHost = value;
this.storage.setItem(`ecmHost`, value);
}
}
public onChangeBPMHost(event: KeyboardEvent): void {
console.log((<HTMLInputElement>event.target).value);
this.bpmHost = (<HTMLInputElement>event.target).value;
this.alfrescoSettingsService.bpmHost = this.bpmHost;
this.storage.setItem(`bpmHost`, this.bpmHost);
let value = (<HTMLInputElement>event.target).value.trim();
if (value) {
this.logService.info(`BPM host: ${value}`);
this.bpmHost = value;
this.settingsService.bpmHost = value;
this.storage.setItem(`bpmHost`, value);
}
}
}
@@ -16,42 +16,41 @@
*/
import { Component } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
@Component({
selector: 'alfresco-webscript-demo',
template: `
<label for="script-path"><b>Insert a scriptPath</b></label><br>
<input id="script-path" type="text" size="48" [(ngModel)]="scriptPath"><br>
<label for="context-root"><b>Insert a contextRoot</b></label><br>
<input id="context-root" type="text" size="48" [(ngModel)]="contextRoot"><br>
<label for="service-path"><b>Insert a servicePath</b></label><br>
<input id="service-path" type="text" size="48" [(ngModel)]="servicePath"><br>
<alfresco-webscript-get [scriptPath]="scriptPath"
[scriptArgs]="scriptArgs"
[contextRoot]="contextRoot"
[servicePath]="servicePath"
[contentType]="'HTML'"
(onSuccess)= "logData($event)"></alfresco-webscript-get>
<label for="script-path"><b>Insert a scriptPath</b></label><br>
<input id="script-path" type="text" size="48" [(ngModel)]="scriptPath"><br>
<label for="context-root"><b>Insert a contextRoot</b></label><br>
<input id="context-root" type="text" size="48" [(ngModel)]="contextRoot"><br>
<label for="service-path"><b>Insert a servicePath</b></label><br>
<input id="service-path" type="text" size="48" [(ngModel)]="servicePath"><br>
<alfresco-webscript-get
[scriptPath]="scriptPath"
[scriptArgs]="scriptArgs"
[contextRoot]="contextRoot"
[servicePath]="servicePath"
[contentType]="'HTML'"
(onSuccess)= "logData($event)">
</alfresco-webscript-get>
`
})
export class WebscriptComponent {
currentPath: string = '/';
authenticated: boolean;
host: string = 'http://127.0.0.1:8080';
scriptPath: string = 'sample/folder/Company%20Home';
contextRoot: string = 'alfresco';
servicePath: string = 'service';
scriptArgs: string = '';
constructor(private logService: LogService) {
}
logData(data) {
console.log(data);
this.logService.log(data);
}
}
+4
View File
@@ -32,9 +32,13 @@ import 'dialog-polyfill/dialog-polyfill.css';
// Flags
import 'flag-icon-css/css/flag-icon.min.css';
import '../public/css/app.css';
import '../public/css/muli-font.css';
// Load the Angular Material 2 stylesheet
import '@angular/material/core/theming/prebuilt/deeppurple-amber.css'
import 'ng2-activiti-form/stencils/runtime.ng1';
import 'ng2-activiti-form/stencils/runtime.adf';
+3 -1
View File
@@ -10,7 +10,6 @@ module.exports = webpackMerge(commonConfig, {
output: {
path: helpers.root('dist'),
publicPath: 'http://localhost:3000/',
filename: '[name].js',
chunkFilename: '[id].chunk.js'
},
@@ -60,6 +59,9 @@ module.exports = webpackMerge(commonConfig, {
],
devServer: {
host: '0.0.0.0',
port: 3000,
inline: true,
historyApiFallback: true,
stats: 'minimal'
}
+14 -6
View File
@@ -1,6 +1,5 @@
var helpers = require('./helpers');
var fs = require('fs');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var glob = require('glob');
const rootPath = helpers.root('node_modules');
@@ -34,12 +33,21 @@ module.exports = {
},
module: {
preLoaders: [
{
test: /\.js$/,
include: [
...alfrescoLibs
],
loader: 'source-map-loader'
}
],
loaders: [
{
test: /\.ts$/,
exclude: /node_modules/,
loaders: ['awesome-typescript-loader', 'angular2-template-loader']
},
{
test: /\.ts$/,
loaders: ['awesome-typescript-loader', 'angular2-template-loader', 'systemjs-loader'],
exclude: ['node_modules','public']
},
{
test: /\.js$/,
include: [
@@ -1,26 +1,29 @@
{
"LOGIN": {
"LOGO": "Alfresco",
"LABEL": {
"LOGIN": "Login",
"USERNAME": "Username",
"PASSWORD": "Password",
"REMEMBER": "Remember"
},
"MESSAGES": {
"USERNAME-REQUIRED": "Required",
"USERNAME-MIN": "Your username needs to be at least 4 characters.",
"PASSWORD-REQUIRED": "Enter your password to sign in",
"LOGIN-ERROR-CREDENTIALS": "You have entered an invalid username or password",
"LOGIN-ERROR-PROVIDERS": "Providers cannot be undefined",
"LOGIN-SUCCESS": "Login successful"
},
"BUTTON": {
"LOGIN": "SIGN IN"
},
"ACTION": {
"HELP": "NEED HELP?",
"REGISTER": "REGISTER"
"LOGIN": {
"LOGO": "Alfresco",
"LABEL": {
"LOGIN": "Login",
"USERNAME": "Username",
"PASSWORD": "Password",
"REMEMBER": "Remember"
},
"MESSAGES": {
"USERNAME-REQUIRED": "Required",
"USERNAME-MIN": "Your username needs to be at least {{customMinLenght}} characters.",
"PASSWORD-REQUIRED": "Enter your password to sign in",
"LOGIN-ERROR-CREDENTIALS": "You have entered an invalid username or password",
"LOGIN-ERROR-PROVIDERS": "Providers cannot be undefined",
"LOGIN-SUCCESS": "Login successful",
"LOGIN-ERROR-CORS": "CORS exception, check your server configuration",
"LOGIN-ERROR-CSRF": "CSRF exception, set [disableCsrf]=\"true\" in alfresco-login component",
"LOGIN-ECM-LICENSE": "The ECM is in read-only mode"
},
"BUTTON": {
"LOGIN": "SIGN IN"
},
"ACTION": {
"HELP": "NEED HELP?",
"REGISTER": "REGISTER"
}
}
}
}
@@ -1,25 +1,28 @@
{
"LOGIN": {
"LABEL": {
"LOGIN": "Autenticazione",
"USERNAME": "Nome utente",
"PASSWORD": "Password",
"REMEMBER": "Ricordami"
},
"MESSAGES": {
"USERNAME-REQUIRED": "Campo obbligatorio",
"USERNAME-MIN": "Inserire un nome utente di minimo 4 caratteri.",
"PASSWORD-REQUIRED": "Campo obbligatorio",
"LOGIN-ERROR-CREDENTIALS": "Nome utente o password non validi",
"LOGIN-ERROR-PROVIDERS": "Providers non può essere nullo",
"LOGIN-SUCCESS": "Login effettuata con successo"
},
"BUTTON": {
"LOGIN": "Accedi"
},
"ACTION": {
"HELP": "BISOGNO DI AIUTO?",
"REGISTER": "REGISTRATI"
"LOGIN": {
"LABEL": {
"LOGIN": "Autenticazione",
"USERNAME": "Nome utente",
"PASSWORD": "Password",
"REMEMBER": "Ricordami"
},
"MESSAGES": {
"USERNAME-REQUIRED": "Campo obbligatorio",
"USERNAME-MIN": "Inserire un nome utente di minimo 4 caratteri.",
"PASSWORD-REQUIRED": "Campo obbligatorio",
"LOGIN-ERROR-CREDENTIALS": "Nome utente o password non validi",
"LOGIN-ERROR-PROVIDERS": "Providers non può essere nullo",
"LOGIN-SUCCESS": "Login effettuata con successo",
"LOGIN-ERROR-CORS": "CORS exception, controlla le configurazioni del tuo server",
"LOGIN-ERROR-CSRF": "CSRF exception, set [disableCsrf]=\"true\" in alfresco-login component",
"LOGIN-ECM-LICENSE": "l'ECM e' in read-only mode"
},
"BUTTON": {
"LOGIN": "Accedi"
},
"ACTION": {
"HELP": "BISOGNO DI AIUTO?",
"REGISTER": "REGISTRATI"
}
}
}
}
}
+33 -9
View File
@@ -11,10 +11,12 @@
<!-- Polyfill(s) for Safari (pre-10.x) -->
<script src=js/Intl.min.js></script>
<!-- IE/FF -->
<script src=js/element.scrollintoviewifneeded-polyfill.js></script>
<!--[if IE]>
<script src=js/shim.min.js></script>
<script src=//cdnjs.cloudflare.com/ajax/libs/dom4/1.8.3/dom4.js></script>
<script src=js/element.scrollintoviewifneeded-polyfill.js></script>
<script src=js/classlist-polyfill.js></script>
<script src=js/web-animations.min.js></script>
<script src=js/typedarray.js></script>
@@ -31,14 +33,31 @@
<script src="js/material.min.js"></script>
<link href="css/iconfont/material-icons.css" rel="stylesheet">
<style>
.main_header_adf .mdl-layout__drawer-button {
right: 0 !important;
left: initial !important;
left: auto;
.loader-container {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
-webkit-box-flex-direction: row;
-moz-box-flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row;
height:100%;
}
.loader-item {
margin: auto;
max-height:100px;
max-width:300px;
}
.loader-text{
white-space: nowrap;
text-align: center;
position: relative;
}
</style>
</head>
<!-- 3. Display the application -->
@@ -46,9 +65,14 @@
<alfresco-app>
<div id="loader-container" class="loader-container">
<div class="loader-item">
<div id="loader-spin" class="mdl-progress mdl-js-progress mdl-progress__indeterminate"></div>
<div id="loader-spin" class="mdl-progress mdl-js-progress mdl-progress__indeterminate is-upgraded"
data-upgraded=",MaterialProgress">
<div class="progressbar bar bar1" style="width: 0%;"></div>
<div class="bufferbar bar bar2" style="width: 100%;"></div>
<div class="auxbar bar bar3" style="width: 0%;"></div>
</div>
<div id="loader-text" class="loader-text">Loading Demo Shell..</div>
</div >
</div>
</div>
</alfresco-app>
</body>
+19 -18
View File
@@ -1,11 +1,11 @@
{
"name": "Alfresco-Angular2-Demo",
"description": "Demo shell for Alfresco Angular2 components",
"version": "1.0.0",
"version": "1.1.0",
"author": "Alfresco Software, Ltd.",
"scripts": {
"clean": "npm install rimraf && npm run clean-build && rimraf dist node_modules typings dist",
"start": "npm run server-versions && webpack-dev-server --inline --progress --port 3000 --max_old_space_size=4096 --max_new_space_size=4096",
"start": "npm run server-versions && webpack-dev-server --progress --max_old_space_size=4096 --max_new_space_size=4096",
"start:dist": "wsrv -s dist/ -p 3000 -a 0.0.0.0",
"clean-build": "rimraf 'app/{,**/}**.js' 'app/{,**/}**.js.map' 'app/{,**/}**.d.ts'",
"test": "karma start",
@@ -62,6 +62,7 @@
"@angular/platform-browser-dynamic": "2.2.2",
"@angular/router": "3.2.2",
"@angular/upgrade": "2.2.2",
"@angular/material": "2.0.0-beta.1",
"systemjs": "0.19.27",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.8",
@@ -73,25 +74,25 @@
"pdfjs-dist": "1.5.404",
"flag-icon-css": "2.3.0",
"moment": "2.15.1",
"chart.js": "^2.1.4",
"chart.js": "2.3.0",
"ng2-charts": "1.1.0",
"raphael": "^2.2.6",
"md-date-time-picker": "^2.2.0",
"alfresco-js-api": "^1.0.0",
"ng2-activiti-analytics": "1.0.0",
"ng2-alfresco-core": "1.0.0",
"ng2-alfresco-datatable": "1.0.0",
"ng2-alfresco-documentlist": "1.0.0",
"ng2-alfresco-login": "1.0.0",
"ng2-alfresco-search": "1.0.0",
"ng2-alfresco-upload": "1.0.0",
"ng2-alfresco-viewer": "1.0.0",
"ng2-activiti-form": "1.0.0",
"ng2-activiti-tasklist": "1.0.0",
"ng2-alfresco-userinfo": "1.0.0",
"ng2-activiti-processlist": "1.0.0",
"ng2-alfresco-webscript": "1.0.0",
"ng2-alfresco-tag": "1.0.0",
"alfresco-js-api": "~1.1.0",
"ng2-activiti-analytics": "1.1.0",
"ng2-alfresco-core": "1.1.0",
"ng2-alfresco-datatable": "1.1.0",
"ng2-alfresco-documentlist": "1.1.0",
"ng2-alfresco-login": "1.1.0",
"ng2-alfresco-search": "1.1.0",
"ng2-alfresco-upload": "1.1.0",
"ng2-alfresco-viewer": "1.1.0",
"ng2-activiti-form": "1.1.0",
"ng2-activiti-tasklist": "1.1.0",
"ng2-alfresco-userinfo": "1.1.0",
"ng2-activiti-processlist": "1.1.0",
"ng2-alfresco-webscript": "1.1.0",
"ng2-alfresco-tag": "1.1.0",
"dialog-polyfill": "^0.4.3",
"element.scrollintoviewifneeded-polyfill": "^1.0.1"
},
+32 -9
View File
@@ -3,7 +3,6 @@ body, html {
height: 100%;
}
.p-10 {
padding: 10px;
}
@@ -13,24 +12,24 @@ body, html {
}
.loader-container {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
-webkit-box-flex-direction: row;
-moz-box-flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row;
height:100%;
height: 100%;
}
.loader-item {
margin: auto;
max-height:100px;
max-width:300px;
max-height: 100px;
max-width: 300px;
}
.loader-text{
.loader-text {
white-space: nowrap;
text-align: center;
position: relative;
@@ -39,3 +38,27 @@ body, html {
._dialog_overlay {
position: static !important;
}
.main_header_adf .mdl-layout__drawer-button {
right: 0 !important;
left: initial !important;
left: auto;
}
.mdl-layout__header {
color: rgb(255, 255, 255);
background-color: rgb(31, 188, 210);
}
.mdl-layout__header .material-icons {
color: rgb(255, 255, 255);
}
.mdl-layout__header-row .mdl-navigation__link {
color: rgb(255, 255, 255);
}
.md-simple-snackbar-action {
border: 0px;
cursor: pointer;
}
File diff suppressed because one or more lines are too long
@@ -69,6 +69,9 @@ Follow the 3 steps below:
<script src="node_modules/material-design-lite/material.min.js"></script>
<link rel="stylesheet" href="node_modules/material-design-icons/iconfont/material-icons.css">
<!-- Load the Angular Material 2 stylesheet -->
<link href="node_modules/@angular/material/core/theming/prebuilt/deeppurple-amber.css" rel="stylesheet">
<!-- Polyfill(s) for Safari (pre-10.x) -->
<script src="node_modules/intl/dist/Intl.min.js"></script>
<script src="node_modules/intl/locale-data/jsonp/en.js"></script>
@@ -39,6 +39,7 @@
"@angular/http": "2.2.2",
"@angular/platform-browser": "2.2.2",
"@angular/platform-browser-dynamic": "2.2.2",
"@angular/material": "2.0.0-beta.1",
"@angular/router": "3.2.2",
"@angular/upgrade": "2.2.2",
"core-js": "^2.4.1",
@@ -57,10 +58,10 @@
"moment": "2.15.1",
"raphael": "^2.2.6",
"ng2-translate": "2.5.0",
"alfresco-js-api": "^1.0.0",
"ng2-alfresco-core": "1.0.0",
"ng2-activiti-diagrams": "1.0.0",
"ng2-activiti-analytics": "^1.0.0"
"alfresco-js-api": "~1.1.0",
"ng2-alfresco-core": "1.1.0",
"ng2-activiti-diagrams": "1.1.0",
"ng2-activiti-analytics": "^1.1.0"
},
"devDependencies": {
"@types/jasmine": "^2.2.33",
@@ -18,51 +18,49 @@
import { NgModule, Component, OnInit } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { CoreModule, AlfrescoSettingsService, AlfrescoAuthenticationService, StorageService } from 'ng2-alfresco-core';
import { CoreModule, AlfrescoSettingsService, AlfrescoAuthenticationService, StorageService, LogService } from 'ng2-alfresco-core';
import { AnalyticsModule } from 'ng2-activiti-analytics';
@Component({
selector: 'alfresco-app-demo',
template: `
<label for="ticket"><b>Insert a valid ticket:</b></label><br>
<input id="ticket" type="text" size="48" (change)="updateTicket()" [(ngModel)]="ticket"><br>
<label for="host"><b>Insert the ip of your Activiti instance:</b></label><br>
<input id="host" type="text" size="48" (change)="updateHost()" [(ngModel)]="host"><br><br>
<div *ngIf="!authenticated" style="color:#FF2323">
Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid ticket to perform
operations.
</div>
<hr>
<label for="ticket"><b>Insert a valid ticket:</b></label><br>
<input id="ticket" type="text" size="48" (change)="updateTicket()" [(ngModel)]="ticket"><br>
<label for="host"><b>Insert the ip of your Activiti instance:</b></label><br>
<input id="host" type="text" size="48" (change)="updateHost()" [(ngModel)]="host"><br><br>
<div *ngIf="!authenticated" style="color:#FF2323">
Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid ticket to perform
operations.
</div>
<hr>
<div class="page-content">
<label for="appId"><b>Insert the appId:</b></label><br>
<input id="appId" size="10" type="text" [(ngModel)]="appId">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col task-column mdl-shadow--2dp">
<analytics-report-list (reportClick)="onReportClick($event)"></analytics-report-list>
</div>
<div class="mdl-cell mdl-cell--8-col task-column mdl-shadow--2dp">
<activiti-analytics [appId]="appId" *ngIf="report" [reportId]="report.id"></activiti-analytics>
<div class="page-content">
<label for="appId"><b>Insert the appId:</b></label><br>
<input id="appId" size="10" type="text" [(ngModel)]="appId">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col task-column mdl-shadow--2dp">
<analytics-report-list (reportClick)="onReportClick($event)"></analytics-report-list>
</div>
<div class="mdl-cell mdl-cell--8-col task-column mdl-shadow--2dp">
<activiti-analytics [appId]="appId" *ngIf="report" [reportId]="report.id"></activiti-analytics>
</div>
</div>
</div>
</div>`
`
})
export class AnalyticsDemoComponent implements OnInit {
appId: number;
report: any;
authenticated: boolean;
host: string = 'http://localhost:9999';
ticket: string;
constructor(private authService: AlfrescoAuthenticationService,
private settingsService: AlfrescoSettingsService,
private storage: StorageService) {
private storage: StorageService,
private logService: LogService) {
settingsService.bpmHost = this.host;
settingsService.setProviders('BPM');
@@ -91,12 +89,12 @@ export class AnalyticsDemoComponent implements OnInit {
login() {
this.authService.login('admin', 'admin').subscribe(
ticket => {
console.log(ticket);
this.logService.log(ticket);
this.ticket = this.authService.getTicketBpm();
this.authenticated = true;
},
error => {
console.log(error);
this.logService.error(error);
this.authenticated = false;
});
}
@@ -22,6 +22,7 @@ import { DiagramsModule } from 'ng2-activiti-diagrams';
import { AnalyticsReportListComponent } from './src/components/analytics-report-list.component';
import { AnalyticsReportParametersComponent } from './src/components/analytics-report-parameters.component';
import { AnalyticsComponent } from './src/components/analytics.component';
import { AnalyticsGeneratorComponent } from './src/components/analytics-generator.component';
import { AnalyticsReportHeatMapComponent } from './src/components/analytics-report-heat-map.component';
import { AnalyticsService } from './src/services/analytics.service';
import { CHART_DIRECTIVES } from 'ng2-charts/ng2-charts';
@@ -29,6 +30,7 @@ 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-generator.component';
export * from './src/components/analytics-report-list.component';
export * from './src/components/analytics-report-parameters.component';
export * from './src/services/analytics.service';
@@ -38,6 +40,7 @@ export const ANALYTICS_DIRECTIVES: any[] = [
AnalyticsComponent,
AnalyticsReportListComponent,
AnalyticsReportParametersComponent,
AnalyticsGeneratorComponent,
AnalyticsReportHeatMapComponent,
WIDGET_DIRECTIVES
];
@@ -1,7 +1,14 @@
// Tun on full stack traces in errors to help debugging
Error.stackTraceLimit = Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
window.componentHandler = {
upgradeAllRegistered: function () {
},
upgradeElement: function () {
}
};
__karma__.loaded = function() {};
@@ -39,6 +46,8 @@ var map = {
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/material': 'npm:@angular/material/bundles/material.umd.js',
// testing
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
@@ -1,13 +1,13 @@
{
"name": "ng2-activiti-analytics",
"description": "Activiti Angular2 Analytics Component",
"version": "1.0.0",
"version": "1.1.0",
"author": "Alfresco Software, Ltd.",
"scripts": {
"clean": "npm install rimraf && npm run clean-build && rimraf dist node_modules typings",
"clean-build": "rimraf index.js index.js.map index.d.ts'src/{,**/}**.js' 'src/{,**/}**.js.map' 'src/{,**/}**.d.ts' bundles",
"build": "npm run clean-build && npm run tslint && rimraf dist && tsc && license-check && npm run build.umd",
"build:w": "npm run clean-build && npm run tslint && rimraf dist && tsc:w && license-check npm run build.umd",
"build:w": "npm run clean-build && npm run tslint && rimraf dist && npm run tsc:w && license-check && npm run build.umd",
"tslint": "tslint -c tslint.json 'src/{,**/}**.ts' 'index.ts' -e '{,**/}**.d.ts' -e './gulpfile.ts'",
"tsc": "tsc",
"tsc:w": "tsc -w",
@@ -16,7 +16,7 @@
"test-browser": "npm run build && concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"",
"posttest": "remap-istanbul -i coverage/report/coverage-final.json -o coverage/report -t html && remap-istanbul -i coverage/report/coverage-final.json -o coverage/report/coverage-final.json",
"coverage": "npm run test && wsrv -o -p 9875 ./coverage/report",
"prepublish": "npm run build",
"prepublish": "npm run test",
"travis": "npm link ng2-alfresco-core ng2-activiti-diagrams",
"gulp": "gulp",
"build.umd": "gulp build.prod --color --env-config prod --build-type prod",
@@ -51,24 +51,26 @@
"@angular/http": "2.0.0",
"@angular/platform-browser": "2.0.0",
"@angular/platform-browser-dynamic": "2.0.0",
"@angular/material": "2.0.0-beta.1",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.12",
"systemjs": "0.19.27",
"zone.js": "^0.6.23",
"chart.js": "^2.1.4",
"chart.js": "2.3.0",
"md-date-time-picker": "^2.2.0",
"ng2-charts": "1.1.0",
"moment": "2.15.1",
"raphael": "^2.2.6",
"alfresco-js-api": "^1.0.0",
"alfresco-js-api": "~1.1.0",
"ng2-translate": "2.5.0",
"ng2-alfresco-core": "1.0.0",
"ng2-activiti-diagrams": "1.0.0"
"ng2-alfresco-core": "1.1.0",
"ng2-activiti-diagrams": "1.1.0"
},
"devDependencies": {
"@types/jasmine": "^2.2.33",
"@types/node": "^6.0.42",
"autoprefixer": "^6.5.4",
"concurrently": "^2.2.0",
"cpx": "1.3.1",
"cssnano": "^3.8.1",
@@ -87,6 +89,7 @@
"gulp-template": "^4.0.0",
"gulp-typescript": "^3.1.3",
"gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.7",
"intl": "^1.2.5",
"jasmine-core": "2.4.1",
"karma": "0.13.22",
@@ -97,6 +100,7 @@
"karma-jasmine-html-reporter": "0.2.0",
"karma-mocha-reporter": "2.0.3",
"license-check": "1.1.5",
"merge-stream": "^1.0.1",
"remap-istanbul": "0.6.3",
"rimraf": "2.5.2",
"run-sequence": "^1.2.2",
@@ -0,0 +1,5 @@
.chart {display: block; width: 100%;}
.analytics-row__entry {
cursor: pointer;
}
@@ -0,0 +1,92 @@
<div *ngIf="reports">
<div *ngFor="let report of reports">
<h4>{{report.title}}</h4>
<div [ngSwitch]="report.type">
<div *ngSwitchCase="'pie'">
<div class="col-md-6">
<div *ngIf="!report.hasData()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<div *ngIf="report.hasData()">
<div *ngIf="report.hasZeroValues()">{{'ANALYTICS.MESSAGES.ZERO-DATA-FOUND' | translate}}</div>
<base-chart *ngIf="!report.hasZeroValues()" class="chart"
[data]="report.data"
[labels]="report.labels"
[chartType]="report.type"></base-chart>
</div>
</div>
</div>
<div *ngSwitchCase="'table'">
<div *ngIf="!report.hasDatasets()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<div [attr.id]="'chart-table-' + report.id" *ngIf="report.hasDatasets()">
<table class="table table-responsive table-condensed" style="width: 100%">
<tr>
<th *ngFor="let label of report.labels">{{label | translate}}</th>
</tr>
<tr *ngFor="let rows of report.datasets" style="text-align: center;">
<td *ngFor="let row of rows">{{row | translate }}</td>
</tr>
</table>
</div>
</div>
<div *ngSwitchCase="'masterDetailTable'">
<div *ngIf="!report.hasDatasets()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<div [attr.id]="'chart-master-detail-table-' + report.id" *ngIf="report.hasDatasets()">
<table class="table table-responsive table-condensed" style="width: 100%">
<tr>
<th *ngFor="let label of report.labels">{{label | translate}}</th>
</tr>
<tr *ngFor="let rows of report.datasets" class="analytics-row__entry" style="text-align: center;">
<td *ngFor="let row of rows" (click)="toggleDetailsTable()">{{row | translate }}</td>
</tr>
</table>
</div>
<div [attr.id]="'chart-master-detail-' + report.id" *ngIf="isShowDetails()">
<table class="table table-responsive table-condensed" style="width: 100%">
<tr>
<th *ngFor="let label of report.detailsTable.labels">{{label | translate}}</th>
</tr>
<tr *ngFor="let rows of report.detailsTable.datasets" style="text-align: center;">
<td *ngFor="let row of rows">{{row | translate }}</td>
</tr>
</table>
</div>
</div>
<div *ngSwitchCase="'bar'">
<div class="col-md-6">
<div *ngIf="!report.hasDatasets()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<base-chart *ngIf="report.hasDatasets()" class="chart"
[datasets]="report.datasets"
[labels]="report.labels"
[options]="report.options"
[chartType]="report.type"></base-chart>
</div>
</div>
<div *ngSwitchCase="'multiBar'">
<div class="col-md-6">
<div *ngIf="!report.hasDatasets()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<div *ngIf="report.hasDatasets()">
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" [attr.for]="'stacked-id'">
<input type="checkbox" [attr.id]="'stacked-id'" class="mdl-checkbox__input"
[checked]="report.options.scales.xAxes[0].stacked"
[(ngModel)]="report.options.scales.xAxes[0].stacked"
(change)="refresh(report)">
<span class="mdl-checkbox__label">Stacked</span>
</label>
<base-chart class="chart"
[datasets]="report.datasets"
[labels]="report.labels"
[options]="report.options"
[chartType]="'bar'"></base-chart>
</div>
</div>
</div>
<div *ngSwitchCase="'HeatMap'">
<analytics-report-heat-map [report]="report"></analytics-report-heat-map>
</div>
<div *ngSwitchDefault>
<span>{{'ANALYTICS.MESSAGES.UNKNOWN-WIDGET-TYPE' | translate}}: {{report.type}}</span>
</div>
</div>
</div>
</div>
<br><br><br>
<div *ngIf="!reports">{{'ANALYTICS.MESSAGES.FILL-PARAMETER' | translate}}</div>
@@ -0,0 +1,230 @@
/*!
* @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 { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { CHART_DIRECTIVES } from 'ng2-charts/ng2-charts';
import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core';
import { DiagramsModule } from 'ng2-activiti-diagrams';
import { AnalyticsReportListComponent } from '../components/analytics-report-list.component';
import { AnalyticsGeneratorComponent } from '../components/analytics-generator.component';
import { AnalyticsReportParametersComponent } from '../components/analytics-report-parameters.component';
import { AnalyticsReportHeatMapComponent } from '../components/analytics-report-heat-map.component';
import { WIDGET_DIRECTIVES } from '../components/widgets/index';
import { Chart } from '../models/chart.model';
import { AnalyticsService } from '../services/analytics.service';
import { ReportQuery } from '../models/report.model';
import * as analyticMock from '../assets/analyticsComponent.mock';
export const ANALYTICS_DIRECTIVES: any[] = [
AnalyticsGeneratorComponent,
AnalyticsReportParametersComponent,
AnalyticsReportListComponent,
AnalyticsReportHeatMapComponent,
WIDGET_DIRECTIVES
];
export const ANALYTICS_PROVIDERS: any[] = [
AnalyticsService
];
declare let jasmine: any;
declare let mdDateTimePicker: any;
describe('AnalyticsGeneratorComponent', () => {
let component: any;
let fixture: ComponentFixture<AnalyticsGeneratorComponent>;
let debug: DebugElement;
let element: HTMLElement;
let componentHandler: any;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule.forRoot(),
DiagramsModule.forRoot()
],
declarations: [
...ANALYTICS_DIRECTIVES,
...CHART_DIRECTIVES
],
providers: [
...ANALYTICS_PROVIDERS
]
}).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); });
}));
beforeEach(() => {
fixture = TestBed.createComponent(AnalyticsGeneratorComponent);
component = fixture.componentInstance;
debug = fixture.debugElement;
element = fixture.nativeElement;
fixture.detectChanges();
componentHandler = jasmine.createSpyObj('componentHandler', [
'upgradeAllRegistered'
]);
window['componentHandler'] = componentHandler;
});
describe('Rendering tests', () => {
beforeEach(() => {
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('Should render the Process definition overview report ', (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();
});
let reportId = 1001;
let reportParamQuery = new ReportQuery({status: 'All'});
component.generateReport(reportId, reportParamQuery);
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();
expect(res.length).toEqual(3);
expect(res[0]).toBeDefined();
expect(res[0].type).toEqual('bar');
expect(res[0].labels).toBeDefined();
expect(res[0].labels.length).toEqual(2);
expect(res[0].labels[0]).toEqual('2016-09-30T00:00:00.000+0000');
expect(res[0].labels[1]).toEqual('2016-10-04T00:00:00.000+0000');
expect(res[0].datasets[0].label).toEqual('series1');
expect(res[0].datasets[0].data[0]).toEqual(3);
expect(res[0].datasets[0].data[1]).toEqual(1);
expect(res[1]).toBeDefined();
expect(res[1].type).toEqual('masterDetailTable');
expect(res[1].datasets).toBeDefined();
expect(res[1].datasets.length).toEqual(2);
expect(res[1].datasets[0][0]).toEqual('fake 1 user task');
expect(res[1].datasets[0][1]).toEqual('1');
expect(res[1].datasets[0][2]).toEqual('2.0');
expect(res[1].datasets[0][3]).toEqual('3.0');
expect(res[1].datasets[0][4]).toEqual('4.0');
expect(res[1].datasets[0][5]).toEqual('5.0');
expect(res[1].datasets[0][6]).toEqual('6.0');
expect(res[1].datasets[1][0]).toEqual('fake 2 user task');
expect(res[1].datasets[1][1]).toEqual('1');
expect(res[1].datasets[1][2]).toEqual('2.0');
expect(res[1].datasets[1][3]).toEqual('3.0');
expect(res[1].datasets[1][4]).toEqual('4.0');
expect(res[1].datasets[1][5]).toEqual('5.0');
expect(res[1].datasets[1][6]).toEqual('6.0');
expect(res[2]).toBeDefined();
expect(res[2].type).toEqual('multiBar');
expect(res[2].labels).toBeDefined();
expect(res[2].labels.length).toEqual(3);
expect(res[2].labels[0]).toEqual(1);
expect(res[2].labels[1]).toEqual(2);
expect(res[2].labels[2]).toEqual(3);
expect(res[2].datasets[0].label).toEqual('averages');
expect(res[2].datasets[0].data[0]).toEqual(0);
expect(res[2].datasets[0].data[1]).toEqual(5);
expect(res[2].datasets[0].data[2]).toEqual(2);
expect(res[2].datasets[1].label).toEqual('minima');
expect(res[2].datasets[1].data[0]).toEqual(0);
expect(res[2].datasets[1].data[1]).toEqual(0);
expect(res[2].datasets[1].data[2]).toEqual(0);
expect(res[2].datasets[2].label).toEqual('maxima');
expect(res[2].datasets[2].data[0]).toEqual(0);
expect(res[2].datasets[2].data[1]).toEqual(29);
expect(res[2].datasets[2].data[2]).toEqual(29);
done();
});
let reportParamQuery = new ReportQuery({status: 'All'});
component.reportId = 1;
component.generateReport(reportParamQuery);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: analyticMock.chartTaskOverview
});
});
it('Should reset the reports when the onChanged is call', () => {
component.reports = [ new Chart({id: 'fake', type: 'fake-type'})];
component.reportId = 1;
component.ngOnChanges();
expect(component.reports).toBeUndefined();
});
it('Should emit onError event with a 404 response ', (done) => {
component.onError.subscribe((err) => {
expect(err).toBeDefined();
done();
});
let reportParamQuery = new ReportQuery({status: 'All'});
component.reportId = 1;
component.generateReport(reportParamQuery);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 404,
contentType: 'json',
responseText: []
});
});
});
});
@@ -0,0 +1,119 @@
/*!
* @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, OnChanges, Input, Output, SimpleChanges } from '@angular/core';
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
import { AnalyticsService } from '../services/analytics.service';
import { ReportQuery } from '../models/report.model';
import { Chart } from '../models/chart.model';
@Component({
moduleId: module.id,
selector: 'activiti-analytics-generator',
templateUrl: './analytics-generator.component.html',
styleUrls: ['./analytics-generator.component.css']
})
export class AnalyticsGeneratorComponent implements OnChanges {
@Input()
reportId: number;
@Input()
reportParamQuery: ReportQuery = undefined;
@Output()
onSuccess = new EventEmitter();
@Output()
onError = new EventEmitter();
reports: Chart[];
showDetails: boolean = false;
public barChartOptions: any = {
responsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}],
xAxes: [{
ticks: {
},
stacked: true
}]
}
};
constructor(private translateService: AlfrescoTranslationService,
private analyticsService: AnalyticsService,
private logService: LogService) {
logService.info('AnalyticsGeneratorComponent');
if (translateService) {
translateService.addTranslationFolder('ng2-activiti-analytics', 'node_modules/ng2-activiti-analytics/src');
}
}
ngOnChanges(changes: SimpleChanges) {
if (this.reportId && this.reportParamQuery) {
this.generateReport(this.reportId, this.reportParamQuery);
} else {
this.reset();
}
}
public generateReport(reportId, reportParamQuery) {
this.analyticsService.getReportsByParams(reportId, reportParamQuery).subscribe(
(res: Chart[]) => {
this.reports = res;
this.onSuccess.emit(res);
},
(err: any) => {
this.onError.emit(err);
this.logService.error(err);
}
);
}
public reset() {
if (this.reports) {
this.reports = undefined;
}
}
public refresh(report): void {
/**
* (My guess), for Angular to recognize the change in the dataset
* it has to change the dataset variable directly,
* so one way around it, is to clone the data, change it and then
* assign it;
*/
let clone = JSON.parse(JSON.stringify(report));
report.datasets = clone.datasets;
}
toggleDetailsTable() {
this.showDetails = !this.showDetails;
}
isShowDetails(): boolean {
return this.showDetails;
}
}
@@ -15,17 +15,18 @@
* limitations under the License.
*/
import { DebugElement } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { CoreModule } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core';
import { DiagramsModule } from 'ng2-activiti-diagrams';
import { AnalyticsReportHeatMapComponent } from '../components/analytics-report-heat-map.component';
import { WIDGET_DIRECTIVES } from '../components/widgets/index';
import { AnalyticsService } from '../services/analytics.service';
import { DebugElement } from '@angular/core';
declare let jasmine: any;
describe('Test ng2-activiti-analytics-report-heat-map', () => {
describe('AnalyticsReportHeatMapComponent', () => {
let componentHandler: any;
let component: any;
@@ -44,8 +45,8 @@ describe('Test ng2-activiti-analytics-report-heat-map', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule,
DiagramsModule
CoreModule.forRoot(),
DiagramsModule.forRoot()
],
declarations: [
AnalyticsReportHeatMapComponent,
@@ -55,6 +56,11 @@ describe('Test ng2-activiti-analytics-report-heat-map', () => {
AnalyticsService
]
}).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); });
}));
beforeEach(() => {
@@ -43,11 +43,11 @@ export class AnalyticsReportHeatMapComponent implements OnInit {
currentMetricColors: string;
metricType: string;
constructor(private translate: AlfrescoTranslationService,
constructor(private translateService: AlfrescoTranslationService,
private analyticsService: AnalyticsService,
private formBuilder: FormBuilder) {
if (translate) {
translate.addTranslationFolder('ng2-activiti-analytics', 'node_modules/ng2-activiti-analytics/src');
if (translateService) {
translateService.addTranslationFolder('ng2-activiti-analytics', 'node_modules/ng2-activiti-analytics/src');
}
}
@@ -15,15 +15,16 @@
* limitations under the License.
*/
import { DebugElement } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { CoreModule } from 'ng2-alfresco-core';
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 { DebugElement } from '@angular/core';
declare let jasmine: any;
describe('Test ng2-activiti-analytics Report list', () => {
describe('AnalyticsReportListComponent', () => {
let reportList = [
{'id': 2002, 'name': 'Fake Test Process definition heat map'},
@@ -35,7 +36,7 @@ describe('Test ng2-activiti-analytics Report list', () => {
let reportSelected = {'id': 2003, 'name': 'Fake Test Process definition overview'};
let component: any;
let component: AnalyticsReportListComponent;
let fixture: ComponentFixture<AnalyticsReportListComponent>;
let debug: DebugElement;
let element: HTMLElement;
@@ -43,7 +44,7 @@ describe('Test ng2-activiti-analytics Report list', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule
CoreModule.forRoot()
],
declarations: [
AnalyticsReportListComponent
@@ -52,6 +53,10 @@ describe('Test ng2-activiti-analytics Report list', () => {
AnalyticsService
]
}).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); });
}));
beforeEach(() => {
@@ -16,11 +16,10 @@
*/
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { Observer, Observable } from 'rxjs/Rx';
import { LogService } from 'ng2-alfresco-core';
import { AnalyticsService } from '../services/analytics.service';
import { ReportParametersModel } from '../models/report.model';
import { Observer } from 'rxjs/Observer';
import { Observable } from 'rxjs/Observable';
@Component({
moduleId: module.id,
@@ -46,9 +45,8 @@ export class AnalyticsReportListComponent implements OnInit {
reports: ReportParametersModel[] = [];
constructor(private auth: AlfrescoAuthenticationService,
private analyticsService: AnalyticsService) {
constructor(private analyticsService: AnalyticsService,
private logService: LogService) {
this.report$ = new Observable<ReportParametersModel>(observer => this.reportObserver = observer).share();
}
@@ -85,7 +83,7 @@ export class AnalyticsReportListComponent implements OnInit {
},
(err: any) => {
this.onError.emit(err);
console.log(err);
this.logService.error(err);
}
);
}
@@ -48,3 +48,18 @@
.icon-small:hover .material-icons {
display: block;
}
.is-hide {
height: 0px;
overflow: hidden;
transition: height 0.5s;
}
.report-container {
border: solid 1px rgb(212, 212, 212);
padding: 10px 10px 10px 10px;
}
.report-container-setting {
padding-left: 10px;
}
@@ -1,75 +1,83 @@
<div class="col-md-6">
<div *ngIf="reportParameters">
<form [formGroup]="reportForm" novalidate>
<div *ngIf="isEditable">
<input
type="text"
class="mdl-textfield__input large"
id="reportName"
autofocus
data-automation-id="reportName"
[value]="reportParameters.name"
(input)="reportParameters.name=$event.target.value"
(blur)="editTitle($event)"
/>
</div>
<div *ngIf="!isEditable">
<span class="icon-small">
<i class="material-icons">mode_edit</i>
<h4 (click)="editEnable()">{{reportParameters.name}}</h4>
</span>
</div><hr>
<div *ngFor="let field of reportParameters.definition.parameters">
<div [ngSwitch]="field.type">
<div *ngSwitchCase="'integer'">
<br>
<number-widget [field]="field" [group]="reportForm.controls.processInstanceGroup" [controllerName]="'slowProcessInstanceInteger'"
[required]="true"></number-widget>
</div>
<div *ngSwitchCase="'duration'">
<br>
<duration-widget [field]="field" [group]="reportForm.controls.durationGroup"
[controllerName]="'duration'"></duration-widget>
</div>
<div *ngSwitchCase="'boolean'">
<br>
<checkbox-widget [field]="field" [group]="reportForm.controls.typeFilteringGroup"
[controllerName]="'typeFiltering'"></checkbox-widget>
</div>
<div *ngSwitchCase="'status'">
<br>
<dropdown-widget [field]="field" [group]="reportForm.controls.statusGroup" [controllerName]="'status'"
[required]="true"></dropdown-widget>
</div>
<div *ngSwitchCase="'processDefinition'">
<br>
<dropdown-widget [field]="field" [group]="reportForm.controls.processDefGroup" [controllerName]="'processDefinitionId'"
[required]="true" (fieldChanged)="onProcessDefinitionChanges(field)"></dropdown-widget>
</div>
<div *ngSwitchCase="'task'">
<br>
<dropdown-widget [field]="field" [group]="reportForm.controls.taskGroup" [controllerName]="'taskName'"
[required]="true"></dropdown-widget>
</div>
<div *ngSwitchCase="'dateRange'">
<br>
<date-range-widget [field]="field" [group]="reportForm.controls.dateRange"></date-range-widget>
</div>
<div *ngSwitchCase="'dateInterval'">
<br>
<dropdown-widget [field]="field" [group]="reportForm.controls.dateIntervalGroup" [controllerName]="'dateRangeInterval'"
[required]="true" [showDefaultOption]="false"></dropdown-widget>
</div>
<div *ngSwitchDefault>
<span>{{'ANALYTICS.MESSAGES.UNKNOWN-WIDGET-TYPE' | translate}}: {{field.type}}</span>
<div class="report-container">
<a class="mdl-navigation__link setting-button" data-automation-id="settings">
<button (click)="toggleParameters()" class="mdl-button mdl-js-button mdl-button--fab mdl-button--colored">
<i class="material-icons">settings</i>
</button>
<span class="report-container-setting">{{'ANALYTICS.MESSAGES.SETTING-TITLE' | translate}}</span>
</a>
<div class="col-md-6" [class.is-hide]="isParametersHide()" >
<div *ngIf="reportParameters">
<form [formGroup]="reportForm" novalidate>
<div *ngIf="isEditable">
<input
type="text"
class="mdl-textfield__input large"
id="reportName"
autofocus
data-automation-id="reportName"
[value]="reportParameters.name"
(input)="reportParameters.name=$event.target.value"
(blur)="editTitle($event)"
/>
</div>
<div *ngIf="!isEditable">
<span class="icon-small">
<i class="material-icons">mode_edit</i>
<h4 (click)="editEnable()">{{reportParameters.name}}</h4>
</span>
</div><hr>
<div *ngFor="let field of reportParameters.definition.parameters">
<div [ngSwitch]="field.type">
<div *ngSwitchCase="'integer'">
<br>
<number-widget [field]="field" [group]="reportForm.controls.processInstanceGroup" [controllerName]="'slowProcessInstanceInteger'"
[required]="true"></number-widget>
</div>
<div *ngSwitchCase="'duration'">
<br>
<duration-widget [field]="field" [group]="reportForm.controls.durationGroup"
[controllerName]="'duration'"></duration-widget>
</div>
<div *ngSwitchCase="'boolean'">
<br>
<checkbox-widget [field]="field" [group]="reportForm.controls.typeFilteringGroup"
[controllerName]="'typeFiltering'"></checkbox-widget>
</div>
<div *ngSwitchCase="'status'">
<br>
<dropdown-widget [field]="field" [group]="reportForm.controls.statusGroup" [controllerName]="'status'"
[required]="true"></dropdown-widget>
</div>
<div *ngSwitchCase="'processDefinition'">
<br>
<dropdown-widget [field]="field" [group]="reportForm.controls.processDefGroup" [controllerName]="'processDefinitionId'"
[required]="true" (fieldChanged)="onProcessDefinitionChanges(field)"></dropdown-widget>
</div>
<div *ngSwitchCase="'task'">
<br>
<dropdown-widget [field]="field" [group]="reportForm.controls.taskGroup" [controllerName]="'taskName'"
[required]="true"></dropdown-widget>
</div>
<div *ngSwitchCase="'dateRange'">
<br>
<date-range-widget [field]="field" [group]="reportForm.controls.dateRange"></date-range-widget>
</div>
<div *ngSwitchCase="'dateInterval'">
<br>
<dropdown-widget [field]="field" [group]="reportForm.controls.dateIntervalGroup" [controllerName]="'dateRangeInterval'"
[required]="true" [showDefaultOption]="false"></dropdown-widget>
</div>
<div *ngSwitchDefault>
<span>{{'ANALYTICS.MESSAGES.UNKNOWN-WIDGET-TYPE' | translate}}: {{field.type}}</span>
</div>
</div>
</div>
<div *ngIf="debug">
<p>ReportForm valid : {{ reportForm.valid }}</p>
<p>ReportForm status : {{ reportForm.errors | json }}</p>
<p>ReportForm FormGroup valid : {{reportForm && reportForm.controls.dateRange.valid | json }}</p>
</div>
</form>
</div>
<div *ngIf="debug">
<p>ReportForm valid : {{ reportForm.valid }}</p>
<p>ReportForm status : {{ reportForm.errors | json }}</p>
<p>ReportForm FormGroup valid : {{reportForm && reportForm.controls.dateRange.valid | json }}</p>
</div>
</form>
</div>
</div>
@@ -16,25 +16,23 @@
*/
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import {
CoreModule
} from 'ng2-alfresco-core';
import { DebugElement, SimpleChange } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import * as moment from 'moment';
import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core';
import { AnalyticsReportParametersComponent } from '../components/analytics-report-parameters.component';
import { WIDGET_DIRECTIVES } from '../components/widgets/index';
import { AnalyticsService } from '../services/analytics.service';
import { ReportParametersModel } from '../models/report.model';
import * as moment from 'moment';
import { DebugElement, SimpleChange } from '@angular/core';
import * as analyticParamsMock from '../assets/analyticsParamsReportComponent.mock';
declare let jasmine: any;
declare let mdDateTimePicker: any;
describe('Test ng2-analytics-report-parameters Report Parameters ', () => {
describe('AnalyticsReportParametersComponent', () => {
let component: any;
let component: AnalyticsReportParametersComponent;
let fixture: ComponentFixture<AnalyticsReportParametersComponent>;
let debug: DebugElement;
let element: HTMLElement;
@@ -44,7 +42,7 @@ describe('Test ng2-analytics-report-parameters Report Parameters ', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule
CoreModule.forRoot()
],
declarations: [
AnalyticsReportParametersComponent,
@@ -54,6 +52,15 @@ describe('Test ng2-analytics-report-parameters Report Parameters ', () => {
AnalyticsService
]
}).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); });
componentHandler = jasmine.createSpyObj('componentHandler', [
'upgradeAllRegistered'
]);
window['componentHandler'] = componentHandler;
}));
beforeEach(() => {
@@ -62,10 +69,6 @@ describe('Test ng2-analytics-report-parameters Report Parameters ', () => {
debug = fixture.debugElement;
element = fixture.nativeElement;
fixture.detectChanges();
componentHandler = jasmine.createSpyObj('componentHandler', [
'upgradeAllRegistered'
]);
window['componentHandler'] = componentHandler;
});
describe('Rendering tests', () => {
@@ -323,9 +326,9 @@ describe('Test ng2-analytics-report-parameters Report Parameters ', () => {
responseText: analyticParamsMock.reportDefParamProcessDefOptionsApp
});
let appId = 1;
let appId = '1';
component.appId = appId;
component.reportId = 1;
component.reportId = '1';
let change = new SimpleChange(null, appId);
component.ngOnChanges({ 'appId': change });
@@ -341,7 +344,7 @@ describe('Test ng2-analytics-report-parameters Report Parameters ', () => {
expect(res[1].name).toEqual('Fake task name 2');
});
component.reportId = 100;
component.reportId = '100';
component.reportParameters = new ReportParametersModel(analyticParamsMock.reportDefParamTask);
component.onProcessDefinitionChanges(analyticParamsMock.fieldProcessDef);
@@ -392,10 +395,10 @@ describe('Test ng2-analytics-report-parameters Report Parameters ', () => {
responseText: []
});
});
});
it('Should convert a string in number', () => {
let numberConvert = component.convertNumber('2');
expect(numberConvert).toEqual(2);
it('Should convert a string in number', () => {
let numberConvert = component.convertNumber('2');
expect(numberConvert).toEqual(2);
});
});
});
@@ -15,12 +15,29 @@
* limitations under the License.
*/
import { Component, EventEmitter, OnInit, OnChanges, Input, Output, SimpleChanges } from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { AnalyticsService } from '../services/analytics.service';
import { ReportParametersModel, ReportQuery, ParameterValueModel, ReportParameterDetailsModel } from '../models/report.model';
import {
Component,
EventEmitter,
OnInit,
OnChanges,
Input,
Output,
SimpleChanges,
OnDestroy,
AfterViewChecked
} from '@angular/core';
import { FormGroup, FormBuilder, FormControl } from '@angular/forms';
import * as moment from 'moment';
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
import { AnalyticsService } from '../services/analytics.service';
import {
ReportParametersModel,
ReportQuery,
ParameterValueModel,
ReportParameterDetailsModel
} from '../models/report.model';
declare var componentHandler;
@Component({
moduleId: module.id,
@@ -28,7 +45,7 @@ import * as moment from 'moment';
templateUrl: './analytics-report-parameters.component.html',
styleUrls: ['./analytics-report-parameters.component.css']
})
export class AnalyticsReportParametersComponent implements OnInit, OnChanges {
export class AnalyticsReportParametersComponent implements OnInit, OnChanges, OnDestroy, AfterViewChecked {
public static FORMAT_DATE_ACTIVITI: string = 'YYYY-MM-DD';
@@ -67,12 +84,14 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges {
private reportParamsSub;
private paramOpts;
private isEditable: boolean = false;
private hideParameters: boolean = true;
constructor(private translate: AlfrescoTranslationService,
constructor(private translateService: AlfrescoTranslationService,
private analyticsService: AnalyticsService,
private formBuilder: FormBuilder ) {
if (translate) {
translate.addTranslationFolder('ng2-activiti-analytics', 'node_modules/ng2-activiti-analytics/src');
private formBuilder: FormBuilder,
private logService: LogService) {
if (translateService) {
translateService.addTranslationFolder('ng2-activiti-analytics', 'node_modules/ng2-activiti-analytics/src');
}
}
@@ -146,7 +165,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges {
}
},
(err: any) => {
console.log(err);
this.logService.error(err);
this.onError.emit(err);
}
);
@@ -160,7 +179,7 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges {
this.onSuccessParamOpt.emit(opts);
},
(err: any) => {
console.log(err);
this.logService.error(err);
this.onError.emit(err);
}
);
@@ -231,9 +250,24 @@ export class AnalyticsReportParametersComponent implements OnInit, OnChanges {
this.onEdit.emit(this.reportParameters.name);
},
(err: any) => {
console.log(err);
this.logService.error(err);
this.onError.emit(err);
}
);
}
ngAfterViewChecked() {
// workaround for MDL issues with dynamic components
if (componentHandler) {
componentHandler.upgradeAllRegistered();
}
}
toggleParameters() {
this.hideParameters = !this.hideParameters;
}
isParametersHide() {
return this.hideParameters;
}
}
@@ -1,25 +1 @@
.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;
}
@@ -5,83 +5,8 @@
(onEdit)="onEditReport($event)">
</analytics-report-parameters>
<div *ngIf="reports">
<div *ngFor="let report of reports">
<h4>{{report.title}}</h4>
<div [ngSwitch]="report.type">
<div *ngSwitchCase="'pie'">
<div class="col-md-6">
<div *ngIf="!report.hasData()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<base-chart *ngIf="report.hasData()" class="chart"
[data]="report.data"
[labels]="report.labels"
[chartType]="report.type"></base-chart>
</div>
</div>
<div *ngSwitchCase="'table'">
<div *ngIf="!report.hasDatasets()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<div [attr.id]="'chart-table-' + report.id" *ngIf="report.hasDatasets()">
<table class="table table-responsive table-condensed" style="width: 100%">
<tr>
<th *ngFor="let label of report.labels">{{label | translate}}</th>
</tr>
<tr *ngFor="let rows of report.datasets" style="text-align: center;">
<td *ngFor="let row of rows">{{row | translate }}</td>
</tr>
</table>
</div>
</div>
<div *ngSwitchCase="'masterDetailTable'">
<div *ngIf="!report.hasDatasets()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<div [attr.id]="'chart-master-detail-table-' + report.id" *ngIf="report.hasDatasets()">
<table class="table table-responsive table-condensed" style="width: 100%">
<tr>
<th *ngFor="let label of report.labels">{{label | translate}}</th>
</tr>
<tr *ngFor="let rows of report.datasets" style="text-align: center;">
<td *ngFor="let row of rows">{{row | translate }}</td>
</tr>
</table>
</div>
</div>
<div *ngSwitchCase="'bar'">
<div class="col-md-6">
<div *ngIf="!report.hasDatasets()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<base-chart *ngIf="report.hasDatasets()" class="chart"
[datasets]="report.datasets"
[labels]="report.labels"
[options]="report.options"
[chartType]="report.type"></base-chart>
</div>
</div>
<div *ngSwitchCase="'multiBar'">
<div class="col-md-6">
<div *ngIf="!report.hasDatasets()">{{'ANALYTICS.MESSAGES.NO-DATA-FOUND' | translate}}</div>
<div *ngIf="report.hasDatasets()">
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" [attr.for]="'stacked-id'">
<input type="checkbox" [attr.id]="'stacked-id'" class="mdl-checkbox__input"
[checked]="report.options.scales.xAxes[0].stacked"
[(ngModel)]="report.options.scales.xAxes[0].stacked"
(change)="refresh(report)">
<span class="mdl-checkbox__label">Stacked</span>
</label>
<base-chart class="chart"
[datasets]="report.datasets"
[labels]="report.labels"
[options]="report.options"
[chartType]="'bar'"></base-chart>
</div>
</div>
</div>
<div *ngSwitchCase="'HeatMap'">
<analytics-report-heat-map [report]="report"></analytics-report-heat-map>
</div>
<div *ngSwitchDefault>
<span>{{'ANALYTICS.MESSAGES.UNKNOWN-WIDGET-TYPE' | translate}}: {{report.type}}</span>
</div>
</div>
</div>
</div>
<br><br><br>
<div *ngIf="!reports">{{'ANALYTICS.MESSAGES.FILL-PARAMETER' | translate}}</div>
</div>
<activiti-analytics-generator [reportId]="reportId"
[reportParamQuery]="reportParamQuery"
#analyticsgenerator>
</activiti-analytics-generator>
</div>
@@ -16,25 +16,23 @@
*/
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import {
CoreModule
} from 'ng2-alfresco-core';
import { DebugElement } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { CHART_DIRECTIVES } from 'ng2-charts/ng2-charts';
import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core';
import { DiagramsModule } from 'ng2-activiti-diagrams';
import { AnalyticsReportListComponent } from '../components/analytics-report-list.component';
import { AnalyticsComponent } from '../components/analytics.component';
import { AnalyticsGeneratorComponent } from '../components/analytics-generator.component';
import { AnalyticsReportParametersComponent } from '../components/analytics-report-parameters.component';
import { AnalyticsReportHeatMapComponent } from '../components/analytics-report-heat-map.component';
import { WIDGET_DIRECTIVES } from '../components/widgets/index';
import { CHART_DIRECTIVES } from 'ng2-charts/ng2-charts';
import { Chart } from '../models/chart.model';
import { AnalyticsService } from '../services/analytics.service';
import { ReportQuery } from '../models/report.model';
import { DebugElement, SimpleChange } from '@angular/core';
import * as analyticMock from '../assets/analyticsComponent.mock';
export const ANALYTICS_DIRECTIVES: any[] = [
AnalyticsComponent,
AnalyticsGeneratorComponent,
AnalyticsReportParametersComponent,
AnalyticsReportListComponent,
AnalyticsReportHeatMapComponent,
@@ -47,7 +45,7 @@ export const ANALYTICS_PROVIDERS: any[] = [
declare let jasmine: any;
declare let mdDateTimePicker: any;
describe('Test ng2-activiti-analytics Report ', () => {
describe('AnalyticsComponent', () => {
let component: any;
let fixture: ComponentFixture<AnalyticsComponent>;
@@ -59,8 +57,8 @@ describe('Test ng2-activiti-analytics Report ', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule,
DiagramsModule
CoreModule.forRoot(),
DiagramsModule.forRoot()
],
declarations: [
...ANALYTICS_DIRECTIVES,
@@ -70,6 +68,10 @@ describe('Test ng2-activiti-analytics Report ', () => {
...ANALYTICS_PROVIDERS
]
}).compileComponents();
let translateService = TestBed.get(AlfrescoTranslationService);
spyOn(translateService, 'addTranslationFolder').and.stub();
spyOn(translateService, 'get').and.callFake((key) => { return Observable.of(key); });
}));
beforeEach(() => {
@@ -93,136 +95,5 @@ describe('Test ng2-activiti-analytics Report ', () => {
jasmine.Ajax.uninstall();
});
it('Should render the Process definition overview report ', (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();
});
let reportParamQuery = new ReportQuery({status: 'All'});
component.appId = 1;
component.reportId = 1001;
component.showReport(reportParamQuery);
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();
expect(res.length).toEqual(3);
expect(res[0]).toBeDefined();
expect(res[0].type).toEqual('bar');
expect(res[0].labels).toBeDefined();
expect(res[0].labels.length).toEqual(2);
expect(res[0].labels[0]).toEqual('2016-09-30T00:00:00.000+0000');
expect(res[0].labels[1]).toEqual('2016-10-04T00:00:00.000+0000');
expect(res[0].datasets[0].label).toEqual('series1');
expect(res[0].datasets[0].data[0]).toEqual(3);
expect(res[0].datasets[0].data[1]).toEqual(1);
expect(res[1]).toBeDefined();
expect(res[1].type).toEqual('table');
expect(res[1].datasets).toBeDefined();
expect(res[1].datasets.length).toEqual(2);
expect(res[1].datasets[0][0]).toEqual('fake 1 user task');
expect(res[1].datasets[0][1]).toEqual('1');
expect(res[1].datasets[0][2]).toEqual('2.0');
expect(res[1].datasets[0][3]).toEqual('3.0');
expect(res[1].datasets[0][4]).toEqual('4.0');
expect(res[1].datasets[0][5]).toEqual('5.0');
expect(res[1].datasets[0][6]).toEqual('6.0');
expect(res[1].datasets[1][0]).toEqual('fake 2 user task');
expect(res[1].datasets[1][1]).toEqual('1');
expect(res[1].datasets[1][2]).toEqual('2.0');
expect(res[1].datasets[1][3]).toEqual('3.0');
expect(res[1].datasets[1][4]).toEqual('4.0');
expect(res[1].datasets[1][5]).toEqual('5.0');
expect(res[1].datasets[1][6]).toEqual('6.0');
expect(res[2]).toBeDefined();
expect(res[2].type).toEqual('multiBar');
expect(res[2].labels).toBeDefined();
expect(res[2].labels.length).toEqual(3);
expect(res[2].labels[0]).toEqual(1);
expect(res[2].labels[1]).toEqual(2);
expect(res[2].labels[2]).toEqual(3);
expect(res[2].datasets[0].label).toEqual('averages');
expect(res[2].datasets[0].data[0]).toEqual(0);
expect(res[2].datasets[0].data[1]).toEqual(5);
expect(res[2].datasets[0].data[2]).toEqual(2);
expect(res[2].datasets[1].label).toEqual('minima');
expect(res[2].datasets[1].data[0]).toEqual(0);
expect(res[2].datasets[1].data[1]).toEqual(0);
expect(res[2].datasets[1].data[2]).toEqual(0);
expect(res[2].datasets[2].label).toEqual('maxima');
expect(res[2].datasets[2].data[0]).toEqual(0);
expect(res[2].datasets[2].data[1]).toEqual(29);
expect(res[2].datasets[2].data[2]).toEqual(29);
done();
});
let reportParamQuery = new ReportQuery({status: 'All'});
component.reportId = 1;
component.showReport(reportParamQuery);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: analyticMock.chartTaskOverview
});
});
it('Should reset the reports when the onChanged is call', () => {
let reportId = 1;
component.reports = [ new Chart({id: 'fake', type: 'fake-type'})];
let change = new SimpleChange(null, reportId);
component.ngOnChanges({ 'reportId': change });
expect(component.reports).toBeUndefined();
});
it('Should emit onError event with a 404 response ', (done) => {
component.onError.subscribe((err) => {
expect(err).toBeDefined();
done();
});
let reportParamQuery = new ReportQuery({status: 'All'});
component.reportId = 1;
component.showReport(reportParamQuery);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 404,
contentType: 'json',
responseText: []
});
});
});
});
@@ -15,11 +15,11 @@
* limitations under the License.
*/
import { Component, EventEmitter, OnChanges, Input, Output, SimpleChanges } from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { Component, EventEmitter, OnChanges, Input, Output, SimpleChanges, ViewChild } from '@angular/core';
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
import { AnalyticsService } from '../services/analytics.service';
import { ReportQuery } from '../models/report.model';
import { Chart } from '../models/chart.model';
import { AnalyticsGeneratorComponent } from './analytics-generator.component';
@Component({
moduleId: module.id,
@@ -30,7 +30,7 @@ import { Chart } from '../models/chart.model';
export class AnalyticsComponent implements OnChanges {
@Input()
appId: string;
appId: number;
@Input()
reportId: number;
@@ -38,80 +38,37 @@ export class AnalyticsComponent implements OnChanges {
@Input()
debug: boolean = false;
@Output()
onSuccess = new EventEmitter();
@Output()
editReport = new EventEmitter();
@Output()
onError = new EventEmitter();
@ViewChild('analyticsgenerator')
analyticsgenerator: AnalyticsGeneratorComponent;
reportParamQuery = new ReportQuery();
reportParamQuery: ReportQuery;
reports: Chart[];
public barChartOptions: any = {
responsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}],
xAxes: [{
ticks: {
},
stacked: true
}]
}
};
constructor(private translate: AlfrescoTranslationService,
private analyticsService: AnalyticsService) {
console.log('AnalyticsComponent');
if (translate) {
translate.addTranslationFolder('ng2-activiti-analytics', 'node_modules/ng2-activiti-analytics/src');
constructor(private translateService: AlfrescoTranslationService,
private analyticsService: AnalyticsService,
private logService: LogService) {
logService.info('AnalyticsComponent');
if (translateService) {
translateService.addTranslationFolder('ng2-activiti-analytics', 'node_modules/ng2-activiti-analytics/src');
}
}
ngOnChanges(changes: SimpleChanges) {
this.reset();
this.analyticsgenerator.reset();
}
public showReport($event) {
this.reportParamQuery = $event;
this.analyticsService.getReportsByParams(this.reportId, this.reportParamQuery).subscribe(
(res: Chart[]) => {
this.reports = res;
this.onSuccess.emit(res);
},
(err: any) => {
this.onError.emit(err);
console.log(err);
}
);
this.analyticsgenerator.generateReport(this.reportId, $event);
}
public reset() {
if (this.reports) {
this.reports = undefined;
}
}
public refresh(report): void {
/**
* (My guess), for Angular to recognize the change in the dataset
* it has to change the dataset variable directly,
* so one way around it, is to clone the data, change it and then
* assign it;
*/
let clone = JSON.parse(JSON.stringify(report));
report.datasets = clone.datasets;
this.analyticsgenerator.reset();
}
public onEditReport(name: string) {
this.editReport.emit(name);
}
}
@@ -2,7 +2,7 @@
<label class="dropdown-widget__label" [attr.for]="field.id">{{field.nameKey | translate}}</label>
<select [formControlName]="controllerName" [attr.id]="'select-' + field.id" class="dropdown-widget__select"
[(ngModel)]="field.value" (ngModelChange)="changeValue($event)">
<option *ngIf="showDefaultOption" value="">{{defaultOptionText}}</option>
<option *ngIf="showDefaultOption" value="null">{{defaultOptionText}}</option>
<option *ngFor="let opt of field.options" [value]="opt.id">{{opt.label}}</option>
</select>
</div>
@@ -4,7 +4,9 @@
"MESSAGES": {
"UNKNOWN-WIDGET-TYPE": "UNKNOWN WIDGET TYPE",
"FILL-PARAMETER": "Fill in the parameters to generate your report",
"NO-DATA-FOUND": "No data found"
"NO-DATA-FOUND": "No data found",
"ZERO-DATA-FOUND": "There are only zero values",
"SETTING-TITLE": "Change report setting"
}
},
"__KEY_REPORTING": {
@@ -1,5 +1,47 @@
{
"ANALYTICS": {
"TTILE": "ANALYTICS"
"TTILE": "ANALYTICS",
"MESSAGES": {
"UNKNOWN-WIDGET-TYPE": "TIPO WIDGET SCONOSCIUTO",
"FILL-PARAMETER": "Riempi tutti i campi per generare il report",
"NO-DATA-FOUND": "Nessun valore trovato",
"ZERO-DATA-FOUND": "Ci sono solo valori che valgono zero",
"SETTING-TITLE": "Modifica i parametri del report"
}
},
"__KEY_REPORTING": {
"DEFAULT-REPORTS": {
"PROCESS-DEFINITION-OVERVIEW": {
"GENERAL-TABLE-TOTAL-PROCESS-DEFINITIONS": "Numero totale di process definitions",
"GENERAL-TABLE-TOTAL-PROCESS-INSTANCES": "Numero totale di process instances",
"GENERAL-TABLE-ACTIVE-PROCESS-INSTANCES": "Numero totale di process instances attivi",
"GENERAL-TABLE-COMPLETED-PROCESS-INSTANCES": "Numero totale di process instances completi"
}
}
},
"REPORTING": {
"DEFAULT-REPORTS": {
"PROCESS-HEAT-MAP": {
"TYPE-FILTERING": "Include tutti gli steps (Deselezionandolo, rimuoverai gli step come start events, gateways, etc.)?"
},
"PROCESS-INSTANCES-OVERVIEW": {
"PROCESS-DEFINITION": "Definizione del processo",
"DATE-RANGE": "Intervallo di Date",
"SLOW-PROC-INST-NUMBER": "Quanti process instances lenti vuoi mostrare?"
},
"TASK-OVERVIEW": {
"PROCESS-DEFINITION": "Definizione del processo",
"DATE-RANGE": "Intervallo di Date",
"DATE-RANGE-INTERVAL": "Aggrega date per"
},
"TASK-SLA": {
"TASK": "Task",
"PROCESS-DEFINITION": "Definizione del processo",
"DATE-RANGE": "Intervallo di Date",
"SLA-DURATION": "Qual' é il tempo che questo task necessita per essere completato per rimanere nella SLA?"
}
},
"PROCESS-STATUS": "Stato del processo",
"TASK-STATUS": "Stato del task"
}
}
@@ -49,6 +49,9 @@ export class Chart {
case 'processDefinitionHeatMap':
chartType = 'HeatMap';
break;
case 'masterDetailTable':
chartType = 'masterDetailTable';
break;
default:
chartType = 'table';
break;
@@ -191,6 +194,22 @@ export class TableChart extends Chart {
}
}
export class DetailsTableChart extends TableChart {
detailsTable: any;
showDetails: boolean = false;
constructor(obj?: any) {
super(obj);
if (obj.detailTables) {
this.detailsTable = new TableChart(obj.detailTables[0]);
}
}
hasDetailsTable() {
return this.detailsTable ? true : false;
}
}
export class HeatMapChart extends Chart {
avgTimePercentages: string;
avgTimeValues: string;
@@ -236,7 +255,20 @@ export class PieChart extends Chart {
this.data.push(data);
}
hasData() {
hasData(): boolean {
return this.data && this.data.length > 0 ? true : false;
}
hasZeroValues(): boolean {
let isZeroValues: boolean = false;
if (this.hasData()) {
isZeroValues = true;
this.data.forEach((value) => {
if (value.toString() !== '0') {
isZeroValues = false;
}
});
}
return isZeroValues;
}
}
@@ -16,18 +16,17 @@
*/
import { Injectable } from '@angular/core';
import { AlfrescoAuthenticationService, AlfrescoSettingsService, AlfrescoApiService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { Response } from '@angular/http';
import { AlfrescoApiService, LogService } from 'ng2-alfresco-core';
import { ReportParametersModel, ParameterValueModel } from '../models/report.model';
import { Chart, PieChart, TableChart, BarChart, HeatMapChart, MultiBarChart } from '../models/chart.model';
import { Chart, PieChart, TableChart, BarChart, HeatMapChart, MultiBarChart, DetailsTableChart } from '../models/chart.model';
@Injectable()
export class AnalyticsService {
constructor(private authService: AlfrescoAuthenticationService,
public apiService: AlfrescoApiService,
private alfrescoSettingsService: AlfrescoSettingsService) {
constructor(private apiService: AlfrescoApiService,
private logService: LogService) {
}
/**
@@ -43,14 +42,14 @@ export class AnalyticsService {
reports.push(reportModel);
});
return reports;
}).catch(this.handleError);
}).catch(err => this.handleError(err));
}
getReportParams(reportId: string): Observable<any> {
return Observable.fromPromise(this.apiService.getInstance().activiti.reportApi.getReportParams(reportId))
.map((res: any) => {
return new ReportParametersModel(res);
}).catch(this.handleError);
}).catch(err => this.handleError(err));
}
getParamValuesByType(type: string, appId: string, reportId?: string, processDefinitionId?: string) {
@@ -123,7 +122,7 @@ export class AnalyticsService {
paramOptions.push(new ParameterValueModel(opt));
});
return paramOptions;
}).catch(this.handleError);
}).catch(err => this.handleError(err));
}
getProcessDefinitionsValues(appId: string): Observable<any> {
@@ -134,7 +133,7 @@ export class AnalyticsService {
paramOptions.push(new ParameterValueModel(opt));
});
return paramOptions;
}).catch(this.handleError);
}).catch(err => this.handleError(err));
}
getTasksByProcessDefinitionId(reportId: string, processDefinitionId: string): Observable<any> {
@@ -145,7 +144,7 @@ export class AnalyticsService {
paramOptions.push(new ParameterValueModel({ id: opt, name: opt }));
});
return paramOptions;
}).catch(this.handleError);
}).catch(err => this.handleError(err));
}
getReportsByParams(reportId: number, paramsQuery: any): Observable<any> {
@@ -160,7 +159,7 @@ export class AnalyticsService {
} else if (chartData.type === 'processDefinitionHeatMap') {
elements.push(new HeatMapChart(chartData));
} else if (chartData.type === 'masterDetailTable') {
elements.push(new TableChart(chartData));
elements.push(new DetailsTableChart(chartData));
} else if (chartData.type === 'barChart') {
elements.push(new BarChart(chartData));
} else if (chartData.type === 'multiBarChart') {
@@ -169,24 +168,24 @@ export class AnalyticsService {
});
return elements;
}).catch(this.handleError);
}).catch(err => this.handleError(err));
}
public createDefaultReports(): Observable<any> {
createDefaultReports(): Observable<any> {
return Observable.fromPromise(this.apiService.getInstance().activiti.reportApi.createDefaultReports())
.map(this.toJson)
.catch(this.handleError);
.catch(err => this.handleError(err));
}
public updateReport(reportId: number, name: string): Observable<any> {
updateReport(reportId: number, name: string): Observable<any> {
return Observable.fromPromise(this.apiService.getInstance().activiti.reportApi.updateReport(reportId, name))
.map((res: any) => {
console.log('upload');
}).catch(this.handleError);
this.logService.info('upload');
}).catch(err => this.handleError(err));
}
private handleError(error: Response) {
console.error(error);
this.logService.error(error);
return Observable.throw(error.json().error || 'Server error');
}
@@ -62,6 +62,9 @@ Follow the 3 steps below:
<script src="node_modules/material-design-lite/material.min.js"></script>
<link rel="stylesheet" href="node_modules/material-design-icons/iconfont/material-icons.css">
<!-- Load the Angular Material 2 stylesheet -->
<link href="node_modules/@angular/material/core/theming/prebuilt/deeppurple-amber.css" rel="stylesheet">
<!-- Polyfill(s) for Safari (pre-10.x) -->
<script src="node_modules/intl/dist/Intl.min.js"></script>
<script src="node_modules/intl/locale-data/jsonp/en.js"></script>
@@ -39,17 +39,18 @@
"@angular/http": "2.2.2",
"@angular/platform-browser": "2.2.2",
"@angular/platform-browser-dynamic": "2.2.2",
"@angular/material": "2.0.0-beta.1",
"@angular/router": "3.2.2",
"@angular/upgrade": "2.2.2",
"alfresco-js-api": "^1.0.0",
"alfresco-js-api": "~1.1.0",
"core-js": "^2.4.1",
"dialog-polyfill": "^0.4.3",
"element.scrollintoviewifneeded-polyfill": "^1.0.1",
"intl": "1.2.4",
"material-design-icons": "2.2.3",
"material-design-lite": "1.2.1",
"ng2-activiti-diagrams": "^1.0.0",
"ng2-alfresco-core": "1.0.0",
"ng2-activiti-diagrams": "^1.1.0",
"ng2-alfresco-core": "1.1.0",
"ng2-translate": "2.5.0",
"raphael": "^2.2.6",
"reflect-metadata": "^0.1.3",
@@ -19,40 +19,39 @@ import { NgModule, Component } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { CoreModule, AlfrescoSettingsService, AlfrescoAuthenticationService, StorageService } from 'ng2-alfresco-core';
import { CoreModule, AlfrescoSettingsService, AlfrescoAuthenticationService, StorageService, LogService } from 'ng2-alfresco-core';
import { DiagramsModule } from 'ng2-activiti-diagrams';
@Component({
selector: 'alfresco-app-demo',
template: `
<label for="ticket"><b>Insert a valid ticket:</b></label><br>
<input id="ticket" type="text" size="48" (change)="updateTicket()" [(ngModel)]="ticket"><br>
<label for="host"><b>Insert the ip of your Activiti instance:</b></label><br>
<input id="host" type="text" size="48" (change)="updateHost()" [(ngModel)]="host"><br><br>
<div *ngIf="!authenticated" style="color:#FF2323">
Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid ticket to perform
operations.
</div>
<hr>
<label for="ticket"><b>Insert a valid ticket:</b></label><br>
<input id="ticket" type="text" size="48" (change)="updateTicket()" [(ngModel)]="ticket"><br>
<label for="host"><b>Insert the ip of your Activiti instance:</b></label><br>
<input id="host" type="text" size="48" (change)="updateHost()" [(ngModel)]="host"><br><br>
<div *ngIf="!authenticated" style="color:#FF2323">
Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid ticket to perform
operations.
</div>
<hr>
<label for="processDefinitionId"><b>Insert the ProcessDefinitionId:</b></label><br>
<input id="processDefinitionId" size="70" type="text" [(ngModel)]="processDefinitionId">
<activiti-diagram [processDefinitionId]="processDefinitionId"></activiti-diagram>`
<label for="processDefinitionId"><b>Insert the ProcessDefinitionId:</b></label><br>
<input id="processDefinitionId" size="70" type="text" [(ngModel)]="processDefinitionId">
<activiti-diagram [processDefinitionId]="processDefinitionId"></activiti-diagram>
`
})
export class DiagramDemoComponent {
processDefinitionId: string = 'ThirdProcess:1:15053';
authenticated: boolean;
host: string = 'http://localhost:9999';
ticket: string;
constructor(private authService: AlfrescoAuthenticationService,
private settingsService: AlfrescoSettingsService,
private storage: StorageService) {
private storage: StorageService,
private logService: LogService) {
settingsService.bpmHost = this.host;
settingsService.setProviders('BPM');
@@ -77,12 +76,12 @@ export class DiagramDemoComponent {
login() {
this.authService.login('admin', 'admin').subscribe(
ticket => {
console.log(ticket);
this.logService.info(`Logged in with ticket ${ticket}`);
this.ticket = this.authService.getTicketBpm();
this.authenticated = true;
},
error => {
console.log(error);
this.logService.error(error);
this.authenticated = false;
});
}
@@ -1,7 +1,14 @@
// Tun on full stack traces in errors to help debugging
Error.stackTraceLimit = Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
window.componentHandler = {
upgradeAllRegistered: function () {
},
upgradeElement: function () {
}
};
__karma__.loaded = function() {};
@@ -39,6 +46,8 @@ var map = {
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/material': 'npm:@angular/material/bundles/material.umd.js',
// testing
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
@@ -1,13 +1,13 @@
{
"name": "ng2-activiti-diagrams",
"description": "Activiti Angular2 Diagrams Component",
"version": "1.0.0",
"version": "1.1.0",
"author": "Alfresco Software, Ltd.",
"scripts": {
"clean": "npm install rimraf && npm run clean-build && rimraf dist node_modules typings",
"clean-build": "rimraf index.js index.js.map index.d.ts'src/{,**/}**.js' 'src/{,**/}**.js.map' 'src/{,**/}**.d.ts' bundles",
"build": "npm run clean-build && npm run tslint && rimraf dist && tsc && license-check && npm run build.umd",
"build:w": "npm run clean-build && npm run tslint && rimraf dist && tsc:w && license-check npm run build.umd",
"build:w": "npm run clean-build && npm run tslint && rimraf dist && npm run tsc:w && license-check && npm run build.umd",
"tslint": "tslint -c tslint.json 'src/{,**/}**.ts' 'index.ts' -e '{,**/}**.d.ts' -e './gulpfile.ts'",
"tsc": "tsc",
"tsc:w": "tsc -w",
@@ -16,7 +16,7 @@
"test-browser": "npm run build && concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"",
"posttest": "remap-istanbul -i coverage/report/coverage-final.json -o coverage/report -t html && remap-istanbul -i coverage/report/coverage-final.json -o coverage/report/coverage-final.json",
"coverage": "npm run test && wsrv -o -p 9875 ./coverage/report",
"prepublish": "npm run build",
"prepublish": "npm run test",
"travis": "npm link ng2-alfresco-core",
"gulp": "gulp",
"build.umd": "gulp build.prod --color --env-config prod --build-type prod",
@@ -47,21 +47,21 @@
"@angular/http": "2.0.0",
"@angular/platform-browser": "2.0.0",
"@angular/platform-browser-dynamic": "2.0.0",
"@angular/material": "2.0.0-beta.1",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.12",
"systemjs": "0.19.27",
"zone.js": "^0.6.23",
"raphael": "^2.2.6",
"chart.js": "^2.1.4",
"ng2-charts": "1.1.0",
"ng2-translate": "2.5.0",
"alfresco-js-api": "^1.0.0",
"ng2-alfresco-core": "1.0.0"
"alfresco-js-api": "~1.1.0",
"ng2-alfresco-core": "1.1.0"
},
"devDependencies": {
"@types/jasmine": "^2.2.33",
"@types/node": "^6.0.42",
"autoprefixer": "^6.5.4",
"concurrently": "^2.2.0",
"cpx": "1.3.1",
"cssnano": "^3.8.1",
@@ -80,6 +80,7 @@
"gulp-template": "^4.0.0",
"gulp-typescript": "^3.1.3",
"gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.7",
"intl": "^1.2.5",
"jasmine-core": "2.4.1",
"karma": "0.13.22",
@@ -90,6 +91,7 @@
"karma-jasmine-html-reporter": "0.2.0",
"karma-mocha-reporter": "2.0.3",
"license-check": "1.1.5",
"merge-stream": "^1.0.1",
"remap-istanbul": "0.6.3",
"rimraf": "2.5.2",
"run-sequence": "^1.2.2",
@@ -16,10 +16,7 @@
*/
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import {
CoreModule,
AlfrescoTranslationService
} from 'ng2-alfresco-core';
import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core';
import { DIAGRAM_DIRECTIVES, DIAGRAM_PROVIDERS } from './index';
import { RAPHAEL_DIRECTIVES, RAPHAEL_PROVIDERS } from './raphael/index';
@@ -50,7 +47,7 @@ describe('Test ng2-activiti-diagrams ', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule
CoreModule.forRoot()
],
declarations: [
...DIAGRAM_DIRECTIVES,
@@ -16,7 +16,7 @@
*/
import { Component, ElementRef, Input, Output, EventEmitter, SimpleChanges } from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
import { DiagramsService } from '../services/diagrams.service';
import { DiagramColorService } from '../services/diagram-color.service';
import { RaphaelService } from './raphael/raphael.service';
@@ -57,17 +57,16 @@ export class DiagramComponent {
PADDING_HEIGHT: number = 60;
private diagram: DiagramModel;
private elementRef: ElementRef;
constructor(elementRef: ElementRef,
private translate: AlfrescoTranslationService,
constructor(private elementRef: ElementRef,
private translateService: AlfrescoTranslationService,
private diagramColorService: DiagramColorService,
private raphaelService: RaphaelService,
private diagramsService: DiagramsService) {
if (translate) {
translate.addTranslationFolder('ng2-activiti-diagrams', 'node_modules/ng2-activiti-diagrams/src');
private diagramsService: DiagramsService,
private logService: LogService) {
if (translateService) {
translateService.addTranslationFolder('ng2-activiti-diagrams', 'node_modules/ng2-activiti-diagrams/src');
}
this.elementRef = elementRef;
}
ngOnChanges(changes: SimpleChanges) {
@@ -86,7 +85,7 @@ export class DiagramComponent {
},
(err: any) => {
this.onError.emit(err);
console.log(err);
this.logService.error(err);
}
);
}
@@ -16,6 +16,7 @@
*/
import { Directive, OnInit, ElementRef, Input, Output, EventEmitter } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
import { Point } from './models/point';
import { RaphaelBase } from './raphael-base';
import { RaphaelService } from './raphael.service';
@@ -43,19 +44,20 @@ export class RaphaelMultilineTextDirective extends RaphaelBase implements OnInit
TEXT_PADDING = 3;
constructor(public elementRef: ElementRef,
raphaelService: RaphaelService) {
raphaelService: RaphaelService,
private logService: LogService) {
super(elementRef, raphaelService);
}
ngOnInit() {
console.log(this.elementRef);
this.logService.log(this.elementRef);
if (this.text === null || this.text === undefined) {
this.text = '';
}
this.draw(this.position, this.text);
}
public draw(position: Point, text: string) {
draw(position: Point, text: string) {
let textPaper = this.paper.text(position.x + this.TEXT_PADDING, position.y + this.TEXT_PADDING, text).attr({
'text-anchor': 'middle',
'font-family': 'Arial',
@@ -16,27 +16,28 @@
*/
import { Injectable } from '@angular/core';
import { AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { Response, Http, Headers, RequestOptions } from '@angular/http';
import { AlfrescoAuthenticationService, AlfrescoSettingsService, LogService } from 'ng2-alfresco-core';
@Injectable()
export class DiagramsService {
constructor(private authService: AlfrescoAuthenticationService,
private http: Http,
private alfrescoSettingsService: AlfrescoSettingsService) {
private settingsService: AlfrescoSettingsService,
private logService: LogService) {
}
getProcessDefinitionModel(processDefinitionId: string): Observable<any> {
let url = `${this.alfrescoSettingsService.getBPMApiBaseUrl()}/app/rest/process-definitions/${processDefinitionId}/model-json`;
let url = `${this.settingsService.getBPMApiBaseUrl()}/app/rest/process-definitions/${processDefinitionId}/model-json`;
let options = this.getRequestOptions();
return this.http
.get(url, options)
.map((res: any) => {
let body = res.json();
return body;
}).catch(this.handleError);
}).catch(err => this.handleError(err));
}
public getHeaders(): Headers {
@@ -53,7 +54,7 @@ export class DiagramsService {
}
private handleError(error: Response) {
console.error(error);
this.logService.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
+92 -5
View File
@@ -31,6 +31,22 @@
</a>
</p>
## Library Contents
### Components
- [ActivitiForm](#activitiform-component)
- ActivitiStartForm
### Services
- [FormService](#formservice)
- ActivitiAlfrescoContentService
- EcmModelService
- FormRenderingService
- NodeService
- WidgetVisibilityService
## Prerequisites
Before you start using this development framework, make sure you have installed all required software and done all the
@@ -65,6 +81,9 @@ Follow the 3 steps below:
<script src="node_modules/material-design-lite/material.min.js"></script>
<link rel="stylesheet" href="node_modules/material-design-icons/iconfont/material-icons.css">
<!-- Load the Angular Material 2 stylesheet -->
<link href="node_modules/@angular/material/core/theming/prebuilt/deeppurple-amber.css" rel="stylesheet">
<!-- Polyfill(s) for Safari (pre-10.x) -->
<script src="node_modules/intl/dist/Intl.min.js"></script>
<script src="node_modules/intl/locale-data/jsonp/en.js"></script>
@@ -98,7 +117,9 @@ Follow the 3 steps below:
Please refer to the following example file: [systemjs.config.js](demo/systemjs
.config.js) .
## Basic usage examples
## ActivitiForm Component
### Basic usage
The component shows a Form from Activiti
@@ -109,6 +130,7 @@ The component shows a Form from Activiti
Usage example of this component :
**main.ts**
```ts
import { NgModule, Component } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@@ -220,9 +242,9 @@ and store the form field as metadata. The param nameNode is optional.
</activiti-form>
```
## Configuration
### Configuration
### Properties
#### Properties
The recommended set of properties can be found in the following table:
@@ -238,11 +260,12 @@ The recommended set of properties can be found in the following table:
| `showDebugButton` | boolean | false | Toggle debug options. |
| `readOnly` | boolean | false | Toggle readonly state of the form. Enforces all form widgets render readonly if enabled. |
| `showRefreshButton` | boolean | true | Toggle rendering of the `Refresh` button. |
| `showValidationIcon` | boolean | true | Toggle rendering of the validation icon next form title. |
| `saveMetadata` | boolean | false | Store the value of the form as metadata. |
| `path` | string | | Path of the folder where to store the metadata. |
| `nameNode` (optional) | string | true | Name to assign to the new node where the metadata are stored. |
#### Advanced properties
##### Advanced properties
The following properties are for complex customisation purposes:
@@ -251,7 +274,7 @@ The recommended set of properties can be found in the following table:
| `form` | FormModel | | Underlying form model instance. |
| `debugMode` | boolean | false | Toggle debug mode, allows displaying additional data for development and debugging purposes. |
### Events
#### Events
| Name | Description |
| --- | --- |
@@ -328,6 +351,70 @@ There are two additional functions that can be of a great value when controlling
**Please note that if `event.preventDefault()` is not called then default outcome behaviour
will also be executed after your custom code.**
## FormService
```ts
import { Component } from '@angular/core';
import { FormService, FormEvent, FormFieldEvent } from 'ng2-activiti-form';
@Component(...)
class MyComponent {
constructor(private formService: FormService) {
formService.formLoaded.subscribe((e: FormEvent) => {
console.log(`Form loaded: ${e.form.id}`);
});
formService.formFieldValueChanged.subscribe((e: FormFieldEvent) => {
console.log(`Field value changed. Form: ${e.form.id}, Field: ${e.field.id}, Value: ${e.field.value}`);
});
}
}
```
### Events
| Name | Args Type | Description |
| --- | --- | --- |
| formLoaded | FormEvent | Raised when form has been loaded or reloaded |
| formFieldValueChanged | FormFieldEvent | Raised when input values change |
| taskCompleted | FormEvent | Raised when a task is completed successfully |
| taskCompletedError | FormErrorEvent | Raised when a task is completed unsuccessfully |
| taskSaved | FormEvent | Raised when a task is saved successfully |
| taskSavedError | FormErrorEvent | Raised when a task is saved unsuccessfully |
### Methods
| Name | Params | Returns | Description |
| --- | --- | --- | --- |
| createFormFromANode | (formName: string) | Observable\<any\> | Create a Form with a fields for each metadata properties |
| createForm | (formName: string) | Observable\<any\> | Create a Form |
| addFieldsToAForm | (formId: string, formModel: FormDefinitionModel) | Observable\<any\> | Add Fileds to A form |
| searchFrom | (name: string) | Observable\<any\> | Search For A Form by name |
| getForms | n/a | Observable\<any\> | Get All the forms |
| getProcessDefinitions | n/a | Observable\<any\> | Get Process Definitions |
| getTasks | n/a | Observable\<any\> | Get All the Tasks |
| getTask | (taskId: string) | Observable\<any\> | Get Task |
| saveTaskForm | (taskId: string, formValues: FormValues) | Observable\<any\> | Save Task Form |
| completeTaskForm | (taskId: string, formValues: FormValues, outcome?: string) | Observable\<any\> | Complete Task Form |
| getTaskForm | (taskId: string) | Observable\<any\> | Get Form related to a taskId |
| getFormDefinitionById | (formId: string) | Observable\<any\> | Get Form Definition |
| getFormDefinitionByName | (name: string) | Observable\<any\> | Returns form definition by a given name. |
| getStartFormInstance | (processId: string) | Observable\<any\> | Get start form instance for a given processId |
| getStartFormDefinition | (processId: string) | Observable\<any\> | Get start form definition for a given process |
| createTemporaryRawRelatedContent | (file: any) | Observable\<any\> | Save File |
| getRestFieldValues | (taskId: string, field: string) | Observable\<any\> | |
| getRestFieldValuesByProcessId | (processDefinitionId: string, field: string) | Observable\<any\> | |
| getRestFieldValuesColumnByProcessId | (processDefinitionId: string, field: string, column?: string) | Observable\<any\> | |
| getRestFieldValuesColumn | (taskId: string, field: string, column?: string) | Observable\<any\> | |
| getWorkflowGroups\* | (filter: string, groupId?: string) | Observable\<GroupModel[]\> | |
| getWorkflowUsers\* | (filter: string, groupId?: string) | Observable\<GroupUserModel[]\> | |
\* _Uses private Activiti WebApp api_
## See also
- [Form Stencils with Angular 2](docs/stencils.md)
@@ -39,6 +39,7 @@
"@angular/http": "2.2.2",
"@angular/platform-browser": "2.2.2",
"@angular/platform-browser-dynamic": "2.2.2",
"@angular/material": "2.0.0-beta.1",
"@angular/router": "3.2.2",
"@angular/upgrade": "2.2.2",
"core-js": "^2.4.1",
@@ -54,9 +55,9 @@
"moment": "2.15.1",
"md-date-time-picker": "^2.2.0",
"ng2-translate": "2.5.0",
"alfresco-js-api": "^1.0.0",
"ng2-alfresco-core": "1.0.0",
"ng2-activiti-form": "^1.0.0"
"alfresco-js-api": "~1.1.0",
"ng2-alfresco-core": "1.1.0",
"ng2-activiti-form": "^1.1.0"
},
"devDependencies": {
"@types/jasmine": "^2.2.33",
@@ -18,40 +18,39 @@
import { NgModule, Component, OnInit } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { CoreModule, AlfrescoSettingsService, AlfrescoAuthenticationService, StorageService } from 'ng2-alfresco-core';
import { CoreModule, AlfrescoSettingsService, AlfrescoAuthenticationService, StorageService, LogService } from 'ng2-alfresco-core';
import { ActivitiFormModule } from 'ng2-activiti-form';
@Component({
selector: 'alfresco-app-demo',
template: `
<label for="ticket"><b>Insert a valid ticket:</b></label><br>
<input id="ticket" type="text" size="48" (change)="updateTicket()" [(ngModel)]="ticket"><br>
<label for="host"><b>Insert the ip of your Activiti instance:</b></label><br>
<input id="host" type="text" size="48" (change)="updateHost()" [(ngModel)]="host"><br><br>
<div *ngIf="!authenticated" style="color:#FF2323">
Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid ticket to perform
operations.
</div>
<hr>
<label for="ticket"><b>Insert a valid ticket:</b></label><br>
<input id="ticket" type="text" size="48" (change)="updateTicket()" [(ngModel)]="ticket"><br>
<label for="host"><b>Insert the ip of your Activiti instance:</b></label><br>
<input id="host" type="text" size="48" (change)="updateHost()" [(ngModel)]="host"><br><br>
<div *ngIf="!authenticated" style="color:#FF2323">
Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid ticket to perform
operations.
</div>
<hr>
<label for="taskId"><b>Insert the taskId:</b></label><br>
<input id="taskId" size="10" type="text" [(ngModel)]="taskId">
<activiti-form [taskId]="taskId"></activiti-form>`
<label for="taskId"><b>Insert the taskId:</b></label><br>
<input id="taskId" size="10" type="text" [(ngModel)]="taskId">
<activiti-form [taskId]="taskId"></activiti-form>
`
})
export class FormDemoComponent implements OnInit {
taskId: number;
authenticated: boolean;
host: string = 'http://localhost:9999';
ticket: string;
constructor(private authService: AlfrescoAuthenticationService,
private settingsService: AlfrescoSettingsService,
private storage: StorageService) {
private storage: StorageService,
private logService: LogService) {
settingsService.bpmHost = this.host;
settingsService.setProviders('BPM');
@@ -76,12 +75,12 @@ export class FormDemoComponent implements OnInit {
login() {
this.authService.login('admin', 'admin').subscribe(
ticket => {
console.log(ticket);
this.logService.info(`Logged in with ticket ${ticket}`);
this.ticket = this.authService.getTicketBpm();
this.authenticated = true;
},
error => {
console.log(error);
this.logService.error(error);
this.authenticated = false;
});
}
@@ -37,6 +37,7 @@ export * from './src/components/widgets/index';
export * from './src/services/ecm-model.service';
export * from './src/services/node.service';
export * from './src/services/form-rendering.service';
export * from './src/events/index';
export const ACTIVITI_FORM_DIRECTIVES: any[] = [
ActivitiForm,
@@ -1,7 +1,14 @@
// Tun on full stack traces in errors to help debugging
Error.stackTraceLimit = Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
window.componentHandler = {
upgradeAllRegistered: function () {
},
upgradeElement: function () {
}
};
__karma__.loaded = function() {};
@@ -39,6 +46,8 @@ var map = {
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/material': 'npm:@angular/material/bundles/material.umd.js',
// testing
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
@@ -1,13 +1,13 @@
{
"name": "ng2-activiti-form",
"description": "Alfresco Activiti Form Component for Angular 2",
"version": "1.0.0",
"version": "1.1.0",
"author": "Alfresco Software, Ltd.",
"scripts": {
"clean": "npm install rimraf && npm run clean-build && rimraf dist node_modules typings",
"clean-build": "rimraf index.js index.js.map index.d.ts'src/{,**/}**.js' 'src/{,**/}**.js.map' 'src/{,**/}**.d.ts' bundles",
"build": "npm run clean-build && npm run tslint && rimraf dist && tsc && license-check && npm run build.umd",
"build:w": "npm run clean-build && npm run tslint && rimraf dist && tsc:w && license-check npm run build.umd",
"build:w": "npm run clean-build && npm run tslint && rimraf dist && npm run tsc:w && license-check && npm run build.umd",
"tslint": "tslint -c tslint.json 'src/{,**/}**.ts' 'index.ts' -e '{,**/}**.d.ts' -e './gulpfile.ts'",
"tsc": "tsc",
"tsc:w": "tsc -w",
@@ -16,7 +16,7 @@
"test-browser": "npm run build && concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"",
"posttest": "remap-istanbul -i coverage/report/coverage-final.json -o coverage/report -t html && remap-istanbul -i coverage/report/coverage-final.json -o coverage/report/coverage-final.json",
"coverage": "npm run test && wsrv -o -p 9875 ./coverage/report",
"prepublish": "npm run build",
"prepublish": "npm run test",
"travis": "npm link ng2-alfresco-core",
"gulp": "gulp",
"build.umd": "gulp build.prod --color --env-config prod --build-type prod",
@@ -54,6 +54,7 @@
"@angular/http": "2.0.0",
"@angular/platform-browser": "2.0.0",
"@angular/platform-browser-dynamic": "2.0.0",
"@angular/material": "2.0.0-beta.1",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.12",
@@ -62,13 +63,13 @@
"moment": "2.15.1",
"md-date-time-picker": "^2.2.0",
"ng2-translate": "2.5.0",
"alfresco-js-api": "^1.0.0",
"ng2-alfresco-core": "1.0.0"
"alfresco-js-api": "~1.1.0",
"ng2-alfresco-core": "1.1.0"
},
"devDependencies": {
"@types/jasmine": "^2.2.33",
"@types/node": "^6.0.42",
"autoprefixer": "^6.5.1",
"autoprefixer": "^6.5.4",
"concurrently": "^2.2.0",
"cpx": "^1.3.1",
"cssnano": "^3.8.1",
@@ -87,6 +88,7 @@
"gulp-template": "^4.0.0",
"gulp-typescript": "^3.1.3",
"gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.7",
"intl": "^1.2.5",
"jasmine-ajax": "^3.2.0",
"jasmine-core": "2.4.1",
@@ -98,6 +100,7 @@
"karma-jasmine-html-reporter": "^0.2.0",
"karma-mocha-reporter": "^2.0.3",
"license-check": "^1.0.4",
"merge-stream": "^1.0.1",
"remap-istanbul": "^0.6.3",
"rimraf": "2.5.2",
"run-sequence": "^1.2.2",
@@ -5,7 +5,7 @@
<div *ngIf="hasForm()">
<div class="mdl-card mdl-shadow--2dp activiti-form-container">
<div class="mdl-card__title">
<i class="material-icons">{{ form.isValid ? 'event_available' : 'event_busy' }}</i>
<i *ngIf="showValidationIcon" class="material-icons">{{ form.isValid ? 'event_available' : 'event_busy' }}</i>
<h2 *ngIf="isTitleEnabled()" class="mdl-card__title-text">{{form.taskName}}</h2>
</div>
<div class="mdl-card__media">
@@ -24,7 +24,7 @@
alfresco-mdl-button
[disabled]="!isOutcomeButtonEnabled(outcome)"
[class.mdl-button--colored]="!outcome.isSystem"
[class.activiti-form-hide-button]="!isOutcomeButtonVisible(outcome)"
[class.activiti-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
(click)="onOutcomeClicked(outcome, $event)">
{{outcome.name}}
</button>
@@ -17,6 +17,7 @@
import { Observable } from 'rxjs/Rx';
import { SimpleChange } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
import { ActivitiForm } from './activiti-form.component';
import { FormModel, FormOutcomeModel, FormFieldModel, FormOutcomeEvent, FormFieldTypes } from './widgets/index';
import { FormService } from './../services/form.service';
@@ -30,6 +31,7 @@ describe('ActivitiForm', () => {
let formComponent: ActivitiForm;
let visibilityService: WidgetVisibilityService;
let nodeService: NodeService;
let logService: LogService;
beforeEach(() => {
componentHandler = jasmine.createSpyObj('componentHandler', [
@@ -37,11 +39,12 @@ describe('ActivitiForm', () => {
]);
window['componentHandler'] = componentHandler;
visibilityService = new WidgetVisibilityService(null);
logService = new LogService();
visibilityService = new WidgetVisibilityService(null, logService);
spyOn(visibilityService, 'refreshVisibility').and.stub();
formService = new FormService(null, null);
nodeService = new NodeService(null, null);
formComponent = new ActivitiForm(formService, visibilityService, null, nodeService);
formService = new FormService(null, null, logService);
nodeService = new NodeService(null);
formComponent = new ActivitiForm(formService, visibilityService, null, nodeService, logService);
});
it('should upgrade MDL content on view checked', () => {
@@ -98,35 +101,73 @@ describe('ActivitiForm', () => {
});
it('should not enable outcome button when model missing', () => {
expect(formComponent.isOutcomeButtonVisible(null)).toBeFalsy();
expect(formComponent.isOutcomeButtonVisible(null, false)).toBeFalsy();
});
it('should enable custom outcome buttons', () => {
let formModel = new FormModel();
formComponent.form = formModel;
let outcome = new FormOutcomeModel(formModel, {id: 'action1', name: 'Action 1'});
expect(formComponent.isOutcomeButtonVisible(outcome)).toBeTruthy();
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
});
it('should allow controlling [complete] button visibility', () => {
let formModel = new FormModel();
formComponent.form = formModel;
let outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.SAVE_ACTION});
formComponent.showSaveButton = true;
expect(formComponent.isOutcomeButtonVisible(outcome)).toBeTruthy();
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
formComponent.showSaveButton = false;
expect(formComponent.isOutcomeButtonVisible(outcome)).toBeFalsy();
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeFalsy();
});
it('should show only [complete] button with readOnly form ', () => {
let formModel = new FormModel();
formModel.readOnly = true;
formComponent.form = formModel;
let outcome = new FormOutcomeModel(formModel, {id: '$complete', name: FormOutcomeModel.COMPLETE_ACTION});
formComponent.showCompleteButton = true;
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
});
it('should not show [save] button with readOnly form ', () => {
let formModel = new FormModel();
formModel.readOnly = true;
formComponent.form = formModel;
let outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.SAVE_ACTION});
formComponent.showSaveButton = true;
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeFalsy();
});
it('should show [custom-outcome] button with readOnly form and selected custom-outcome', () => {
let formModel = new FormModel({selectedOutcome: 'custom-outcome'});
formModel.readOnly = true;
formComponent.form = formModel;
let outcome = new FormOutcomeModel(formModel, {id: '$customoutome', name: 'custom-outcome'});
formComponent.showCompleteButton = true;
formComponent.showSaveButton = true;
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
outcome = new FormOutcomeModel(formModel, {id: '$customoutome2', name: 'custom-outcome2'});
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeFalsy();
});
it('should allow controlling [save] button visibility', () => {
let formModel = new FormModel();
formModel.readOnly = false;
formComponent.form = formModel;
let outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.COMPLETE_ACTION});
formComponent.showCompleteButton = true;
expect(formComponent.isOutcomeButtonVisible(outcome)).toBeTruthy();
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy();
formComponent.showCompleteButton = false;
expect(formComponent.isOutcomeButtonVisible(outcome)).toBeFalsy();
expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeFalsy();
});
it('should load form on refresh', () => {
@@ -560,13 +601,6 @@ describe('ActivitiForm', () => {
expect(formService.completeTaskForm).not.toHaveBeenCalled();
});
it('should log error to console by default', () => {
const error = 'Error';
spyOn(console, 'log').and.stub();
formComponent.handleError(error);
expect(console.log).toHaveBeenCalledWith(error);
});
it('should complete form form and raise corresponding event', () => {
spyOn(formService, 'completeTaskForm').and.callFake(() => {
return Observable.create(observer => {
@@ -15,18 +15,13 @@
* limitations under the License.
*/
import {
Component,
OnInit, AfterViewChecked, OnChanges,
SimpleChanges,
Input,
Output,
EventEmitter
} from '@angular/core';
import { Component, OnInit, AfterViewChecked, OnChanges, SimpleChanges, Input, Output, EventEmitter } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
import { EcmModelService } from './../services/ecm-model.service';
import { FormService } from './../services/form.service';
import { NodeService } from './../services/node.service';
import { FormModel, FormOutcomeModel, FormValues, FormFieldModel, FormOutcomeEvent } from './widgets/core/index';
import { FormEvent, FormErrorEvent } from './../events/index';
import { WidgetVisibilityService } from './../services/widget-visibility.service';
@@ -85,6 +80,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
static SAVE_OUTCOME_ID: string = '$save';
static COMPLETE_OUTCOME_ID: string = '$complete';
static START_PROCESS_OUTCOME_ID: string = '$startProcess';
static CUSTOM_OUTCOME_ID: string = '$custom';
@Input()
@@ -129,6 +125,9 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
@Input()
showRefreshButton: boolean = true;
@Input()
showValidationIcon: boolean = true;
@Output()
formSaved: EventEmitter<FormModel> = new EventEmitter<FormModel>();
@@ -149,9 +148,10 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
debugMode: boolean = false;
constructor(protected formService: FormService,
public visibilityService: WidgetVisibilityService,
protected visibilityService: WidgetVisibilityService,
private ecmModelService: EcmModelService,
private nodeService: NodeService) {
private nodeService: NodeService,
private logService: LogService) {
}
hasForm(): boolean {
@@ -182,14 +182,20 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
return false;
}
isOutcomeButtonVisible(outcome: FormOutcomeModel): boolean {
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
if (outcome && outcome.name) {
if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) {
return this.showCompleteButton;
}
if (isFormReadOnly) {
return outcome.isSelected ;
}
if (outcome.name === FormOutcomeModel.SAVE_ACTION) {
return this.showSaveButton;
}
if (outcome.name === FormOutcomeModel.START_PROCESS_ACTION) {
return false;
}
return true;
}
return false;
@@ -252,15 +258,20 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
return true;
}
if (outcome.id === ActivitiForm.START_PROCESS_OUTCOME_ID) {
this.completeTaskForm();
return true;
}
if (outcome.id === ActivitiForm.CUSTOM_OUTCOME_ID) {
this.formSaved.emit(this.form);
this.onTaskSaved(this.form);
this.storeFormAsMetadata();
return true;
}
} else {
// Note: Activiti is using NAME field rather than ID for outcomes
if (outcome.name) {
this.formSaved.emit(this.form);
this.onTaskSaved(this.form);
this.completeTaskForm(outcome.name);
return true;
}
@@ -326,8 +337,8 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
.getTaskForm(taskId)
.subscribe(
form => {
this.form = new FormModel(form, data, this.readOnly);
this.formLoaded.emit(this.form);
this.form = new FormModel(form, data, this.readOnly, this.formService);
this.onFormLoaded(this.form);
},
(error) => {
this.handleError(error);
@@ -342,7 +353,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
form => {
this.formName = form.name;
this.form = this.parseForm(form);
this.formLoaded.emit(this.form);
this.onFormLoaded(this.form);
},
(error) => {
this.handleError(error);
@@ -357,9 +368,8 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
id => {
this.formService.getFormDefinitionById(id).subscribe(
form => {
// console.log('Get Form By Form definition Name', form);
this.form = this.parseForm(form);
this.formLoaded.emit(this.form);
this.onFormLoaded(this.form);
},
(error) => {
this.handleError(error);
@@ -378,12 +388,10 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
.saveTaskForm(this.form.taskId, this.form.values)
.subscribe(
() => {
this.formSaved.emit(this.form);
this.onTaskSaved(this.form);
this.storeFormAsMetadata();
},
(error) => {
this.handleError(error);
}
error => this.onTaskSavedError(this.form, error)
);
}
}
@@ -394,24 +402,22 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
.completeTaskForm(this.form.taskId, this.form.values, outcome)
.subscribe(
() => {
this.formCompleted.emit(this.form);
this.onTaskCompleted(this.form);
this.storeFormAsMetadata();
},
(error) => {
this.handleError(error);
}
error => this.onTaskCompletedError(this.form, error)
);
}
}
handleError(err: any): any {
console.log(err);
this.logService.error(err);
this.onError.emit(err);
}
parseForm(json: any): FormModel {
if (json) {
let form = new FormModel(json, this.data, this.readOnly);
let form = new FormModel(json, this.data, this.readOnly, this.formService);
if (!json.fields) {
form.outcomes = this.getFormDefinitionOutcomes(form);
}
@@ -427,7 +433,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
*/
getFormDefinitionOutcomes(form: FormModel): FormOutcomeModel[] {
return [
new FormOutcomeModel(form, {id: '$custom', name: FormOutcomeModel.SAVE_ACTION, isSystem: true})
new FormOutcomeModel(form, { id: '$custom', name: FormOutcomeModel.SAVE_ACTION, isSystem: true })
];
}
@@ -478,4 +484,29 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
);
}
}
protected onFormLoaded(form: FormModel) {
this.formLoaded.emit(form);
this.formService.formLoaded.next(new FormEvent(form));
}
protected onTaskSaved(form: FormModel) {
this.formSaved.emit(form);
this.formService.taskSaved.next(new FormEvent(form));
}
protected onTaskSavedError(form: FormModel, error: any) {
this.handleError(error);
this.formService.taskSavedError.next(new FormErrorEvent(form, error));
}
protected onTaskCompleted(form: FormModel) {
this.formCompleted.emit(form);
this.formService.taskCompleted.next(new FormEvent(form));
}
protected onTaskCompletedError(form: FormModel, error: any) {
this.handleError(error);
this.formService.taskCompletedError.next(new FormErrorEvent(form, error));
}
}
@@ -21,7 +21,7 @@
alfresco-mdl-button
[disabled]="!isOutcomeButtonEnabled(outcome)"
[class.mdl-button--colored]="!outcome.isSystem"
[class.activiti-form-hide-button]="!isOutcomeButtonVisible(outcome)"
[class.activiti-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
(click)="onOutcomeClicked(outcome, $event)">
{{outcome.name}}
</button>
@@ -41,7 +41,7 @@ describe('ActivitiStartForm', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CoreModule],
imports: [CoreModule.forRoot()],
declarations: [
ActivitiStartForm,
FormFieldComponent,
@@ -17,7 +17,8 @@
import {
Component,
AfterViewChecked, OnChanges,
AfterViewChecked,
OnChanges,
SimpleChanges,
Input,
ViewChild,
@@ -25,10 +26,11 @@ import {
Output,
EventEmitter
} from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
import { ActivitiForm } from './activiti-form.component';
import { FormService } from './../services/form.service';
import { WidgetVisibilityService } from './../services/widget-visibility.service';
import { FormOutcomeModel } from './widgets/core/index';
/**
* Displays the start form for a named process definition, which can be used to retrieve values to start a new process.
@@ -67,6 +69,9 @@ export class ActivitiStartForm extends ActivitiForm implements AfterViewChecked,
@Input()
showRefreshButton: boolean = true;
@Input()
readOnlyForm: boolean = false;
@Output()
outcomeClick: EventEmitter<any> = new EventEmitter<any>();
@@ -75,12 +80,15 @@ export class ActivitiStartForm extends ActivitiForm implements AfterViewChecked,
constructor(private translate: AlfrescoTranslationService,
formService: FormService,
visibilityService: WidgetVisibilityService) {
super(formService, visibilityService, null, null);
visibilityService: WidgetVisibilityService,
logService: LogService) {
super(formService, visibilityService, null, null, logService);
if (this.translate) {
this.translate.addTranslationFolder('ng2-activiti-form', 'node_modules/ng2-activiti-form/src');
}
this.showTitle = false;
}
ngOnChanges(changes: SimpleChanges) {
@@ -107,12 +115,11 @@ export class ActivitiStartForm extends ActivitiForm implements AfterViewChecked,
this.formName = form.name;
form.processDefinitionId = this.processDefinitionId;
this.form = this.parseForm(form);
this.form.readOnly = this.readOnlyForm;
// this.form.processDefinitionId = this.processDefinitionId;
this.formLoaded.emit(this.form);
},
(error) => {
this.handleError(error);
}
error => this.handleError(error)
);
}
@@ -123,15 +130,38 @@ export class ActivitiStartForm extends ActivitiForm implements AfterViewChecked,
form => {
this.formName = form.processDefinitionName;
this.form = this.parseForm(form);
this.form.readOnly = this.readOnlyForm;
this.formLoaded.emit(this.form);
},
(error) => {
this.handleError(error);
}
error => this.handleError(error)
);
}
/** @override */
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
if (outcome && outcome.isSystem && ( outcome.name === FormOutcomeModel.SAVE_ACTION ||
outcome.name === FormOutcomeModel.COMPLETE_ACTION )) {
return false;
} else if (outcome && outcome.name === FormOutcomeModel.START_PROCESS_ACTION) {
return true;
}
return super.isOutcomeButtonVisible(outcome, isFormReadOnly);
}
/** @override */
saveTaskForm() {
// do nothing
}
/** @override */
onRefreshClicked() {
if (this.processDefinitionId) {
this.visibilityService.cleanProcessVariable();
this.getStartFormDefinition(this.processDefinitionId);
} else if (this.processId) {
this.visibilityService.cleanProcessVariable();
this.loadStartForm(this.processId);
}
}
completeTaskForm(outcome?: string) {
@@ -16,6 +16,7 @@
*/
import { Observable } from 'rxjs/Rx';
import { LogServiceMock } from 'ng2-alfresco-core';
import { AttachWidget } from './attach.widget';
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
import { FormFieldModel } from './../core/form-field.model';
@@ -28,10 +29,12 @@ describe('AttachWidget', () => {
let widget: AttachWidget;
let contentService: ActivitiAlfrescoContentService;
let dialogPolyfill: any;
let logService: LogServiceMock;
beforeEach(() => {
contentService = new ActivitiAlfrescoContentService(null, null);
widget = new AttachWidget(contentService);
logService = new LogServiceMock();
contentService = new ActivitiAlfrescoContentService(null, logService);
widget = new AttachWidget(contentService, logService);
dialogPolyfill = {
registerDialog(obj: any) {
@@ -268,9 +271,9 @@ describe('AttachWidget', () => {
Observable.throw(error)
);
spyOn(console, 'log').and.stub();
spyOn(logService, 'error').and.stub();
widget.getExternalContentNodes();
expect(console.log).toHaveBeenCalledWith(error);
expect(logService.error).toHaveBeenCalledWith(error);
});
it('should register dialog via polyfill', () => {
@@ -16,6 +16,7 @@
*/
import { Component, OnInit, Input, Output, EventEmitter, ViewChild } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
import { WidgetComponent } from './../widget.component';
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
import { ExternalContent } from '../core/external-content';
@@ -49,7 +50,8 @@ export class AttachWidget extends WidgetComponent implements OnInit {
@ViewChild('dialog')
dialog: any;
constructor(private contentService: ActivitiAlfrescoContentService) {
constructor(private contentService: ActivitiAlfrescoContentService,
private logService: LogService) {
super();
}
@@ -97,7 +99,7 @@ export class AttachWidget extends WidgetComponent implements OnInit {
this.contentService.getAlfrescoNodes(this.selectedFolderAccountId, this.selectedFolderPathId)
.subscribe(
nodes => this.selectedFolderNodes = nodes,
error => this.handleError(error)
error => this.logService.error(error)
);
}
@@ -18,3 +18,7 @@
.container-widget__header-text.collapsible {
cursor: pointer;
}
.container-widget__mdl-grid {
align-items: center;
}
@@ -11,9 +11,9 @@
<span (click)="onExpanderClicked()" id="container-header-label">{{content.name}}</span>
</h4>
</div>
<div class="mdl-grid" [ngClass]="{'hidden':!(content?.isVisible && content?.isExpanded)}">
<div class="mdl-grid container-widget__mdl-grid" [ngClass]="{'hidden':!(content?.isVisible && content?.isExpanded)}">
<div *ngFor="let col of content.columns" class="mdl-cell mdl-cell--{{col.size}}-col">
<div class="mdl-grid" *ngIf="col.hasFields()">
<div class="mdl-grid container-widget__mdl-grid" *ngIf="col.hasFields()">
<div *ngFor="let field of col.fields" class="mdl-cell mdl-cell--12-col">
<form-field [field]="field"></form-field>
</div>
@@ -22,14 +22,17 @@ export class FormOutcomeModel extends FormWidgetModel {
static SAVE_ACTION: string = 'Save'; // Activiti 'Save' action name
static COMPLETE_ACTION: string = 'Complete'; // Activiti 'Complete' action name
static START_PROCESS_ACTION: string = 'Start Process'; // Activiti 'Start Process' action name
isSystem: boolean = false;
isSelected: boolean = false;
constructor(form: FormModel, json?: any) {
super(form, json);
if (json) {
this.isSystem = json.isSystem ? true : false;
this.isSelected = form && json.name === form.selectedOutcome ? true : false;
}
}
}
@@ -270,13 +270,16 @@ describe('FormModel', () => {
};
let form = new FormModel(json);
expect(form.outcomes.length).toBe(2);
expect(form.outcomes.length).toBe(3);
expect(form.outcomes[0].id).toBe(FormModel.SAVE_OUTCOME);
expect(form.outcomes[0].isSystem).toBeTruthy();
expect(form.outcomes[1].id).toBe(FormModel.COMPLETE_OUTCOME);
expect(form.outcomes[1].isSystem).toBeTruthy();
expect(form.outcomes[2].id).toBe(FormModel.START_PROCESS_OUTCOME);
expect(form.outcomes[2].isSystem).toBeTruthy();
});
it('should create outcomes only when fields available', () => {
@@ -23,12 +23,15 @@ import { FormOutcomeModel } from './form-outcome.model';
import { FormFieldModel } from './form-field.model';
import { FormFieldTypes } from './form-field-types';
import { FormFieldTemplates } from './form-field-templates';
import { FormService } from './../../../services/form.service';
import { FormFieldEvent } from './../../../events/index';
export class FormModel {
static UNSET_TASK_NAME: string = 'Nameless task';
static SAVE_OUTCOME: string = '$save';
static COMPLETE_OUTCOME: string = '$complete';
static START_PROCESS_OUTCOME: string = '$startProcess';
readonly id: string;
readonly name: string;
@@ -47,6 +50,7 @@ export class FormModel {
fields: FormWidgetModel[] = [];
outcomes: FormOutcomeModel[] = [];
customFieldTemplates: FormFieldTemplates = {};
readonly selectedOutcome: string;
values: FormValues = {};
@@ -64,7 +68,7 @@ export class FormModel {
return this.outcomes && this.outcomes.length > 0;
}
constructor(json?: any, data?: FormValues, readOnly: boolean = false) {
constructor(json?: any, data?: FormValues, readOnly: boolean = false, protected formService?: FormService) {
this.readOnly = readOnly;
if (json) {
@@ -76,6 +80,7 @@ export class FormModel {
this.taskName = json.taskName || json.name || FormModel.UNSET_TASK_NAME;
this.processDefinitionId = json.processDefinitionId;
this.customFieldTemplates = json.customFieldTemplates || {};
this.selectedOutcome = json.selectedOutcome || {};
let tabCache: FormWidgetModelCache<TabModel> = {};
@@ -103,11 +108,12 @@ export class FormModel {
if (json.fields) {
let saveOutcome = new FormOutcomeModel(this, { id: FormModel.SAVE_OUTCOME, name: 'Save', isSystem: true });
let completeOutcome = new FormOutcomeModel(this, {id: FormModel.COMPLETE_OUTCOME, name: 'Complete', isSystem: true });
let startProcessOutcome = new FormOutcomeModel(this, { id: FormModel.START_PROCESS_OUTCOME, name: 'Start Process', isSystem: true });
let customOutcomes = (json.outcomes || []).map(obj => new FormOutcomeModel(this, obj));
this.outcomes = [saveOutcome].concat(
customOutcomes.length > 0 ? customOutcomes : [completeOutcome]
customOutcomes.length > 0 ? customOutcomes : [completeOutcome, startProcessOutcome]
);
}
}
@@ -116,6 +122,9 @@ export class FormModel {
onFormFieldChanged(field: FormFieldModel) {
this.validateField(field);
if (this.formService) {
this.formService.formFieldValueChanged.next(new FormFieldEvent(this, field));
}
}
// TODO: consider evaluating and caching once the form is loaded
@@ -1,9 +1,21 @@
.date-widget {
width: 100%;
padding-top: 10px;
padding-bottom: 10px;
}
.date-widget--button {
margin-top: 15px;
margin-top: 10px;
}
.mdl-date__input{
padding-top: 5px;
padding-bottom: 5px;
}
.mdl-grid__date-widget{
align-items:center;
padding: 0px;
}
.date-widget__invalid .mdl-textfield__input {
@@ -21,3 +33,8 @@
.date-widget__invalid .mdl-textfield__error {
visibility: visible !important;
}
.date-widget-button__cell{
margin-top: 0px;
margin-bottom: 0px;
}
@@ -1,9 +1,9 @@
<div class="mdl-grid" *ngIf="field?.isVisible" id="data-widget">
<div class="mdl-grid mdl-grid__date-widget" *ngIf="field?.isVisible" id="data-widget">
<div class="mdl-cell mdl-cell--11-col">
<div class="mdl-textfield mdl-js-textfield date-widget"
[class.date-widget__invalid]="!field.isValid">
<label [attr.for]="field.id">{{field.name}}</label>
<input class="mdl-textfield__input"
<input class="mdl-textfield__input mdl-date__input"
type="text"
[attr.id]="field.id"
[attr.required]="isRequired()"
@@ -17,7 +17,7 @@
</div>
<div class="mdl-cell mdl-cell--1-col">
<button
class="mdl-button mdl-js-button mdl-button--icon date-widget--button"
class="mdl-button mdl-js-button mdl-button--icon"
(click)="datePicker.toggle()">
<i class="material-icons">date_range</i>
</button>
@@ -16,7 +16,7 @@
*/
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { CoreModule } from 'ng2-alfresco-core';
import { CoreModule, LogServiceMock } from 'ng2-alfresco-core';
import { Observable } from 'rxjs/Rx';
import { DisplayValueWidget } from './display-value.widget';
import { FormService } from '../../../services/form.service';
@@ -26,20 +26,19 @@ import { FormFieldTypes } from '../core/form-field-types';
import { FormModel } from '../core/form.model';
import { DynamicTableColumn, DynamicTableRow } from './../dynamic-table/dynamic-table.widget.model';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
import { AlfrescoSettingsService } from 'ng2-alfresco-core';
describe('DisplayValueWidget', () => {
let widget: DisplayValueWidget;
let formService: FormService;
let visibilityService: WidgetVisibilityService;
let settingsService: AlfrescoSettingsService;
let logService: LogServiceMock;
beforeEach(() => {
settingsService = new AlfrescoSettingsService();
formService = new FormService(null, null);
visibilityService = new WidgetVisibilityService(null);
widget = new DisplayValueWidget(formService, visibilityService, settingsService);
logService = new LogServiceMock();
formService = new FormService(null, null, logService);
visibilityService = new WidgetVisibilityService(null, logService);
widget = new DisplayValueWidget(formService, visibilityService, logService);
});
it('should require field to setup default value', () => {
@@ -393,7 +392,7 @@ describe('DisplayValueWidget', () => {
Observable.throw(error)
);
spyOn(console, 'log').and.stub();
spyOn(logService, 'error').and.stub();
let form = new FormModel({taskId: '<id>'});
@@ -409,7 +408,7 @@ describe('DisplayValueWidget', () => {
});
widget.ngOnInit();
expect(formService.getRestFieldValues).toHaveBeenCalled();
expect(console.log).toHaveBeenCalledWith(error);
expect(logService.error).toHaveBeenCalledWith(error);
expect(widget.value).toBe('100');
});
@@ -16,14 +16,14 @@
*/
import { Component, OnInit } from '@angular/core';
import * as moment from 'moment';
import { LogService } from 'ng2-alfresco-core';
import { WidgetComponent } from './../widget.component';
import { FormFieldTypes } from '../core/form-field-types';
import { FormService } from '../../../services/form.service';
import { FormFieldOption } from './../core/form-field-option';
import { DynamicTableColumn, DynamicTableRow } from './../dynamic-table/dynamic-table.widget.model';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
import { AlfrescoSettingsService } from 'ng2-alfresco-core';
import * as moment from 'moment';
@Component({
moduleId: module.id,
@@ -51,7 +51,7 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
constructor(private formService: FormService,
private visibilityService: WidgetVisibilityService,
private settingsService: AlfrescoSettingsService) {
private logService: LogService) {
super();
}
@@ -181,9 +181,10 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
} else {
this.value = this.field.value;
}
this.visibilityService.refreshVisibility(this.field.form);
},
error => {
console.log(error);
this.logService.error(error);
this.value = this.field.value;
}
);
@@ -202,9 +203,10 @@ export class DisplayValueWidget extends WidgetComponent implements OnInit {
} else {
this.value = this.field.value;
}
this.visibilityService.refreshVisibility(this.field.form);
},
error => {
console.log(error);
this.logService.error(error);
this.value = this.field.value;
}
);
@@ -1,9 +1,13 @@
.dropdown-widget {
width: 100%;
padding-top: 20px;
padding-bottom: 20px;
}
.dropdown-widget__select {
width: 100%;
margin-top: 5px;
margin-bottom: 5px;
}
.dropdown-widget__invalid .dropdown-widget__select {
@@ -15,14 +15,14 @@
* limitations under the License.
*/
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { Observable } from 'rxjs/Rx';
import { CoreModule } from 'ng2-alfresco-core';
import { FormService } from '../../../services/form.service';
import { DropdownWidget } from './dropdown.widget';
import { FormModel } from './../core/form.model';
import { FormFieldModel } from './../core/form-field.model';
import { FormFieldOption } from './../core/form-field-option';
import { CoreModule } from 'ng2-alfresco-core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { EcmModelService } from '../../../services/ecm-model.service';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
@@ -33,9 +33,9 @@ describe('DropdownWidget', () => {
let visibilityService: WidgetVisibilityService;
beforeEach(() => {
formService = new FormService(null, null);
visibilityService = new WidgetVisibilityService(null);
widget = new DropdownWidget(formService, visibilityService);
formService = new FormService(null, null, null);
visibilityService = new WidgetVisibilityService(null, null);
widget = new DropdownWidget(formService, visibilityService, null);
widget.field = new FormFieldModel(new FormModel());
});
@@ -74,12 +74,6 @@ describe('DropdownWidget', () => {
expect(formService.getRestFieldValues).toHaveBeenCalledWith(taskId, fieldId);
});
it('should log error to console by default', () => {
spyOn(console, 'error').and.stub();
widget.handleError('Err');
expect(console.error).toHaveBeenCalledWith('Err');
});
it('should preserve empty option when loading fields', () => {
let restFieldValue: FormFieldOption = <FormFieldOption> { id: '1', name: 'Option1' };
spyOn(formService, 'getRestFieldValues').and.returnValue(
@@ -16,6 +16,7 @@
*/
import { Component, OnInit } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
import { FormService } from '../../../services/form.service';
import { WidgetComponent } from './../widget.component';
import { FormFieldOption } from './../core/form-field-option';
@@ -30,7 +31,8 @@ import { WidgetVisibilityService } from '../../../services/widget-visibility.ser
export class DropdownWidget extends WidgetComponent implements OnInit {
constructor(private formService: FormService,
private visibilityService: WidgetVisibilityService) {
private visibilityService: WidgetVisibilityService,
private logService: LogService) {
super();
}
@@ -59,7 +61,7 @@ export class DropdownWidget extends WidgetComponent implements OnInit {
this.field.options = options.concat((result || []));
this.field.updateForm();
},
this.handleError
err => this.handleError(err)
);
}
@@ -78,7 +80,7 @@ export class DropdownWidget extends WidgetComponent implements OnInit {
this.field.options = options.concat((result || []));
this.field.updateForm();
},
this.handleError
err => this.handleError(err)
);
}
@@ -97,7 +99,7 @@ export class DropdownWidget extends WidgetComponent implements OnInit {
}
handleError(error: any) {
console.error(error);
this.logService.error(error);
}
}
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import { LogServiceMock } from 'ng2-alfresco-core';
import { DynamicTableWidget } from './dynamic-table.widget';
import { DynamicTableModel, DynamicTableRow, DynamicTableColumn } from './dynamic-table.widget.model';
import { FormModel, FormFieldTypes } from './../core/index';
@@ -25,11 +26,13 @@ describe('DynamicTableWidget', () => {
let widget: DynamicTableWidget;
let table: DynamicTableModel;
let visibilityService: WidgetVisibilityService;
let logService: LogServiceMock;
beforeEach(() => {
logService = new LogServiceMock();
table = new DynamicTableModel(null);
visibilityService = new WidgetVisibilityService(null);
widget = new DynamicTableWidget(null, visibilityService);
visibilityService = new WidgetVisibilityService(null, logService);
widget = new DynamicTableWidget(null, visibilityService, logService);
widget.content = table;
});
@@ -192,13 +195,13 @@ describe('DynamicTableWidget', () => {
});
it('should require table to save changes', () => {
spyOn(console, 'log').and.stub();
spyOn(logService, 'error').and.stub();
widget.editMode = true;
widget.content = null;
widget.onSaveChanges();
expect(widget.editMode).toBeFalsy();
expect(console.log).toHaveBeenCalledWith(widget.ERROR_MODEL_NOT_FOUND);
expect(logService.error).toHaveBeenCalledWith(widget.ERROR_MODEL_NOT_FOUND);
});
it('should cancel changes', () => {
@@ -16,6 +16,7 @@
*/
import { Component, ElementRef, OnInit } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
import { WidgetComponent } from './../widget.component';
import { DynamicTableModel, DynamicTableRow, DynamicTableColumn } from './dynamic-table.widget.model';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
@@ -36,7 +37,8 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
editRow: DynamicTableRow = null;
constructor(private elementRef: ElementRef,
private visibilityService: WidgetVisibilityService) {
private visibilityService: WidgetVisibilityService,
private logService: LogService) {
super();
}
@@ -136,7 +138,7 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit {
}
this.content.flushValue();
} else {
this.handleError(this.ERROR_MODEL_NOT_FOUND);
this.logService.error(this.ERROR_MODEL_NOT_FOUND);
}
this.editMode = false;
}
@@ -39,7 +39,7 @@ describe('DropdownEditorComponent', () => {
let row: DynamicTableRow;
beforeEach(() => {
formService = new FormService(null, null);
formService = new FormService(null, null, null);
row = <DynamicTableRow> { value: { dropdown: 'one' } };
column = <DynamicTableColumn> {
@@ -56,7 +56,7 @@ describe('DropdownEditorComponent', () => {
table.rows.push(row);
table.columns.push(column);
component = new DropdownEditorComponent(formService);
component = new DropdownEditorComponent(formService, null);
component.table = table;
component.row = row;
component.column = column;
@@ -16,6 +16,7 @@
*/
import { Component, Input, OnInit } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
import { DynamicTableModel, DynamicTableRow, DynamicTableColumn, DynamicTableColumnOption } from './../../dynamic-table.widget.model';
import { FormService } from './../../../../../services/form.service';
@@ -39,7 +40,9 @@ export class DropdownEditorComponent implements OnInit {
@Input()
column: DynamicTableColumn;
constructor(private formService: FormService) {}
constructor(private formService: FormService,
private logService: LogService) {
}
ngOnInit() {
let field = this.table.field;
@@ -98,6 +101,6 @@ export class DropdownEditorComponent implements OnInit {
}
handleError(error: any) {
console.error(error);
this.logService.error(error);
}
}
@@ -36,7 +36,7 @@ describe('FunctionalGroupWidget', () => {
]);
window['componentHandler'] = componentHandler;
formService = new FormService(null, null);
formService = new FormService(null, null, null);
elementRef = new ElementRef(null);
widget = new FunctionalGroupWidget(formService, elementRef);
widget.field = new FormFieldModel(new FormModel());
@@ -36,7 +36,7 @@ describe('PeopleWidget', () => {
]);
window['componentHandler'] = componentHandler;
formService = new FormService(null, null);
formService = new FormService(null, null, null);
elementRef = new ElementRef(null);
widget = new PeopleWidget(formService, elementRef);
widget.field = new FormFieldModel(new FormModel());
@@ -15,13 +15,14 @@
* limitations under the License.
*/
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { Observable } from 'rxjs/Rx';
import { CoreModule, LogServiceMock } from 'ng2-alfresco-core';
import { FormService } from '../../../services/form.service';
import { RadioButtonsWidget } from './radio-buttons.widget';
import { FormModel } from './../core/form.model';
import { FormFieldModel } from './../core/form-field.model';
import { CoreModule } from 'ng2-alfresco-core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { EcmModelService } from '../../../services/ecm-model.service';
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
import { FormFieldTypes } from '../core/form-field-types';
@@ -33,11 +34,13 @@ describe('RadioButtonsWidget', () => {
let formService: FormService;
let widget: RadioButtonsWidget;
let visibilityService: WidgetVisibilityService;
let logService: LogServiceMock;
beforeEach(() => {
formService = new FormService(null, null);
visibilityService = new WidgetVisibilityService(null);
widget = new RadioButtonsWidget(formService, visibilityService);
logService = new LogServiceMock();
formService = new FormService(null, null, logService);
visibilityService = new WidgetVisibilityService(null, logService);
widget = new RadioButtonsWidget(formService, visibilityService, logService);
widget.field = new FormFieldModel(new FormModel(), { restUrl: '<url>' });
});
@@ -118,12 +121,12 @@ describe('RadioButtonsWidget', () => {
});
it('should log error to console by default', () => {
spyOn(console, 'error').and.stub();
spyOn(logService, 'error').and.stub();
widget.handleError('Err');
expect(console.error).toHaveBeenCalledWith('Err');
expect(logService.error).toHaveBeenCalledWith('Err');
});
it('should update the field value when an option is selected', () => {
xit('should update the field value when an option is selected', () => {
spyOn(widget, 'checkVisibility').and.stub();
widget.onOptionClick('fake-opt');
@@ -16,6 +16,7 @@
*/
import { Component, OnInit } from '@angular/core';
import { LogService } from 'ng2-alfresco-core';
import { WidgetComponent } from './../widget.component';
import { FormService } from '../../../services/form.service';
import { FormFieldOption } from './../core/form-field-option';
@@ -30,7 +31,8 @@ import { WidgetVisibilityService } from '../../../services/widget-visibility.ser
export class RadioButtonsWidget extends WidgetComponent implements OnInit {
constructor(private formService: FormService,
private visibilityService: WidgetVisibilityService) {
private visibilityService: WidgetVisibilityService,
private logService: LogService) {
super();
}
@@ -55,7 +57,7 @@ export class RadioButtonsWidget extends WidgetComponent implements OnInit {
this.field.options = result || [];
this.field.updateForm();
},
this.handleError
err => this.handleError(err)
);
}
@@ -70,7 +72,7 @@ export class RadioButtonsWidget extends WidgetComponent implements OnInit {
this.field.options = result || [];
this.field.updateForm();
},
this.handleError
err => this.handleError(err)
);
}
@@ -84,7 +86,7 @@ export class RadioButtonsWidget extends WidgetComponent implements OnInit {
}
handleError(error: any) {
console.error(error);
this.logService.error(error);
}
}

Some files were not shown because too many files have changed in this diff Show More