From 4f3467e7a53b947ee33984068cbbf150273ce027 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Sat, 16 Jul 2016 22:32:16 +0100 Subject: [PATCH 01/18] webscript component viewer --- ng2-components/ng2-alfresco-core/package.json | 2 +- .../ng2-alfresco-datatable/package.json | 2 +- .../src/data/object-datatable-adapter.ts | 19 ++ .../ng2-alfresco-documentlist/package.json | 2 +- .../ng2-alfresco-login/package.json | 2 +- .../ng2-alfresco-search/package.json | 2 +- ng2-components/ng2-alfresco-upload/README.md | 4 +- .../ng2-alfresco-upload/package.json | 2 +- .../ng2-alfresco-viewer/package.json | 2 +- .../ng2-alfresco-webscript/.editorconfig | 23 ++ .../ng2-alfresco-webscript/.gitignore | 13 ++ .../ng2-alfresco-webscript/.travis.yml | 12 ++ ng2-components/ng2-alfresco-webscript/LICENSE | 13 ++ .../ng2-alfresco-webscript/README.md | 197 ++++++++++++++++++ .../assets/license_header.txt | 16 ++ .../ng2-alfresco-webscript/demo/.editorconfig | 10 + .../ng2-alfresco-webscript/demo/.gitignore | 6 + .../ng2-alfresco-webscript/demo/README.md | 19 ++ .../ng2-alfresco-webscript/demo/index.html | 39 ++++ .../ng2-alfresco-webscript/demo/package.json | 65 ++++++ .../ng2-alfresco-webscript/demo/src/main.ts | 115 ++++++++++ .../demo/systemjs.config.js | 57 +++++ .../ng2-alfresco-webscript/demo/tsconfig.json | 19 ++ .../ng2-alfresco-webscript/demo/tslint.json | 124 +++++++++++ .../ng2-alfresco-webscript/demo/typings.json | 7 + .../demo/wsrv-config.json | 5 + .../ng2-alfresco-webscript/index.ts | 32 +++ .../ng2-alfresco-webscript/karma-test-shim.js | 109 ++++++++++ .../ng2-alfresco-webscript/karma.conf.js | 91 ++++++++ .../ng2-alfresco-webscript/package.json | 92 ++++++++ .../AlfrescoSettingsService.service.mock.ts | 36 ++++ .../src/webscript.component.spec.ts | 194 +++++++++++++++++ .../src/webscript.component.ts | 178 ++++++++++++++++ .../ng2-alfresco-webscript/tsconfig.json | 27 +++ .../ng2-alfresco-webscript/tslint.json | 121 +++++++++++ .../ng2-alfresco-webscript/typings.json | 7 + 36 files changed, 1655 insertions(+), 9 deletions(-) create mode 100644 ng2-components/ng2-alfresco-webscript/.editorconfig create mode 100644 ng2-components/ng2-alfresco-webscript/.gitignore create mode 100644 ng2-components/ng2-alfresco-webscript/.travis.yml create mode 100644 ng2-components/ng2-alfresco-webscript/LICENSE create mode 100644 ng2-components/ng2-alfresco-webscript/README.md create mode 100644 ng2-components/ng2-alfresco-webscript/assets/license_header.txt create mode 100644 ng2-components/ng2-alfresco-webscript/demo/.editorconfig create mode 100644 ng2-components/ng2-alfresco-webscript/demo/.gitignore create mode 100644 ng2-components/ng2-alfresco-webscript/demo/README.md create mode 100644 ng2-components/ng2-alfresco-webscript/demo/index.html create mode 100644 ng2-components/ng2-alfresco-webscript/demo/package.json create mode 100644 ng2-components/ng2-alfresco-webscript/demo/src/main.ts create mode 100644 ng2-components/ng2-alfresco-webscript/demo/systemjs.config.js create mode 100644 ng2-components/ng2-alfresco-webscript/demo/tsconfig.json create mode 100644 ng2-components/ng2-alfresco-webscript/demo/tslint.json create mode 100644 ng2-components/ng2-alfresco-webscript/demo/typings.json create mode 100644 ng2-components/ng2-alfresco-webscript/demo/wsrv-config.json create mode 100644 ng2-components/ng2-alfresco-webscript/index.ts create mode 100644 ng2-components/ng2-alfresco-webscript/karma-test-shim.js create mode 100644 ng2-components/ng2-alfresco-webscript/karma.conf.js create mode 100644 ng2-components/ng2-alfresco-webscript/package.json create mode 100644 ng2-components/ng2-alfresco-webscript/src/assets/AlfrescoSettingsService.service.mock.ts create mode 100644 ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts create mode 100644 ng2-components/ng2-alfresco-webscript/src/webscript.component.ts create mode 100644 ng2-components/ng2-alfresco-webscript/tsconfig.json create mode 100644 ng2-components/ng2-alfresco-webscript/tslint.json create mode 100644 ng2-components/ng2-alfresco-webscript/typings.json diff --git a/ng2-components/ng2-alfresco-core/package.json b/ng2-components/ng2-alfresco-core/package.json index 4f8af8938e..52cbb6a668 100644 --- a/ng2-components/ng2-alfresco-core/package.json +++ b/ng2-components/ng2-alfresco-core/package.json @@ -18,7 +18,7 @@ "tsc:w": "tsc -w", "pretest": "npm run build", "test": "karma start karma.conf.js --reporters mocha,coverage --single-run", - "test-browser": "karma start karma.conf.js --reporters kjhtml ", + "test-browser": "npm run build && karma start karma.conf.js --reporters kjhtml ", "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", diff --git a/ng2-components/ng2-alfresco-datatable/package.json b/ng2-components/ng2-alfresco-datatable/package.json index 42631c6e4d..bf6963306d 100644 --- a/ng2-components/ng2-alfresco-datatable/package.json +++ b/ng2-components/ng2-alfresco-datatable/package.json @@ -18,7 +18,7 @@ "tsc:w": "tsc -w", "pretest": "npm run build", "test": "karma start karma.conf.js --reporters mocha,coverage --single-run", - "test-browser": "concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"", + "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", diff --git a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts index 3c538a2612..c860af09ea 100644 --- a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts +++ b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts @@ -32,6 +32,25 @@ export class ObjectDataTableAdapter implements DataTableAdapter { private _rows: DataRow[]; private _columns: DataColumn[]; + static generationSchema(rowToExaminate: any) { + let schema = []; + + if (typeof rowToExaminate === 'object') { + for (let key in rowToExaminate) { + if (rowToExaminate.hasOwnProperty(key)) { + schema.push({ + type: 'text', + key: key, + title: key, + sortable: false + }); + } + } + } + + return schema; + } + constructor(data: any[], schema: DataColumn[]) { this._rows = []; this._columns = []; diff --git a/ng2-components/ng2-alfresco-documentlist/package.json b/ng2-components/ng2-alfresco-documentlist/package.json index cfdbd6ecf8..3e6323f29b 100644 --- a/ng2-components/ng2-alfresco-documentlist/package.json +++ b/ng2-components/ng2-alfresco-documentlist/package.json @@ -17,7 +17,7 @@ "tsc:w": "tsc -w", "pretest": "npm run build", "test": "karma start karma.conf.js --reporters mocha,coverage --single-run", - "test-browser": "concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"", + "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", diff --git a/ng2-components/ng2-alfresco-login/package.json b/ng2-components/ng2-alfresco-login/package.json index f78c15c3f6..61b06efce8 100644 --- a/ng2-components/ng2-alfresco-login/package.json +++ b/ng2-components/ng2-alfresco-login/package.json @@ -17,7 +17,7 @@ "tsc:w": "tsc -w", "pretest": "npm run build", "test": "karma start karma.conf.js --reporters mocha,coverage --single-run", - "test-browser": "concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"", + "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", diff --git a/ng2-components/ng2-alfresco-search/package.json b/ng2-components/ng2-alfresco-search/package.json index 98c23331fc..5f575b8d21 100644 --- a/ng2-components/ng2-alfresco-search/package.json +++ b/ng2-components/ng2-alfresco-search/package.json @@ -17,7 +17,7 @@ "tsc:w": "tsc -w", "pretest": "npm run build", "test": "karma start karma.conf.js --reporters mocha,coverage --single-run", - "test-browser": "concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"", + "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", diff --git a/ng2-components/ng2-alfresco-upload/README.md b/ng2-components/ng2-alfresco-upload/README.md index 8509749e16..a86608e76d 100644 --- a/ng2-components/ng2-alfresco-upload/README.md +++ b/ng2-components/ng2-alfresco-upload/README.md @@ -53,7 +53,7 @@ This component, provide a buttons to upload files to alfresco. Add the following dependency to your index.html: ```html - + ``` The following component needs to be added to your systemjs.config: @@ -221,7 +221,7 @@ npm run build ##Build the files and keep watching for changes ```sh -$ npm run build:w +npm run build:w ``` ## Running unit tests diff --git a/ng2-components/ng2-alfresco-upload/package.json b/ng2-components/ng2-alfresco-upload/package.json index d05fdb5692..7dfe8fbac6 100644 --- a/ng2-components/ng2-alfresco-upload/package.json +++ b/ng2-components/ng2-alfresco-upload/package.json @@ -17,7 +17,7 @@ "tsc:w": "tsc -w", "pretest": "npm run build", "test": "karma start karma.conf.js --reporters mocha,coverage --single-run", - "test-browser": "concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"", + "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", diff --git a/ng2-components/ng2-alfresco-viewer/package.json b/ng2-components/ng2-alfresco-viewer/package.json index cecc281b1e..cd19111d33 100644 --- a/ng2-components/ng2-alfresco-viewer/package.json +++ b/ng2-components/ng2-alfresco-viewer/package.json @@ -17,7 +17,7 @@ "tsc:w": "tsc -w", "pretest": "npm run build", "test": "karma start karma.conf.js --reporters mocha,coverage --single-run", - "test-browser": "concurrently \"karma start karma.conf.js --reporters kjhtml\" \"npm run watch-task\"", + "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", diff --git a/ng2-components/ng2-alfresco-webscript/.editorconfig b/ng2-components/ng2-alfresco-webscript/.editorconfig new file mode 100644 index 0000000000..75a2477db7 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/.editorconfig @@ -0,0 +1,23 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[package.json] +indent_style = space +indent_size = 2 + +[karma.conf.js] +indent_style = space +indent_size = 2 + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/ng2-components/ng2-alfresco-webscript/.gitignore b/ng2-components/ng2-alfresco-webscript/.gitignore new file mode 100644 index 0000000000..3bea8a0c07 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/.gitignore @@ -0,0 +1,13 @@ +npm-debug.log +node_modules +jspm_packages +.idea +typings +coverage +src/**/*.js +src/**/*.js.map +src/**/*.d.ts +demo/**/*.js +demo/**/*.js.map +demo/**/*.d.ts +!systemjs.config.js diff --git a/ng2-components/ng2-alfresco-webscript/.travis.yml b/ng2-components/ng2-alfresco-webscript/.travis.yml new file mode 100644 index 0000000000..ab817d7644 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/.travis.yml @@ -0,0 +1,12 @@ +language: node_js +node_js: + - v5 + - v4 + - '0.12' + - '0.10' +install: npm install +sudo: false +after_success: + npm run coverage +# Send coverage data to Coveralls +after_script: "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js" diff --git a/ng2-components/ng2-alfresco-webscript/LICENSE b/ng2-components/ng2-alfresco-webscript/LICENSE new file mode 100644 index 0000000000..de3d8c60b8 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/LICENSE @@ -0,0 +1,13 @@ +Copyright 2016 Alfresco + +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. diff --git a/ng2-components/ng2-alfresco-webscript/README.md b/ng2-components/ng2-alfresco-webscript/README.md new file mode 100644 index 0000000000..29bb623a2b --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/README.md @@ -0,0 +1,197 @@ +# Alfresco Webscript Component for Angular 2 +

+ + travis
+    Status + + + travis
+    Status + + + Coverage Status + + + npm downloads + + + license + + + alfresco component + + + angular 2 + + + typescript + + + node version + +

+ +### Node +To correctly use this component check that on your machine is running Node version 5.0.0 or higher. + +## Install + +```sh +npm install --save ng2-alfresco-webscript +``` + +Components included: + +* Alfresco Webscript Component + +#### Dependencies + +Add the following dependency to your index.html: + +```html + +``` + +The following component needs to be added to your systemjs.config: + +- ng2-translate +- ng2-alfresco-core +- ng2-alfresco-datatable + +Please refer to the following example to have an idea of how your systemjs.config should look like : + +https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-alfresco-webscript/demo/systemjs.config.js + +#### Style +The style of this component is based on material design, so if you want to visualize it correctly you have to add the material +design dependency to your project: + +```sh +npm install --save material-design-icons material-design-lite +``` + +Also make sure you include these dependencies in your .html page: + +```html + + + + +``` + +#### Basic usage + + +```html + + + ``` + +Example of an App that use Alfresco webscript component : + +main.ts +```ts + +import { Component } from '@angular/core'; +import { bootstrap } from '@angular/platform-browser-dynamic'; +import { HTTP_PROVIDERS } from '@angular/http'; + +import { + ALFRESCO_CORE_PROVIDERS, + AlfrescoSettingsService, + AlfrescoAuthenticationService +} from 'ng2-alfresco-core'; + +import { WEBSCRIPTCOMPONENT } from 'ng2-alfresco-webscript'; + +@Component({ + selector: 'my-app', + template: ` + + `, + directives: [WEBSCRIPTCOMPONENT] +}) +export class AppComponent { + + scriptPath: string = 'sample/folder/Company%20Home'; + + contextRoot: string = 'alfresco'; + + servicePath: string = 'service'; + + constructor(public auth: AlfrescoAuthenticationService, + alfrescoSettingsService: AlfrescoSettingsService) { + alfrescoSettingsService.host = 'http://myalfrescoip'; + } +} + +bootstrap(AppComponent, [ + HTTP_PROVIDERS, + ALFRESCO_CORE_PROVIDERS +]); + +``` + +#### Options + +**scriptPath** {string} path to Web Script (as defined by Web Script) +**scriptArgs** {Object} arguments to pass to Web Script +**contextRoot** {string} path where application is deployed default value 'alfresco' +**servicePath** {string} path where Web Script service is mapped default value 'service' +**contentType** {string} how to handle the data received from te web script JSON | HTML | DATATABLE | TEXT + + +## Build from sources +Alternatively you can build component from sources with the following commands: + + +```sh +npm install +npm run build +``` + +##Build the files and keep watching for changes + +```sh +npm run build:w +``` + +## Running unit tests + +```sh +npm test +``` + +## Running unit tests in browser + +```sh +npm test-browser +``` + +This task rebuilds all the code, runs tslint, license checks and other quality check tools +before performing unit testing. + +## Code coverage + +```sh +npm run coverage +``` + +## Demo + +If you want have a demo of how the component works, please check the demo folder : + +```sh +cd demo +npm install +npm start +``` + diff --git a/ng2-components/ng2-alfresco-webscript/assets/license_header.txt b/ng2-components/ng2-alfresco-webscript/assets/license_header.txt new file mode 100644 index 0000000000..83fd1531a3 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/assets/license_header.txt @@ -0,0 +1,16 @@ +/*! + * @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. + */ \ No newline at end of file diff --git a/ng2-components/ng2-alfresco-webscript/demo/.editorconfig b/ng2-components/ng2-alfresco-webscript/demo/.editorconfig new file mode 100644 index 0000000000..8ed330c4a2 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/.editorconfig @@ -0,0 +1,10 @@ + +root = true + +[{src,scripts}/**.{ts,json,js}] +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 diff --git a/ng2-components/ng2-alfresco-webscript/demo/.gitignore b/ng2-components/ng2-alfresco-webscript/demo/.gitignore new file mode 100644 index 0000000000..6afdbb8367 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/.gitignore @@ -0,0 +1,6 @@ +typings/ +node_modules/ +.idea +dist/ +!systemjs.config.js +!browser-sync-config.js diff --git a/ng2-components/ng2-alfresco-webscript/demo/README.md b/ng2-components/ng2-alfresco-webscript/demo/README.md new file mode 100644 index 0000000000..28571bbab5 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/README.md @@ -0,0 +1,19 @@ +# ng2-alfresco-webscript - Demo + +* To install dependencies + +```sh +$ npm install +``` + +* To provide a live demo + +```sh +$ npm run start +``` + +* To clean npm_modules and typings folder + +```sh +$ npm run clean +``` diff --git a/ng2-components/ng2-alfresco-webscript/demo/index.html b/ng2-components/ng2-alfresco-webscript/demo/index.html new file mode 100644 index 0000000000..ec2facc018 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/index.html @@ -0,0 +1,39 @@ + + + + + Alfresco Angular 2 Web Script - Demo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ng2-components/ng2-alfresco-webscript/demo/package.json b/ng2-components/ng2-alfresco-webscript/demo/package.json new file mode 100644 index 0000000000..640456a54d --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/package.json @@ -0,0 +1,65 @@ +{ + "name": "ng2-alfresco-webscript-demo", + "description": "Alfresco Angular2 Viewer - Demo", + "version": "0.2.0", + "author": "Alfresco Software, Ltd.", + "main": "index.js", + "scripts": { + "clean": "rimraf dist node_modules typings", + "typings": "typings install", + "postinstall": "npm run typings && npm run build", + "start": "concurrently \"npm run build:w\" \"npm run server\" ", + "server": "wsrv -o -s -l", + "build": "npm run tslint && rimraf dist && tsc", + "build:w": "npm run tslint && rimraf dist && tsc -w", + "tslint": "npm run tslint-src && npm run tslint-root", + "tslint-src": "tslint -c tslint.json src/{,**/}**.ts", + "tslint-root": "tslint -c tslint.json *.ts" + }, + "license": "Apache-2.0", + "dependencies": { + "@angular/common": "2.0.0-rc.3", + "@angular/compiler": "2.0.0-rc.3", + "@angular/core": "2.0.0-rc.3", + "@angular/forms": "0.1.1", + "@angular/http": "2.0.0-rc.3", + "@angular/platform-browser": "2.0.0-rc.3", + "@angular/platform-browser-dynamic": "2.0.0-rc.3", + "@angular/router": "3.0.0-alpha.7", + "@angular/router-deprecated": "2.0.0-rc.2", + "@angular/upgrade": "2.0.0-rc.3", + "systemjs": "0.19.27", + "core-js": "2.4.0", + "reflect-metadata": "0.1.3", + "rxjs": "5.0.0-beta.6", + "zone.js": "0.6.12", + + "material-design-icons": "2.2.3", + "material-design-lite": "1.1.3", + + "alfresco-js-api": "^0.2.0", + + "ng2-translate": "2.2.2", + "ng2-alfresco-core": "^0.2.0", + "ng2-alfresco-datatable": "^0.2.0" + }, + "devDependencies": { + "concurrently": "2.0.0", + "rimraf": "2.5.2", + "tslint": "3.8.1", + "typescript": "1.8.10", + "typings": "1.0.4", + "wsrv": "0.1.3" + }, + "contributors": [ + { + "name": "Eugenio Romano", + "email": "eugenio.romano@alfresco.com" + } + ], + "keywords": [ + "angular2", + "typescript", + "alfresco" + ] +} diff --git a/ng2-components/ng2-alfresco-webscript/demo/src/main.ts b/ng2-components/ng2-alfresco-webscript/demo/src/main.ts new file mode 100644 index 0000000000..925344bdaf --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/src/main.ts @@ -0,0 +1,115 @@ +/*! + * @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, OnInit } from '@angular/core'; +import { bootstrap } from '@angular/platform-browser-dynamic'; +import { HTTP_PROVIDERS } from '@angular/http'; + +import { + ALFRESCO_CORE_PROVIDERS, + AlfrescoSettingsService, + AlfrescoAuthenticationService +} from 'ng2-alfresco-core'; + +import { WEBSCRIPTCOMPONENT } from 'ng2-alfresco-webscript'; + +@Component({ + selector: 'alfresco-webscript-demo', + template: ` +
+
+
+

+
+ Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid token to perform + operations. +
+
+
+
+
+
+
+
+
+ +
+ `, + directives: [WEBSCRIPTCOMPONENT] +}) +class WebscriptDemo implements OnInit { + + 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 = ''; + + token: string; + + constructor(private authService: AlfrescoAuthenticationService, + private alfrescoSettingsService: AlfrescoSettingsService) { + + alfrescoSettingsService.host = this.host; + if (this.authService.getTicket()) { + this.token = this.authService.getTicket(); + } + } + + public updateToken(): void { + localStorage.setItem('token', this.token); + } + + public updateHost(): void { + this.alfrescoSettingsService.host = this.host; + this.login(); + } + + ngOnInit() { + this.login(); + } + + login() { + this.authService.login('admin', 'admin', ['ECM']).subscribe( + token => { + console.log(token); + this.token = token; + this.authenticated = true; + }, + error => { + console.log(error); + this.authenticated = false; + }); + } +} + +bootstrap(WebscriptDemo, [ + HTTP_PROVIDERS, + ALFRESCO_CORE_PROVIDERS +]); diff --git a/ng2-components/ng2-alfresco-webscript/demo/systemjs.config.js b/ng2-components/ng2-alfresco-webscript/demo/systemjs.config.js new file mode 100644 index 0000000000..e55a9a592e --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/systemjs.config.js @@ -0,0 +1,57 @@ +/** + * System configuration for Angular 2 samples + * Adjust as necessary for your application needs. + */ +(function(global) { + // map tells the System loader where to look for things + var map = { + 'app': 'dist', // 'dist', + '@angular': 'node_modules/@angular', + 'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api', + 'rxjs': 'node_modules/rxjs', + + 'ng2-translate': 'node_modules/ng2-translate', + 'ng2-alfresco-core': 'node_modules/ng2-alfresco-core/dist', + 'ng2-alfresco-datatable': 'node_modules/ng2-alfresco-datatable/dist', + 'ng2-alfresco-webscript': 'node_modules/ng2-alfresco-webscript/dist' + }; + // packages tells the System loader how to load when no filename and/or no extension + var packages = { + 'app': { main: 'main.js', defaultExtension: 'js' }, + 'rxjs': { defaultExtension: 'js' }, + 'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' }, + + 'ng2-translate': { defaultExtension: 'js' }, + 'ng2-alfresco-core': { main: 'index.js', defaultExtension: 'js' }, + 'ng2-alfresco-datatable': { main: 'index.js', defaultExtension: 'js' }, + 'ng2-alfresco-webscript': { main: 'index.js', defaultExtension: 'js' } + }; + var ngPackageNames = [ + 'common', + 'compiler', + 'core', + 'http', + 'platform-browser', + 'platform-browser-dynamic', + 'router', + 'router-deprecated', + 'upgrade' + ]; + // Individual files (~300 requests): + function packIndex(pkgName) { + packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' }; + } + // Bundled (~40 requests): + function packUmd(pkgName) { + packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }; + } + // Most environments should use UMD; some (Karma) need the individual index files + var setPackageConfig = System.packageWithIndex ? packIndex : packUmd; + // Add package entries for angular packages + ngPackageNames.forEach(setPackageConfig); + var config = { + map: map, + packages: packages + }; + System.config(config); +})(this); diff --git a/ng2-components/ng2-alfresco-webscript/demo/tsconfig.json b/ng2-components/ng2-alfresco-webscript/demo/tsconfig.json new file mode 100644 index 0000000000..772c3a7e75 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "system", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "removeComments": true, + "declaration": true, + "outDir": "dist" + }, + "exclude": [ + "dist", + "node_modules", + "typings/main", + "typings/main.d.ts" + ] +} diff --git a/ng2-components/ng2-alfresco-webscript/demo/tslint.json b/ng2-components/ng2-alfresco-webscript/demo/tslint.json new file mode 100644 index 0000000000..8c48e76469 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/tslint.json @@ -0,0 +1,124 @@ +{ + "rules": { + "align": [ + true, + "parameters", + "arguments", + "statements" + ], + "ban": false, + "class-name": true, + "comment-format": [ + true, + "check-space", + "check-lowercase" + ], + "curly": true, + "eofline": true, + "forin": true, + "indent": [ + true, + "spaces" + ], + "interface-name": false, + "jsdoc-format": true, + "label-position": true, + "label-undefined": true, + "max-line-length": [ + true, + 140 + ], + "member-ordering": [ + true, + "public-before-private", + "static-before-instance", + "variables-before-functions" + ], + "no-any": false, + "no-arg": true, + "no-bitwise": true, + "no-conditional-assignment": true, + "no-consecutive-blank-lines": false, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-constructor-vars": false, + "no-debugger": true, + "no-duplicate-key": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-require-imports": true, + "no-shadowed-variable": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unreachable": true, + "no-unused-expression": true, + "no-unused-variable": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "no-var-requires": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "quotemark": [ + true, + "single", + "avoid-escape" + ], + "radix": true, + "semicolon": true, + "switch-default": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef": false, + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-strict": false, + "variable-name": [ + true, + "check-format", + "allow-leading-underscore", + "ban-keywords" + ], + "whitespace": [ + true, + "check-branch", + "check-operator", + "check-separator", + "check-type", + "check-module", + "check-decl" + ] + } +} diff --git a/ng2-components/ng2-alfresco-webscript/demo/typings.json b/ng2-components/ng2-alfresco-webscript/demo/typings.json new file mode 100644 index 0000000000..7e0e18568d --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/typings.json @@ -0,0 +1,7 @@ +{ + "globalDependencies": { + "core-js": "registry:dt/core-js#0.0.0+20160317120654", + "jasmine": "registry:dt/jasmine#2.2.0+20160505161446", + "node": "registry:dt/node#4.0.0+20160509154515" + } +} diff --git a/ng2-components/ng2-alfresco-webscript/demo/wsrv-config.json b/ng2-components/ng2-alfresco-webscript/demo/wsrv-config.json new file mode 100644 index 0000000000..a9365f9cb8 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/demo/wsrv-config.json @@ -0,0 +1,5 @@ +{ + "watch": [ + "node_modules/ng2-alfresco-datatable/dist/**/*.{html,htm,css,js}" + ] +} diff --git a/ng2-components/ng2-alfresco-webscript/index.ts b/ng2-components/ng2-alfresco-webscript/index.ts new file mode 100644 index 0000000000..9886c75274 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/index.ts @@ -0,0 +1,32 @@ +/*! + * @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 { WebscriptComponent } from './src/webscript.component'; + +/** + * ng2-alfresco-webscript, provide components get data from webscript and visualize in a table. + */ + +export * from './src/webscript.component'; + +export default { + components: [WebscriptComponent] +}; + +export const WEBSCRIPTCOMPONENT: [any] = [ + WebscriptComponent +]; diff --git a/ng2-components/ng2-alfresco-webscript/karma-test-shim.js b/ng2-components/ng2-alfresco-webscript/karma-test-shim.js new file mode 100644 index 0000000000..bffeaa9753 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/karma-test-shim.js @@ -0,0 +1,109 @@ +// Tun on full stack traces in errors to help debugging +Error.stackTraceLimit = Infinity; + +jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; + +__karma__.loaded = function() {}; + +var map = { + 'app': 'base/dist', + 'rxjs': 'base/node_modules/rxjs', + '@angular': 'base/node_modules/@angular', + 'ng2-translate' : '/base/node_modules/ng2-translate', + 'ng2-alfresco-core': '/base/node_modules/ng2-alfresco-core/dist', + 'ng2-alfresco-datatable': '/base/node_modules/ng2-alfresco-datatable/dist' +}; + +var packages = { + 'app': { main: 'main.js', defaultExtension: 'js' }, + 'rxjs': { defaultExtension: 'js' }, + 'ng2-translate': { defaultExtension: 'js' }, + 'ng2-alfresco-core': { main: 'index.js', defaultExtension: 'js' }, + 'ng2-alfresco-datatable': { main: 'index.js', defaultExtension: 'js' } +}; + +var packageNames = [ + '@angular/common', + '@angular/compiler', + '@angular/core', + '@angular/http', + '@angular/platform-browser', + '@angular/platform-browser-dynamic', + '@angular/router', + '@angular/router-deprecated', + '@angular/testing', + '@angular/upgrade' +]; + +packageNames.forEach(function(pkgName) { + packages[pkgName] = { main: 'index.js', defaultExtension: 'js' }; +}); + +packages['base/dist'] = { + defaultExtension: 'js', + format: 'register', + map: Object.keys(window.__karma__.files).filter(onlyAppFiles).reduce(createPathRecords, {}) +}; + +var config = { + map: map, + packages: packages +}; + +System.config(config); + +System.import('@angular/platform-browser/src/browser/browser_adapter') + .then(function(browser_adapter) { browser_adapter.BrowserDomAdapter.makeCurrent(); }) + .then(function () { + return Promise.all([ + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ]) + }) + .then(function (providers) { + var testing = providers[0]; + var testingBrowser = providers[1]; + + testing.setBaseTestProviders( + testingBrowser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, + testingBrowser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS); + + }) + .then(function() { return Promise.all(resolveTestFiles()); }) + .then( + function() { + __karma__.start(); + }, + function(error) { + if(typeof __karma__.error == 'function') { + __karma__.error(error.stack || error); + }else{ + console.error(error); + } + } + ); +function createPathRecords(pathsMapping, appPath) { + var pathParts = appPath.split('/'); + var moduleName = './' + pathParts.slice(Math.max(pathParts.length - 2, 1)).join('/'); + moduleName = moduleName.replace(/\.js$/, ''); + pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]; + return pathsMapping; +} + +function onlyAppFiles(filePath) { + return /\/base\/dist\/(?!.*\.spec\.js$).*\.js$/.test(filePath); +} + +function onlySpecFiles(path) { + return /\.spec\.js$/.test(path); +} + +function resolveTestFiles() { + return Object.keys(window.__karma__.files) // All files served by Karma. + .filter(onlySpecFiles) + .map(function(moduleName) { + // loads all spec files via their global module names (e.g. + // 'base/dist/vg-player/vg-player.spec') + return System.import(moduleName); + }); +} diff --git a/ng2-components/ng2-alfresco-webscript/karma.conf.js b/ng2-components/ng2-alfresco-webscript/karma.conf.js new file mode 100644 index 0000000000..2db4427f82 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/karma.conf.js @@ -0,0 +1,91 @@ +'use strict'; + +module.exports = function (config) { + config.set({ + + basePath: '.', + + frameworks: ['jasmine-ajax', 'jasmine'], + + files: [ + // paths loaded by Karma + {pattern: 'node_modules/reflect-metadata/Reflect.js', included: true, watched: true}, + {pattern: 'node_modules/systemjs/dist/system.src.js', included: true, watched: false}, + {pattern: 'node_modules/zone.js/dist/zone.js', included: true, watched: true}, + {pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false}, + {pattern: 'node_modules/rxjs/**/*.map', included: false, watched: false}, + {pattern: 'node_modules/@angular/**/*.js', included: false, watched: false}, + {pattern: 'node_modules/@angular/**/*.map', included: false, watched: false}, + {pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false}, + {pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.js', included: false, served: true, watched: false}, + {pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.html', included: false, served: true, watched: false}, + {pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.css', included: false, served: true, watched: false}, + {pattern: 'node_modules/ng2-translate/**/*.js', included: false, served: true, watched: false}, + {pattern: 'node_modules/alfresco-js-api/dist/alfresco-js-api.js', included: true, watched: false}, + + {pattern: 'karma-test-shim.js', included: true, watched: true}, + + // paths loaded via module imports + {pattern: 'dist/**/*.js', included: false, watched: true}, + {pattern: 'dist/**/*.html', included: true, served: true, watched: true}, + {pattern: 'dist/**/*.css', included: true, served: true, watched: true}, + + // paths to support debugging with source maps in dev tools + {pattern: 'src/**/*.ts', included: false, watched: false}, + {pattern: 'dist/**/*.js.map', included: false, watched: false} + ], + + // proxied base paths + proxies: { + // required for component assets fetched by Angular's compiler + '/src/': '/base/src/' + }, + + // list of files to exclude + exclude: [ + 'node_modules/**/*spec.js' + ], + + port: 9876, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + colors: true, + + autoWatch: true, + + browsers: ['Chrome'], + + // Karma plugins loaded + plugins: [ + 'karma-jasmine', + 'karma-coverage', + 'karma-jasmine-ajax', + 'karma-chrome-launcher', + 'karma-mocha-reporter', + 'karma-jasmine-html-reporter' + ], + + // Coverage reporter generates the coverage + reporters: ['mocha', 'coverage', 'kjhtml'], + + // Source files that you wanna generate coverage for. + // Do not include tests or libraries (these files will be instrumented by Istanbul) + preprocessors: { + 'dist/**/!(*spec).js': ['coverage'] + }, + + coverageReporter: { + dir: 'coverage/', + subdir: 'report', + reporters: [ + {type: 'text'}, + {type: 'text-summary'}, + {type: 'json', file: 'coverage-final.json'}, + {type: 'html'} + ] + } + }) +}; diff --git a/ng2-components/ng2-alfresco-webscript/package.json b/ng2-components/ng2-alfresco-webscript/package.json new file mode 100644 index 0000000000..811f7c9aff --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/package.json @@ -0,0 +1,92 @@ +{ + "name": "ng2-alfresco-webscript", + "description": "webscript executor", + "version": "0.1.0", + "author": "Alfresco Software, Ltd.", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "scripts": { + "postinstall": "typings install", + "clean": "rimraf dist node_modules typings", + "typings": "typings install", + "build": "npm run tslint && rimraf dist && tsc && npm run copy-dist && license-check", + "build:w": "npm run tslint && rimraf dist && npm run watch-task", + "watch-task": "concurrently \"npm run tsc:w\" \"npm run copy-dist:w\" \"license-check\"", + "tslint": "tslint -c tslint.json *.ts && tslint -c tslint.json src/{,**/}**.ts", + "copy-dist": "cpx \"./src/**/*.{html,css,json,png,jpg,gif,svg}\" ./dist/src", + "copy-dist:w": "cpx \"./src/**/*.{html,css,json,png,jpg,gif,svg}\" ./dist/src -w", + "tsc": "tsc", + "tsc:w": "tsc -w", + "pretest": "npm run build", + "test": "karma start karma.conf.js --reporters mocha,coverage --single-run", + "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", + "travis": "echo 'placeholder'" + }, + "repository": { + "type": "git", + "url": "https://github.com/Alfresco/alfresco-ng2-components.git" + }, + "bugs": { + "url": "https://github.com/Alfresco/alfresco-ng2-components/issues" + }, + "dependencies": { + "@angular/common": "2.0.0-rc.3", + "@angular/compiler": "2.0.0-rc.3", + "@angular/core": "2.0.0-rc.3", + "@angular/http": "2.0.0-rc.3", + "@angular/platform-browser": "2.0.0-rc.3", + "@angular/platform-browser-dynamic": "2.0.0-rc.3", + "@angular/router": "3.0.0-alpha.7", + "@angular/router-deprecated": "2.0.0-rc.2", + "@angular/upgrade": "2.0.0-rc.3", + "systemjs": "0.19.27", + "core-js": "^2.4.0", + "alfresco-js-api": "^0.2.0", + + "ng2-translate": "2.2.2", + "ng2-alfresco-core": "^0.2.0", + "ng2-alfresco-datatable": "^0.2.0", + "reflect-metadata": "^0.1.3", + "rxjs": "5.0.0-beta.6", + "zone.js": "^0.6.12" + }, + "devDependencies": { + "concurrently": "^2.1.0", + "coveralls": "^2.11.9", + "cpx": "^1.3.1", + "jasmine-ajax": "^3.2.0", + "jasmine-core": "2.4.1", + "karma": "~0.13.22", + "karma-chrome-launcher": "~1.0.1", + "karma-coverage": "^1.0.0", + "karma-jasmine": "~1.0.2", + "karma-jasmine-ajax": "^0.1.13", + "karma-jasmine-html-reporter": "^0.2.0", + "karma-mocha-reporter": "^2.0.3", + "license-check": "^1.0.4", + "remap-istanbul": "^0.6.3", + "rimraf": "2.5.2", + "traceur": "^0.0.91", + "tslint": "^3.8.1", + "typescript": "^1.8.10", + "typings": "^1.0.4", + "wsrv": "0.1.3" + }, + "keywords": [ + "webscript", + "alfresco-component" + ], + "license-check-config": { + "src": [ + "./dist/**/*.js" + ], + "path": "assets/license_header.txt", + "blocking": false, + "logInfo": false, + "logError": true + }, + "license": "Apache-2.0" +} diff --git a/ng2-components/ng2-alfresco-webscript/src/assets/AlfrescoSettingsService.service.mock.ts b/ng2-components/ng2-alfresco-webscript/src/assets/AlfrescoSettingsService.service.mock.ts new file mode 100644 index 0000000000..593b36c19f --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/src/assets/AlfrescoSettingsService.service.mock.ts @@ -0,0 +1,36 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; + +@Injectable() +export class AlfrescoSettingsServiceMock { + + static DEFAULT_HOST_ADDRESS: string = 'fakehost'; + + private providers: string[] = ['ECM', 'BPM']; + + private _host: string = AlfrescoSettingsServiceMock.DEFAULT_HOST_ADDRESS; + + public get host(): string { + return this._host; + } + + getProviders(): string [] { + return this.providers; + } +} diff --git a/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts b/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts new file mode 100644 index 0000000000..0789bda90a --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts @@ -0,0 +1,194 @@ +/*! + * @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 { describe, expect, it, inject, beforeEachProviders, beforeEach, afterEach } from '@angular/core/testing'; +import { TestComponentBuilder } from '@angular/compiler/testing'; +import { WebscriptComponent } from '../src/webscript.component'; +import { AlfrescoSettingsServiceMock } from '../src/assets/AlfrescoSettingsService.service.mock'; +import { HTTP_PROVIDERS } from '@angular/http'; + +import { AlfrescoAuthenticationService, AlfrescoSettingsService } from 'ng2-alfresco-core'; + +declare let jasmine: any; + +describe('Test ng2-alfresco-webscript', () => { + + let webscriptComponentFixture; + + beforeEachProviders(() => { + return [ + HTTP_PROVIDERS, + {provide: AlfrescoSettingsService, useClass: AlfrescoSettingsServiceMock}, + {provide: AlfrescoAuthenticationService, useClass: AlfrescoAuthenticationService} + ]; + }); + + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + return tcb + .createAsync(WebscriptComponent) + .then(fixture => webscriptComponentFixture = fixture); + })); + + describe('View', () => { + it('webscript html wrapper should be present', () => { + let element = webscriptComponentFixture.nativeElement; + expect(element.querySelector('#webscript-html-wrapper')).toBeDefined(); + }); + + it('webscript JSON datatable wrapper should be present', () => { + let element = webscriptComponentFixture.nativeElement; + expect(element.querySelector('#webscript-json-wrapper')).toBeDefined(); + }); + + it('webscript plain text datatable wrapper should be present', () => { + let element = webscriptComponentFixture.nativeElement; + expect(element.querySelector('#webscript-plaintext-wrapper')).toBeDefined(); + }); + }); + + describe('Content tests', () => { + + beforeEach(() => { + jasmine.Ajax.install(); + }); + + afterEach(() => { + jasmine.Ajax.uninstall(); + }); + + it('webscript url should be the one configured by the input param', (done) => { + let component = webscriptComponentFixture.componentInstance; + component.scriptPath = 'sample/folder/Company%20Home'; + + component.ngOnChanges().then(() => { + webscriptComponentFixture.detectChanges(); + let request = jasmine.Ajax.requests.mostRecent(); + expect(request.url).toBe('fakehost/alfresco/service/sample/folder/Company%20Home'); + done(); + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'text/plain', + responseText: '
' + }); + }); + + it('webscript TEXT response should be displayed', (done) => { + let component = webscriptComponentFixture.componentInstance; + let element = webscriptComponentFixture.nativeElement; + + component.scriptPath = 'sample/folder/Company%20Home'; + component.contentType = 'TEXT'; + + component.ngOnChanges().then(() => { + webscriptComponentFixture.detectChanges(); + expect(element.querySelector('#webscript-data').innerHTML) + .toBe('text test'); + done(); + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'text/html', + responseText: 'text test' + }); + }); + + it('webscript JSON response should be displayed', (done) => { + let component = webscriptComponentFixture.componentInstance; + let element = webscriptComponentFixture.nativeElement; + + component.scriptPath = 'sample/folder/Company%20Home'; + component.contentType = 'JSON'; + + component.ngOnChanges().then(() => { + webscriptComponentFixture.detectChanges(); + expect(element.querySelector('#webscript-data').innerHTML) + .toBe('{"0":{"id":1,"name":"Name 1"},"1":{"id":2,"name":"Name 2"}}'); + done(); + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: [{id: 1, name: 'Name 1'}, + {id: 2, name: 'Name 2'}] + }); + }); + + it('webscript HTML response should be displayed', (done) => { + let component = webscriptComponentFixture.componentInstance; + let element = webscriptComponentFixture.nativeElement; + + component.scriptPath = 'sample/folder/Company%20Home'; + component.contentType = 'HTML'; + + component.ngOnChanges().then(() => { + webscriptComponentFixture.detectChanges(); + expect(element.querySelector('#webscript-data').innerHTML) + .toBe(''); + done(); + }); + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'text/html', + responseText: '' + }); + }); + + it('webscript Datatable response should be displayed', (done) => { + let component = webscriptComponentFixture.componentInstance; + let element = webscriptComponentFixture.nativeElement; + + component.scriptPath = 'sample/folder/Company%20Home'; + component.contentType = 'DATATABLE'; + + component.ngOnChanges().then(() => { + webscriptComponentFixture.detectChanges(); + expect(element.querySelector('#webscript-datatable-wrapper').innerHTML) + .toBe(''); + done(); + }); + + let dataTable = { + data: [ + {id: 1, name: 'Name 1'}, + {id: 2, name: 'Name 2'} + ], + schema: [{ + type: 'text', + key: 'id', + title: 'Id', + sortable: true + }, { + type: 'text', + key: 'name', + title: 'Name', + sortable: true + }] + }; + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: dataTable + }); + }); + }); +}); diff --git a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts new file mode 100644 index 0000000000..042681855d --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts @@ -0,0 +1,178 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, Input } from '@angular/core'; +import { + ALFRESCO_DATATABLE_DIRECTIVES, + ObjectDataTableAdapter +} from 'ng2-alfresco-datatable'; + +import { + AlfrescoAuthenticationService +} from 'ng2-alfresco-core'; + +/** + * + * + * + * This component, provide a get webscript viewer + * + * @InputParam {string} scriptPath path to Web Script (as defined by Web Script) + * @InputParam {Object} scriptArgs arguments to pass to Web Script + * @InputParam {string} contextRoot path where application is deployed default value 'alfresco' + * @InputParam {string} servicePath path where Web Script service is mapped default value 'service' + * @InputParam {string} contentType JSON | HTML | DATATABLE | TEXT + * + * @returns {WebscriptComponent} . + */ +@Component({ + selector: 'alfresco-webscript-get', + template: ` +
+
+
Error during the deserialization of {{data}} as {{contentType}}
`, + directives: [ALFRESCO_DATATABLE_DIRECTIVES] +}) +export class WebscriptComponent { + + @Input() + scriptPath: string; + + @Input() + scriptArgs: any; + + @Input() + contextRoot: string = 'alfresco'; + + @Input() + servicePath: string = 'service'; + + @Input() + contentType: string = 'TEXT'; + + data: any = undefined; + + show: boolean = false; + + /** + * Constructor + * @param auth + */ + constructor(public authService: AlfrescoAuthenticationService) { + + } + + ngOnChanges(changes) { + this.clean(); + + return new Promise((resolve, reject) => { + this.authService.getAlfrescoApi().webScript.executeWebScript('GET', this.scriptPath, this.scriptArgs, this.contextRoot, this.servicePath).then((data) => { + if (this.contentType === 'JSON') { + this.show = this.showDataAsJSON(data); + } else if (this.contentType === 'DATATABLE') { + this.show = this.showDataAsDataTable(data); + } else { + this.show = this.showDataAsHTML(data); + } + resolve(); + }, function (error) { + console.log('Error' + error); + reject(); + }); + }); + } + + /** + * Parserize and show the data id data is a JSON + * + * @param data + * + * @retutns boolean true if the component is able to Show the data as JSON + */ + showDataAsJSON(data: any) { + let jsonShow = true; + try { + this.data = JSON.stringify(data); + let wrapper = document.getElementById('webscript-data'); + wrapper.innerHTML = this.data; + } catch (e) { + jsonShow = false; + } + + return jsonShow; + } + + /** + * Parserize and show the data id data is a html/xml + * + * @param data + * + * @retutns boolean true if the component is able to Show the data as html/xml + */ + showDataAsHTML(data: any) { + let htmlShow = false; + let domParser = new DOMParser(); + + if (domParser.parseFromString(data, 'text/xml')) { + let wrapper = document.getElementById('webscript-data'); + wrapper.innerHTML = data; + this.data = data; + htmlShow = true; + } + + return htmlShow; + } + + /** + * show the data in a ng2-alfresco-datatable + * + * @param data + * + * @retutns boolean true if the component is able to Show the data as datatable + */ + showDataAsDataTable(data: any) { + let datatableShow = true; + try { + if (!data.schema) { + data.schema = ObjectDataTableAdapter.generationSchema(data[0]); + } + if (data.schema && data.schema.length > 0) { + this.data = new ObjectDataTableAdapter(data.data, data.schema); + } else { + datatableShow = false; + } + } catch (e) { + datatableShow = false; + } + + return datatableShow; + } + + clean() { + let wrapper = document.getElementById('webscript-data'); + wrapper.innerHTML = ''; + this.data = undefined; + } + + isDataTableCOntent() { + return this.contentType === 'DATATABLE' && this.show; + } +} diff --git a/ng2-components/ng2-alfresco-webscript/tsconfig.json b/ng2-components/ng2-alfresco-webscript/tsconfig.json new file mode 100644 index 0000000000..e4d2ae201a --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "system", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "removeComments": true, + "declaration": true, + "noLib": false, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "noImplicitAny": false, + "noImplicitReturns": false, + "noImplicitUseStrict": false, + "noFallthroughCasesInSwitch": true, + "outDir": "dist" + }, + "exclude": [ + "demo", + "node_modules", + "typings/main", + "typings/main.d.ts", + "dist" + ] +} diff --git a/ng2-components/ng2-alfresco-webscript/tslint.json b/ng2-components/ng2-alfresco-webscript/tslint.json new file mode 100644 index 0000000000..ba706079f4 --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/tslint.json @@ -0,0 +1,121 @@ +{ + "rules": { + "align": [ + true, + "parameters", + "statements" + ], + "ban": false, + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "eofline": true, + "forin": true, + "indent": [ + true, + "spaces" + ], + "interface-name": false, + "jsdoc-format": true, + "label-position": true, + "label-undefined": true, + "max-line-length": [ + true, + 180 + ], + "member-ordering": [ + true, + "static-before-instance", + "variables-before-functions" + ], + "no-any": false, + "no-arg": true, + "no-bitwise": false, + "no-conditional-assignment": true, + "no-consecutive-blank-lines": false, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-constructor-vars": false, + "no-debugger": true, + "no-duplicate-key": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-inferrable-types": false, + "no-internal-module": true, + "no-require-imports": true, + "no-shadowed-variable": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unreachable": true, + "no-unused-expression": true, + "no-unused-variable": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "no-var-requires": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "quotemark": [ + true, + "single", + "avoid-escape" + ], + "radix": true, + "semicolon": true, + "switch-default": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef": false, + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "use-strict": false, + "variable-name": [ + true, + "check-format", + "allow-leading-underscore", + "ban-keywords" + ], + "whitespace": [ + true, + "check-branch", + "check-operator", + "check-separator", + "check-type", + "check-module", + "check-decl" + ] + } +} diff --git a/ng2-components/ng2-alfresco-webscript/typings.json b/ng2-components/ng2-alfresco-webscript/typings.json new file mode 100644 index 0000000000..7e0e18568d --- /dev/null +++ b/ng2-components/ng2-alfresco-webscript/typings.json @@ -0,0 +1,7 @@ +{ + "globalDependencies": { + "core-js": "registry:dt/core-js#0.0.0+20160317120654", + "jasmine": "registry:dt/jasmine#2.2.0+20160505161446", + "node": "registry:dt/node#4.0.0+20160509154515" + } +} From 90a4ef03699d68636fb64ffd39277ccb9d316463 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 18 Jul 2016 14:49:50 +0100 Subject: [PATCH 02/18] improve documentation and test --- README.md | 1 + ng2-components/README.md | 1 + .../ng2-alfresco-webscript/README.md | 106 +++++++++++++++++- .../ng2-alfresco-webscript/demo/src/main.ts | 16 ++- .../docs/assets/HTML.png | Bin 0 -> 68993 bytes .../docs/assets/datatable.png | Bin 0 -> 22360 bytes .../ng2-alfresco-webscript/karma.conf.js | 1 + .../ng2-alfresco-webscript/package.json | 4 + .../src/webscript.component.spec.ts | 30 ++++- .../src/webscript.component.ts | 31 +++-- 10 files changed, 171 insertions(+), 19 deletions(-) create mode 100644 ng2-components/ng2-alfresco-webscript/docs/assets/HTML.png create mode 100644 ng2-components/ng2-alfresco-webscript/docs/assets/datatable.png diff --git a/README.md b/README.md index a8f9444e61..3d2a490a25 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ The following is a list of some of the components that you can use when building - [Viewer](ng2-components/ng2-alfresco-viewer/README.md) - [Login](ng2-components/ng2-alfresco-login/README.md) - [Upload](ng2-components/ng2-alfresco-upload/README.md) +- [Webscript viewer](ng2-components/ng2-alfresco-webscript/README.md) You can browse all the components at the following [page](http://devproducts.alfresco.com/). diff --git a/ng2-components/README.md b/ng2-components/README.md index bffb887a03..4f2098a0a9 100644 --- a/ng2-components/README.md +++ b/ng2-components/README.md @@ -35,6 +35,7 @@ - [Viewer](ng2-alfresco-viewer/README.md) - [Login](ng2-alfresco-login/README.md) - [Upload](ng2-alfresco-upload/README.md) +- [Webscript viewer](ng2-components/ng2-alfresco-webscript/README.md) You can browse all the components at the following address: diff --git a/ng2-components/ng2-alfresco-webscript/README.md b/ng2-components/ng2-alfresco-webscript/README.md index 29bb623a2b..02b5d608b5 100644 --- a/ng2-components/ng2-alfresco-webscript/README.md +++ b/ng2-components/ng2-alfresco-webscript/README.md @@ -87,7 +87,8 @@ Also make sure you include these dependencies in your .html page: [scriptArgs]="Object" [contextRoot]="string" [servicePath]="string" - [contentType]="JSON | HTML | DATATABLE | TEXT"> + [contentType]="JSON | HTML | DATATABLE | TEXT" + (onSuccess)= "logData($event)"> ``` @@ -147,12 +148,111 @@ bootstrap(AppComponent, [ **contextRoot** {string} path where application is deployed default value 'alfresco' **servicePath** {string} path where Web Script service is mapped default value 'service' **contentType** {string} how to handle the data received from te web script JSON | HTML | DATATABLE | TEXT +***data*** {string} data contain the plain value get from the webscipt is an output parameter + +## Webscript View HTML example +This sample demonstrates how to implement a Webscript component that renders the HTML contents that come from a webscript +This sample Web Scripts reside in your Alfresco Server AND you can access the folder webscript here: + +http://localhost:8080/alfresco/service/sample/folder/Company%20Home +```html + + +``` + +![Custom columns](docs/assets/HTML.png) + +## Webscript View DATATABLE example +This sample demonstrates how to implement a Webscript component that renders the JSON contents that come from a webscript + +http://localhost:8080/alfresco/service/sample/folder/DATATABLE + +```html + + +``` + +If you want show the result from a webscript inside a ng2-alfresco-datatable you have to return from the GET of the webscript the datatructure below: +subdivide in data and schema + +```ts +data: [], +schema: [] +``` + +this is an example: + +```ts +data: [ + {id: 1, name: 'Name 1'}, + {id: 2, name: 'Name 2'} +], +schema: [{ + type: 'text', + key: 'id', + title: 'Id', + sortable: true +}, { + type: 'text', + key: 'name', + title: 'Name', + sortable: true +}] +``` + +or you can send just the array data and the component will create a schema for you: + +```ts +data: [ + {id: 1, name: 'Name 1'}, + {id: 2, name: 'Name 2'} +]] +``` + +that will render the follow table + +![Custom columns](docs/assets/datatable.png) + + +## Webscript View JSON example +This sample demonstrates how to implement a Webscript component that renders the JSON contents that come from a webscript +This sample Web Scripts reside in your Alfresco Server AND you can access the folder webscript here: + +http://localhost:8080/alfresco/service/sample/folder/JSON%EXAMPLE + +```html + + +``` + +You can get the plain data from the webscript through the **onSuccess** event parameter and use it as you need in your application + +```ts + logDataExample(data) { + console.log('You webscript data are here' + data); + } +``` + + ## Build from sources Alternatively you can build component from sources with the following commands: - - + + ```sh npm install npm run build diff --git a/ng2-components/ng2-alfresco-webscript/demo/src/main.ts b/ng2-components/ng2-alfresco-webscript/demo/src/main.ts index 925344bdaf..fae84a5847 100644 --- a/ng2-components/ng2-alfresco-webscript/demo/src/main.ts +++ b/ng2-components/ng2-alfresco-webscript/demo/src/main.ts @@ -22,7 +22,8 @@ import { HTTP_PROVIDERS } from '@angular/http'; import { ALFRESCO_CORE_PROVIDERS, AlfrescoSettingsService, - AlfrescoAuthenticationService + AlfrescoAuthenticationService, + CONTEXT_MENU_DIRECTIVES } from 'ng2-alfresco-core'; import { WEBSCRIPTCOMPONENT } from 'ng2-alfresco-webscript'; @@ -50,10 +51,11 @@ import { WEBSCRIPTCOMPONENT } from 'ng2-alfresco-webscript'; [scriptArgs]="scriptArgs" [contextRoot]="contextRoot" [servicePath]="servicePath" - [contentType]="'HTM'"> -
+ [contentType]="'HTML'" + (onSuccess)= "logData($event)"> +
{{prova}} `, - directives: [WEBSCRIPTCOMPONENT] + directives: [WEBSCRIPTCOMPONENT, CONTEXT_MENU_DIRECTIVES] }) class WebscriptDemo implements OnInit { @@ -73,6 +75,8 @@ class WebscriptDemo implements OnInit { token: string; + prova: string; + constructor(private authService: AlfrescoAuthenticationService, private alfrescoSettingsService: AlfrescoSettingsService) { @@ -107,6 +111,10 @@ class WebscriptDemo implements OnInit { this.authenticated = false; }); } + + logData(data) { + console.log(data); + } } bootstrap(WebscriptDemo, [ diff --git a/ng2-components/ng2-alfresco-webscript/docs/assets/HTML.png b/ng2-components/ng2-alfresco-webscript/docs/assets/HTML.png new file mode 100644 index 0000000000000000000000000000000000000000..b64090bb2a78b01a2ae60b3f7615457b559c63ff GIT binary patch literal 68993 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

pVF(GCgQ4oW*mK8x}N)(WnuE&>rb~42a^`~ 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 literal 0 HcmV?d00001 diff --git a/ng2-components/ng2-alfresco-webscript/karma.conf.js b/ng2-components/ng2-alfresco-webscript/karma.conf.js index 2db4427f82..c84efe0a76 100644 --- a/ng2-components/ng2-alfresco-webscript/karma.conf.js +++ b/ng2-components/ng2-alfresco-webscript/karma.conf.js @@ -23,6 +23,7 @@ module.exports = function (config) { {pattern: 'node_modules/ng2-translate/**/*.js', included: false, served: true, watched: false}, {pattern: 'node_modules/alfresco-js-api/dist/alfresco-js-api.js', included: true, watched: false}, + {pattern: 'node_modules/material-design-lite/material.min.js', included: true, watched: false}, {pattern: 'karma-test-shim.js', included: true, watched: true}, // paths loaded via module imports diff --git a/ng2-components/ng2-alfresco-webscript/package.json b/ng2-components/ng2-alfresco-webscript/package.json index 811f7c9aff..42b49c0fd8 100644 --- a/ng2-components/ng2-alfresco-webscript/package.json +++ b/ng2-components/ng2-alfresco-webscript/package.json @@ -75,6 +75,10 @@ "typings": "^1.0.4", "wsrv": "0.1.3" }, + "peerDependencies": { + "material-design-icons": "^2.2.3", + "material-design-lite": "^1.1.3" + }, "keywords": [ "webscript", "alfresco-component" diff --git a/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts b/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts index 0789bda90a..e516ae4783 100644 --- a/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts +++ b/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts @@ -161,8 +161,7 @@ describe('Test ng2-alfresco-webscript', () => { component.ngOnChanges().then(() => { webscriptComponentFixture.detectChanges(); - expect(element.querySelector('#webscript-datatable-wrapper').innerHTML) - .toBe(''); + expect(element.querySelector('#webscript-datatable-wrapper').innerHTML).not.toBe.undefined; done(); }); @@ -190,5 +189,32 @@ describe('Test ng2-alfresco-webscript', () => { responseText: dataTable }); }); + + it('webscript Datatable response should be displayed also if no schema is provided', (done) => { + let component = webscriptComponentFixture.componentInstance; + let element = webscriptComponentFixture.nativeElement; + + component.scriptPath = 'sample/folder/Company%20Home'; + component.contentType = 'DATATABLE'; + + component.ngOnChanges().then(() => { + webscriptComponentFixture.detectChanges(); + expect(element.querySelector('#webscript-datatable-wrapper').innerHTML).not.toBe.undefined; + done(); + }); + + let dataTable = { + data: [ + {id: 1, name: 'Name 1'}, + {id: 2, name: 'Name 2'} + ] + }; + + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'json', + responseText: dataTable + }); + }); }); }); diff --git a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts index 042681855d..6309977592 100644 --- a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts +++ b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts @@ -15,22 +15,24 @@ * limitations under the License. */ -import { Component, Input } from '@angular/core'; +import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { + AlfrescoAuthenticationService, + CONTEXT_MENU_DIRECTIVES, + CONTEXT_MENU_PROVIDERS +} from 'ng2-alfresco-core'; import { ALFRESCO_DATATABLE_DIRECTIVES, ObjectDataTableAdapter } from 'ng2-alfresco-datatable'; -import { - AlfrescoAuthenticationService -} from 'ng2-alfresco-core'; - /** * + * [contentType]="JSON|HTML|DATATABLE" + * (onSuccess)="customMethod($event)> * * * This component, provide a get webscript viewer @@ -41,15 +43,18 @@ import { * @InputParam {string} servicePath path where Web Script service is mapped default value 'service' * @InputParam {string} contentType JSON | HTML | DATATABLE | TEXT * + * @Output - onSuccess - The event is emitted when the data are recived + * * @returns {WebscriptComponent} . */ @Component({ selector: 'alfresco-webscript-get', template: `

-
+
Error during the deserialization of {{data}} as {{contentType}}
`, - directives: [ALFRESCO_DATATABLE_DIRECTIVES] + directives: [ALFRESCO_DATATABLE_DIRECTIVES, CONTEXT_MENU_DIRECTIVES], + providers: [CONTEXT_MENU_PROVIDERS] }) export class WebscriptComponent { @@ -68,6 +73,9 @@ export class WebscriptComponent { @Input() contentType: string = 'TEXT'; + @Output() + onSuccess = new EventEmitter(); + data: any = undefined; show: boolean = false; @@ -92,6 +100,9 @@ export class WebscriptComponent { } else { this.show = this.showDataAsHTML(data); } + + this.onSuccess.emit(data); + resolve(); }, function (error) { console.log('Error' + error); @@ -152,7 +163,7 @@ export class WebscriptComponent { let datatableShow = true; try { if (!data.schema) { - data.schema = ObjectDataTableAdapter.generationSchema(data[0]); + data.schema = ObjectDataTableAdapter.generationSchema(data.data[0]); } if (data.schema && data.schema.length > 0) { this.data = new ObjectDataTableAdapter(data.data, data.schema); @@ -172,7 +183,7 @@ export class WebscriptComponent { this.data = undefined; } - isDataTableCOntent() { + isDataTableContent() { return this.contentType === 'DATATABLE' && this.show; } } From 78ca82c7e81d289dc8b2e0f0b2082bf7d2f86214 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 18 Jul 2016 15:44:44 +0100 Subject: [PATCH 03/18] add travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e3b02c4670..6d7431ea22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,7 @@ env: - MODULE=ng2-alfresco-search - MODULE=ng2-alfresco-upload - MODULE=ng2-alfresco-viewer + - MODULE=ng2-alfresco-webscript before_script: - if ([ "$MODULE" != "ng2-alfresco-core" ] && [ "$MODULE" != "ng2-alfresco-viewer" ]); then From bd69226bbb37279cb6a5ef96779e9bba15bcd459 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 18 Jul 2016 15:47:30 +0100 Subject: [PATCH 04/18] rename generatechema --- .../ng2-alfresco-datatable/src/data/object-datatable-adapter.ts | 2 +- .../ng2-alfresco-webscript/src/webscript.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts index c860af09ea..0f6fdc81e0 100644 --- a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts +++ b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts @@ -32,7 +32,7 @@ export class ObjectDataTableAdapter implements DataTableAdapter { private _rows: DataRow[]; private _columns: DataColumn[]; - static generationSchema(rowToExaminate: any) { + static generatechema(rowToExaminate: any) { let schema = []; if (typeof rowToExaminate === 'object') { diff --git a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts index 6309977592..95cf0d490a 100644 --- a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts +++ b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts @@ -163,7 +163,7 @@ export class WebscriptComponent { let datatableShow = true; try { if (!data.schema) { - data.schema = ObjectDataTableAdapter.generationSchema(data.data[0]); + data.schema = ObjectDataTableAdapter.generatechema(data.data[0]); } if (data.schema && data.schema.length > 0) { this.data = new ObjectDataTableAdapter(data.data, data.schema); From 387ac6329cae996c15c41d7134dcac09c5cf4637 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 18 Jul 2016 16:14:31 +0100 Subject: [PATCH 05/18] add checkbox option file upload --- .../app/components/files/files.component.html | 76 ++++++++++++------- .../app/components/files/files.component.ts | 24 +++++- 2 files changed, 68 insertions(+), 32 deletions(-) diff --git a/demo-shell-ng2/app/components/files/files.component.html b/demo-shell-ng2/app/components/files/files.component.html index e99f78a2c9..abd3c5b233 100644 --- a/demo-shell-ng2/app/components/files/files.component.html +++ b/demo-shell-ng2/app/components/files/files.component.html @@ -120,37 +120,55 @@
+

+ +

-
Single file upload
- - -
Folder upload
- - +

+ +

-
Multiple file upload
- - - +

+ +

+ +
Upload
+
+
+ Extension accepted + +
+
+
+ +
+
+
+
+ +
+
+
- -
-
diff --git a/demo-shell-ng2/app/components/files/files.component.ts b/demo-shell-ng2/app/components/files/files.component.ts index 4d549d15e9..98c21b3d1f 100644 --- a/demo-shell-ng2/app/components/files/files.component.ts +++ b/demo-shell-ng2/app/components/files/files.component.ts @@ -56,12 +56,14 @@ export class FilesComponent { fileName: string; mimeType: string; fileShowed: boolean = false; + multipleFileUpload: boolean = false; + folderUpload: boolean = false; + acceptedFilesTypeShow: boolean = false; acceptedFilesType: string = '.jpg,.pdf,.js'; - constructor( - private contentService: AlfrescoContentService, - documentActions: DocumentActionsService) { + constructor(private contentService: AlfrescoContentService, + documentActions: DocumentActionsService) { documentActions.setHandler('my-handler', this.myDocumentActionHandler.bind(this)); } @@ -93,4 +95,20 @@ export class FilesComponent { this.currentPath = event.path; } } + + toggleMultipleFileUpload() { + this.multipleFileUpload = !this.multipleFileUpload; + return this.multipleFileUpload; + } + + toggleFolder() { + this.multipleFileUpload = false; + this.folderUpload = !this.folderUpload; + return this.folderUpload; + } + + toggleAcceptedFilesType() { + this.acceptedFilesTypeShow = !this.acceptedFilesTypeShow; + return this.acceptedFilesTypeShow; + } } From d9f533de63009ed8689b0179e7f5f5f79014555e Mon Sep 17 00:00:00 2001 From: Hussain Ashraf Date: Mon, 18 Jul 2016 16:24:20 +0100 Subject: [PATCH 06/18] Add data-automation-id to action menu --- .../src/components/datatable/datatable.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html index 6c4543a705..3c726bdd2c 100644 --- a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html +++ b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html @@ -63,7 +63,7 @@ -
    Date: Mon, 18 Jul 2016 16:42:59 +0100 Subject: [PATCH 07/18] Fix logout problem --- ...rescoAuthenticationService.service.spec.ts | 22 +++++++++++++++++++ .../AlfrescoAuthenticationService.service.ts | 4 +++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.spec.ts b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.spec.ts index 3ec6b1a0aa..68f2ed7a9b 100644 --- a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.spec.ts +++ b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.spec.ts @@ -203,6 +203,28 @@ describe('AlfrescoAuthentication', () => { ); }); + it('should logout only for if the provider is loggedin', (done) => { + let providers = ['BPM', 'ECM']; + let alfSetting = injector.get(AlfrescoSettingsService); + alfSetting.providers = providers; + + service = injector.get(AlfrescoAuthenticationService); + localStorage.setItem('ticket-ECM', 'fake-post-ticket-ECM'); + service.createProviderInstance(providers); + spyOn(AlfrescoAuthenticationECM.prototype, 'callApiLogout').and.returnValue(fakePromiseECM); + service.performeSaveToken('ECM', 'fake-ticket-ECM'); + service.logout() + .subscribe(() => { + expect(service.isLoggedIn(providers[0])).toBe(false); + expect(service.getTicket(providers[0])).toBeUndefined(); + expect(localStorage.getItem('ticket-ECM')).toBeUndefined(); + done(); + } + ); + }); + + + it('should return an error if no provider are defined calling the logout', (done) => { let providers = []; let alfSetting = injector.get(AlfrescoSettingsService); diff --git a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts index d427bcfc7c..202e4612c2 100644 --- a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts +++ b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts @@ -152,7 +152,9 @@ export class AlfrescoAuthenticationService extends AlfrescoAuthenticationBase { private performLogout(): Observable { let observableBatch = []; this.providersInstance.forEach((authInstance) => { - observableBatch.push(authInstance.logout()); + if (authInstance.isLoggedIn()) { + observableBatch.push(authInstance.logout()); + } }); return Observable.create(observer => { Observable.forkJoin(observableBatch).subscribe( From 60106239b7fce85d93c094b0df2a74727e850045 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 18 Jul 2016 17:27:12 +0100 Subject: [PATCH 08/18] integrate call in the demo shell and script demo shell --- demo-shell-ng2/app/app.component.html | 2 + demo-shell-ng2/app/app.component.ts | 4 +- .../webscript/webscript.component.ts | 62 +++++++++++++++++++ demo-shell-ng2/browser-sync-config.js | 5 +- demo-shell-ng2/package.json | 3 +- demo-shell-ng2/systemjs.config.js | 6 +- .../ng2-alfresco-webscript/demo/src/main.ts | 4 +- scripts/npm-clean.sh | 3 +- scripts/npm-link-demo-shell.sh | 13 +++- scripts/npm-publish.sh | 3 +- scripts/update-version.sh | 6 +- 11 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 demo-shell-ng2/app/components/webscript/webscript.component.ts diff --git a/demo-shell-ng2/app/app.component.html b/demo-shell-ng2/app/app.component.html index 0447a85c1c..f473f1dac1 100644 --- a/demo-shell-ng2/app/app.component.html +++ b/demo-shell-ng2/app/app.component.html @@ -16,6 +16,7 @@ DataTable Uploader Tasks + Webscript Login @@ -44,6 +45,7 @@ Uploader Login Tasks + Webscript
diff --git a/demo-shell-ng2/app/app.component.ts b/demo-shell-ng2/app/app.component.ts index f39e2c25cf..3cdc27d4e5 100644 --- a/demo-shell-ng2/app/app.component.ts +++ b/demo-shell-ng2/app/app.component.ts @@ -32,6 +32,7 @@ import { SearchComponent } from './components/search/search.component'; import { SearchBarComponent } from './components/search/search-bar.component'; import { LoginDemoComponent } from './components/login/login-demo.component'; import { TasksDemoComponent } from './components/tasks/tasks-demo.component'; +import { WebscriptComponent } from './components/webscript/webscript.component'; declare var document: any; @@ -50,7 +51,8 @@ declare var document: any; {path: '/uploader', name: 'Uploader', component: UploadButtonComponent}, {path: '/login', name: 'Login', component: LoginDemoComponent}, {path: '/search', name: 'Search', component: SearchComponent}, - {path: '/tasks', name: 'Tasks', component: TasksDemoComponent} + {path: '/tasks', name: 'Tasks', component: TasksDemoComponent}, + {path: '/webscript', name: 'Webscript', component: WebscriptComponent} ]) export class AppComponent { translate: AlfrescoTranslationService; diff --git a/demo-shell-ng2/app/components/webscript/webscript.component.ts b/demo-shell-ng2/app/components/webscript/webscript.component.ts new file mode 100644 index 0000000000..839c42975f --- /dev/null +++ b/demo-shell-ng2/app/components/webscript/webscript.component.ts @@ -0,0 +1,62 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { + CONTEXT_MENU_DIRECTIVES +} from 'ng2-alfresco-core'; + +import { WEBSCRIPTCOMPONENT } from 'ng2-alfresco-webscript'; + +@Component({ + selector: 'alfresco-webscript-demo', + template: ` +
+
+
+
+
+
+ + `, + directives: [WEBSCRIPTCOMPONENT, CONTEXT_MENU_DIRECTIVES] +}) +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 = ''; + + logData(data) { + console.log(data); + } +} diff --git a/demo-shell-ng2/browser-sync-config.js b/demo-shell-ng2/browser-sync-config.js index 2d1ab1d7db..af6440b202 100644 --- a/demo-shell-ng2/browser-sync-config.js +++ b/demo-shell-ng2/browser-sync-config.js @@ -18,7 +18,8 @@ browserSync.init({ 'node_modules/ng2-alfresco-login/dist/**/*.{html,htm,css,js}', 'node_modules/ng2-alfresco-search/dist/**/*.{html,htm,css,js}', 'node_modules/ng2-alfresco-upload/dist/**/*.{html,htm,css,js}', - 'node_modules/ng2-alfresco-viewer/dist/**/*.{html,htm,css,js}'], + 'node_modules/ng2-alfresco-viewer/dist/**/*.{html,htm,css,js}', + 'node_modules/ng2-alfresco-webscript/dist/**/*.{html,htm,css,js}'], - reloadDelay: 1000 +reloadDelay: 1000 }); diff --git a/demo-shell-ng2/package.json b/demo-shell-ng2/package.json index c73bab0da2..03942c0e8b 100644 --- a/demo-shell-ng2/package.json +++ b/demo-shell-ng2/package.json @@ -81,7 +81,8 @@ "ng2-alfresco-login": "0.2.0", "ng2-alfresco-search": "0.2.0", "ng2-alfresco-upload": "0.2.0", - "ng2-alfresco-viewer": "0.2.0" + "ng2-alfresco-viewer": "0.2.0", + "ng2-alfresco-webscript": "0.2.0" }, "devDependencies": { "browser-sync": "2.10.0", diff --git a/demo-shell-ng2/systemjs.config.js b/demo-shell-ng2/systemjs.config.js index 2e9336eec1..e08cab9f3e 100644 --- a/demo-shell-ng2/systemjs.config.js +++ b/demo-shell-ng2/systemjs.config.js @@ -17,7 +17,8 @@ 'ng2-alfresco-login': 'node_modules/ng2-alfresco-login/dist', 'ng2-alfresco-search': 'node_modules/ng2-alfresco-search/dist', 'ng2-alfresco-upload': 'node_modules/ng2-alfresco-upload/dist', - 'ng2-alfresco-viewer': 'node_modules/ng2-alfresco-viewer/dist' + 'ng2-alfresco-viewer': 'node_modules/ng2-alfresco-viewer/dist', + 'ng2-alfresco-webscript': 'node_modules/ng2-alfresco-webscript/dist' }; // packages tells the System loader how to load when no filename and/or no extension var packages = { @@ -33,7 +34,8 @@ 'ng2-alfresco-login': { main: 'index.js', defaultExtension: 'js'}, 'ng2-alfresco-search': { main: 'index.js', defaultExtension: 'js'}, 'ng2-alfresco-upload': { main: 'index.js', defaultExtension: 'js'}, - 'ng2-alfresco-viewer': { main: 'index.js', defaultExtension: 'js'} + 'ng2-alfresco-viewer': { main: 'index.js', defaultExtension: 'js'}, + 'ng2-alfresco-webscript': { main: 'index.js', defaultExtension: 'js'} }; var ngPackageNames = [ 'common', diff --git a/ng2-components/ng2-alfresco-webscript/demo/src/main.ts b/ng2-components/ng2-alfresco-webscript/demo/src/main.ts index fae84a5847..9a8fde946d 100644 --- a/ng2-components/ng2-alfresco-webscript/demo/src/main.ts +++ b/ng2-components/ng2-alfresco-webscript/demo/src/main.ts @@ -53,7 +53,7 @@ import { WEBSCRIPTCOMPONENT } from 'ng2-alfresco-webscript'; [servicePath]="servicePath" [contentType]="'HTML'" (onSuccess)= "logData($event)"> -
{{prova}} +
`, directives: [WEBSCRIPTCOMPONENT, CONTEXT_MENU_DIRECTIVES] }) @@ -75,8 +75,6 @@ class WebscriptDemo implements OnInit { token: string; - prova: string; - constructor(private authService: AlfrescoAuthenticationService, private alfrescoSettingsService: AlfrescoSettingsService) { diff --git a/scripts/npm-clean.sh b/scripts/npm-clean.sh index 7bfe5ff60e..59ca1b7635 100755 --- a/scripts/npm-clean.sh +++ b/scripts/npm-clean.sh @@ -9,7 +9,8 @@ for PACKAGE in \ ng2-alfresco-login \ ng2-alfresco-search \ ng2-alfresco-upload \ - ng2-alfresco-viewer + ng2-alfresco-viewer \ + ng2-alfresco-webscript do echo "====== clean component: ${PACKAGE} =====" cd "$DIR/../ng2-components/${PACKAGE}" diff --git a/scripts/npm-link-demo-shell.sh b/scripts/npm-link-demo-shell.sh index 300327b4ad..22da9d98be 100755 --- a/scripts/npm-link-demo-shell.sh +++ b/scripts/npm-link-demo-shell.sh @@ -20,12 +20,20 @@ npm link ng2-alfresco-core npm link ng2-alfresco-datatable npm link +#LINK WEBSCRIPT +echo "====== linking component: ng2-alfresco-webscript =====" +cd "$DIR/../ng2-components/ng2-alfresco-webscript" +npm link ng2-alfresco-core +npm link ng2-alfresco-datatable +npm link + #LINK ALL THE OTHERS COMPONENTS for PACKAGE in \ ng2-alfresco-login \ ng2-alfresco-search \ ng2-alfresco-upload \ - ng2-alfresco-viewer + ng2-alfresco-viewer \ + ng2-alfresco-webscript do DESTDIR="$DIR/../ng2-components/${PACKAGE}" echo "====== linking component: ${PACKAGE} =====" @@ -44,7 +52,8 @@ for PACKAGE in \ ng2-alfresco-login \ ng2-alfresco-search \ ng2-alfresco-upload \ - ng2-alfresco-viewer + ng2-alfresco-viewer \ + ng2-alfresco-webscript do DESTDIR="$DIR/../ng2-components/${PACKAGE}" echo "====== demo shell linking: ${PACKAGE} =====" diff --git a/scripts/npm-publish.sh b/scripts/npm-publish.sh index 42a263a6b2..9591b8ba48 100755 --- a/scripts/npm-publish.sh +++ b/scripts/npm-publish.sh @@ -11,7 +11,8 @@ for PACKAGE in \ ng2-alfresco-login \ ng2-alfresco-search \ ng2-alfresco-upload \ - ng2-alfresco-viewer + ng2-alfresco-viewer \ + ng2-alfresco-webscript do DESTDIR="$DIR/../ng2-components/${PACKAGE}" echo "====== PUBLISHING: ${DESTDIR} =====" diff --git a/scripts/update-version.sh b/scripts/update-version.sh index 168e5bf685..609350a64f 100755 --- a/scripts/update-version.sh +++ b/scripts/update-version.sh @@ -21,7 +21,8 @@ for PACKAGE in \ ng2-alfresco-login \ ng2-alfresco-search \ ng2-alfresco-upload \ - ng2-alfresco-viewer + ng2-alfresco-viewer \ + ng2-alfresco-webscript do DESTDIR="$DIR/../ng2-components/${PACKAGE}" echo "====== UPDATE VERSION of ${PACKAGE} to ${VERSION} version in all the package.json ======" @@ -35,7 +36,8 @@ for PACKAGE in \ ng2-alfresco-login \ ng2-alfresco-search \ ng2-alfresco-upload \ - ng2-alfresco-viewer + ng2-alfresco-viewer \ + ng2-alfresco-webscript do DESTDIR="$DIR/../ng2-components/${PACKAGE}" echo "====== UPDATE VERSION OF ${PACKAGE} to ${VERSION} version ======" From b41c81f4a2388cddab85ee86a4c8b17d6e5614f3 Mon Sep 17 00:00:00 2001 From: Mario Romano Date: Mon, 18 Jul 2016 19:15:24 +0100 Subject: [PATCH 09/18] add module to ci --- .travis.yml | 4 ++-- appveyor.yml | 3 +++ ng2-components/ng2-alfresco-webscript/package.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6d7431ea22..01f77d2897 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,14 +32,14 @@ before_script: - if ([ "$MODULE" != "ng2-alfresco-core" ] && [ "$MODULE" != "ng2-alfresco-viewer" ]); then (cd ng2-components/ng2-alfresco-core; npm install; npm link); fi - - if [[ "$MODULE" == "ng2-alfresco-documentlist" ]]; then + - if ([ "$MODULE" == "ng2-alfresco-documentlist" ] || [ "$MODULE" == "ng2-alfresco-webscript" ]); then (cd ng2-components/ng2-alfresco-datatable;npm link ng2-alfresco-core; npm install; npm link); fi - cd ng2-components/$MODULE; - if ([ "$MODULE" != "ng2-alfresco-core" ] && [ "$MODULE" != "ng2-alfresco-viewer" ]); then npm link ng2-alfresco-core; fi - - if [[ "$MODULE" == "ng2-alfresco-documentlist" ]]; then + - if ([ "$MODULE" == "ng2-alfresco-documentlist" ] || [ "$MODULE" == "ng2-alfresco-webscript" ]); then npm link ng2-alfresco-datatable; fi - npm install; diff --git a/appveyor.yml b/appveyor.yml index adc7eaaf1f..d952249c71 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,7 @@ environment: - COMPONENT_NAME: ng2-alfresco-search - COMPONENT_NAME: ng2-alfresco-upload - COMPONENT_NAME: ng2-alfresco-viewer + - COMPONENT_NAME: ng2-alfresco-webscript # Install scripts. (runs after repo cloning) install: @@ -22,9 +23,11 @@ install: # 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-alfresco-webscript (cd ng2-components/ng2-alfresco-datatable && npm link ng2-alfresco-core && npm install && 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-alfresco-webscript (npm link ng2-alfresco-datatable) - npm install # Post-install test scripts. diff --git a/ng2-components/ng2-alfresco-webscript/package.json b/ng2-components/ng2-alfresco-webscript/package.json index 42b49c0fd8..4d7c0a9540 100644 --- a/ng2-components/ng2-alfresco-webscript/package.json +++ b/ng2-components/ng2-alfresco-webscript/package.json @@ -1,6 +1,6 @@ { "name": "ng2-alfresco-webscript", - "description": "webscript executor", + "description": "Alfresco webscript executor", "version": "0.1.0", "author": "Alfresco Software, Ltd.", "main": "./dist/index.js", From c86e23351c574235a5df4ab92f703483a01ed60d Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 18 Jul 2016 22:44:08 +0100 Subject: [PATCH 10/18] test fix --- .../src/data/object-datatable-adapter.ts | 2 +- ng2-components/ng2-alfresco-webscript/package.json | 5 +---- .../ng2-alfresco-webscript/src/webscript.component.ts | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts index 0f6fdc81e0..d0094fb1b5 100644 --- a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts +++ b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts @@ -32,7 +32,7 @@ export class ObjectDataTableAdapter implements DataTableAdapter { private _rows: DataRow[]; private _columns: DataColumn[]; - static generatechema(rowToExaminate: any) { + static generateSchema(rowToExaminate: any) { let schema = []; if (typeof rowToExaminate === 'object') { diff --git a/ng2-components/ng2-alfresco-webscript/package.json b/ng2-components/ng2-alfresco-webscript/package.json index 4d7c0a9540..4c744ec0dd 100644 --- a/ng2-components/ng2-alfresco-webscript/package.json +++ b/ng2-components/ng2-alfresco-webscript/package.json @@ -67,6 +67,7 @@ "karma-jasmine-html-reporter": "^0.2.0", "karma-mocha-reporter": "^2.0.3", "license-check": "^1.0.4", + "material-design-lite": "^1.1.3", "remap-istanbul": "^0.6.3", "rimraf": "2.5.2", "traceur": "^0.0.91", @@ -75,10 +76,6 @@ "typings": "^1.0.4", "wsrv": "0.1.3" }, - "peerDependencies": { - "material-design-icons": "^2.2.3", - "material-design-lite": "^1.1.3" - }, "keywords": [ "webscript", "alfresco-component" diff --git a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts index 95cf0d490a..72354fc6c7 100644 --- a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts +++ b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts @@ -163,7 +163,7 @@ export class WebscriptComponent { let datatableShow = true; try { if (!data.schema) { - data.schema = ObjectDataTableAdapter.generatechema(data.data[0]); + data.schema = ObjectDataTableAdapter.generateSchema(data.data[0]); } if (data.schema && data.schema.length > 0) { this.data = new ObjectDataTableAdapter(data.data, data.schema); From beb37a2dedd539ae9d1de6e5657598d9caaf0081 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Tue, 19 Jul 2016 10:21:22 +0100 Subject: [PATCH 11/18] test and doc generateSchema --- .../ng2-alfresco-datatable/README.md | 34 +++++++++++++++++++ .../src/data/object-datatable-adapter.spec.ts | 13 +++++++ .../src/data/object-datatable-adapter.ts | 26 ++++++++------ .../src/webscript.component.ts | 2 +- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/ng2-components/ng2-alfresco-datatable/README.md b/ng2-components/ng2-alfresco-datatable/README.md index 26681e0ca7..7f68b788ff 100644 --- a/ng2-components/ng2-alfresco-datatable/README.md +++ b/ng2-components/ng2-alfresco-datatable/README.md @@ -307,6 +307,7 @@ a custom `DataTableAdapter` using the following interfaces: ```ts interface DataTableAdapter { + generateSchema(row: DataRow): col: DataColumn; getRows(): Array; setRows(rows: Array): void; getColumns(): Array; @@ -363,6 +364,39 @@ let data = new ObjectDataTableAdapter( ); ``` +## Generate schema +Is possible to auto generate your schema if you have only the data row + +```ts +let data = [ + { id: 2, name: 'abs' }, + { id: 1, name: 'xyz' } +]; + +let schema = ObjectDataTableAdapter.generateSchema(data); + +/*Auto generated schema value: + + [ + { + type: 'text', + key: 'id', + title: 'Id', + sortable: false + }, + { + type: 'text', + key: 'name', + title: 'Name', + sortable: false + } + ] + + */ + +``` + + ## Build from sources Alternatively you can build component from sources with the following commands: diff --git a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.spec.ts b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.spec.ts index 95eeb8ee97..75d4c1abb5 100644 --- a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.spec.ts +++ b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.spec.ts @@ -367,4 +367,17 @@ describe('ObjectDataRow', () => { expect(row.hasValue('some.other.prop')).toBeFalsy(); }); + it('should generateSchema generate a schema from data', () => { + let data = [ + { id: 2, name: 'abs' }, + { id: 1, name: 'xyz' } + ]; + + let schema = ObjectDataTableAdapter.generateSchema(data); + + expect(schema.length).toBe(2); + expect(schema[0].title).toBe('id'); + expect(schema[1].title).toBe('name'); + }); + }); diff --git a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts index d0094fb1b5..b86de45d14 100644 --- a/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts +++ b/ng2-components/ng2-alfresco-datatable/src/data/object-datatable-adapter.ts @@ -32,22 +32,26 @@ export class ObjectDataTableAdapter implements DataTableAdapter { private _rows: DataRow[]; private _columns: DataColumn[]; - static generateSchema(rowToExaminate: any) { + static generateSchema(data: any[]) { let schema = []; - if (typeof rowToExaminate === 'object') { - for (let key in rowToExaminate) { - if (rowToExaminate.hasOwnProperty(key)) { - schema.push({ - type: 'text', - key: key, - title: key, - sortable: false - }); + if (data && data.length) { + let rowToExaminate = data[0]; + + if (typeof rowToExaminate === 'object') { + for (let key in rowToExaminate) { + if (rowToExaminate.hasOwnProperty(key)) { + schema.push({ + type: 'text', + key: key, + title: key, + sortable: false + }); + } } } - } + } return schema; } diff --git a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts index 72354fc6c7..e7cc434bdb 100644 --- a/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts +++ b/ng2-components/ng2-alfresco-webscript/src/webscript.component.ts @@ -163,7 +163,7 @@ export class WebscriptComponent { let datatableShow = true; try { if (!data.schema) { - data.schema = ObjectDataTableAdapter.generateSchema(data.data[0]); + data.schema = ObjectDataTableAdapter.generateSchema(data.data); } if (data.schema && data.schema.length > 0) { this.data = new ObjectDataTableAdapter(data.data, data.schema); From 3d84c9b99bc8f88a6f37b0e544c475afe99e4241 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Tue, 19 Jul 2016 11:17:09 +0100 Subject: [PATCH 12/18] move js api 0.2.1 --- demo-shell-ng2/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo-shell-ng2/package.json b/demo-shell-ng2/package.json index 03942c0e8b..2d98e7d983 100644 --- a/demo-shell-ng2/package.json +++ b/demo-shell-ng2/package.json @@ -74,7 +74,7 @@ "pdfjs-dist": "1.5.258", "flag-icon-css": "2.3.0", - "alfresco-js-api": "0.2.0", + "alfresco-js-api": "0.2.1", "ng2-alfresco-core": "0.2.0", "ng2-alfresco-datatable": "0.2.0", "ng2-alfresco-documentlist": "0.2.0", From a638f3ee6f9e8cdc1e2f89ab92cbc6d7dd1b30a1 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Tue, 19 Jul 2016 14:18:15 +0100 Subject: [PATCH 13/18] refer to internal webscript dist until the new package is not release --- demo-shell-ng2/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo-shell-ng2/package.json b/demo-shell-ng2/package.json index 2d98e7d983..ae10a5fcb9 100644 --- a/demo-shell-ng2/package.json +++ b/demo-shell-ng2/package.json @@ -82,7 +82,7 @@ "ng2-alfresco-search": "0.2.0", "ng2-alfresco-upload": "0.2.0", "ng2-alfresco-viewer": "0.2.0", - "ng2-alfresco-webscript": "0.2.0" + "ng2-alfresco-webscript": "file:../ng2-components/ng2-alfresco-webscript" }, "devDependencies": { "browser-sync": "2.10.0", From 3859c4cd470a9946482577bb9d8ef2914b03935b Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Wed, 20 Jul 2016 12:10:52 +0200 Subject: [PATCH 14/18] Cannot view a file #449 --- demo-shell-ng2/app/components/files/files.component.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/demo-shell-ng2/app/components/files/files.component.html b/demo-shell-ng2/app/components/files/files.component.html index abd3c5b233..b7e044a0dd 100644 --- a/demo-shell-ng2/app/components/files/files.component.html +++ b/demo-shell-ng2/app/components/files/files.component.html @@ -171,4 +171,12 @@ + +
+
+ From 5a87734810c88744da85f63f1ce2a1f12b511542 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Wed, 20 Jul 2016 11:21:27 +0100 Subject: [PATCH 15/18] Fix ticket name --- .../services/AlfrescoAuthenticationService.service.spec.ts | 2 +- .../src/services/AlfrescoAuthenticationService.service.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.spec.ts b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.spec.ts index 68f2ed7a9b..26fdd818b8 100644 --- a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.spec.ts +++ b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.spec.ts @@ -212,7 +212,7 @@ describe('AlfrescoAuthentication', () => { localStorage.setItem('ticket-ECM', 'fake-post-ticket-ECM'); service.createProviderInstance(providers); spyOn(AlfrescoAuthenticationECM.prototype, 'callApiLogout').and.returnValue(fakePromiseECM); - service.performeSaveToken('ECM', 'fake-ticket-ECM'); + service.performeSaveTicket('ECM', 'fake-ticket-ECM'); service.logout() .subscribe(() => { expect(service.isLoggedIn(providers[0])).toBe(false); diff --git a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts index 202e4612c2..c8eb0071bb 100644 --- a/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts +++ b/ng2-components/ng2-alfresco-core/src/services/AlfrescoAuthenticationService.service.ts @@ -82,7 +82,7 @@ export class AlfrescoAuthenticationService extends AlfrescoAuthenticationBase { Observable.forkJoin(observableBatch).subscribe( (response: any[]) => { response.forEach((res) => { - this.performeSaveToken(res.type, res.ticket); + this.performeSaveTicket(res.type, res.ticket); }); observer.next(response); }, @@ -125,7 +125,7 @@ export class AlfrescoAuthenticationService extends AlfrescoAuthenticationBase { * @param type - providerName * @param ticket */ - private performeSaveToken(type: string, ticket: string) { + private performeSaveTicket(type: string, ticket: string) { let auth: AbstractAuthentication = this.findProviderInstance(type); if (auth) { auth.saveTicket(ticket); From c0cad35372da913f219475221296a89c881917d6 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Wed, 20 Jul 2016 12:13:39 +0100 Subject: [PATCH 16/18] Fix tabindex --- .../src/components/alfresco-login.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.html b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.html index b53a97d4bf..12fc7db37a 100644 --- a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.html +++ b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.html @@ -39,7 +39,7 @@
-
From cab661064ca9931d0361bc8686333f7649dbd8b3 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Wed, 20 Jul 2016 16:51:21 +0100 Subject: [PATCH 17/18] Emit event when the folder is created --- .../src/components/upload-drag-area.component.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts index 8b92fec338..1e6ade00c6 100644 --- a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts +++ b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts @@ -138,6 +138,9 @@ export class UploadDragAreaComponent { .subscribe( message => { let self = this; + this.onSuccess.emit({ + value: 'Created folder' + }); let dirReader = folder.createReader(); dirReader.readEntries(function (entries: any) { for (let i = 0; i < entries.length; i++) { From 07d5c86b1b7ff3d1d01686bc037112744d7ec3d6 Mon Sep 17 00:00:00 2001 From: mauriziovitale84 Date: Wed, 20 Jul 2016 17:01:25 +0100 Subject: [PATCH 18/18] Fix unit test --- .../src/components/upload-drag-area.component.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.spec.ts b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.spec.ts index 9ebe0fcab5..51030ab9bc 100644 --- a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.spec.ts +++ b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.spec.ts @@ -23,6 +23,7 @@ import { AlfrescoSettingsServiceMock } from '../assets/AlfrescoSettingsService.s import { TranslationMock } from '../assets/translation.service.mock'; import { UploadService } from '../services/upload.service'; import { HTTP_PROVIDERS } from '@angular/http'; +import { EventEmitter } from '@angular/core'; declare var AlfrescoApi: any; @@ -171,7 +172,7 @@ describe('AlfrescoUploadDragArea', () => { it('should create a folder and call onFilesEntityDropped with the file inside the folder', done => { let component = componentFixture.componentInstance; component.currentFolderPath = '/root-fake-/sites-fake/document-library-fake'; - component.onSuccess = null; + component.onSuccess = new EventEmitter(); componentFixture.detectChanges();