gravitonian

Generating an app with Angular CLI and preparing it for use with ADF 2.0.0

Blog Post created by gravitonian Employee on Dec 15, 2017

Introduction 

This article is a deep dive into how an ADF application is configured, built, and run. Specifically for ADF version 2.0.0. It's very much a one-time-only type of read that you would do in the beginning of your first ADF project. It will mostly likely benefit you a lot in the long run to know what's in this article. When you are on top of the stuff in this article you would most likely use generators, or clone a GitHub project, when starting a new ADF project.  

 

Article Series

This article is part of series of articles covering ADF 2.0:

 

 

Introduction to ADF

In this section we will look at what ADF really is.

 

Overview

The Alfresco Application Development Framework, referred to as ADF, is built on top of the Angular 5 JavaScript framework. You can think of ADF as a library of Alfresco web components that can be used to build a content management web application and/or a process management web application.

 

There are a number of web components that you can use to integrate your web application with Alfresco Content Services (ACS). Here are some of these components:

 

  • Folder Hierarchy Breadcrumbs - display a breadcrumb with clickable folder path
  • Document List - list folders and files
  • Search - search folders and files
  • Tag - manage and list tags
  • Upload - upload files via button or drag-and-drop
  • Viewer - preview files in the browser
  • Webscript - call a Web Script (i.e. a ReST call)

 

And for integrating with Alfresco Process Services (APS) you have the following components:

 

  • Analytics - display graph reports such as process instance overview
  • Diagram - show process definition diagram, if associated with running process instance then the activities are highlighted according to their state
  • Process Apps - shows a list of process applications
  • Process List - show a list of process instances
  • Process Details - multiple components are available to show different details for a process
  • Task List - show a list of task instances for a process instance(s)
  • Task Details - multiple components are available to show different details for a task

 

There are also a number of generic components that are used with both ACS and APS:

 

  • Toolbar - an extension to the Angular Material toolbar with a title and color
  • Card View - displays properties in a nice layout 
  • Data Table - generic data table implementation that is used by, for example, Document List
  • Drag-and-Drop - Drag and drop files into for example a folder
  • Form - display properties from nodes, tasks, and other sources in a form defined in JSON
  • Login - authenticates with both services
  • User Info - display information about a user

 

Architecture

These ADF components don’t talk directly to the ACS and APS backend services. There are some layers between them that are worth knowing about before you start hacking. The ADF components talk to ADF services, which in turn talks to the Alfresco JS API, which internally calls ACS and APS via their respective ReST APIs. You could use the both the ADF services and the Alfresco JS API directly from your application if there is no ADF component available to do what you want. In fact, you will quite frequently have to use the ADF services in your application to fetch content nodes, process instances, task instances etc.

 

The following picture illustrates the architecture of an ADF solution:

 

Alfresco ADF Architecture

The ADF components and services are implemented in Angular, which in turn is implemented in TypeScript. The Alfresco JavaScript library is pure JavaScript and could be used with any other JavaScript framework. 

 

Application Generator

Before we move on it is worth mentioning that there is an ADF application generator that can be very useful if you just want to quickly get going with an ADF project, such as for a demo or proof-of-concept scenario. It covers use cases for both ACS and APS. It can be used to generate the following types of ADF applications:

 

  • ADF Content Management App (use this template if your app is only going to talk to ACS)
  • ADF Process Management App (use this template if your app is only going to talk to APS)
  • ADF Content and Process Management App

 

On the other hand, if you want to know how to create an Angular CLI application from scratch, and how to set it up to work with ADF version 2.0.0. And you want to be able to pick and choose what ADF components to use, building your custom content and/or process management interface, then read on.

 

Using the App Generator is simple. Install the Yeoman tool. Then install the App Generator as follows:

 

$ sudo npm install generator-alfresco-adf-app -g

Password:

+ generator-alfresco-adf-app@2.0.0

added 201 packages in 5.805s

 

Running the generator is easy:

 

$ yo

? 'Allo Martin! What would you like to do? (Use arrow keys)

  Run a generator

❯ Alfresco Adf App

  ──────────────

  Update your generators

  Install a generator

  Find some help

  Clear global config

 

Select the 'Alfresco Adf App' generator and follow instructions.

Make sure you use the latest 2.0.0 version of the ADF App Generator as older ones will generate an application that maybe has more features than you would like when starting out. If you see the following:

 

martins-macbook-pro:ADF mbergljung$ yo

? 'Allo Martin! What would you like to do? (Use arrow keys)

  Run a generator

❯ Ng2 Alfresco App

  Alfresco Adf App

  ──────────────

  Update your generators

  Install a generator

  Find some help

 

Then that means you got two ADF app generators installed, the new one (i.e. Alfresco Adf App) and the old one (Ng2 Alfresco App). Remove the old one as follows:

 

$ sudo npm uninstall -g generator-ng2-alfresco-app

Prerequisites

This article is written with the assumption that you are starting out from scratch with your ADF project and that you are new to ADF development. If you have worked with Angular before that would be good, but it is not absolutely necessary.

 

Source Code

The associated source code for this article can be found in this GitHub project. It is highly recommended that you have it available when walking through this tutorial. If for some reason you cannot get the code from this article working, then you can always go to the GitHub project for the source of truth.

 

Installing Alfresco Content and Process Services

In this section we will discuss how to install both ACS and APS so that we have them ready when working with any of the ADF components. You will need Alfresco Content Services version 5.2 or higher, Enterprise or Community edition. For APS you will need an Enterprise version 1.6 or higher (Activiti community edition is not yet supported). The reason you need these new versions is because the Alfresco JavaScript API wraps ReST APIs that require these versions.

If you intend to build a client that will only talk to an ACS server, then don’t install APS, and vice versa.

Installing Alfresco Content Services (ACS)

  1. Request an Enterprise trial from https://www.alfresco.com/platform/content-services-ecm/trial/download.
  2. Download the installer via the link in the email:
    If you are on a Mac then download Community installer from Download Alfresco Community ECM Now | Alfresco
    ACS Installer Email
  3. Start the installer and use admin as both the username and password.
  4. Start ACS (On Mac you can start using /Applications/alfresco-content-services/Application Manager, on Windows you can start using C:\alfresco-content-services5.2.1\manager-windows.exe).
  5. Verify that you can login to Alfresco Share with the username and password from http://localhost:8080/share: 

 

Installing Alfresco Process Services (APS)

The easiest way to get going with APS is to start it up via Docker. However we will also look at how to install it with the out-of-the-box installer.

 

Installing APS with Docker

If you don't have Docker CE, download and follow official installation guides here.  

 

When you got Docker installed it is easy to get up and running with APS 1.7.0:

 

$ docker container run -d -p 9080:8080 --name aps170 alfresco/process-services:1.7.0

 

This runs a new Docker container with the name aps164 containing APS version 1.6.4 that you can access on http://localhost:9080/activiti-app. The application that you will create in this article is preconfigured to expect APS to be running on port 9080. If you want to use a different port change the port number in the app file proxy.conf.json.

 

APS requires a license and when you first access it there will be a red information box about uploading a license. You can actually go through and request a trial license as described below, and then upload this license.

If you want to know what APS Docker Images that are available, then have a look here

Installing APS with out-of-the-box installer

  1. Download the installer from the link in the email (Step 1):APS Installer Email
  2. Request an Enterprise trial from https://www.alfresco.com/platform/process-services-bpm/trial/download.
  3. Download a trial license from the link in the above email (Step 2).
  4. Start the installer. At the end make a note of URLs and usernames:
  5. Put the downloaded license file into /Applications/alfresco-process-services170/tomcat/lib.
  6. Change port numbers (e.g. 8080) not to clash with ACS. 
    Open up /Applications/alfresco-process-services170/tomcat/conf/server.xml and change 8005 -> 9005, 8080 - 9080, 8009 -> 9009.   
  7. Start APS (On Mac you can start using /Applications/alfresco-process-services170/StartProcessServices.app, on Windows you can start using C:\alfresco-process-services170\start-process-services.bat).
  8. Verify that you can login to Alfresco Process Services with the username and password from http://localhost:9080/activiti-app:

 

Configure username and password

If your ADF application is only going to talk to ACS, then you don’t have to complete this part, just use the ACS credentials as per installation (e.g. admin/admin).

For the ADF Login component to work properly with both services they need to have the same username and password available. It is also important to make sure that the user has proper permissions within the ACS repository, so files and folders can be managed from ADF applications. The same thing is true for the APS user, which needs to have access to the process applications that should be accessed from the ADF application.

 

It is common to use admin/admin as username/password for ACS. In APS we will have admin@app.activiti.com/admin set up by default. In APS the email address for a user is also used as the username. It is not possible to create a username such as admin in APS.

 

So let’s use admin@app.activiti.com/admin as username/password in both services, which means we need to set up a new user in ACS:

 

  1. Login to ACS at http://localhost:8080/share as admin/admin (or whatever password you specified when installing ACS).
  2. Click on the Admin Tools menu item.
  3. Click on the Users menu item in the left menu.
  4. Click on the New User button.
  5. Fill in the user info as follows:
  6. Make sure the username is admin@app.activiti.com and that the password is admin. Also, add the user to the ALFRESCO_ADMINISTRATORS group so it will have full access to the repository.
  7. Make sure you can login to ACS with the new user:

 

Installing ADF Prerequisites

Alfresco Application Development Framework (ADF) uses the Node.js JavaScript runtime and the npm package manager. So we need to make sure we have them installed with the correct versions. ADF version 2.0.0 requires Node.js version 8. When setting up an Angular project for ADF development it is recommended to use Angular CLI, so we will install that toolkit as well.

 

Installing Node.js

  1. Download from https://nodejs.org/en/download/, click the Current tab and then select a package based on architecture. I’m on MacOS, so selecting macOS installer (.pkg):
  1. Run the package installer
  2. When finished we should see (Note. you don't see this dialog on Windows):
  1. Test the installation and make sure you got node version >=8 and npm >=5:

Martins-MacBook-Pro:~ martin$ node -v

v8.6.0

Martins-MacBook-Pro:~ martin$ npm -v

5.4.2

 

Installing Angular CLI

Angular CLI is a Command Line Interface (CLI) to automate your development workflow when working with Angular applications. It allows you to:

 

  • Create a new Angular application
  • Run a development server with LiveReload support to preview your application during development
  • Add features to your existing Angular application, such as components and services
  • Run your application’s unit tests
  • Run your application’s end-to-end (E2E) tests
  • Build your application for deployment to production

 

To install Angular CLI, run:

Angular CLI version 1.5.x need to be installed/used, such as 1.5.0 or 1.5.4. Version 1.6.0 does not work.

Martins-MacBook-Pro:~ martin$ npm install -g @angular/cli@1.5.4

Which will install the ng command globally on your system.

On Mac/Linux you might have to run as root with sudo npm install...

On Windows you might have to open a Command prompt and run as Administrator.

 

If you already have an earlier version of Angular CLI installed, then you can update to version 1.5.4 with: 


$ npm uninstall -g @angular/cli

$ npm install -g @angular/cli@1.5.4

Be prepared that installing Angular CLI might take some time...

To verify whether your installation completed successfully, you can run ng version:

 

Martins-MacBook-Pro:~ martin$ ng version

   _                      _                 ____ _     ___

  / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|

 / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |

/ ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |

/_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|

              |___/

@angular/cli: 1.5.4

node: 8.6.0

os: darwin x64

Angular:

...

 

Now that you have Angular CLI installed, let’s use it to create a new application that we can prepare for ADF development.

 

Generating an Angular app with Angular CLI

To create a new app you use the ng new <app-name> command. It will create a new directory with the app-name and generate all the needed files in it.

 

The app should support routing between different components (call them pages if you like), so we will add the --routing option. This creates a separate file src/app/app-routing.module.ts. The file includes an empty Routes object that you can fill with routes to different components (i.e. pages). Routing capabilities will come in handy when you start developing a more realistic application that contains multiple pages.

 

We will also set up the project so it is prepared to use SASS. You will get style files ending in .scss (instead of .css) and in the .angular-cli.json configuration file it will set style extension as follows:

 

"defaults": {
  "styleExt": "scss",
  "component": {}
}

 

While executing the command stand in the directory where you want to create a subdirectory with the new application:

 

Martins-MacBook-Pro:ADF mbergljung$ ng new adf-workbench20 --routing --style=scss

  create adf-workbench20/README.md (1030 bytes)

  create adf-workbench20/.angular-cli.json (1252 bytes)

  create adf-workbench20/.editorconfig (245 bytes)

  create adf-workbench20/.gitignore (516 bytes)

  create adf-workbench20/src/assets/.gitkeep (0 bytes)

  create adf-workbench20/src/environments/environment.prod.ts (51 bytes)

  create adf-workbench20/src/environments/environment.ts (387 bytes)

  create adf-workbench20/src/favicon.ico (5430 bytes)

  create adf-workbench20/src/index.html (301 bytes)

  create adf-workbench20/src/main.ts (370 bytes)

  create adf-workbench20/src/polyfills.ts (2667 bytes)

  create adf-workbench20/src/styles.scss (80 bytes)

  create adf-workbench20/src/test.ts (1085 bytes)

  create adf-workbench20/src/tsconfig.app.json (211 bytes)

  create adf-workbench20/src/tsconfig.spec.json (304 bytes)

  create adf-workbench20/src/typings.d.ts (104 bytes)

  create adf-workbench20/e2e/app.e2e-spec.ts (297 bytes)

  create adf-workbench20/e2e/app.po.ts (208 bytes)

  create adf-workbench20/e2e/tsconfig.e2e.json (235 bytes)

  create adf-workbench20/karma.conf.js (923 bytes)

  create adf-workbench20/package.json (1320 bytes)

  create adf-workbench20/protractor.conf.js (722 bytes)

  create adf-workbench20/tsconfig.json (363 bytes)

  create adf-workbench20/tslint.json (3044 bytes)

  create adf-workbench20/src/app/app-routing.module.ts (245 bytes)

  create adf-workbench20/src/app/app.module.ts (395 bytes)

  create adf-workbench20/src/app/app.component.scss (0 bytes)

  create adf-workbench20/src/app/app.component.html (1173 bytes)

  create adf-workbench20/src/app/app.component.spec.ts (1103 bytes)

  create adf-workbench20/src/app/app.component.ts (208 bytes)

Installing packages for tooling via npm.

Installed packages for tooling via npm.

Successfully initialized git.

Project 'adf-workbench20' successfully created.

Be prepared that the 'Installing packages for tooling via npm' might take some time..., don't Ctrl-C out of it.

It is quite fast now though with node.js 8. It will populate the node_modules directory.

You can already see what files that have been created for the adf-workbench20 app. You can also list the directory to see what’s there:

 

Martins-MacBook-Pro:ADF mbergljung$ cd adf-workbench20/

Martins-MacBook-Pro:adf-workbench20 mbergljung$ ls -l

total 704

-rw-r--r--    1 mbergljung  staff    1030 28 Nov 13:59 README.md

drwxr-xr-x    5 mbergljung  staff     170 28 Nov 13:59 e2e

-rw-r--r--    1 mbergljung  staff     923 28 Nov 13:59 karma.conf.js

drwxr-xr-x  810 mbergljung  staff   27540 28 Nov 13:59 node_modules

-rw-r--r--    1 mbergljung  staff  335611 28 Nov 13:59 package-lock.json

-rw-r--r--    1 mbergljung  staff    1320 28 Nov 13:59 package.json

-rw-r--r--    1 mbergljung  staff     722 28 Nov 13:59 protractor.conf.js

drwxr-xr-x   14 mbergljung  staff     476 28 Nov 13:59 src

-rw-r--r--    1 mbergljung  staff     363 28 Nov 13:59 tsconfig.json

-rw-r--r--    1 mbergljung  staff    3044 28 Nov 13:59 tslint.json

 

Behind the scenes, the following happens:

 

  • A new directory adf-workbench20 is created containing the new application.
  • The application is created with Angular version 5 runtime dependencies.
  • The application brings in TypeScript as a development dependency and configures it for you.
  • All source files and directories for the new Angular application are created based on the name we specified (adf-workbench20) and best practices from the official Angular Style Guide.
  • npm dependencies are installed, which means that all dependencies that are specified by default in package.json are downloaded and installed in the local app node_modules directory. This is why it might take a bit of time before the command is finished. However, with Node.js 8 this should be really fast when you have used it for a while.
  • Karma unit test runner is configured for you.
  • Protractor end-to-end test framework is configured for you.
  • Environment files with default settings are created.
  • Git is initialized (i.e. git init) so whenever you start changing or adding stuff, it will be tracked by git.

 

Let's quickly run through and explain what most of these directories and files mean:

 

  • dist - Production or Development builds of our application go here. This directory is not yet there, but will be when you build.
  • src - Application code goes here.
  • src/app Out-of-the-box you get the main app module and component that is bootstrapped with the platformBrowserDynamic bootstrapper. You would typically continue to add modules, components, services etc under the app directory. And then include them in the AppModule.
  • src/assets -  Images and app configuration files. 
  • src/environments - Settings for the different environments, dev, qa, prod.
  • src/index.html - Angular apps are so called Single Page Apps (SPA), this is the single HTML page.
  • src/main.ts - Main application entry point where the AppModule is bootstrapped.
  • src/polyfills.ts A polyfill is a browser fallback, made in JavaScript, that allows functionality you expect to work in modern browsers to work in older browsers. This file contains polyfills for features in ES6 and ES7 not yet supported by browsers.
  • src/styles.scss - Global styles file, put stuff here that you want to use in many different components.
  • src/test.ts - Prepares the test environment and runs all the unit tests.
  • src/tsconfig.app.json - Typescript configuration file for the Angular App.
  • src/typings.d.ts - Typescript type definition file.
  • e2e - The End-2-End functional tests for the application goes here.
  • angular-cli.json - Main Angular CLI config file, also serves as Webpack configuration.
  • karma.conf.js - Unit test runner configuration.
  • package.json - Runtime and development dependency declarations. This is also where scripts are defined. Semver is used to specify version numbers for dependencies. We are going to update this file in this article to use exact versions. Basically locking down exactly what library versions the app is using.
  • package-lock.json - This file is used to lock down dependency versions for the whole dependency tree. The dependencies in package.json are what is called direct dependencies. They in turn depend on other libraries (transitive dependencies). With this file we lock down also transitive dependency versions.
  • protractor.conf.js - End-to-End test runner configuration.
  • tsconfig.json - TypeScript configuration on the root level is used for IDE integration.
  • tslint.json -  Lint configuration for TypeScript code checks.

 

It is preferred to work with the Angular application from a JavaScript IDE such as Visual Studio Code (Open Source) or WebStorm (Commercial):

 

 

Running the App in Development Mode

The basic app module and app component have been generated, so you should now be able to run the app from the adf-workbench20 directory with the ng serve command:

 

Martins-MacBook-Pro:adf-workbench20 mbergljung$ ng serve

** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **

Date: 2017-11-28T14:09:31.012Z                                                          

Hash: cc39d16e4e8227c5a775

Time: 5489ms

chunk {inlineinline.bundle.js (inline) 5.79 kB [entry] [rendered]

chunk {mainmain.bundle.js (main) 24.4 kB [initial] [rendered]

chunk {polyfillspolyfills.bundle.js (polyfills) 557 kB [initial] [rendered]

chunk {stylesstyles.bundle.js (styles) 35.3 kB [initial] [rendered]

chunk {vendorvendor.bundle.js (vendor) 8.04 MB [initial] [rendered]

 

webpack: Compiled successfully.

 

Access the app from a browser via http://localhost:4200:

 

 

Not much to brag about, but it is a starting point!

 

Behind the scenes, the following happens:

 

  1. Angular CLI loads its configuration from .angular-cli.json
  2. And runs Webpack to build and bundle all JavaScript and CSS code
  3. And starts webpack dev server to preview the result on localhost:4200

 

Notice that the ng serve command does not exit and return to your terminal prompt after step 3. Instead, because it includes LiveReload support, the process actively watches your src directory for file changes. When a file change is detected, step 2 is repeated and a notification is sent to your browser so it can refresh automatically.

 

This also means that if you make any changes to stuff outside the src/ directory, such as .angular-cli.json, then you need to restart the server for them to take effect.

 

To stop the process and return to your prompt, press ctrl-c.

Angular CLI is tightly integrated with Webpack, so you will for example not see a webpack.config.js file in the same directory as package.json. Instead all config for things like webapp assets are done in Angular CLI’s config file, .angular-cli.json.

Introduction to Webpack

You might be wondering what Webpack is. It's an open-source module bundler for JavaScript applications. When Webpack processes your application, it recursively builds a dependency graph that includes every module your application needs, then packages all of those modules into a small number of bundles to be loaded by the browser. 

 

Webpack is a very powerful module bundler. A bundle is a JavaScript file that incorporates assets that belong together and should be served to the client in a response to a single file request. A bundle can include JavaScript, CSS styles, HTML, and almost any other kind of file.

 

Webpack scans your application source code, looking for import statements (e.g. import { Component } from '@angular/core';), building a dependency graph, and emitting one or more bundles. With plugins and rules, Webpack can preprocess and minify different non-JavaScript files such as TypeScript, SASS, and LESS files.

 

You determine what Webpack does and how it does it with a JavaScript configuration file, webpack.config.js. Angular CLI uses Webpack under the hood, and all configuration for it is instead in .angular-cli.json. You will not see a webpack.config.js in an Angular CLI app.

 

You can see the bundles that are generated by Webpack for our app when we started it above:

  • inline.bundle.js - This is the Webpack loader. A tiny file with Webpack utilities that are needed when loading other files. Eventually this will be written inside the index.html file itself and not being generated as a separate file at all.
  • main.bundle.js - Your own code and anything else you imported.
  • vendor.bundle.js - This is generated by default in dev mode, and ignored by default in prod mode (ng build -prodor ng serve -prod). It includes the Angular libraries with little or no modification. This is to speed up the build process. Also some people think it's a good idea to keep these in a separate file when it doesn't change much and then it can be cached for longer.
  • polyfills.bundle.js - Contains the polyfills.
  • styles.bundle.js - Contains the styles.

 

Introduction to Angular CLI Configuration

The Angular CLI configuration is done in the .angular-cli.json file and it is important to understand the different parts of this file before moving on. We have already mentioned this file a couple of times and we know that the Webpack configuration is done via this file too, there is no webpack.config.json.  

 

The following list explains the most important parts of the file:

 

  • apps - an array of application configurations (It is possible to manage more than one app config, for example if you have a special development configuration...).
  • apps.root - points to the source code for the application.
  • apps.outDir - points to the output directory for distribution files (created when you run ng build).
  • apps.assets - put here a list of all application assets to include, such as images, i18n resources etc, we will add a lot of stuff here.
  • apps.index - points to the index.html file to use.
  • apps.main - points to the main JavaScript file that is the entry point into the application.
  • apps.polyfills - points to the polyfils file to include.
  • apps.test - points to the file with unit test configuration.
  • apps.tsconfig - TypeScript configuration for the application.
  • apps.prefix - use this prefix for all new component selectors (e.g. selector: 'app-root').
  • apps.styles - put here a list of all stylesheets (CSS) that should be included. We will add stuff here a lot.
  • apps.scripts - put here a list of all scripts (JS) that should be included. We will add stuff here a lot. 

 

As we can see, everything is controlled via this file.

 

Adding Dependencies and Resources to the App

Every ADF based application will of course need a lot of libraries and resources to run. To add these we update the following files in the adf-workbench20 application:

 

  • package.json - used to configure dependencies (i.e. libraries) that are needed by the application during runtime and development. If you are new to package.json, then it might help to know that it is to npm what a POM file is to maven, it defines dependencies for the application.
  • .angular-cli.json - as seen in the previous section, this file is used to configure assets (i.e. resources such icons), styles, and JS files that are used by the application. Angular CLI is integrated with Webpack, which will bundle these files up into something that can be run.

 

Finding out what library versions ADF 2.0.0 requires

It is very important that the libraries we set up as dependencies for the application matches the library versions that the ADF Components expects to use. We will be using ADF version 2.0.0 so we need to find out what Angular version it expects to use, what Angular Material components version, etc. We can do this by using a utility called npm-remote-ls.

 

Install it like this:

 

Martins-MacBook-Pro:adf-workbench20 martin$ npm install -g npm-remote-ls

 

This installs this utility globally on your machine (-g), and not in the node_modules directory for the adf-workbench20 app. To find out the dependencies that ADF version 2.0.0 uses you can pick one of its libraries, such as @alfresco/adf-core, and run the tool on it:

 

Martins-MacBook-Pro:adf-workbench20 martin$ npm-remote-ls @alfresco/adf-core@2.0.0

└─ @alfresco/adf-core@2.0.0

   ├─ @angular/animations@5.0.0

     └─ tslib@1.8.0

   ├─ @angular/compiler@5.0.0

     └─ tslib@1.8.0

   ├─ @angular/http@5.0.0

     └─ tslib@1.8.0

   ├─ @angular/cdk@5.0.0-rc0

     └─ tslib@1.8.0

   ├─ @angular/flex-layout@2.0.0-beta.10

     └─ tslib@1.8.0

   ├─ @angular/common@5.0.0

     └─ tslib@1.8.0

   ├─ @angular/forms@5.0.0

     └─ tslib@1.8.0

   ├─ @angular/core@5.0.0

     └─ tslib@1.8.0

   ├─ @angular/material-moment-adapter@5.0.0-rc0

     └─ tslib@1.8.0

   ├─ alfresco-js-api@2.0.0

     ├─ event-emitter@0.3.4

       ├─ d@0.1.1

         └─ es5-ext@0.10.37

       └─ es5-ext@0.10.37

         ├─ es6-iterator@2.0.3

           ├─ d@1.0.0

             └─ es5-ext@0.10.37

           ├─ es6-symbol@3.1.1

           └─ es5-ext@0.10.37

         └─ es6-symbol@3.1.1

             ├─ d@1.0.0

             └─ es5-ext@0.10.37

     └─ superagent@3.4.1

       ├─ extend@3.0.1

       ├─ mime@1.6.0

       ├─ form-data@2.3.1

         ├─ combined-stream@1.0.5

           └─ delayed-stream@1.0.0

         ├─ asynckit@0.4.0

         └─ mime-types@2.1.17

           └─ mime-db@1.30.0

       ├─ debug@2.6.9

         └─ ms@2.0.0

       ├─ methods@1.1.2

       ├─ cookiejar@2.1.1

       ├─ formidable@1.1.1

       ├─ qs@6.5.1

       ├─ component-emitter@1.2.1

       └─ readable-stream@2.3.3

           ├─ inherits@2.0.3

           ├─ safe-buffer@5.1.1

           ├─ core-util-is@1.0.2

           ├─ util-deprecate@1.0.2

           ├─ isarray@1.0.0

           ├─ string_decoder@1.0.3

             └─ safe-buffer@5.1.1

           └─ process-nextick-args@1.0.7

   ├─ @angular/platform-browser-dynamic@5.0.0

     └─ tslib@1.8.0

   ├─ hammerjs@2.0.8

   ├─ core-js@2.4.1

   ├─ chart.js@2.5.0

     ├─ chartjs-color@2.2.0

       ├─ chartjs-color-string@0.5.0

         └─ color-name@1.1.3

       └─ color-convert@0.5.3

     └─ moment@2.19.3

   ├─ @angular/material@5.0.0-rc0

     └─ tslib@1.8.0

   ├─ minimatch@3.0.4

     └─ brace-expansion@1.1.8

       ├─ balanced-match@1.0.0

       └─ concat-map@0.0.1

   ├─ @ngx-translate/core@8.0.0

   ├─ moment@2.15.2

   ├─ raphael@2.2.7

     └─ eve-raphael@0.5.0

   ├─ zone.js@0.8.14

   ├─ reflect-metadata@0.1.10

   ├─ rxjs@5.5.2

     └─ symbol-observable@1.1.0

   ├─ systemjs@0.19.27

     └─ when@3.7.8

   ├─ ng2-charts@1.6.0

     └─ chart.js@2.7.1

       ├─ chartjs-color@2.2.0

       └─ moment@2.18.1

   ├─ @angular/platform-browser@5.0.0

     └─ tslib@1.8.0

   ├─ pdfjs-dist@1.5.404

     └─ node-ensure@0.0.0

   └─ @angular/router@5.0.0

      └─ tslib@1.8.0

 

Here we can immediately find out the expected versions for several important libraries:

 

  • Angular libs - 5.0.0
  • Angular CDK - 5.0.0-rc0
  • Angular Material - 5.0.0-rc0
  • Angular Flex Layout - 2.0.0-beta.10
  • Core JS - 2.4.1
  • Moment - 2.15.2
  • Minimatch - 3.0.4
  • HammerJs - 2.0.8
  • NGX Translate Core - 8.0.0
  • RxJS - 5.5.2
  • Reflect Metadata - 0.1.10
  • Zone - 0.8.14
  • Raphael - 2.2.7
  • Chart.js - 2.5.0 
  • ng2 Charts - 1.6.0
  • PDF JS Dist - 1.5.404
  • Alfresco JS API - 2.0.0

 

We now have all the necessary version information to be able to configure the application with the necessary dependencies and resources so ADF version 2.0.0 will work smoothly.

 

To check dependencies for a beta version do for example:

 

Martins-MacBook-Pro:adf-workbench20 martin$ npm-remote-ls ng2-alfresco-core@2.0.0-beta3

 

Update Library Versions

In this section we will update a number of library/package versions in the generated package.json file.

 

Update Angular version

Start by updating the generated application to use an absolute Angular version 5.0.0. Note here that we changed ^5.0.0 to 5.0.0, removing the caret, which otherwise will update you to the latest version. 

 

Open package.json and update it to look as follows:

 

{
  "name": "adf-workbench20",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "core-js": "^2.4.1",
    "rxjs": "^5.5.2",
    "zone.js": "^0.8.14"
  },
...

 

Update Core.js version

The Core.js version is the same. Just need to remove the caret. Open package.json and update the dependencies section to look as follows:

 

{
  "name": "adf-workbench20",
...
  "private": true,
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
      "core-js": "2.4.1",
    "rxjs": "^5.5.2",
    "zone.js": "^0.8.14"
  },
...

 

Update Reactive Extensions for JavaScript version

The Reactive Extensions for JavaScript (RxJS) is a set of libraries to compose asynchronous and event-based programs using observable collections and Array#extras style composition in JavaScript.

 

The version of RxJS in the generated project is correct, we just need to remove the caret in front of it so we don't get any surprise updates that makes the app behave weird, update it as follows in package.json:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "core-js": "2.4.1",
      "rxjs": "5.5.2",
    "zone.js": "^0.8.14"
  },
...

 

To switch off numerous and unnecessary type warnings related to the RxJs library, update the root Typescript configuration (for the IDE) file adf-workbench20/tsconfig.json and the skipLibCheck and paths properties as follows:

 

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ],
    "skipLibCheck": true,
    "paths": {
      "rxjs/*": ["../node_modules/rxjs/*" ],
      "@angular/*": ["../node_modules/@angular/*"]
    }

  }
}

 

Update Zone version

The Zone library provides a way to represent the dynamic extent of asynchronous calls in Node. Just like the scope of a function defines where it may be used, the extent of a call represents the lifetime that is it active.

 

The version of Zone in the generated project is not correct, update it as follows in package.json:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "core-js": "2.4.1",
    "rxjs": "5.5.2",
      "zone.js": "0.8.14"
  },
...

 

Add Libraries

In this section we will add a number of library/package versions to the generated package.json file.

 

Add Angular Material Design Components

The styling of the ADF Components is based on Google Material Design. To implement the ADF components so they follow Material Design styling the Angular Material Design components library is used. We need to install it and we can then also use these Angular Material components when building our UI.

 

Open up package.json and add the @angular/cdk and @angular/material library dependencies:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
       "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
       "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "core-js": "2.4.1",
    "rxjs": "5.5.2",
    "zone.js": "0.8.14"
  },
...

 

The Angular CDK is comprised of a bunch of services, directives, components, classes, modules, etc to make our lives easier when developing Angular components. The CDK actually provides general-purpose tools for building components that are not coupled to Material Design.

 

Add Angular Flex Layout

The ADF framework uses the Angular Flex Layout, which provides a sophisticated layout API using Flexbox CSS + mediaQuery. This module provides Angular (v4.1 and higher) developers with component layout features using a custom Layout API, mediaQuery observables, and injected DOM flexbox-2016 CSS stylings. 

 

Bring in the library as follows in package.json:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
      "@angular/flex-layout": "2.0.0-beta.10",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "core-js": "2.4.1",
    "rxjs": "5.5.2",
    "zone.js": "0.8.14"
  },
...

 

Add moment to manage date and time in JavaScript

The moment library provides Angular pipes for manipulating display of date and time. Add it as a dependency in package.json:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/flex-layout": "2.0.0-beta.10",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "core-js": "2.4.1",
      "moment-es6": "1.0.0",
      "moment": "2.15.2",
    "rxjs": "5.5.2",
    "zone.js": "0.8.14"
  },
...

We can see here that we also add another moment related library called moment-es6. This module exports momentjs library object as ES6 style default field.

 

For moment to work we need to load the JavaScript file for it in .angular-cli.json as follows:

 

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "adf-workbench20"
  },
  "apps": [
    {
...
      "scripts": [ 
        "../node_modules/moment/min/moment.min.js"
      ],
...

 

This script will be loaded exactly as if you had added it via a <script> tag inside index.html. Note also that any stylesheet file specified in the styles section will be loaded exactly as if you added it in a <link> tag inside index.html. You might be tempted to just specify these in the index.html file directly, doing this will not get them packaged up into a bundle by webpack.

 

The apps[0].styles will end up in the dist/styles.bundle.js bundle file and the apps[0].scripts will end up in the dist/scripts.bundle.js bundle file.

 

Add ngx-translate to manage internationalization

Ngx-Translate is an internationalization library for Angular 2+. It lets you define translations for your content in different languages and switch between them easily.  Add it as a dependency in package.json:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/flex-layout": "2.0.0-beta.10",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
      "@ngx-translate/core": "8.0.0",
    "core-js": "2.4.1",
    "moment-es6": "1.0.0",
    "moment": "2.15.2",
    "rxjs": "5.5.2",
    "zone.js": "0.8.14"
  },

 

Add Diagram and Chart Libs

There are several components in ADF that displays diagrams and charts. The backing libraries for these components are Raphael, Chart.js, Ng2-Charts. Add the necessary dependencies in package.json as follows:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/flex-layout": "2.0.0-beta.10",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "@ngx-translate/core": "8.0.0",
      "chart.js": "2.5.0",
    "core-js": "2.4.1",
    "moment-es6": "1.0.0",
    "moment": "2.15.2",
      "ng2-charts": "1.6.0",
      "raphael": "2.2.7",
    "rxjs": "5.5.2",
    "zone.js": "0.8.14"
  },

The Raphael library requires that a JS file is loaded. Set this up in .angular-cli.json as follows:

 

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "adf-workbench20"
  },
  "apps": [
    {
...
      "scripts": [
        "../node_modules/raphael/raphael.min.js",
        "../node_modules/moment/min/moment.min.js"
      ],

 

Add Document Viewer Lib

The document viewer component in ADF uses a library called PDFJS. Add the dependency in package.json:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/flex-layout": "2.0.0-beta.10",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "@ngx-translate/core": "8.0.0",
    "chart.js": "2.5.0",
    "core-js": "2.4.1",
    "moment-es6": "1.0.0",
    "moment": "2.15.2",
    "ng2-charts": "1.6.0",
      "pdfjs-dist": "1.5.404",
    "raphael": "2.2.7",
    "rxjs": "5.5.2",
    "zone.js": "0.8.14"
  },

The PDFJS library requires that some Assets and JS files are loaded. Set this up in .angular-cli.json as follows:

 

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "adf-workbench20"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico",
         {
          "glob": "pdf.worker.js",
          "input": "../node_modules/pdfjs-dist/build",
          "output": "./"
        }
      ],
...
      "scripts": [
        "../node_modules/pdfjs-dist/build/pdf.js",
        "../node_modules/pdfjs-dist/web/pdf_viewer.js",
        "../node_modules/raphael/raphael.min.js",
        "../node_modules/moment/min/moment.min.js"
      ],
...

The PDFJS library also need to be initialized when the application is loaded via the main entry point. Update the src/main.ts file as follows:

 

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

import 'hammerjs';
import 'chart.js';
import 'ng2-charts';

import pdfjsLib from 'pdfjs-dist';
pdfjsLib.PDFJS.workerSrc = 'pdf.worker.js';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.log(err));

 We take the opportunity to add some other libraries too at this point (i.e. hammer.js, chart.js, and ng2-charts).

 

Add Miscellaneous Libraries that ADF is Dependent on

The following libraries are also used by ADF:

 

  • classlist - Not really an Element#classList polyfill. IE9 doesn’t have classList, and other browsers have incomplete implementations; hence, this module.
  • hammerjs - Supporting touch screens.
  • custom-event-polyfill Polyfill for creating CustomEvents on IE9/10/11 if native implementation is missing.
  • intlPolyfill the ECMA-402 Intl API.
  • minimatchA minimal RegExp matching utility.
  • reflect-metadataPolyfill for Metadata Reflection API.
  • web-animations-jsJavaScript implementation of the Web Animations API.

 

Add them to package.json as follows:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/flex-layout": "2.0.0-beta.10",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "@ngx-translate/core": "8.0.0",
    "chart.js": "2.5.0",
      "classlist.js": "1.1.20150312",
    "core-js": "2.4.1",
      "custom-event-polyfill": "0.3.0",
      "hammerjs": "2.0.8",
      "intl": "1.2.5",
      "minimatch": "3.0.4",
    "moment-es6": "1.0.0",
    "moment": "2.15.2",
    "ng2-charts": "1.6.0",
    "pdfjs-dist": "1.5.404",
    "raphael": "2.2.7",
      "reflect-metadata": "0.1.10",
    "rxjs": "5.5.2",
      "web-animations-js": "2.3.1",
    "zone.js": "0.8.14"
  },

 

Lock down TypeScript version

By default the generated project will have the typescript version configured in a way such as this:

 

"typescript": "~2.4.2"

 

This is not ideal as the tilde character in front of it means that whenever a patch version is released by Microsoft, such as version 2.4.3, our project could be updated with the new version without us realising it. This can be bad news as this could effect some ADF component, and it could take a while before we realise what is going on. So remove the tilde and specify it as follows instead in the devDependencies section:

 

...
"devDependencies": {
    "@angular/cli": "1.5.4",
    "@angular/compiler-cli": "5.0.0",
    "@angular/language-service": "5.0.0",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "^4.0.1",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~3.2.0",
    "tslint": "~5.7.0",
      "typescript": "2.4.2"
  }
...

 

Adding ADF Dependencies and Resources

There are only a few ADF libraries that we need to add to the application to prepare it for development of a Content Management application or a Process Management application. At this point we can also configure Google Material Styles.

 

Adding the Alfresco JavaScript Library

Alfresco ADF components uses the Alfresco JavaScript library to talk to ACS and APS. This JavaScript library basically abstracts the Content Services REST API and the Process Services REST API.

 

Add it as follows in package.json:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/flex-layout": "2.0.0-beta.10",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "@ngx-translate/core": "8.0.0",
      "alfresco-js-api": "2.0.0",
    "chart.js": "2.5.0",
    "classlist.js": "1.1.20150312",
    "core-js": "2.4.1",
    "custom-event-polyfill": "0.3.0",
    "hammerjs": "2.0.8",
    "intl": "1.2.5",
    "minimatch": "3.0.4",
    "moment-es6": "1.0.0",
    "moment": "2.15.2",
    "ng2-charts": "1.6.0",
    "pdfjs-dist": "1.5.404",
    "raphael": "2.2.7",
    "reflect-metadata": "0.1.10",
    "rxjs": "5.5.2",
    "web-animations-js": "2.3.1",
    "zone.js": "0.8.14"
  },
...

 

This JS library can also be used directly in cases where there are no ADF components that fit the requirements. Note that the Alfresco JavaScript library follows the same versioning as the ADF, so we specify 2.0.0.

 

Adding the ADF Libraries

There are only a few ADF libraries that we need to add to the application to bring in all the ADF components and services:

 

  • @alfresco/adf-core - general components and services not specific to content or process management.
  • @alfresco/adf-content-services - components specific to content management with ACS, such as a Document List.
  • @alfresco/adf-insight - components specific to ACS analytics and diagrams.
  • @alfresco/adf-process-services - components specific to process management with APS, such as a Task List.

 

Add these libs as follows in package.json:

 

{
  "name": "adf-workbench20",
...
  "dependencies": {
    "@angular/animations": "5.0.0",
    "@angular/cdk": "5.0.0-rc0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/flex-layout": "2.0.0-beta.10",
    "@angular/forms": "5.0.0",
    "@angular/http": "5.0.0",
    "@angular/material": "5.0.0-rc0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/router": "5.0.0",
    "@ngx-translate/core": "8.0.0",
    "alfresco-js-api": "2.0.0",
      "@alfresco/adf-core": "2.0.0",
      "@alfresco/adf-content-services": "2.0.0",
      "@alfresco/adf-insights": "2.0.1",
      "@alfresco/adf-process-services": "2.0.0",
    "chart.js": "2.5.0",
    "classlist.js": "1.1.20150312",
    "core-js": "2.4.1",
    "custom-event-polyfill": "0.3.0",
    "hammerjs": "2.0.8",
    "intl": "1.2.5",
    "minimatch": "3.0.4",
    "moment-es6": "1.0.0",
    "moment": "2.15.2",
    "ng2-charts": "1.6.0",
    "pdfjs-dist": "1.5.404",
    "raphael": "2.2.7",
    "reflect-metadata": "0.1.10",
    "rxjs": "5.5.2",
    "web-animations-js": "2.3.1",
    "zone.js": "0.8.14"
  },
...

 

Note that for the @alfresco/insight library we use version 2.0.1 

At this point you might be thinking,  why would we bring in all the components and services if we are not going to use all of them? For example, if we are going to build a Content Management application we will not need the Process Services components. We don't need to worry about this as Webpack does something called Tree Shaking that will remove all "dead code", so we will not have excess code in the final app artifact.

 

Adding the ADF Resources

The styling of the ADF Components is based on Google Material Design. In this section we add the necessary styles, icons, JavaScript files etc. 

 

We need to tell the app about the i18n resources, icon resources, etc that are embedded in the ADF libraries. This is done in the .angular-cli.json file in the assets section. We want these assets to be packaged and bundled up by the Webpack tool, making them available during runtime.

 

Add the new assets to the assets sections in the .angular-cli.json file:

 

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "adf-workbench20"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico",
        {
          "glob": "**/*",
          "input": "../resources",
          "output": "./resources"
        },
        {
          "glob": "**/
*",
          "input": "../node_modules/@alfresco/adf-core/prebuilt-themes",
          "output": "./assets/prebuilt-themes"
        },
        {
          "glob": "**/*",
          "input": "../node_modules/@alfresco/adf-core/bundles/assets",
          "output": "./assets/"
        },
        {
          "glob": "**/
*",
          "input": "../node_modules/@alfresco/adf-insights/bundles/assets",
          "output": "./assets/"
        },
        {
          "glob": "**/*",
          "input": "../node_modules/@alfresco/adf-process-services/bundles/assets",
          "output": "./assets/"
        },
        {
          "glob": "**/
*",
          "input": "../node_modules/@alfresco/adf-content-services/bundles/assets",
          "output": "./assets/"
        },
        {
          "glob": "pdf.worker.js",
          "input": "../node_modules/pdfjs-dist/build",
          "output": "./"
        }
      ],
...

 

We can see here that the prebuilt ADF Google Material themes will be copied into, and available, in the /assets/prebuilt-themes directory. What we also do here in the app[0].assets section is to tell Angular CLI that all the assets, such as images and i18n resource files, that are located in the adf-core, adf-process-services, adf-insights, and adf-content-services packages should be copied into the ./assets directory.

 

Note that we are referencing the node_modules directory relatively from the src directory, not from the directory where the .angular-cli.json file is located.

 

And now add a new property called stylePreprocessorOptions to the .angular-cli.json file as follows:

 

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "adf-workbench20"
  },
  "apps": [
    {
...
      "stylePreprocessorOptions": {
        "includePaths": [
          "../node_modules/"
        ]
      }
    }
  ],
...

 

In order to simplify style imports we also add style include paths via the stylePreprocessorOptions entry in .angular-cli.json. Files in that folder, for example, ./node_modules/@alfresco/adf-content-services/_theming.scss, can be imported from anywhere in your project without the need for a relative path:

 

/* src/app/app.component.scss
  A relative path works */

@import '../node_modules/@alfresco/adf-content-services/_theming.scss';
/* But now this works as well */
@import '~@alfresco/adf-content-services/theming';

 

Adding Google Material Design Resources

The styling of the ADF Components is based on Google Material Design. In this section we add the necessary styles and icons to the application.

The Google Material Design Icons should be loaded via the src/index.html file, update it as follows:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>ADF Workbench 2.0</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link href="https://fonts.googleapis.com/css?family=Muli" rel="stylesheet">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

</head>
<body>
  <app-root></app-root>
</body>
</html>

The Google Material Design Theme is set up in the src/styles.scss file as follows:

@import '~@alfresco/adf-core/prebuilt-themes/adf-blue-orange.css';
@import '~@alfresco/adf-content-services/theming';
@import '~@alfresco/adf-process-services/theming';
@import '~@alfresco/adf-core/theming';
@import '~@angular/material/theming';

@include mat-core($alfresco-typography);

$primary: mat-palette($alfresco-accent-orange);
$accent: mat-palette($alfresco-accent-purple);
$warn: mat-palette($alfresco-warn);
$theme: mat-light-theme($primary, $accent, $warn);

@include angular-material-theme($theme);
@include adf-content-services-theme($theme);
@include adf-process-services-theme($theme);
@include adf-core-theme($theme);

body, html {
  margin: 0;
  height: 100%;
  overflow: hidden;
  font-size: mat-font-size($alfresco-typography, body-1);
  font-family: mat-font-family($alfresco-typography);
  line-height: mat-line-height($alfresco-typography, body-1);
}

body {
  overflow: auto;
}

 

Global Styles

As you can see from the above app[0].styles configuration the styles.scss file was already included in our .angular-cli.json file. This is where you add style information that is relevant to the entire application, such as the Google Material Design theme that the app will use. And so far, this is what you would expect. But, as you know, Angular 2 takes styling to the next level.

Component Styles

Assuming you have done a bit of Angular web development, you know that you can also add style information in your components.  If you open the existing src/app/app.component.ts file, you will notice that there is both a templateUrl and a styleUrls attribute in the @Component() metadata section:

 

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'app';
}

 

In the styleUrls property you can specify a list of relative URLs of CSS files to include.

If we include CSS information in the CSS files, you will see that when we render the page, the CSS gets rewritten so that the CSS is scoped to the component. Looking at an ADF component, such as the LoginComponent, we can see that this is used:

 

@Component({
    selector: 'adf-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.scss'],
    host: {'(blur)': 'onBlur($event)'},
    encapsulation: ViewEncapsulation.None
})
export class LoginComponent implements OnInit {

 

Install all Dependencies

It’s time to install all the libraries that we defined in package.json. We need to do this now otherwise it will be difficult to work with the components from our IDE as it would not know anything about the modules and classes we are trying to use. Basically we need to get the local /node_modules directory populated with all the new libraries that we configured.

 

Remove the node_modules directory and then run npm install to download all the extra libraries that we have defined in package.json to node_modules:

 

Martins-MacBook-Pro:adf-workbench20 mbergljung$ rm -rf node_modules/

Martins-MacBook-Pro:adf-workbench20 mbergljung$ npm install

...

Testing binary

Binary is fine

added 1110 packages in 15.43s

Martins-MacBook-Pro:adf-workbench20 mbergljung$ npm dedup

moved 1 package in 3.132s

 

After we have run npm install we also run npm dedup. This will remove any duplicate transitive dependencies. If a transitive dependency already exists it will not be downloaded again, but this depends on the order we have specified the libraries in package.json. So always good to do a dedup after an install.

 

You might be tempted to run npm update instead of npm install. This will also work but it changes package.json dependencies version specifications. It will add carets in front of version numbers, so not what we want. So be careful with this command.

List the node_modules directory if you want to find out all the downloaded libs:

 

Martins-MacBook-Pro:node_modules mbergljung$ ls -l|more

total 0

drwxr-xr-x    6 mbergljung  staff    204 29 Nov 13:26 @alfresco

drwxr-xr-x   18 mbergljung  staff    612 29 Nov 13:26 @angular

drwxr-xr-x    5 mbergljung  staff    170 29 Nov 13:26 @angular-devkit

drwxr-xr-x    4 mbergljung  staff    136 29 Nov 13:26 @ngtools

drwxr-xr-x    3 mbergljung  staff    102 29 Nov 13:26 @ngx-translate

drwxr-xr-x    3 mbergljung  staff    102 29 Nov 13:26 @schematics

drwxr-xr-x    7 mbergljung  staff    238 29 Nov 13:26 @types

drwxr-xr-x    6 mbergljung  staff    204 29 Nov 13:26 abbrev

drwxr-xr-x    7 mbergljung  staff    238 29 Nov 13:26 accepts

drwxr-xr-x    9 mbergljung  staff    306 29 Nov 13:26 acorn

...

 

Check that no duplicate libs are included

Note here that the @alfresco/adf-core library has all its dependencies specified in its own package.json, as would be expected, and we call these transitive dependencies. As we saw earlier on, we can easily find out the dependencies for a library we use with the npm-remote-ls tool.

 

Now it's time to make sure that the package.json for our adf-workbench20 application has been configured with matching ADF 2.0 libraries. In your IDE, navigate into the node_modules directory and look up the @alfresco/adf-core library. You should see something like this:

 

 

We should not see any node_modules directory for the  @alfresco/adf-core library if we have configured the app’s package.json correctly. On the other hand, if we have not configured the same library versions as ADF 2.0 expects, then we could see something like this:

 

 

In this case the core-js library has been configured with a different version in package.json than adf-core depends on, so it loads its own version. And this means that we could experience problems during runtime.

Make sure that the app you are building uses the same versions for all libraries that ADF depends on.

Import the ADF Core Module into the Application

The ADF Core module provides all the services that the ADF components needs, such as AppConfigService, AuthenticationService, NodeService, AppsProcessService, SearchService etc. It also provides some common components, such as ToolbarComponentUserInfoComponent, ViewerComponent, LoginComponent etc, which might be used frequently.

 

Open up the src/app/app.module.ts file and import the ADF CoreModule from the @alfresco/adf-core package:  

 

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';

import { CoreModule } from '@alfresco/adf-core';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    CoreModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

Configure the ADF App with the location of ACS and APS

The ADF app needs to be configured with the location of the ACS and the APS servers. We don’t want to hardcode this in component code. Fortunately there is a file called app.config.json that can be used for this. The ADF framework will automatically look for it.

 

Create it with the following content and put it in the src directory:

 

{
  "ecmHost": "http://{hostname}{:port}",
  "bpmHost": "http://{hostname}{:port}",
  "application": {
    "name": "Alfresco ADF Appplication"
  },
  "languages": [
    {
      "key": "en",
      "label": "English"
    },
    {
      "key": "fr",
      "label": "French"
    },
    {
      "key": "de",
      "label": "German"
    },
    {
      "key": "it",
      "label": "Italian"
    },
    {
      "key": "es",
      "label": "Spanish"
    },
    {
      "key": "ja",
      "label": "Japanese"
    },
    {
      "key": "nl",
      "label": "Dutch"
    },
    {
      "key": "pt-BR",
      "label": "Brazilian Portuguese"
    },
    {
      "key": "nb",
      "label": "Norwegian"
    },
    {
      "key": "ru",
      "label": "Russian"
    },
    {
      "key": "zh-CN",
      "label": "Simplified Chinese"
    }
  ],
  "logLevel": "trace"
}

 

Version 2.0 of the application development framework supports a number of languages, so we add them at the same time.

 

The app.config.json file is not loaded unless we configure it to be bundled as an asset. Open up .angular-cli.json and add it to the assets section as follows:

 

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "adf-workbench20"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico",
        "app.config.json",
        {
          "glob": "**/*",
          "input": "../resources",
          "output": "./resources"
        },
        ...
      ],
...

 

You are probably wondering about the URLs in the app.config.json file. What values would be substituted for the hostname and port variables. At runtime the {hostname} and {port} variables will be replaced with the data from the running application, such as localhost and 4200. The ACS and the APS servers are obviously not running both on localhost:4200, only the app runs on this address, so how does that work. A Webpack web proxy is used as an intermediate, solving also the CORS problem. We need to add a file called adf-workbench20/proxy.conf.json with the following content:

 

{
  "/alfresco": {
    "target": "http://localhost:8080",
    "secure": false,
    "changeOrigin": true
  },
  "/activiti-app": {
    "target": "http://localhost:9080",
    "secure": false,
    "changeOrigin": true
  }
}

 

The target URLs need to match the installations we did earlier on for ACS (http://localhost:8080/alfresco) and APS (http://localhost:9080/activiti-app). 

If you are using just one of the backend services, for example ACS. Then you don't need to worry about configuring the other one (e.g. /activiti-app). And vice versa.

Now, the proxy.conf.json file is not magically read by Webpack, we need to configure Webpack with the location of it. Open up .angular-cli.json and update the defaults section as follows:

 

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "adf-workbench20"
  },
...
  "defaults": {
    "styleExt": "scss",
    "component": {
    },
    "serve": {
      "proxyConfig": "proxy.conf.json",
      "port": 4200
    }
  }
}

By using the Webpack proxy we don’t need to configure CORS in ACS or APS.

So what all this means is that a call to for example ACS will be using the http://localhost:4200/alfresco URL, which does not cause any CORS problems as the host and port are the same as where the app is running. This URL will then be rewritten via the Webpack proxy to http://127.0.0.1:8080/, where the ACS backend is running.

 

Logging into ACS and APS

The first thing that we are going to need to do in our app is to login to Content Services and/or Process Services. We can do this with the ADF Login component. When we have a session with these services we can start using other components, such as the Document List. The login component is available in the @alfresco/adf-core library, which is already installed.

 

Adding the ADF Login component to the App

Every ADF component has extensive documentation available together with the source code in a .md markdown file. For example, if you navigate to the Login component docs you would see something like this:

 

 

The page covers everything from documentation, installation, basic usage, to advanced concepts. The basic markup that will put the login component onto the page looks like this:

 

<adf-login 
    [providers]="'ALL'"
    (success)="mySuccessMethod($event)"
    (error)="myErrorMethod($event)">

</adf-login>

 

The providers property controls what backing services to connect to. By default it will connect only to the Content Services (i.e. providers value set to 'ECM'). By specifying ALL we make sure to login to both Content Services and Process Services.

If you are using only one of the backend services, such as APS, then make sure to specify only that service in the providers field (e.g. ‘ECM’ if logging in only to ACS and 'BPM' if logging in only to APS). 

The two event callback methods will be invoked when a successful login has completed (success) or if an error occurs (error).

 

Making the Login component available to the App

The application that we generated comes with only one component, the main application component, represented by the TypeScript class AppComponent defined in the src/app/app.component.ts file. The view template is available in the src/app/app.component.html file.

 

To use the login component from the app component we need to first import it from the @alfresco/adf-core package. The Alfresco Login Component is defined in the TypeScript class LoginComponent. The import is done implicitly via a module called LoginModule, which should be added to the AppModule in the src/app/app.module.ts file as follows:

 

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';

import { CoreModule, LoginModule } from '@alfresco/adf-core';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    CoreModule,
    LoginModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

If you look in the LoginModule file you can see that it exports the LoginComponent and some directives at the root level. Any component that exist, or we create, can now use the login component.

 

Adding the Alfresco Login component to the App component template

To quickly test the Login component we will add it to the existing root app component. Open up the src/app/app.component.html template file, you should see some markup like this:

 

<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
  <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
  <li>
    <h2><a target="_blank" rel="noopener" href="https://a