├── .editorconfig
├── .gitignore
├── .prettierrc
├── .releaserc
├── .travis.yml
├── .vscode
└── launch.json
├── README.md
├── angular.json
├── config
├── cmd.ts
├── dashboard.ts
├── default.ts
└── proxy.conf.js
├── gulpfile.ts
├── package-lock.json
├── package.json
├── projects
├── demo
│ ├── browserslist
│ ├── src
│ │ ├── app
│ │ │ ├── app.component.html
│ │ │ ├── app.component.scss
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ └── example-mocks
│ │ │ │ ├── http.mock.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── system.mock.ts
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ ├── oauth-resp.html
│ │ ├── polyfills.ts
│ │ ├── shared.styles.scss
│ │ └── styles.css
│ └── tsconfig.app.json
└── library
│ ├── karma.conf.js
│ ├── ng-package.json
│ ├── package.json
│ ├── src
│ ├── lib
│ │ ├── directives
│ │ │ ├── binding.directive.spec.ts
│ │ │ └── binding.directive.ts
│ │ ├── library.module.ts
│ │ ├── services
│ │ │ ├── binding.service.spec.ts
│ │ │ ├── binding.service.ts
│ │ │ ├── composer.service.spec.ts
│ │ │ ├── composer.service.ts
│ │ │ ├── http.service.spec.ts
│ │ │ └── http.service.ts
│ │ └── settings.ts
│ ├── oauth-resp.html
│ ├── public-api.ts
│ └── test.ts
│ ├── tsconfig.lib.json
│ ├── tsconfig.spec.json
│ └── tslint.json
├── tsconfig.json
└── tslint.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 4
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | # Only exists if Bazel was run
8 | /bazel-out
9 |
10 | # dependencies
11 | /node_modules
12 |
13 | # profiling files
14 | chrome-profiler-events.json
15 | speed-measure-plugin.json
16 |
17 | # IDEs and editors
18 | /.idea
19 | .project
20 | .classpath
21 | .c9/
22 | *.launch
23 | .settings/
24 | *.sublime-workspace
25 |
26 | # IDE - VSCode
27 | .vscode/*
28 | !.vscode/settings.json
29 | !.vscode/tasks.json
30 | !.vscode/launch.json
31 | !.vscode/extensions.json
32 | .history/*
33 |
34 | # misc
35 | /.sass-cache
36 | /connect.lock
37 | /coverage
38 | /libpeerconnection.log
39 | npm-debug.log
40 | yarn-error.log
41 | testem.log
42 | /typings
43 | *.tgz
44 |
45 | # System Files
46 | .DS_Store
47 | Thumbs.db
48 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "tabWidth": 4,
4 | "printWidth": 100
5 | }
--------------------------------------------------------------------------------
/.releaserc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "@semantic-release/commit-analyzer",
4 | "@semantic-release/release-notes-generator",
5 | ["@semantic-release/npm", {
6 | "pkgRoot": "dist/library"
7 | }],
8 | ["@semantic-release/git", {
9 | "assets": ["package.json", "npm-shrinkwrap.json"]
10 | }]
11 | ]
12 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | addons:
3 | chrome: stable
4 | cache:
5 | directories:
6 | - ~/.npm
7 | notifications:
8 | email: false
9 | node_js:
10 | - '12'
11 | script:
12 | - npm run test:ci && gulp build
13 | after_success:
14 | - if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then npm run semantic-release; fi
15 | branches:
16 | except:
17 | - /^v\d+\.\d+\.\d+$/
18 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "chrome",
9 | "request": "launch",
10 | "name": "Launch Chrome against localhost",
11 | "url": "http://localhost:4200",
12 | "webRoot": "${workspaceFolder}"
13 | }
14 | ]
15 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular 8+ Composer Library
2 |
3 | [](https://travis-ci.org/acaengine/composer)
4 | [](https://badge.fury.io/js/%40acaengine%2Fcomposer)
5 | [](https://david-dm.org/acaengine/composer)
6 | [](https://github.com/semantic-release/semantic-release)
7 |
8 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.0.
9 |
10 | ## Development server
11 |
12 | Run `gulp serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
13 |
14 | ## Build
15 |
16 | Run `gulp build` to build the library. The build artifacts will be stored in the `dist/library` directory. Use the `--prod` flag for a production build.
17 |
18 | ## Running unit tests
19 |
20 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
21 |
22 | ## Installation
23 |
24 | You install the library from npm using `npm install @acaengine/composer`;
25 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "library": {
7 | "projectType": "library",
8 | "root": "projects/library",
9 | "sourceRoot": "projects/library/src",
10 | "prefix": "lib",
11 | "architect": {
12 | "build": {
13 | "builder": "@angular-devkit/build-ng-packagr:build",
14 | "options": {
15 | "tsConfig": "projects/library/tsconfig.lib.json",
16 | "project": "projects/library/ng-package.json"
17 | },
18 | "assets": [
19 | "projects/library/src/oauth-resp.html"
20 | ]
21 | },
22 | "test": {
23 | "builder": "@angular-devkit/build-angular:karma",
24 | "options": {
25 | "main": "projects/library/src/test.ts",
26 | "tsConfig": "projects/library/tsconfig.spec.json",
27 | "karmaConfig": "projects/library/karma.conf.js"
28 | }
29 | },
30 | "lint": {
31 | "builder": "@angular-devkit/build-angular:tslint",
32 | "options": {
33 | "tsConfig": [
34 | "projects/library/tsconfig.lib.json",
35 | "projects/library/tsconfig.spec.json"
36 | ],
37 | "exclude": [
38 | "**/node_modules/**"
39 | ]
40 | }
41 | }
42 | }
43 | },
44 | "demo": {
45 | "projectType": "application",
46 | "schematics": {
47 | "@schematics/angular:class": {
48 | "skipTests": true
49 | },
50 | "@schematics/angular:component": {
51 | "skipTests": true
52 | },
53 | "@schematics/angular:directive": {
54 | "skipTests": true
55 | },
56 | "@schematics/angular:guard": {
57 | "skipTests": true
58 | },
59 | "@schematics/angular:module": {
60 | "skipTests": true
61 | },
62 | "@schematics/angular:pipe": {
63 | "skipTests": true
64 | },
65 | "@schematics/angular:service": {
66 | "skipTests": true
67 | }
68 | },
69 | "root": "projects/demo",
70 | "sourceRoot": "projects/demo/src",
71 | "prefix": "app",
72 | "architect": {
73 | "build": {
74 | "builder": "@angular-devkit/build-angular:browser",
75 | "options": {
76 | "outputPath": "dist/demo",
77 | "index": "projects/demo/src/index.html",
78 | "main": "projects/demo/src/main.ts",
79 | "polyfills": "projects/demo/src/polyfills.ts",
80 | "tsConfig": "projects/demo/tsconfig.app.json",
81 | "assets": [
82 | "projects/demo/src/favicon.ico",
83 | "projects/demo/src/assets",
84 | "projects/demo/src/oauth-resp.html"
85 | ],
86 | "stylePreprocessorOptions": {
87 | "includePaths": [
88 | "projects/demo/src",
89 | "node_modules"
90 | ]
91 | },
92 | "styles": [
93 | "projects/demo/src/styles.css"
94 | ],
95 | "scripts": []
96 | },
97 | "configurations": {
98 | "production": {
99 | "fileReplacements": [
100 | {
101 | "replace": "projects/demo/src/environments/environment.ts",
102 | "with": "projects/demo/src/environments/environment.prod.ts"
103 | }
104 | ],
105 | "optimization": true,
106 | "outputHashing": "all",
107 | "sourceMap": false,
108 | "extractCss": true,
109 | "namedChunks": false,
110 | "aot": true,
111 | "extractLicenses": true,
112 | "vendorChunk": false,
113 | "buildOptimizer": true,
114 | "budgets": [
115 | {
116 | "type": "initial",
117 | "maximumWarning": "2mb",
118 | "maximumError": "5mb"
119 | }
120 | ]
121 | }
122 | }
123 | },
124 | "serve": {
125 | "builder": "@angular-devkit/build-angular:dev-server",
126 | "options": {
127 | "browserTarget": "demo:build",
128 | "port": 4200,
129 | "host": "0.0.0.0",
130 | "proxyConfig": "config/proxy.conf.js"
131 | },
132 | "configurations": {
133 | "production": {
134 | "browserTarget": "demo:build:production"
135 | }
136 | }
137 | },
138 | "extract-i18n": {
139 | "builder": "@angular-devkit/build-angular:extract-i18n",
140 | "options": {
141 | "browserTarget": "demo:build"
142 | }
143 | },
144 | "lint": {
145 | "builder": "@angular-devkit/build-angular:tslint",
146 | "options": {
147 | "tsConfig": [
148 | "projects/demo/tsconfig.app.json",
149 | "projects/demo/tsconfig.spec.json"
150 | ],
151 | "exclude": [
152 | "**/node_modules/**"
153 | ]
154 | }
155 | }
156 | }
157 | }},
158 | "defaultProject": "library"
159 | }
--------------------------------------------------------------------------------
/config/cmd.ts:
--------------------------------------------------------------------------------
1 | const { spawn } = require('child_process');
2 | const { platform } = require('process');
3 |
4 | const proc = (cmd, args) =>
5 | new Promise((resolve, reject) => {
6 | const p = createSpawn(cmd, args);
7 | p.on('exit', (code, signal) => code === 0 ? resolve() : reject(signal));
8 | });
9 |
10 | const npmScript = (name) => (...args) =>
11 | proc('npm', ['run', name, '--', ...args]);
12 |
13 | const npmAction = (name) => (...args) =>
14 | proc('npm', [name, ...args]);
15 |
16 | function createSpawn(cmd, args) {
17 | return platform === 'win32' ? spawn(cmd, args, { shell: true, stdio: 'inherit' }) : spawn(cmd, args, { stdio: 'inherit' });
18 | }
19 |
20 | module.exports = {
21 | ng: npmScript('ng'),
22 | version: npmAction('version')
23 | };
24 |
--------------------------------------------------------------------------------
/config/dashboard.ts:
--------------------------------------------------------------------------------
1 |
2 | const util = require('gulp-util');
3 |
4 | const colorMap = {
5 | 'development': 'yellow',
6 | 'production': 'green',
7 | 'dev': 'yellow',
8 | 'prod': 'green'
9 | };
10 |
11 | const dash = {
12 | show: (env: string) => {
13 | const color = colorMap[env] || 'magenta';
14 | console.log(`
15 | _____ _____ _____
16 | /\\ \\ /\\ \\ /\\ \\
17 | /::\\ \\ /::\\ \\ /::\\ \\
18 | /::::\\ \\ /::::\\ \\ /::::\\ \\
19 | /::::::\\ \\ /::::::\\ \\ /::::::\\ \\
20 | /::::::::\\ \\ /:::/\\:::\\ \\ /::::::::\\ \\
21 | /::::::::::\\ \\ /:::/ \\:::\\ \\ /::::::::::\\ \\
22 | /::::::::::::\\ \\ /:::/ \\:::\\ \\ /::::::::::::\\ \\
23 | /::::::::::::::\\ \\ /:::/ / \\:::\\ \\ /::::::::::::::\\ \\
24 | /:::/\\:::::::::::\\ \\ /:::/ / \\:::\\ \\ /:::/\\:::::::::::\\ \\
25 | /:::/ \\:::::::::::\\____\\/:::/____/ \\:::\\____\\/:::/ \\:::::::::::\\____\\
26 | \\::/ \\::::::::::/ /\\:::\\ \\ \\::/ /\\::/ \\::::::::::/ /
27 | \\/____/ \\::::::::/ / \\:::\\ \\ \\/____/ \\/____/ \\::::::::/ /
28 | \\::::::/ / \\:::\\ \\ \\::::::/ /
29 | \\::::/ / \\:::\\ \\ \\::::/ /
30 | /:::/ / \\:::\\ \\ /:::/ /
31 | /:::/ / \\:::\\ \\ /:::/ /
32 | /:::/ / \\:::\\ \\ /:::/ /
33 | /:::/ / \\:::\\____\\ /:::/ /
34 | \\::/ / \\::/ / \\::/ /
35 | \\/____/ \\/____/ \\/____/
36 |
37 | ============ ACA Angular Application ============
38 | Current environment: ${util.colors[color](env)}
39 | =================================================
40 | `);
41 | }
42 | };
43 |
44 | module.exports = {
45 | Dashboard: dash
46 | };
47 |
--------------------------------------------------------------------------------
/config/default.ts:
--------------------------------------------------------------------------------
1 |
2 | const del = require('del');
3 | const gulp = require('gulp');
4 | const yargs = require('yargs');
5 | const replace = require('gulp-string-replace');
6 | const dayjs = require('dayjs');
7 |
8 | const { ng, version } = require('./cmd');
9 | const { Dashboard } = require('./dashboard');
10 |
11 | /** Node project configuration */
12 | const npmconfig = require('../package.json');
13 | /** Command line arguments */
14 | const argv = yargs.argv;
15 | /** Angular CLI arguments */
16 | const ngargs: string[] = [];
17 |
18 | const library_path = './projects/library';
19 |
20 | if (argv.prod || (argv.demo === true && argv.prod !== 'false')) { ngargs.push('--prod'); }
21 | if (argv.aot || (argv.demo === true && argv.aot !== 'false')) { ngargs.push('--aot'); }
22 | if (argv.port && !isNaN(parseInt(argv.port, 10))) { ngargs.push(`--port=${parseInt(argv.port, 10)}`); }
23 | if (argv.ssl) { ngargs.push('--ssl'); }
24 |
25 | Dashboard.show(argv.prod ? 'prod' : 'dev');
26 |
27 | /** Nuke old build assets */
28 | gulp.task('clean', () => ((...globs: string[]) => del(globs))('dist/', 'compiled/', '_package'));
29 |
30 | /** Build the library */
31 | gulp.task('ng:build', () => ng('build', 'library', ...ngargs));
32 |
33 | /** Serve the demo with the library */
34 | gulp.task('ng:serve', () => ng('serve', 'demo', ...ngargs));
35 |
36 | /** Update version details to the current time and version */
37 | gulp.task('version:update', () => {
38 | const v = npmconfig.version;
39 | const b = dayjs().startOf('s').valueOf();
40 | return gulp.src([`${library_path}/src/lib/library.module.ts`]) // Any file globs are supported
41 | .pipe(replace(/public static version = '[0-9a-zA-Z.-]*'/g, `public static version = '${v}'`, { logs: { enabled: true } }))
42 | .pipe(replace(/readonly build = dayjs\([0-9]*\);/g, `readonly build = dayjs(${b});`, { logs: { enabled: true } }))
43 | .pipe(gulp.dest(`${library_path}/src/lib`));
44 | });
45 |
46 | /** Return version details back to the dev details */
47 | gulp.task('version:clean', () => {
48 | const v = npmconfig.version;
49 | const b = dayjs().startOf('s').valueOf();
50 | return gulp.src([`${library_path}/src/lib/library.module.ts`]) // Any file globs are supported
51 | .pipe(replace(/public static version = '[0-9a-zA-Z.-]*'/g, `public static version = 'local-dev'`, { logs: { enabled: true } }))
52 | .pipe(replace(/readonly build = dayjs\([0-9]*\);/g, `readonly build = dayjs();`, { logs: { enabled: true } }))
53 | .pipe(gulp.dest(`${library_path}/src/lib`));
54 | });
55 |
56 | /** Copy root project version into */
57 | gulp.task('version:copy', () => {
58 | const v = require('../package.json').version;
59 | return gulp.src([`${library_path}/package.json`]) // Any file globs are supported
60 | .pipe(replace(/"version": "[0-9a-zA-Z.-]*"/g, `"version": "${v}"`, { logs: { enabled: true } }))
61 | .pipe(gulp.dest(library_path));
62 | });
63 |
64 | /** Run pre build tasks */
65 | gulp.task('pre-build', gulp.series('version:copy', 'version:update'));
66 |
67 | /** Run post build tasks */
68 | gulp.task('post-build', gulp.series('version:clean'));
69 |
70 | /** Run build tasks */
71 | gulp.task('build', gulp.series('pre-build', 'ng:build', 'post-build'));
72 |
73 | /** Run serve tasks */
74 | gulp.task('serve', gulp.series('ng:serve'));
--------------------------------------------------------------------------------
/config/proxy.conf.js:
--------------------------------------------------------------------------------
1 |
2 | const domain = 'localhost:8080';
3 | const secure = false;
4 | const valid_ssl = false;
5 |
6 | const PROXY_CONFIG = [
7 | {
8 | context: [
9 | "/api",
10 | "/control",
11 | "/build",
12 | "/auth",
13 | "/styles",
14 | "/scripts",
15 | "/login",
16 | "/backoffice"
17 | ],
18 | target: `http${secure ? 's' : ''}://${domain}`,
19 | secure: valid_ssl,
20 | changeOrigin: true
21 | },
22 | {
23 | context: [
24 | "/control/websocket"
25 | ],
26 | target: `ws${secure ? 's' : ''}://${domain}`,
27 | secure: valid_ssl,
28 | changeOrigin: true,
29 | ws: true
30 | }
31 | ];
32 |
33 | module.exports = PROXY_CONFIG;
34 |
--------------------------------------------------------------------------------
/gulpfile.ts:
--------------------------------------------------------------------------------
1 |
2 | require('./config/default');
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-composer-project",
3 | "version": "0.0.0-development",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "test": "ng test",
9 | "lint": "ng lint",
10 | "e2e": "ng e2e",
11 | "postversion": "gulp build",
12 | "publish": "gulp build && npm publish dist/library",
13 | "semantic-release": "semantic-release",
14 | "test:ci": "ng test library --watch=false --browsers=ChromeHeadless",
15 | "postpublish": "cp -r ./dist/library/package.json ./projects/library/"
16 | },
17 | "private": true,
18 | "dependencies": {
19 | "@acaengine/ts-client": "^3.1.0",
20 | "@angular/common": "^8.0.3",
21 | "@angular/compiler": "^8.0.3",
22 | "@angular/core": "^8.0.3",
23 | "@angular/forms": "^8.0.3",
24 | "@angular/platform-browser": "^8.0.3",
25 | "@angular/platform-browser-dynamic": "^8.0.3",
26 | "@angular/router": "^8.0.3",
27 | "rxjs": "~6.4.0",
28 | "tslib": "^1.10.0",
29 | "zone.js": "~0.9.1"
30 | },
31 | "devDependencies": {
32 | "@angular-devkit/build-angular": "^0.800.6",
33 | "@angular-devkit/build-ng-packagr": "^0.800.6",
34 | "@angular/cli": "^8.0.6",
35 | "@angular/compiler-cli": "^8.0.3",
36 | "@angular/language-service": "^8.0.3",
37 | "@semantic-release/git": "^8.0.0",
38 | "@semantic-release/npm": "^5.3.4",
39 | "@types/jasmine": "^3.3.16",
40 | "@types/jasminewd2": "^2.0.8",
41 | "@types/node": "~8.9.4",
42 | "codelyzer": "^5.2.0",
43 | "dayjs": "^1.8.17",
44 | "gulp": "^4.0.2",
45 | "gulp-string-replace": "^1.1.2",
46 | "gulp-util": "^3.0.8",
47 | "jasmine-core": "~3.4.0",
48 | "jasmine-spec-reporter": "~4.2.1",
49 | "karma": "~4.1.0",
50 | "karma-chrome-launcher": "~2.2.0",
51 | "karma-coverage-istanbul-reporter": "^2.0.6",
52 | "karma-jasmine": "~2.0.1",
53 | "karma-jasmine-html-reporter": "^1.4.0",
54 | "ng-packagr": "^5.7.1",
55 | "protractor": "~5.4.0",
56 | "semantic-release": "^16.0.3",
57 | "ts-md5": "^1.2.7",
58 | "ts-node": "^7.0.1",
59 | "tsickle": "^0.35.0",
60 | "tslint": "~5.15.0",
61 | "typescript": "~3.4.3",
62 | "yargs": "^13.3.0"
63 | },
64 | "repository": {
65 | "type": "git",
66 | "url": "https://github.com/acaengine/composer.git"
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/projects/demo/browserslist:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # You can see what browsers were selected by your queries by running:
6 | # npx browserslist
7 |
8 | > 0.5%
9 | last 2 versions
10 | Firefox ESR
11 | not dead
12 | not IE 9-11 # For IE 9-11 support, remove 'not'.
--------------------------------------------------------------------------------
/projects/demo/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ model.value | json }}
5 | {{ model.active }}
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 |
2 | @import 'shared.styles';
3 |
4 | html, body, .app {
5 | height: 100%;
6 | width: 100%;
7 | margin: 0;
8 | padding: 0;
9 | }
10 |
11 | .app {
12 | overflow: auto;
13 | }
14 |
15 | body {
16 | min-height: 100%;
17 | overflow: hidden;
18 | background-color: #eee;
19 | font-size: $desktop-font-size;
20 | @include respond-to(mobile) {
21 | font-size: $tablet-font-size;
22 | }
23 | @include respond-to(mobile) {
24 | font-size: $mobile-font-size;
25 | }
26 | }
27 |
28 | * {
29 | font-family: $main-font;
30 | }
31 |
32 | @include respond-to(not-mobile) {
33 | .mobile-only,
34 | .mobile {
35 | display: none !important;
36 | }
37 | }
38 |
39 | @include respond-to(not-tablet) {
40 | .tablet-only,
41 | .tablet {
42 | display: none !important;
43 | }
44 | }
45 |
46 | @include respond-to(not-desktop) {
47 | .desktop-only,
48 | .desktop {
49 | display: none !important;
50 | }
51 | }
52 |
53 | @include respond-to(desktop) {
54 | .not-desktop {
55 | display: none !important;
56 | }
57 | }
58 |
59 | @include respond-to(tablet) {
60 | .not-tablet,
61 | .desktop-only {
62 | display: none !important;
63 | }
64 | }
65 |
66 | @include respond-to(mobile) {
67 | .not-mobile,
68 | .desktop-only {
69 | display: none !important;
70 | }
71 | }
72 |
73 | .overlay-backdrop {
74 | background-color: rgba(#000, .54);
75 | }
76 |
77 | .test {
78 | display: flex;
79 | align-items: center;
80 | justify-content: center;
81 | flex-direction: column;
82 | margin: 1em auto;
83 | width: 24em;
84 | min-height: 10em;
85 | padding: 1em;
86 | background-color: #fff;
87 | border-radius: 4px;
88 | box-shadow: 0 1px 3px 0 rgba(#000, .2), 0 1px 1px 0 rgba(#000, .14), 0 2px 1px -1px rgba(#000, .12);
89 |
90 | }
91 |
92 | button {
93 | font-size: 1em;
94 | padding: .5em 1em;
95 | border-radius: 4px;
96 | min-width: 12em;
97 | background-color: #1E88E5;
98 | color: #fff;
99 | margin: .25em;
100 | }
101 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewEncapsulation, OnInit } from '@angular/core';
2 |
3 | import { ComposerService } from 'projects/library/src/lib/services/composer.service';
4 | import { ACAEngineOptions, EngineZone, EngineSettings } from '@acaengine/ts-client';
5 |
6 | import { Md5 } from 'ts-md5';
7 |
8 | declare global {
9 | interface Window {
10 | composer: ComposerService;
11 | EngineZone: any;
12 | EngineSettings: any;
13 | debug: boolean;
14 | }
15 | }
16 |
17 | @Component({
18 | selector: 'app-root',
19 | templateUrl: `./app.component.html`,
20 | styleUrls: ['./app.component.scss'],
21 | encapsulation: ViewEncapsulation.None
22 | })
23 | export class AppComponent implements OnInit {
24 | public model: { [name: string]: any } = {};
25 |
26 | constructor(private _composer: ComposerService) { }
27 |
28 | public ngOnInit(): void {
29 | window.composer = this._composer;
30 | window.EngineZone = EngineZone;
31 | window.EngineSettings = EngineSettings;
32 | window.debug = true;
33 | this.initialiseComposer();
34 | }
35 |
36 | public initialiseComposer(tries: number = 0) {
37 | // Get domain information for configuring composer
38 | const host = location.hostname;
39 | const protocol = location.protocol;
40 | const port = location.port;
41 | const url = location.origin;
42 | // Generate configuration for composer
43 | const config: ACAEngineOptions = {
44 | scope: 'public',
45 | host: `${host}:${port}`,
46 | auth_uri: `${url}/auth/oauth/authorize`,
47 | token_uri: `${url}/auth/token`,
48 | redirect_uri: `${location.origin}/oauth-resp.html`,
49 | handle_login: true,
50 | mock: false
51 | };
52 | localStorage.setItem(`${Md5.hashStr(config.redirect_uri)}_access_token`, 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJBQ0FFIiwiaWF0IjoxNTc4MDEyMDYzLCJleHAiOjE1NzkyMjE2NjMsImF1ZCI6ImxvY2FsaG9zdCIsInN1YiI6Ijg1VmJPbjE2ZWJBRnYwIiwidSI6eyJuIjoiQUNBIFN1cHBvcnQgKGxvY2FsaG9zdDo4MDgwKSIsImUiOiJzdXBwb3J0QGFjYS5pbSIsInAiOjJ9fQ.a_MdB4pUCRiwjWgoaW_7jt0aRk61piD1TuZ0HqwabrCed1BsM5vM4VD39UOhs9uKPj4eHAIM7lPbSBhjdNDtAhy_xBsoosoap5Qv9kC-ZjaEN3zcRjstgsYwFwtlLFCDBxOd5gAJVwtgXLcB8bzbzYtvl2i_UAtm5fDSL_WpUHKeGyGJEvPowDgzlBn0FqYrq6BdTOg6YotqiKMO2EhDiXDFYjIrZl4hU36gLZu_Gp5nSBCukrT0MX-nR9V4ySbBD_5pinV9PikIArNTBZLuSbhjo5ohzcljlJREuFrc38L0uoTmbitLk-qIEPYie4yrjjwkEmV-FWLVz4i_NTFM1Q');
53 | // Setup/Initialise composer
54 | this._composer.setup(config);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/projects/demo/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 |
2 | import { NgModule } from '@angular/core';
3 | import { BrowserModule } from '@angular/platform-browser';
4 | import { RouterModule } from '@angular/router';
5 |
6 | import { AppComponent } from './app.component';
7 | import { ComposerModule } from 'projects/library/src/public-api';
8 | import { FormsModule } from '@angular/forms';
9 |
10 | import './example-mocks';
11 |
12 | @NgModule({
13 | declarations: [
14 | AppComponent
15 | ],
16 | imports: [
17 | BrowserModule,
18 | ComposerModule,
19 | FormsModule,
20 | RouterModule.forRoot([])
21 | ],
22 | providers: [],
23 | bootstrap: [AppComponent]
24 | })
25 | export class AppModule { }
26 |
--------------------------------------------------------------------------------
/projects/demo/src/app/example-mocks/http.mock.ts:
--------------------------------------------------------------------------------
1 |
2 | import { MockHttpRequestHandlerOptions, generateMockSystem } from '@acaengine/ts-client';
3 |
4 | const MOCK_SYSTEMS = Array(Math.floor(Math.random() * 100 + 5)).fill(0).map(i => generateMockSystem());
5 |
6 | const handlers: MockHttpRequestHandlerOptions[] = [
7 | {
8 | path: '/api/engine/v1/systems',
9 | metadata: {},
10 | method: 'GET',
11 | callback: (request) => MOCK_SYSTEMS
12 | },
13 | {
14 | path: '/api/engine/v1/systems/:id',
15 | metadata: {},
16 | method: 'GET',
17 | callback: (request) => {
18 | console.log('Event:', request);
19 | return MOCK_SYSTEMS.find(i => request.route_params.id === i.id);
20 | }
21 | }
22 | ]
23 |
24 | window.control.handlers = handlers;
25 |
--------------------------------------------------------------------------------
/projects/demo/src/app/example-mocks/index.ts:
--------------------------------------------------------------------------------
1 |
2 | import './http.mock';
3 | import './system.mock';
4 |
--------------------------------------------------------------------------------
/projects/demo/src/app/example-mocks/system.mock.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | const system_list = {
4 | 'sys-rhAUvsBsBo': {
5 | Bookings: [{
6 | today: ['Yes'],
7 | $power: function () {
8 | this._system.Bookings[0].today = [...this._system.Bookings[0].today, 'No'];
9 | }
10 | }]
11 | }
12 | };
13 |
14 | window.control.systems = system_list;
15 |
--------------------------------------------------------------------------------
/projects/demo/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mr-dev-dragon/composer/3685019b3e890830977d09027205ebccc36fa9d9/projects/demo/src/assets/.gitkeep
--------------------------------------------------------------------------------
/projects/demo/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/projects/demo/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/projects/demo/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mr-dev-dragon/composer/3685019b3e890830977d09027205ebccc36fa9d9/projects/demo/src/favicon.ico
--------------------------------------------------------------------------------
/projects/demo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/projects/demo/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule)
12 | .catch(err => console.error(err));
13 |
--------------------------------------------------------------------------------
/projects/demo/src/oauth-resp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Authentication Success
7 |
8 |
9 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/projects/demo/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import './zone-flags.ts';
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | import 'zone.js/dist/zone'; // Included with Angular CLI.
59 |
60 |
61 | /***************************************************************************************************
62 | * APPLICATION IMPORTS
63 | */
64 |
--------------------------------------------------------------------------------
/projects/demo/src/shared.styles.scss:
--------------------------------------------------------------------------------
1 | /*==============================*\
2 | || Shared Global SASS Variables ||
3 | \*==============================*/
4 |
5 | /*=================================*\
6 | || Color Variables ||
7 | \*=================================*/
8 |
9 | $color1: #0288D1;
10 | $color2: #FF9800;
11 | $color2-dark: #FB8C00;
12 |
13 | $color-disabled: rgba(#000, .2);
14 |
15 | $success: #4CAF50;
16 | $error: #F44336;
17 | $error-neutral: #6d6e71;
18 | $error-active: #D32F2F;
19 | $pending: #FF9800;
20 | $neutral: #6d6e71;
21 |
22 | /*=================================*\
23 | || Font Variables ||
24 | \*=================================*/
25 |
26 | $desktop-font-size: 20px;
27 | $tablet-font-size: 20px;
28 | $mobile-font-size: 16px;
29 |
30 | $charter: 'CharterITC BT', Georgia, 'Times New Roman', Times, serif;
31 | $font-stack: "Segoe UI", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif;
32 |
33 | $heading-font: $charter;
34 | $main-font: $font-stack;
35 |
36 | /*===================*\
37 | || Media Queries ||
38 | \*===================*/
39 |
40 | $break-mobile: 450px;
41 | $break-tablet: 800px;
42 |
43 | $break-landscape-mobile: 800px;
44 | $break-landscape-tablet: 1048px;
45 |
46 | @mixin respond-to($media) {
47 | @if $media == mobile {
48 | @media only screen and (orientation: portrait) and (max-width: $break-mobile) {
49 | @content;
50 | }
51 | @media only screen and (orientation: landscape) and (max-width: $break-landscape-mobile) {
52 | @content;
53 | }
54 | } @else if $media == not-mobile {
55 | @media only screen and (orientation: portrait) and (min-width: $break-mobile + 1) {
56 | @content;
57 | }
58 | @media only screen and (orientation: landscape) and (min-width: $break-landscape-mobile + 1) {
59 | @content;
60 | }
61 | } @else if $media == tablet {
62 | @media only screen and (orientation: portrait) and (min-width: $break-mobile + 1) and (max-width: $break-tablet) {
63 | @content;
64 | }
65 | @media only screen and (orientation: landscape) and (min-width: $break-landscape-mobile + 1) and (max-width: $break-landscape-tablet) {
66 | @content;
67 | }
68 | } @else if $media == tablet-mobile {
69 | @media only screen and (orientation: portrait) and (max-width: $break-tablet) {
70 | @content;
71 | }
72 | @media only screen and (orientation: landscape) and (max-width: $break-landscape-tablet) {
73 | @content;
74 | }
75 | } @else if $media == desktop {
76 | @media only screen and (orientation: portrait) and (min-width: $break-tablet) {
77 | @content;
78 | }
79 | @media only screen and (orientation: landscape) and (min-width: $break-landscape-tablet) {
80 | @content;
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/projects/demo/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/projects/demo/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/app",
5 | "types": []
6 | },
7 | "include": [
8 | "src/**/*.ts"
9 | ],
10 | "exclude": [
11 | "src/test.ts",
12 | "src/**/*.spec.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/projects/library/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, '../../coverage/library'),
20 | reports: ['html', 'lcovonly'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | customLaunchers: {
30 | ChromeHeadlessNoSandbox: {
31 | base: 'ChromeHeadless',
32 | flags: ['--no-sandbox']
33 | }
34 | },
35 | singleRun: false,
36 | restartOnFileChange: true
37 | });
38 | };
39 |
--------------------------------------------------------------------------------
/projects/library/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/library",
4 | "lib": {
5 | "entryFile": "src/public-api.ts"
6 | },
7 | "whitelistedNonPeerDependencies": [
8 | "@acaengine/ts-client"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/projects/library/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@acaengine/composer",
3 | "version": "0.0.0-development",
4 | "publishConfig": {
5 | "access": "public"
6 | },
7 | "keywords": [
8 | "angular",
9 | "composer"
10 | ],
11 | "description": "Engine Composer API for Angular 8+",
12 | "homepage": "https://github.com/acaengine/composer#readme",
13 | "bugs": {
14 | "url": "https://github.com/acaengine/composer/issues"
15 | },
16 | "dependencies": {
17 | "@acaengine/ts-client": "^3.1.0"
18 | },
19 | "peerDependencies": {
20 | "@angular/common": "^8.0.0",
21 | "@angular/core": "^8.0.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/projects/library/src/lib/directives/binding.directive.spec.ts:
--------------------------------------------------------------------------------
1 | import { BindingDirective } from './binding.directive';
2 |
3 | describe('BindingDirective', () => {
4 | let directive: BindingDirective;
5 | let service: any;
6 | let element: any;
7 | let renderer: any;
8 |
9 | beforeEach(() => {
10 | service = jasmine.createSpyObj('ComposerService', ['bind', 'exec']);
11 | element = jasmine.createSpyObj('ElementRef', ['exec']);
12 | renderer = jasmine.createSpyObj('Renderer2', ['listen']);
13 | directive = new BindingDirective(service, element, renderer);
14 | });
15 |
16 | it('should create an instance', () => {
17 | expect(directive).toBeTruthy();
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/projects/library/src/lib/directives/binding.directive.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Directive,
3 | Input,
4 | SimpleChanges,
5 | OnInit,
6 | OnChanges,
7 | OnDestroy,
8 | ElementRef,
9 | Renderer2,
10 | EventEmitter,
11 | Output
12 | } from '@angular/core';
13 | import { Subscription } from 'rxjs';
14 |
15 | import { BindingService } from '../services/binding.service';
16 |
17 | @Directive({
18 | selector: 'i[bind], [binding], co-bind'
19 | })
20 | export class BindingDirective implements OnInit, OnChanges, OnDestroy {
21 | /** ID of the system to bind */
22 | @Input() public sys: string;
23 | /** Class name of the module to bind */
24 | @Input() public mod: string;
25 | /** Index of the system to bind */
26 | @Input() public index = 1;
27 | /** Status variable to bind to */
28 | @Input() public bind: string;
29 | /** Method to execute */
30 | @Input() public exec: string;
31 | /** Event to listen for on the parent */
32 | @Input('onEvent') public on_event: string;
33 | /** ID of the system to bind to */
34 | @Input() public params: any[] = [];
35 | /** Current value of the binding */
36 | @Input() public model: T;
37 | /** Emitter for changes to the value of the binding */
38 | @Output() public modelChange = new EventEmitter();
39 |
40 | /** Listener for event on host element */
41 | private event_listener: () => void;
42 | /** Listener for changes to the binding value */
43 | private listener: Subscription;
44 | /** Listener for initialisation state of composer */
45 | private init_listener: Subscription;
46 | /** Callback to unbind to the status variable */
47 | private unbind: () => void;
48 |
49 | constructor(
50 | private _service: BindingService,
51 | private _element: ElementRef,
52 | private _renderer: Renderer2
53 | ) {}
54 |
55 | public ngOnInit(): void {
56 | this.init_listener = this._service.is_initialised.subscribe(init => {
57 | if (init) {
58 | this.bindVariable();
59 | if (this.init_listener) {
60 | this.init_listener.unsubscribe();
61 | this.init_listener = null;
62 | }
63 | }
64 | });
65 | }
66 |
67 | public ngOnDestroy(): void {
68 | if (this.listener) {
69 | this.listener.unsubscribe();
70 | this.listener = null;
71 | }
72 | if (this.unbind) {
73 | this.unbind();
74 | this.unbind = null;
75 | }
76 | if (this.event_listener) {
77 | this.event_listener();
78 | this.event_listener = null;
79 | }
80 | }
81 |
82 | public ngOnChanges(changes: SimpleChanges): void {
83 | if (changes.sys || changes.mod || changes.bind) {
84 | this.ngOnDestroy();
85 | this.bindVariable();
86 | }
87 | if (changes.on_event && this.on_event) {
88 | if (this.event_listener) {
89 | this.event_listener();
90 | this.event_listener = null;
91 | }
92 | this.event_listener = this._renderer.listen(
93 | this._element.nativeElement,
94 | this.on_event,
95 | () => this.execute()
96 | );
97 | }
98 | }
99 |
100 | /** Bind to set status variable */
101 | private bindVariable() {
102 | if (this._service.initialised && this.bind && this.sys && this.mod) {
103 | const module = this._service.module(this.sys, this.mod, this.index);
104 | const binding = module.binding(this.bind);
105 | this.unbind = binding.bind();
106 | this.listener = binding.listen(value => setTimeout(() => {
107 | this.model = value;
108 | this.modelChange.emit(this.model);
109 | }, 10));
110 | }
111 | }
112 |
113 | /** Excute the set method on the module */
114 | private execute() {
115 | if (this._service.initialised && this.exec && this.sys && this.mod) {
116 | const module = this._service.module(this.sys, this.mod, this.index);
117 | console.log('Params:', this.params);
118 | module.exec(this.exec, this.params).then(result => {
119 | // Emit exec result if not bound to status variable
120 | if (!this.bind) {
121 | this.model = result;
122 | this.modelChange.emit(this.model);
123 | }
124 | });
125 | }
126 | }
127 | /**
128 | * Update local value when form control value is changed
129 | * @param value The new value for the component
130 | */
131 | public writeValue(value: T) {
132 | this.model = value;
133 | this.modelChange.emit(this.model);
134 | if (this.exec) {
135 | this.execute();
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/projects/library/src/lib/library.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { version } from './settings';
5 |
6 | import { BindingDirective } from './directives/binding.directive';
7 |
8 | import * as dayjs_api from 'dayjs';
9 | const dayjs = dayjs_api;
10 |
11 | @NgModule({
12 | declarations: [
13 | BindingDirective
14 | ],
15 | imports: [
16 | CommonModule
17 | ],
18 | exports: [
19 | BindingDirective
20 | ]
21 | })
22 | export class LibraryModule {
23 | public static version = 'local-dev';
24 | private static init = false;
25 | readonly build = dayjs();
26 |
27 | constructor() {
28 | if (!LibraryModule.init) {
29 | const now = dayjs();
30 | LibraryModule.init = true;
31 | const build = now.isSame(this.build, 'd') ? `Today at ${this.build.format('h:mmA')}` : this.build.format('D MMM YYYY, h:mmA');
32 | version(LibraryModule.version, build);
33 | }
34 | }
35 | }
36 |
37 | export { LibraryModule as ACA_COMPOSER_MODULE };
38 | export { LibraryModule as ComposerModule };
39 |
--------------------------------------------------------------------------------
/projects/library/src/lib/services/binding.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 |
3 | import { BindingService } from './binding.service';
4 |
5 | describe('BindingService', () => {
6 | beforeEach(() => TestBed.configureTestingModule({}));
7 |
8 | it('should be created', () => {
9 | const service: BindingService = TestBed.get(BindingService);
10 | expect(service).toBeTruthy();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/projects/library/src/lib/services/binding.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { EngineBindingService } from '@acaengine/ts-client';
3 |
4 | import { ComposerService } from './composer.service';
5 | import { Observable } from 'rxjs';
6 |
7 | @Injectable({
8 | providedIn: 'root'
9 | })
10 | export class BindingService extends EngineBindingService {
11 | /** Whether composer is initialised */
12 | public _initialised: boolean = false;
13 |
14 | constructor(private composer: ComposerService) {
15 | super(undefined);
16 | this.composer.initialised.subscribe((init) => {
17 | this._initialised = init;
18 | if (init) {
19 | (this as any)._websocket = this.composer.realtime;
20 | }
21 | });
22 | }
23 |
24 | /** Whether composer is initialised */
25 | public get initialised(): boolean {
26 | return this._initialised;
27 | }
28 |
29 | /** Observable */
30 | public get is_initialised(): Observable {
31 | return this.composer.initialised;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/projects/library/src/lib/services/composer.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 |
3 | import { ComposerService } from './composer.service';
4 |
5 | describe('ComposerService', () => {
6 | beforeEach(() => TestBed.configureTestingModule({}));
7 |
8 | it('should be created', () => {
9 | const service: ComposerService = TestBed.get(ComposerService);
10 | expect(service).toBeTruthy();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/projects/library/src/lib/services/composer.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Observable } from 'rxjs';
3 | import {
4 | ACAEngine,
5 | EngineAuthService,
6 | EngineBindingService,
7 | EngineWebsocket,
8 | EngineApplicationsService,
9 | EngineDriversService,
10 | EngineModulesService,
11 | EngineSystemsService,
12 | EngineZonesService,
13 | EngineUsersService,
14 | EngineHttpClient,
15 | EngineDomainsService,
16 | ACAEngineOptions,
17 | EngineTriggersService,
18 | EngineSystemTriggersService,
19 | EngineSettingsService,
20 | EngineRepositoriesService,
21 | EngineOAuthSourcesService,
22 | EngineSAMLSourcesService,
23 | EngineLDAPSourcesService
24 | } from '@acaengine/ts-client';
25 |
26 | @Injectable({
27 | providedIn: 'root'
28 | })
29 | export class ComposerService {
30 | /** Initialise ACAEngine API */
31 | public setup(options: ACAEngineOptions) {
32 | ACAEngine.init(options);
33 | }
34 |
35 | /** Observable for the intialised state of composer */
36 | public get initialised(): Observable {
37 | return ACAEngine.initialised;
38 | }
39 |
40 | /** Observable for the intialised state of composer */
41 | public get is_initialised(): boolean {
42 | return ACAEngine.is_initialised;
43 | }
44 |
45 | /** HTTP Client for making request with composer credentials */
46 | public get http(): EngineHttpClient {
47 | return ACAEngine.http;
48 | }
49 |
50 | /** Authentication service for Composer */
51 | public get auth(): EngineAuthService {
52 | return ACAEngine.auth;
53 | }
54 |
55 | /** Service for binding to engine's realtime API */
56 | public get bindings(): EngineBindingService {
57 | return ACAEngine.bindings;
58 | }
59 | /** HTTP service for engine applications */
60 | public get applications(): EngineApplicationsService {
61 | return ACAEngine.applications;
62 | }
63 |
64 | /** HTTP service for engine auth sources */
65 | public get oauth_sources(): EngineOAuthSourcesService {
66 | return ACAEngine.oauth_sources;
67 | }
68 |
69 | /** HTTP service for engine auth sources */
70 | public get saml_sources(): EngineSAMLSourcesService {
71 | return ACAEngine.saml_sources;
72 | }
73 |
74 | /** HTTP service for engine auth sources */
75 | public get ldap_sources(): EngineLDAPSourcesService {
76 | return ACAEngine.ldap_sources;
77 | }
78 |
79 | /** HTTP service for engine domains */
80 | public get domains(): EngineDomainsService {
81 | return ACAEngine.domains;
82 | }
83 |
84 | /** Interface for engine realtime API communications */
85 | public get realtime(): EngineWebsocket {
86 | return ACAEngine.realtime;
87 | }
88 |
89 | /** HTTP service for engine drivers */
90 | public get drivers(): EngineDriversService {
91 | return ACAEngine.drivers;
92 | }
93 |
94 | /** HTTP service for engine modules */
95 | public get modules(): EngineModulesService {
96 | return ACAEngine.modules;
97 | }
98 |
99 | /** HTTP service for engine repositories */
100 | public get repositories(): EngineRepositoriesService {
101 | return ACAEngine.repositories;
102 | }
103 |
104 | /** HTTP service for engine systems */
105 | public get systems(): EngineSystemsService {
106 | return ACAEngine.systems;
107 | }
108 |
109 | /** HTTP service for engine triggers */
110 | public get triggers(): EngineTriggersService {
111 | return ACAEngine.triggers;
112 | }
113 |
114 | /** HTTP service for engine system triggers */
115 | public get system_triggers(): EngineSystemTriggersService {
116 | return ACAEngine.system_triggers;
117 | }
118 |
119 | /** HTTP service for engine auth sources */
120 | public get users(): EngineUsersService {
121 | return ACAEngine.users;
122 | }
123 |
124 | /** HTTP service for engine auth sources */
125 | public get settings(): EngineSettingsService {
126 | return ACAEngine.settings;
127 | }
128 |
129 | /** HTTP service for engine auth sources */
130 | public get zones(): EngineZonesService {
131 | return ACAEngine.zones;
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/projects/library/src/lib/services/http.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 |
3 | import { EngineHttpService } from './http.service';
4 |
5 | describe('HttpService', () => {
6 | beforeEach(() => TestBed.configureTestingModule({}));
7 |
8 | it('should be created', () => {
9 | const service: EngineHttpService = TestBed.get(EngineHttpService);
10 | expect(service).toBeTruthy();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/projects/library/src/lib/services/http.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { EngineHttpClient } from '@acaengine/ts-client';
3 |
4 | import { ComposerService } from './composer.service';
5 |
6 | /**
7 | * Wrapper service for the HTTP client in composer
8 | */
9 | @Injectable({
10 | providedIn: 'root'
11 | })
12 | export class EngineHttpService {
13 |
14 | private get http(): EngineHttpClient {
15 | return this._composer.http;
16 | }
17 |
18 | constructor(private _composer: ComposerService) { }
19 |
20 | /**
21 | * Perform AJAX HTTP GET request
22 | * @param url URL of the GET endpoint
23 | * @param options Options to add to the request
24 | */
25 | public get get() {
26 | return this.http.get;
27 | }
28 |
29 | /**
30 | * Perform AJAX HTTP POST request
31 | * @param url URL of the POST endpoint
32 | * @param body Body contents of the request
33 | * @param options Options to add to the request
34 | */
35 | public get post() {
36 | return this.http.post;
37 | }
38 |
39 | /**
40 | * Perform AJAX HTTP PUT request
41 | * @param url URL of the PUT endpoint
42 | * @param body Body contents of the request
43 | * @param options Options to add to the request
44 | */
45 | public get put() {
46 | return this.http.put;
47 | }
48 |
49 | /**
50 | * Perform AJAX HTTP PATCH request
51 | * @param url URL of the PATCH endpoint
52 | * @param body Body contents of the request
53 | * @param options Options to add to the request
54 | */
55 | public get patch() {
56 | return this.http.patch;
57 | }
58 |
59 | /**
60 | * Perform AJAX HTTP DELETE request
61 | * @param url URL of the DELETE endpoint
62 | * @param options Options to add to the request
63 | */
64 | public get delete() {
65 | return this.http.delete;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/projects/library/src/lib/settings.ts:
--------------------------------------------------------------------------------
1 | declare global {
2 | interface Window {
3 | debug: boolean;
4 | }
5 | }
6 |
7 | export const LIB_NAME = 'Composer';
8 |
9 | /**
10 | * Formatted console messages for the library
11 | * @param type Identifier for the message location
12 | * @param msg Message to send
13 | * @param args Javascript variables to pass to the console
14 | * @param out Output stream name for messages. Defaults to `'debug'`
15 | * @param color Secondary colour for type
16 | */
17 | export function log(type: string, msg: string, args?: any, out: string = 'debug', color?: string) {
18 | if (window.debug) {
19 | const clr = color ? color : '#009688';
20 | const COLOURS = ['color: #0288D1', `color:${clr}`, 'color: default'];
21 | if (args) {
22 | if (hasColours()) {
23 | console[out](`%c[${LIB_NAME}]%c[${type}] %c${msg}`, ...COLOURS, args);
24 | } else {
25 | console[out](`[${LIB_NAME}][${type}] ${msg}`, args);
26 | }
27 | } else {
28 | if (hasColours()) {
29 | console[out](`%c[${LIB_NAME}]%c[${type}] %c${msg}`, ...COLOURS);
30 | } else {
31 | console[out](`[${LIB_NAME}][${type}] ${msg}`);
32 | }
33 | }
34 | }
35 | }
36 |
37 | /**
38 | * Log formatted error message
39 | * @param type Identifier for the message location
40 | * @param msg Message to send
41 | * @param args Javascript variables to pass to the console
42 | */
43 | export function error(type: string, msg: string, args?: any) {
44 | log(type, msg, args, 'error');
45 | }
46 |
47 | /**
48 | * Log formatted version information for the library
49 | * @param version
50 | * @param build
51 | * @param out
52 | */
53 | export function version(version: string, build: string, out: any = 'debug') {
54 | const COLOURS = ['color: #f44336', `color: #9c27b0`, 'color: default'];
55 | if (hasColours()) {
56 | console[out](`%c[ACA]%c[LIB] %c${LIB_NAME} - ${version} | ${build}`, ...COLOURS);
57 | } else {
58 | console[out](`[ACA][LIB] ${LIB_NAME} - ${version} | ${build}`);
59 | }
60 | }
61 |
62 | /**
63 | * Whether the browser console supports CSS colours
64 | */
65 | export function hasColours() {
66 | const doc = document as any;
67 | return !(doc.documentMode || /Edge/.test(navigator.userAgent));
68 | }
69 |
--------------------------------------------------------------------------------
/projects/library/src/oauth-resp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Authentication Success
7 |
8 |
9 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/projects/library/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of library
3 | */
4 |
5 | export * from './lib/library.module';
6 |
7 | export * from './lib/directives/binding.directive';
8 |
9 | export * from './lib/services/composer.service';
10 | export * from './lib/services/binding.service';
11 | export * from './lib/services/http.service';
12 |
--------------------------------------------------------------------------------
/projects/library/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone';
4 | import 'zone.js/dist/zone-testing';
5 | import { getTestBed } from '@angular/core/testing';
6 | import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
7 |
8 | declare const require: any;
9 |
10 | // First, initialize the Angular testing environment.
11 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
12 | // Then we find all the tests.
13 | const context = require.context('./', true, /\.spec\.ts$/);
14 | // And load the modules.
15 | context.keys().map(context);
16 |
--------------------------------------------------------------------------------
/projects/library/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/lib",
5 | "target": "es2015",
6 | "declaration": true,
7 | "inlineSources": true,
8 | "types": [],
9 | "lib": [
10 | "dom",
11 | "es2018"
12 | ]
13 | },
14 | "angularCompilerOptions": {
15 | "annotateForClosureCompiler": true,
16 | "skipTemplateCodegen": true,
17 | "strictMetadataEmit": true,
18 | "fullTemplateTypeCheck": true,
19 | "strictInjectionParameters": true,
20 | "enableResourceInlining": true
21 | },
22 | "exclude": [
23 | "src/test.ts",
24 | "**/*.spec.ts"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/projects/library/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/spec",
5 | "types": [
6 | "jasmine",
7 | "node"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts"
12 | ],
13 | "include": [
14 | "**/*.spec.ts",
15 | "**/*.d.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/projects/library/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tslint.json",
3 | "rules": {
4 | "directive-selector": [
5 | true,
6 | "attribute",
7 | "lib",
8 | "camelCase"
9 | ],
10 | "component-selector": [
11 | true,
12 | "element",
13 | "lib",
14 | "kebab-case"
15 | ]
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "module": "esnext",
9 | "moduleResolution": "node",
10 | "emitDecoratorMetadata": true,
11 | "experimentalDecorators": true,
12 | "importHelpers": true,
13 | "target": "es2015",
14 | "typeRoots": [
15 | "node_modules/@types"
16 | ],
17 | "lib": [
18 | "es2018",
19 | "dom"
20 | ],
21 | "paths": {
22 | "library": [
23 | "dist/library"
24 | ],
25 | "library/*": [
26 | "dist/library/*"
27 | ]
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended",
3 | "rulesDirectory": [
4 | "codelyzer"
5 | ],
6 | "rules": {
7 | "array-type": false,
8 | "arrow-parens": false,
9 | "deprecation": {
10 | "severity": "warn"
11 | },
12 | "import-blacklist": [
13 | true,
14 | "rxjs/Rx"
15 | ],
16 | "interface-name": false,
17 | "max-classes-per-file": false,
18 | "max-line-length": [
19 | true,
20 | 140
21 | ],
22 | "member-access": false,
23 | "member-ordering": [
24 | true,
25 | {
26 | "order": [
27 | "static-field",
28 | "instance-field",
29 | "static-method",
30 | "instance-method"
31 | ]
32 | }
33 | ],
34 | "no-consecutive-blank-lines": false,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-empty": false,
44 | "no-inferrable-types": [
45 | true,
46 | "ignore-params"
47 | ],
48 | "no-non-null-assertion": true,
49 | "no-redundant-jsdoc": true,
50 | "no-switch-case-fall-through": true,
51 | "no-use-before-declare": true,
52 | "no-var-requires": false,
53 | "object-literal-key-quotes": [
54 | true,
55 | "as-needed"
56 | ],
57 | "object-literal-sort-keys": false,
58 | "ordered-imports": false,
59 | "quotemark": [
60 | true,
61 | "single"
62 | ],
63 | "trailing-comma": false,
64 | "component-class-suffix": true,
65 | "contextual-lifecycle": true,
66 | "directive-class-suffix": true,
67 | "no-conflicting-lifecycle": true,
68 | "no-host-metadata-property": true,
69 | "no-input-rename": true,
70 | "no-inputs-metadata-property": true,
71 | "no-output-native": true,
72 | "no-output-on-prefix": true,
73 | "no-output-rename": true,
74 | "no-outputs-metadata-property": true,
75 | "template-banana-in-box": true,
76 | "template-no-negated-async": true,
77 | "use-lifecycle-interface": true,
78 | "use-pipe-transform-interface": true
79 | }
80 | }
--------------------------------------------------------------------------------