diff --git a/angular.json b/angular.json index 42c0aba18..efbbedfcf 100644 --- a/angular.json +++ b/angular.json @@ -55,6 +55,11 @@ "glob": "**/*.js", "input": "node_modules/@ngstack/code-editor/workers", "output": "./assets/workers" + }, + { + "glob": "**/*.json", + "input": "dist/my-extension/assets", + "output": "/assets/plugins" } ], "styles": [ @@ -284,6 +289,41 @@ } } } + }, + "my-extension": { + "root": "projects/my-extension", + "sourceRoot": "projects/my-extension/src", + "projectType": "library", + "prefix": "lib", + "targets": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/my-extension/tsconfig.lib.json", + "project": "projects/my-extension/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/my-extension/src/test.ts", + "tsConfig": "projects/my-extension/tsconfig.spec.json", + "karmaConfig": "projects/my-extension/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/my-extension/tsconfig.lib.json", + "projects/my-extension/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } } }, "defaultProject": "app", diff --git a/cspell.json b/cspell.json index ddb8d9a9e..64c56caf6 100644 --- a/cspell.json +++ b/cspell.json @@ -4,6 +4,7 @@ "words": [ "succes", "sharedlinks", + "Redistributable", "ngrx", "ngstack", diff --git a/docs/extending.md b/docs/extending.md index d91d72938..9f07fcb2d 100644 --- a/docs/extending.md +++ b/docs/extending.md @@ -1567,3 +1567,229 @@ node: 10 You have successfully created a new menu button that invokes your custom action and redirects you to the extra application route. + +## Redistributable libraries + +Extension libraries are based on the standard Angular libraries and definition files in the JSON format. + +

+Please read more details in the following article: [Library support in Angular CLI 6](https://github.com/angular/angular-cli/wiki/stories-create-library#library-support-in-angular-cli-6) +

+ +### Creating extension library + +First, generate a new project within the workspace: + +```sh +ng generate library my-extension +``` + +You will get a new project in the `projects/my-extensions` folder. +By default, the project contains at least the following content: + +* Example component `my-extension.component.ts` +* Example service `my-extension.service.ts` +* Angular Module example `my-extension.module.ts` + +Next, build the project with the following command: + +```sh +ng build my-extension +``` + +Angular CLI automatically configures Typescript path mappings for the project, +so that you do not need any additional steps to link the library. + +#### Register dynamic components + +Update `my-extension.module.ts` and put all the content you plan to use at runtime dynamically to the `entryComponents` section of the module. + +```typescript +@NgModule({ + imports: [], + declarations: [MyExtensionComponent], + exports: [MyExtensionComponent], + entryComponents: [MyExtensionComponent] +}) +export class MyExtensionModule { } +``` + +Let's now register `MyExtensionComponent` as an extension component. +Update the code as in the next example: + +```typescript +import { ExtensionService } from '@alfresco/adf-extensions'; + +@NgModule({...}) +export class MyExtensionModule { + constructor(extensions: ExtensionService) { + extensions.setComponents({ + 'my-extension.main.component': MyExtensionComponent, + }); + } +} +``` + +Now you can use `my-extension.main.component` identifier in the JSON definitions +if you want to reference the `MyExtensionComponent`. + +#### Plugin definition file + +Create a new `assets/my-extension.json` file in the library project root folder with the following content: + +```json +{ + "$schema": "../../../extension.schema.json", + "$version": "1.0.0", + "$name": "plugin1", + "$description": "demo plugin", + + "routes": [ + { + "id": "my.extension.route", + "path": "ext/my/route", + "component": "my-extension.main.component" + } + ], + + "features": { + "navbar": [ + { + "id": "my.extension.nav", + "items": [ + { + "id": "my.extension.main", + "icon": "extension", + "title": "My Extension", + "route": "my.extension.route" + } + ] + } + ] + } +} +``` + +Update the root `package.json` file and append the following entry to the `scripts` section: + +```json +{ + "scripts": { + ..., + + "build:my-extension": + "ng build my-extension && cpr projects/my-extension/assets dist/my-extension/assets --deleteFirst" + } +} +``` + +You can now use that script to build the library and copy assets to the output folder. + +

+It is a good practice to provide installation instructions for your library in the `README.md` file. +Be sure to mention that developers should have a build rule to copy your plugin definition file to the `assets/plugins` folder of the main application. +

+ +### Publishing library to NPM + +You should rebuild the library every time before publishing: + +```sh +npm run build:my-extension +``` + +Go to the output folder and run the publish command. + +```sh +cd dist/my-extension +npm publish +``` + +Note that requires for you have a valid [NPM](https://www.npmjs.com/) account. + +

+See more details in the [Publishing your library](https://github.com/angular/angular-cli/wiki/stories-create-library#publishing-your-library) article. +

+ +### Consuming extension library + +Assuming that you have published your extension library to NPM, +you can install it using the standard command: + +```sh +npm install my-extension +``` + +That should install the library and all its dependencies. + +

+You do not need installing library in the original workspace as the application is +already configured to use the local version from the `dist` folder. +

+ +#### Copy assets + +Edit `angular.json` configuration file and add the following rule if you develop and test extension library in the same workspace + +```json +{ + "glob": "**/*.json", + "input": "dist/my-extension/assets", + "output": "/assets/plugins" +} +``` + +Use the following rule in case you are installing extension from NPM: + +```json +{ + "glob": "**/*.json", + "input": "node_modules/my-extension/assets", + "output": "/assets/plugins" +} +``` + +#### Register module + +In the main application, edit the `src/app/extensions.module.ts` file and append the module declaration as in the next example: + +```typescript +... +import { MyExtensionModule } from 'my-extension'; + +@NgModule({ + ... + imports: [ + ..., + MyExtensionModule + ] +}) +export class AppExtensionsModule {} +``` + +#### Register plugin + +Finally, update the `assets/app.extensions.json` file and add a reference to the new plugin: + +```json +{ + "$references": [ + ..., + "my-extension.json" + ] +} +``` + +### Testing library + +Run the application and ensure you have an extra navigation sidebar entry: + +```sh +npm start +``` + +Click the `My Extension` link and in the main content area you should see the extension component coming from your library. + +

+Depending on the application setup, you may need enabling external plugins via the `Settings` dialog available for `admin` users (clicking the application profile button). +

diff --git a/package-lock.json b/package-lock.json index 05f8afe20..b6c181d70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -622,19 +622,19 @@ } }, "@angular-devkit/schematics": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.8.0.tgz", - "integrity": "sha512-XmyNyj/JDXXKACH5XE6cGht6YH5n8KpVLr/X3EPp322yB8HlWWDOsI1UwchzNU769aP7YwjDNwEmu3+8RGD6Ng==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.8.1.tgz", + "integrity": "sha512-ab3xeyTpPA9JO7oXgdfbQ/+5djddvoKjFaxFFcLD5GxgDDnvJcmhgDkluJY9JZHH2oSFaW8u1G5zg8uo1HrriA==", "dev": true, "requires": { - "@angular-devkit/core": "0.8.0", + "@angular-devkit/core": "0.8.1", "rxjs": "~6.2.0" }, "dependencies": { "@angular-devkit/core": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.0.tgz", - "integrity": "sha512-2kzpw4CHeZOrbs2iKeEmqQuj4tfqMbklrVXt2ktQmasTc83pgEaXbUvnxb1He+UtSkuVq3ErZ3ZRlDf/fmeRZQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.1.tgz", + "integrity": "sha512-0TKjF/nHb7+wwWIQ5iuQRzDIF2CphmX9ZojBIGH6PWFgQNKG0yUWqSa+PTpr5eOcGYBOa1rHLf10iyPHDmBdBw==", "dev": true, "requires": { "ajv": "~6.4.0", @@ -1054,16 +1054,16 @@ } }, "@angular/cli": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.2.0.tgz", - "integrity": "sha512-F0BfB59e7HM/STneWj5VvGZHDfotFvY9KKLzJgsazaJaDxo2sPDHm4gTJSHH9FgfuVQkA5e4N11uMeI110zzsA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.2.1.tgz", + "integrity": "sha512-4AO014PohYc/vbNaO6nPi/a6JqxdOHN2m0WLutgRGoBQswqSGn7aLEG1erZKRzbfq39E1a/efnNmEI3Okl3h1Q==", "dev": true, "requires": { - "@angular-devkit/architect": "0.8.0", - "@angular-devkit/core": "0.8.0", - "@angular-devkit/schematics": "0.8.0", - "@schematics/angular": "0.8.0", - "@schematics/update": "0.8.0", + "@angular-devkit/architect": "0.8.1", + "@angular-devkit/core": "0.8.1", + "@angular-devkit/schematics": "0.8.1", + "@schematics/angular": "0.8.1", + "@schematics/update": "0.8.1", "json-schema-traverse": "^0.4.1", "opn": "^5.3.0", "rxjs": "~6.2.0", @@ -1073,19 +1073,19 @@ }, "dependencies": { "@angular-devkit/architect": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.8.0.tgz", - "integrity": "sha512-rgyucHNPzJawBYqM9LSnOWNm9KM6E8ovzvQgzF8SePderqn6TGFAlrDvaZasgLtrihCAR//lNhKUm8w8ft3rgQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.8.1.tgz", + "integrity": "sha512-bf/8tg8X2y9f6wE2r48KAW2AVexfGd/rfTHRvl9+kSsFFtXVA233GNAL6Qs+wJ/G2t1NFddnE3ME2eyhJYxBwA==", "dev": true, "requires": { - "@angular-devkit/core": "0.8.0", + "@angular-devkit/core": "0.8.1", "rxjs": "~6.2.0" } }, "@angular-devkit/core": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.0.tgz", - "integrity": "sha512-2kzpw4CHeZOrbs2iKeEmqQuj4tfqMbklrVXt2ktQmasTc83pgEaXbUvnxb1He+UtSkuVq3ErZ3ZRlDf/fmeRZQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.1.tgz", + "integrity": "sha512-0TKjF/nHb7+wwWIQ5iuQRzDIF2CphmX9ZojBIGH6PWFgQNKG0yUWqSa+PTpr5eOcGYBOa1rHLf10iyPHDmBdBw==", "dev": true, "requires": { "ajv": "~6.4.0", @@ -1695,37 +1695,26 @@ } }, "@schematics/angular": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.8.0.tgz", - "integrity": "sha512-D7fCtbhHg4aHRyDfSFxjKbcMOgz9IzMBWVjHJU7LGCGvX67H6eCNqbEf/Ogu1jzFQjMFR5VvPjXhamqTXjv7ug==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.8.1.tgz", + "integrity": "sha512-AW7063IaYFIcskt+eI5k4drb/hDuY2wK3zLsW01E49WaBcRhXVIOVox7cbfwHCA6zch117WZ5xVZlbGHJ4pkMw==", "dev": true, "requires": { - "@angular-devkit/core": "0.8.0", - "@angular-devkit/schematics": "0.8.0", + "@angular-devkit/core": "0.8.1", + "@angular-devkit/schematics": "0.8.1", "typescript": ">=2.6.2 <2.10" }, "dependencies": { "@angular-devkit/core": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.0.tgz", - "integrity": "sha512-2kzpw4CHeZOrbs2iKeEmqQuj4tfqMbklrVXt2ktQmasTc83pgEaXbUvnxb1He+UtSkuVq3ErZ3ZRlDf/fmeRZQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.1.tgz", + "integrity": "sha512-0TKjF/nHb7+wwWIQ5iuQRzDIF2CphmX9ZojBIGH6PWFgQNKG0yUWqSa+PTpr5eOcGYBOa1rHLf10iyPHDmBdBw==", "dev": true, "requires": { "ajv": "~6.4.0", "chokidar": "^2.0.3", "rxjs": "~6.2.0", "source-map": "^0.5.6" - }, - "dependencies": { - "rxjs": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz", - "integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - } } }, "ajv": { @@ -2102,6 +2091,15 @@ "to-regex": "^3.0.2" } }, + "rxjs": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz", + "integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "uri-js": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", @@ -2114,13 +2112,13 @@ } }, "@schematics/update": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.8.0.tgz", - "integrity": "sha512-5nrvUWdsrn/iW/V4Dk0a1/yxnzmstxVlsI0PKFRImkU67pVmJDGkELqFg1fQBnqKcFJoBUHtkGt3+P4b8BdHsw==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.8.1.tgz", + "integrity": "sha512-G5EU8nvqAC9fX09sV+UEM9EgR+PjGwguUatOk10uvwvZvCfO+W0FVeLmSap9A6mJ+e8YOH6XFpkwLG0AMuhYrw==", "dev": true, "requires": { - "@angular-devkit/core": "0.8.0", - "@angular-devkit/schematics": "0.8.0", + "@angular-devkit/core": "0.8.1", + "@angular-devkit/schematics": "0.8.1", "npm-registry-client": "^8.5.1", "rxjs": "~6.2.0", "semver": "^5.3.0", @@ -2128,9 +2126,9 @@ }, "dependencies": { "@angular-devkit/core": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.0.tgz", - "integrity": "sha512-2kzpw4CHeZOrbs2iKeEmqQuj4tfqMbklrVXt2ktQmasTc83pgEaXbUvnxb1He+UtSkuVq3ErZ3ZRlDf/fmeRZQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.1.tgz", + "integrity": "sha512-0TKjF/nHb7+wwWIQ5iuQRzDIF2CphmX9ZojBIGH6PWFgQNKG0yUWqSa+PTpr5eOcGYBOa1rHLf10iyPHDmBdBw==", "dev": true, "requires": { "ajv": "~6.4.0", @@ -2575,7 +2573,8 @@ "@types/showdown": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-1.7.5.tgz", - "integrity": "sha512-uUSUP6XtyTclRzTH0NLkEIiEowxYXOWDeulpngrPltEceOmsGdhfrl8xr3D4QfJA7FuUUyHwFQuWWURLFg3hgg==" + "integrity": "sha512-uUSUP6XtyTclRzTH0NLkEIiEowxYXOWDeulpngrPltEceOmsGdhfrl8xr3D4QfJA7FuUUyHwFQuWWURLFg3hgg==", + "dev": true }, "@types/strip-bom": { "version": "3.0.0", @@ -2866,9 +2865,9 @@ } }, "alfresco-js-api-node": { - "version": "2.5.0-b048ff2aad00611aac1c02af531549b60acc0e66", - "resolved": "https://registry.npmjs.org/alfresco-js-api-node/-/alfresco-js-api-node-2.5.0-b048ff2aad00611aac1c02af531549b60acc0e66.tgz", - "integrity": "sha512-HuRpoyuDYRF+IcuAApEJNeZWgfvW0ioe+QXiPwsGlHzgbYlqz2iwGPuXBaxp4XdfL0g2IIckf2MElp6IBpFbQA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/alfresco-js-api-node/-/alfresco-js-api-node-2.5.0.tgz", + "integrity": "sha512-sx/tBSaY24mkSz9yLwVEWGHDP+BSQT6JfrjdxDgxecop27bYC/EjZCFlS/lCDKXXeeJtGrEL59CQZmJ+NTDGlw==", "dev": true, "requires": { "event-emitter": "0.3.4", @@ -4130,9 +4129,9 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "codelyzer": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.4.3.tgz", - "integrity": "sha512-BrARi+8uo3gajjFFXA5bMhE0wZ0nd/QRjyLISA37anjN2f7pxcb6rkhQX9/GJLTwsUiSaOLbghSIWkHy4F67NQ==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.4.4.tgz", + "integrity": "sha512-JgFMudx0n50IuE/ydAfnkksCwQkWSVWgYvhDPHZgDUbmsiYC22VuEXKu5l8Hhx9UJsLgjWDLjTAFGj2WaW5DUA==", "dev": true, "requires": { "app-root-path": "^2.1.0", @@ -4504,6 +4503,26 @@ } } }, + "cpr": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cpr/-/cpr-3.0.1.tgz", + "integrity": "sha1-uaVQOLfNgaNcF7l2GJW9hJau8eU=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.5", + "minimist": "^1.2.0", + "mkdirp": "~0.5.1", + "rimraf": "^2.5.4" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "create-ecdh": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", diff --git a/package.json b/package.json index 2dc2c8044..cae435f7a 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,11 @@ "ng": "ng", "start": "npm run server-versions && npm run build.libs.dev && ng serve --open", "start:prod": "npm run server-versions && npm run build.libs.prod && ng serve --prod --open", - "build.libs.dev": "ng build adf-extensions && ng build aca-dev-tools", - "build.libs.prod": "ng build adf-extensions --prod && ng build aca-dev-tools --prod", + "build.libs.dev": "ng build adf-extensions && ng build aca-dev-tools && npm run build:my-extension", + "build.libs.prod": "ng build adf-extensions --prod && ng build aca-dev-tools --prod && npm run build:my-extension", "build": "npm run server-versions && npm run build.libs.prod && node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng build app --prod", "build:dev": "npm run server-versions && npm run build.libs.dev && ng build", + "build:my-extension": "ng build my-extension && cpr projects/my-extension/assets dist/my-extension/assets --deleteFirst", "test": "npm run build.libs.dev && ng test app --code-coverage", "test:ci": "npm run build.libs.dev && ng test app --code-coverage --watch=false", "lint": "ng lint", @@ -49,7 +50,6 @@ "@ngrx/store-devtools": "^6.1.0", "@ngstack/code-editor": "^0.4.3", "@ngx-translate/core": "^10.0.2", - "@types/showdown": "^1.7.5", "alfresco-js-api": "2.5.0", "core-js": "^2.5.7", "hammerjs": "2.0.8", @@ -66,15 +66,17 @@ "devDependencies": { "@angular-devkit/build-angular": "~0.8.0", "@angular-devkit/build-ng-packagr": "~0.8.0", - "@angular/cli": "^6.2.0", + "@angular/cli": "^6.2.1", "@angular/compiler-cli": "6.1.7", "@angular/language-service": "6.1.7", "@types/jasmine": "^2.5.53", "@types/jasminewd2": "^2.0.2", "@types/node": "9.3.0", "@types/selenium-webdriver": "^3.0.8", - "alfresco-js-api-node": "2.5.0-b048ff2aad00611aac1c02af531549b60acc0e66", - "codelyzer": "^4.4.3", + "@types/showdown": "^1.7.5", + "alfresco-js-api-node": "^2.5.0", + "codelyzer": "^4.4.4", + "cpr": "^3.0.1", "cspell": "^3.1.3", "jasmine-core": "~2.8.0", "jasmine-reporters": "^2.2.1", diff --git a/projects/my-extension/assets/my-extension.json b/projects/my-extension/assets/my-extension.json new file mode 100644 index 000000000..3e492a708 --- /dev/null +++ b/projects/my-extension/assets/my-extension.json @@ -0,0 +1,30 @@ +{ + "$schema": "../../../extension.schema.json", + "$version": "1.0.0", + "$name": "plugin1", + "$description": "demo plugin", + + "routes": [ + { + "id": "my.extension.route", + "path": "ext/my/route", + "component": "my-extension.main.component" + } + ], + + "features": { + "navbar": [ + { + "id": "my.extension.nav", + "items": [ + { + "id": "my.extension.main", + "icon": "extension", + "title": "My Extension", + "route": "my.extension.route" + } + ] + } + ] + } +} diff --git a/projects/my-extension/karma.conf.js b/projects/my-extension/karma.conf.js new file mode 100644 index 000000000..4c5f8d03f --- /dev/null +++ b/projects/my-extension/karma.conf.js @@ -0,0 +1,31 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage'), + reports: ['html', 'lcovonly'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/projects/my-extension/ng-package.json b/projects/my-extension/ng-package.json new file mode 100644 index 000000000..ed4d8c2eb --- /dev/null +++ b/projects/my-extension/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/my-extension", + "lib": { + "entryFile": "src/public_api.ts" + } +} \ No newline at end of file diff --git a/projects/my-extension/package.json b/projects/my-extension/package.json new file mode 100644 index 000000000..261671ec8 --- /dev/null +++ b/projects/my-extension/package.json @@ -0,0 +1,8 @@ +{ + "name": "my-extension", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^6.0.0-rc.0 || ^6.0.0", + "@angular/core": "^6.0.0-rc.0 || ^6.0.0" + } +} \ No newline at end of file diff --git a/projects/my-extension/src/lib/my-extension.component.spec.ts b/projects/my-extension/src/lib/my-extension.component.spec.ts new file mode 100644 index 000000000..349674994 --- /dev/null +++ b/projects/my-extension/src/lib/my-extension.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MyExtensionComponent } from './my-extension.component'; + +describe('MyExtensionComponent', () => { + let component: MyExtensionComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MyExtensionComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MyExtensionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/my-extension/src/lib/my-extension.component.ts b/projects/my-extension/src/lib/my-extension.component.ts new file mode 100644 index 000000000..64ac67f20 --- /dev/null +++ b/projects/my-extension/src/lib/my-extension.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'lib-my-extension', + template: ` +

+ my-extension works! +

+ `, + styles: [] +}) +export class MyExtensionComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/projects/my-extension/src/lib/my-extension.module.ts b/projects/my-extension/src/lib/my-extension.module.ts new file mode 100644 index 000000000..ff56075f2 --- /dev/null +++ b/projects/my-extension/src/lib/my-extension.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { MyExtensionComponent } from './my-extension.component'; +import { ExtensionService } from '@alfresco/adf-extensions'; + +@NgModule({ + imports: [ + ], + declarations: [MyExtensionComponent], + exports: [MyExtensionComponent], + entryComponents: [MyExtensionComponent] +}) +export class MyExtensionModule { + constructor(extensions: ExtensionService) { + extensions.setComponents({ + 'my-extension.main.component': MyExtensionComponent, + }); + } +} diff --git a/projects/my-extension/src/lib/my-extension.service.spec.ts b/projects/my-extension/src/lib/my-extension.service.spec.ts new file mode 100644 index 000000000..02efff0f8 --- /dev/null +++ b/projects/my-extension/src/lib/my-extension.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { MyExtensionService } from './my-extension.service'; + +describe('MyExtensionService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: MyExtensionService = TestBed.get(MyExtensionService); + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/my-extension/src/lib/my-extension.service.ts b/projects/my-extension/src/lib/my-extension.service.ts new file mode 100644 index 000000000..d67ac35e5 --- /dev/null +++ b/projects/my-extension/src/lib/my-extension.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class MyExtensionService { + + constructor() { } +} diff --git a/projects/my-extension/src/public_api.ts b/projects/my-extension/src/public_api.ts new file mode 100644 index 000000000..e53c40142 --- /dev/null +++ b/projects/my-extension/src/public_api.ts @@ -0,0 +1,7 @@ +/* + * Public API Surface of my-extension + */ + +export * from './lib/my-extension.service'; +export * from './lib/my-extension.component'; +export * from './lib/my-extension.module'; diff --git a/projects/my-extension/src/test.ts b/projects/my-extension/src/test.ts new file mode 100644 index 000000000..e11ff1c97 --- /dev/null +++ b/projects/my-extension/src/test.ts @@ -0,0 +1,22 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'core-js/es7/reflect'; +import 'zone.js/dist/zone'; +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/projects/my-extension/tsconfig.lib.json b/projects/my-extension/tsconfig.lib.json new file mode 100644 index 000000000..89a9991c0 --- /dev/null +++ b/projects/my-extension/tsconfig.lib.json @@ -0,0 +1,32 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "module": "es2015", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "inlineSources": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "types": [], + "lib": [ + "dom", + "es2015" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/projects/my-extension/tsconfig.spec.json b/projects/my-extension/tsconfig.spec.json new file mode 100644 index 000000000..16da33db0 --- /dev/null +++ b/projects/my-extension/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/projects/my-extension/tslint.json b/projects/my-extension/tslint.json new file mode 100644 index 000000000..73f120b7e --- /dev/null +++ b/projects/my-extension/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/src/app/extensions.module.ts b/src/app/extensions.module.ts index 52a22d85b..fac563865 100644 --- a/src/app/extensions.module.ts +++ b/src/app/extensions.module.ts @@ -1,6 +1,7 @@ import { NgModule } from '@angular/core'; import { AcaDevToolsModule } from 'aca-dev-tools'; import { CodeEditorModule } from '@ngstack/code-editor'; +import { MyExtensionModule } from 'my-extension'; // Main entry point for external extensions only. // For any application-specific code use CoreExtensionsModule instead. @@ -13,7 +14,8 @@ import { CodeEditorModule } from '@ngstack/code-editor'; // use local Typings Worker typingsWorkerUrl: 'assets/workers/typings-worker.js' }), - AcaDevToolsModule + AcaDevToolsModule, + MyExtensionModule ] }) export class AppExtensionsModule {} diff --git a/src/assets/app.extensions.json b/src/assets/app.extensions.json index aa9c46969..60e055b4c 100644 --- a/src/assets/app.extensions.json +++ b/src/assets/app.extensions.json @@ -5,7 +5,8 @@ "$references": [ "plugin1.json", "plugin2.json", - "dev.tools.json" + "dev.tools.json", + "my-extension.json" ], "rules": [ diff --git a/tsconfig.json b/tsconfig.json index 6dca9206f..5cb010a3e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,6 +30,12 @@ ], "@alfresco/adf-extensions/*": [ "dist/@alfresco/adf-extensions/*" + ], + "my-extension": [ + "dist/my-extension" + ], + "my-extension/*": [ + "dist/my-extension/*" ] } }, @@ -39,4 +45,4 @@ "angularCompilerOptions": { "preserveWhitespaces": false } -} +} \ No newline at end of file