From 96aada138b11aff4353db4a71769e5551f894209 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 2 Oct 2017 09:40:10 -0500 Subject: [PATCH 001/205] initial load of project restructuring --- ngapp/.angular-cli.json | 60 + ngapp/.editorconfig | 13 + ngapp/.gitignore | 43 + ngapp/README.md | 28 + ngapp/e2e/app.e2e-spec.ts | 14 + ngapp/e2e/app.po.ts | 11 + ngapp/e2e/tsconfig.e2e.json | 14 + ngapp/karma.conf.js | 33 + ngapp/package-lock.json | 9879 +++++++++++++++++ ngapp/package.json | 49 + ngapp/protractor.conf.js | 28 + .../activities-cards.component.css | 69 + .../activities-cards.component.html | 34 + .../activities-cards.component.spec.ts | 25 + .../activities-cards.component.ts | 78 + .../activities-list.component.css | 36 + .../activities-list.component.html | 40 + .../activities-list.component.spec.ts | 25 + .../activities-list.component.ts | 77 + .../app/activities/activities.component.css | 57 + .../app/activities/activities.component.html | 107 + .../activities/activities.component.spec.ts | 25 + .../app/activities/activities.component.ts | 190 + ngapp/src/app/activities/activities.module.ts | 48 + .../add-activity/add-activity.component.css | 12 + .../add-activity/add-activity.component.html | 16 + .../add-activity.component.spec.ts | 25 + .../add-activity/add-activity.component.ts | 54 + .../app/activities/shared/activity.model.ts | 87 + .../shared/activity.service.spec.ts | 15 + .../app/activities/shared/activity.service.ts | 109 + .../add-activity-form.component.css | 60 + .../add-activity-form.component.html | 43 + .../add-activity-form.component.spec.ts | 25 + .../add-activity-form.component.ts | 66 + .../activities/shared/new-activity.model.ts | 97 + ngapp/src/app/app.component.css | 0 ngapp/src/app/app.component.html | 20 + ngapp/src/app/app.component.spec.ts | 32 + ngapp/src/app/app.component.ts | 27 + ngapp/src/app/app.module.ts | 41 + .../add-connection-form.component.css | 60 + .../add-connection-form.component.html | 42 + .../add-connection-form.component.spec.ts | 27 + .../add-connection-form.component.ts | 63 + .../add-connection.component.css | 12 + .../add-connection.component.html | 16 + .../add-connection.component.spec.ts | 27 + .../add-connection.component.ts | 61 + .../connections-cards.component.css | 68 + .../connections-cards.component.html | 35 + .../connections-cards.component.spec.ts | 27 + .../connections-cards.component.ts | 74 + .../connections-list.component.css | 36 + .../connections-list.component.html | 40 + .../connections-list.component.spec.ts | 27 + .../connections-list.component.ts | 75 + .../app/connections/connections.component.css | 57 + .../connections/connections.component.html | 107 + .../connections/connections.component.spec.ts | 25 + .../app/connections/connections.component.ts | 198 + .../src/app/connections/connections.module.ts | 53 + .../edit-connection.component.css | 12 + .../edit-connection.component.html | 18 + .../edit-connection.component.spec.ts | 25 + .../edit-connection.component.ts | 60 + .../add-connection-form.component.css | 60 + .../add-connection-form.component.html | 42 + .../add-connection-form.component.spec.ts | 27 + .../add-connection-form.component.ts | 63 + .../connections/shared/connection.model.ts | 103 + .../shared/connection.service.spec.ts | 15 + .../connections/shared/connection.service.ts | 74 + .../shared/new-connection.model.ts | 112 + ngapp/src/app/core/api.service.spec.ts | 17 + ngapp/src/app/core/api.service.ts | 47 + .../breadcrumb/breadcrumb.component.css | 3 + .../breadcrumb/breadcrumb.component.html | 2 + .../breadcrumb/breadcrumb.component.spec.ts | 25 + .../breadcrumb/breadcrumb.component.ts | 32 + .../breadcrumbs/breadcrumbs.component.css | 7 + .../breadcrumbs/breadcrumbs.component.html | 7 + .../breadcrumbs/breadcrumbs.component.spec.ts | 25 + .../core/breadcrumbs/breadcrumbs.component.ts | 28 + ngapp/src/app/core/common.ts | 111 + ngapp/src/app/core/core.module.ts | 37 + .../core/nav-header/nav-header.component.html | 58 + .../core/nav-header/nav-header.component.less | 46 + .../nav-header/nav-header.component.spec.ts | 25 + .../core/nav-header/nav-header.component.ts | 53 + .../vertical-nav/vertical-nav.component.html | 18 + .../vertical-nav/vertical-nav.component.less | 89 + .../vertical-nav.component.spec.ts | 27 + .../vertical-nav/vertical-nav.component.ts | 115 + .../src/app/shared/abstract-page.component.ts | 85 + .../confirm-delete.component.css | 0 .../confirm-delete.component.html | 20 + .../confirm-delete.component.spec.ts | 27 + .../confirm-delete.component.ts | 78 + .../page-error/page-error.component.css | 14 + .../page-error/page-error.component.html | 115 + .../page-error/page-error.component.spec.ts | 25 + .../shared/page-error/page-error.component.ts | 95 + ngapp/src/app/shared/shared.module.ts | 38 + ngapp/src/assets/.gitkeep | 0 ngapp/src/environments/environment.prod.ts | 3 + ngapp/src/environments/environment.ts | 15 + ngapp/src/favicon.ico | Bin 0 -> 5430 bytes ngapp/src/index.html | 14 + ngapp/src/main.ts | 11 + ngapp/src/polyfills.ts | 72 + ngapp/src/styles.css | 1 + ngapp/src/test.ts | 32 + ngapp/src/tsconfig.app.json | 13 + ngapp/src/tsconfig.spec.json | 20 + ngapp/src/typings.d.ts | 5 + ngapp/tsconfig.json | 28 + ngapp/tslint.json | 142 + 118 files changed, 15078 insertions(+) create mode 100644 ngapp/.angular-cli.json create mode 100644 ngapp/.editorconfig create mode 100644 ngapp/.gitignore create mode 100644 ngapp/README.md create mode 100644 ngapp/e2e/app.e2e-spec.ts create mode 100644 ngapp/e2e/app.po.ts create mode 100644 ngapp/e2e/tsconfig.e2e.json create mode 100644 ngapp/karma.conf.js create mode 100644 ngapp/package-lock.json create mode 100644 ngapp/package.json create mode 100644 ngapp/protractor.conf.js create mode 100644 ngapp/src/app/activities/activities-cards/activities-cards.component.css create mode 100644 ngapp/src/app/activities/activities-cards/activities-cards.component.html create mode 100644 ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts create mode 100644 ngapp/src/app/activities/activities-cards/activities-cards.component.ts create mode 100644 ngapp/src/app/activities/activities-list/activities-list.component.css create mode 100644 ngapp/src/app/activities/activities-list/activities-list.component.html create mode 100644 ngapp/src/app/activities/activities-list/activities-list.component.spec.ts create mode 100644 ngapp/src/app/activities/activities-list/activities-list.component.ts create mode 100644 ngapp/src/app/activities/activities.component.css create mode 100644 ngapp/src/app/activities/activities.component.html create mode 100644 ngapp/src/app/activities/activities.component.spec.ts create mode 100644 ngapp/src/app/activities/activities.component.ts create mode 100644 ngapp/src/app/activities/activities.module.ts create mode 100644 ngapp/src/app/activities/add-activity/add-activity.component.css create mode 100644 ngapp/src/app/activities/add-activity/add-activity.component.html create mode 100644 ngapp/src/app/activities/add-activity/add-activity.component.spec.ts create mode 100644 ngapp/src/app/activities/add-activity/add-activity.component.ts create mode 100644 ngapp/src/app/activities/shared/activity.model.ts create mode 100644 ngapp/src/app/activities/shared/activity.service.spec.ts create mode 100644 ngapp/src/app/activities/shared/activity.service.ts create mode 100644 ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.css create mode 100644 ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.html create mode 100644 ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts create mode 100644 ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts create mode 100644 ngapp/src/app/activities/shared/new-activity.model.ts create mode 100644 ngapp/src/app/app.component.css create mode 100644 ngapp/src/app/app.component.html create mode 100644 ngapp/src/app/app.component.spec.ts create mode 100644 ngapp/src/app/app.component.ts create mode 100644 ngapp/src/app/app.module.ts create mode 100644 ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.css create mode 100644 ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.html create mode 100644 ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts create mode 100644 ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.ts create mode 100644 ngapp/src/app/connections/add-connection/add-connection.component.css create mode 100644 ngapp/src/app/connections/add-connection/add-connection.component.html create mode 100644 ngapp/src/app/connections/add-connection/add-connection.component.spec.ts create mode 100644 ngapp/src/app/connections/add-connection/add-connection.component.ts create mode 100644 ngapp/src/app/connections/connections-cards/connections-cards.component.css create mode 100644 ngapp/src/app/connections/connections-cards/connections-cards.component.html create mode 100644 ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts create mode 100644 ngapp/src/app/connections/connections-cards/connections-cards.component.ts create mode 100644 ngapp/src/app/connections/connections-list/connections-list.component.css create mode 100644 ngapp/src/app/connections/connections-list/connections-list.component.html create mode 100644 ngapp/src/app/connections/connections-list/connections-list.component.spec.ts create mode 100644 ngapp/src/app/connections/connections-list/connections-list.component.ts create mode 100644 ngapp/src/app/connections/connections.component.css create mode 100644 ngapp/src/app/connections/connections.component.html create mode 100644 ngapp/src/app/connections/connections.component.spec.ts create mode 100644 ngapp/src/app/connections/connections.component.ts create mode 100644 ngapp/src/app/connections/connections.module.ts create mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.css create mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.html create mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts create mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.ts create mode 100644 ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css create mode 100644 ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html create mode 100644 ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts create mode 100644 ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts create mode 100644 ngapp/src/app/connections/shared/connection.model.ts create mode 100644 ngapp/src/app/connections/shared/connection.service.spec.ts create mode 100644 ngapp/src/app/connections/shared/connection.service.ts create mode 100644 ngapp/src/app/connections/shared/new-connection.model.ts create mode 100644 ngapp/src/app/core/api.service.spec.ts create mode 100644 ngapp/src/app/core/api.service.ts create mode 100644 ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css create mode 100644 ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html create mode 100644 ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts create mode 100644 ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts create mode 100644 ngapp/src/app/core/breadcrumbs/breadcrumbs.component.css create mode 100644 ngapp/src/app/core/breadcrumbs/breadcrumbs.component.html create mode 100644 ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts create mode 100644 ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts create mode 100644 ngapp/src/app/core/common.ts create mode 100644 ngapp/src/app/core/core.module.ts create mode 100644 ngapp/src/app/core/nav-header/nav-header.component.html create mode 100644 ngapp/src/app/core/nav-header/nav-header.component.less create mode 100644 ngapp/src/app/core/nav-header/nav-header.component.spec.ts create mode 100644 ngapp/src/app/core/nav-header/nav-header.component.ts create mode 100644 ngapp/src/app/core/vertical-nav/vertical-nav.component.html create mode 100644 ngapp/src/app/core/vertical-nav/vertical-nav.component.less create mode 100644 ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts create mode 100644 ngapp/src/app/core/vertical-nav/vertical-nav.component.ts create mode 100644 ngapp/src/app/shared/abstract-page.component.ts create mode 100644 ngapp/src/app/shared/confirm-delete/confirm-delete.component.css create mode 100644 ngapp/src/app/shared/confirm-delete/confirm-delete.component.html create mode 100644 ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts create mode 100644 ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts create mode 100644 ngapp/src/app/shared/page-error/page-error.component.css create mode 100644 ngapp/src/app/shared/page-error/page-error.component.html create mode 100644 ngapp/src/app/shared/page-error/page-error.component.spec.ts create mode 100644 ngapp/src/app/shared/page-error/page-error.component.ts create mode 100644 ngapp/src/app/shared/shared.module.ts create mode 100644 ngapp/src/assets/.gitkeep create mode 100644 ngapp/src/environments/environment.prod.ts create mode 100644 ngapp/src/environments/environment.ts create mode 100644 ngapp/src/favicon.ico create mode 100644 ngapp/src/index.html create mode 100644 ngapp/src/main.ts create mode 100644 ngapp/src/polyfills.ts create mode 100644 ngapp/src/styles.css create mode 100644 ngapp/src/test.ts create mode 100644 ngapp/src/tsconfig.app.json create mode 100644 ngapp/src/tsconfig.spec.json create mode 100644 ngapp/src/typings.d.ts create mode 100644 ngapp/tsconfig.json create mode 100644 ngapp/tslint.json diff --git a/ngapp/.angular-cli.json b/ngapp/.angular-cli.json new file mode 100644 index 00000000..fdc1df3f --- /dev/null +++ b/ngapp/.angular-cli.json @@ -0,0 +1,60 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "project": { + "name": "beetle-studio" + }, + "apps": [ + { + "root": "src", + "outDir": "dist", + "assets": [ + "assets", + "favicon.ico" + ], + "index": "index.html", + "main": "main.ts", + "polyfills": "polyfills.ts", + "test": "test.ts", + "tsconfig": "tsconfig.app.json", + "testTsconfig": "tsconfig.spec.json", + "prefix": "app", + "styles": [ + "styles.css" + ], + "scripts": [], + "environmentSource": "environments/environment.ts", + "environments": { + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" + } + } + ], + "e2e": { + "protractor": { + "config": "./protractor.conf.js" + } + }, + "lint": [ + { + "project": "src/tsconfig.app.json", + "exclude": "**/node_modules/**" + }, + { + "project": "src/tsconfig.spec.json", + "exclude": "**/node_modules/**" + }, + { + "project": "e2e/tsconfig.e2e.json", + "exclude": "**/node_modules/**" + } + ], + "test": { + "karma": { + "config": "./karma.conf.js" + } + }, + "defaults": { + "styleExt": "css", + "component": {} + } +} diff --git a/ngapp/.editorconfig b/ngapp/.editorconfig new file mode 100644 index 00000000..6e87a003 --- /dev/null +++ b/ngapp/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/ngapp/.gitignore b/ngapp/.gitignore new file mode 100644 index 00000000..6b668143 --- /dev/null +++ b/ngapp/.gitignore @@ -0,0 +1,43 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +testem.log +/typings +yarn-error.log + +# e2e +/e2e/*.js +/e2e/*.map + +# System Files +.DS_Store +Thumbs.db diff --git a/ngapp/README.md b/ngapp/README.md new file mode 100644 index 00000000..e66b7bea --- /dev/null +++ b/ngapp/README.md @@ -0,0 +1,28 @@ +# BeetleStudio + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.3.2. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). +Before running the tests make sure you are serving the app via `ng serve`. + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/ngapp/e2e/app.e2e-spec.ts b/ngapp/e2e/app.e2e-spec.ts new file mode 100644 index 00000000..ce845c4e --- /dev/null +++ b/ngapp/e2e/app.e2e-spec.ts @@ -0,0 +1,14 @@ +import { AppPage } from './app.po'; + +describe('beetle-studio App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getParagraphText()).toEqual('Welcome to app!'); + }); +}); diff --git a/ngapp/e2e/app.po.ts b/ngapp/e2e/app.po.ts new file mode 100644 index 00000000..82ea75ba --- /dev/null +++ b/ngapp/e2e/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get('/'); + } + + getParagraphText() { + return element(by.css('app-root h1')).getText(); + } +} diff --git a/ngapp/e2e/tsconfig.e2e.json b/ngapp/e2e/tsconfig.e2e.json new file mode 100644 index 00000000..1d9e5edf --- /dev/null +++ b/ngapp/e2e/tsconfig.e2e.json @@ -0,0 +1,14 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "baseUrl": "./", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} diff --git a/ngapp/karma.conf.js b/ngapp/karma.conf.js new file mode 100644 index 00000000..af139fad --- /dev/null +++ b/ngapp/karma.conf.js @@ -0,0 +1,33 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular/cli'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular/cli/plugins/karma') + ], + client:{ + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + reports: [ 'html', 'lcovonly' ], + fixWebpackSourcePaths: true + }, + angularCli: { + environment: 'dev' + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json new file mode 100644 index 00000000..663ed29e --- /dev/null +++ b/ngapp/package-lock.json @@ -0,0 +1,9879 @@ +{ + "name": "beetle-studio", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/build-optimizer": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.13.tgz", + "integrity": "sha512-yEMkYU4YU8XlA5OauPhg22ZEWJ4X2VhiFKUwfeo4UWJ7lz4XWiuBJocrT5NHWqI1S0rOLpSixLXG9byvFMbavA==", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "source-map": "0.5.7", + "typescript": "2.3.4" + } + }, + "@angular/animations": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.4.4.tgz", + "integrity": "sha1-ovk1NgQ0er4V35gpIFiEL1Lwi8I=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/cli": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.3.2.tgz", + "integrity": "sha512-VAZXI19PbhhUE/dJH5r6HT7502y0OXYzxhbGIagh/e7SNKnVV8KglVL4zfTfnsI8kmLrFFbAmPy7xomKO8Btkg==", + "dev": true, + "requires": { + "@angular-devkit/build-optimizer": "0.0.13", + "@ngtools/json-schema": "1.1.0", + "@ngtools/webpack": "1.6.2", + "autoprefixer": "6.7.7", + "chalk": "2.1.0", + "circular-dependency-plugin": "3.0.0", + "common-tags": "1.4.0", + "core-object": "3.1.5", + "css-loader": "0.28.7", + "cssnano": "3.10.0", + "denodeify": "1.2.1", + "diff": "3.3.1", + "ember-cli-normalize-entity-name": "1.0.0", + "ember-cli-string-utils": "1.1.0", + "exports-loader": "0.6.4", + "extract-text-webpack-plugin": "3.0.0", + "file-loader": "0.10.1", + "fs-extra": "4.0.2", + "get-caller-file": "1.0.2", + "glob": "7.1.2", + "heimdalljs": "0.2.5", + "heimdalljs-logger": "0.1.9", + "html-webpack-plugin": "2.30.1", + "inflection": "1.12.0", + "inquirer": "3.3.0", + "isbinaryfile": "3.0.2", + "istanbul-instrumenter-loader": "2.0.0", + "karma-source-map-support": "1.2.0", + "less": "2.7.2", + "less-loader": "4.0.5", + "license-webpack-plugin": "0.5.1", + "lodash": "4.17.4", + "memory-fs": "0.4.1", + "minimatch": "3.0.4", + "node-modules-path": "1.0.1", + "node-sass": "4.5.3", + "nopt": "4.0.1", + "opn": "5.1.0", + "portfinder": "1.0.13", + "postcss-loader": "1.3.3", + "postcss-url": "5.1.2", + "raw-loader": "0.5.1", + "resolve": "1.4.0", + "rsvp": "3.6.2", + "rxjs": "5.4.3", + "sass-loader": "6.0.6", + "script-loader": "0.7.1", + "semver": "5.4.1", + "silent-error": "1.1.0", + "source-map-loader": "0.2.1", + "source-map-support": "0.4.18", + "style-loader": "0.13.2", + "stylus": "0.54.5", + "stylus-loader": "3.0.1", + "temp": "0.8.3", + "typescript": "2.3.4", + "url-loader": "0.5.9", + "walk-sync": "0.3.2", + "webpack": "3.4.1", + "webpack-dev-middleware": "1.12.0", + "webpack-dev-server": "2.5.1", + "webpack-merge": "4.1.0", + "zone.js": "0.8.18" + } + }, + "@angular/common": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.4.4.tgz", + "integrity": "sha1-rgqBiqoMaj8JAee4C9lOHCLrk2U=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/compiler": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.4.4.tgz", + "integrity": "sha1-Mm6wAp2aNUGqyhJN75rcUcNvK0E=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/compiler-cli": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.4.4.tgz", + "integrity": "sha1-BjCApJfZF1OWglBQIixxfaGE9s8=", + "dev": true, + "requires": { + "@angular/tsc-wrapped": "4.4.4", + "minimist": "1.2.0", + "reflect-metadata": "0.1.10" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@angular/core": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.4.4.tgz", + "integrity": "sha1-vTfs9UFY+XSJmWyThr0iL4CjL1w=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/forms": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.4.4.tgz", + "integrity": "sha1-TbN5BQm2sQ8duKfBt/Uhh89kz9Q=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/http": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.4.4.tgz", + "integrity": "sha1-Zn+vYWu2JBaOr65u6S5euiOp0fI=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/language-service": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-4.4.4.tgz", + "integrity": "sha1-D2hgUuOVDBkSjxO3Qp/BS6/mm9Q=", + "dev": true + }, + "@angular/platform-browser": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.4.4.tgz", + "integrity": "sha1-o4mOLnup2E/6DUcUTGlxF5x1ruY=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/platform-browser-dynamic": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.4.4.tgz", + "integrity": "sha1-w8nrhUpShVagcFQSeTLlJ/qTLhQ=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/router": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.4.4.tgz", + "integrity": "sha1-e+ORCW6EPLPgT58F0dZaiN+bx88=", + "requires": { + "tslib": "1.7.1" + } + }, + "@angular/tsc-wrapped": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.4.4.tgz", + "integrity": "sha1-mEGCHlVha4JsoWAlD+heFfx0/8M=", + "dev": true, + "requires": { + "tsickle": "0.21.6" + } + }, + "@ngtools/json-schema": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz", + "integrity": "sha1-w6DFRNYjkqzCgTpCyKDcb1j4aSI=", + "dev": true + }, + "@ngtools/webpack": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.6.2.tgz", + "integrity": "sha512-2s2kCCV3FQUC+MG69e+H5k7zELuVcQ0Gkl1ioqR25HOclxv0UGVY7jsmz9LRm/DanS5ORXQt4S82EFV1dY4w+A==", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "magic-string": "0.22.4", + "source-map": "0.5.7" + } + }, + "@types/jasmine": { + "version": "2.5.54", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.54.tgz", + "integrity": "sha512-B9YofFbUljs19g5gBKUYeLIulsh31U5AK70F41BImQRHEZQGm4GcN922UvnYwkduMqbC/NH+9fruWa/zrqvHIg==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.3.tgz", + "integrity": "sha512-hYDVmQZT5VA2kigd4H4bv7vl/OhlympwREUemqBdOqtrYTo5Ytm12a5W5/nGgGYdanGVxj0x/VhZ7J3hOg/YKg==", + "dev": true, + "requires": { + "@types/jasmine": "2.5.54" + } + }, + "@types/node": { + "version": "6.0.88", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.88.tgz", + "integrity": "sha512-bYDPZTX0/s1aihdjLuAgogUAT5M+TpoWChEMea2p0yOcfn5bu3k6cJb9cp6nw268XeSNIGGr+4+/8V5K6BGzLQ==", + "dev": true + }, + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "2.53.42", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.42.tgz", + "integrity": "sha1-dMt3+2BS7a/yqJhN2v2I1BnyXKw=", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "dev": true, + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", + "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "dev": true, + "requires": { + "acorn": "4.0.13" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "adm-zip": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", + "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, + "requires": { + "extend": "3.0.1", + "semver": "5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true + } + } + }, + "ajv": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", + "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "json-schema-traverse": "0.3.1", + "json-stable-stringify": "1.0.1" + } + }, + "ajv-keywords": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.0.tgz", + "integrity": "sha1-opbhf3v658HOT34N5T0pyzIWLfA=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", + "dev": true + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "app-root-path": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.0.1.tgz", + "integrity": "sha1-zWLc+OT9WkF+/GZNLlsQZTxlG0Y=", + "dev": true + }, + "append-transform": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true, + "requires": { + "default-require-extensions": "1.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "dev": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", + "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true, + "optional": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "asn1.js": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz", + "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "autoprefixer": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", + "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000740", + "normalize-range": "0.1.2", + "num2fraction": "1.2.2", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + } + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "binary-extensions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", + "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=", + "dev": true + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "optional": true, + "requires": { + "inherits": "2.0.3" + } + }, + "blocking-proxy": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.5.tgz", + "integrity": "sha1-RikF4Nz76pcPQao3Ij3anAexkSs=", + "dev": true, + "requires": { + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.1", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.15" + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "2.1.1", + "deep-equal": "1.0.1", + "dns-equal": "1.0.0", + "dns-txt": "2.0.2", + "multicast-dns": "6.1.1", + "multicast-dns-service-types": "1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + } + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.8.tgz", + "integrity": "sha512-WYCMOT/PtGTlpOKFht0YJFYcPy6pLCR98CtWfzK13zoynLlBMvAdEMSRGmgnJCw2M2j/5qxBkinZQFobieM8dQ==", + "dev": true, + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "browserify-cipher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", + "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", + "dev": true, + "requires": { + "browserify-aes": "1.0.8", + "browserify-des": "1.0.0", + "evp_bytestokey": "1.0.3" + } + }, + "browserify-des": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", + "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "des.js": "1.0.0", + "inherits": "2.0.3" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "randombytes": "2.0.5" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "elliptic": "6.4.0", + "inherits": "2.0.3", + "parse-asn1": "5.1.0" + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "dev": true, + "requires": { + "pako": "0.2.9" + } + }, + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "1.0.30000740", + "electron-to-chromium": "1.3.24" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "1.2.1", + "ieee754": "1.1.8", + "isarray": "1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "2.3.2", + "upper-case": "1.1.3" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "caniuse-api": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", + "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000740", + "lodash.memoize": "4.1.2", + "lodash.uniq": "4.5.0" + } + }, + "caniuse-db": { + "version": "1.0.30000740", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000740.tgz", + "integrity": "sha1-A/yqoXbj7QdYlfctRsGhIUm76sk=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + }, + "dependencies": { + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + } + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "fsevents": "1.1.2", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "circular-dependency-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-3.0.0.tgz", + "integrity": "sha1-m2hpLjWw41EJmNAWS2rlARvqV2A=", + "dev": true + }, + "clap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", + "dev": true, + "requires": { + "chalk": "1.1.3" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "clean-css": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz", + "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "clone": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", + "dev": true + }, + "clone-deep": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz", + "integrity": "sha1-NIxhrpzb4O3+BT2R/0zFIdeQ7eg=", + "dev": true, + "requires": { + "for-own": "1.0.0", + "is-plain-object": "2.0.4", + "kind-of": "3.2.2", + "shallow-clone": "0.1.2" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", + "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", + "dev": true, + "requires": { + "q": "1.5.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "codelyzer": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-3.1.2.tgz", + "integrity": "sha1-n/HwQfubXuXb60W6hm368EmDrwQ=", + "dev": true, + "requires": { + "app-root-path": "2.0.1", + "css-selector-tokenizer": "0.7.0", + "cssauron": "1.4.0", + "semver-dsl": "1.0.1", + "source-map": "0.5.7", + "sprintf-js": "1.0.3" + } + }, + "color": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", + "dev": true, + "requires": { + "clone": "1.0.2", + "color-convert": "1.9.0", + "color-string": "0.3.0" + } + }, + "color-convert": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", + "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-string": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "colormin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", + "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", + "dev": true, + "requires": { + "color": "0.11.4", + "css-color-names": "0.0.4", + "has": "1.0.1" + } + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combine-lists": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", + "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "common-tags": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.4.0.tgz", + "integrity": "sha1-EYe+Tz1M8MBCfUP3Tu8fc1AWFMA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz", + "integrity": "sha1-FnGKdd4oPtjmBAQWJaIGRYZ5fYo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "compression": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz", + "integrity": "sha1-7/JgPvwuIs+G810uuTWJ+YdTc9s=", + "dev": true, + "requires": { + "accepts": "1.3.4", + "bytes": "3.0.0", + "compressible": "2.0.11", + "debug": "2.6.9", + "on-headers": "1.0.1", + "safe-buffer": "5.1.1", + "vary": "1.1.2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "connect": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz", + "integrity": "sha1-+43ee6B2OHfQ7J352sC0tA5yx9o=", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.0.6", + "parseurl": "1.3.2", + "utils-merge": "1.0.1" + }, + "dependencies": { + "finalhandler": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", + "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + } + } + }, + "connect-history-api-fallback": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz", + "integrity": "sha1-5R0X+PDvDbkKZP20feMFFVbp8Wk=", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "0.1.4" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=" + }, + "core-object": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz", + "integrity": "sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg==", + "dev": true, + "requires": { + "chalk": "2.1.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "0.3.1", + "js-yaml": "3.7.0", + "minimist": "1.2.0", + "object-assign": "4.1.1", + "os-homedir": "1.0.2", + "parse-json": "2.2.0", + "require-from-string": "1.2.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "create-ecdh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "elliptic": "6.4.0" + } + }, + "create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "sha.js": "2.4.9" + } + }, + "create-hmac": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", + "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.9" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "4.1.1", + "which": "1.3.0" + } + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "crypto-browserify": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz", + "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==", + "dev": true, + "requires": { + "browserify-cipher": "1.0.0", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.0", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "diffie-hellman": "5.0.2", + "inherits": "2.0.3", + "pbkdf2": "3.0.14", + "public-encrypt": "4.0.0", + "randombytes": "2.0.5" + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-loader": { + "version": "0.28.7", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.7.tgz", + "integrity": "sha512-GxMpax8a/VgcfRrVy0gXD6yLd5ePYbXX/5zGgTVYp4wXtJklS8Z2VaUArJgc//f6/Dzil7BaJObdSv8eKKCPgg==", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "css-selector-tokenizer": "0.7.0", + "cssnano": "3.10.0", + "icss-utils": "2.1.0", + "loader-utils": "1.1.0", + "lodash.camelcase": "4.3.0", + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-modules-extract-imports": "1.1.0", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0", + "postcss-value-parser": "3.3.0", + "source-list-map": "2.0.0" + } + }, + "css-parse": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", + "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=", + "dev": true + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "1.0.0", + "css-what": "2.1.0", + "domutils": "1.5.1", + "nth-check": "1.0.1" + } + }, + "css-selector-tokenizer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", + "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", + "dev": true, + "requires": { + "cssesc": "0.1.0", + "fastparse": "1.1.1", + "regexpu-core": "1.0.0" + } + }, + "css-what": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "2.3.8" + } + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cssnano": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", + "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", + "dev": true, + "requires": { + "autoprefixer": "6.7.7", + "decamelize": "1.2.0", + "defined": "1.0.0", + "has": "1.0.1", + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-calc": "5.3.1", + "postcss-colormin": "2.2.2", + "postcss-convert-values": "2.6.1", + "postcss-discard-comments": "2.0.4", + "postcss-discard-duplicates": "2.1.0", + "postcss-discard-empty": "2.1.0", + "postcss-discard-overridden": "0.1.1", + "postcss-discard-unused": "2.2.3", + "postcss-filter-plugins": "2.0.2", + "postcss-merge-idents": "2.1.7", + "postcss-merge-longhand": "2.0.2", + "postcss-merge-rules": "2.1.2", + "postcss-minify-font-values": "1.0.5", + "postcss-minify-gradients": "1.0.5", + "postcss-minify-params": "1.2.2", + "postcss-minify-selectors": "2.1.1", + "postcss-normalize-charset": "1.1.1", + "postcss-normalize-url": "3.0.8", + "postcss-ordered-values": "2.2.3", + "postcss-reduce-idents": "2.4.0", + "postcss-reduce-initial": "1.0.1", + "postcss-reduce-transforms": "1.0.4", + "postcss-svgo": "2.1.6", + "postcss-unique-selectors": "2.0.2", + "postcss-value-parser": "3.3.0", + "postcss-zindex": "2.2.0" + } + }, + "csso": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", + "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", + "dev": true, + "requires": { + "clap": "1.2.3", + "source-map": "0.5.7" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "0.10.30" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "dev": true, + "requires": { + "strip-bom": "2.0.0" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "6.1.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "p-map": "1.2.0", + "pify": "3.0.0", + "rimraf": "2.6.2" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", + "dev": true + }, + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "detect-node": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", + "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=", + "dev": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", + "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "miller-rabin": "4.0.1", + "randombytes": "2.0.5" + } + }, + "directory-encoder": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/directory-encoder/-/directory-encoder-0.7.2.tgz", + "integrity": "sha1-WbTiqk8lQi9sY7UntGL14tDdLFg=", + "dev": true, + "requires": { + "fs-extra": "0.23.1", + "handlebars": "1.3.0", + "img-stats": "0.5.2" + }, + "dependencies": { + "fs-extra": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.23.1.tgz", + "integrity": "sha1-ZhHbpq3yq43Jxp+rN83fiBgVfj0=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.2" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + } + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.2.2.tgz", + "integrity": "sha512-kN+DjfGF7dJGUL7nWRktL9Z18t1rWP3aQlyZdY8XlpvU3Nc6GeFTQApftcjtWKxAZfiggZSGrCEoszNgvnpwDg==", + "dev": true, + "requires": { + "ip": "1.1.5", + "safe-buffer": "5.1.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "1.1.1" + } + }, + "dom-converter": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", + "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", + "dev": true, + "requires": { + "utila": "0.3.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "1.0.1", + "ent": "2.2.0", + "extend": "3.0.1", + "void-elements": "2.0.1" + } + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=", + "dev": true + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.24", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.24.tgz", + "integrity": "sha1-m3uIuwXOufoBahd4M8wt3jiPIbY=", + "dev": true + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "ember-cli-normalize-entity-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz", + "integrity": "sha1-CxT3vLxZmqEXtf3cgeT9A8S61bc=", + "dev": true, + "requires": { + "silent-error": "1.1.0" + } + }, + "ember-cli-string-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz", + "integrity": "sha1-ObZ3/CgF9VFzc1N2/O8njqpEUqE=", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=", + "dev": true + }, + "engine.io": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.3.tgz", + "integrity": "sha1-jef5eJXSDTm4X4ju7nd7K9QrE9Q=", + "dev": true, + "requires": { + "accepts": "1.3.3", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "ws": "1.1.2" + }, + "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "dev": true, + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "engine.io-client": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.3.tgz", + "integrity": "sha1-F5jtk0USRkU9TG9jXXogH+lA1as=", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parsejson": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "1.1.2", + "xmlhttprequest-ssl": "1.5.3", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "engine.io-parser": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", + "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.6", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary": "0.1.7", + "wtf-8": "1.0.0" + } + }, + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "memory-fs": "0.4.1", + "object-assign": "4.1.1", + "tapable": "0.2.8" + } + }, + "ensure-posix-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz", + "integrity": "sha1-pls+QtC3HPxYXrd0+ZQ8jZuRsMI=", + "dev": true + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "errno": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", + "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", + "dev": true, + "requires": { + "prr": "0.0.0" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es5-ext": { + "version": "0.10.30", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz", + "integrity": "sha1-cUGhaDZpfbq/qq7uQUlc4p9SyTk=", + "dev": true, + "requires": { + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } + }, + "es6-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30", + "es6-symbol": "3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30", + "es6-iterator": "2.0.1", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30" + } + }, + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "eventsource": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", + "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", + "dev": true, + "requires": { + "original": "1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "1.3.4", + "safe-buffer": "5.1.1" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-braces": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", + "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "dev": true, + "requires": { + "array-slice": "0.2.3", + "array-unique": "0.2.1", + "braces": "0.1.5" + }, + "dependencies": { + "braces": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", + "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "dev": true, + "requires": { + "expand-range": "0.1.1" + } + }, + "expand-range": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "dev": true, + "requires": { + "is-number": "0.1.1", + "repeat-string": "0.2.2" + } + }, + "is-number": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", + "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", + "dev": true + }, + "repeat-string": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", + "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", + "dev": true + } + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "exports-loader": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.6.4.tgz", + "integrity": "sha1-1w/GEhl1s1/BKDDPUnVL4nQPyIY=", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "source-map": "0.5.7" + } + }, + "express": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.0.tgz", + "integrity": "sha1-tRljjk61jnF4yBtJjvIveYyy4lU=", + "dev": true, + "requires": { + "accepts": "1.3.4", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.1", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.2", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.0", + "serve-static": "1.13.0", + "setprototypeof": "1.1.0", + "statuses": "1.3.1", + "type-is": "1.6.15", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + } + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "external-editor": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.5.tgz", + "integrity": "sha512-Msjo64WT5W+NhOpQXh0nOHm+n0RfU1QUwDnKYvJ8dEJ8zlwLrqXNTv5mSUTJpepf41PDJGyhueTw2vNZW+Fr/w==", + "dev": true, + "requires": { + "iconv-lite": "0.4.19", + "jschardet": "1.5.1", + "tmp": "0.0.33" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extract-text-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.0.tgz", + "integrity": "sha1-kMqnkHvESfM1AF46x1MrQbAN5hI=", + "dev": true, + "requires": { + "async": "2.5.0", + "loader-utils": "1.1.0", + "schema-utils": "0.3.0", + "webpack-sources": "1.0.1" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "dev": true + }, + "fastparse": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", + "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": "0.7.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-0.10.1.tgz", + "integrity": "sha1-gVA0EZiR/GRB+1pkwRvJPCLd2EI=", + "dev": true, + "requires": { + "loader-utils": "1.1.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "7.1.2", + "minimatch": "3.0.4" + } + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "1.0.0" + } + }, + "fs-extra": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", + "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.7.0", + "node-pre-gyp": "0.6.36" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.36", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "gaze": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "dev": true, + "optional": true, + "requires": { + "globule": "1.2.0" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "globule": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", + "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", + "dev": true, + "optional": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.4", + "minimatch": "3.0.4" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "handle-thing": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", + "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", + "dev": true + }, + "handlebars": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-1.3.0.tgz", + "integrity": "sha1-npsTCpPjiUkTItl1zz7BgYw3zjQ=", + "dev": true, + "requires": { + "optimist": "0.3.7", + "uglify-js": "2.3.6" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true, + "optional": true + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "uglify-js": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz", + "integrity": "sha1-+gmEdwtCi3qbKoBY9GNV0U/vIRo=", + "dev": true, + "optional": true, + "requires": { + "async": "0.2.10", + "optimist": "0.3.7", + "source-map": "0.1.43" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.2.3", + "har-schema": "2.0.0" + } + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-binary": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "hash-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.0.2" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "heimdalljs": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.5.tgz", + "integrity": "sha1-aqVDCO7nk7ZCz/nPlHgURfN3MKw=", + "dev": true, + "requires": { + "rsvp": "3.2.1" + }, + "dependencies": { + "rsvp": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz", + "integrity": "sha1-B8tKXfJa3Z6Cbrxn3Mn9idsn2Eo=", + "dev": true + } + } + }, + "heimdalljs-logger": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz", + "integrity": "sha1-12raTkW3u294b8nAEKaOsuL68XY=", + "dev": true, + "requires": { + "debug": "2.6.9", + "heimdalljs": "0.2.5" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "1.0.0" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "obuf": "1.1.1", + "readable-stream": "2.3.3", + "wbuf": "1.7.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "html-comment-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", + "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", + "dev": true + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "html-minifier": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.5.tgz", + "integrity": "sha512-g+1+NBycQI0fGnggd52JM8TRUweG7+9W2wrtjGitMAqc4G7maweAHvVAAjz9veHseIH3tYKE2lk2USGSoewIrQ==", + "dev": true, + "requires": { + "camel-case": "3.0.0", + "clean-css": "4.1.9", + "commander": "2.11.0", + "he": "1.1.1", + "ncname": "1.0.0", + "param-case": "2.1.1", + "relateurl": "0.2.7", + "uglify-js": "3.1.2" + } + }, + "html-webpack-plugin": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz", + "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=", + "dev": true, + "requires": { + "bluebird": "3.5.0", + "html-minifier": "3.5.5", + "loader-utils": "0.2.17", + "lodash": "4.17.4", + "pretty-error": "2.1.1", + "toposort": "1.0.4" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, + "htmlparser2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", + "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.1.0", + "domutils": "1.1.6", + "readable-stream": "1.0.34" + }, + "dependencies": { + "domutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", + "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "dev": true, + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + }, + "dependencies": { + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.8.tgz", + "integrity": "sha512-jmHp99g6/fLx0pRNJqzsQgjsclCHAY7NhIeA3/U+bsGNvgbvUCQFQY9m5AYpqpAxY/2VcikfbKpjQozSTiz0jA==", + "dev": true + }, + "http-proxy": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", + "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", + "dev": true, + "requires": { + "eventemitter3": "1.2.0", + "requires-port": "1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", + "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", + "dev": true, + "requires": { + "http-proxy": "1.16.2", + "is-glob": "3.1.0", + "lodash": "4.17.4", + "micromatch": "2.3.11" + }, + "dependencies": { + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "2.1.1" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", + "dev": true + }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.9", + "extend": "3.0.1" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", + "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", + "dev": true, + "requires": { + "postcss": "6.0.12" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.12.tgz", + "integrity": "sha512-K6SLofXEK43FBSyZ6/ExQV7ji24OEw4tEY6x1CAf7+tcoMWJoO24Rf3rVFVpk+5IQL1e1Cy3sTKfg7hXuLzafg==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.5.7", + "supports-color": "4.4.0" + } + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", + "dev": true + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, + "img-stats": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/img-stats/-/img-stats-0.5.2.tgz", + "integrity": "sha1-wgNJbELy2esuWrgjL6dWurMsnis=", + "dev": true, + "requires": { + "xmldom": "0.1.27" + } + }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "dev": true, + "optional": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.1.0", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.0.5", + "figures": "2.0.0", + "lodash": "4.17.4", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "internal-ip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", + "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", + "dev": true, + "requires": { + "meow": "3.7.0" + } + }, + "interpret": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", + "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=", + "dev": true + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "1.10.0" + } + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-svg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", + "dev": true, + "requires": { + "html-comment-regex": "1.1.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isbinaryfile": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", + "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-api": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.1.14.tgz", + "integrity": "sha1-JbxXAffGgMD//5E95G42GaOm5oA=", + "dev": true, + "requires": { + "async": "2.5.0", + "fileset": "2.0.3", + "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-hook": "1.0.7", + "istanbul-lib-instrument": "1.8.0", + "istanbul-lib-report": "1.1.1", + "istanbul-lib-source-maps": "1.2.1", + "istanbul-reports": "1.1.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "once": "1.4.0" + } + }, + "istanbul-instrumenter-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-2.0.0.tgz", + "integrity": "sha1-5UkpAKsLuoNe+oAkywC+mz7qJwA=", + "dev": true, + "requires": { + "convert-source-map": "1.5.0", + "istanbul-lib-instrument": "1.8.0", + "loader-utils": "0.2.17", + "object-assign": "4.1.1" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", + "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz", + "integrity": "sha512-3U2HB9y1ZV9UmFlE12Fx+nPtFqIymzrqCksrXujm3NVbAZIJg/RfYgO1XiIa0mbmxTjWpVEVlkIZJ25xVIAfkQ==", + "dev": true, + "requires": { + "append-transform": "0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.8.0.tgz", + "integrity": "sha1-ZvbJQhzJ7EcE928tsIS6kHiitTI=", + "dev": true, + "requires": { + "babel-generator": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.1.1", + "semver": "5.4.1" + } + }, + "istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-tvF+YmCmH4thnez6JFX06ujIA19WPa9YUiwjc1uALF2cv5dmE3It8b5I8Ob7FHJ70H9Y5yF+TDkVa/mcADuw1Q==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "1.1.1", + "mkdirp": "0.5.1", + "path-parse": "1.0.5", + "supports-color": "3.2.3" + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz", + "integrity": "sha512-mukVvSXCn9JQvdJl8wP/iPhqig0MRtuWuD4ZNKo6vB2Ik//AmhAKe3QnPN02dmkRe3lTudFk3rzoHhwU4hb94w==", + "dev": true, + "requires": { + "debug": "2.6.9", + "istanbul-lib-coverage": "1.1.1", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "source-map": "0.5.7" + } + }, + "istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha1-D7Lj9qqZIr085F0F2KtNXo4HvU8=", + "dev": true, + "requires": { + "handlebars": "4.0.10" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + } + } + }, + "handlebars": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", + "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "7.1.2", + "jasmine-core": "2.8.0" + }, + "dependencies": { + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.6.4.tgz", + "integrity": "sha1-3skmzQqfoof7bbXHVfpIfnTOysU=", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.1.1.tgz", + "integrity": "sha1-Wm1Yq11hvqcwn7wnkjlRF1axtYg=", + "dev": true, + "requires": { + "colors": "1.1.2" + } + }, + "jasminewd2": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.1.0.tgz", + "integrity": "sha1-2llSddGuYx3nNqwKfH2Fyfc+9lI=", + "dev": true + }, + "js-base64": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz", + "integrity": "sha512-Y2/+DnfJJXT1/FCwUebUhLWb3QihxiSC42+ctHLGogmW2jPY6LCapMdFZXRvVP2z6qyKW7s6qncE/9gSqZiArw==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "2.7.3" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jschardet": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz", + "integrity": "sha512-vE2hT1D0HLZCLLclfBSfkfTTedhVj0fubHpJBHKwwUWX0nSbhPAfk+SG9rTX95BYNmau8rGFfCeaT6T5OW1C2A==", + "dev": true + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "json-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "karma": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz", + "integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==", + "dev": true, + "requires": { + "bluebird": "3.5.0", + "body-parser": "1.18.2", + "chokidar": "1.7.0", + "colors": "1.1.2", + "combine-lists": "1.0.1", + "connect": "3.6.5", + "core-js": "2.5.1", + "di": "0.0.1", + "dom-serialize": "2.2.1", + "expand-braces": "0.1.2", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "http-proxy": "1.16.2", + "isbinaryfile": "3.0.2", + "lodash": "3.10.1", + "log4js": "0.6.38", + "mime": "1.4.1", + "minimatch": "3.0.4", + "optimist": "0.6.1", + "qjobs": "1.1.5", + "range-parser": "1.2.0", + "rimraf": "2.6.2", + "safe-buffer": "5.1.1", + "socket.io": "1.7.3", + "source-map": "0.5.7", + "tmp": "0.0.31", + "useragent": "2.2.1" + }, + "dependencies": { + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, + "tmp": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + } + } + }, + "karma-chrome-launcher": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.1.1.tgz", + "integrity": "sha1-IWh5xorATY1RQOmWGboEtZr9Rs8=", + "dev": true, + "requires": { + "fs-access": "1.0.1", + "which": "1.3.0" + } + }, + "karma-cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/karma-cli/-/karma-cli-1.0.1.tgz", + "integrity": "sha1-rmw8WKMTodALRRZMRVubhs4X+WA=", + "dev": true, + "requires": { + "resolve": "1.4.0" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.3.0.tgz", + "integrity": "sha1-0ULNnFVzHJ42Pvc3To7xoxvr+ts=", + "dev": true, + "requires": { + "istanbul-api": "1.1.14", + "minimatch": "3.0.4" + } + }, + "karma-jasmine": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.0.tgz", + "integrity": "sha1-IuTAa/mhguUpTR9wXjczgRuBCs8=", + "dev": true + }, + "karma-jasmine-html-reporter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz", + "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", + "dev": true, + "requires": { + "karma-jasmine": "1.1.0" + } + }, + "karma-source-map-support": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.2.0.tgz", + "integrity": "sha1-G/gee7SwiWJ6s1LsQXnhF8QGpUA=", + "dev": true, + "requires": { + "source-map-support": "0.4.18" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + }, + "lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "less": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/less/-/less-2.7.2.tgz", + "integrity": "sha1-No1sxz4fsDmBGDKAkYdDxdz5s98=", + "dev": true, + "requires": { + "errno": "0.1.4", + "graceful-fs": "4.1.11", + "image-size": "0.5.5", + "mime": "1.4.1", + "mkdirp": "0.5.1", + "promise": "7.3.1", + "request": "2.83.0", + "source-map": "0.5.7" + } + }, + "less-loader": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.0.5.tgz", + "integrity": "sha1-rhVadAbKxqzSk9eFWH/P8PR4xN0=", + "dev": true, + "requires": { + "clone": "2.1.1", + "loader-utils": "1.1.0", + "pify": "2.3.0" + }, + "dependencies": { + "clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + } + } + }, + "license-webpack-plugin": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-0.5.1.tgz", + "integrity": "sha1-aNivEDSGqcTrzt237V071h84O+Q=", + "dev": true, + "requires": { + "object-assign": "4.1.1" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "loader-runner": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", + "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "dev": true + }, + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true, + "optional": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.mergewith": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz", + "integrity": "sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=", + "dev": true, + "optional": true + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log4js": { + "version": "0.6.38", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", + "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", + "dev": true, + "requires": { + "readable-stream": "1.0.34", + "semver": "4.3.6" + }, + "dependencies": { + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "dev": true + } + } + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "macaddress": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", + "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=", + "dev": true + }, + "magic-string": { + "version": "0.22.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.4.tgz", + "integrity": "sha512-kxBL06p6iO2qPBHsqGK2b3cRwiRGpnmSuVWNhwHcMX7qJOUr1HvricYP1LZOCdkQBUp0jiWg2d6WJwR3vYgByw==", + "dev": true, + "requires": { + "vlq": "0.2.2" + } + }, + "make-error": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz", + "integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y=", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "matcher-collection": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.5.tgz", + "integrity": "sha512-nUCmzKipcJEwYsBVAFh5P+d7JBuhJaW1xs85Hara9xuMLqtCVUrW6DSC0JVIkluxEH2W45nPBM/wjHtBXa/tYA==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "math-expression-evaluator": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", + "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", + "dev": true + }, + "md5.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "dev": true, + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3" + }, + "dependencies": { + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "0.1.4", + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "0.1.8", + "is-extendable": "0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multicast-dns": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.1.1.tgz", + "integrity": "sha1-bn3oalcIcqsXBYrepxYLvsqBTd4=", + "dev": true, + "requires": { + "dns-packet": "1.2.2", + "thunky": "0.1.0" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", + "dev": true, + "optional": true + }, + "ncname": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz", + "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=", + "dev": true, + "requires": { + "xml-char-classes": "1.0.0" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "1.1.4" + } + }, + "node-forge": { + "version": "0.6.33", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.33.tgz", + "integrity": "sha1-RjgRh59XPUUVWtap9D3ClujoXrw=", + "dev": true + }, + "node-gyp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", + "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.1.2", + "osenv": "0.1.4", + "request": "2.83.0", + "rimraf": "2.6.2", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.3.0" + }, + "dependencies": { + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.1" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true, + "optional": true + } + } + }, + "node-libs-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz", + "integrity": "sha1-o6WeyXAkmFtG6Vg3lkb5bEthZkY=", + "dev": true, + "requires": { + "assert": "1.4.1", + "browserify-zlib": "0.1.4", + "buffer": "4.9.1", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.11.1", + "domain-browser": "1.1.7", + "events": "1.1.1", + "https-browserify": "0.0.1", + "os-browserify": "0.2.1", + "path-browserify": "0.0.0", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.3", + "stream-browserify": "2.0.1", + "stream-http": "2.7.2", + "string_decoder": "0.10.31", + "timers-browserify": "2.0.4", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.10.3", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + } + } + }, + "node-modules-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz", + "integrity": "sha1-QAlrCM560OoUaAhjr0ScfHWl0cg=", + "dev": true + }, + "node-sass": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.5.3.tgz", + "integrity": "sha1-0JydEXlkEjnRuX/8YjH9zsU+FWg=", + "dev": true, + "optional": true, + "requires": { + "async-foreach": "0.1.3", + "chalk": "1.1.3", + "cross-spawn": "3.0.1", + "gaze": "1.1.2", + "get-stdin": "4.0.1", + "glob": "7.1.2", + "in-publish": "2.0.0", + "lodash.assign": "4.2.0", + "lodash.clonedeep": "4.5.0", + "lodash.mergewith": "4.6.0", + "meow": "3.7.0", + "mkdirp": "0.5.1", + "nan": "2.7.0", + "node-gyp": "3.6.2", + "npmlog": "4.1.2", + "request": "2.83.0", + "sass-graph": "2.2.4", + "stdout-stream": "1.4.0" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + } + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "requires": { + "abbrev": "1.1.1", + "osenv": "0.1.4" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "prepend-http": "1.0.4", + "query-string": "4.3.4", + "sort-keys": "1.1.2" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "1.0.0" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + }, + "dependencies": { + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + } + } + }, + "obuf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.1.tgz", + "integrity": "sha1-EEEktsYCxnlogaBCVB0220OlJk4=", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "opn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", + "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", + "dev": true, + "requires": { + "is-wsl": "1.1.0" + } + }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "dev": true, + "requires": { + "wordwrap": "0.0.3" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "dev": true + }, + "original": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", + "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=", + "dev": true, + "requires": { + "url-parse": "1.0.5" + }, + "dependencies": { + "url-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz", + "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=", + "dev": true, + "requires": { + "querystringify": "0.0.4", + "requires-port": "1.0.0" + } + } + } + }, + "os-browserify": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz", + "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.1.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "2.3.2" + } + }, + "parse-asn1": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", + "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", + "dev": true, + "requires": { + "asn1.js": "4.9.1", + "browserify-aes": "1.0.8", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.14" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parsejson": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", + "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pbkdf2": { + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", + "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "dev": true, + "requires": { + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.9" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "portfinder": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz", + "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", + "dev": true, + "requires": { + "async": "1.5.2", + "debug": "2.6.9", + "mkdirp": "0.5.1" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, + "postcss": { + "version": "5.2.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.17.tgz", + "integrity": "sha1-z09Ze4ZNZcikkrLqvp1wbIecOIs=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "js-base64": "2.3.2", + "source-map": "0.5.7", + "supports-color": "3.2.3" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + } + } + }, + "postcss-calc": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", + "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-message-helpers": "2.0.0", + "reduce-css-calc": "1.3.0" + } + }, + "postcss-colormin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", + "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", + "dev": true, + "requires": { + "colormin": "1.1.2", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-convert-values": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", + "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-discard-comments": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", + "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-discard-duplicates": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", + "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-discard-empty": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", + "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-discard-overridden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", + "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-discard-unused": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", + "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "uniqs": "2.0.0" + } + }, + "postcss-filter-plugins": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", + "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "uniqid": "4.1.1" + } + }, + "postcss-load-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", + "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1", + "postcss-load-options": "1.2.0", + "postcss-load-plugins": "2.3.0" + } + }, + "postcss-load-options": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", + "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1" + } + }, + "postcss-load-plugins": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", + "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1" + } + }, + "postcss-loader": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-1.3.3.tgz", + "integrity": "sha1-piHqH6KQYqg5cqRvVEhncTAZFus=", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-load-config": "1.2.0" + } + }, + "postcss-merge-idents": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", + "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-merge-longhand": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", + "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-merge-rules": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", + "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-api": "1.6.1", + "postcss": "5.2.17", + "postcss-selector-parser": "2.2.3", + "vendors": "1.0.1" + } + }, + "postcss-message-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", + "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=", + "dev": true + }, + "postcss-minify-font-values": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", + "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-minify-gradients": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", + "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-minify-params": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", + "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0", + "uniqs": "2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", + "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "has": "1.0.1", + "postcss": "5.2.17", + "postcss-selector-parser": "2.2.3" + } + }, + "postcss-modules-extract-imports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz", + "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", + "dev": true, + "requires": { + "postcss": "6.0.12" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.12.tgz", + "integrity": "sha512-K6SLofXEK43FBSyZ6/ExQV7ji24OEw4tEY6x1CAf7+tcoMWJoO24Rf3rVFVpk+5IQL1e1Cy3sTKfg7hXuLzafg==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.5.7", + "supports-color": "4.4.0" + } + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-modules-local-by-default": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", + "dev": true, + "requires": { + "css-selector-tokenizer": "0.7.0", + "postcss": "6.0.12" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.12.tgz", + "integrity": "sha512-K6SLofXEK43FBSyZ6/ExQV7ji24OEw4tEY6x1CAf7+tcoMWJoO24Rf3rVFVpk+5IQL1e1Cy3sTKfg7hXuLzafg==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.5.7", + "supports-color": "4.4.0" + } + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-modules-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", + "dev": true, + "requires": { + "css-selector-tokenizer": "0.7.0", + "postcss": "6.0.12" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.12.tgz", + "integrity": "sha512-K6SLofXEK43FBSyZ6/ExQV7ji24OEw4tEY6x1CAf7+tcoMWJoO24Rf3rVFVpk+5IQL1e1Cy3sTKfg7hXuLzafg==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.5.7", + "supports-color": "4.4.0" + } + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-modules-values": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", + "dev": true, + "requires": { + "icss-replace-symbols": "1.1.0", + "postcss": "6.0.12" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.12.tgz", + "integrity": "sha512-K6SLofXEK43FBSyZ6/ExQV7ji24OEw4tEY6x1CAf7+tcoMWJoO24Rf3rVFVpk+5IQL1e1Cy3sTKfg7hXuLzafg==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.5.7", + "supports-color": "4.4.0" + } + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-normalize-charset": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", + "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-normalize-url": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", + "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", + "dev": true, + "requires": { + "is-absolute-url": "2.1.0", + "normalize-url": "1.9.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-ordered-values": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", + "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-reduce-idents": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", + "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-reduce-initial": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", + "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-reduce-transforms": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", + "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", + "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", + "dev": true, + "requires": { + "flatten": "1.0.2", + "indexes-of": "1.0.1", + "uniq": "1.0.1" + } + }, + "postcss-svgo": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", + "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", + "dev": true, + "requires": { + "is-svg": "2.1.0", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0", + "svgo": "0.7.2" + } + }, + "postcss-unique-selectors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", + "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "postcss": "5.2.17", + "uniqs": "2.0.0" + } + }, + "postcss-url": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-5.1.2.tgz", + "integrity": "sha1-mLMWW+jVkkccsMqt3iwNH4MvEz4=", + "dev": true, + "requires": { + "directory-encoder": "0.7.2", + "js-base64": "2.3.2", + "mime": "1.4.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "path-is-absolute": "1.0.1", + "postcss": "5.2.17" + } + }, + "postcss-value-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", + "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", + "dev": true + }, + "postcss-zindex": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", + "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.17", + "uniqs": "2.0.0" + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "2.0.1", + "utila": "0.4.0" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "optional": true, + "requires": { + "asap": "2.0.6" + } + }, + "protractor": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.1.2.tgz", + "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", + "dev": true, + "requires": { + "@types/node": "6.0.88", + "@types/q": "0.0.32", + "@types/selenium-webdriver": "2.53.42", + "blocking-proxy": "0.0.5", + "chalk": "1.1.3", + "glob": "7.1.2", + "jasmine": "2.8.0", + "jasminewd2": "2.1.0", + "optimist": "0.6.1", + "q": "1.4.1", + "saucelabs": "1.3.0", + "selenium-webdriver": "3.0.1", + "source-map-support": "0.4.18", + "webdriver-js-extender": "1.0.0", + "webdriver-manager": "12.0.6" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "webdriver-manager": { + "version": "12.0.6", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz", + "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", + "dev": true, + "requires": { + "adm-zip": "0.4.7", + "chalk": "1.1.3", + "del": "2.2.2", + "glob": "7.1.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "q": "1.4.1", + "request": "2.83.0", + "rimraf": "2.6.2", + "semver": "5.4.1", + "xml2js": "0.4.19" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + } + } + }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "dev": true, + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } + }, + "prr": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", + "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "parse-asn1": "5.1.0", + "randombytes": "2.0.5" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", + "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=", + "dev": true + }, + "qjobs": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz", + "integrity": "sha1-ZZ3p8s+NzCehSBJ28gU3cnI4LnM=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "strict-uri-encode": "1.1.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz", + "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "randombytes": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", + "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, + "raw-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.3", + "set-immediate-shim": "1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "math-expression-evaluator": "1.2.17", + "reduce-function-call": "1.0.2" + } + }, + "reduce-function-call": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", + "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "dev": true, + "requires": { + "balanced-match": "0.4.2" + } + }, + "reflect-metadata": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.10.tgz", + "integrity": "sha1-tPg3BEFqytiZiMmxVjXUfgO5NEo=", + "dev": true + }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", + "dev": true + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "1.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz", + "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-converter": "0.1.4", + "htmlparser2": "3.3.0", + "strip-ansi": "3.0.1", + "utila": "0.3.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", + "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "dev": true, + "requires": { + "hash-base": "2.0.2", + "inherits": "2.0.3" + } + }, + "rsvp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", + "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", + "dev": true + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "rxjs": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz", + "integrity": "sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==", + "requires": { + "symbol-observable": "1.0.4" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "dev": true, + "optional": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.4", + "scss-tokenizer": "0.2.3", + "yargs": "7.1.0" + } + }, + "sass-loader": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-6.0.6.tgz", + "integrity": "sha512-c3/Zc+iW+qqDip6kXPYLEgsAu2lf4xz0EZDplB7EmSUMda12U1sGJPetH55B/j9eu0bTtKzKlNPWWyYC7wFNyQ==", + "dev": true, + "requires": { + "async": "2.5.0", + "clone-deep": "0.3.0", + "loader-utils": "1.1.0", + "lodash.tail": "4.1.1", + "pify": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "saucelabs": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", + "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", + "dev": true, + "requires": { + "https-proxy-agent": "1.0.0" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "5.2.3" + } + }, + "script-loader": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/script-loader/-/script-loader-0.7.1.tgz", + "integrity": "sha512-upPXlUIIRY1o1ba8w8nOLm3ZEndtpczyPmA3HJ4ZdktyMNct3wxj3VTl+0/PENtYSKJdzdVhWrLiHhBIEOiFqg==", + "dev": true, + "requires": { + "raw-loader": "0.5.1" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "optional": true, + "requires": { + "js-base64": "2.3.2", + "source-map": "0.4.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selenium-webdriver": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz", + "integrity": "sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=", + "dev": true, + "requires": { + "adm-zip": "0.4.7", + "rimraf": "2.6.2", + "tmp": "0.0.30", + "xml2js": "0.4.19" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + } + } + }, + "selfsigned": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.1.tgz", + "integrity": "sha1-v4y3uDJWxFUeMTR8YxF3jbme7FI=", + "dev": true, + "requires": { + "node-forge": "0.6.33" + } + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "5.4.1" + } + }, + "send": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.0.tgz", + "integrity": "sha1-FjONu5ou3krVe0hCDsO4LY6ApXs=", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "1.1.1", + "destroy": "1.0.4", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "1.0.3", + "http-errors": "1.6.2", + "mime-types": "2.1.17", + "parseurl": "1.3.2" + } + }, + "serve-static": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.0.tgz", + "integrity": "sha1-gQyR24AOlLoofq5rTgbKq5/cFvE=", + "dev": true, + "requires": { + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz", + "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "dev": true, + "requires": { + "is-extendable": "0.1.1", + "kind-of": "2.0.1", + "lazy-cache": "0.2.7", + "mixin-object": "2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "silent-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz", + "integrity": "sha1-IglwbxyFCp8dENDYQJGLRvJuG8k=", + "dev": true, + "requires": { + "debug": "2.6.9" + } + }, + "sntp": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", + "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + }, + "socket.io": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.3.tgz", + "integrity": "sha1-uK+cq6AJSeVo42nxMn6pvp6iRhs=", + "dev": true, + "requires": { + "debug": "2.3.3", + "engine.io": "1.8.3", + "has-binary": "0.1.7", + "object-assign": "4.1.0", + "socket.io-adapter": "0.5.0", + "socket.io-client": "1.7.3", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "object-assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", + "dev": true + } + } + }, + "socket.io-adapter": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", + "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", + "dev": true, + "requires": { + "debug": "2.3.3", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "socket.io-client": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.3.tgz", + "integrity": "sha1-sw6GqhDV7zVGYBwJzeR2Xjgdo3c=", + "dev": true, + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "2.3.3", + "engine.io-client": "1.8.3", + "has-binary": "0.1.7", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseuri": "0.0.5", + "socket.io-parser": "2.3.1", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", + "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", + "dev": true, + "requires": { + "component-emitter": "1.1.2", + "debug": "2.2.0", + "isarray": "0.0.1", + "json3": "3.3.2" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.18.tgz", + "integrity": "sha1-2bKJMWyn33dZXvKZ4HXw+TfrQgc=", + "dev": true, + "requires": { + "faye-websocket": "0.10.0", + "uuid": "2.0.3" + }, + "dependencies": { + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + } + } + }, + "sockjs-client": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.2.tgz", + "integrity": "sha1-8CEqhVDkyUaMjM6u79LjSTwDOtU=", + "dev": true, + "requires": { + "debug": "2.6.9", + "eventsource": "0.1.6", + "faye-websocket": "0.11.1", + "inherits": "2.0.3", + "json3": "3.3.2", + "url-parse": "1.1.9" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "dev": true, + "requires": { + "websocket-driver": "0.7.0" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "1.1.0" + } + }, + "source-list-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", + "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-loader": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.1.tgz", + "integrity": "sha1-SBJr6SML1H+tBeRqjDwuPS2r5Qc=", + "dev": true, + "requires": { + "async": "0.9.2", + "loader-utils": "0.2.17", + "source-map": "0.1.43" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "spdy": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", + "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", + "dev": true, + "requires": { + "debug": "2.6.9", + "handle-thing": "1.2.5", + "http-deceiver": "1.2.7", + "safe-buffer": "5.1.1", + "select-hose": "2.0.0", + "spdy-transport": "2.0.20" + } + }, + "spdy-transport": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.20.tgz", + "integrity": "sha1-c15yBUxIayNU/onnAiVgBKOazk0=", + "dev": true, + "requires": { + "debug": "2.6.9", + "detect-node": "2.0.3", + "hpack.js": "2.1.6", + "obuf": "1.1.1", + "readable-stream": "2.3.3", + "safe-buffer": "5.1.1", + "wbuf": "1.7.2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "stdout-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", + "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "dev": true, + "optional": true, + "requires": { + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "stream-http": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", + "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", + "dev": true, + "requires": { + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "style-loader": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.13.2.tgz", + "integrity": "sha1-dFMzhM9pjHEEx5URULSXF63C87s=", + "dev": true, + "requires": { + "loader-utils": "1.1.0" + } + }, + "stylus": { + "version": "0.54.5", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", + "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", + "dev": true, + "requires": { + "css-parse": "1.7.0", + "debug": "2.6.9", + "glob": "7.0.6", + "mkdirp": "0.5.1", + "sax": "0.5.8", + "source-map": "0.1.43" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", + "dev": true + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "stylus-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.1.tgz", + "integrity": "sha1-d/SzT9Aw0lsmF7z1UT21sHMMQIk=", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "lodash.clonedeep": "4.5.0", + "when": "3.6.4" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "dev": true, + "requires": { + "coa": "1.0.4", + "colors": "1.1.2", + "csso": "2.3.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "sax": "1.2.4", + "whet.extend": "0.9.9" + } + }, + "symbol-observable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", + "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=" + }, + "tapable": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", + "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "optional": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "temp": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", + "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2", + "rimraf": "2.2.8" + }, + "dependencies": { + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "thunky": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz", + "integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=", + "dev": true + }, + "time-stamp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz", + "integrity": "sha1-lcakRTDhW6jW9KPsuMOj+sRto1c=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz", + "integrity": "sha512-uZYhyU3EX8O7HQP+J9fTVYwsq90Vr68xPEFo7yrVImIxYvHgukBEgOB/SgGoorWVTzGM/3Z+wUNnboA4M8jWrg==", + "dev": true, + "requires": { + "setimmediate": "1.0.5" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "toposort": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.4.tgz", + "integrity": "sha1-qGEHaQy+6MrkOzSdL2AWJQCSTfw=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "ts-node": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.2.2.tgz", + "integrity": "sha1-u9KOOK9Kqj6WB2xGbhsiAZfBo84=", + "dev": true, + "requires": { + "arrify": "1.0.1", + "chalk": "2.1.0", + "diff": "3.3.1", + "make-error": "1.3.0", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18", + "tsconfig": "6.0.0", + "v8flags": "3.0.1", + "yn": "2.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "tsconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz", + "integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=", + "dev": true, + "requires": { + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "tsickle": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.21.6.tgz", + "integrity": "sha1-U7Abl5xcE/2xOvs/uVgXflmRWI0=", + "dev": true, + "requires": { + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "source-map": "0.5.7", + "source-map-support": "0.4.18" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "tslib": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", + "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=" + }, + "tslint": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.3.2.tgz", + "integrity": "sha1-5WRZ+wlacwfxA7hAUhdPXju+9u0=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "colors": "1.1.2", + "diff": "3.3.1", + "glob": "7.1.2", + "optimist": "0.6.1", + "resolve": "1.4.0", + "semver": "5.4.1", + "tslib": "1.7.1", + "tsutils": "2.10.0" + }, + "dependencies": { + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + } + } + }, + "tsutils": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.10.0.tgz", + "integrity": "sha1-rpRRHfJlbrBuRCQFb7pcOIiHBAw=", + "dev": true, + "requires": { + "tslib": "1.7.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "typescript": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.3.4.tgz", + "integrity": "sha1-PTgyGCgjHkNPKHUUlZw3qCtin0I=", + "dev": true + }, + "uglify-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.2.tgz", + "integrity": "sha512-kKJ8zg7Ivw3DG9Ytgp4+iiSHq3HaHjEQMvyT2x2Bs8kSUwVemj6bPGFp6YWL81f5NAIOLVUKPxBSvqLRGXMpdw==", + "dev": true, + "requires": { + "commander": "2.11.0", + "source-map": "0.5.7" + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-js": "2.8.29", + "webpack-sources": "1.0.1" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqid": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", + "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", + "dev": true, + "requires": { + "macaddress": "0.2.8" + } + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-loader": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.5.9.tgz", + "integrity": "sha512-B7QYFyvv+fOBqBVeefsxv6koWWtjmHaMFT6KZWti4KRw8YUD/hOU+3AECvXuzyVawIBx3z7zQRejXCDSO5kk1Q==", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "mime": "1.3.6" + }, + "dependencies": { + "mime": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", + "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=", + "dev": true + } + } + }, + "url-parse": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.9.tgz", + "integrity": "sha1-xn8dd11R8KGJEd17P/rSe7nlvRk=", + "dev": true, + "requires": { + "querystringify": "1.0.0", + "requires-port": "1.0.0" + }, + "dependencies": { + "querystringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz", + "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs=", + "dev": true + } + } + }, + "useragent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", + "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", + "dev": true, + "requires": { + "lru-cache": "2.2.4", + "tmp": "0.0.33" + }, + "dependencies": { + "lru-cache": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", + "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", + "dev": true + } + } + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "v8flags": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.1.tgz", + "integrity": "sha1-3Oj8N5wX2fLJ6e142JzgAFKxt2s=", + "dev": true, + "requires": { + "homedir-polyfill": "1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", + "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "vlq": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.2.tgz", + "integrity": "sha1-4xbVJXtAuGu0PLjV/qXX9U1rDKE=", + "dev": true + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "walk-sync": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz", + "integrity": "sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ==", + "dev": true, + "requires": { + "ensure-posix-path": "1.0.2", + "matcher-collection": "1.0.5" + } + }, + "watchpack": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz", + "integrity": "sha1-ShRyvLuVK9Cpu0A2gB+VTfs5+qw=", + "dev": true, + "requires": { + "async": "2.5.0", + "chokidar": "1.7.0", + "graceful-fs": "4.1.11" + } + }, + "wbuf": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.2.tgz", + "integrity": "sha1-1pe5nx9ZUS3ydRvkJ2nBWAtYAf4=", + "dev": true, + "requires": { + "minimalistic-assert": "1.0.0" + } + }, + "webdriver-js-extender": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", + "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", + "dev": true, + "requires": { + "@types/selenium-webdriver": "2.53.42", + "selenium-webdriver": "2.53.3" + }, + "dependencies": { + "adm-zip": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", + "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", + "dev": true + }, + "sax": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", + "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=", + "dev": true + }, + "selenium-webdriver": { + "version": "2.53.3", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz", + "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=", + "dev": true, + "requires": { + "adm-zip": "0.4.4", + "rimraf": "2.6.2", + "tmp": "0.0.24", + "ws": "1.1.2", + "xml2js": "0.4.4" + } + }, + "tmp": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", + "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=", + "dev": true + }, + "xml2js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", + "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", + "dev": true, + "requires": { + "sax": "0.6.1", + "xmlbuilder": "9.0.4" + } + } + } + }, + "webpack": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.4.1.tgz", + "integrity": "sha1-TD9PP7MYFVpNsMtqNv8FxWl0GPQ=", + "dev": true, + "requires": { + "acorn": "5.1.2", + "acorn-dynamic-import": "2.0.2", + "ajv": "5.2.3", + "ajv-keywords": "2.1.0", + "async": "2.5.0", + "enhanced-resolve": "3.4.1", + "escope": "3.6.0", + "interpret": "1.0.4", + "json-loader": "0.5.7", + "json5": "0.5.1", + "loader-runner": "2.3.0", + "loader-utils": "1.1.0", + "memory-fs": "0.4.1", + "mkdirp": "0.5.1", + "node-libs-browser": "2.0.0", + "source-map": "0.5.7", + "supports-color": "4.4.0", + "tapable": "0.2.8", + "uglifyjs-webpack-plugin": "0.4.6", + "watchpack": "1.4.0", + "webpack-sources": "1.0.1", + "yargs": "8.0.2" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, + "webpack-dev-middleware": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz", + "integrity": "sha1-007++y7dp+HTtdvgcolRMhllFwk=", + "dev": true, + "requires": { + "memory-fs": "0.4.1", + "mime": "1.4.1", + "path-is-absolute": "1.0.1", + "range-parser": "1.2.0", + "time-stamp": "2.0.0" + } + }, + "webpack-dev-server": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.5.1.tgz", + "integrity": "sha1-oC5yaoe7YD211xq7fW0mSb8Qx2k=", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "3.5.0", + "chokidar": "1.7.0", + "compression": "1.7.1", + "connect-history-api-fallback": "1.3.0", + "del": "3.0.0", + "express": "4.16.0", + "html-entities": "1.2.1", + "http-proxy-middleware": "0.17.4", + "internal-ip": "1.2.0", + "opn": "4.0.2", + "portfinder": "1.0.13", + "selfsigned": "1.10.1", + "serve-index": "1.9.1", + "sockjs": "0.3.18", + "sockjs-client": "1.1.2", + "spdy": "3.4.7", + "strip-ansi": "3.0.1", + "supports-color": "3.2.3", + "webpack-dev-middleware": "1.12.0", + "yargs": "6.6.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "pinkie-promise": "2.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "4.2.1" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "3.0.0" + } + } + } + }, + "webpack-merge": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.0.tgz", + "integrity": "sha1-atciI7PguDflMeRZfBmfkJNhUR4=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "webpack-sources": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.0.1.tgz", + "integrity": "sha512-05tMxipUCwHqYaVS8xc7sYPTly8PzXayRCB4dTxLhWTqlKUiwH6ezmEe0OSreL1c30LAuA3Zqmc+uEBUGFJDjw==", + "dev": true, + "requires": { + "source-list-map": "2.0.0", + "source-map": "0.5.7" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": "0.4.8", + "websocket-extensions": "0.1.2" + } + }, + "websocket-extensions": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.2.tgz", + "integrity": "sha1-Dhh4HeYpoYMIzhSBZQ9n/6JpOl0=", + "dev": true + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", + "dev": true + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "dev": true, + "requires": { + "string-width": "1.0.2" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz", + "integrity": "sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8=", + "dev": true, + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + } + }, + "wtf-8": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", + "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=", + "dev": true + }, + "xml-char-classes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", + "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=", + "dev": true + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.4" + } + }, + "xmlbuilder": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", + "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=", + "dev": true + }, + "xmldom": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", + "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", + "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "optional": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "optional": true + } + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + }, + "zone.js": { + "version": "0.8.18", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.18.tgz", + "integrity": "sha512-knKOBQM0oea3/x9pdyDuDi7RhxDlJhOIkeixXSiTKWLgs4LpK37iBc+1HaHwzlciHUKT172CymJFKo8Xgh+44Q==" + } + } +} diff --git a/ngapp/package.json b/ngapp/package.json new file mode 100644 index 00000000..29d3bc4a --- /dev/null +++ b/ngapp/package.json @@ -0,0 +1,49 @@ +{ + "name": "beetle-studio", + "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": "^4.2.4", + "@angular/common": "^4.2.4", + "@angular/compiler": "^4.2.4", + "@angular/core": "^4.2.4", + "@angular/forms": "^4.2.4", + "@angular/http": "^4.2.4", + "@angular/platform-browser": "^4.2.4", + "@angular/platform-browser-dynamic": "^4.2.4", + "@angular/router": "^4.2.4", + "core-js": "^2.4.1", + "rxjs": "^5.4.2", + "zone.js": "^0.8.14" + }, + "devDependencies": { + "@angular/cli": "1.3.2", + "@angular/compiler-cli": "^4.2.4", + "@angular/language-service": "^4.2.4", + "@types/jasmine": "~2.5.53", + "@types/jasminewd2": "~2.0.2", + "@types/node": "~6.0.60", + "codelyzer": "~3.1.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.3.2", + "typescript": "~2.3.3" + } +} diff --git a/ngapp/protractor.conf.js b/ngapp/protractor.conf.js new file mode 100644 index 00000000..7ee3b5ee --- /dev/null +++ b/ngapp/protractor.conf.js @@ -0,0 +1,28 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './e2e/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: 'e2e/tsconfig.e2e.json' + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.css b/ngapp/src/app/activities/activities-cards/activities-cards.component.css new file mode 100644 index 00000000..f6b28f60 --- /dev/null +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.css @@ -0,0 +1,69 @@ +.container-cards-pf { + padding: 0; + margin-top: 0; +} + +.row-cards-pf { + padding: 0; +} + + +.activity-card-action-icon { + cursor: pointer; +} + +.activity-card-icon { + border: 2px solid #39a5dc; + border-radius: 50%; + padding: 5px; + margin-right: 10px; + width: 32px; +} + +.activity-card .activity-card-title { + font-size: 16px; + font-weight: bold; +} + +.activity-card { + -webkit-transition: background-color 300ms; + -moz-transition: background-color 300ms; + -ms-transition: background-color 300ms; + -o-transition: background-color 300ms; + transition: background-color 300ms; + height: 220px; +} +.activity-card:hover { + background-color: rgb(237, 237, 237); +} + +.activity-card.active { + background-color: rgb(221, 234, 255); +} + +.activity-description { + font-size: 13px; + overflow-y: auto; +} + +.activity-card .activity-tags { + margin-bottom: 8px; +} +.activity-card .activity-tags .activity-tags-label { + font-weight: bold; + margin-right: 5px; +} +.activity-card .activity-tags .activity-tag { + margin-right: 5px; + border: 1px solid #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + padding: 2px 4px; +} +.activity-card .activity-tags .activity-tag:hover { + cursor: pointer; + background-color: #0088ce; + border-color: #00659c; + color: white; +} diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.html b/ngapp/src/app/activities/activities-cards/activities-cards.component.html new file mode 100644 index 00000000..0fd12d02 --- /dev/null +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.html @@ -0,0 +1,34 @@ +
+
+ +
+
+
+ +

+ + {{ activity.getId() }} + + +

+
+
+ Source: + {{ activity.getSourceConnection() }}    +
+
+ Target: + {{ activity.getSourceConnection() }}    +
+ +
+
+
+
+
diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts new file mode 100644 index 00000000..972ebbd1 --- /dev/null +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ActivitiesCardsComponent } from './activities-cards.component'; + +describe('ActivitiesCardsComponent', () => { + let component: ActivitiesCardsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ActivitiesCardsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ActivitiesCardsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.ts new file mode 100644 index 00000000..48e97ee3 --- /dev/null +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.ts @@ -0,0 +1,78 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { EventEmitter } from '@angular/core'; +import { Input } from '@angular/core'; +import { Output } from '@angular/core'; + +import { Activity } from '@activities/shared/activity.model'; + +@Component({ + moduleId: module.id, + selector: 'app-activities-cards', + templateUrl: 'activities-cards.component.html', + styleUrls: ['activities-cards.component.css'] +}) +export class ActivitiesCardsComponent { + + @Input() activities: Activity[]; + @Input() selectedActivities: Activity[]; + @Output() onActivitySelected: EventEmitter = new EventEmitter(); + @Output() onActivityDeselected: EventEmitter = new EventEmitter(); + @Output() onTagSelected: EventEmitter = new EventEmitter(); + @Output() onStartActivity: EventEmitter = new EventEmitter(); + @Output() onEditActivity: EventEmitter = new EventEmitter(); + @Output() onDeleteActivity: EventEmitter = new EventEmitter(); + + /** + * Constructor. + */ + constructor() {} + + public toggleActivitySelected(activity: Activity): void { + if (this.isSelected(activity)) { + this.onActivityDeselected.emit(activity); + } else { + this.onActivitySelected.emit(activity); + } + } + + public isSelected(activity: Activity): boolean { + return this.selectedActivities.indexOf(activity) !== -1; + } + + public startActivity(activityName: string): void { + this.onStartActivity.emit(activityName); + } + + public editActivity(activityName: string): void { + this.onEditActivity.emit(activityName); + } + + public deleteActivity(activityName: string): void { + this.onDeleteActivity.emit(activityName); + } + + public selectTag(tag: string, event: MouseEvent): void { + event.stopPropagation(); + event.preventDefault(); + this.onTagSelected.emit(tag); + } + +} + diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.css b/ngapp/src/app/activities/activities-list/activities-list.component.css new file mode 100644 index 00000000..2ea63ec6 --- /dev/null +++ b/ngapp/src/app/activities/activities-list/activities-list.component.css @@ -0,0 +1,36 @@ + +.list-group-item { + -webkit-transition: background-color 300ms; + -moz-transition: background-color 300ms; + -ms-transition: background-color 300ms; + -o-transition: background-color 300ms; + transition: background-color 300ms; +} +.list-group-item, .list-group-item:first-child { + margin-bottom: 5px; + border-top: 1px solid rgb(57, 165, 220); +} +.list-group-item.active { + background-color: #def3ff; +} + +.list-group-item .activity-tags { +} +.list-group-item .activity-tags .activity-tags-label { + font-weight: bold; + margin-right: 5px; +} +.list-group-item .activity-tags .activity-tag { + margin-right: 5px; + border: 1px solid #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + padding: 2px 4px; +} +.list-group-item .activity-tags .activity-tag:hover { + cursor: pointer; + background-color: #0088ce; + border-color: #00659c; + color: white; +} diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.html b/ngapp/src/app/activities/activities-list/activities-list.component.html new file mode 100644 index 00000000..b037c7e6 --- /dev/null +++ b/ngapp/src/app/activities/activities-list/activities-list.component.html @@ -0,0 +1,40 @@ +
+
+
+
+ +
+
+ +
+
+ Source: + {{ activity.getSourceConnection() }}    +
+
+ Target: + {{ activity.getTargetConnection() }}    +
+ +
+
+
+ + + +
+
+
+
diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts new file mode 100644 index 00000000..f0221d7f --- /dev/null +++ b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ActivitiesListComponent } from './activities-list.component'; + +describe('ActivitiesListComponent', () => { + let component: ActivitiesListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ActivitiesListComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ActivitiesListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.ts b/ngapp/src/app/activities/activities-list/activities-list.component.ts new file mode 100644 index 00000000..d328d2d5 --- /dev/null +++ b/ngapp/src/app/activities/activities-list/activities-list.component.ts @@ -0,0 +1,77 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { EventEmitter } from '@angular/core'; +import { Input } from '@angular/core'; +import { Output } from '@angular/core'; + +import { Activity } from '@activities/shared/activity.model'; + +@Component({ + moduleId: module.id, + selector: 'app-activities-list', + templateUrl: 'activities-list.component.html', + styleUrls: ['activities-list.component.css'] +}) +export class ActivitiesListComponent { + + @Input() activities: Activity[]; + @Input() selectedActivities: Activity[]; + @Output() onActivitySelected: EventEmitter = new EventEmitter(); + @Output() onActivityDeselected: EventEmitter = new EventEmitter(); + @Output() onTagSelected: EventEmitter = new EventEmitter(); + @Output() onEditActivity: EventEmitter = new EventEmitter(); + @Output() onStartActivity: EventEmitter = new EventEmitter(); + @Output() onDeleteActivity: EventEmitter = new EventEmitter(); + + /** + * Constructor. + */ + constructor() {} + + public toggleActivitySelected(activity: Activity): void { + if (this.isSelected(activity)) { + this.onActivityDeselected.emit(activity); + } else { + this.onActivitySelected.emit(activity); + } + } + + public isSelected(activity: Activity): boolean { + return this.selectedActivities.indexOf(activity) !== -1; + } + + public startActivity(activityName: string): void { + this.onStartActivity.emit(activityName); + } + + public editActivity(activityName: string): void { + this.onEditActivity.emit(activityName); + } + + public deleteActivity(activityName: string): void { + this.onDeleteActivity.emit(activityName); + } + + public selectTag(tag: string, event: MouseEvent): void { + event.stopPropagation(); + event.preventDefault(); + this.onTagSelected.emit(tag); + } + +} diff --git a/ngapp/src/app/activities/activities.component.css b/ngapp/src/app/activities/activities.component.css new file mode 100644 index 00000000..fdcfb0e2 --- /dev/null +++ b/ngapp/src/app/activities/activities.component.css @@ -0,0 +1,57 @@ +.toolbar-pf { + margin-top: 5px; +} + +.toolbar-pf form { + margin-bottom: 0; +} + +.toolbar-pf-results { + margin-top: 0; +} + +.activity-list-items { + margin-top: 10px +} + +.activity-list-activities .toolbar-pf { + background-color: transparent; +} + +.activity-list-activities .toolbar-pf .toolbar-pf-results { + background-color: white; +} + +a.clear-filters { + cursor: pointer; +} + +.toolbar-pf-view-selector { + float: right; +} + +.toolbar-pf-view-selector li a { + cursor: pointer; + color: #333; +} + +.toolbar-pf-view-selector li a:hover { + color: #0088ce; +} + +.activity-list-items .empty-state { + text-align: center; +} + +.blank-slate-pf { + background-color: white; + width: 50%; + min-width: 500px; + margin-left: auto; + margin-right: auto; + margin-top: 15px; +} + +.activity-list-items .none-matched-state .alert { + background-color: white; +} diff --git a/ngapp/src/app/activities/activities.component.html b/ngapp/src/app/activities/activities.component.html new file mode 100644 index 00000000..24ae1492 --- /dev/null +++ b/ngapp/src/app/activities/activities.component.html @@ -0,0 +1,107 @@ +
+ +
+ +
  • +
    +
    + + + +
    +
    +

    Activities

    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
      +
    • +
    • +
    +
    +
    +
    +
    +
    {{ filteredActivities.length }} Activities found + (out + of {{ allActivities.length }} total)
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +

    No Activities Found

    +

    + No Activities were found - please click below to create a new Activity! +

    +
    + +
    +
    +
    +
    +
    + + No Activities matched the filter!  Please try changing your filter criteria... +
    +
    + + +
    +
    +
    +
    +
    +

    +

    Loading Activities...

    +

    +
    +
    +
    +
    +
    + + +
    + + +
    + +
    + +
    + +
    + +

    Do you really want to delete the selected Activity?

    +
    diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts new file mode 100644 index 00000000..29f86a9f --- /dev/null +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ActivitiesComponent } from './activities.component'; + +describe('ActivitiesComponent', () => { + let component: ActivitiesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ActivitiesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ActivitiesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts new file mode 100644 index 00000000..9e5c5827 --- /dev/null +++ b/ngapp/src/app/activities/activities.component.ts @@ -0,0 +1,190 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { ViewChild } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Router } from '@angular/router'; + +import { Activity } from '@activities/shared/activity.model'; +import { NewActivity } from '@activities/shared/new-activity.model'; +import { ActivityService } from '@activities/shared/activity.service'; +import { ArrayUtils } from '@core/common'; +import { AbstractPageComponent } from "@shared/abstract-page.component"; +import { ConfirmDeleteComponent } from '@shared/confirm-delete/confirm-delete.component'; + +class Filters { + nameFilter: string; + sortDirection: string; + layout: string; + + constructor(params?: any) { + this.reset(); + if (params) { + for (const key of Object.keys(params)) { + this[key] = params[ key ]; + } + } + } + + public accepts(activity: Activity): boolean { + const name: string = activity.getId().toLocaleLowerCase(); + const namef: string = this.nameFilter.toLocaleLowerCase(); + return name.indexOf(namef) >= 0; + } + + public reset(): void { + this.nameFilter = ''; + this.sortDirection = 'ASC'; + this.layout = 'card'; + } +} + +@Component({ + moduleId: module.id, + selector: 'app-activities', + templateUrl: './activities.component.html', + styleUrls: ['./activities.component.css'], + providers: [ ActivityService ] +}) +export class ActivitiesComponent extends AbstractPageComponent { + + allActivities: Activity[] = []; + filteredActivities: Activity[] = []; + selectedActivities: Activity[] = []; + filters: Filters = new Filters(); + private activityNameForDelete: string; + + @ViewChild(ConfirmDeleteComponent) confirmDeleteDialog: ConfirmDeleteComponent; + + constructor(private router: Router, route: ActivatedRoute, private activityService: ActivityService) { + super(route); + } + + public loadAsyncPageData() { + this.allActivities = this.activityService.getAllActivities(); + this.filteredActivities = this.filterActivities(); + this.loaded('activities'); + } + + /** + * Filters and sorts the list of activities based on the user input + */ + private filterActivities(): Activity[] { + // Clear the array first. + this.filteredActivities.splice(0, this.filteredActivities.length); + for (const activity of this.allActivities) { + if (this.filters.accepts(activity)) { + this.filteredActivities.push(activity); + } + } + this.filteredActivities.sort( (a1: Activity, a2: Activity) => { + let rval: number = a1.getId().localeCompare(a2.getId()); + if (this.filters.sortDirection === 'DESC') { + rval *= -1; + } + return rval; + }); + + this.selectedActivities = ArrayUtils.intersect(this.selectedActivities, this.filteredActivities); + + return this.filteredActivities; + } + + public onSelected(activity: Activity): void { + // Only allow one item to be selected + this.selectedActivities.shift(); + this.selectedActivities.push(activity); + } + + public onDeselected(activity: Activity): void { + // Only one item is selected at a time + this.selectedActivities.shift(); + // this.selectedConnections.splice(this.selectedConnections.indexOf(connection), 1); + } + + public onEdit(activityName: string): void { + const link: string[] = [ '/activities/edit-activity' ]; + this.router.navigate(link); + } + + public onDelete(activityName: string): void { + this.activityNameForDelete = activityName; + this.confirmDeleteDialog.open(); + } + + public onStart(activityName: string): void { + alert('Start activity ' + activityName); + } + + public isFiltered(): boolean { + return this.allActivities.length !== this.filteredActivities.length; + } + + public toggleSortDirection(): void { + if (this.filters.sortDirection === 'ASC') { + this.filters.sortDirection = 'DESC'; + } else { + this.filters.sortDirection = 'ASC'; + } + this.filterActivities(); + } + + public clearFilters(): void { + this.filters.nameFilter = ''; + this.filterActivities(); + } + + public onListLayout(): void { + this.filters.layout = 'list'; + } + + public onCardLayout(): void { + this.filters.layout = 'card'; + } + + /** + * Called to delete all selected APIs. + */ + public deleteActivity(): void { + const selectedActiv = this.filterActivities().find(x => x.getId() === this.activityNameForDelete); + + const activityToDelete: NewActivity = new NewActivity(); + activityToDelete.setName(selectedActiv.getId()); + + // Note: we can only delete selected items that we can see in the UI. + console.log('[ActivitiesPageComponent] Deleting selected Activity.'); + this.activityService.deleteActivity(activityToDelete); + /* + this.apiService + .deleteActivity(activityToDelete) + .subscribe( + () => { + this.removeActivityFromList(selectedActiv); + const link: string[] = [ '/activities' ]; + console.log('[CreateApiPageComponent] Navigating to: %o', link); + this.router.navigate(link); + } + ); + */ + } + + private removeActivityFromList(activity: Activity) { + this.allActivities.splice(this.allActivities.indexOf(activity), 1); + this.filterActivities(); + } +} diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts new file mode 100644 index 00000000..ce440250 --- /dev/null +++ b/ngapp/src/app/activities/activities.module.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { ActivitiesCardsComponent } from "@activities/activities-cards/activities-cards.component"; +import { ActivitiesComponent } from "@activities/activities.component"; +import { ActivitiesListComponent } from "@activities/activities-list/activities-list.component"; +import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; +import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; +import { ConnectionsModule } from "@connections/connections.module"; +import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { ActivityService } from "@activities/shared/activity.service"; + +@NgModule({ + imports: [ + CommonModule, + ConnectionsModule, + CoreModule, + SharedModule + ], + declarations: [ + ActivitiesCardsComponent, + ActivitiesComponent, + ActivitiesListComponent, + AddActivityComponent, + AddActivityFormComponent + ], + providers: [ + ActivityService + ]}) +export class ActivitiesModule { } diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.css b/ngapp/src/app/activities/add-activity/add-activity.component.css new file mode 100644 index 00000000..4508ce85 --- /dev/null +++ b/ngapp/src/app/activities/add-activity/add-activity.component.css @@ -0,0 +1,12 @@ +.add-activity-form { + padding: 15px +} + +.add-activity-form .form-instructions { + font-size: 15px; + padding-top: 10px +} + +.add-activity-form .form-instructions ol { + padding-left: 20px; +} diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.html b/ngapp/src/app/activities/add-activity/add-activity.component.html new file mode 100644 index 00000000..b5e62e7f --- /dev/null +++ b/ngapp/src/app/activities/add-activity/add-activity.component.html @@ -0,0 +1,16 @@ +
    +
    + +
  • +
  • +
    +
    +
    +
    +

    Add Activity

    +
    +
    + +
    +
    +
    diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts new file mode 100644 index 00000000..01d8081b --- /dev/null +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddActivityComponent } from './add-activity.component'; + +describe('AddActivityComponent', () => { + let component: AddActivityComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AddActivityComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddActivityComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.ts b/ngapp/src/app/activities/add-activity/add-activity.component.ts new file mode 100644 index 00000000..800d6275 --- /dev/null +++ b/ngapp/src/app/activities/add-activity/add-activity.component.ts @@ -0,0 +1,54 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { ViewChild } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Router } from '@angular/router'; + +import { ActivityService } from '@activities/shared/activity.service'; +import { AddActivityFormComponent } from '@activities/shared/add-activity-form/add-activity-form.component'; +import { NewActivity } from '@activities/shared/new-activity.model'; +import { AbstractPageComponent } from '@shared/abstract-page.component'; + +@Component({ + selector: 'app-add-activity', + templateUrl: './add-activity.component.html', + styleUrls: ['./add-activity.component.css'] +}) +export class AddActivityComponent extends AbstractPageComponent { + + @ViewChild(AddActivityFormComponent) form: AddActivityFormComponent; + + constructor(private router: Router, route: ActivatedRoute, private activityService: ActivityService) { + super(route); + } + + /** + * Called when the Add Activity form (component) emits a "add-activity" event. This is bound to + * from the add-activity.page.html template. + * @param {NewActivity} activity + */ + public onCreateActivity(activity: NewActivity) { + console.log('[AddActivityComponent] onCreateActivity(): ' + JSON.stringify(activity)); + this.activityService.createActivity(activity); + const link: string[] = [ '/activities' ]; + console.log('[AddActivityComponent] Navigating to: %o', link); + this.router.navigate(link); + } + +} diff --git a/ngapp/src/app/activities/shared/activity.model.ts b/ngapp/src/app/activities/shared/activity.model.ts new file mode 100644 index 00000000..6f6f201a --- /dev/null +++ b/ngapp/src/app/activities/shared/activity.model.ts @@ -0,0 +1,87 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class Activity { + + private keng__id: string; + private dv__sourceConnection: string; + private dv__targetConnection: string; + + /** + * @param {Object} json the JSON representation of a Activity + * @returns {Activity} the new Activity (never null) + */ + public static create( json: Object = {} ) { + const conn = new Activity(); + conn.setValues( json ); + return conn; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the activity identifier (can be null) + */ + public getId(): string { + return this.keng__id; + } + + /** + * @returns {string} the source connection name (can be null) + */ + public getSourceConnection(): string { + return this.dv__sourceConnection; + } + + /** + * @returns {string} the target connection name (can be null) + */ + public getTargetConnection(): string { + return this.dv__targetConnection; + } + + /** + * @param {string} id the activity identifier (optional) + */ + public setId( id?: string ): void { + this.keng__id = id ? id : null; + } + + /** + * @param {string} sourceConnection the source connection (optional) + */ + public setSourceConnection( sourceConnection?: string ): void { + this.dv__sourceConnection = sourceConnection ? sourceConnection : null; + } + + /** + * @param {string} targetConnection the target connection (optional) + */ + public setTargetConnection( targetConnection?: string ): void { + this.dv__targetConnection = targetConnection ? targetConnection : null; + } + + /** + * Set all object values using the supplied Activity json + * @param {Object} values + */ + public setValues(values: Object = {}) { + Object.assign(this, values); + } +} diff --git a/ngapp/src/app/activities/shared/activity.service.spec.ts b/ngapp/src/app/activities/shared/activity.service.spec.ts new file mode 100644 index 00000000..edd00760 --- /dev/null +++ b/ngapp/src/app/activities/shared/activity.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { ActivityService } from './activity.service'; + +describe('ActivityService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ActivityService] + }); + }); + + it('should be created', inject([ActivityService], (service: ActivityService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/ngapp/src/app/activities/shared/activity.service.ts b/ngapp/src/app/activities/shared/activity.service.ts new file mode 100644 index 00000000..d4cd06ac --- /dev/null +++ b/ngapp/src/app/activities/shared/activity.service.ts @@ -0,0 +1,109 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +import { Activity } from "@activities/shared/activity.model"; +import { NewActivity } from "@activities/shared/new-activity.model"; +import { NewConnection } from "@connections/shared/new-connection.model"; +import { ApiService } from "@core/api.service"; + +@Injectable() +export class ActivityService extends ApiService { + + activity1 = new Activity(); + activity2 = new Activity(); + activity3 = new Activity(); + activities: Activity[] = [this.activity1, this.activity2, this.activity3]; + newActivity1 = new NewActivity(); + + constructor( private http: Http ) { + super(); + this.activity1.setId('activity1'); + this.activity1.setSourceConnection('activity1SrcConn'); + this.activity1.setTargetConnection('activity1TgtConn'); + this.activity2.setId('activity2'); + this.activity2.setSourceConnection('activity2SrcConn'); + this.activity2.setTargetConnection('activity2TgtConn'); + this.activity3.setId('activity3'); + this.activity3.setSourceConnection('activity3SrcConn'); + this.activity3.setTargetConnection('activity3TgtConn'); + this.newActivity1.setName('newActivity1'); + const srcConn = new NewConnection(); + srcConn.setName('new1Src'); + srcConn.setJndiName('new1SrcJndi'); + srcConn.setDriverName('new1SrcDriver'); + srcConn.setJdbc(true); + this.newActivity1.setSourceConnection(srcConn); + const tgtConn = new NewConnection(); + tgtConn.setName('new1Tgt'); + tgtConn.setJndiName('new1TgtJndi'); + tgtConn.setDriverName('new1TgtDriver'); + tgtConn.setJdbc(false); + this.newActivity1.setTargetConnection(tgtConn); + } + + /** + * Get the activities from the komodo rest interface + * @returns {Activity[]} + */ + public getAllActivities(): Activity[] { + return this.activities; + /* + return this.http + .get(KOMODO_WORKSPACE_URL + '/activities', this.getAuthRequestOptions()) + .map(response => { + const activities = response.json(); + return activities.map((activity) => {const activ = new Activity(); activ.setValues(activity); return activ; }); + }) + .catch(this.handleError); + */ + } + + /** + * Create an activity via the komodo rest interface + * @param {NewActivity} activity + * @returns {Activity} + */ + public createActivity(activity: NewActivity): NewActivity { + return this.newActivity1; + /* + return this.http + .post(KOMODO_WORKSPACE_URL + '/activities/' + activity.name, activity, this.getAuthRequestOptions()) + .map(response => { + return new Activity(); + }) + .catch(this.handleError); + */ + } + + /** + * Delete an activity via the komodo rest interface + * @param {NewActivity} activity + */ + public deleteActivity(activity: NewActivity): NewActivity { + /* + return this.http + .delete(KOMODO_WORKSPACE_URL + '/activities/' + activity.name, this.getAuthRequestOptions()) + .map(response => null) + .catch(this.handleError); + */ + return null; + } + +} diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.css b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.css new file mode 100644 index 00000000..ccc697d4 --- /dev/null +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.css @@ -0,0 +1,60 @@ +select { + width: auto; +} + +.create-activity-form-panel.dragging { + border: 1px dashed #39a5dc; + background-color: #eef; +} + +.create-activity-form-panel { + padding-top: 25px; +} + +span.disabled { + color: #999; +} + +.dropdown ul { + max-height: 250px; + overflow: auto; +} + +div.spinner { + display: inline-block; + margin-right: 5px; +} + +.platform-toggle { + display: inline-block; + text-align: center; + cursor: pointer; + border: 1px solid transparent; + padding: 5px; + margin-right: 8px; + border-radius: 3px; +} +.platform-toggle:hover { + border: 1px solid #bee1f4; + background-color: #def3ff; +} +.platform-toggle.selected { + background-color: #0088ce; + color: white; + cursor: default; + border: 1px solid transparent; +} +.platform-toggle.disabled { + opacity: 0.6; + cursor: not-allowed; +} +.platform-toggle span.fa { + font-size: 32px; +} +.platform-toggle span.lbl { + font-size: 14px; +} + +.account-link-warning { + margin-top: 10px; +} diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.html b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.html new file mode 100644 index 00000000..352c982a --- /dev/null +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.html @@ -0,0 +1,43 @@ +
    +

    Activity Properties

    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts new file mode 100644 index 00000000..c3af6749 --- /dev/null +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddActivityFormComponent } from './add-activity-form.component'; + +describe('AddActivityFormComponent', () => { + let component: AddActivityFormComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AddActivityFormComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddActivityFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts new file mode 100644 index 00000000..444a3521 --- /dev/null +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts @@ -0,0 +1,66 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { EventEmitter } from '@angular/core'; +import { OnInit } from '@angular/core'; +import { Output } from '@angular/core'; +import { Router } from '@angular/router'; + +import { NewActivity } from '@activities/shared/new-activity.model'; + +@Component({ + selector: 'app-add-activity-form', + templateUrl: './add-activity-form.component.html', + styleUrls: ['./add-activity-form.component.css'] +}) +export class AddActivityFormComponent implements OnInit { + + @Output() onCreateActivity = new EventEmitter(); + + model = new NewActivity(); + creatingActivity = false; + + constructor( private router: Router ) { } + + ngOnInit() { + } + + get currentActivity() { return JSON.stringify(this.model); } + + /** + * Called when the user clicks the "Create Activity" submit button on the form. + */ + public createActivity(): void { + const activity: NewActivity = new NewActivity(); + activity.setName(this.model.getName()); + activity.setDescription(this.model.getDescription()); + activity.setSourceConnection(this.model.getSourceConnection()); + activity.setTargetConnection(this.model.getTargetConnection()); + + console.log('[AddActivityFormComponent] Firing create-activity event: %o', activity); + + this.creatingActivity = true; + this.onCreateActivity.emit(activity); + } + + public cancelAdd(): void { + const link: string[] = [ '/activities' ]; + this.router.navigate(link); + } + +} diff --git a/ngapp/src/app/activities/shared/new-activity.model.ts b/ngapp/src/app/activities/shared/new-activity.model.ts new file mode 100644 index 00000000..ffa4abbf --- /dev/null +++ b/ngapp/src/app/activities/shared/new-activity.model.ts @@ -0,0 +1,97 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NewConnection } from '@connections/shared/new-connection.model'; + +export class NewActivity { + + name: string; + description: string; + sourceConnection: NewConnection = new NewConnection(); + targetConnection: NewConnection = new NewConnection(); + + /** + * Constructor + */ + constructor() { + // nothing to do + } + + /** + * @returns {string} the activity name (can be null) + */ + public getName(): string { + return this.name; + } + + /** + * @returns {string} the activity description (can be null) + */ + public getDescription(): string { + return this.description; + } + + /** + * @returns {NewConnection} the source connection (can be null) + */ + public getSourceConnection(): NewConnection { + return this.sourceConnection; + } + + /** + * @returns {NewConnection} the target connection (can be null) + */ + public getTargetConnection(): NewConnection { + return this.targetConnection; + } + + /** + * @param {string} name the activity name (optional) + */ + public setName( name?: string ): void { + this.name = name ? name : null; + } + + /** + * @param {string} description the activity description (optional) + */ + public setDescription( description?: string ): void { + this.description = description ? description : null; + } + + /** + * @param {NewConnection} sourceConnection the source connection (optional) + */ + public setSourceConnection( sourceConnection?: NewConnection ): void { + this.sourceConnection = sourceConnection ? sourceConnection : null; + } + + /** + * @param {NewConnection} targetConnection the target connection (optional) + */ + public setTargetConnection( targetConnection?: NewConnection ): void { + this.targetConnection = targetConnection ? targetConnection : null; + } + + // overrides toJSON - we do not want the name supplied in the json body. + public toJSON() { + return { + sourceConnection: this.sourceConnection, + targetConnection: this.targetConnection + }; + } +} diff --git a/ngapp/src/app/app.component.css b/ngapp/src/app/app.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/app.component.html b/ngapp/src/app/app.component.html new file mode 100644 index 00000000..230f4edc --- /dev/null +++ b/ngapp/src/app/app.component.html @@ -0,0 +1,20 @@ + +
    +

    + Welcome to {{title}}! +

    + +
    +

    Here are some links to help you start:

    + + diff --git a/ngapp/src/app/app.component.spec.ts b/ngapp/src/app/app.component.spec.ts new file mode 100644 index 00000000..9510495a --- /dev/null +++ b/ngapp/src/app/app.component.spec.ts @@ -0,0 +1,32 @@ +import { TestBed, async } from '@angular/core/testing'; + +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + + it(`should have as title 'app'`, async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('app'); + })); + + it('should render title in a h1 tag', async(() => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); + })); +}); diff --git a/ngapp/src/app/app.component.ts b/ngapp/src/app/app.component.ts new file mode 100644 index 00000000..07e99db6 --- /dev/null +++ b/ngapp/src/app/app.component.ts @@ -0,0 +1,27 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'app'; +} diff --git a/ngapp/src/app/app.module.ts b/ngapp/src/app/app.module.ts new file mode 100644 index 00000000..744528a2 --- /dev/null +++ b/ngapp/src/app/app.module.ts @@ -0,0 +1,41 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { ActivitiesModule } from "@activities/activities.module"; +import { AppComponent } from '@app/app.component'; +import { ConnectionsModule } from "@connections/connections.module"; +import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + ActivitiesModule, + BrowserModule, + ConnectionsModule, + CoreModule, + SharedModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.css b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.css new file mode 100644 index 00000000..491084a8 --- /dev/null +++ b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.css @@ -0,0 +1,60 @@ +select { + width: auto; +} + +.create-connection-form-panel.dragging { + border: 1px dashed #39a5dc; + background-color: #eef; +} + +.create-connection-form-panel { + padding-top: 25px; +} + +span.disabled { + color: #999; +} + +.dropdown ul { + max-height: 250px; + overflow: auto; +} + +div.spinner { + display: inline-block; + margin-right: 5px; +} + +.platform-toggle { + display: inline-block; + text-align: center; + cursor: pointer; + border: 1px solid transparent; + padding: 5px; + margin-right: 8px; + border-radius: 3px; +} +.platform-toggle:hover { + border: 1px solid #bee1f4; + background-color: #def3ff; +} +.platform-toggle.selected { + background-color: #0088ce; + color: white; + cursor: default; + border: 1px solid transparent; +} +.platform-toggle.disabled { + opacity: 0.6; + cursor: not-allowed; +} +.platform-toggle span.fa { + font-size: 32px; +} +.platform-toggle span.lbl { + font-size: 14px; +} + +.account-link-warning { + margin-top: 10px; +} diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.html b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.html new file mode 100644 index 00000000..0c42ee26 --- /dev/null +++ b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.html @@ -0,0 +1,42 @@ +
    +

    Connection Properties

    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts new file mode 100644 index 00000000..75c440b1 --- /dev/null +++ b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts @@ -0,0 +1,27 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FormsModule } from '@angular/forms'; +import { AddConnectionFormComponent } from './add-connection-form.component'; + +describe('AddConnectionFormComponent', () => { + let component: AddConnectionFormComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ FormsModule ], + declarations: [ AddConnectionFormComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddConnectionFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.ts b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.ts new file mode 100644 index 00000000..5ebdd104 --- /dev/null +++ b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Router } from '@angular/router'; + +import { NewConnection } from '@connections/shared/new-connection.model'; + +@Component({ + selector: 'app-add-connection-form', + templateUrl: './add-connection-form.component.html', + styleUrls: ['./add-connection-form.component.css'] +}) +export class AddConnectionFormComponent implements OnInit { + + @Output() onCreateConnection = new EventEmitter(); + + model = new NewConnection(); + creatingConnection = false; + + constructor( private router: Router ) { } + + ngOnInit() { + } + + get currentConnection() { return JSON.stringify(this.model); } + + /** + * Called when the user clicks the "Create Connection" submit button on the form. + */ + public createConnection(): void { + const connection: NewConnection = new NewConnection(); + connection.setName(this.model.getName()); + connection.setJndiName(this.model.getJndiName()); + connection.setDriverName(this.model.getDriverName()); + connection.setJdbc(this.model.isJdbc()); + + console.log('[AddConnectionFormComponent] Firing create-connection event: %o', connection); + + this.creatingConnection = true; + this.onCreateConnection.emit(connection); + } + + public cancelAdd(): void { + const link: string[] = [ '/connections' ]; + this.router.navigate(link); + } + +} diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.css b/ngapp/src/app/connections/add-connection/add-connection.component.css new file mode 100644 index 00000000..77de754d --- /dev/null +++ b/ngapp/src/app/connections/add-connection/add-connection.component.css @@ -0,0 +1,12 @@ +.add-connection-form { + padding: 15px +} + +.add-connection-form .form-instructions { + font-size: 15px; + padding-top: 10px +} + +.add-connection-form .form-instructions ol { + padding-left: 20px; +} diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html new file mode 100644 index 00000000..aa99c374 --- /dev/null +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -0,0 +1,16 @@ +
    +
    + +
  • +
  • +
    +
    +
    +
    +

    Add Connection

    +
    +
    + +
    +
    +
    diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts new file mode 100644 index 00000000..2648c53f --- /dev/null +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -0,0 +1,27 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; + +import { AddConnectionComponent } from './add-connection.component'; + +describe('AddConnectionComponent', () => { + let component: AddConnectionComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ RouterTestingModule ], + declarations: [ AddConnectionComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddConnectionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ngapp/src/app/connections/add-connection/add-connection.component.ts new file mode 100644 index 00000000..7ded2f2f --- /dev/null +++ b/ngapp/src/app/connections/add-connection/add-connection.component.ts @@ -0,0 +1,61 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { ViewChild } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Router } from '@angular/router'; + +import { AddConnectionFormComponent } from '@connections/shared/add-connection-form/add-connection-form.component'; +import { ConnectionService } from '@connections/shared/connection.service'; +import { NewConnection } from '@connections/shared/new-connection.model'; +import { AbstractPageComponent } from '@shared/abstract-page.component'; + +@Component({ + selector: 'app-add-connection', + templateUrl: '@connections/add-connection.component.html', + styleUrls: ['@connections/add-connection.component.css'] +}) +export class AddConnectionComponent extends AbstractPageComponent { + + @ViewChild(AddConnectionFormComponent) form: AddConnectionFormComponent; + + constructor(private router: Router, route: ActivatedRoute, private apiService: ConnectionService) { + super(route); + } + + /** + * Called when the Add Connection form (component) emits a "add-connection" event. This is bound to + * from the add-connection.page.html template. + * @param {NewConnection} connection + */ + public onCreateConnection(connection: NewConnection) { + console.log('[AddConnectionComponent] onCreateConnection(): ' + JSON.stringify(connection)); + this.apiService + .createConnection(connection) + .subscribe( + () => { + this.form.creatingConnection = false; + const link: string[] = [ '/connections' ]; + console.log('[AddConnectionComponent] Navigating to: %o', link); + this.router.navigate(link); + } + ); + + } + +} diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.css b/ngapp/src/app/connections/connections-cards/connections-cards.component.css new file mode 100644 index 00000000..8956339e --- /dev/null +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.css @@ -0,0 +1,68 @@ +.container-cards-pf { + padding: 0; + margin-top: 0; +} + +.row-cards-pf { + padding: 0; +} + +.connection-card-action-icon { + cursor: pointer; +} + +.connection-card-icon { + border: 2px solid #39a5dc; + border-radius: 50%; + padding: 5px; + margin-right: 10px; + width: 32px; +} + +.connection-card .connection-card-title { + font-size: 16px; + font-weight: bold; +} + +.connection-card { + -webkit-transition: background-color 300ms; + -moz-transition: background-color 300ms; + -ms-transition: background-color 300ms; + -o-transition: background-color 300ms; + transition: background-color 300ms; + height: 220px; +} +.connection-card:hover { + background-color: rgb(237, 237, 237); +} + +.connection-card.active { + background-color: rgb(221, 234, 255); +} + +.connection-description { + font-size: 13px; + overflow-y: auto; +} + +.connection-card .connection-tags { + margin-bottom: 8px; +} +.connection-card .connection-tags .connection-tags-label { + font-weight: bold; + margin-right: 5px; +} +.connection-card .connection-tags .connection-tag { + margin-right: 5px; + border: 1px solid #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + padding: 2px 4px; +} +.connection-card .connection-tags .connection-tag:hover { + cursor: pointer; + background-color: #0088ce; + border-color: #00659c; + color: white; +} diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.html b/ngapp/src/app/connections/connections-cards/connections-cards.component.html new file mode 100644 index 00000000..0aa9e62b --- /dev/null +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.html @@ -0,0 +1,35 @@ +
    +
    + +
    +
    +
    + +

    + + {{ connection.getId() }} + + +

    +
    +
    + JNDI: + {{ connection.getJndiName() }}    +
    +
    + Driver: + {{ connection.getDriverName() }}    +
    + +
    +
    +
    + +
    +
    diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts new file mode 100644 index 00000000..9745eec4 --- /dev/null +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts @@ -0,0 +1,27 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; + +import { ConnectionsCardsComponent } from './connections-cards.component'; + +describe('ConnectionsCardsComponent', () => { + let component: ConnectionsCardsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ RouterTestingModule ], + declarations: [ ConnectionsCardsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConnectionsCardsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts new file mode 100644 index 00000000..f988bd7c --- /dev/null +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts @@ -0,0 +1,74 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, Output, Input } from '@angular/core'; + +import { Connection } from '@connections/shared/connection.model'; + +@Component({ + moduleId: module.id, + selector: 'app-connections-cards', + templateUrl: 'connections-cards.component.html', + styleUrls: ['connections-cards.component.css'] +}) +export class ConnectionsCardsComponent { + + @Input() connections: Connection[]; + @Input() selectedConnections: Connection[]; + @Output() onConnectionSelected: EventEmitter = new EventEmitter(); + @Output() onConnectionDeselected: EventEmitter = new EventEmitter(); + @Output() onTagSelected: EventEmitter = new EventEmitter(); + @Output() onPingConnection: EventEmitter = new EventEmitter(); + @Output() onEditConnection: EventEmitter = new EventEmitter(); + @Output() onDeleteConnection: EventEmitter = new EventEmitter(); + + /** + * Constructor. + */ + constructor() {} + + public toggleConnectionSelected(connection: Connection): void { + if (this.isSelected(connection)) { + this.onConnectionDeselected.emit(connection); + } else { + this.onConnectionSelected.emit(connection); + } + } + + public isSelected(connection: Connection): boolean { + return this.selectedConnections.indexOf(connection) !== -1; + } + + public pingConnection(connectionName: string): void { + this.onPingConnection.emit(connectionName); + } + + public editConnection(connectionName: string): void { + this.onEditConnection.emit(connectionName); + } + + public deleteConnection(connectionName: string): void { + this.onDeleteConnection.emit(connectionName); + } + + public selectTag(tag: string, event: MouseEvent): void { + event.stopPropagation(); + event.preventDefault(); + this.onTagSelected.emit(tag); + } + +} diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.css b/ngapp/src/app/connections/connections-list/connections-list.component.css new file mode 100644 index 00000000..14cedd29 --- /dev/null +++ b/ngapp/src/app/connections/connections-list/connections-list.component.css @@ -0,0 +1,36 @@ + +.list-group-item { + -webkit-transition: background-color 300ms; + -moz-transition: background-color 300ms; + -ms-transition: background-color 300ms; + -o-transition: background-color 300ms; + transition: background-color 300ms; +} +.list-group-item, .list-group-item:first-child { + margin-bottom: 5px; + border-top: 1px solid rgb(57, 165, 220); +} +.list-group-item.active { + background-color: #ffffff; +} + +.list-group-item .connection-tags { +} +.list-group-item .connection-tags .connection-tags-label { + font-weight: bold; + margin-right: 5px; +} +.list-group-item .connection-tags .connection-tag { + margin-right: 5px; + border: 1px solid #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + padding: 2px 4px; +} +.list-group-item .connection-tags .connection-tag:hover { + cursor: pointer; + background-color: #0088ce; + border-color: #00659c; + color: white; +} diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.html b/ngapp/src/app/connections/connections-list/connections-list.component.html new file mode 100644 index 00000000..d720570d --- /dev/null +++ b/ngapp/src/app/connections/connections-list/connections-list.component.html @@ -0,0 +1,40 @@ +
    +
    +
    +
    + +
    +
    + +
    +
    + JNDI: + {{ connection.getDriverName() }}    +
    +
    + Driver: + {{ connection.getDriverName() }}    +
    + +
    +
    +
    + + + +
    +
    +
    +
    diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts new file mode 100644 index 00000000..b754d8d4 --- /dev/null +++ b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts @@ -0,0 +1,27 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConnectionsListComponent } from './connections-list.component'; +import { RouterTestingModule } from '@angular/router/testing'; + +describe('ConnectionsListComponent', () => { + let component: ConnectionsListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ RouterTestingModule ], + declarations: [ ConnectionsListComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConnectionsListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.ts b/ngapp/src/app/connections/connections-list/connections-list.component.ts new file mode 100644 index 00000000..e37a5cfe --- /dev/null +++ b/ngapp/src/app/connections/connections-list/connections-list.component.ts @@ -0,0 +1,75 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, Output, Input } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Connection } from '@connections/shared/connection.model'; + +@Component({ + moduleId: module.id, + selector: 'app-connections-list', + templateUrl: 'connections-list.component.html', + styleUrls: ['connections-list.component.css'] +}) +export class ConnectionsListComponent { + + @Input() connections: Connection[]; + @Input() selectedConnections: Connection[]; + @Output() onConnectionSelected: EventEmitter = new EventEmitter(); + @Output() onConnectionDeselected: EventEmitter = new EventEmitter(); + @Output() onTagSelected: EventEmitter = new EventEmitter(); + @Output() onEditConnection: EventEmitter = new EventEmitter(); + @Output() onPingConnection: EventEmitter = new EventEmitter(); + @Output() onDeleteConnection: EventEmitter = new EventEmitter(); + + /** + * Constructor. + */ + constructor(private router: Router) {} + + public toggleConnectionSelected(connection: Connection): void { + if (this.isSelected(connection)) { + this.onConnectionDeselected.emit(connection); + } else { + this.onConnectionSelected.emit(connection); + } + } + + public isSelected(connection: Connection): boolean { + return this.selectedConnections.indexOf(connection) !== -1; + } + + public pingConnection(connectionName: string): void { + this.onPingConnection.emit(connectionName); + } + + public editConnection(connectionName: string): void { + this.onEditConnection.emit(connectionName); + } + + public deleteConnection(connectionName: string): void { + this.onDeleteConnection.emit(connectionName); + } + + public selectTag(tag: string, event: MouseEvent): void { + event.stopPropagation(); + event.preventDefault(); + this.onTagSelected.emit(tag); + } + +} diff --git a/ngapp/src/app/connections/connections.component.css b/ngapp/src/app/connections/connections.component.css new file mode 100644 index 00000000..f665144b --- /dev/null +++ b/ngapp/src/app/connections/connections.component.css @@ -0,0 +1,57 @@ +.toolbar-pf { + margin-top: 5px; +} + +.toolbar-pf form { + margin-bottom: 0; +} + +.toolbar-pf-results { + margin-top: 0; +} + +.connection-list-items { + margin-top: 10px +} + +.connection-list-connections .toolbar-pf { + background-color: transparent; +} + +.connection-list-connections .toolbar-pf .toolbar-pf-results { + background-color: white; +} + +a.clear-filters { + cursor: pointer; +} + +.toolbar-pf-view-selector { + float: right; +} + +.toolbar-pf-view-selector li a { + cursor: pointer; + color: #333; +} + +.toolbar-pf-view-selector li a:hover { + color: #0088ce; +} + +.connection-list-items .empty-state { + text-align: center; +} + +.blank-slate-pf { + background-color: white; + width: 50%; + min-width: 500px; + margin-left: auto; + margin-right: auto; + margin-top: 15px; +} + +.connection-list-items .none-matched-state .alert { + background-color: white; +} diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html new file mode 100644 index 00000000..e07c0dc0 --- /dev/null +++ b/ngapp/src/app/connections/connections.component.html @@ -0,0 +1,107 @@ +
    + +
    + +
  • +
    +
    + + + +
    +
    +

    Connections

    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
      +
    • +
    • +
    +
    +
    +
    +
    +
    {{ filteredConnections.length }} Connections found + (out of {{ + allConnections.length }} total)
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +

    No Connections Found

    +

    + No Connections were found - please click below to create a new Connection! +

    +
    + +
    +
    +
    +
    +
    + + No Connections matched the filter!  Please try changing your filter criteria... +
    +
    + + +
    +
    +
    +
    +
    +

    +

    Loading Connections...

    +

    +
    +
    +
    +
    +
    + + +
    + + +
    + +
    + +
    + +
    + +

    Do you really want to delete the selected Connection?

    +
    diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts new file mode 100644 index 00000000..e75fb37e --- /dev/null +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConnectionsComponent } from './connections.component'; + +describe('ConnectionsComponent', () => { + let component: ConnectionsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ConnectionsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConnectionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts new file mode 100644 index 00000000..5baecb01 --- /dev/null +++ b/ngapp/src/app/connections/connections.component.ts @@ -0,0 +1,198 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, ViewChild } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { AbstractPageComponent } from '@shared/abstract-page.component'; +import { ArrayUtils } from '@core/common'; +import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionService } from '@connections/shared/connection.service'; +import { NewConnection } from '@connections/shared/new-connection.model'; + +class Filters { + nameFilter: string; + sortDirection: string; + layout: string; + + constructor(params?: any) { + this.reset(); + if (params) { + for (const key of Object.keys(params)) { + const value: string = params[key]; + this[key] = value; + } + } + } + + public accepts(connection: Connection): boolean { + const name: string = connection.getId().toLocaleLowerCase(); + const namef: string = this.nameFilter.toLocaleLowerCase(); + return name.indexOf(namef) >= 0; + } + + public reset(): void { + this.nameFilter = ''; + this.sortDirection = 'ASC'; + this.layout = 'card'; + } +} + +@Component({ + selector: 'app-connections', + templateUrl: './connections.component.html', + styleUrls: ['./connections.component.css'], + providers: [ConnectionService] +}) +export class ConnectionsComponent extends AbstractPageComponent { + + allConnections: Connection[] = []; + filteredConnections: Connection[] = []; + selectedConnections: Connection[] = []; + filters: Filters = new Filters(); + private connectionNameForDelete: string; + + @ViewChild(ConfirmDeleteComponent) confirmDeleteDialog: ConfirmDeleteComponent; + + constructor(private router: Router, route: ActivatedRoute, private connectionService: ConnectionService) { + super(route); + } + + public loadAsyncPageData() { + this.connectionService + .getAllConnections() + .subscribe( + (connections) => { + this.allConnections = connections; + this.filteredConnections = this.filterConnections(); + this.loaded('connections'); + }, + (error) => { + console.error('[ConnectionsComponent] Error getting connections.'); + this.error(error); + } + ); + } + + /** + * Filters and sorts the list of connections based on the user input + */ + private filterConnections(): Connection[] { + // Clear the array first. + this.filteredConnections.splice(0, this.filteredConnections.length); + for (const connection of this.allConnections) { + if (this.filters.accepts(connection)) { + this.filteredConnections.push(connection); + } + } + this.filteredConnections.sort( (c1: Connection, c2: Connection) => { + let rval: number = c1.getId().localeCompare(c2.getId()); + if (this.filters.sortDirection === 'DESC') { + rval *= -1; + } + return rval; + }); + + this.selectedConnections = ArrayUtils.intersect(this.selectedConnections, this.filteredConnections); + + return this.filteredConnections; + } + + public onSelected(connection: Connection): void { + // Only allow one item to be selected + this.selectedConnections.shift(); + this.selectedConnections.push(connection); + } + + public onDeselected(connection: Connection): void { + // Only one item is selected at a time + this.selectedConnections.shift(); + // this.selectedConnections.splice(this.selectedConnections.indexOf(connection), 1); + } + + public onEdit(connName: string): void { + const link: string[] = [ '/connections/edit-connection' ]; + this.router.navigate(link); + } + + public onDelete(connName: string): void { + this.connectionNameForDelete = connName; + this.confirmDeleteDialog.open(); + } + + public onPing(connName: string): void { + alert('Ping connection ' + connName); + } + + public isFiltered(): boolean { + return this.allConnections.length !== this.filteredConnections.length; + } + + public toggleSortDirection(): void { + if (this.filters.sortDirection === 'ASC') { + this.filters.sortDirection = 'DESC'; + } else { + this.filters.sortDirection = 'ASC'; + } + this.filterConnections(); + } + + public clearFilters(): void { + this.filters.nameFilter = ''; + this.filterConnections(); + } + + public onListLayout(): void { + this.filters.layout = 'list'; + } + + public onCardLayout(): void { + this.filters.layout = 'card'; + } + + /** + * Called to delete all selected APIs. + */ + public deleteConnection(): void { + const selectedConn = this.filterConnections().find(x => x.getId() === this.connectionNameForDelete); + + // const itemsToDelete: Connection[] = ArrayUtils.intersect(this.selectedConnections, this.filteredConnections); + // const selectedConn = itemsToDelete[0]; + + const connectionToDelete: NewConnection = new NewConnection(); + connectionToDelete.setName(selectedConn.getId()); + + // Note: we can only delete selected items that we can see in the UI. + console.log('[ConnectionsPageComponent] Deleting selected Connection.'); + this.connectionService + .deleteConnection(connectionToDelete) + .subscribe( + () => { + this.removeConnectionFromList(selectedConn); + const link: string[] = [ '/connections' ]; + console.log('[CreateApiPageComponent] Navigating to: %o', link); + this.router.navigate(link); + } + ); + } + + private removeConnectionFromList(connection: Connection) { + this.allConnections.splice(this.allConnections.indexOf(connection), 1); + this.filterConnections(); + } +} diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts new file mode 100644 index 00000000..43c126ff --- /dev/null +++ b/ngapp/src/app/connections/connections.module.ts @@ -0,0 +1,53 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; +import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; +import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; +import { ConnectionsComponent } from "@connections/connections.component"; +import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; +import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; +import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { NewConnection } from "@connections/shared/new-connection.model"; + +@NgModule({ + imports: [ + CommonModule, + CoreModule, + SharedModule, + ], + declarations: [ + AddConnectionComponent, + AddConnectionFormComponent, + ConnectionsCardsComponent, + ConnectionsComponent, + ConnectionsListComponent, + EditConnectionComponent + ], + providers: [ + ConnectionService + ], + exports: [ + NewConnection + ] +}) +export class ConnectionsModule { } diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.css b/ngapp/src/app/connections/edit-connection/edit-connection.component.css new file mode 100644 index 00000000..73a87d5c --- /dev/null +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.css @@ -0,0 +1,12 @@ +.edit-connection-form { + padding: 15px +} + +.edit-connection-form .form-instructions { + font-size: 15px; + padding-top: 10px +} + +.edit-connection-form .form-instructions ol { + padding-left: 20px; +} diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.html b/ngapp/src/app/connections/edit-connection/edit-connection.component.html new file mode 100644 index 00000000..44784a3d --- /dev/null +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.html @@ -0,0 +1,18 @@ +
    +
    + +
  • +
  • +
    +
    +
    +
    +

    Edit Connection

    +
    + +
    +
    diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts new file mode 100644 index 00000000..7e1f6135 --- /dev/null +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditConnectionComponent } from './edit-connection.component'; + +describe('EditConnectionComponent', () => { + let component: EditConnectionComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ EditConnectionComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(EditConnectionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.ts new file mode 100644 index 00000000..c49d6800 --- /dev/null +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.ts @@ -0,0 +1,60 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Router } from '@angular/router'; + +import { NewConnection } from '@connections/shared/new-connection.model'; +import { ConnectionService } from '@connections/shared/connection.service'; +import { AbstractPageComponent } from '@shared/abstract-page.component'; + +@Component({ + selector: 'app-edit-connection', + templateUrl: './edit-connection.component.html', + styleUrls: ['./edit-connection.component.css'] +}) +export class EditConnectionComponent extends AbstractPageComponent { + +// @ViewChild(AddConnectionFormComponent) form: AddConnectionFormComponent; + + constructor(private router: Router, route: ActivatedRoute, private connectionService: ConnectionService) { + super(route); + } + + /** + * Called when the Add Connection form (component) emits a "add-connection" event. This is bound to + * from the add-connection.page.html template. + * @param {NewConnection} connection + */ + /* + public onCreateConnection(connection: NewConnection) { + console.log('[AddConnectionComponent] onCreateConnection(): ' + JSON.stringify(connection)); + this.apiService + .createConnection(connection) + .subscribe( + () => { + this.form.creatingConnection = false; + const link: string[] = [ '/connections' ]; + console.log('[AddConnectionComponent] Navigating to: %o', link); + this.router.navigate(link); + } + ); + + } + */ +} diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css new file mode 100644 index 00000000..491084a8 --- /dev/null +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css @@ -0,0 +1,60 @@ +select { + width: auto; +} + +.create-connection-form-panel.dragging { + border: 1px dashed #39a5dc; + background-color: #eef; +} + +.create-connection-form-panel { + padding-top: 25px; +} + +span.disabled { + color: #999; +} + +.dropdown ul { + max-height: 250px; + overflow: auto; +} + +div.spinner { + display: inline-block; + margin-right: 5px; +} + +.platform-toggle { + display: inline-block; + text-align: center; + cursor: pointer; + border: 1px solid transparent; + padding: 5px; + margin-right: 8px; + border-radius: 3px; +} +.platform-toggle:hover { + border: 1px solid #bee1f4; + background-color: #def3ff; +} +.platform-toggle.selected { + background-color: #0088ce; + color: white; + cursor: default; + border: 1px solid transparent; +} +.platform-toggle.disabled { + opacity: 0.6; + cursor: not-allowed; +} +.platform-toggle span.fa { + font-size: 32px; +} +.platform-toggle span.lbl { + font-size: 14px; +} + +.account-link-warning { + margin-top: 10px; +} diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html new file mode 100644 index 00000000..0c42ee26 --- /dev/null +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html @@ -0,0 +1,42 @@ +
    +

    Connection Properties

    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts new file mode 100644 index 00000000..75c440b1 --- /dev/null +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts @@ -0,0 +1,27 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FormsModule } from '@angular/forms'; +import { AddConnectionFormComponent } from './add-connection-form.component'; + +describe('AddConnectionFormComponent', () => { + let component: AddConnectionFormComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ FormsModule ], + declarations: [ AddConnectionFormComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddConnectionFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts new file mode 100644 index 00000000..5ebdd104 --- /dev/null +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Router } from '@angular/router'; + +import { NewConnection } from '@connections/shared/new-connection.model'; + +@Component({ + selector: 'app-add-connection-form', + templateUrl: './add-connection-form.component.html', + styleUrls: ['./add-connection-form.component.css'] +}) +export class AddConnectionFormComponent implements OnInit { + + @Output() onCreateConnection = new EventEmitter(); + + model = new NewConnection(); + creatingConnection = false; + + constructor( private router: Router ) { } + + ngOnInit() { + } + + get currentConnection() { return JSON.stringify(this.model); } + + /** + * Called when the user clicks the "Create Connection" submit button on the form. + */ + public createConnection(): void { + const connection: NewConnection = new NewConnection(); + connection.setName(this.model.getName()); + connection.setJndiName(this.model.getJndiName()); + connection.setDriverName(this.model.getDriverName()); + connection.setJdbc(this.model.isJdbc()); + + console.log('[AddConnectionFormComponent] Firing create-connection event: %o', connection); + + this.creatingConnection = true; + this.onCreateConnection.emit(connection); + } + + public cancelAdd(): void { + const link: string[] = [ '/connections' ]; + this.router.navigate(link); + } + +} diff --git a/ngapp/src/app/connections/shared/connection.model.ts b/ngapp/src/app/connections/shared/connection.model.ts new file mode 100644 index 00000000..55aef1fd --- /dev/null +++ b/ngapp/src/app/connections/shared/connection.model.ts @@ -0,0 +1,103 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class Connection { + + private keng__id: string; + private dv__jndiName: string; + private dv__driverName: string; + private keng__properties: Map< string, string > = new Map< string, string >(); + + /** + * @param {Object} json the JSON representation of a Connection + * @returns {Connection} the new Connection (never null) + */ + public static create( json: Object = {} ) { + const conn = new Connection(); + conn.setValues( json ); + return conn; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the connection driver name (can be null) + */ + public getDriverName(): string { + return this.dv__driverName; + } + + /** + * @returns {string} the connection identifier (can be null) + */ + public getId(): string { + return this.keng__id; + } + + /** + * @returns {string} the connection JNDI name (can be null) + */ + public getJndiName(): string { + return this.dv__jndiName; + } + + /** + * @returns {Map} the connection properties (never null) + */ + public getProperties(): Map< string, string > { + return this.keng__properties; + } + + /** + * @param {string} driverName the connection driver name (optional) + */ + public setDriverName( driverName?: string ): void { + this.dv__driverName = driverName ? driverName : null; + } + + /** + * @param {string} id the connection identifier (optional) + */ + public setId( id?: string ): void { + this.keng__id = id ? id : null; + } + + /** + * @param {string} jndiName the connection JNDI name (optional) + */ + public setJndiName( jndiName?: string ): void { + this.dv__jndiName = jndiName ? jndiName : null; + } + + /** + * @param {Map} props the connection properties (optional) + */ + public setProperties( props?: Map< string, string > ): void { + this.keng__properties = props ? props : new Map< string, string >(); + } + + /** + * Set all object values using the supplied Connection json + * @param {Object} values + */ + public setValues(values: Object = {}) { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ngapp/src/app/connections/shared/connection.service.spec.ts new file mode 100644 index 00000000..9c0392c2 --- /dev/null +++ b/ngapp/src/app/connections/shared/connection.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { ConnectionService } from './connection.service'; + +describe('ConnectionService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ConnectionService] + }); + }); + + it('should be created', inject([ConnectionService], (service: ConnectionService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts new file mode 100644 index 00000000..a9e3ecff --- /dev/null +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -0,0 +1,74 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; +import { Observable } from 'rxjs/Observable'; + +import { Connection } from "@connections/shared/connection.model"; +import { NewConnection } from "@connections/shared/new-connection.model"; +import { ApiService } from "@core/api.service"; +import { KOMODO_WORKSPACE_URL } from "@core/api.service"; + +@Injectable() +export class ConnectionService extends ApiService { + + constructor( private http: Http ) { + super(); + } + + /** + * Get the connections from the komodo rest interface + * @returns {Observable} + */ + public getAllConnections(): Observable { + return this.http + .get(KOMODO_WORKSPACE_URL + '/connections', this.getAuthRequestOptions()) + .map(response => { + const connections = response.json(); + return connections.map((connection) => {const conn = Connection.create( connection ); return conn; }); + }) + .catch(this.handleError); + } + + /** + * Create a connection via the komodo rest interface + * @param {NewConnection} connection + * @returns {Observable} + */ + public createConnection(connection: NewConnection): Observable { + return this.http + .post(KOMODO_WORKSPACE_URL + '/connections/' + connection.getName(), connection, this.getAuthRequestOptions()) + .map(response => { + return new Connection(); + }) + .catch(this.handleError); + } + + /** + * Delete a connection via the komodo rest interface + * @param {NewConnection} connection + * @returns {Observable} + */ + public deleteConnection(connection: NewConnection): Observable { + return this.http + .delete(KOMODO_WORKSPACE_URL + '/connections/' + connection.getName(), this.getAuthRequestOptions()) + .map(response => null) + .catch(this.handleError); + } + +} diff --git a/ngapp/src/app/connections/shared/new-connection.model.ts b/ngapp/src/app/connections/shared/new-connection.model.ts new file mode 100644 index 00000000..c433b9f7 --- /dev/null +++ b/ngapp/src/app/connections/shared/new-connection.model.ts @@ -0,0 +1,112 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class NewConnection { + + name: string; + jndiName: string; + driverName: string; + jdbc: boolean; + properties: Map< string, string > = new Map< string, string >(); + + /** + * Constructor + */ + constructor() { + } + + /** + * @returns {string} the connection name (can be null) + */ + public getName(): string { + return this.name; + } + + /** + * @returns {string} the connection jndi name (can be null) + */ + public getJndiName(): string { + return this.jndiName; + } + + /** + * @returns {string} the connection driver name (can be null) + */ + public getDriverName(): string { + return this.driverName; + } + + /** + * @returns {boolean} the jdbc status + */ + public isJdbc(): boolean { + return this.jdbc; + } + + /** + * @returns {Map} the connection properties (never null) + */ + public getProperties(): Map< string, string > { + return this.properties; + } + + /** + * @param {string} name the connection name (optional) + */ + public setName( name?: string ): void { + this.name = name ? name : null; + } + + /** + * @param {string} jndiName the connection JNDI name (optional) + */ + public setJndiName( jndiName?: string ): void { + this.jndiName = jndiName ? jndiName : null; + } + + /** + * @param {string} driverName the connection driver name (optional) + */ + public setDriverName( driverName?: string ): void { + this.driverName = driverName ? driverName : null; + } + + /** + * @param {boolean} jdbc the jdbc status (optional) + */ + public setJdbc( isJdbc?: boolean ): void { + this.jdbc = isJdbc ? isJdbc : true; + } + + /** + * @param {Map} props the connection properties (optional) + */ + public setProperties( props?: Map< string, string > ): void { + this.properties = props ? props : new Map< string, string >(); + } + + + // overrides toJSON - we do not want the name supplied in the json body. + public toJSON() { + return { + jndiName: this.jndiName, + driverName: this.driverName, + jdbc: this.jdbc, + parameters: this.properties + }; + } +} diff --git a/ngapp/src/app/core/api.service.spec.ts b/ngapp/src/app/core/api.service.spec.ts new file mode 100644 index 00000000..a2a555b0 --- /dev/null +++ b/ngapp/src/app/core/api.service.spec.ts @@ -0,0 +1,17 @@ +import { TestBed, inject } from '@angular/core/testing'; +import { HttpModule } from '@angular/http'; + +import { ApiService } from './api.service'; + +describe('ApiService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpModule], + providers: [ApiService] + }); + }); + + it('should be created', inject([ApiService], (service: ApiService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts new file mode 100644 index 00000000..ca80c009 --- /dev/null +++ b/ngapp/src/app/core/api.service.ts @@ -0,0 +1,47 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { environment } from '@environments/environment'; +import {Http, Headers, RequestOptions} from '@angular/http'; +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/observable/throw'; + +export const KOMODO_WORKSPACE_URL = environment.komodoWorkspaceUrl; + +@Injectable() +export class ApiService { + + /** + * Get the Auth RequestOptions + * TODO: User and password are currently hardcoded to the DSB kit server credentials (dsbUser | 1demo-user1) + * @returns {RequestOptions} + */ + protected getAuthRequestOptions(): RequestOptions { + const headers = new Headers({ 'Authorization': 'Basic ' + btoa('dsbUser:1demo-user1') }); + const options = new RequestOptions({ headers: headers }); + return options; + } + + protected handleError (error: Response | any) { + console.error('ApiService::handleError', error); + return Observable.throw(error); + } + +} diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css new file mode 100644 index 00000000..f0673af3 --- /dev/null +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css @@ -0,0 +1,3 @@ +.studio-breadcrumb { + color: inherit; +} diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html new file mode 100644 index 00000000..708dbf0f --- /dev/null +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html @@ -0,0 +1,2 @@ +{{ label }} +{{ label }} diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts new file mode 100644 index 00000000..d7beb331 --- /dev/null +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BreadcrumbComponent } from './breadcrumb.component'; + +describe('BreadcrumbComponent', () => { + let component: BreadcrumbComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ BreadcrumbComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(BreadcrumbComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts new file mode 100644 index 00000000..fe366990 --- /dev/null +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Component, Input} from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: '[app-breadcrumb]', + templateUrl: 'breadcrumb.component.html', + styleUrls: ['breadcrumb.component.css'] +}) +export class BreadcrumbComponent { + + @Input() label: string; + @Input() icon: string; + @Input() route: string[]; + +} diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.css b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.css new file mode 100644 index 00000000..6119a67d --- /dev/null +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.css @@ -0,0 +1,7 @@ +.studio-breadcrumbs { + float: left; +} +.studio-breadcrumbs .breadcrumb { + margin-bottom: 0; + float: left; +} diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.html b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.html new file mode 100644 index 00000000..2f1e707c --- /dev/null +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.html @@ -0,0 +1,7 @@ +
    +
    + +
    +
    diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts new file mode 100644 index 00000000..1b1a1708 --- /dev/null +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BreadcrumbsComponent } from './breadcrumbs.component'; + +describe('BreadcrumbsComponent', () => { + let component: BreadcrumbsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ BreadcrumbsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(BreadcrumbsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts new file mode 100644 index 00000000..542e0604 --- /dev/null +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Component} from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'breadcrumbs', + templateUrl: 'breadcrumbs.component.html', + styleUrls: ['breadcrumbs.component.css'] +}) +export class BreadcrumbsComponent { + +} diff --git a/ngapp/src/app/core/common.ts b/ngapp/src/app/core/common.ts new file mode 100644 index 00000000..fb926d8e --- /dev/null +++ b/ngapp/src/app/core/common.ts @@ -0,0 +1,111 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +export class ArrayUtils { + + /** + * Returns the intersection of two arrays. + * @param a1 + * @param a2 + */ + public static intersect(a1: any[], a2: any[]): any[] { + let rval: any[] = []; + for (let item of a1) { + if (ArrayUtils.contains(a2, item)) { + rval.push(item); + } + } + return rval; + } + + /** + * Returns true if the given item is contained in the given array. + * @param a + * @param item + * @return {boolean} + */ + public static contains(a: any[], item: any): boolean { + for (let aitem of a) { + if (aitem === item) { + return true; + } + } + return false; + } + +} + +export class ObjectUtils { + + public static isNullOrUndefined(object: any): boolean { + return object === undefined || object === null; + } + + public static objectEquals(x:any, y:any) { + if (x === null || x === undefined || y === null || y === undefined) { return x === y; } + // after this just checking type of one would be enough + if (x.constructor !== y.constructor) { return false; } + // if they are functions, they should exactly refer to same one (because of closures) + if (x instanceof Function) { return x === y; } + // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES) + if (x instanceof RegExp) { return x === y; } + if (x === y || x.valueOf() === y.valueOf()) { return true; } + if (Array.isArray(x) && x.length !== y.length) { return false; } + + // if they are dates, they must had equal valueOf + if (x instanceof Date) { return false; } + + // if they are strictly equal, they both need to be object at least + if (!(x instanceof Object)) { return false; } + if (!(y instanceof Object)) { return false; } + + var p = Object.keys(x); + return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) && + p.every(function (i) { return ObjectUtils.objectEquals(x[i], y[i]); }); + } + +} + +export class HttpUtils { + + public static parseLinkHeader(header: string): any { + let links: any = new Object(); + if (ObjectUtils.isNullOrUndefined(header)) { + return links; + } + if (header.length === 0) { + return links; + } + + // Split parts by comma + let parts: string[] = header.split(','); + + // Parse each part into a named link + parts.forEach( part => { + var section = part.split(';'); + if (section.length == 2) { + var url = section[0].replace(/<(.*)>/, '$1').trim(); + var name = section[1].replace(/rel="(.*)"/, '$1').trim(); + links[name] = url; + } + }); + + return links; + } + +} diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts new file mode 100644 index 00000000..6b7b29d7 --- /dev/null +++ b/ngapp/src/app/core/core.module.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; +import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; +import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; +import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; + +@NgModule({ + imports: [ + CommonModule + ], + declarations: [ + BreadcrumbComponent, + BreadcrumbsComponent, + NavHeaderComponent, + VerticalNavComponent + ] +}) +export class CoreModule { } diff --git a/ngapp/src/app/core/nav-header/nav-header.component.html b/ngapp/src/app/core/nav-header/nav-header.component.html new file mode 100644 index 00000000..063af975 --- /dev/null +++ b/ngapp/src/app/core/nav-header/nav-header.component.html @@ -0,0 +1,58 @@ + + diff --git a/ngapp/src/app/core/nav-header/nav-header.component.less b/ngapp/src/app/core/nav-header/nav-header.component.less new file mode 100644 index 00000000..71f63621 --- /dev/null +++ b/ngapp/src/app/core/nav-header/nav-header.component.less @@ -0,0 +1,46 @@ +@import "../dimensions.less"; + +.navbar { + height: @navbar-height; +} +.navbar .navbar-header { + height: @navbar-height - 3; +} + +.navbar .navbar-brand { + padding: 0; +} +.navbar .navbar-brand .navbar-brand-logo { + line-height: @navbar-height - 3; + font-family: 'Josefin Sans', sans-serif; + font-size: @navbar-logo-size; + font-weight: bold; + color: white; +} +.navbar .navbar-brand .navbar-brand-logo:hover { + color: gold; +} + +.navbar a.dropdown-toggle { + height: @navbar-height - 3; + line-height: 34px; + font-size: 13px; + vertical-align: middle; +} +.navbar a.dropdown-toggle .pficon { + position: initial; +} + +.navbar .dropdown-menu a { + cursor: pointer; +} +.navbar .dropdown-menu a.disabled { + cursor: not-allowed; + color: #999; +} + +.product-versions-pf table tr td { + color: white; + font-size: 13px; + padding-right: 10px; +} diff --git a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts new file mode 100644 index 00000000..f0483e1b --- /dev/null +++ b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NavHeaderComponent } from './nav-header.component'; + +describe('NavHeaderComponent', () => { + let component: NavHeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ NavHeaderComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(NavHeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/core/nav-header/nav-header.component.ts b/ngapp/src/app/core/nav-header/nav-header.component.ts new file mode 100644 index 00000000..8cd96137 --- /dev/null +++ b/ngapp/src/app/core/nav-header/nav-header.component.ts @@ -0,0 +1,53 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Component, OnInit, Inject} from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'app-nav-header', + templateUrl: './nav-header.component.html', + styleUrls: [ './nav-header.component.less' ] +}) +export class NavHeaderComponent implements OnInit { + + version = 'N/A'; + builtOn: Date = new Date(); + projectUrl = 'http://www.apicur.io/'; + + constructor() { + if (window['ApicurioStudioInfo']) { + console.log('[NavHeaderComponent] Found app info: %o', window['ApicurioStudioInfo']) + this.version = window['ApicurioStudioInfo'].version; + this.builtOn = new Date(window['ApicurioStudioInfo'].builtOn); + this.projectUrl = window['ApicurioStudioInfo'].url; + } else { + console.log('[NavHeaderComponent] App info not found.'); + } + } + + ngOnInit(): void { + } + + public user(): string { + return 'User'; + } + + public logout(): void { + } + +} diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html new file mode 100644 index 00000000..b81aeee0 --- /dev/null +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html @@ -0,0 +1,18 @@ +
    + +
    +
    + +
    Activities
    +
    +
    + +
    Connections
    +
    +
    +
    +
    + +
    diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.less b/ngapp/src/app/core/vertical-nav/vertical-nav.component.less new file mode 100644 index 00000000..4570e59f --- /dev/null +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.less @@ -0,0 +1,89 @@ +@import "../dimensions.less"; + +#studio-vertical-nav { + position: absolute; + left: 0; + width: 120px; + top: @navbar-height; + bottom: 0; + background-color: white; + overflow: hidden; + z-index: 100; +} +#studio-vertical-nav .studio-nav-item { + color: #666; + border-bottom: 1px solid #ddd; + padding: 15px 10px 15px 10px; + text-align: center; + border-right: 1px solid #ddd; +} +#studio-vertical-nav .studio-nav-item-filler { + border-right: 1px solid #ddd; + height: 100%; +} +#studio-vertical-nav .studio-nav-item:hover { + background-color: rgba(0, 0, 55, .05); + cursor: pointer; +} +#studio-vertical-nav .studio-nav-item.active { + color: #0088ce; +} +#studio-vertical-nav .studio-nav-item.selected { + border-right: 1px solid white; + color: black; + background-color: white; +} +#studio-vertical-nav .studio-nav-item > span { + font-size: 22px; + display: inline-block; +} +#studio-vertical-nav .studio-nav-item > div { + font-size: 14px; +} + +#studio-vertical-nav-details { + position: absolute; + left: -160px; + width: 280px; + top: @navbar-height; + bottom: 0; + background-color: white; + border-right: 1px solid #ddd; + z-index: 99; + padding: 15px; + -webkit-transition: left 200ms; + -moz-transition: left 200ms; + -ms-transition: left 200ms; + -o-transition: left 200ms; + transition: left 200ms; +} +#studio-vertical-nav-details.out { + left: 120px; +} +#studio-vertical-nav-details .studio-nav-detail-item h3 { + margin-top: 0; + padding-bottom: 3px; + border-bottom: 1px solid #ddd; +} +#studio-vertical-nav-details .studio-nav-detail-item p.description { + line-height: 17px; + padding: 3px; +} +#studio-vertical-nav-details .studio-nav-detail-item h4 { + font-weight: bold; + font-size: 12px; + margin-top: 20px; +} +#studio-vertical-nav-details .studio-nav-detail-item .action { + padding-left: 8px; +} + +#studio-nav-menu-shade { + position: absolute; + left: 120px; + right: 0; + top: @navbar-height; + bottom: 0; + z-index: 80; + background-color: rgba(0, 0, 0, .2); +} diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts new file mode 100644 index 00000000..0c113e43 --- /dev/null +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts @@ -0,0 +1,27 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; + +import { VerticalNavComponent } from './vertical-nav.component'; + +describe('VerticalNavComponent', () => { + let component: VerticalNavComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + declarations: [ VerticalNavComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(VerticalNavComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts new file mode 100644 index 00000000..c6ee0a2b --- /dev/null +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -0,0 +1,115 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit } from '@angular/core'; +import {Router, NavigationEnd} from '@angular/router'; + +/** + * Models the menus off the main left-hand vertical nav. + */ +enum VerticalNavType { + Home, Activities, Connections +} + +@Component({ + moduleId: module.id, + selector: 'app-vertical-nav', + templateUrl: './vertical-nav.component.html', + styleUrls: ['./vertical-nav.component.less'] +}) + +export class VerticalNavComponent implements OnInit { + + public menuTypes: any = VerticalNavType; + public currentMenu: VerticalNavType = VerticalNavType.Home; + + constructor(private router: Router) { + } + + ngOnInit(): void { + console.log('Subscribing to router events.'); + this.router.events.subscribe(event => { + if (event instanceof NavigationEnd) { + this.onShadeClick(); + } + }); + } + + /** + * Returns true if the currently active route is /activities/* + * @returns {boolean} + */ + isActivitiesRoute(): boolean { + return this.router.isActive('/activities', true); + } + + /** + * Returns true if the currently active route is /connections/* + * @returns {boolean} + */ + isConnectionsRoute(): boolean { + return this.router.isActive('/connections', true); + } + + /** + * Called when the user clicks the vertical menu shade (the grey shaded area behind the submenu div that + * is displayed when a sub-menu is selected). Clicking the shade makes the sub-menu div go away. + */ + onShadeClick(): void { + /* + this.subMenuOut = false; + setTimeout(() => { + this.currentSubMenu = VerticalNavSubMenuType.None; + }, 180); + */ + } + + /** + * Called when the user clicks the vertical menu Activities item. + */ + onActivitiesClick(): void { + this.currentMenu = VerticalNavType.Activities; + const link: string[] = [ '/activities' ]; + this.router.navigate(link); + } + + /** + * Called when the user clicks the vertical menu Connections item. + */ + onConnectionsClick(): void { + this.currentMenu = VerticalNavType.Connections; + const link: string[] = [ '/connections' ]; + this.router.navigate(link); + } + + /** + * Toggles a sub-menu off the main vertical left-hand menu bar. If the sub-menu is + * already selected, it de-selects it. + * @param subMenu the sub-menu to toggle + */ + /* + toggleSubMenu(subMenu: VerticalNavSubMenuType): void { + if (this.subMenuOut && this.currentSubMenu === subMenu) { + this.onShadeClick(); + } else { + this.currentSubMenu = subMenu; + this.subMenuOut = true; + } + } + */ + +} diff --git a/ngapp/src/app/shared/abstract-page.component.ts b/ngapp/src/app/shared/abstract-page.component.ts new file mode 100644 index 00000000..761bc3ae --- /dev/null +++ b/ngapp/src/app/shared/abstract-page.component.ts @@ -0,0 +1,85 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {Observable} from 'rxjs/Observable'; +import 'rxjs/add/observable/combineLatest'; + +export abstract class AbstractPageComponent implements OnInit { + + public dataLoaded: Map = new Map(); + public pageError: any; + + /** + * C'tor. + * @param {ActivatedRoute} route + */ + constructor(protected route: ActivatedRoute) { + } + + /** + * Called when the page is initialized. Triggers the loading of asynchronous + * page data. + */ + public ngOnInit(): void { + const combined = Observable.combineLatest(this.route.params, this.route.queryParams, (params, qparams) => ({params, qparams})); + combined.subscribe( ap => { + this.loadAsyncPageData(ap.params, ap.qparams); + }); + } + + /** + * Called to kick off loading the page's async data. Subclasses should + * override to provide page-specific data loading. + * @param pathParams + * @param queryParams + */ + public loadAsyncPageData(pathParams: any, queryParams: any): void { + } + + /** + * Called by a subclass (page) to report an error during loading of data. + * @param error + */ + public error(error: any): void { + console.error(' Error: %o', error); + this.pageError = error; + } + + /** + * Called when page data has been loaded. + * @param key + */ + public loaded(key: string): void { + this.dataLoaded[key] = true; + } + + /** + * Called to determine whether some page data has been loaded yet. + * @param key + * @return {boolean} + */ + public isLoaded(key: string): boolean { + if (this.dataLoaded[key]) { + return true; + } else { + return false; + } + } + +} diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.css b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html new file mode 100644 index 00000000..0cc2b288 --- /dev/null +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html @@ -0,0 +1,20 @@ + diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts new file mode 100644 index 00000000..f225b8cf --- /dev/null +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts @@ -0,0 +1,27 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConfirmDeleteComponent } from './confirm-delete.component'; +import {ModalModule} from 'ngx-bootstrap'; + +describe('ConfirmDeleteComponent', () => { + let component: ConfirmDeleteComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ModalModule.forRoot()], + declarations: [ ConfirmDeleteComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfirmDeleteComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts new file mode 100644 index 00000000..7db312a1 --- /dev/null +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts @@ -0,0 +1,78 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Component, Output, EventEmitter, ViewChildren, QueryList, ElementRef} from '@angular/core'; +import {ModalDirective} from 'ngx-bootstrap'; + +@Component({ + moduleId: module.id, + selector: 'app-confirm-delete', + templateUrl: './confirm-delete.component.html', + styleUrls: ['./confirm-delete.component.css'] +}) + +export class ConfirmDeleteComponent { + + @Output() onDelete: EventEmitter = new EventEmitter(); + + @ViewChildren('confirmDeleteModal') confirmDeleteModal: QueryList; + + protected _isOpen = false; + + /** + * Called to open the dialog. + */ + public open(): void { + this._isOpen = true; + this.confirmDeleteModal.changes.subscribe( thing => { + if (this.confirmDeleteModal.first) { + this.confirmDeleteModal.first.show(); + } + }); + } + + /** + * Called to close the dialog. + */ + public close(): void { + this._isOpen = false; + } + + /** + * Called when the user clicks "Yes". + */ + protected delete(): void { + this.onDelete.emit(true); + this.cancel(); + } + + /** + * Called when the user clicks "cancel". + */ + protected cancel(): void { + this.confirmDeleteModal.first.hide(); + } + + /** + * Returns true if the dialog is open. + * @return {boolean} + */ + public isOpen(): boolean { + return this._isOpen; + } + +} diff --git a/ngapp/src/app/shared/page-error/page-error.component.css b/ngapp/src/app/shared/page-error/page-error.component.css new file mode 100644 index 00000000..4b01f5de --- /dev/null +++ b/ngapp/src/app/shared/page-error/page-error.component.css @@ -0,0 +1,14 @@ +.card-pf-error { + border-top-color: red; +} + +.card-pf-error .card-pf-title .fa { + color: red; +} + +.card-pf-error .card-pf-body .details { +} +.card-pf-error .card-pf-body .details pre { + max-height: 350px; + overflow-y: auto; +} diff --git a/ngapp/src/app/shared/page-error/page-error.component.html b/ngapp/src/app/shared/page-error/page-error.component.html new file mode 100644 index 00000000..b48ece70 --- /dev/null +++ b/ngapp/src/app/shared/page-error/page-error.component.html @@ -0,0 +1,115 @@ +
    +
    +
    +
    + + +
    +
    +

    + + Server Error Encountered +

    +
    +
    +

    + Error was encountered communicating with the server. Please reload the page. +

    +
    + +
    +
    +
    +

    Server Error Details

    +
    {{ stackTrace() }}
    +
    +
    + +
    + + +
    +
    +

    + + Page Not Found +

    +
    +
    +

    + You attempted to navigate to a page that does not exist! Please hit the back button + or go back to home (button below). +

    + +
    +
    + + +
    +
    +

    + + Data Already Exists +

    +
    +
    +

    + It appears you attempted to add or create something that already exists. Instead of adding it again, + try finding the existing resource and editing. +

    +
    + Back to Home + +
    +
    +
    + + +
    +
    +

    + + Connection Error + (Could Not Reach Server) +

    +
    +
    +

    + We couldn't reach the server. Try reloading the page in a few minutes or check your internet connection. +

    +
    + +
    +
    +
    + + +
    +
    +

    + + Unexpected Error on Page + ( + {{ errorMessage() }} + ) +

    +
    +
    +

    + Something unexpected happened. Please try reloading the page, or you could just go back to Home. + See the buttons below... +

    +
    + Back to Dashboard + +
    +
    +
    + +
    +
    +
    diff --git a/ngapp/src/app/shared/page-error/page-error.component.spec.ts b/ngapp/src/app/shared/page-error/page-error.component.spec.ts new file mode 100644 index 00000000..e39ec9ed --- /dev/null +++ b/ngapp/src/app/shared/page-error/page-error.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PageErrorComponent } from './page-error.component'; + +describe('PageErrorComponent', () => { + let component: PageErrorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PageErrorComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PageErrorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/shared/page-error/page-error.component.ts b/ngapp/src/app/shared/page-error/page-error.component.ts new file mode 100644 index 00000000..4c2b2ada --- /dev/null +++ b/ngapp/src/app/shared/page-error/page-error.component.ts @@ -0,0 +1,95 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Component, Input} from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'app-page-error', + templateUrl: './page-error.component.html', + styleUrls: ['./page-error.component.css'] +}) +export class PageErrorComponent { + + @Input() error: any; + + private eobj: any = null; + private showDetails = false; + + /** + * Called to reload the browser page. + */ + public reloadPage(): void { + window.location.reload(); + } + + /** + * Returns whether details should be shown. + */ + public shouldShowDetails(): boolean { + return this.showDetails; + } + + /** + * Called to toggle the error details. + */ + public toggleDetails(): void { + this.showDetails = !this.showDetails; + } + + /** + * Returns the error code. + */ + public errorCode(): number { + return this.error.status; + } + + /** + * Returns the error type. Only valid when the error code is 500. + * @return {()=>string} + */ + public errorMessage(): string { + return this.error.statusText; + } + + /** + * Returns the error stack trace. Only valid when the error code is 500. + */ + public stackTrace(): string { + return this.errorObj().trace; + } + + /** + * Returns the error type. Only valid when the error code is 500. + * @return {()=>string} + */ + public errorType(): string { + return this.errorObj().errorType; + } + + /** + * Returns the parsed error body. + * @return {any} + */ + private errorObj(): any { + if (this.eobj === null) { + this.eobj = this.error.json(); + } + return this.eobj; + } + +} diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts new file mode 100644 index 00000000..97d78b71 --- /dev/null +++ b/ngapp/src/app/shared/shared.module.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { PageErrorComponent } from "@shared/page-error/page-error.component"; + +@NgModule({ + imports: [ + CommonModule + ], + declarations: [ + ConfirmDeleteComponent, + PageErrorComponent + ], + exports: [ + ConfirmDeleteComponent, + PageErrorComponent + ] +}) +export class SharedModule { +} diff --git a/ngapp/src/assets/.gitkeep b/ngapp/src/assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts new file mode 100644 index 00000000..3612073b --- /dev/null +++ b/ngapp/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts new file mode 100644 index 00000000..19351240 --- /dev/null +++ b/ngapp/src/environments/environment.ts @@ -0,0 +1,15 @@ +// The file contents for the current environment will overwrite these during build. +// The build system defaults to the dev environment which uses `environment.ts`, but if you do +// `ng build --env=prod` then `environment.prod.ts` will be used instead. +// The list of which env maps to which file can be found in `.angular-cli.json`. + +export const environment = { + production: false, + + // REST URL - Komodo workspace + komodoWorkspaceUrl: 'https://localhost:8443/vdb-builder/v1/workspace', + + // REST URL - Komodo teiid server + komodoTeiidUrl: 'https://localhost:8443/vdb-builder/v1/teiid' + +}; diff --git a/ngapp/src/favicon.ico b/ngapp/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8081c7ceaf2be08bf59010158c586170d9d2d517 GIT binary patch literal 5430 zcmc(je{54#6vvCoAI3i*G5%$U7!sA3wtMZ$fH6V9C`=eXGJb@R1%(I_{vnZtpD{6n z5Pl{DmxzBDbrB>}`90e12m8T*36WoeDLA&SD_hw{H^wM!cl_RWcVA!I+x87ee975; z@4kD^=bYPn&pmG@(+JZ`rqQEKxW<}RzhW}I!|ulN=fmjVi@x{p$cC`)5$a!)X&U+blKNvN5tg=uLvuLnuqRM;Yc*swiexsoh#XPNu{9F#c`G zQLe{yWA(Y6(;>y|-efAy11k<09(@Oo1B2@0`PtZSkqK&${ zgEY}`W@t{%?9u5rF?}Y7OL{338l*JY#P!%MVQY@oqnItpZ}?s z!r?*kwuR{A@jg2Chlf0^{q*>8n5Ir~YWf*wmsh7B5&EpHfd5@xVaj&gqsdui^spyL zB|kUoblGoO7G(MuKTfa9?pGH0@QP^b#!lM1yHWLh*2iq#`C1TdrnO-d#?Oh@XV2HK zKA{`eo{--^K&MW66Lgsktfvn#cCAc*(}qsfhrvOjMGLE?`dHVipu1J3Kgr%g?cNa8 z)pkmC8DGH~fG+dlrp(5^-QBeEvkOvv#q7MBVLtm2oD^$lJZx--_=K&Ttd=-krx(Bb zcEoKJda@S!%%@`P-##$>*u%T*mh+QjV@)Qa=Mk1?#zLk+M4tIt%}wagT{5J%!tXAE;r{@=bb%nNVxvI+C+$t?!VJ@0d@HIyMJTI{vEw0Ul ze(ha!e&qANbTL1ZneNl45t=#Ot??C0MHjjgY8%*mGisN|S6%g3;Hlx#fMNcL<87MW zZ>6moo1YD?P!fJ#Jb(4)_cc50X5n0KoDYfdPoL^iV`k&o{LPyaoqMqk92wVM#_O0l z09$(A-D+gVIlq4TA&{1T@BsUH`Bm=r#l$Z51J-U&F32+hfUP-iLo=jg7Xmy+WLq6_tWv&`wDlz#`&)Jp~iQf zZP)tu>}pIIJKuw+$&t}GQuqMd%Z>0?t%&BM&Wo^4P^Y z)c6h^f2R>X8*}q|bblAF?@;%?2>$y+cMQbN{X$)^R>vtNq_5AB|0N5U*d^T?X9{xQnJYeU{ zoZL#obI;~Pp95f1`%X3D$Mh*4^?O?IT~7HqlWguezmg?Ybq|7>qQ(@pPHbE9V?f|( z+0xo!#m@Np9PljsyxBY-UA*{U*la#8Wz2sO|48_-5t8%_!n?S$zlGe+NA%?vmxjS- zHE5O3ZarU=X}$7>;Okp(UWXJxI%G_J-@IH;%5#Rt$(WUX?6*Ux!IRd$dLP6+SmPn= z8zjm4jGjN772R{FGkXwcNv8GBcZI#@Y2m{RNF_w8(Z%^A*!bS*!}s6sh*NnURytky humW;*g7R+&|Ledvc- + + + + BeetleStudio + + + + + + + + + diff --git a/ngapp/src/main.ts b/ngapp/src/main.ts new file mode 100644 index 00000000..a9ca1caf --- /dev/null +++ b/ngapp/src/main.ts @@ -0,0 +1,11 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/ngapp/src/polyfills.ts b/ngapp/src/polyfills.ts new file mode 100644 index 00000000..7831e97b --- /dev/null +++ b/ngapp/src/polyfills.ts @@ -0,0 +1,72 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** Evergreen browsers require these. **/ +import 'core-js/es6/reflect'; +import 'core-js/es7/reflect'; + + +/** + * Required to support Web Animations `@angular/animation`. + * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + + + +/*************************************************************************************************** + * Zone JS is required by Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + +/** + * Date, currency, decimal and percent pipes. + * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 + */ +// import 'intl'; // Run `npm install --save intl`. +/** + * Need to import at least one locale-data with intl. + */ +// import 'intl/locale-data/jsonp/en'; diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css new file mode 100644 index 00000000..90d4ee00 --- /dev/null +++ b/ngapp/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/ngapp/src/test.ts b/ngapp/src/test.ts new file mode 100644 index 00000000..cd612eeb --- /dev/null +++ b/ngapp/src/test.ts @@ -0,0 +1,32 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/long-stack-trace-zone'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test'; +import 'zone.js/dist/jasmine-patch'; +import 'zone.js/dist/async-test'; +import 'zone.js/dist/fake-async-test'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. +declare const __karma__: any; +declare const require: any; + +// Prevent Karma from running prematurely. +__karma__.loaded = function () {}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); +// Finally, start Karma to run the tests. +__karma__.start(); diff --git a/ngapp/src/tsconfig.app.json b/ngapp/src/tsconfig.app.json new file mode 100644 index 00000000..39ba8dba --- /dev/null +++ b/ngapp/src/tsconfig.app.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "baseUrl": "./", + "module": "es2015", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ] +} diff --git a/ngapp/src/tsconfig.spec.json b/ngapp/src/tsconfig.spec.json new file mode 100644 index 00000000..63d89ff2 --- /dev/null +++ b/ngapp/src/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "baseUrl": "./", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/ngapp/src/typings.d.ts b/ngapp/src/typings.d.ts new file mode 100644 index 00000000..ef5c7bd6 --- /dev/null +++ b/ngapp/src/typings.d.ts @@ -0,0 +1,5 @@ +/* SystemJS module definition */ +declare var module: NodeModule; +interface NodeModule { + id: string; +} diff --git a/ngapp/tsconfig.json b/ngapp/tsconfig.json new file mode 100644 index 00000000..107cad33 --- /dev/null +++ b/ngapp/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "src", + "paths": { + "@activities/*": ["app/activities/*"], + "@app/*": ["app/*"], + "@connections/*": ["app/connections/*"], + "@core/*": ["app/core/*"], + "@environments/*": ["environments/*"], + "@shared/*": ["app/shared/*"] + }, + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2017", + "dom" + ] + } +} diff --git a/ngapp/tslint.json b/ngapp/tslint.json new file mode 100644 index 00000000..0db5751c --- /dev/null +++ b/ngapp/tslint.json @@ -0,0 +1,142 @@ +{ + "rulesDirectory": [ + "node_modules/codelyzer" + ], + "rules": { + "arrow-return-shorthand": true, + "callable-types": true, + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "eofline": true, + "forin": true, + "import-blacklist": [ + true, + "rxjs" + ], + "import-spacing": true, + "indent": [ + true, + "spaces" + ], + "interface-over-type-literal": true, + "label-position": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-misused-new": true, + "no-non-null-assertion": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "prefer-const": true, + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "typeof-compare": true, + "unified-signatures": true, + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ], + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true, + "no-access-missing-member": true, + "templates-use-public": true, + "invoke-injectable": true + } +} From c833f3327ad9e2e7c207fcabd4cabf2d7223dbd0 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 2 Oct 2017 10:50:13 -0500 Subject: [PATCH 002/205] Fixes all the errors identified when running 'ng serve' --- ngapp/package-lock.json | 5 +++++ ngapp/package.json | 1 + .../connections/add-connection/add-connection.component.ts | 4 ++-- ngapp/src/app/core/core.less | 2 ++ ngapp/src/app/core/nav-header/nav-header.component.less | 2 +- ngapp/src/app/core/nav-header/nav-header.component.ts | 2 +- ngapp/src/app/core/vertical-nav/vertical-nav.component.less | 2 +- 7 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 ngapp/src/app/core/core.less diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index 663ed29e..b8ee70d8 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -5837,6 +5837,11 @@ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", "dev": true }, + "ngx-bootstrap": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-1.9.3.tgz", + "integrity": "sha512-beoKQGJEFwdg0ctIpGb+vx4PTPkyqHrA5tBAEbnUn7ZlTjjfA6533QYGv3qVoKPDNkkHmLA3lRjWKxEMYepCdg==" + }, "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", diff --git a/ngapp/package.json b/ngapp/package.json index 29d3bc4a..71bf8330 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -22,6 +22,7 @@ "@angular/platform-browser-dynamic": "^4.2.4", "@angular/router": "^4.2.4", "core-js": "^2.4.1", + "ngx-bootstrap": "^1.9.3", "rxjs": "^5.4.2", "zone.js": "^0.8.14" }, diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ngapp/src/app/connections/add-connection/add-connection.component.ts index 7ded2f2f..a1f093cc 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.ts @@ -27,8 +27,8 @@ import { AbstractPageComponent } from '@shared/abstract-page.component'; @Component({ selector: 'app-add-connection', - templateUrl: '@connections/add-connection.component.html', - styleUrls: ['@connections/add-connection.component.css'] + templateUrl: './add-connection.component.html', + styleUrls: ['./add-connection.component.css'] }) export class AddConnectionComponent extends AbstractPageComponent { diff --git a/ngapp/src/app/core/core.less b/ngapp/src/app/core/core.less new file mode 100644 index 00000000..c04e4b38 --- /dev/null +++ b/ngapp/src/app/core/core.less @@ -0,0 +1,2 @@ +@navbar-height: 48px; +@navbar-logo-size: 32px; diff --git a/ngapp/src/app/core/nav-header/nav-header.component.less b/ngapp/src/app/core/nav-header/nav-header.component.less index 71f63621..a68d57e5 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.less +++ b/ngapp/src/app/core/nav-header/nav-header.component.less @@ -1,4 +1,4 @@ -@import "../dimensions.less"; +@import "../core.less"; .navbar { height: @navbar-height; diff --git a/ngapp/src/app/core/nav-header/nav-header.component.ts b/ngapp/src/app/core/nav-header/nav-header.component.ts index 8cd96137..5406ba16 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.ts @@ -27,7 +27,7 @@ export class NavHeaderComponent implements OnInit { version = 'N/A'; builtOn: Date = new Date(); - projectUrl = 'http://www.apicur.io/'; + projectUrl = 'http://jboss.org/teiiddesigner/'; constructor() { if (window['ApicurioStudioInfo']) { diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.less b/ngapp/src/app/core/vertical-nav/vertical-nav.component.less index 4570e59f..dd4b3984 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.less +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.less @@ -1,4 +1,4 @@ -@import "../dimensions.less"; +@import "../core.less"; #studio-vertical-nav { position: absolute; From 2b1d7dc0d97fb0913a11ec70d8f53add4a0fb385 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 2 Oct 2017 12:56:04 -0500 Subject: [PATCH 003/205] fix some dependency issues --- ngapp/package-lock.json | 900 ------------------ .../src/app/connections/connections.module.ts | 2 - ngapp/src/app/core/core.module.ts | 4 +- ngapp/src/app/shared/shared.module.ts | 4 +- 4 files changed, 6 insertions(+), 904 deletions(-) diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index b8ee70d8..2691daa4 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -1182,7 +1182,6 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2895,905 +2894,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", - "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.7.0", - "node-pre-gyp": "0.6.36" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.36", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - } - } - }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 43c126ff..4a6a6ff1 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -27,7 +27,6 @@ import { EditConnectionComponent } from "@connections/edit-connection/edit-conne import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { ConnectionService } from "@connections/shared/connection.service"; -import { NewConnection } from "@connections/shared/new-connection.model"; @NgModule({ imports: [ @@ -47,7 +46,6 @@ import { NewConnection } from "@connections/shared/new-connection.model"; ConnectionService ], exports: [ - NewConnection ] }) export class ConnectionsModule { } diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 6b7b29d7..28826455 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -17,6 +17,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import {RouterModule} from '@angular/router'; import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; @@ -25,7 +26,8 @@ import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; @NgModule({ imports: [ - CommonModule + CommonModule, + RouterModule ], declarations: [ BreadcrumbComponent, diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index 97d78b71..3190adca 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -20,10 +20,12 @@ import { NgModule } from '@angular/core'; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { PageErrorComponent } from "@shared/page-error/page-error.component"; +import { ModalModule } from 'ngx-bootstrap'; @NgModule({ imports: [ - CommonModule + CommonModule, + ModalModule ], declarations: [ ConfirmDeleteComponent, From afc2360df0cdd6032e84781834dc4d0684c92d4b Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 2 Oct 2017 15:09:22 -0500 Subject: [PATCH 004/205] more fixes after reorg --- .../activities-cards.component.spec.ts | 2 + .../activities-list.component.spec.ts | 2 + ngapp/src/app/activities/activities.module.ts | 6 +- .../add-activity.component.spec.ts | 14 +++- .../add-activity-form.component.spec.ts | 4 + .../shared/mock-activity.service.ts | 82 +++++++++++++++++++ ngapp/src/app/app.component.css | 3 + ngapp/src/app/app.component.html | 24 ++---- ngapp/src/app/app.component.ts | 34 ++++---- ngapp/src/app/app.module.ts | 2 + ngapp/src/app/app.routing.ts | 52 ++++++++++++ .../add-connection-form.component.spec.ts | 3 +- .../src/app/connections/connections.module.ts | 4 + .../edit-connection.component.spec.ts | 6 +- .../add-connection-form.component.spec.ts | 3 +- ngapp/src/app/core/core.module.ts | 6 ++ 16 files changed, 204 insertions(+), 43 deletions(-) create mode 100644 ngapp/src/app/activities/shared/mock-activity.service.ts create mode 100644 ngapp/src/app/app.routing.ts diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts index 972ebbd1..6a1749ba 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts @@ -1,6 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivitiesCardsComponent } from './activities-cards.component'; +import {RouterModule} from "@angular/router"; describe('ActivitiesCardsComponent', () => { let component: ActivitiesCardsComponent; @@ -8,6 +9,7 @@ describe('ActivitiesCardsComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [RouterModule], declarations: [ ActivitiesCardsComponent ] }) .compileComponents(); diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts index f0221d7f..dc7769b4 100644 --- a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts +++ b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts @@ -1,6 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivitiesListComponent } from './activities-list.component'; +import {RouterModule} from "@angular/router"; describe('ActivitiesListComponent', () => { let component: ActivitiesListComponent; @@ -8,6 +9,7 @@ describe('ActivitiesListComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [ RouterModule ], declarations: [ ActivitiesListComponent ] }) .compileComponents(); diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts index ce440250..3cf592bc 100644 --- a/ngapp/src/app/activities/activities.module.ts +++ b/ngapp/src/app/activities/activities.module.ts @@ -27,13 +27,17 @@ import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { ActivityService } from "@activities/shared/activity.service"; +import {RouterModule} from "@angular/router"; +import {FormsModule} from "@angular/forms"; @NgModule({ imports: [ CommonModule, ConnectionsModule, CoreModule, - SharedModule + SharedModule, + RouterModule, + FormsModule ], declarations: [ ActivitiesCardsComponent, diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 01d8081b..811aebfe 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -1,6 +1,14 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { AddActivityComponent } from './add-activity.component'; +import {FormsModule} from "@angular/forms"; +import {RouterTestingModule} from "@angular/router/testing"; +import {HttpModule} from '@angular/http'; +import {BreadcrumbComponent} from '@core/breadcrumbs/breadcrumb/breadcrumb.component'; +import {BreadcrumbsComponent} from '@core/breadcrumbs/breadcrumbs.component'; +import {AddActivityFormComponent} from '@activities/shared/add-activity-form/add-activity-form.component'; +import {ActivityService} from '@activities/shared/activity.service'; +import {MockActivityService} from '@activities/shared/mock-activity.service'; describe('AddActivityComponent', () => { let component: AddActivityComponent; @@ -8,7 +16,11 @@ describe('AddActivityComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ AddActivityComponent ] + imports: [ FormsModule, RouterTestingModule, HttpModule], + declarations: [ AddActivityComponent, AddActivityFormComponent, BreadcrumbComponent, BreadcrumbsComponent ], + providers: [ + { provide: ActivityService, useClass: MockActivityService }, + ] }) .compileComponents(); })); diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts index c3af6749..bf6d6085 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts @@ -1,6 +1,9 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule } from '@angular/forms'; +import { RouterTestingModule } from '@angular/router/testing'; import { AddActivityFormComponent } from './add-activity-form.component'; +import { CoreModule } from '@core/core.module'; describe('AddActivityFormComponent', () => { let component: AddActivityFormComponent; @@ -8,6 +11,7 @@ describe('AddActivityFormComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [ FormsModule, RouterTestingModule, CoreModule ], declarations: [ AddActivityFormComponent ] }) .compileComponents(); diff --git a/ngapp/src/app/activities/shared/mock-activity.service.ts b/ngapp/src/app/activities/shared/mock-activity.service.ts new file mode 100644 index 00000000..d65d62bf --- /dev/null +++ b/ngapp/src/app/activities/shared/mock-activity.service.ts @@ -0,0 +1,82 @@ +import {Injectable } from '@angular/core'; +import {environment } from '../../../environments/environment'; +import {Http} from '@angular/http'; +import {Activity } from '@activities/shared/activity.model'; +import {NewActivity } from '@activities/shared/new-activity.model'; +import {Connection} from '@connections/shared/connection.model'; +import {NewConnection} from '@connections/shared/new-connection.model'; +import 'rxjs/add/operator/map'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/observable/throw'; +import 'rxjs/add/observable/of'; + +const KOMODO_WORKSPACE_URL = environment.komodoWorkspaceUrl; + +@Injectable() +export class MockActivityService { + + activity1 = new Activity(); + activity2 = new Activity(); + activity3 = new Activity(); + activities: Activity[] = [this.activity1, this.activity2, this.activity3]; + newActivity1 = new NewActivity(); + + newConnection = new NewConnection(); + conn1 = new Connection(); + conn2 = new Connection(); + conn3 = new Connection(); + conns: Connection[] = [this.conn1, this.conn2, this.conn3]; + + constructor( private http: Http ) { + this.activity1.setId('activity1'); + this.activity1.setSourceConnection('activity1SrcConn'); + this.activity1.setTargetConnection('activity1TgtConn'); + this.activity2.setId('activity2'); + this.activity2.setSourceConnection('activity2SrcConn'); + this.activity2.setTargetConnection('activity2TgtConn'); + this.activity3.setId('activity3'); + this.activity3.setSourceConnection('activity3SrcConn'); + this.activity3.setTargetConnection('activity3TgtConn'); + this.newActivity1.setName('newActivity1'); + const srcConn = new NewConnection(); + srcConn.setName('new1Src'); + srcConn.setJndiName('new1SrcJndi'); + srcConn.setDriverName('new1SrcDriver'); + srcConn.setJdbc(true); + this.newActivity1.setSourceConnection(srcConn); + const tgtConn = new NewConnection(); + tgtConn.setName('new1Tgt'); + tgtConn.setJndiName('new1TgtJndi'); + tgtConn.setDriverName('new1TgtDriver'); + tgtConn.setJdbc(false); + this.newActivity1.setTargetConnection(tgtConn); + + + } + + /** + * Get the activities from the komodo rest interface + * @returns {Activity[]} + */ + public getAllActivities(): Activity[] { + return this.activities; + } + + /** + * Create an activity via the komodo rest interface + * @param {NewActivity} activity + * @returns {Activity} + */ + public createActivity(activity: NewActivity): NewActivity { + return this.newActivity1; + } + + /** + * Delete an activity via the komodo rest interface + * @param {NewActivity} activity + */ + public deleteActivity(activity: NewActivity): NewActivity { + return null; + } + +} diff --git a/ngapp/src/app/app.component.css b/ngapp/src/app/app.component.css index e69de29b..9d244549 100644 --- a/ngapp/src/app/app.component.css +++ b/ngapp/src/app/app.component.css @@ -0,0 +1,3 @@ +.app-component { + color: inherit; +} diff --git a/ngapp/src/app/app.component.html b/ngapp/src/app/app.component.html index 230f4edc..362cb25d 100644 --- a/ngapp/src/app/app.component.html +++ b/ngapp/src/app/app.component.html @@ -1,20 +1,8 @@ - -
    -

    - Welcome to {{title}}! -

    - +
    + + +
    + +
    -

    Here are some links to help you start:

    - diff --git a/ngapp/src/app/app.component.ts b/ngapp/src/app/app.component.ts index 07e99db6..97b98638 100644 --- a/ngapp/src/app/app.component.ts +++ b/ngapp/src/app/app.component.ts @@ -1,27 +1,21 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) -export class AppComponent { - title = 'app'; +export class AppComponent implements OnInit { + + routerOutletWrapperId: string; + routerOutletWrapperClass: string; + + constructor() { + this.routerOutletWrapperId = 'studio-page-body'; + this.routerOutletWrapperClass = ''; + } + + ngOnInit() { + } + } diff --git a/ngapp/src/app/app.module.ts b/ngapp/src/app/app.module.ts index 744528a2..6a8bb65d 100644 --- a/ngapp/src/app/app.module.ts +++ b/ngapp/src/app/app.module.ts @@ -17,6 +17,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; +import { RouterModule } from "@angular/router"; import { ActivitiesModule } from "@activities/activities.module"; import { AppComponent } from '@app/app.component'; @@ -33,6 +34,7 @@ import { SharedModule } from "@shared/shared.module"; BrowserModule, ConnectionsModule, CoreModule, + RouterModule, SharedModule ], providers: [], diff --git a/ngapp/src/app/app.routing.ts b/ngapp/src/app/app.routing.ts new file mode 100644 index 00000000..193785d6 --- /dev/null +++ b/ngapp/src/app/app.routing.ts @@ -0,0 +1,52 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {ModuleWithProviders} from '@angular/core'; +import {Routes, RouterModule} from '@angular/router'; + +/* Pages */ +import { ConnectionsComponent } from "@connections/connections.component"; +import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; +import { ActivitiesComponent } from "@activities/activities.component"; +import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; +import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; + + +const _appRoutes: any[] = [ + { + path: 'activities', + component: ActivitiesComponent + }, + { + path: 'activities/add-activity', + component: AddActivityComponent + }, + { + path: 'connections', + component: ConnectionsComponent + }, + { + path: 'connections/add-connection', + component: AddConnectionComponent + }, + { + path: 'connections/edit-connection', + component: EditConnectionComponent + } +]; + +export const AppRouting: ModuleWithProviders = RouterModule.forRoot(_appRoutes); diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts index 75c440b1..947a91f5 100644 --- a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts @@ -2,6 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { AddConnectionFormComponent } from './add-connection-form.component'; +import { RouterTestingModule } from '@angular/router/testing'; describe('AddConnectionFormComponent', () => { let component: AddConnectionFormComponent; @@ -9,7 +10,7 @@ describe('AddConnectionFormComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule ], + imports: [ FormsModule, RouterTestingModule ], declarations: [ AddConnectionFormComponent ] }) .compileComponents(); diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 4a6a6ff1..2883a9f5 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -27,12 +27,16 @@ import { EditConnectionComponent } from "@connections/edit-connection/edit-conne import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { ConnectionService } from "@connections/shared/connection.service"; +import { FormsModule } from "@angular/forms"; +import { RouterModule } from "@angular/router"; @NgModule({ imports: [ CommonModule, CoreModule, SharedModule, + FormsModule, + RouterModule ], declarations: [ AddConnectionComponent, diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts index 7e1f6135..9f7d728f 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts @@ -1,6 +1,9 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { EditConnectionComponent } from './edit-connection.component'; +import {RouterTestingModule} from '@angular/router/testing'; +import {BreadcrumbsComponent} from '@core/breadcrumbs/breadcrumbs.component'; +import {BreadcrumbComponent} from '@core/breadcrumbs/breadcrumb/breadcrumb.component'; describe('EditConnectionComponent', () => { let component: EditConnectionComponent; @@ -8,7 +11,8 @@ describe('EditConnectionComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ EditConnectionComponent ] + imports: [ RouterTestingModule ], + declarations: [ EditConnectionComponent, BreadcrumbsComponent, BreadcrumbComponent ] }) .compileComponents(); })); diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts index 75c440b1..f91ec220 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts @@ -2,6 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { AddConnectionFormComponent } from './add-connection-form.component'; +import {RouterTestingModule} from '@angular/router/testing'; describe('AddConnectionFormComponent', () => { let component: AddConnectionFormComponent; @@ -9,7 +10,7 @@ describe('AddConnectionFormComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule ], + imports: [ FormsModule, RouterTestingModule ], declarations: [ AddConnectionFormComponent ] }) .compileComponents(); diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 28826455..4eb5bd1f 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -34,6 +34,12 @@ import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; BreadcrumbsComponent, NavHeaderComponent, VerticalNavComponent + ], + exports: [ + BreadcrumbComponent, + BreadcrumbsComponent, + NavHeaderComponent, + VerticalNavComponent ] }) export class CoreModule { } From 0fb9d55258424cb23fd7373916ccb4644b9ae59c Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 2 Oct 2017 15:34:01 -0500 Subject: [PATCH 005/205] Removed workspace.xml from git. Moved .gitignore to project root. --- ngapp/.gitignore | 43 -- ngapp/package-lock.json | 900 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 900 insertions(+), 43 deletions(-) delete mode 100644 ngapp/.gitignore diff --git a/ngapp/.gitignore b/ngapp/.gitignore deleted file mode 100644 index 6b668143..00000000 --- a/ngapp/.gitignore +++ /dev/null @@ -1,43 +0,0 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. - -# compiled output -/dist -/tmp -/out-tsc - -# dependencies -/node_modules - -# IDEs and editors -/.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# IDE - VSCode -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -# misc -/.sass-cache -/connect.lock -/coverage -/libpeerconnection.log -npm-debug.log -testem.log -/typings -yarn-error.log - -# e2e -/e2e/*.js -/e2e/*.map - -# System Files -.DS_Store -Thumbs.db diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index 2691daa4..b8ee70d8 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -1182,6 +1182,7 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", + "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2894,6 +2895,905 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", + "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.7.0", + "node-pre-gyp": "0.6.36" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.36", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", From edb3b855a0125037c2f327e4dadd449f4a669fdd Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 2 Oct 2017 16:25:24 -0500 Subject: [PATCH 006/205] fix app routing --- ngapp/src/app/activities/activities.module.ts | 2 -- ngapp/src/app/app.module.ts | 2 ++ ngapp/src/app/core/core.module.ts | 2 ++ ngapp/src/index.html | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts index 3cf592bc..5860f73f 100644 --- a/ngapp/src/app/activities/activities.module.ts +++ b/ngapp/src/app/activities/activities.module.ts @@ -23,7 +23,6 @@ import { ActivitiesComponent } from "@activities/activities.component"; import { ActivitiesListComponent } from "@activities/activities-list/activities-list.component"; import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; -import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { ActivityService } from "@activities/shared/activity.service"; @@ -33,7 +32,6 @@ import {FormsModule} from "@angular/forms"; @NgModule({ imports: [ CommonModule, - ConnectionsModule, CoreModule, SharedModule, RouterModule, diff --git a/ngapp/src/app/app.module.ts b/ngapp/src/app/app.module.ts index 6a8bb65d..08dafb3d 100644 --- a/ngapp/src/app/app.module.ts +++ b/ngapp/src/app/app.module.ts @@ -24,12 +24,14 @@ import { AppComponent } from '@app/app.component'; import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; +import {AppRouting} from "@app/app.routing"; @NgModule({ declarations: [ AppComponent ], imports: [ + AppRouting, ActivitiesModule, BrowserModule, ConnectionsModule, diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 4eb5bd1f..de40608a 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -23,10 +23,12 @@ import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; +import {HttpModule} from "@angular/http"; @NgModule({ imports: [ CommonModule, + HttpModule, RouterModule ], declarations: [ diff --git a/ngapp/src/index.html b/ngapp/src/index.html index 813b1233..ea27c496 100644 --- a/ngapp/src/index.html +++ b/ngapp/src/index.html @@ -7,6 +7,10 @@ + + + + From 2b492013daecac710a5b1133a384f36e50a7a5e8 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 3 Oct 2017 10:53:30 -0500 Subject: [PATCH 007/205] Fixes Jasmine unit tests --- .../activities-cards.component.spec.ts | 4 +- .../activities-list.component.spec.ts | 4 +- .../activities/activities.component.spec.ts | 15 ++++-- .../add-activity.component.spec.ts | 11 ++-- .../shared/activity.service.spec.ts | 2 + .../add-activity-form.component.spec.ts | 2 +- ngapp/src/app/app.component.spec.ts | 15 ++---- .../add-connection.component.spec.ts | 19 +++++-- .../connections/connections.component.spec.ts | 15 ++++-- .../edit-connection.component.spec.ts | 17 +++--- .../add-connection-form.component.spec.ts | 6 +-- .../shared/connection.service.spec.ts | 6 ++- .../shared/mock-connection.service.ts | 52 +++++++++++++++++++ .../breadcrumb/breadcrumb.component.spec.ts | 6 ++- .../confirm-delete.component.spec.ts | 2 +- .../page-error/page-error.component.spec.ts | 3 ++ ngapp/src/app/shared/shared.module.ts | 2 +- 17 files changed, 132 insertions(+), 49 deletions(-) create mode 100644 ngapp/src/app/connections/shared/mock-connection.service.ts diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts index 6a1749ba..cb150f35 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts @@ -1,6 +1,6 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { ActivitiesCardsComponent } from './activities-cards.component'; +import {ActivitiesCardsComponent} from './activities-cards.component'; import {RouterModule} from "@angular/router"; describe('ActivitiesCardsComponent', () => { diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts index dc7769b4..e5333214 100644 --- a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts +++ b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts @@ -1,6 +1,6 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { ActivitiesListComponent } from './activities-list.component'; +import {ActivitiesListComponent} from './activities-list.component'; import {RouterModule} from "@angular/router"; describe('ActivitiesListComponent', () => { diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts index 29f86a9f..e0d7b7b8 100644 --- a/ngapp/src/app/activities/activities.component.spec.ts +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -1,6 +1,14 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { ActivitiesComponent } from './activities.component'; +import {ActivitiesComponent} from './activities.component'; +import {FormsModule} from "@angular/forms"; +import {RouterTestingModule} from "@angular/router/testing"; +import {ActivitiesListComponent} from "@activities/activities-list/activities-list.component"; +import {ActivitiesCardsComponent} from "@activities/activities-cards/activities-cards.component"; +import {ModalModule} from "ngx-bootstrap"; +import {HttpModule} from "@angular/http"; +import {CoreModule} from "@core/core.module"; +import {SharedModule} from "@shared/shared.module"; describe('ActivitiesComponent', () => { let component: ActivitiesComponent; @@ -8,7 +16,8 @@ describe('ActivitiesComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ActivitiesComponent ] + imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], + declarations: [ ActivitiesComponent, ActivitiesListComponent, ActivitiesCardsComponent ] }) .compileComponents(); })); diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 811aebfe..a2aed000 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -1,14 +1,13 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { AddActivityComponent } from './add-activity.component'; +import {AddActivityComponent} from './add-activity.component'; import {FormsModule} from "@angular/forms"; import {RouterTestingModule} from "@angular/router/testing"; import {HttpModule} from '@angular/http'; -import {BreadcrumbComponent} from '@core/breadcrumbs/breadcrumb/breadcrumb.component'; -import {BreadcrumbsComponent} from '@core/breadcrumbs/breadcrumbs.component'; import {AddActivityFormComponent} from '@activities/shared/add-activity-form/add-activity-form.component'; import {ActivityService} from '@activities/shared/activity.service'; import {MockActivityService} from '@activities/shared/mock-activity.service'; +import {CoreModule} from "@core/core.module"; describe('AddActivityComponent', () => { let component: AddActivityComponent; @@ -16,8 +15,8 @@ describe('AddActivityComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, RouterTestingModule, HttpModule], - declarations: [ AddActivityComponent, AddActivityFormComponent, BreadcrumbComponent, BreadcrumbsComponent ], + imports: [ CoreModule, FormsModule, HttpModule, RouterTestingModule ], + declarations: [ AddActivityComponent, AddActivityFormComponent ], providers: [ { provide: ActivityService, useClass: MockActivityService }, ] diff --git a/ngapp/src/app/activities/shared/activity.service.spec.ts b/ngapp/src/app/activities/shared/activity.service.spec.ts index edd00760..205583d8 100644 --- a/ngapp/src/app/activities/shared/activity.service.spec.ts +++ b/ngapp/src/app/activities/shared/activity.service.spec.ts @@ -1,10 +1,12 @@ import { TestBed, inject } from '@angular/core/testing'; +import { HttpModule } from "@angular/http"; import { ActivityService } from './activity.service'; describe('ActivityService', () => { beforeEach(() => { TestBed.configureTestingModule({ + imports: [ HttpModule ], providers: [ActivityService] }); }); diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts index bf6d6085..ff795e1c 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts @@ -11,7 +11,7 @@ describe('AddActivityFormComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, RouterTestingModule, CoreModule ], + imports: [ CoreModule, FormsModule, RouterTestingModule ], declarations: [ AddActivityFormComponent ] }) .compileComponents(); diff --git a/ngapp/src/app/app.component.spec.ts b/ngapp/src/app/app.component.spec.ts index 9510495a..e5406172 100644 --- a/ngapp/src/app/app.component.spec.ts +++ b/ngapp/src/app/app.component.spec.ts @@ -1,10 +1,13 @@ import { TestBed, async } from '@angular/core/testing'; import { AppComponent } from './app.component'; +import { RouterTestingModule } from "@angular/router/testing"; +import { CoreModule } from "@core/core.module"; describe('AppComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [ CoreModule, RouterTestingModule ], declarations: [ AppComponent ], @@ -17,16 +20,4 @@ describe('AppComponent', () => { expect(app).toBeTruthy(); })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app.title).toEqual('app'); - })); - - it('should render title in a h1 tag', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); }); diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 2648c53f..06f3c190 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -1,7 +1,13 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {RouterTestingModule} from '@angular/router/testing'; -import { AddConnectionComponent } from './add-connection.component'; +import {AddConnectionComponent} from './add-connection.component'; +import {AddConnectionFormComponent} from "@connections/add-connection/add-connection-form/add-connection-form.component"; +import {FormsModule} from "@angular/forms"; +import {ConnectionService} from "@connections/shared/connection.service"; +import {MockConnectionService} from "@connections/shared/mock-connection.service"; +import {HttpModule} from "@angular/http"; +import {CoreModule} from "@core/core.module"; describe('AddConnectionComponent', () => { let component: AddConnectionComponent; @@ -9,8 +15,11 @@ describe('AddConnectionComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ RouterTestingModule ], - declarations: [ AddConnectionComponent ] + imports: [ CoreModule, FormsModule, HttpModule, RouterTestingModule ], + declarations: [ AddConnectionComponent, AddConnectionFormComponent ], + providers: [ + { provide: ConnectionService, useClass: MockConnectionService }, + ] }) .compileComponents(); })); diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index e75fb37e..ab0c2062 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -1,6 +1,14 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { ConnectionsComponent } from './connections.component'; +import {ConnectionsComponent} from './connections.component'; +import {FormsModule} from "@angular/forms"; +import {RouterTestingModule} from "@angular/router/testing"; +import {ConnectionsListComponent} from "@connections/connections-list/connections-list.component"; +import {ConnectionsCardsComponent} from "@connections/connections-cards/connections-cards.component"; +import {ModalModule} from "ngx-bootstrap"; +import {HttpModule} from "@angular/http"; +import {CoreModule} from "@core/core.module"; +import {SharedModule} from "@shared/shared.module"; describe('ConnectionsComponent', () => { let component: ConnectionsComponent; @@ -8,7 +16,8 @@ describe('ConnectionsComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ConnectionsComponent ] + imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], + declarations: [ ConnectionsComponent, ConnectionsListComponent, ConnectionsCardsComponent ] }) .compileComponents(); })); diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts index 9f7d728f..61909809 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts @@ -1,9 +1,11 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { EditConnectionComponent } from './edit-connection.component'; +import {EditConnectionComponent} from './edit-connection.component'; import {RouterTestingModule} from '@angular/router/testing'; -import {BreadcrumbsComponent} from '@core/breadcrumbs/breadcrumbs.component'; -import {BreadcrumbComponent} from '@core/breadcrumbs/breadcrumb/breadcrumb.component'; +import {ConnectionService} from "@connections/shared/connection.service"; +import {MockConnectionService} from "@connections/shared/mock-connection.service"; +import {HttpModule} from "@angular/http"; +import {CoreModule} from "@core/core.module"; describe('EditConnectionComponent', () => { let component: EditConnectionComponent; @@ -11,8 +13,11 @@ describe('EditConnectionComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ RouterTestingModule ], - declarations: [ EditConnectionComponent, BreadcrumbsComponent, BreadcrumbComponent ] + imports: [ CoreModule, HttpModule, RouterTestingModule ], + declarations: [ EditConnectionComponent ], + providers: [ + { provide: ConnectionService, useClass: MockConnectionService }, + ] }) .compileComponents(); })); diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts index f91ec220..c2e10619 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts @@ -1,7 +1,7 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; -import { AddConnectionFormComponent } from './add-connection-form.component'; +import {FormsModule} from '@angular/forms'; +import {AddConnectionFormComponent} from './add-connection-form.component'; import {RouterTestingModule} from '@angular/router/testing'; describe('AddConnectionFormComponent', () => { diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ngapp/src/app/connections/shared/connection.service.spec.ts index 9c0392c2..e3450eb5 100644 --- a/ngapp/src/app/connections/shared/connection.service.spec.ts +++ b/ngapp/src/app/connections/shared/connection.service.spec.ts @@ -1,10 +1,12 @@ -import { TestBed, inject } from '@angular/core/testing'; +import {TestBed, inject} from '@angular/core/testing'; -import { ConnectionService } from './connection.service'; +import {ConnectionService} from './connection.service'; +import {HttpModule} from "@angular/http"; describe('ConnectionService', () => { beforeEach(() => { TestBed.configureTestingModule({ + imports: [ HttpModule ], providers: [ConnectionService] }); }); diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts new file mode 100644 index 00000000..3fef25d7 --- /dev/null +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -0,0 +1,52 @@ +import {Injectable } from '@angular/core'; +import {Http} from '@angular/http'; +import {environment} from "@environments/environment"; +import {Connection} from '@connections/shared/connection.model'; +import {NewConnection} from '@connections/shared/new-connection.model'; +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/observable/throw'; +import 'rxjs/add/observable/of'; + +const KOMODO_WORKSPACE_URL = environment.komodoWorkspaceUrl; + +@Injectable() +export class MockConnectionService { + + newConnection = new NewConnection(); + conn1 = new Connection(); + conn2 = new Connection(); + conn3 = new Connection(); + conns: Connection[] = [this.conn1, this.conn2, this.conn3]; + + constructor( private http: Http ) { + } + + /** + * Get the connections from the komodo rest interface + * @returns {Observable} + */ + public getAllConnections(): Observable { + return Observable.of(this.conns); + } + + /** + * Create a connection via the komodo rest interface + * @param {NewConnection} connection + * @returns {Observable} + */ + public createConnection(connection: NewConnection): Observable { + return Observable.of(this.newConnection); + } + + /** + * Delete a connection via the komodo rest interface + * @param {NewConnection} connection + * @returns {Observable} + */ + public deleteConnection(connection: NewConnection): Observable { + return Observable.of(this.newConnection); + } + +} diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts index d7beb331..d8de5e11 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts @@ -1,6 +1,7 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { BreadcrumbComponent } from './breadcrumb.component'; +import {BreadcrumbComponent} from './breadcrumb.component'; +import {RouterTestingModule} from "@angular/router/testing"; describe('BreadcrumbComponent', () => { let component: BreadcrumbComponent; @@ -8,6 +9,7 @@ describe('BreadcrumbComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [ RouterTestingModule ], declarations: [ BreadcrumbComponent ] }) .compileComponents(); diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts index f225b8cf..b604596b 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts @@ -1,7 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ConfirmDeleteComponent } from './confirm-delete.component'; -import {ModalModule} from 'ngx-bootstrap'; +import { ModalModule } from 'ngx-bootstrap'; describe('ConfirmDeleteComponent', () => { let component: ConfirmDeleteComponent; diff --git a/ngapp/src/app/shared/page-error/page-error.component.spec.ts b/ngapp/src/app/shared/page-error/page-error.component.spec.ts index e39ec9ed..0734ecae 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.spec.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.spec.ts @@ -1,6 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { PageErrorComponent } from './page-error.component'; +import { HttpModule } from "@angular/http"; describe('PageErrorComponent', () => { let component: PageErrorComponent; @@ -8,6 +9,7 @@ describe('PageErrorComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [ HttpModule ], declarations: [ PageErrorComponent ] }) .compileComponents(); @@ -16,6 +18,7 @@ describe('PageErrorComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(PageErrorComponent); component = fixture.componentInstance; + component.error = 'test'; fixture.detectChanges(); }); diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index 3190adca..5d2e9456 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -25,7 +25,7 @@ import { ModalModule } from 'ngx-bootstrap'; @NgModule({ imports: [ CommonModule, - ModalModule + ModalModule.forRoot() ], declarations: [ ConfirmDeleteComponent, From 02e96a2e10d5e93e97d998672b6b0a420be51803 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 3 Oct 2017 16:35:11 -0500 Subject: [PATCH 008/205] Create separate routing modules --- .../activities/activities-routing.module.ts | 39 +++++++++++++++ ngapp/src/app/activities/activities.module.ts | 10 ++-- ngapp/src/app/app-routing.module.ts | 41 ++++++++++++++++ ngapp/src/app/app.module.ts | 10 ++-- .../connections-routing.module.ts} | 47 +++++++------------ .../src/app/connections/connections.module.ts | 10 ++-- .../core/nav-header/nav-header.component.ts | 10 ++-- .../page-not-found.component.css | 0 .../page-not-found.component.html | 1 + .../page-not-found.component.spec.ts | 25 ++++++++++ .../page-not-found.component.ts | 33 +++++++++++++ ngapp/src/app/shared/shared.module.ts | 7 ++- ngapp/src/environments/environment.ts | 5 +- ngapp/src/main.ts | 9 ++-- 14 files changed, 196 insertions(+), 51 deletions(-) create mode 100644 ngapp/src/app/activities/activities-routing.module.ts create mode 100644 ngapp/src/app/app-routing.module.ts rename ngapp/src/app/{app.routing.ts => connections/connections-routing.module.ts} (53%) create mode 100644 ngapp/src/app/shared/page-not-found/page-not-found.component.css create mode 100644 ngapp/src/app/shared/page-not-found/page-not-found.component.html create mode 100644 ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts create mode 100644 ngapp/src/app/shared/page-not-found/page-not-found.component.ts diff --git a/ngapp/src/app/activities/activities-routing.module.ts b/ngapp/src/app/activities/activities-routing.module.ts new file mode 100644 index 00000000..dfb15b51 --- /dev/null +++ b/ngapp/src/app/activities/activities-routing.module.ts @@ -0,0 +1,39 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { Routes } from '@angular/router'; + +import { ActivitiesComponent } from "@activities/activities.component"; +import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; + +const activitiesRoutes: Routes = [ + { path: 'activities', component: ActivitiesComponent }, + { path: 'activities/add-activity', component: AddActivityComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot( activitiesRoutes ) + ], + exports: [ + RouterModule + ] +}) + +export class ActivitiesRoutingModule {} diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts index 5860f73f..68aa3dfd 100644 --- a/ngapp/src/app/activities/activities.module.ts +++ b/ngapp/src/app/activities/activities.module.ts @@ -17,21 +17,25 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { FormsModule } from "@angular/forms"; +import { RouterModule } from "@angular/router"; import { ActivitiesCardsComponent } from "@activities/activities-cards/activities-cards.component"; import { ActivitiesComponent } from "@activities/activities.component"; import { ActivitiesListComponent } from "@activities/activities-list/activities-list.component"; +import { ActivitiesRoutingModule } from "@activities/activities-routing.module"; import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; +import { ActivityService } from "@activities/shared/activity.service"; +import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; -import { ActivityService } from "@activities/shared/activity.service"; -import {RouterModule} from "@angular/router"; -import {FormsModule} from "@angular/forms"; @NgModule({ imports: [ + ActivitiesRoutingModule, CommonModule, + ConnectionsModule, CoreModule, SharedModule, RouterModule, diff --git a/ngapp/src/app/app-routing.module.ts b/ngapp/src/app/app-routing.module.ts new file mode 100644 index 00000000..b1d13da5 --- /dev/null +++ b/ngapp/src/app/app-routing.module.ts @@ -0,0 +1,41 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { Routes } from '@angular/router'; + +import { environment } from '@environments/environment'; +import { PageNotFoundComponent } from "@shared/page-not-found/page-not-found.component"; + +const appRoutes: Routes = [ + {path: '', redirectTo: environment.homePagePath, pathMatch: 'full'}, + {path: 'connections', loadChildren: '@connections/connections.module#ConnectionsModule'}, + {path: 'activities', loadChildren: '@activities/activities.module#ActivitiesModule'}, + { path: '**', component: PageNotFoundComponent }, // always last +]; + +@NgModule({ + imports: [ + RouterModule.forRoot( appRoutes ) + ], + exports: [ + RouterModule + ] +}) + +export class AppRoutingModule {} diff --git a/ngapp/src/app/app.module.ts b/ngapp/src/app/app.module.ts index 08dafb3d..86be24d4 100644 --- a/ngapp/src/app/app.module.ts +++ b/ngapp/src/app/app.module.ts @@ -20,24 +20,28 @@ import { NgModule } from '@angular/core'; import { RouterModule } from "@angular/router"; import { ActivitiesModule } from "@activities/activities.module"; +import { ActivitiesRoutingModule } from "@activities/activities-routing.module"; import { AppComponent } from '@app/app.component'; +import { AppRoutingModule } from "@app/app-routing.module"; import { ConnectionsModule } from "@connections/connections.module"; +import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; -import {AppRouting} from "@app/app.routing"; @NgModule({ declarations: [ AppComponent ], imports: [ - AppRouting, ActivitiesModule, BrowserModule, ConnectionsModule, CoreModule, RouterModule, - SharedModule + SharedModule, + ActivitiesRoutingModule, + ConnectionsRoutingModule, + AppRoutingModule // last so its routes are check after all other routes ], providers: [], bootstrap: [AppComponent] diff --git a/ngapp/src/app/app.routing.ts b/ngapp/src/app/connections/connections-routing.module.ts similarity index 53% rename from ngapp/src/app/app.routing.ts rename to ngapp/src/app/connections/connections-routing.module.ts index 193785d6..4fb13f12 100644 --- a/ngapp/src/app/app.routing.ts +++ b/ngapp/src/app/connections/connections-routing.module.ts @@ -15,38 +15,27 @@ * limitations under the License. */ -import {ModuleWithProviders} from '@angular/core'; -import {Routes, RouterModule} from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { Routes } from '@angular/router'; -/* Pages */ -import { ConnectionsComponent } from "@connections/connections.component"; import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; -import { ActivitiesComponent } from "@activities/activities.component"; -import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; +import { ConnectionsComponent } from "@connections/connections.component"; import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; - -const _appRoutes: any[] = [ - { - path: 'activities', - component: ActivitiesComponent - }, - { - path: 'activities/add-activity', - component: AddActivityComponent - }, - { - path: 'connections', - component: ConnectionsComponent - }, - { - path: 'connections/add-connection', - component: AddConnectionComponent - }, - { - path: 'connections/edit-connection', - component: EditConnectionComponent - } +const connectionsRoutes: Routes = [ + { path: 'connections', component: ConnectionsComponent }, + { path: 'connections/add-connection', component: AddConnectionComponent }, + { path: 'connections/edit-connection', component: EditConnectionComponent } ]; -export const AppRouting: ModuleWithProviders = RouterModule.forRoot(_appRoutes); +@NgModule({ + imports: [ + RouterModule.forRoot( connectionsRoutes ) + ], + exports: [ + RouterModule + ] +}) + +export class ConnectionsRoutingModule {} diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 2883a9f5..03de83c6 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -17,6 +17,8 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { FormsModule } from "@angular/forms"; +import { RouterModule } from "@angular/router"; import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; @@ -25,13 +27,13 @@ import { ConnectionsComponent } from "@connections/connections.component"; import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; import { CoreModule } from "@core/core.module"; -import { SharedModule } from "@shared/shared.module"; import { ConnectionService } from "@connections/shared/connection.service"; -import { FormsModule } from "@angular/forms"; -import { RouterModule } from "@angular/router"; +import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; +import { SharedModule } from "@shared/shared.module"; @NgModule({ imports: [ + ConnectionsRoutingModule, CommonModule, CoreModule, SharedModule, @@ -48,8 +50,6 @@ import { RouterModule } from "@angular/router"; ], providers: [ ConnectionService - ], - exports: [ ] }) export class ConnectionsModule { } diff --git a/ngapp/src/app/core/nav-header/nav-header.component.ts b/ngapp/src/app/core/nav-header/nav-header.component.ts index 5406ba16..27161eb1 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.ts @@ -30,11 +30,11 @@ export class NavHeaderComponent implements OnInit { projectUrl = 'http://jboss.org/teiiddesigner/'; constructor() { - if (window['ApicurioStudioInfo']) { - console.log('[NavHeaderComponent] Found app info: %o', window['ApicurioStudioInfo']) - this.version = window['ApicurioStudioInfo'].version; - this.builtOn = new Date(window['ApicurioStudioInfo'].builtOn); - this.projectUrl = window['ApicurioStudioInfo'].url; + if (window['BeetleStudio']) { + console.log('[NavHeaderComponent] Found app info: %o', window['BeetleStudio']) + this.version = window['BeetleStudio'].version; + this.builtOn = new Date(window['BeetleStudio'].builtOn); + this.projectUrl = window['BeetleStudio'].url; } else { console.log('[NavHeaderComponent] App info not found.'); } diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.css b/ngapp/src/app/shared/page-not-found/page-not-found.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.html b/ngapp/src/app/shared/page-not-found/page-not-found.component.html new file mode 100644 index 00000000..5727cb89 --- /dev/null +++ b/ngapp/src/app/shared/page-not-found/page-not-found.component.html @@ -0,0 +1 @@ +

    Page not found

    diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts b/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts new file mode 100644 index 00000000..39170086 --- /dev/null +++ b/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PageNotFoundComponent } from './page-not-found.component'; + +describe('PageNotFoundComponent', () => { + let component: PageNotFoundComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PageNotFoundComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PageNotFoundComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.ts b/ngapp/src/app/shared/page-not-found/page-not-found.component.ts new file mode 100644 index 00000000..8d32187c --- /dev/null +++ b/ngapp/src/app/shared/page-not-found/page-not-found.component.ts @@ -0,0 +1,33 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { OnInit } from '@angular/core'; + +@Component({ + selector: 'app-page-not-found', + templateUrl: './page-not-found.component.html', + styleUrls: ['./page-not-found.component.css'] +}) +export class PageNotFoundComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index 5d2e9456..de2cad57 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -21,6 +21,7 @@ import { NgModule } from '@angular/core'; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { PageErrorComponent } from "@shared/page-error/page-error.component"; import { ModalModule } from 'ngx-bootstrap'; +import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; @NgModule({ imports: [ @@ -29,11 +30,13 @@ import { ModalModule } from 'ngx-bootstrap'; ], declarations: [ ConfirmDeleteComponent, - PageErrorComponent + PageErrorComponent, + PageNotFoundComponent ], exports: [ ConfirmDeleteComponent, - PageErrorComponent + PageErrorComponent, + PageNotFoundComponent ] }) export class SharedModule { diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index 19351240..f5d4d61b 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -6,10 +6,13 @@ export const environment = { production: false, + // the home page path + homePagePath: '/connections', + // REST URL - Komodo workspace komodoWorkspaceUrl: 'https://localhost:8443/vdb-builder/v1/workspace', // REST URL - Komodo teiid server - komodoTeiidUrl: 'https://localhost:8443/vdb-builder/v1/teiid' + komodoTeiidUrl: 'https://localhost:8443/vdb-builder/v1/teiid', }; diff --git a/ngapp/src/main.ts b/ngapp/src/main.ts index a9ca1caf..7bf103b4 100644 --- a/ngapp/src/main.ts +++ b/ngapp/src/main.ts @@ -1,11 +1,14 @@ import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; +import { AppModule } from '@app/app.module'; +import { environment } from '@environments/environment'; if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule); +platformBrowserDynamic().bootstrapModule( AppModule ) + .then( success => console.log( `Bootstrap success` ) ) + .catch( err => console.error( err ) ); + From fa06aaea9cee3b6a58459fec6693858d36185c41 Mon Sep 17 00:00:00 2001 From: Ted Jones - Red Hat Date: Wed, 4 Oct 2017 16:59:43 -0500 Subject: [PATCH 009/205] Removed extra add-connection-form folder and corrected path. --- .../add-connection-form.component.css | 60 ------------------ .../add-connection-form.component.html | 42 ------------- .../add-connection-form.component.spec.ts | 28 --------- .../add-connection-form.component.ts | 63 ------------------- .../add-connection.component.spec.ts | 2 +- 5 files changed, 1 insertion(+), 194 deletions(-) delete mode 100644 ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.css delete mode 100644 ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.html delete mode 100644 ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts delete mode 100644 ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.ts diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.css b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.css deleted file mode 100644 index 491084a8..00000000 --- a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.css +++ /dev/null @@ -1,60 +0,0 @@ -select { - width: auto; -} - -.create-connection-form-panel.dragging { - border: 1px dashed #39a5dc; - background-color: #eef; -} - -.create-connection-form-panel { - padding-top: 25px; -} - -span.disabled { - color: #999; -} - -.dropdown ul { - max-height: 250px; - overflow: auto; -} - -div.spinner { - display: inline-block; - margin-right: 5px; -} - -.platform-toggle { - display: inline-block; - text-align: center; - cursor: pointer; - border: 1px solid transparent; - padding: 5px; - margin-right: 8px; - border-radius: 3px; -} -.platform-toggle:hover { - border: 1px solid #bee1f4; - background-color: #def3ff; -} -.platform-toggle.selected { - background-color: #0088ce; - color: white; - cursor: default; - border: 1px solid transparent; -} -.platform-toggle.disabled { - opacity: 0.6; - cursor: not-allowed; -} -.platform-toggle span.fa { - font-size: 32px; -} -.platform-toggle span.lbl { - font-size: 14px; -} - -.account-link-warning { - margin-top: 10px; -} diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.html b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.html deleted file mode 100644 index 0c42ee26..00000000 --- a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.html +++ /dev/null @@ -1,42 +0,0 @@ -
    -

    Connection Properties

    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    -
    - - -
    -
    -
    -
    diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts deleted file mode 100644 index 947a91f5..00000000 --- a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { FormsModule } from '@angular/forms'; -import { AddConnectionFormComponent } from './add-connection-form.component'; -import { RouterTestingModule } from '@angular/router/testing'; - -describe('AddConnectionFormComponent', () => { - let component: AddConnectionFormComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ FormsModule, RouterTestingModule ], - declarations: [ AddConnectionFormComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AddConnectionFormComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.ts b/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.ts deleted file mode 100644 index 5ebdd104..00000000 --- a/ngapp/src/app/connections/add-connection/add-connection-form/add-connection-form.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; -import { Router } from '@angular/router'; - -import { NewConnection } from '@connections/shared/new-connection.model'; - -@Component({ - selector: 'app-add-connection-form', - templateUrl: './add-connection-form.component.html', - styleUrls: ['./add-connection-form.component.css'] -}) -export class AddConnectionFormComponent implements OnInit { - - @Output() onCreateConnection = new EventEmitter(); - - model = new NewConnection(); - creatingConnection = false; - - constructor( private router: Router ) { } - - ngOnInit() { - } - - get currentConnection() { return JSON.stringify(this.model); } - - /** - * Called when the user clicks the "Create Connection" submit button on the form. - */ - public createConnection(): void { - const connection: NewConnection = new NewConnection(); - connection.setName(this.model.getName()); - connection.setJndiName(this.model.getJndiName()); - connection.setDriverName(this.model.getDriverName()); - connection.setJdbc(this.model.isJdbc()); - - console.log('[AddConnectionFormComponent] Firing create-connection event: %o', connection); - - this.creatingConnection = true; - this.onCreateConnection.emit(connection); - } - - public cancelAdd(): void { - const link: string[] = [ '/connections' ]; - this.router.navigate(link); - } - -} diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 06f3c190..0e58c22e 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -2,7 +2,7 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {RouterTestingModule} from '@angular/router/testing'; import {AddConnectionComponent} from './add-connection.component'; -import {AddConnectionFormComponent} from "@connections/add-connection/add-connection-form/add-connection-form.component"; +import {AddConnectionFormComponent} from "@connections/shared/add-connection-form/add-connection-form.component"; import {FormsModule} from "@angular/forms"; import {ConnectionService} from "@connections/shared/connection.service"; import {MockConnectionService} from "@connections/shared/mock-connection.service"; From 1376884638282d00cd04959f493e49c9c7621921 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 6 Oct 2017 17:01:51 -0500 Subject: [PATCH 010/205] Made changes to tslint.json and fixed most of the errors and warnings --- ngapp/e2e/app.e2e-spec.ts | 8 +- ngapp/e2e/app.po.ts | 11 +- .../activities-cards.component.spec.ts | 9 +- .../activities-cards.component.ts | 38 ++--- .../activities-list.component.spec.ts | 9 +- .../activities-list.component.ts | 37 ++-- .../activities/activities-routing.module.ts | 23 ++- .../app/activities/activities.component.html | 20 +-- .../activities/activities.component.spec.ts | 17 +- .../app/activities/activities.component.ts | 147 +++++++++------- ngapp/src/app/activities/activities.module.ts | 13 +- .../add-activity/add-activity.component.html | 2 +- .../add-activity.component.spec.ts | 17 +- .../add-activity/add-activity.component.ts | 43 +++-- .../app/activities/shared/activity.model.ts | 10 +- .../shared/activity.service.spec.ts | 9 +- .../app/activities/shared/activity.service.ts | 59 ++++--- .../add-activity-form.component.html | 8 +- .../add-activity-form.component.spec.ts | 15 +- .../add-activity-form.component.ts | 68 +++++--- .../shared/mock-activity.service.ts | 81 +++++---- .../activities/shared/new-activity.model.ts | 12 +- ngapp/src/app/app-routing.module.ts | 19 ++- ngapp/src/app/app.component.spec.ts | 9 +- ngapp/src/app/app.component.ts | 38 +++-- ngapp/src/app/app.module.ts | 13 +- .../add-connection.component.html | 2 +- .../add-connection.component.spec.ts | 15 +- .../add-connection.component.ts | 47 ++--- .../connections-cards.component.spec.ts | 11 +- .../connections-cards.component.ts | 31 ++-- .../connections-list.component.spec.ts | 11 +- .../connections-list.component.ts | 35 ++-- .../connections/connections-routing.module.ts | 17 +- .../connections/connections.component.html | 20 +-- .../connections/connections.component.spec.ts | 15 +- .../app/connections/connections.component.ts | 161 ++++++++++-------- .../src/app/connections/connections.module.ts | 13 +- .../edit-connection.component.html | 2 +- .../edit-connection.component.spec.ts | 13 +- .../edit-connection.component.ts | 29 ++-- .../add-connection-form.component.html | 9 +- .../add-connection-form.component.spec.ts | 13 +- .../add-connection-form.component.ts | 42 +++-- .../connections/shared/connection.model.ts | 8 +- .../shared/connection.service.spec.ts | 8 +- .../connections/shared/connection.service.ts | 28 +-- .../shared/mock-connection.service.ts | 35 ++-- .../shared/new-connection.model.ts | 16 +- ngapp/src/app/core/api.service.spec.ts | 11 +- ngapp/src/app/core/api.service.ts | 26 +-- .../breadcrumb/breadcrumb.component.spec.ts | 9 +- .../breadcrumb/breadcrumb.component.ts | 14 +- .../breadcrumbs/breadcrumbs.component.spec.ts | 9 +- .../core/breadcrumbs/breadcrumbs.component.ts | 8 +- ngapp/src/app/core/common.ts | 111 ------------ ngapp/src/app/core/core.module.ts | 13 +- .../nav-header/nav-header.component.spec.ts | 9 +- .../core/nav-header/nav-header.component.ts | 37 ++-- ngapp/src/app/core/utils/array-utils.ts | 49 ++++++ ngapp/src/app/core/utils/object-utils.ts | 65 +++++++ .../vertical-nav.component.spec.ts | 11 +- .../vertical-nav/vertical-nav.component.ts | 73 ++++---- .../src/app/shared/abstract-page.component.ts | 23 ++- .../confirm-delete.component.html | 2 +- .../confirm-delete.component.spec.ts | 11 +- .../confirm-delete.component.ts | 19 +-- ngapp/src/app/shared/id-filter.ts | 69 ++++++++ ngapp/src/app/shared/identifiable.ts | 28 +++ ngapp/src/app/shared/layout-type.enum.ts | 33 ++++ .../page-error/page-error.component.spec.ts | 11 +- .../shared/page-error/page-error.component.ts | 24 +-- .../page-not-found.component.spec.ts | 9 +- .../page-not-found.component.ts | 16 +- ngapp/src/app/shared/shared.module.ts | 9 +- ngapp/src/app/shared/sort-direction.enum.ts | 33 ++++ ngapp/src/environments/environment.ts | 23 ++- ngapp/src/main.ts | 14 +- ngapp/src/polyfills.ts | 25 +-- ngapp/src/test.ts | 22 +-- ngapp/tslint.json | 110 ++++++++---- 81 files changed, 1285 insertions(+), 957 deletions(-) delete mode 100644 ngapp/src/app/core/common.ts create mode 100644 ngapp/src/app/core/utils/array-utils.ts create mode 100644 ngapp/src/app/core/utils/object-utils.ts create mode 100644 ngapp/src/app/shared/id-filter.ts create mode 100644 ngapp/src/app/shared/identifiable.ts create mode 100644 ngapp/src/app/shared/layout-type.enum.ts create mode 100644 ngapp/src/app/shared/sort-direction.enum.ts diff --git a/ngapp/e2e/app.e2e-spec.ts b/ngapp/e2e/app.e2e-spec.ts index ce845c4e..7b5d260f 100644 --- a/ngapp/e2e/app.e2e-spec.ts +++ b/ngapp/e2e/app.e2e-spec.ts @@ -1,14 +1,14 @@ -import { AppPage } from './app.po'; +import { AppPage } from "./app.po"; -describe('beetle-studio App', () => { +describe("beetle-studio App", () => { let page: AppPage; beforeEach(() => { page = new AppPage(); }); - it('should display welcome message', () => { + it("should display welcome message", () => { page.navigateTo(); - expect(page.getParagraphText()).toEqual('Welcome to app!'); + expect(page.getParagraphText()).toEqual("Welcome to app!"); }); }); diff --git a/ngapp/e2e/app.po.ts b/ngapp/e2e/app.po.ts index 82ea75ba..b7e87d8a 100644 --- a/ngapp/e2e/app.po.ts +++ b/ngapp/e2e/app.po.ts @@ -1,11 +1,12 @@ -import { browser, by, element } from 'protractor'; +import { browser, by, element } from "protractor"; +import { promise } from "selenium-webdriver"; export class AppPage { - navigateTo() { - return browser.get('/'); + public navigateTo(): promise.Promise< any > { + return browser.get("/"); } - getParagraphText() { - return element(by.css('app-root h1')).getText(); + public getParagraphText(): promise.Promise { + return element(by.css("app-root h1")).getText(); } } diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts index cb150f35..ac58cb3e 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts @@ -1,9 +1,8 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; - -import {ActivitiesCardsComponent} from './activities-cards.component'; +import {ActivitiesCardsComponent} from "@activities/activities-cards/activities-cards.component"; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; import {RouterModule} from "@angular/router"; -describe('ActivitiesCardsComponent', () => { +describe("ActivitiesCardsComponent", () => { let component: ActivitiesCardsComponent; let fixture: ComponentFixture; @@ -21,7 +20,7 @@ describe('ActivitiesCardsComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.ts index 48e97ee3..a8be58a2 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.ts +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.ts @@ -15,34 +15,35 @@ * limitations under the License. */ -import { Component } from '@angular/core'; -import { EventEmitter } from '@angular/core'; -import { Input } from '@angular/core'; -import { Output } from '@angular/core'; - -import { Activity } from '@activities/shared/activity.model'; +import { Activity } from "@activities/shared/activity.model"; +import { Component } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { Input } from "@angular/core"; +import { Output } from "@angular/core"; @Component({ moduleId: module.id, - selector: 'app-activities-cards', - templateUrl: 'activities-cards.component.html', - styleUrls: ['activities-cards.component.css'] + selector: "app-activities-cards", + templateUrl: "activities-cards.component.html", + styleUrls: ["activities-cards.component.css"] }) export class ActivitiesCardsComponent { - @Input() activities: Activity[]; - @Input() selectedActivities: Activity[]; - @Output() onActivitySelected: EventEmitter = new EventEmitter(); - @Output() onActivityDeselected: EventEmitter = new EventEmitter(); - @Output() onTagSelected: EventEmitter = new EventEmitter(); - @Output() onStartActivity: EventEmitter = new EventEmitter(); - @Output() onEditActivity: EventEmitter = new EventEmitter(); - @Output() onDeleteActivity: EventEmitter = new EventEmitter(); + @Input() private activities: Activity[]; + @Input() private selectedActivities: Activity[]; + @Output() private onActivitySelected: EventEmitter = new EventEmitter(); + @Output() private onActivityDeselected: EventEmitter = new EventEmitter(); + @Output() private onTagSelected: EventEmitter = new EventEmitter(); + @Output() private onStartActivity: EventEmitter = new EventEmitter(); + @Output() private onEditActivity: EventEmitter = new EventEmitter(); + @Output() private onDeleteActivity: EventEmitter = new EventEmitter(); /** * Constructor. */ - constructor() {} + constructor() { + // nothing to do + } public toggleActivitySelected(activity: Activity): void { if (this.isSelected(activity)) { @@ -75,4 +76,3 @@ export class ActivitiesCardsComponent { } } - diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts index e5333214..6cf27629 100644 --- a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts +++ b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts @@ -1,9 +1,8 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; - -import {ActivitiesListComponent} from './activities-list.component'; +import {ActivitiesListComponent} from "@activities/activities-list/activities-list.component"; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; import {RouterModule} from "@angular/router"; -describe('ActivitiesListComponent', () => { +describe("ActivitiesListComponent", () => { let component: ActivitiesListComponent; let fixture: ComponentFixture; @@ -21,7 +20,7 @@ describe('ActivitiesListComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.ts b/ngapp/src/app/activities/activities-list/activities-list.component.ts index d328d2d5..bd046482 100644 --- a/ngapp/src/app/activities/activities-list/activities-list.component.ts +++ b/ngapp/src/app/activities/activities-list/activities-list.component.ts @@ -15,34 +15,35 @@ * limitations under the License. */ -import { Component } from '@angular/core'; -import { EventEmitter } from '@angular/core'; -import { Input } from '@angular/core'; -import { Output } from '@angular/core'; - -import { Activity } from '@activities/shared/activity.model'; +import { Activity } from "@activities/shared/activity.model"; +import { Component } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { Input } from "@angular/core"; +import { Output } from "@angular/core"; @Component({ moduleId: module.id, - selector: 'app-activities-list', - templateUrl: 'activities-list.component.html', - styleUrls: ['activities-list.component.css'] + selector: "app-activities-list", + templateUrl: "activities-list.component.html", + styleUrls: ["activities-list.component.css"] }) export class ActivitiesListComponent { - @Input() activities: Activity[]; - @Input() selectedActivities: Activity[]; - @Output() onActivitySelected: EventEmitter = new EventEmitter(); - @Output() onActivityDeselected: EventEmitter = new EventEmitter(); - @Output() onTagSelected: EventEmitter = new EventEmitter(); - @Output() onEditActivity: EventEmitter = new EventEmitter(); - @Output() onStartActivity: EventEmitter = new EventEmitter(); - @Output() onDeleteActivity: EventEmitter = new EventEmitter(); + @Input() private activities: Activity[]; + @Input() private selectedActivities: Activity[]; + @Output() private onActivitySelected: EventEmitter = new EventEmitter(); + @Output() private onActivityDeselected: EventEmitter = new EventEmitter(); + @Output() private onTagSelected: EventEmitter = new EventEmitter(); + @Output() private onEditActivity: EventEmitter = new EventEmitter(); + @Output() private onStartActivity: EventEmitter = new EventEmitter(); + @Output() private onDeleteActivity: EventEmitter = new EventEmitter(); /** * Constructor. */ - constructor() {} + constructor() { + // nothing to do + } public toggleActivitySelected(activity: Activity): void { if (this.isSelected(activity)) { diff --git a/ngapp/src/app/activities/activities-routing.module.ts b/ngapp/src/app/activities/activities-routing.module.ts index dfb15b51..d91f9a7b 100644 --- a/ngapp/src/app/activities/activities-routing.module.ts +++ b/ngapp/src/app/activities/activities-routing.module.ts @@ -2,12 +2,7 @@ * @license * Copyright 2017 JBoss Inc * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * Licensed under the Apache License, / * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,16 +10,20 @@ * limitations under the License. */ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { Routes } from '@angular/router'; - import { ActivitiesComponent } from "@activities/activities.component"; import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { Routes } from "@angular/router"; + +export const activitiesRootPath = "/activities"; +export const addActivityPath = activitiesRootPath + "/add-activity"; +export const editActivityPath = activitiesRootPath + "/edit-activity"; const activitiesRoutes: Routes = [ - { path: 'activities', component: ActivitiesComponent }, - { path: 'activities/add-activity', component: AddActivityComponent } + { path: activitiesRootPath, component: ActivitiesComponent }, + { path: addActivityPath, component: AddActivityComponent } +// { path: editActivityPath, component: EditActivityComponent } ]; @NgModule({ diff --git a/ngapp/src/app/activities/activities.component.html b/ngapp/src/app/activities/activities.component.html index 24ae1492..00566588 100644 --- a/ngapp/src/app/activities/activities.component.html +++ b/ngapp/src/app/activities/activities.component.html @@ -18,22 +18,22 @@

    Activities

    - +
      -
    • -
    • +
    • +
    @@ -60,7 +60,7 @@

    No Activities Found

    @@ -79,7 +79,7 @@

    No Activities Found

    -

    Loading Activities...

    + Loading Activities...

    @@ -89,10 +89,10 @@

    - -
    diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts index e0d7b7b8..2eb9437c 100644 --- a/ngapp/src/app/activities/activities.component.spec.ts +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -1,16 +1,15 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; - -import {ActivitiesComponent} from './activities.component'; -import {FormsModule} from "@angular/forms"; -import {RouterTestingModule} from "@angular/router/testing"; -import {ActivitiesListComponent} from "@activities/activities-list/activities-list.component"; import {ActivitiesCardsComponent} from "@activities/activities-cards/activities-cards.component"; -import {ModalModule} from "ngx-bootstrap"; +import {ActivitiesListComponent} from "@activities/activities-list/activities-list.component"; +import {ActivitiesComponent} from "@activities/activities.component"; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {FormsModule} from "@angular/forms"; import {HttpModule} from "@angular/http"; +import {RouterTestingModule} from "@angular/router/testing"; import {CoreModule} from "@core/core.module"; import {SharedModule} from "@shared/shared.module"; +import {ModalModule} from "ngx-bootstrap"; -describe('ActivitiesComponent', () => { +describe("ActivitiesComponent", () => { let component: ActivitiesComponent; let fixture: ComponentFixture; @@ -28,7 +27,7 @@ describe('ActivitiesComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index 9e5c5827..3d0e316c 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -15,70 +15,54 @@ * limitations under the License. */ -import { Component } from '@angular/core'; -import { ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Router } from '@angular/router'; - -import { Activity } from '@activities/shared/activity.model'; -import { NewActivity } from '@activities/shared/new-activity.model'; -import { ActivityService } from '@activities/shared/activity.service'; -import { ArrayUtils } from '@core/common'; +import { addActivityPath, editActivityPath } from "@activities/activities-routing.module"; +import { Activity } from "@activities/shared/activity.model"; +import { ActivityService } from "@activities/shared/activity.service"; +import { NewActivity } from "@activities/shared/new-activity.model"; +import { ViewChild } from "@angular/core"; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Router } from "@angular/router"; +import { ArrayUtils } from "@core/utils/array-utils"; import { AbstractPageComponent } from "@shared/abstract-page.component"; -import { ConfirmDeleteComponent } from '@shared/confirm-delete/confirm-delete.component'; - -class Filters { - nameFilter: string; - sortDirection: string; - layout: string; - - constructor(params?: any) { - this.reset(); - if (params) { - for (const key of Object.keys(params)) { - this[key] = params[ key ]; - } - } - } - - public accepts(activity: Activity): boolean { - const name: string = activity.getId().toLocaleLowerCase(); - const namef: string = this.nameFilter.toLocaleLowerCase(); - return name.indexOf(namef) >= 0; - } - - public reset(): void { - this.nameFilter = ''; - this.sortDirection = 'ASC'; - this.layout = 'card'; - } -} +import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { IdFilter } from "@shared/id-filter"; +import { LayoutType } from "@shared/layout-type.enum"; +import { SortDirection } from "@shared/sort-direction.enum"; @Component({ moduleId: module.id, - selector: 'app-activities', - templateUrl: './activities.component.html', - styleUrls: ['./activities.component.css'], + selector: "app-activities", + templateUrl: "./activities.component.html", + styleUrls: ["./activities.component.css"], providers: [ ActivityService ] }) export class ActivitiesComponent extends AbstractPageComponent { - allActivities: Activity[] = []; - filteredActivities: Activity[] = []; - selectedActivities: Activity[] = []; - filters: Filters = new Filters(); + public addActivityLink = addActivityPath; + + private allActivities: Activity[] = []; + private filteredActivities: Activity[] = []; + private selectedActivities: Activity[] = []; private activityNameForDelete: string; + private router: Router; + private activityService: ActivityService; + private filter: IdFilter = new IdFilter(); + private layout: LayoutType = LayoutType.CARD; + private sortDirection: SortDirection; - @ViewChild(ConfirmDeleteComponent) confirmDeleteDialog: ConfirmDeleteComponent; + @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; - constructor(private router: Router, route: ActivatedRoute, private activityService: ActivityService) { + constructor(router: Router, route: ActivatedRoute, activityService: ActivityService) { super(route); + this.router = router; + this.activityService = activityService; } - public loadAsyncPageData() { + public loadAsyncPageData(): void { this.allActivities = this.activityService.getAllActivities(); this.filteredActivities = this.filterActivities(); - this.loaded('activities'); + this.loaded("activities"); } /** @@ -88,13 +72,13 @@ export class ActivitiesComponent extends AbstractPageComponent { // Clear the array first. this.filteredActivities.splice(0, this.filteredActivities.length); for (const activity of this.allActivities) { - if (this.filters.accepts(activity)) { + if (this.filter.accepts(activity)) { this.filteredActivities.push(activity); } } this.filteredActivities.sort( (a1: Activity, a2: Activity) => { let rval: number = a1.getId().localeCompare(a2.getId()); - if (this.filters.sortDirection === 'DESC') { + if (this.sortDirection === SortDirection.DESC) { rval *= -1; } return rval; @@ -118,7 +102,7 @@ export class ActivitiesComponent extends AbstractPageComponent { } public onEdit(activityName: string): void { - const link: string[] = [ '/activities/edit-activity' ]; + const link: string[] = [ editActivityPath ]; this.router.navigate(link); } @@ -128,7 +112,7 @@ export class ActivitiesComponent extends AbstractPageComponent { } public onStart(activityName: string): void { - alert('Start activity ' + activityName); + alert("Start activity " + activityName); } public isFiltered(): boolean { @@ -136,38 +120,73 @@ export class ActivitiesComponent extends AbstractPageComponent { } public toggleSortDirection(): void { - if (this.filters.sortDirection === 'ASC') { - this.filters.sortDirection = 'DESC'; + if (this.sortDirection === SortDirection.ASC) { + this.sortDirection = SortDirection.DESC; } else { - this.filters.sortDirection = 'ASC'; + this.sortDirection = SortDirection.ASC; } this.filterActivities(); } public clearFilters(): void { - this.filters.nameFilter = ''; + this.filter.reset(); this.filterActivities(); } + /** + * @returns {boolean} true if activities are being represented by cards + */ + public get isCardLayout(): boolean { + return this.layout === LayoutType.CARD; + } + + /** + * @returns {boolean} true if activities are being represented by items in a list + */ + public get isListLayout(): boolean { + return this.layout === LayoutType.LIST; + } + + /** + * @returns {boolean} true if sorting activity names in ascending order + */ + public get isSortAscending(): boolean { + return this.sortDirection === SortDirection.ASC; + } + + /** + * @returns {boolean} true if sorting activity names in descending order + */ + public get isSortDescending(): boolean { + return this.sortDirection === SortDirection.DESC; + } + + /** + * @returns {string} the pattern the activity names are being matched to (can be null or empty) + */ + public get nameFilter(): string { + return this.filter.getPattern(); + } + public onListLayout(): void { - this.filters.layout = 'list'; + this.layout = LayoutType.LIST; } public onCardLayout(): void { - this.filters.layout = 'card'; + this.layout = LayoutType.CARD; } /** - * Called to delete all selected APIs. + * Called to doDelete all selected APIs. */ public deleteActivity(): void { - const selectedActiv = this.filterActivities().find(x => x.getId() === this.activityNameForDelete); + const selectedActivity = this.filterActivities().find((x) => x.getId() === this.activityNameForDelete); const activityToDelete: NewActivity = new NewActivity(); - activityToDelete.setName(selectedActiv.getId()); + activityToDelete.setName(selectedActivity.getId()); - // Note: we can only delete selected items that we can see in the UI. - console.log('[ActivitiesPageComponent] Deleting selected Activity.'); + // Note: we can only doDelete selected items that we can see in the UI. + console.log("[ActivitiesPageComponent] Deleting selected Activity."); this.activityService.deleteActivity(activityToDelete); /* this.apiService @@ -183,7 +202,7 @@ export class ActivitiesComponent extends AbstractPageComponent { */ } - private removeActivityFromList(activity: Activity) { + private removeActivityFromList(activity: Activity): void { this.allActivities.splice(this.allActivities.indexOf(activity), 1); this.filterActivities(); } diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts index 68aa3dfd..392fddb4 100644 --- a/ngapp/src/app/activities/activities.module.ts +++ b/ngapp/src/app/activities/activities.module.ts @@ -15,18 +15,17 @@ * limitations under the License. */ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { FormsModule } from "@angular/forms"; -import { RouterModule } from "@angular/router"; - import { ActivitiesCardsComponent } from "@activities/activities-cards/activities-cards.component"; -import { ActivitiesComponent } from "@activities/activities.component"; import { ActivitiesListComponent } from "@activities/activities-list/activities-list.component"; import { ActivitiesRoutingModule } from "@activities/activities-routing.module"; +import { ActivitiesComponent } from "@activities/activities.component"; import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; -import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; import { ActivityService } from "@activities/shared/activity.service"; +import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { FormsModule } from "@angular/forms"; +import { RouterModule } from "@angular/router"; import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.html b/ngapp/src/app/activities/add-activity/add-activity.component.html index b5e62e7f..40204d82 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.html +++ b/ngapp/src/app/activities/add-activity/add-activity.component.html @@ -1,7 +1,7 @@
    -
  • +
  • diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index a2aed000..6f83ea28 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -1,15 +1,14 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; - -import {AddActivityComponent} from './add-activity.component'; +import {AddActivityComponent} from "@activities/add-activity/add-activity.component"; +import {ActivityService} from "@activities/shared/activity.service"; +import {AddActivityFormComponent} from "@activities/shared/add-activity-form/add-activity-form.component"; +import {MockActivityService} from "@activities/shared/mock-activity.service"; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; import {FormsModule} from "@angular/forms"; +import {HttpModule} from "@angular/http"; import {RouterTestingModule} from "@angular/router/testing"; -import {HttpModule} from '@angular/http'; -import {AddActivityFormComponent} from '@activities/shared/add-activity-form/add-activity-form.component'; -import {ActivityService} from '@activities/shared/activity.service'; -import {MockActivityService} from '@activities/shared/mock-activity.service'; import {CoreModule} from "@core/core.module"; -describe('AddActivityComponent', () => { +describe("AddActivityComponent", () => { let component: AddActivityComponent; let fixture: ComponentFixture; @@ -30,7 +29,7 @@ describe('AddActivityComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.ts b/ngapp/src/app/activities/add-activity/add-activity.component.ts index 800d6275..eb38ea96 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.ts @@ -15,27 +15,34 @@ * limitations under the License. */ -import { Component } from '@angular/core'; -import { ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Router } from '@angular/router'; - -import { ActivityService } from '@activities/shared/activity.service'; -import { AddActivityFormComponent } from '@activities/shared/add-activity-form/add-activity-form.component'; -import { NewActivity } from '@activities/shared/new-activity.model'; -import { AbstractPageComponent } from '@shared/abstract-page.component'; +import { activitiesRootPath } from "@activities/activities-routing.module"; +import { ActivityService } from "@activities/shared/activity.service"; +import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; +import { NewActivity } from "@activities/shared/new-activity.model"; +import { Component } from "@angular/core"; +import { ViewChild } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Router } from "@angular/router"; +import { AbstractPageComponent } from "@shared/abstract-page.component"; @Component({ - selector: 'app-add-activity', - templateUrl: './add-activity.component.html', - styleUrls: ['./add-activity.component.css'] + selector: "app-add-activity", + templateUrl: "./add-activity.component.html", + styleUrls: ["./add-activity.component.css"] }) export class AddActivityComponent extends AbstractPageComponent { - @ViewChild(AddActivityFormComponent) form: AddActivityFormComponent; + public activitiesLink = activitiesRootPath; + + private router: Router; + private activityService: ActivityService; + + @ViewChild(AddActivityFormComponent) private form: AddActivityFormComponent; - constructor(private router: Router, route: ActivatedRoute, private activityService: ActivityService) { + constructor(router: Router, route: ActivatedRoute, activityService: ActivityService) { super(route); + this.router = router; + this.activityService = activityService; } /** @@ -43,11 +50,11 @@ export class AddActivityComponent extends AbstractPageComponent { * from the add-activity.page.html template. * @param {NewActivity} activity */ - public onCreateActivity(activity: NewActivity) { - console.log('[AddActivityComponent] onCreateActivity(): ' + JSON.stringify(activity)); + public onCreateActivity(activity: NewActivity): void { + console.log("[AddActivityComponent] onCreateActivity(): " + JSON.stringify(activity)); this.activityService.createActivity(activity); - const link: string[] = [ '/activities' ]; - console.log('[AddActivityComponent] Navigating to: %o', link); + const link: string[] = [ activitiesRootPath ]; + console.log("[AddActivityComponent] Navigating to: %o", link); this.router.navigate(link); } diff --git a/ngapp/src/app/activities/shared/activity.model.ts b/ngapp/src/app/activities/shared/activity.model.ts index 6f6f201a..32d64d14 100644 --- a/ngapp/src/app/activities/shared/activity.model.ts +++ b/ngapp/src/app/activities/shared/activity.model.ts @@ -25,10 +25,10 @@ export class Activity { * @param {Object} json the JSON representation of a Activity * @returns {Activity} the new Activity (never null) */ - public static create( json: Object = {} ) { - const conn = new Activity(); - conn.setValues( json ); - return conn; + public static create( json: Object = {} ): Activity { + const activity = new Activity(); + activity.setValues( json ); + return activity; } constructor() { @@ -81,7 +81,7 @@ export class Activity { * Set all object values using the supplied Activity json * @param {Object} values */ - public setValues(values: Object = {}) { + public setValues(values: Object = {}): void { Object.assign(this, values); } } diff --git a/ngapp/src/app/activities/shared/activity.service.spec.ts b/ngapp/src/app/activities/shared/activity.service.spec.ts index 205583d8..64e8f7e6 100644 --- a/ngapp/src/app/activities/shared/activity.service.spec.ts +++ b/ngapp/src/app/activities/shared/activity.service.spec.ts @@ -1,9 +1,8 @@ -import { TestBed, inject } from '@angular/core/testing'; +import { ActivityService } from "@activities/shared/activity.service"; +import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; -import { ActivityService } from './activity.service'; - -describe('ActivityService', () => { +describe("ActivityService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], @@ -11,7 +10,7 @@ describe('ActivityService', () => { }); }); - it('should be created', inject([ActivityService], (service: ActivityService) => { + it("should be created", inject([ActivityService], (service: ActivityService) => { expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/activities/shared/activity.service.ts b/ngapp/src/app/activities/shared/activity.service.ts index d4cd06ac..cfe999dd 100644 --- a/ngapp/src/app/activities/shared/activity.service.ts +++ b/ngapp/src/app/activities/shared/activity.service.ts @@ -15,45 +15,46 @@ * limitations under the License. */ -import { Injectable } from '@angular/core'; -import { Http } from '@angular/http'; - import { Activity } from "@activities/shared/activity.model"; import { NewActivity } from "@activities/shared/new-activity.model"; +import { Injectable } from "@angular/core"; +import { Http } from "@angular/http"; import { NewConnection } from "@connections/shared/new-connection.model"; import { ApiService } from "@core/api.service"; @Injectable() export class ActivityService extends ApiService { - activity1 = new Activity(); - activity2 = new Activity(); - activity3 = new Activity(); - activities: Activity[] = [this.activity1, this.activity2, this.activity3]; - newActivity1 = new NewActivity(); + private activity1 = new Activity(); + private activity2 = new Activity(); + private activity3 = new Activity(); + private activities: Activity[] = [this.activity1, this.activity2, this.activity3]; + private newActivity1 = new NewActivity(); + private http: Http; - constructor( private http: Http ) { + constructor( http: Http ) { super(); - this.activity1.setId('activity1'); - this.activity1.setSourceConnection('activity1SrcConn'); - this.activity1.setTargetConnection('activity1TgtConn'); - this.activity2.setId('activity2'); - this.activity2.setSourceConnection('activity2SrcConn'); - this.activity2.setTargetConnection('activity2TgtConn'); - this.activity3.setId('activity3'); - this.activity3.setSourceConnection('activity3SrcConn'); - this.activity3.setTargetConnection('activity3TgtConn'); - this.newActivity1.setName('newActivity1'); + this.http = http; + this.activity1.setId("activity1"); + this.activity1.setSourceConnection("activity1SrcConn"); + this.activity1.setTargetConnection("activity1TgtConn"); + this.activity2.setId("activity2"); + this.activity2.setSourceConnection("activity2SrcConn"); + this.activity2.setTargetConnection("activity2TgtConn"); + this.activity3.setId("activity3"); + this.activity3.setSourceConnection("activity3SrcConn"); + this.activity3.setTargetConnection("activity3TgtConn"); + this.newActivity1.setName("newActivity1"); const srcConn = new NewConnection(); - srcConn.setName('new1Src'); - srcConn.setJndiName('new1SrcJndi'); - srcConn.setDriverName('new1SrcDriver'); + srcConn.setName("new1Src"); + srcConn.setJndiName("new1SrcJndi"); + srcConn.setDriverName("new1SrcDriver"); srcConn.setJdbc(true); this.newActivity1.setSourceConnection(srcConn); const tgtConn = new NewConnection(); - tgtConn.setName('new1Tgt'); - tgtConn.setJndiName('new1TgtJndi'); - tgtConn.setDriverName('new1TgtDriver'); + tgtConn.setName("new1Tgt"); + tgtConn.setJndiName("new1TgtJndi"); + tgtConn.setDriverName("new1TgtDriver"); tgtConn.setJdbc(false); this.newActivity1.setTargetConnection(tgtConn); } @@ -66,7 +67,7 @@ export class ActivityService extends ApiService { return this.activities; /* return this.http - .get(KOMODO_WORKSPACE_URL + '/activities', this.getAuthRequestOptions()) + .get(komodoWorkspaceUrl + '/activities', this.getAuthRequestOptions()) .map(response => { const activities = response.json(); return activities.map((activity) => {const activ = new Activity(); activ.setValues(activity); return activ; }); @@ -81,10 +82,11 @@ export class ActivityService extends ApiService { * @returns {Activity} */ public createActivity(activity: NewActivity): NewActivity { + // TODO implement createActivity() return this.newActivity1; /* return this.http - .post(KOMODO_WORKSPACE_URL + '/activities/' + activity.name, activity, this.getAuthRequestOptions()) + .post(komodoWorkspaceUrl + '/activities/' + activity.name, activity, this.getAuthRequestOptions()) .map(response => { return new Activity(); }) @@ -97,9 +99,10 @@ export class ActivityService extends ApiService { * @param {NewActivity} activity */ public deleteActivity(activity: NewActivity): NewActivity { + // TODO implement deleteActivity() /* return this.http - .delete(KOMODO_WORKSPACE_URL + '/activities/' + activity.name, this.getAuthRequestOptions()) + .doDelete(komodoWorkspaceUrl + '/activities/' + activity.name, this.getAuthRequestOptions()) .map(response => null) .catch(this.handleError); */ diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.html b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.html index 352c982a..2344a4ec 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.html +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.html @@ -5,25 +5,25 @@

    Activity Properties

    - +
    - +
    - +
    - +

    diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts index ff795e1c..b97472f0 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts @@ -1,11 +1,10 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; -import { RouterTestingModule } from '@angular/router/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; +import { RouterTestingModule } from "@angular/router/testing"; +import { CoreModule } from "@core/core.module"; +import { AddActivityFormComponent } from "./add-activity-form.component"; -import { AddActivityFormComponent } from './add-activity-form.component'; -import { CoreModule } from '@core/core.module'; - -describe('AddActivityFormComponent', () => { +describe("AddActivityFormComponent", () => { let component: AddActivityFormComponent; let fixture: ComponentFixture; @@ -23,7 +22,7 @@ describe('AddActivityFormComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts index 444a3521..a32a1777 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts @@ -15,32 +15,62 @@ * limitations under the License. */ -import { Component } from '@angular/core'; -import { EventEmitter } from '@angular/core'; -import { OnInit } from '@angular/core'; -import { Output } from '@angular/core'; -import { Router } from '@angular/router'; - -import { NewActivity } from '@activities/shared/new-activity.model'; +import { activitiesRootPath } from "@activities/activities-routing.module"; +import { NewActivity } from "@activities/shared/new-activity.model"; +import { Component } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { Output } from "@angular/core"; +import { Router } from "@angular/router"; +import { NewConnection } from "@connections/shared/new-connection.model"; @Component({ - selector: 'app-add-activity-form', - templateUrl: './add-activity-form.component.html', - styleUrls: ['./add-activity-form.component.css'] + selector: "app-add-activity-form", + templateUrl: "./add-activity-form.component.html", + styleUrls: ["./add-activity-form.component.css"] }) -export class AddActivityFormComponent implements OnInit { +export class AddActivityFormComponent { - @Output() onCreateActivity = new EventEmitter(); + private model = new NewActivity(); + private creatingActivity = false; + private router: Router; - model = new NewActivity(); - creatingActivity = false; + @Output() private onCreateActivity = new EventEmitter(); - constructor( private router: Router ) { } + constructor( router: Router ) { + this.router = router; + } - ngOnInit() { + /** + * @returns {string} the activity description + */ + public get activityDescription(): string { + return this.model.getDescription(); } - get currentActivity() { return JSON.stringify(this.model); } + /** + * @returns {string} the activity name + */ + public get activityName(): string { + return this.model.getName(); + } + + /** + * @returns {string} the activity's source connection + */ + public get activitySource(): NewConnection { + return this.model.getSourceConnection(); + } + + /** + * @returns {string} the activity's target connection + */ + public get activityTarget(): NewConnection { + return this.model.getTargetConnection(); + } + + public get currentActivity(): string { + return JSON.stringify(this.model); + } /** * Called when the user clicks the "Create Activity" submit button on the form. @@ -52,14 +82,14 @@ export class AddActivityFormComponent implements OnInit { activity.setSourceConnection(this.model.getSourceConnection()); activity.setTargetConnection(this.model.getTargetConnection()); - console.log('[AddActivityFormComponent] Firing create-activity event: %o', activity); + console.log("[AddActivityFormComponent] Firing create-activity event: %o", activity); this.creatingActivity = true; this.onCreateActivity.emit(activity); } public cancelAdd(): void { - const link: string[] = [ '/activities' ]; + const link: string[] = [ activitiesRootPath ]; this.router.navigate(link); } diff --git a/ngapp/src/app/activities/shared/mock-activity.service.ts b/ngapp/src/app/activities/shared/mock-activity.service.ts index d65d62bf..a983c80a 100644 --- a/ngapp/src/app/activities/shared/mock-activity.service.ts +++ b/ngapp/src/app/activities/shared/mock-activity.service.ts @@ -1,57 +1,56 @@ -import {Injectable } from '@angular/core'; -import {environment } from '../../../environments/environment'; -import {Http} from '@angular/http'; -import {Activity } from '@activities/shared/activity.model'; -import {NewActivity } from '@activities/shared/new-activity.model'; -import {Connection} from '@connections/shared/connection.model'; -import {NewConnection} from '@connections/shared/new-connection.model'; -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/throw'; -import 'rxjs/add/observable/of'; - -const KOMODO_WORKSPACE_URL = environment.komodoWorkspaceUrl; +import {Activity } from "@activities/shared/activity.model"; +import {NewActivity } from "@activities/shared/new-activity.model"; +import {Injectable } from "@angular/core"; +import {Http} from "@angular/http"; +import {Connection} from "@connections/shared/connection.model"; +import {NewConnection} from "@connections/shared/new-connection.model"; +import "rxjs/add/observable/of"; +import "rxjs/add/observable/throw"; +import "rxjs/add/operator/catch"; +import "rxjs/add/operator/map"; @Injectable() export class MockActivityService { - activity1 = new Activity(); - activity2 = new Activity(); - activity3 = new Activity(); - activities: Activity[] = [this.activity1, this.activity2, this.activity3]; - newActivity1 = new NewActivity(); + private activity1 = new Activity(); + private activity2 = new Activity(); + private activity3 = new Activity(); + private activities: Activity[] = [this.activity1, this.activity2, this.activity3]; + private newActivity1 = new NewActivity(); + + private newConnection = new NewConnection(); + private conn1 = new Connection(); + private conn2 = new Connection(); + private conn3 = new Connection(); + private conns: Connection[] = [this.conn1, this.conn2, this.conn3]; - newConnection = new NewConnection(); - conn1 = new Connection(); - conn2 = new Connection(); - conn3 = new Connection(); - conns: Connection[] = [this.conn1, this.conn2, this.conn3]; + private http: Http; - constructor( private http: Http ) { - this.activity1.setId('activity1'); - this.activity1.setSourceConnection('activity1SrcConn'); - this.activity1.setTargetConnection('activity1TgtConn'); - this.activity2.setId('activity2'); - this.activity2.setSourceConnection('activity2SrcConn'); - this.activity2.setTargetConnection('activity2TgtConn'); - this.activity3.setId('activity3'); - this.activity3.setSourceConnection('activity3SrcConn'); - this.activity3.setTargetConnection('activity3TgtConn'); - this.newActivity1.setName('newActivity1'); + constructor( http: Http ) { + this.http = http; + this.activity1.setId("activity1"); + this.activity1.setSourceConnection("activity1SrcConn"); + this.activity1.setTargetConnection("activity1TgtConn"); + this.activity2.setId("activity2"); + this.activity2.setSourceConnection("activity2SrcConn"); + this.activity2.setTargetConnection("activity2TgtConn"); + this.activity3.setId("activity3"); + this.activity3.setSourceConnection("activity3SrcConn"); + this.activity3.setTargetConnection("activity3TgtConn"); + this.newActivity1.setName("newActivity1"); const srcConn = new NewConnection(); - srcConn.setName('new1Src'); - srcConn.setJndiName('new1SrcJndi'); - srcConn.setDriverName('new1SrcDriver'); + srcConn.setName("new1Src"); + srcConn.setJndiName("new1SrcJndi"); + srcConn.setDriverName("new1SrcDriver"); srcConn.setJdbc(true); this.newActivity1.setSourceConnection(srcConn); const tgtConn = new NewConnection(); - tgtConn.setName('new1Tgt'); - tgtConn.setJndiName('new1TgtJndi'); - tgtConn.setDriverName('new1TgtDriver'); + tgtConn.setName("new1Tgt"); + tgtConn.setJndiName("new1TgtJndi"); + tgtConn.setDriverName("new1TgtDriver"); tgtConn.setJdbc(false); this.newActivity1.setTargetConnection(tgtConn); - } /** diff --git a/ngapp/src/app/activities/shared/new-activity.model.ts b/ngapp/src/app/activities/shared/new-activity.model.ts index ffa4abbf..925a81db 100644 --- a/ngapp/src/app/activities/shared/new-activity.model.ts +++ b/ngapp/src/app/activities/shared/new-activity.model.ts @@ -15,14 +15,14 @@ * limitations under the License. */ -import { NewConnection } from '@connections/shared/new-connection.model'; +import { NewConnection } from "@connections/shared/new-connection.model"; export class NewActivity { - name: string; - description: string; - sourceConnection: NewConnection = new NewConnection(); - targetConnection: NewConnection = new NewConnection(); + private name: string; + private description: string; + private sourceConnection: NewConnection = new NewConnection(); + private targetConnection: NewConnection = new NewConnection(); /** * Constructor @@ -88,7 +88,7 @@ export class NewActivity { } // overrides toJSON - we do not want the name supplied in the json body. - public toJSON() { + public toJSON(): {} { return { sourceConnection: this.sourceConnection, targetConnection: this.targetConnection diff --git a/ngapp/src/app/app-routing.module.ts b/ngapp/src/app/app-routing.module.ts index b1d13da5..64b486da 100644 --- a/ngapp/src/app/app-routing.module.ts +++ b/ngapp/src/app/app-routing.module.ts @@ -15,18 +15,19 @@ * limitations under the License. */ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { Routes } from '@angular/router'; - -import { environment } from '@environments/environment'; +import { activitiesRootPath } from "@activities/activities-routing.module"; +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { Routes } from "@angular/router"; +import { connectionsRootPath } from "@connections/connections-routing.module"; +import { environment } from "@environments/environment"; import { PageNotFoundComponent } from "@shared/page-not-found/page-not-found.component"; const appRoutes: Routes = [ - {path: '', redirectTo: environment.homePagePath, pathMatch: 'full'}, - {path: 'connections', loadChildren: '@connections/connections.module#ConnectionsModule'}, - {path: 'activities', loadChildren: '@activities/activities.module#ActivitiesModule'}, - { path: '**', component: PageNotFoundComponent }, // always last + { path: "", redirectTo: environment.homePagePath, pathMatch: "full" }, + { path: connectionsRootPath, loadChildren: "@connections/connections.module#ConnectionsModule" }, + { path: activitiesRootPath, loadChildren: "@activities/activities.module#ActivitiesModule" }, + { path: "**", component: PageNotFoundComponent }, // always last ]; @NgModule({ diff --git a/ngapp/src/app/app.component.spec.ts b/ngapp/src/app/app.component.spec.ts index e5406172..184f0bbf 100644 --- a/ngapp/src/app/app.component.spec.ts +++ b/ngapp/src/app/app.component.spec.ts @@ -1,10 +1,9 @@ -import { TestBed, async } from '@angular/core/testing'; - -import { AppComponent } from './app.component'; +import { async, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; import { CoreModule } from "@core/core.module"; +import { AppComponent } from "./app.component"; -describe('AppComponent', () => { +describe("AppComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ CoreModule, RouterTestingModule ], @@ -14,7 +13,7 @@ describe('AppComponent', () => { }).compileComponents(); })); - it('should create the app', async(() => { + it("should create the app", async(() => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; expect(app).toBeTruthy(); diff --git a/ngapp/src/app/app.component.ts b/ngapp/src/app/app.component.ts index 97b98638..3cdf875a 100644 --- a/ngapp/src/app/app.component.ts +++ b/ngapp/src/app/app.component.ts @@ -1,21 +1,35 @@ -import { Component, OnInit } from '@angular/core'; +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from "@angular/core"; @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] + selector: "app-root", + templateUrl: "./app.component.html", + styleUrls: ["./app.component.css"] }) -export class AppComponent implements OnInit { +export class AppComponent { - routerOutletWrapperId: string; - routerOutletWrapperClass: string; + private routerOutletWrapperId: string; + private routerOutletWrapperClass: string; constructor() { - this.routerOutletWrapperId = 'studio-page-body'; - this.routerOutletWrapperClass = ''; - } - - ngOnInit() { + this.routerOutletWrapperId = "studio-page-body"; + this.routerOutletWrapperClass = ""; } } diff --git a/ngapp/src/app/app.module.ts b/ngapp/src/app/app.module.ts index 86be24d4..f1acc022 100644 --- a/ngapp/src/app/app.module.ts +++ b/ngapp/src/app/app.module.ts @@ -15,16 +15,15 @@ * limitations under the License. */ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; -import { RouterModule } from "@angular/router"; - -import { ActivitiesModule } from "@activities/activities.module"; import { ActivitiesRoutingModule } from "@activities/activities-routing.module"; -import { AppComponent } from '@app/app.component'; +import { ActivitiesModule } from "@activities/activities.module"; +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { RouterModule } from "@angular/router"; import { AppRoutingModule } from "@app/app-routing.module"; -import { ConnectionsModule } from "@connections/connections.module"; +import { AppComponent } from "@app/app.component"; import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; +import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index aa99c374..f3a8c469 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -1,7 +1,7 @@
    -
  • +
  • diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 0e58c22e..ad0ca88c 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -1,15 +1,14 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import {RouterTestingModule} from '@angular/router/testing'; - -import {AddConnectionComponent} from './add-connection.component'; -import {AddConnectionFormComponent} from "@connections/shared/add-connection-form/add-connection-form.component"; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; import {FormsModule} from "@angular/forms"; +import {HttpModule} from "@angular/http"; +import {RouterTestingModule} from "@angular/router/testing"; +import {AddConnectionFormComponent} from "@connections/shared/add-connection-form/add-connection-form.component"; import {ConnectionService} from "@connections/shared/connection.service"; import {MockConnectionService} from "@connections/shared/mock-connection.service"; -import {HttpModule} from "@angular/http"; import {CoreModule} from "@core/core.module"; +import {AddConnectionComponent} from "./add-connection.component"; -describe('AddConnectionComponent', () => { +describe("AddConnectionComponent", () => { let component: AddConnectionComponent; let fixture: ComponentFixture; @@ -30,7 +29,7 @@ describe('AddConnectionComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ngapp/src/app/connections/add-connection/add-connection.component.ts index a1f093cc..2fbbf50e 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.ts @@ -15,27 +15,34 @@ * limitations under the License. */ -import { Component } from '@angular/core'; -import { ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Router } from '@angular/router'; - -import { AddConnectionFormComponent } from '@connections/shared/add-connection-form/add-connection-form.component'; -import { ConnectionService } from '@connections/shared/connection.service'; -import { NewConnection } from '@connections/shared/new-connection.model'; -import { AbstractPageComponent } from '@shared/abstract-page.component'; +import { Component } from "@angular/core"; +import { ViewChild } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Router } from "@angular/router"; +import { addConnectionPath, connectionsRootPath } from "@connections/connections-routing.module"; +import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { NewConnection } from "@connections/shared/new-connection.model"; +import { AbstractPageComponent } from "@shared/abstract-page.component"; @Component({ - selector: 'app-add-connection', - templateUrl: './add-connection.component.html', - styleUrls: ['./add-connection.component.css'] + selector: "app-add-connection", + templateUrl: "./add-connection.component.html", + styleUrls: ["./add-connection.component.css"] }) export class AddConnectionComponent extends AbstractPageComponent { - @ViewChild(AddConnectionFormComponent) form: AddConnectionFormComponent; + public addConnectionLink = addConnectionPath; + + private router: Router; + private connectionService: ConnectionService; + + @ViewChild(AddConnectionFormComponent) private form: AddConnectionFormComponent; - constructor(private router: Router, route: ActivatedRoute, private apiService: ConnectionService) { + constructor(router: Router, route: ActivatedRoute, connectionService: ConnectionService) { super(route); + this.router = router; + this.connectionService = connectionService; } /** @@ -43,15 +50,15 @@ export class AddConnectionComponent extends AbstractPageComponent { * from the add-connection.page.html template. * @param {NewConnection} connection */ - public onCreateConnection(connection: NewConnection) { - console.log('[AddConnectionComponent] onCreateConnection(): ' + JSON.stringify(connection)); - this.apiService + public onCreateConnection(connection: NewConnection): void { + console.log("[AddConnectionComponent] onCreateConnection(): " + JSON.stringify(connection)); + this.connectionService .createConnection(connection) .subscribe( () => { - this.form.creatingConnection = false; - const link: string[] = [ '/connections' ]; - console.log('[AddConnectionComponent] Navigating to: %o', link); + this.form.connectionCreated(); + const link: string[] = [ connectionsRootPath ]; + console.log("[AddConnectionComponent] Navigating to: %o", link); this.router.navigate(link); } ); diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts index 9745eec4..555d014f 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts @@ -1,9 +1,8 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; -import { ConnectionsCardsComponent } from './connections-cards.component'; - -describe('ConnectionsCardsComponent', () => { +describe("ConnectionsCardsComponent", () => { let component: ConnectionsCardsComponent; let fixture: ComponentFixture; @@ -21,7 +20,7 @@ describe('ConnectionsCardsComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts index f988bd7c..dc4f2bff 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts @@ -15,31 +15,32 @@ * limitations under the License. */ -import { Component, EventEmitter, Output, Input } from '@angular/core'; - -import { Connection } from '@connections/shared/connection.model'; +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; @Component({ moduleId: module.id, - selector: 'app-connections-cards', - templateUrl: 'connections-cards.component.html', - styleUrls: ['connections-cards.component.css'] + selector: "app-connections-cards", + templateUrl: "connections-cards.component.html", + styleUrls: ["connections-cards.component.css"] }) export class ConnectionsCardsComponent { - @Input() connections: Connection[]; - @Input() selectedConnections: Connection[]; - @Output() onConnectionSelected: EventEmitter = new EventEmitter(); - @Output() onConnectionDeselected: EventEmitter = new EventEmitter(); - @Output() onTagSelected: EventEmitter = new EventEmitter(); - @Output() onPingConnection: EventEmitter = new EventEmitter(); - @Output() onEditConnection: EventEmitter = new EventEmitter(); - @Output() onDeleteConnection: EventEmitter = new EventEmitter(); + @Input() private connections: Connection[]; + @Input() private selectedConnections: Connection[]; + @Output() private onConnectionSelected: EventEmitter = new EventEmitter(); + @Output() private onConnectionDeselected: EventEmitter = new EventEmitter(); + @Output() private onTagSelected: EventEmitter = new EventEmitter(); + @Output() private onPingConnection: EventEmitter = new EventEmitter(); + @Output() private onEditConnection: EventEmitter = new EventEmitter(); + @Output() private onDeleteConnection: EventEmitter = new EventEmitter(); /** * Constructor. */ - constructor() {} + constructor() { + // nothing to do + } public toggleConnectionSelected(connection: Connection): void { if (this.isSelected(connection)) { diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts index b754d8d4..60c27bf5 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts +++ b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts @@ -1,9 +1,8 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; -import { ConnectionsListComponent } from './connections-list.component'; -import { RouterTestingModule } from '@angular/router/testing'; - -describe('ConnectionsListComponent', () => { +describe("ConnectionsListComponent", () => { let component: ConnectionsListComponent; let fixture: ComponentFixture; @@ -21,7 +20,7 @@ describe('ConnectionsListComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.ts b/ngapp/src/app/connections/connections-list/connections-list.component.ts index e37a5cfe..15869b84 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.ts +++ b/ngapp/src/app/connections/connections-list/connections-list.component.ts @@ -15,32 +15,35 @@ * limitations under the License. */ -import { Component, EventEmitter, Output, Input } from '@angular/core'; -import { Router } from '@angular/router'; - -import { Connection } from '@connections/shared/connection.model'; +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { Router } from "@angular/router"; +import { Connection } from "@connections/shared/connection.model"; @Component({ moduleId: module.id, - selector: 'app-connections-list', - templateUrl: 'connections-list.component.html', - styleUrls: ['connections-list.component.css'] + selector: "app-connections-list", + templateUrl: "connections-list.component.html", + styleUrls: ["connections-list.component.css"] }) export class ConnectionsListComponent { - @Input() connections: Connection[]; - @Input() selectedConnections: Connection[]; - @Output() onConnectionSelected: EventEmitter = new EventEmitter(); - @Output() onConnectionDeselected: EventEmitter = new EventEmitter(); - @Output() onTagSelected: EventEmitter = new EventEmitter(); - @Output() onEditConnection: EventEmitter = new EventEmitter(); - @Output() onPingConnection: EventEmitter = new EventEmitter(); - @Output() onDeleteConnection: EventEmitter = new EventEmitter(); + private router: Router; + + @Input() private connections: Connection[]; + @Input() private selectedConnections: Connection[]; + @Output() private onConnectionSelected: EventEmitter = new EventEmitter(); + @Output() private onConnectionDeselected: EventEmitter = new EventEmitter(); + @Output() private onTagSelected: EventEmitter = new EventEmitter(); + @Output() private onEditConnection: EventEmitter = new EventEmitter(); + @Output() private onPingConnection: EventEmitter = new EventEmitter(); + @Output() private onDeleteConnection: EventEmitter = new EventEmitter(); /** * Constructor. */ - constructor(private router: Router) {} + constructor(router: Router) { + this.router = router; + } public toggleConnectionSelected(connection: Connection): void { if (this.isSelected(connection)) { diff --git a/ngapp/src/app/connections/connections-routing.module.ts b/ngapp/src/app/connections/connections-routing.module.ts index 4fb13f12..643674f0 100644 --- a/ngapp/src/app/connections/connections-routing.module.ts +++ b/ngapp/src/app/connections/connections-routing.module.ts @@ -15,18 +15,21 @@ * limitations under the License. */ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { Routes } from '@angular/router'; - +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { Routes } from "@angular/router"; import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; import { ConnectionsComponent } from "@connections/connections.component"; import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; +export const connectionsRootPath = "/connections"; +export const addConnectionPath = connectionsRootPath + "/add-connection"; +export const editConnectionPath = connectionsRootPath + "/edit-connection"; + const connectionsRoutes: Routes = [ - { path: 'connections', component: ConnectionsComponent }, - { path: 'connections/add-connection', component: AddConnectionComponent }, - { path: 'connections/edit-connection', component: EditConnectionComponent } + { path: connectionsRootPath, component: ConnectionsComponent }, + { path: addConnectionPath, component: AddConnectionComponent }, + { path: editConnectionPath, component: EditConnectionComponent } ]; @NgModule({ diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index e07c0dc0..24826296 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -18,22 +18,22 @@

    Connections

    - +
      -
    • -
    • +
    • +
    @@ -60,7 +60,7 @@

    No Connections Found

    @@ -79,7 +79,7 @@

    No Connections Found

    -

    Loading Connections...

    + Loading Connections...

    @@ -89,10 +89,10 @@

    - -
    diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index ab0c2062..c7c8aca4 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -1,16 +1,15 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; - -import {ConnectionsComponent} from './connections.component'; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; import {FormsModule} from "@angular/forms"; +import {HttpModule} from "@angular/http"; import {RouterTestingModule} from "@angular/router/testing"; -import {ConnectionsListComponent} from "@connections/connections-list/connections-list.component"; import {ConnectionsCardsComponent} from "@connections/connections-cards/connections-cards.component"; -import {ModalModule} from "ngx-bootstrap"; -import {HttpModule} from "@angular/http"; +import {ConnectionsListComponent} from "@connections/connections-list/connections-list.component"; +import {ConnectionsComponent} from "@connections/connections.component"; import {CoreModule} from "@core/core.module"; import {SharedModule} from "@shared/shared.module"; +import {ModalModule} from "ngx-bootstrap"; -describe('ConnectionsComponent', () => { +describe("ConnectionsComponent", () => { let component: ConnectionsComponent; let fixture: ComponentFixture; @@ -28,7 +27,7 @@ describe('ConnectionsComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 5baecb01..c10b07eb 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -15,75 +15,58 @@ * limitations under the License. */ -import { Component, ViewChild } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; - -import { AbstractPageComponent } from '@shared/abstract-page.component'; -import { ArrayUtils } from '@core/common'; -import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { Component, ViewChild } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { addConnectionPath, connectionsRootPath, editConnectionPath } from "@connections/connections-routing.module"; import { Connection } from "@connections/shared/connection.model"; -import { ConnectionService } from '@connections/shared/connection.service'; -import { NewConnection } from '@connections/shared/new-connection.model'; - -class Filters { - nameFilter: string; - sortDirection: string; - layout: string; - - constructor(params?: any) { - this.reset(); - if (params) { - for (const key of Object.keys(params)) { - const value: string = params[key]; - this[key] = value; - } - } - } - - public accepts(connection: Connection): boolean { - const name: string = connection.getId().toLocaleLowerCase(); - const namef: string = this.nameFilter.toLocaleLowerCase(); - return name.indexOf(namef) >= 0; - } - - public reset(): void { - this.nameFilter = ''; - this.sortDirection = 'ASC'; - this.layout = 'card'; - } -} +import { ConnectionService } from "@connections/shared/connection.service"; +import { NewConnection } from "@connections/shared/new-connection.model"; +import { ArrayUtils } from "@core/utils/array-utils"; +import { AbstractPageComponent } from "@shared/abstract-page.component"; +import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { IdFilter } from "@shared/id-filter"; +import { LayoutType } from "@shared/layout-type.enum"; +import { SortDirection } from "@shared/sort-direction.enum"; @Component({ - selector: 'app-connections', - templateUrl: './connections.component.html', - styleUrls: ['./connections.component.css'], + selector: "app-connections", + templateUrl: "./connections.component.html", + styleUrls: ["./connections.component.css"], providers: [ConnectionService] }) export class ConnectionsComponent extends AbstractPageComponent { - allConnections: Connection[] = []; - filteredConnections: Connection[] = []; - selectedConnections: Connection[] = []; - filters: Filters = new Filters(); + public addConnectionLink: string = addConnectionPath; + + private allConnections: Connection[] = []; + private filteredConnections: Connection[] = []; + private selectedConnections: Connection[] = []; private connectionNameForDelete: string; + private router: Router; + private connectionService: ConnectionService; + private filter: IdFilter = new IdFilter(); + private layout: LayoutType = LayoutType.CARD; + private sortDirection: SortDirection; - @ViewChild(ConfirmDeleteComponent) confirmDeleteDialog: ConfirmDeleteComponent; + @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; - constructor(private router: Router, route: ActivatedRoute, private connectionService: ConnectionService) { + constructor(router: Router, route: ActivatedRoute, connectionService: ConnectionService) { super(route); + this.router = router; + this.connectionService = connectionService; } - public loadAsyncPageData() { + public loadAsyncPageData(): void { this.connectionService .getAllConnections() .subscribe( (connections) => { this.allConnections = connections; this.filteredConnections = this.filterConnections(); - this.loaded('connections'); + this.loaded("connections"); }, (error) => { - console.error('[ConnectionsComponent] Error getting connections.'); + console.error("[ConnectionsComponent] Error getting connections."); this.error(error); } ); @@ -96,13 +79,13 @@ export class ConnectionsComponent extends AbstractPageComponent { // Clear the array first. this.filteredConnections.splice(0, this.filteredConnections.length); for (const connection of this.allConnections) { - if (this.filters.accepts(connection)) { + if (this.filter.accepts(connection)) { this.filteredConnections.push(connection); } } this.filteredConnections.sort( (c1: Connection, c2: Connection) => { let rval: number = c1.getId().localeCompare(c2.getId()); - if (this.filters.sortDirection === 'DESC') { + if (this.sortDirection === SortDirection.DESC) { rval *= -1; } return rval; @@ -113,6 +96,52 @@ export class ConnectionsComponent extends AbstractPageComponent { return this.filteredConnections; } + /** + * @returns {boolean} true if connections are being represented by cards + */ + public get isCardLayout(): boolean { + return this.layout === LayoutType.CARD; + } + + /** + * @returns {boolean} true if connections are being represented by items in a list + */ + public get isListLayout(): boolean { + return this.layout === LayoutType.LIST; + } + + /** + * @returns {boolean} true if sorting connection names in ascending order + */ + public get isSortAscending(): boolean { + return this.sortDirection === SortDirection.ASC; + } + + /** + * @returns {boolean} true if sorting connection names in descending order + */ + public get isSortDescending(): boolean { + return this.sortDirection === SortDirection.DESC; + } + + /** + * @returns {string} the pattern the connection names are being matched to (can be null or empty) + */ + public get nameFilter(): string { + return this.filter.getPattern(); + } + + /** + * @param {string} pattern the new pattern for the connection name filter (can be null or empty) + */ + public set nameFilter( pattern: string ) { + this.filter.setFilter( pattern ); + } + + public onPing( connName: string): void { + alert("Ping connection " + connName); + } + public onSelected(connection: Connection): void { // Only allow one item to be selected this.selectedConnections.shift(); @@ -126,7 +155,7 @@ export class ConnectionsComponent extends AbstractPageComponent { } public onEdit(connName: string): void { - const link: string[] = [ '/connections/edit-connection' ]; + const link: string[] = [ editConnectionPath ]; this.router.navigate(link); } @@ -135,41 +164,37 @@ export class ConnectionsComponent extends AbstractPageComponent { this.confirmDeleteDialog.open(); } - public onPing(connName: string): void { - alert('Ping connection ' + connName); - } - public isFiltered(): boolean { return this.allConnections.length !== this.filteredConnections.length; } public toggleSortDirection(): void { - if (this.filters.sortDirection === 'ASC') { - this.filters.sortDirection = 'DESC'; + if (this.sortDirection === SortDirection.ASC) { + this.sortDirection = SortDirection.DESC; } else { - this.filters.sortDirection = 'ASC'; + this.sortDirection = SortDirection.ASC; } this.filterConnections(); } public clearFilters(): void { - this.filters.nameFilter = ''; + this.filter.reset(); this.filterConnections(); } public onListLayout(): void { - this.filters.layout = 'list'; + this.layout = LayoutType.LIST; } public onCardLayout(): void { - this.filters.layout = 'card'; + this.layout = LayoutType.CARD; } /** - * Called to delete all selected APIs. + * Called to doDelete all selected APIs. */ public deleteConnection(): void { - const selectedConn = this.filterConnections().find(x => x.getId() === this.connectionNameForDelete); + const selectedConn = this.filterConnections().find((x) => x.getId() === this.connectionNameForDelete); // const itemsToDelete: Connection[] = ArrayUtils.intersect(this.selectedConnections, this.filteredConnections); // const selectedConn = itemsToDelete[0]; @@ -177,21 +202,21 @@ export class ConnectionsComponent extends AbstractPageComponent { const connectionToDelete: NewConnection = new NewConnection(); connectionToDelete.setName(selectedConn.getId()); - // Note: we can only delete selected items that we can see in the UI. - console.log('[ConnectionsPageComponent] Deleting selected Connection.'); + // Note: we can only doDelete selected items that we can see in the UI. + console.log("[ConnectionsPageComponent] Deleting selected Connection."); this.connectionService .deleteConnection(connectionToDelete) .subscribe( () => { this.removeConnectionFromList(selectedConn); - const link: string[] = [ '/connections' ]; - console.log('[CreateApiPageComponent] Navigating to: %o', link); + const link: string[] = [ connectionsRootPath ]; + console.log("[CreateApiPageComponent] Navigating to: %o", link); this.router.navigate(link); } ); } - private removeConnectionFromList(connection: Connection) { + private removeConnectionFromList(connection: Connection): void { this.allConnections.splice(this.allConnections.indexOf(connection), 1); this.filterConnections(); } diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 03de83c6..b2eea625 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -15,20 +15,19 @@ * limitations under the License. */ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; import { FormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; - import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; -import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; -import { ConnectionsComponent } from "@connections/connections.component"; import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; +import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; +import { ConnectionsComponent } from "@connections/connections.component"; import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; -import { CoreModule } from "@core/core.module"; +import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; import { ConnectionService } from "@connections/shared/connection.service"; -import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; +import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; @NgModule({ diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.html b/ngapp/src/app/connections/edit-connection/edit-connection.component.html index 44784a3d..37e19af2 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.html +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.html @@ -1,7 +1,7 @@
    -
  • +
  • diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts index 61909809..afb364b1 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts @@ -1,13 +1,12 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; - -import {EditConnectionComponent} from './edit-connection.component'; -import {RouterTestingModule} from '@angular/router/testing'; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {HttpModule} from "@angular/http"; +import {RouterTestingModule} from "@angular/router/testing"; import {ConnectionService} from "@connections/shared/connection.service"; import {MockConnectionService} from "@connections/shared/mock-connection.service"; -import {HttpModule} from "@angular/http"; import {CoreModule} from "@core/core.module"; +import {EditConnectionComponent} from "./edit-connection.component"; -describe('EditConnectionComponent', () => { +describe("EditConnectionComponent", () => { let component: EditConnectionComponent; let fixture: ComponentFixture; @@ -28,7 +27,7 @@ describe('EditConnectionComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.ts index c49d6800..807a6c74 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.ts +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.ts @@ -15,25 +15,32 @@ * limitations under the License. */ -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Router } from '@angular/router'; - -import { NewConnection } from '@connections/shared/new-connection.model'; -import { ConnectionService } from '@connections/shared/connection.service'; -import { AbstractPageComponent } from '@shared/abstract-page.component'; +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { Router } from "@angular/router"; +import { connectionsRootPath } from "@connections/connections-routing.module"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { NewConnection } from "@connections/shared/new-connection.model"; +import { AbstractPageComponent } from "@shared/abstract-page.component"; @Component({ - selector: 'app-edit-connection', - templateUrl: './edit-connection.component.html', - styleUrls: ['./edit-connection.component.css'] + selector: "app-edit-connection", + templateUrl: "./edit-connection.component.html", + styleUrls: ["./edit-connection.component.css"] }) export class EditConnectionComponent extends AbstractPageComponent { + public connectionsLink = connectionsRootPath; + + private router: Router; + private connectionService: ConnectionService; + // @ViewChild(AddConnectionFormComponent) form: AddConnectionFormComponent; - constructor(private router: Router, route: ActivatedRoute, private connectionService: ConnectionService) { + constructor(router: Router, route: ActivatedRoute, connectionService: ConnectionService) { super(route); + this.router = router; + this.connectionService = connectionService; } /** diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html index 0c42ee26..05e92068 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html @@ -5,25 +5,25 @@

    Connection Properties

    - +
    - +
    - +
    - +

    @@ -39,4 +39,5 @@

    Connection Properties

    +

    diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts index c2e10619..2f52da6d 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts @@ -1,10 +1,9 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {FormsModule} from "@angular/forms"; +import {RouterTestingModule} from "@angular/router/testing"; +import {AddConnectionFormComponent} from "./add-connection-form.component"; -import {FormsModule} from '@angular/forms'; -import {AddConnectionFormComponent} from './add-connection-form.component'; -import {RouterTestingModule} from '@angular/router/testing'; - -describe('AddConnectionFormComponent', () => { +describe("AddConnectionFormComponent", () => { let component: AddConnectionFormComponent; let fixture: ComponentFixture; @@ -22,7 +21,7 @@ describe('AddConnectionFormComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts index 5ebdd104..126a0da2 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts @@ -15,29 +15,31 @@ * limitations under the License. */ -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; -import { Router } from '@angular/router'; - -import { NewConnection } from '@connections/shared/new-connection.model'; +import { Component, EventEmitter, Output } from "@angular/core"; +import { Router } from "@angular/router"; +import { connectionsRootPath } from "@connections/connections-routing.module"; +import { NewConnection } from "@connections/shared/new-connection.model"; @Component({ - selector: 'app-add-connection-form', - templateUrl: './add-connection-form.component.html', - styleUrls: ['./add-connection-form.component.css'] + selector: "app-add-connection-form", + templateUrl: "./add-connection-form.component.html", + styleUrls: ["./add-connection-form.component.css"] }) -export class AddConnectionFormComponent implements OnInit { - - @Output() onCreateConnection = new EventEmitter(); +export class AddConnectionFormComponent { - model = new NewConnection(); - creatingConnection = false; + private creatingConnection = false; + private model = new NewConnection(); + private router: Router; - constructor( private router: Router ) { } + @Output() private onCreateConnection = new EventEmitter(); - ngOnInit() { + constructor( router: Router ) { + this.router = router; } - get currentConnection() { return JSON.stringify(this.model); } + public currentConnection(): string { + return JSON.stringify(this.model); + } /** * Called when the user clicks the "Create Connection" submit button on the form. @@ -49,15 +51,21 @@ export class AddConnectionFormComponent implements OnInit { connection.setDriverName(this.model.getDriverName()); connection.setJdbc(this.model.isJdbc()); - console.log('[AddConnectionFormComponent] Firing create-connection event: %o', connection); + console.log("[AddConnectionFormComponent] Firing create-connection event: %o", connection); this.creatingConnection = true; this.onCreateConnection.emit(connection); } public cancelAdd(): void { - const link: string[] = [ '/connections' ]; + const link: string[] = [ connectionsRootPath ]; this.router.navigate(link); } + /** + * Called when the connection has been created. + */ + public connectionCreated(): void { + this.creatingConnection = false; + } } diff --git a/ngapp/src/app/connections/shared/connection.model.ts b/ngapp/src/app/connections/shared/connection.model.ts index 55aef1fd..5dcfb54e 100644 --- a/ngapp/src/app/connections/shared/connection.model.ts +++ b/ngapp/src/app/connections/shared/connection.model.ts @@ -15,7 +15,9 @@ * limitations under the License. */ -export class Connection { +import { Identifiable } from "@shared/identifiable"; + +export class Connection implements Identifiable< string > { private keng__id: string; private dv__jndiName: string; @@ -26,7 +28,7 @@ export class Connection { * @param {Object} json the JSON representation of a Connection * @returns {Connection} the new Connection (never null) */ - public static create( json: Object = {} ) { + public static create( json: Object = {} ): Connection { const conn = new Connection(); conn.setValues( json ); return conn; @@ -96,7 +98,7 @@ export class Connection { * Set all object values using the supplied Connection json * @param {Object} values */ - public setValues(values: Object = {}) { + public setValues(values: Object = {}): void { Object.assign(this, values); } diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ngapp/src/app/connections/shared/connection.service.spec.ts index e3450eb5..36c64aac 100644 --- a/ngapp/src/app/connections/shared/connection.service.spec.ts +++ b/ngapp/src/app/connections/shared/connection.service.spec.ts @@ -1,9 +1,9 @@ -import {TestBed, inject} from '@angular/core/testing'; +import {inject, TestBed} from "@angular/core/testing"; -import {ConnectionService} from './connection.service'; import {HttpModule} from "@angular/http"; +import {ConnectionService} from "./connection.service"; -describe('ConnectionService', () => { +describe("ConnectionService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], @@ -11,7 +11,7 @@ describe('ConnectionService', () => { }); }); - it('should be created', inject([ConnectionService], (service: ConnectionService) => { + it("should be created", inject([ConnectionService], (service: ConnectionService) => { expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index a9e3ecff..d0b23b1f 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -15,20 +15,22 @@ * limitations under the License. */ -import { Injectable } from '@angular/core'; -import { Http } from '@angular/http'; -import { Observable } from 'rxjs/Observable'; - +import { Injectable } from "@angular/core"; +import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { NewConnection } from "@connections/shared/new-connection.model"; import { ApiService } from "@core/api.service"; -import { KOMODO_WORKSPACE_URL } from "@core/api.service"; +import { komodoWorkspaceUrl } from "@core/api.service"; +import { Observable } from "rxjs/Observable"; @Injectable() export class ConnectionService extends ApiService { - constructor( private http: Http ) { + private http: Http; + + constructor( http: Http ) { super(); + this.http = http; } /** @@ -37,10 +39,10 @@ export class ConnectionService extends ApiService { */ public getAllConnections(): Observable { return this.http - .get(KOMODO_WORKSPACE_URL + '/connections', this.getAuthRequestOptions()) - .map(response => { + .get(komodoWorkspaceUrl + "/connections", this.getAuthRequestOptions()) + .map((response) => { const connections = response.json(); - return connections.map((connection) => {const conn = Connection.create( connection ); return conn; }); + return connections.map((connection) => Connection.create( connection )); }) .catch(this.handleError); } @@ -52,8 +54,8 @@ export class ConnectionService extends ApiService { */ public createConnection(connection: NewConnection): Observable { return this.http - .post(KOMODO_WORKSPACE_URL + '/connections/' + connection.getName(), connection, this.getAuthRequestOptions()) - .map(response => { + .post(komodoWorkspaceUrl + "/connections/" + connection.getName(), connection, this.getAuthRequestOptions()) + .map((response) => { return new Connection(); }) .catch(this.handleError); @@ -66,8 +68,8 @@ export class ConnectionService extends ApiService { */ public deleteConnection(connection: NewConnection): Observable { return this.http - .delete(KOMODO_WORKSPACE_URL + '/connections/' + connection.getName(), this.getAuthRequestOptions()) - .map(response => null) + .delete(komodoWorkspaceUrl + "/connections/" + connection.getName(), this.getAuthRequestOptions()) + .map((response) => null) .catch(this.handleError); } diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 3fef25d7..7728d0f5 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -1,26 +1,25 @@ -import {Injectable } from '@angular/core'; -import {Http} from '@angular/http'; -import {environment} from "@environments/environment"; -import {Connection} from '@connections/shared/connection.model'; -import {NewConnection} from '@connections/shared/new-connection.model'; -import { Observable } from 'rxjs/Observable'; -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/throw'; -import 'rxjs/add/observable/of'; - -const KOMODO_WORKSPACE_URL = environment.komodoWorkspaceUrl; +import {Injectable } from "@angular/core"; +import {Http} from "@angular/http"; +import {Connection} from "@connections/shared/connection.model"; +import {NewConnection} from "@connections/shared/new-connection.model"; +import "rxjs/add/observable/of"; +import "rxjs/add/observable/throw"; +import "rxjs/add/operator/catch"; +import "rxjs/add/operator/map"; +import { Observable } from "rxjs/Observable"; @Injectable() export class MockConnectionService { - newConnection = new NewConnection(); - conn1 = new Connection(); - conn2 = new Connection(); - conn3 = new Connection(); - conns: Connection[] = [this.conn1, this.conn2, this.conn3]; + private newConnection = new NewConnection(); + private conn1 = new Connection(); + private conn2 = new Connection(); + private conn3 = new Connection(); + private conns: Connection[] = [this.conn1, this.conn2, this.conn3]; + private http: Http; - constructor( private http: Http ) { + constructor( http: Http ) { + this.http = http; } /** diff --git a/ngapp/src/app/connections/shared/new-connection.model.ts b/ngapp/src/app/connections/shared/new-connection.model.ts index c433b9f7..903eee0a 100644 --- a/ngapp/src/app/connections/shared/new-connection.model.ts +++ b/ngapp/src/app/connections/shared/new-connection.model.ts @@ -17,16 +17,17 @@ export class NewConnection { - name: string; - jndiName: string; - driverName: string; - jdbc: boolean; - properties: Map< string, string > = new Map< string, string >(); + private name: string; + private jndiName: string; + private driverName: string; + private jdbc: boolean; + private properties: Map< string, string > = new Map< string, string >(); /** * Constructor */ constructor() { + // nothing to do } /** @@ -86,7 +87,7 @@ export class NewConnection { } /** - * @param {boolean} jdbc the jdbc status (optional) + * @param {boolean} isJdbc the jdbc status (optional) */ public setJdbc( isJdbc?: boolean ): void { this.jdbc = isJdbc ? isJdbc : true; @@ -99,9 +100,8 @@ export class NewConnection { this.properties = props ? props : new Map< string, string >(); } - // overrides toJSON - we do not want the name supplied in the json body. - public toJSON() { + public toJSON(): {} { return { jndiName: this.jndiName, driverName: this.driverName, diff --git a/ngapp/src/app/core/api.service.spec.ts b/ngapp/src/app/core/api.service.spec.ts index a2a555b0..adb65131 100644 --- a/ngapp/src/app/core/api.service.spec.ts +++ b/ngapp/src/app/core/api.service.spec.ts @@ -1,9 +1,8 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { HttpModule } from '@angular/http'; +import { inject, TestBed } from "@angular/core/testing"; +import { HttpModule } from "@angular/http"; +import { ApiService } from "@core/api.service"; -import { ApiService } from './api.service'; - -describe('ApiService', () => { +describe("ApiService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpModule], @@ -11,7 +10,7 @@ describe('ApiService', () => { }); }); - it('should be created', inject([ApiService], (service: ApiService) => { + it("should be created", inject([ApiService], (service: ApiService) => { expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index ca80c009..96ef2e3c 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -15,15 +15,16 @@ * limitations under the License. */ -import { Injectable } from '@angular/core'; -import { environment } from '@environments/environment'; -import {Http, Headers, RequestOptions} from '@angular/http'; -import { Observable } from 'rxjs/Observable'; -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/throw'; +import { Injectable } from "@angular/core"; +import {Headers, RequestOptions} from "@angular/http"; +import { environment } from "@environments/environment"; +import "rxjs/add/observable/throw"; +import "rxjs/add/operator/catch"; +import "rxjs/add/operator/map"; +import { Observable } from "rxjs/Observable"; +import { ErrorObservable } from "rxjs/observable/ErrorObservable"; -export const KOMODO_WORKSPACE_URL = environment.komodoWorkspaceUrl; +export const komodoWorkspaceUrl = environment.komodoWorkspaceUrl; @Injectable() export class ApiService { @@ -34,13 +35,12 @@ export class ApiService { * @returns {RequestOptions} */ protected getAuthRequestOptions(): RequestOptions { - const headers = new Headers({ 'Authorization': 'Basic ' + btoa('dsbUser:1demo-user1') }); - const options = new RequestOptions({ headers: headers }); - return options; + const headers = new Headers({ "Authorization": "Basic " + btoa("dsbUser:1demo-user1") }); + return new RequestOptions({ headers }); } - protected handleError (error: Response | any) { - console.error('ApiService::handleError', error); + protected handleError(error: Response | any): ErrorObservable { + console.error("ApiService::handleError", error); return Observable.throw(error); } diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts index d8de5e11..ac1e2d9b 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts @@ -1,9 +1,8 @@ -import {async, ComponentFixture, TestBed} from '@angular/core/testing'; - -import {BreadcrumbComponent} from './breadcrumb.component'; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; import {RouterTestingModule} from "@angular/router/testing"; +import {BreadcrumbComponent} from "./breadcrumb.component"; -describe('BreadcrumbComponent', () => { +describe("BreadcrumbComponent", () => { let component: BreadcrumbComponent; let fixture: ComponentFixture; @@ -21,7 +20,7 @@ describe('BreadcrumbComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts index fe366990..0c58cbff 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts @@ -15,18 +15,18 @@ * limitations under the License. */ -import {Component, Input} from '@angular/core'; +import {Component, Input} from "@angular/core"; @Component({ moduleId: module.id, - selector: '[app-breadcrumb]', - templateUrl: 'breadcrumb.component.html', - styleUrls: ['breadcrumb.component.css'] + selector: "[app-breadcrumb]", + templateUrl: "breadcrumb.component.html", + styleUrls: ["breadcrumb.component.css"] }) export class BreadcrumbComponent { - @Input() label: string; - @Input() icon: string; - @Input() route: string[]; + @Input() private label: string; + @Input() private icon: string; + @Input() private route: string[]; } diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts index 1b1a1708..aea8e021 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts @@ -1,8 +1,7 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { BreadcrumbsComponent } from "./breadcrumbs.component"; -import { BreadcrumbsComponent } from './breadcrumbs.component'; - -describe('BreadcrumbsComponent', () => { +describe("BreadcrumbsComponent", () => { let component: BreadcrumbsComponent; let fixture: ComponentFixture; @@ -19,7 +18,7 @@ describe('BreadcrumbsComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts index 542e0604..d9a049fc 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts @@ -15,13 +15,13 @@ * limitations under the License. */ -import {Component} from '@angular/core'; +import {Component} from "@angular/core"; @Component({ moduleId: module.id, - selector: 'breadcrumbs', - templateUrl: 'breadcrumbs.component.html', - styleUrls: ['breadcrumbs.component.css'] + selector: "breadcrumbs", + templateUrl: "breadcrumbs.component.html", + styleUrls: ["breadcrumbs.component.css"] }) export class BreadcrumbsComponent { diff --git a/ngapp/src/app/core/common.ts b/ngapp/src/app/core/common.ts deleted file mode 100644 index fb926d8e..00000000 --- a/ngapp/src/app/core/common.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -export class ArrayUtils { - - /** - * Returns the intersection of two arrays. - * @param a1 - * @param a2 - */ - public static intersect(a1: any[], a2: any[]): any[] { - let rval: any[] = []; - for (let item of a1) { - if (ArrayUtils.contains(a2, item)) { - rval.push(item); - } - } - return rval; - } - - /** - * Returns true if the given item is contained in the given array. - * @param a - * @param item - * @return {boolean} - */ - public static contains(a: any[], item: any): boolean { - for (let aitem of a) { - if (aitem === item) { - return true; - } - } - return false; - } - -} - -export class ObjectUtils { - - public static isNullOrUndefined(object: any): boolean { - return object === undefined || object === null; - } - - public static objectEquals(x:any, y:any) { - if (x === null || x === undefined || y === null || y === undefined) { return x === y; } - // after this just checking type of one would be enough - if (x.constructor !== y.constructor) { return false; } - // if they are functions, they should exactly refer to same one (because of closures) - if (x instanceof Function) { return x === y; } - // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES) - if (x instanceof RegExp) { return x === y; } - if (x === y || x.valueOf() === y.valueOf()) { return true; } - if (Array.isArray(x) && x.length !== y.length) { return false; } - - // if they are dates, they must had equal valueOf - if (x instanceof Date) { return false; } - - // if they are strictly equal, they both need to be object at least - if (!(x instanceof Object)) { return false; } - if (!(y instanceof Object)) { return false; } - - var p = Object.keys(x); - return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) && - p.every(function (i) { return ObjectUtils.objectEquals(x[i], y[i]); }); - } - -} - -export class HttpUtils { - - public static parseLinkHeader(header: string): any { - let links: any = new Object(); - if (ObjectUtils.isNullOrUndefined(header)) { - return links; - } - if (header.length === 0) { - return links; - } - - // Split parts by comma - let parts: string[] = header.split(','); - - // Parse each part into a named link - parts.forEach( part => { - var section = part.split(';'); - if (section.length == 2) { - var url = section[0].replace(/<(.*)>/, '$1').trim(); - var name = section[1].replace(/rel="(.*)"/, '$1').trim(); - links[name] = url; - } - }); - - return links; - } - -} diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index de40608a..adbf929c 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -15,15 +15,14 @@ * limitations under the License. */ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import {RouterModule} from '@angular/router'; - -import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; -import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import {HttpModule} from "@angular/http"; +import {RouterModule} from "@angular/router"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; -import {HttpModule} from "@angular/http"; +import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; +import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; @NgModule({ imports: [ diff --git a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts index f0483e1b..454cc499 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts @@ -1,8 +1,7 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; -import { NavHeaderComponent } from './nav-header.component'; - -describe('NavHeaderComponent', () => { +describe("NavHeaderComponent", () => { let component: NavHeaderComponent; let fixture: ComponentFixture; @@ -19,7 +18,7 @@ describe('NavHeaderComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/core/nav-header/nav-header.component.ts b/ngapp/src/app/core/nav-header/nav-header.component.ts index 27161eb1..19964510 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.ts @@ -15,39 +15,40 @@ * limitations under the License. */ -import {Component, OnInit, Inject} from '@angular/core'; +import {Component} from "@angular/core"; @Component({ moduleId: module.id, - selector: 'app-nav-header', - templateUrl: './nav-header.component.html', - styleUrls: [ './nav-header.component.less' ] + selector: "app-nav-header", + templateUrl: "./nav-header.component.html", + styleUrls: [ "./nav-header.component.less" ] }) -export class NavHeaderComponent implements OnInit { +export class NavHeaderComponent { - version = 'N/A'; - builtOn: Date = new Date(); - projectUrl = 'http://jboss.org/teiiddesigner/'; + private version = "N/A"; + private builtOn: Date = new Date(); + private projectUrl = "http://jboss.org/teiiddesigner/"; + private userId = "user"; constructor() { - if (window['BeetleStudio']) { - console.log('[NavHeaderComponent] Found app info: %o', window['BeetleStudio']) - this.version = window['BeetleStudio'].version; - this.builtOn = new Date(window['BeetleStudio'].builtOn); - this.projectUrl = window['BeetleStudio'].url; + // TODO this does not work + if (window["BeetleStudio"]) { + console.log("[NavHeaderComponent] Found app info: %o", window["BeetleStudio"]); + this.version = window["BeetleStudio"].version; + this.builtOn = new Date(window["BeetleStudio"].builtOn); + this.projectUrl = window["BeetleStudio"].url; } else { - console.log('[NavHeaderComponent] App info not found.'); + console.log("[NavHeaderComponent] App info not found."); } } - ngOnInit(): void { - } - public user(): string { - return 'User'; + // TODO implement user() + return this.userId; } public logout(): void { + // TODO implement logout() } } diff --git a/ngapp/src/app/core/utils/array-utils.ts b/ngapp/src/app/core/utils/array-utils.ts new file mode 100644 index 00000000..8ee19662 --- /dev/null +++ b/ngapp/src/app/core/utils/array-utils.ts @@ -0,0 +1,49 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class ArrayUtils { + + /** + * @param a the array being searched + * @param item the item being searched for + * @return {boolean} true if the given item is contained in the given array + */ + public static contains( a: any[], item: any ): boolean { + for ( const aitem of a ) { + if ( aitem === item ) { + return true; + } + } + return false; + } + + /** + * @param {any[]} a1 the first array + * @param {any[]} a2 the second array + * @returns {any[]} the intersection of two arrays + */ + public static intersect( a1: any[], a2: any[] ): any[] { + const rval: any[] = []; + for ( const item of a1 ) { + if ( ArrayUtils.contains( a2, item ) ) { + rval.push( item ); + } + } + return rval; + } + +} diff --git a/ngapp/src/app/core/utils/object-utils.ts b/ngapp/src/app/core/utils/object-utils.ts new file mode 100644 index 00000000..80d78d31 --- /dev/null +++ b/ngapp/src/app/core/utils/object-utils.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class ObjectUtils { + + public static isNullOrUndefined( object: any ): boolean { + return object === undefined || object === null; + } + + public static objectEquals( x: any, y: any ): boolean { + if ( x === null || x === undefined || y === null || y === undefined ) { + return x === y; + } + // after this just checking type of one would be enough + if ( x.constructor !== y.constructor ) { + return false; + } + // if they are functions, they should exactly refer to same one (because of closures) + if ( x instanceof Function ) { + return x === y; + } + // if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES) + if ( x instanceof RegExp ) { + return x === y; + } + if ( x === y || x.valueOf() === y.valueOf() ) { + return true; + } + if ( Array.isArray( x ) && x.length !== y.length ) { + return false; + } + + // if they are dates, they must had equal valueOf + if ( x instanceof Date ) { + return false; + } + + // if they are strictly equal, they both need to be object at least + if ( !(x instanceof Object) ) { + return false; + } + if ( !(y instanceof Object) ) { + return false; + } + + const p = Object.keys( x ); + return Object.keys( y ).every( (i) => p.indexOf( i ) !== -1 ) && + p.every( (i) => ObjectUtils.objectEquals( x[ i ], y[ i ] ) ); + } + +} diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts index 0c113e43..2e155a86 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts @@ -1,9 +1,8 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterTestingModule } from "@angular/router/testing"; +import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; -import { VerticalNavComponent } from './vertical-nav.component'; - -describe('VerticalNavComponent', () => { +describe("VerticalNavComponent", () => { let component: VerticalNavComponent; let fixture: ComponentFixture; @@ -21,7 +20,7 @@ describe('VerticalNavComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index c6ee0a2b..8dd65775 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import { Component, OnInit } from '@angular/core'; -import {Router, NavigationEnd} from '@angular/router'; +import { Component, OnInit } from "@angular/core"; +import { NavigationEnd, Router } from "@angular/router"; /** * Models the menus off the main left-hand vertical nav. @@ -27,49 +27,50 @@ enum VerticalNavType { @Component({ moduleId: module.id, - selector: 'app-vertical-nav', - templateUrl: './vertical-nav.component.html', - styleUrls: ['./vertical-nav.component.less'] + selector: "app-vertical-nav", + templateUrl: "./vertical-nav.component.html", + styleUrls: ["./vertical-nav.component.less"] }) export class VerticalNavComponent implements OnInit { + public menuTypes: any = VerticalNavType; + public currentMenu: VerticalNavType = VerticalNavType.Home; + private router: Router; - public menuTypes: any = VerticalNavType; - public currentMenu: VerticalNavType = VerticalNavType.Home; + constructor(router: Router) { + this.router = router; + } - constructor(private router: Router) { - } - - ngOnInit(): void { - console.log('Subscribing to router events.'); - this.router.events.subscribe(event => { - if (event instanceof NavigationEnd) { - this.onShadeClick(); - } - }); - } + public ngOnInit(): void { + console.log("Subscribing to router events."); + this.router.events.subscribe((event) => { + if (event instanceof NavigationEnd) { + this.onShadeClick(); + } + }); + } - /** - * Returns true if the currently active route is /activities/* - * @returns {boolean} - */ - isActivitiesRoute(): boolean { - return this.router.isActive('/activities', true); - } + /** + * Returns true if the currently active route is /activities/* + * @returns {boolean} + */ + private isActivitiesRoute(): boolean { + return this.router.isActive( "/activities", true ); + } /** * Returns true if the currently active route is /connections/* * @returns {boolean} */ - isConnectionsRoute(): boolean { - return this.router.isActive('/connections', true); - } + private isConnectionsRoute(): boolean { + return this.router.isActive("/connections", true); + } /** - * Called when the user clicks the vertical menu shade (the grey shaded area behind the submenu div that - * is displayed when a sub-menu is selected). Clicking the shade makes the sub-menu div go away. - */ - onShadeClick(): void { + * Called when the user clicks the vertical menu shade (the grey shaded area behind the submenu div that + * is displayed when a sub-menu is selected). Clicking the shade makes the sub-menu div go away. + */ + private onShadeClick(): void { /* this.subMenuOut = false; setTimeout(() => { @@ -81,18 +82,18 @@ export class VerticalNavComponent implements OnInit { /** * Called when the user clicks the vertical menu Activities item. */ - onActivitiesClick(): void { + private onActivitiesClick(): void { this.currentMenu = VerticalNavType.Activities; - const link: string[] = [ '/activities' ]; + const link: string[] = [ "/activities" ]; this.router.navigate(link); } /** * Called when the user clicks the vertical menu Connections item. */ - onConnectionsClick(): void { + private onConnectionsClick(): void { this.currentMenu = VerticalNavType.Connections; - const link: string[] = [ '/connections' ]; + const link: string[] = [ "/connections" ]; this.router.navigate(link); } diff --git a/ngapp/src/app/shared/abstract-page.component.ts b/ngapp/src/app/shared/abstract-page.component.ts index 761bc3ae..973dadc1 100644 --- a/ngapp/src/app/shared/abstract-page.component.ts +++ b/ngapp/src/app/shared/abstract-page.component.ts @@ -15,21 +15,23 @@ * limitations under the License. */ -import {OnInit} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; -import {Observable} from 'rxjs/Observable'; -import 'rxjs/add/observable/combineLatest'; +import {OnInit} from "@angular/core"; +import {ActivatedRoute} from "@angular/router"; +import "rxjs/add/observable/combineLatest"; +import {Observable} from "rxjs/Observable"; export abstract class AbstractPageComponent implements OnInit { public dataLoaded: Map = new Map(); public pageError: any; + protected route: ActivatedRoute; /** * C'tor. * @param {ActivatedRoute} route */ - constructor(protected route: ActivatedRoute) { + constructor(route: ActivatedRoute) { + this.route = route; } /** @@ -38,7 +40,7 @@ export abstract class AbstractPageComponent implements OnInit { */ public ngOnInit(): void { const combined = Observable.combineLatest(this.route.params, this.route.queryParams, (params, qparams) => ({params, qparams})); - combined.subscribe( ap => { + combined.subscribe( (ap) => { this.loadAsyncPageData(ap.params, ap.qparams); }); } @@ -50,6 +52,7 @@ export abstract class AbstractPageComponent implements OnInit { * @param queryParams */ public loadAsyncPageData(pathParams: any, queryParams: any): void { + // TODO is this method needed } /** @@ -57,7 +60,7 @@ export abstract class AbstractPageComponent implements OnInit { * @param error */ public error(error: any): void { - console.error(' Error: %o', error); + console.error(" Error: %o", error); this.pageError = error; } @@ -75,11 +78,7 @@ export abstract class AbstractPageComponent implements OnInit { * @return {boolean} */ public isLoaded(key: string): boolean { - if (this.dataLoaded[key]) { - return true; - } else { - return false; - } + return !!this.dataLoaded[ key ]; } } diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html index 0cc2b288..f3d76dbe 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html @@ -13,7 +13,7 @@
    diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts index b604596b..fecdd15c 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts @@ -1,9 +1,8 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { ModalModule } from "ngx-bootstrap"; +import { ConfirmDeleteComponent } from "./confirm-delete.component"; -import { ConfirmDeleteComponent } from './confirm-delete.component'; -import { ModalModule } from 'ngx-bootstrap'; - -describe('ConfirmDeleteComponent', () => { +describe("ConfirmDeleteComponent", () => { let component: ConfirmDeleteComponent; let fixture: ComponentFixture; @@ -21,7 +20,7 @@ describe('ConfirmDeleteComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts index 7db312a1..1dd5742a 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts @@ -15,21 +15,20 @@ * limitations under the License. */ -import {Component, Output, EventEmitter, ViewChildren, QueryList, ElementRef} from '@angular/core'; -import {ModalDirective} from 'ngx-bootstrap'; +import {Component, EventEmitter, Output, QueryList, ViewChildren} from "@angular/core"; +import {ModalDirective} from "ngx-bootstrap"; @Component({ moduleId: module.id, - selector: 'app-confirm-delete', - templateUrl: './confirm-delete.component.html', - styleUrls: ['./confirm-delete.component.css'] + selector: "app-confirm-delete", + templateUrl: "./confirm-delete.component.html", + styleUrls: ["./confirm-delete.component.css"] }) export class ConfirmDeleteComponent { - @Output() onDelete: EventEmitter = new EventEmitter(); - - @ViewChildren('confirmDeleteModal') confirmDeleteModal: QueryList; + @Output() private onDelete: EventEmitter = new EventEmitter(); + @ViewChildren("confirmDeleteModal") private confirmDeleteModal: QueryList; protected _isOpen = false; @@ -38,7 +37,7 @@ export class ConfirmDeleteComponent { */ public open(): void { this._isOpen = true; - this.confirmDeleteModal.changes.subscribe( thing => { + this.confirmDeleteModal.changes.subscribe( (thing) => { if (this.confirmDeleteModal.first) { this.confirmDeleteModal.first.show(); } @@ -55,7 +54,7 @@ export class ConfirmDeleteComponent { /** * Called when the user clicks "Yes". */ - protected delete(): void { + protected doDelete(): void { this.onDelete.emit(true); this.cancel(); } diff --git a/ngapp/src/app/shared/id-filter.ts b/ngapp/src/app/shared/id-filter.ts new file mode 100644 index 00000000..44180eaf --- /dev/null +++ b/ngapp/src/app/shared/id-filter.ts @@ -0,0 +1,69 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Identifiable } from "@shared/identifiable"; + +const emptyPattern = ""; + +export class IdFilter { + + private pattern: string = emptyPattern; + + constructor() { + // nothing to do + } + + /** + * @param {Identifiable} obj the object whose ID is being compared to the filter + * @returns {boolean} true if the ID matches the filter + */ + public accepts( obj: Identifiable< string > ): boolean { + if ( this.pattern === "" ) { + return true; + } + + const id: string = obj.getId().toLocaleLowerCase(); + const localized: string = this.pattern.toLocaleLowerCase(); + return id.indexOf( localized ) >= 0; + } + + /** + * @returns {string} the pattern being matched to + */ + public getPattern(): string { + return this.pattern; + } + + /** + * Resets the pattern so that all IDs will match the pattern. + */ + public reset(): void { + this.pattern = emptyPattern; + } + + /** + * @param {string} pattern the pattern to match IDs with (can be empty or null) + */ + public setFilter( pattern?: string ): void { + if ( pattern ) { + this.pattern = pattern; + } else { + this.pattern = emptyPattern; + } + } + +} diff --git a/ngapp/src/app/shared/identifiable.ts b/ngapp/src/app/shared/identifiable.ts new file mode 100644 index 00000000..c81fbf5f --- /dev/null +++ b/ngapp/src/app/shared/identifiable.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * An object that has an identifiable property. + */ +export interface Identifiable< T > { + + /** + * @returns {T} the object identifier (can be null) + */ + getId(): T; + +} diff --git a/ngapp/src/app/shared/layout-type.enum.ts b/ngapp/src/app/shared/layout-type.enum.ts new file mode 100644 index 00000000..bd457faa --- /dev/null +++ b/ngapp/src/app/shared/layout-type.enum.ts @@ -0,0 +1,33 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * An enumeration of valid collection member layout types. + */ +export enum LayoutType { + + /** + * Members of a collection are represented by a card. + */ + CARD, + + /** + * Members of a collections are represented as an item in the list. + */ + LIST + +} diff --git a/ngapp/src/app/shared/page-error/page-error.component.spec.ts b/ngapp/src/app/shared/page-error/page-error.component.spec.ts index 0734ecae..56523109 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.spec.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.spec.ts @@ -1,9 +1,8 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageErrorComponent } from './page-error.component'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; +import { PageErrorComponent } from "@shared/page-error/page-error.component"; -describe('PageErrorComponent', () => { +describe("PageErrorComponent", () => { let component: PageErrorComponent; let fixture: ComponentFixture; @@ -18,11 +17,11 @@ describe('PageErrorComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(PageErrorComponent); component = fixture.componentInstance; - component.error = 'test'; + component.error = "test"; fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/shared/page-error/page-error.component.ts b/ngapp/src/app/shared/page-error/page-error.component.ts index 4c2b2ada..e8674c9c 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.ts @@ -15,27 +15,20 @@ * limitations under the License. */ -import {Component, Input} from '@angular/core'; +import {Component, Input} from "@angular/core"; @Component({ moduleId: module.id, - selector: 'app-page-error', - templateUrl: './page-error.component.html', - styleUrls: ['./page-error.component.css'] + selector: "app-page-error", + templateUrl: "./page-error.component.html", + styleUrls: ["./page-error.component.css"] }) export class PageErrorComponent { - @Input() error: any; - private eobj: any = null; private showDetails = false; - /** - * Called to reload the browser page. - */ - public reloadPage(): void { - window.location.reload(); - } + @Input() private error: any; /** * Returns whether details should be shown. @@ -92,4 +85,11 @@ export class PageErrorComponent { return this.eobj; } + /** + * Called to reload the browser page. + */ + public reloadPage(): void { + window.location.reload(); + } + } diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts b/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts index 39170086..ca583db0 100644 --- a/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts +++ b/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts @@ -1,8 +1,7 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { PageNotFoundComponent } from "@shared/page-not-found/page-not-found.component"; -import { PageNotFoundComponent } from './page-not-found.component'; - -describe('PageNotFoundComponent', () => { +describe("PageNotFoundComponent", () => { let component: PageNotFoundComponent; let fixture: ComponentFixture; @@ -19,7 +18,7 @@ describe('PageNotFoundComponent', () => { fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.ts b/ngapp/src/app/shared/page-not-found/page-not-found.component.ts index 8d32187c..dc011f8f 100644 --- a/ngapp/src/app/shared/page-not-found/page-not-found.component.ts +++ b/ngapp/src/app/shared/page-not-found/page-not-found.component.ts @@ -15,19 +15,17 @@ * limitations under the License. */ -import { Component } from '@angular/core'; -import { OnInit } from '@angular/core'; +import { Component } from "@angular/core"; @Component({ - selector: 'app-page-not-found', - templateUrl: './page-not-found.component.html', - styleUrls: ['./page-not-found.component.css'] + selector: "app-page-not-found", + templateUrl: "./page-not-found.component.html", + styleUrls: ["./page-not-found.component.css"] }) -export class PageNotFoundComponent implements OnInit { +export class PageNotFoundComponent { - constructor() { } - - ngOnInit() { + constructor() { + // nothing to do } } diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index de2cad57..0dda2657 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -15,13 +15,12 @@ * limitations under the License. */ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; - +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { PageErrorComponent } from "@shared/page-error/page-error.component"; -import { ModalModule } from 'ngx-bootstrap'; -import { PageNotFoundComponent } from './page-not-found/page-not-found.component'; +import { ModalModule } from "ngx-bootstrap"; +import { PageNotFoundComponent } from "./page-not-found/page-not-found.component"; @NgModule({ imports: [ diff --git a/ngapp/src/app/shared/sort-direction.enum.ts b/ngapp/src/app/shared/sort-direction.enum.ts new file mode 100644 index 00000000..9b33aff1 --- /dev/null +++ b/ngapp/src/app/shared/sort-direction.enum.ts @@ -0,0 +1,33 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * An enumeration of valid sort directions. + */ +export enum SortDirection { + + /** + * Sort connections in ascending order. + */ + ASC, + + /** + * Sort connections in descending order. + */ + DESC + +} diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index f5d4d61b..1c44c54e 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -1,3 +1,20 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // The file contents for the current environment will overwrite these during build. // The build system defaults to the dev environment which uses `environment.ts`, but if you do // `ng build --env=prod` then `environment.prod.ts` will be used instead. @@ -7,12 +24,12 @@ export const environment = { production: false, // the home page path - homePagePath: '/connections', + homePagePath: "/connections", // REST URL - Komodo workspace - komodoWorkspaceUrl: 'https://localhost:8443/vdb-builder/v1/workspace', + komodoWorkspaceUrl: "https://localhost:8443/vdb-builder/v1/workspace", // REST URL - Komodo teiid server - komodoTeiidUrl: 'https://localhost:8443/vdb-builder/v1/teiid', + komodoTeiidUrl: "https://localhost:8443/vdb-builder/v1/teiid", }; diff --git a/ngapp/src/main.ts b/ngapp/src/main.ts index 7bf103b4..26d51333 100644 --- a/ngapp/src/main.ts +++ b/ngapp/src/main.ts @@ -1,14 +1,12 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { AppModule } from '@app/app.module'; -import { environment } from '@environments/environment'; +import { enableProdMode } from "@angular/core"; +import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; +import { AppModule } from "@app/app.module"; +import { environment } from "@environments/environment"; if (environment.production) { enableProdMode(); } platformBrowserDynamic().bootstrapModule( AppModule ) - .then( success => console.log( `Bootstrap success` ) ) - .catch( err => console.error( err ) ); - + .then( (success) => console.log( `Bootstrap success` ) ) + .catch( (err) => console.error( err ) ); diff --git a/ngapp/src/polyfills.ts b/ngapp/src/polyfills.ts index 7831e97b..4c4a22d7 100644 --- a/ngapp/src/polyfills.ts +++ b/ngapp/src/polyfills.ts @@ -18,7 +18,9 @@ * BROWSER POLYFILLS */ -/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +/** + * IE9, IE10 and IE11 requires all of the following polyfills. + */ // import 'core-js/es6/symbol'; // import 'core-js/es6/object'; // import 'core-js/es6/function'; @@ -34,28 +36,27 @@ // import 'core-js/es6/weak-map'; // import 'core-js/es6/set'; -/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +/** + * IE10 and IE11 requires the following for NgClass support on SVG elements + */ // import 'classlist.js'; // Run `npm install --save classlist.js`. -/** Evergreen browsers require these. **/ -import 'core-js/es6/reflect'; -import 'core-js/es7/reflect'; - +/** + * Evergreen browsers require these. + */ +import "core-js/es6/reflect"; +import "core-js/es7/reflect"; /** * Required to support Web Animations `@angular/animation`. * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation - **/ + */ // import 'web-animations-js'; // Run `npm install --save web-animations-js`. - - /*************************************************************************************************** * Zone JS is required by Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - +import "zone.js/dist/zone"; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS diff --git a/ngapp/src/test.ts b/ngapp/src/test.ts index cd612eeb..a3a544c5 100644 --- a/ngapp/src/test.ts +++ b/ngapp/src/test.ts @@ -1,23 +1,25 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/long-stack-trace-zone'; -import 'zone.js/dist/proxy.js'; -import 'zone.js/dist/sync-test'; -import 'zone.js/dist/jasmine-patch'; -import 'zone.js/dist/async-test'; -import 'zone.js/dist/fake-async-test'; -import { getTestBed } from '@angular/core/testing'; +import { getTestBed } from "@angular/core/testing"; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +} from "@angular/platform-browser-dynamic/testing"; +import "zone.js/dist/async-test"; +import "zone.js/dist/fake-async-test"; +import "zone.js/dist/jasmine-patch"; +import "zone.js/dist/long-stack-trace-zone"; +import "zone.js/dist/proxy.js"; +import "zone.js/dist/sync-test"; // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. declare const __karma__: any; declare const require: any; // Prevent Karma from running prematurely. -__karma__.loaded = function () {}; +__karma__.loaded = () => { + // nothing to do +}; // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( @@ -25,7 +27,7 @@ getTestBed().initTestEnvironment( platformBrowserDynamicTesting() ); // Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); +const context = require.context("./", true, /\.spec\.ts$/); // And load the modules. context.keys().map(context); // Finally, start Karma to run the tests. diff --git a/ngapp/tslint.json b/ngapp/tslint.json index 0db5751c..b9f02e58 100644 --- a/ngapp/tslint.json +++ b/ngapp/tslint.json @@ -1,8 +1,18 @@ { + "extends": [ + "tslint:recommended" + ], "rulesDirectory": [ "node_modules/codelyzer" ], "rules": { + "align": [ + true, + "members", + "parameters", + "statements" + ], + "angular-whitespace": [true, "check-interpolation"], "arrow-return-shorthand": true, "callable-types": true, "class-name": true, @@ -10,7 +20,22 @@ true, "check-space" ], + "component-class-suffix": true, + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ], "curly": true, + "deprecation": true, + "directive-class-suffix": true, + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], "eofline": true, "forin": true, "import-blacklist": [ @@ -20,28 +45,29 @@ "import-spacing": true, "indent": [ true, - "spaces" + "spaces", + 4 ], + "interface-name": false, "interface-over-type-literal": true, + "invoke-injectable": true, "label-position": true, + "max-classes-per-file": [true, 1], "max-line-length": [ true, 140 ], - "member-access": false, + "member-access": true, "member-ordering": [ true, - { - "order": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } + "static-before-instance", + "variables-before-functions" ], + "new-parens": true, + "no-access-missing-member": true, "no-arg": true, "no-bitwise": true, + "no-consecutive-blank-lines": true, "no-console": [ true, "debug", @@ -52,16 +78,20 @@ ], "no-construct": true, "no-debugger": true, + "no-duplicate-imports": true, "no-duplicate-super": true, - "no-empty": false, + "no-empty": true, "no-empty-interface": true, "no-eval": true, + "no-input-rename": true, + "no-output-rename": true, "no-inferrable-types": [ true, "ignore-params" ], "no-misused-new": true, "no-non-null-assertion": true, + "no-parameter-properties": true, "no-shadowed-variable": true, "no-string-literal": false, "no-string-throw": true, @@ -70,7 +100,11 @@ "no-unnecessary-initializer": true, "no-unused-expression": true, "no-use-before-declare": true, - "no-var-keyword": true, + "no-var-keyword": [ + true, + "as-needed" + ], + "object-literal-key-quotes": false, "object-literal-sort-keys": false, "one-line": [ true, @@ -79,20 +113,40 @@ "check-else", "check-whitespace" ], + "one-variable-per-declaration": [ + true, + "ignore-for-loop" + ], + "ordered-imports": [ + true, + { + "import-sources-order": "case-insensitive", + "named-imports-order": "case-insensitive" + } + ], "prefer-const": true, "quotemark": [ true, - "single" + "double" ], "radix": true, + "restrict-plus-operands": false, "semicolon": [ true, "always" ], + "switch-default": true, + "templates-use-public": true, + "trailing-comma": false, "triple-equals": [ true, "allow-null-check" ], + "typedef": [ + true, + "call-signature", + "property-declaration" + ], "typedef-whitespace": [ true, { @@ -105,38 +159,24 @@ ], "typeof-compare": true, "unified-signatures": true, - "variable-name": false, + "variable-name": [ + true, + "ban-keywords" + ], "whitespace": [ true, "check-branch", "check-decl", "check-operator", + "check-module", + "check-preblock", "check-separator", "check-type" ], - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "component-selector": [ - true, - "element", - "app", - "kebab-case" - ], + "use-host-property-decorator": true, "use-input-property-decorator": true, "use-output-property-decorator": true, - "use-host-property-decorator": true, - "no-input-rename": true, - "no-output-rename": true, "use-life-cycle-interface": true, - "use-pipe-transform-interface": true, - "component-class-suffix": true, - "directive-class-suffix": true, - "no-access-missing-member": true, - "templates-use-public": true, - "invoke-injectable": true + "use-pipe-transform-interface": true } } From b81535b16209011907958b323ac154d523289ab9 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 9 Oct 2017 09:56:46 -0500 Subject: [PATCH 011/205] fixes some circular dependencies caught when running 'ng serve' --- .../activities/activities-routing.module.ts | 12 +++---- .../app/activities/activities.component.ts | 8 ++--- ngapp/src/app/activities/activities.module.ts | 5 +-- .../add-activity/add-activity.component.ts | 7 ++-- .../activities/shared/activities-constants.ts | 24 ++++++++++++++ .../add-activity-form.component.ts | 5 +-- ngapp/src/app/app-routing.module.ts | 9 +++-- ngapp/src/app/app.component.ts | 1 + .../add-connection.component.ts | 7 ++-- .../connections/connections-routing.module.ts | 12 +++---- .../app/connections/connections.component.ts | 9 ++--- .../edit-connection.component.ts | 5 +-- .../add-connection-form.component.html | 8 ++--- .../add-connection-form.component.ts | 33 +++++++++++++++++-- .../connections/shared/connection.service.ts | 11 ++++--- .../shared/connections-constants.ts | 24 ++++++++++++++ ngapp/src/app/core/api.service.ts | 3 -- .../core/breadcrumbs/breadcrumbs.component.ts | 4 +-- .../vertical-nav/vertical-nav.component.ts | 7 ++-- ngapp/src/environments/environment.ts | 3 +- 20 files changed, 137 insertions(+), 60 deletions(-) create mode 100644 ngapp/src/app/activities/shared/activities-constants.ts create mode 100644 ngapp/src/app/connections/shared/connections-constants.ts diff --git a/ngapp/src/app/activities/activities-routing.module.ts b/ngapp/src/app/activities/activities-routing.module.ts index d91f9a7b..79528fdc 100644 --- a/ngapp/src/app/activities/activities-routing.module.ts +++ b/ngapp/src/app/activities/activities-routing.module.ts @@ -12,18 +12,15 @@ import { ActivitiesComponent } from "@activities/activities.component"; import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; +import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { NgModule } from "@angular/core"; import { RouterModule } from "@angular/router"; import { Routes } from "@angular/router"; -export const activitiesRootPath = "/activities"; -export const addActivityPath = activitiesRootPath + "/add-activity"; -export const editActivityPath = activitiesRootPath + "/edit-activity"; - const activitiesRoutes: Routes = [ - { path: activitiesRootPath, component: ActivitiesComponent }, - { path: addActivityPath, component: AddActivityComponent } -// { path: editActivityPath, component: EditActivityComponent } + { path: ActivitiesConstants.activitiesRootRoute, component: ActivitiesComponent }, + { path: ActivitiesConstants.addActivityRoute, component: AddActivityComponent } +// { path: ActivitiesConstants.editActivityRoute, component: EditActivityComponent } ]; @NgModule({ @@ -34,5 +31,4 @@ const activitiesRoutes: Routes = [ RouterModule ] }) - export class ActivitiesRoutingModule {} diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index 3d0e316c..c51ea1a9 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -15,12 +15,12 @@ * limitations under the License. */ -import { addActivityPath, editActivityPath } from "@activities/activities-routing.module"; +import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { Activity } from "@activities/shared/activity.model"; import { ActivityService } from "@activities/shared/activity.service"; import { NewActivity } from "@activities/shared/new-activity.model"; -import { ViewChild } from "@angular/core"; import { Component } from "@angular/core"; +import { ViewChild } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { Router } from "@angular/router"; import { ArrayUtils } from "@core/utils/array-utils"; @@ -39,7 +39,7 @@ import { SortDirection } from "@shared/sort-direction.enum"; }) export class ActivitiesComponent extends AbstractPageComponent { - public addActivityLink = addActivityPath; + public readonly addActivityLink = ActivitiesConstants.addActivityPath; private allActivities: Activity[] = []; private filteredActivities: Activity[] = []; @@ -102,7 +102,7 @@ export class ActivitiesComponent extends AbstractPageComponent { } public onEdit(activityName: string): void { - const link: string[] = [ editActivityPath ]; + const link: string[] = [ ActivitiesConstants.editActivityPath ]; this.router.navigate(link); } diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts index 392fddb4..599796fa 100644 --- a/ngapp/src/app/activities/activities.module.ts +++ b/ngapp/src/app/activities/activities.module.ts @@ -49,5 +49,6 @@ import { SharedModule } from "@shared/shared.module"; ], providers: [ ActivityService - ]}) -export class ActivitiesModule { } + ] +}) +export class ActivitiesModule {} diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.ts b/ngapp/src/app/activities/add-activity/add-activity.component.ts index eb38ea96..4849d017 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { activitiesRootPath } from "@activities/activities-routing.module"; +import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { ActivityService } from "@activities/shared/activity.service"; import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; import { NewActivity } from "@activities/shared/new-activity.model"; @@ -26,13 +26,14 @@ import { Router } from "@angular/router"; import { AbstractPageComponent } from "@shared/abstract-page.component"; @Component({ + moduleId: module.id, selector: "app-add-activity", templateUrl: "./add-activity.component.html", styleUrls: ["./add-activity.component.css"] }) export class AddActivityComponent extends AbstractPageComponent { - public activitiesLink = activitiesRootPath; + public readonly activitiesLink = ActivitiesConstants.activitiesRootPath; private router: Router; private activityService: ActivityService; @@ -53,7 +54,7 @@ export class AddActivityComponent extends AbstractPageComponent { public onCreateActivity(activity: NewActivity): void { console.log("[AddActivityComponent] onCreateActivity(): " + JSON.stringify(activity)); this.activityService.createActivity(activity); - const link: string[] = [ activitiesRootPath ]; + const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; console.log("[AddActivityComponent] Navigating to: %o", link); this.router.navigate(link); } diff --git a/ngapp/src/app/activities/shared/activities-constants.ts b/ngapp/src/app/activities/shared/activities-constants.ts new file mode 100644 index 00000000..66fea42c --- /dev/null +++ b/ngapp/src/app/activities/shared/activities-constants.ts @@ -0,0 +1,24 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, / + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class ActivitiesConstants { + + public static readonly activitiesRootRoute = "activities"; + public static readonly activitiesRootPath = "/" + ActivitiesConstants.activitiesRootRoute; + + public static readonly addActivityRoute = ActivitiesConstants.activitiesRootRoute + "/add-activity"; + public static readonly addActivityPath = ActivitiesConstants.activitiesRootPath + "/add-activity"; + + public static readonly editActivityroute = ActivitiesConstants.activitiesRootRoute + "/edit-activity"; + public static readonly editActivityPath = ActivitiesConstants.activitiesRootPath + "/edit-activity"; + +} diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts index a32a1777..3cc72898 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { activitiesRootPath } from "@activities/activities-routing.module"; +import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { NewActivity } from "@activities/shared/new-activity.model"; import { Component } from "@angular/core"; import { EventEmitter } from "@angular/core"; @@ -24,6 +24,7 @@ import { Router } from "@angular/router"; import { NewConnection } from "@connections/shared/new-connection.model"; @Component({ + moduleId: module.id, selector: "app-add-activity-form", templateUrl: "./add-activity-form.component.html", styleUrls: ["./add-activity-form.component.css"] @@ -89,7 +90,7 @@ export class AddActivityFormComponent { } public cancelAdd(): void { - const link: string[] = [ activitiesRootPath ]; + const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; this.router.navigate(link); } diff --git a/ngapp/src/app/app-routing.module.ts b/ngapp/src/app/app-routing.module.ts index 64b486da..40fae7ab 100644 --- a/ngapp/src/app/app-routing.module.ts +++ b/ngapp/src/app/app-routing.module.ts @@ -15,18 +15,18 @@ * limitations under the License. */ -import { activitiesRootPath } from "@activities/activities-routing.module"; +import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { NgModule } from "@angular/core"; import { RouterModule } from "@angular/router"; import { Routes } from "@angular/router"; -import { connectionsRootPath } from "@connections/connections-routing.module"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { environment } from "@environments/environment"; import { PageNotFoundComponent } from "@shared/page-not-found/page-not-found.component"; const appRoutes: Routes = [ { path: "", redirectTo: environment.homePagePath, pathMatch: "full" }, - { path: connectionsRootPath, loadChildren: "@connections/connections.module#ConnectionsModule" }, - { path: activitiesRootPath, loadChildren: "@activities/activities.module#ActivitiesModule" }, + { path: ConnectionsConstants.connectionsRootRoute, loadChildren: "@connections/connections.module#ConnectionsModule" }, + { path: ActivitiesConstants.activitiesRootRoute, loadChildren: "@activities/activities.module#ActivitiesModule" }, { path: "**", component: PageNotFoundComponent }, // always last ]; @@ -38,5 +38,4 @@ const appRoutes: Routes = [ RouterModule ] }) - export class AppRoutingModule {} diff --git a/ngapp/src/app/app.component.ts b/ngapp/src/app/app.component.ts index 3cdf875a..91a24300 100644 --- a/ngapp/src/app/app.component.ts +++ b/ngapp/src/app/app.component.ts @@ -18,6 +18,7 @@ import { Component } from "@angular/core"; @Component({ + moduleId: module.id, selector: "app-root", templateUrl: "./app.component.html", styleUrls: ["./app.component.css"] diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ngapp/src/app/connections/add-connection/add-connection.component.ts index 2fbbf50e..f797c14b 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.ts @@ -19,20 +19,21 @@ import { Component } from "@angular/core"; import { ViewChild } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { Router } from "@angular/router"; -import { addConnectionPath, connectionsRootPath } from "@connections/connections-routing.module"; import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; import { ConnectionService } from "@connections/shared/connection.service"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { NewConnection } from "@connections/shared/new-connection.model"; import { AbstractPageComponent } from "@shared/abstract-page.component"; @Component({ + moduleId: module.id, selector: "app-add-connection", templateUrl: "./add-connection.component.html", styleUrls: ["./add-connection.component.css"] }) export class AddConnectionComponent extends AbstractPageComponent { - public addConnectionLink = addConnectionPath; + public readonly addConnectionLink = ConnectionsConstants.addConnectionPath; private router: Router; private connectionService: ConnectionService; @@ -57,7 +58,7 @@ export class AddConnectionComponent extends AbstractPageComponent { .subscribe( () => { this.form.connectionCreated(); - const link: string[] = [ connectionsRootPath ]; + const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; console.log("[AddConnectionComponent] Navigating to: %o", link); this.router.navigate(link); } diff --git a/ngapp/src/app/connections/connections-routing.module.ts b/ngapp/src/app/connections/connections-routing.module.ts index 643674f0..49089690 100644 --- a/ngapp/src/app/connections/connections-routing.module.ts +++ b/ngapp/src/app/connections/connections-routing.module.ts @@ -21,15 +21,12 @@ import { Routes } from "@angular/router"; import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; import { ConnectionsComponent } from "@connections/connections.component"; import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; - -export const connectionsRootPath = "/connections"; -export const addConnectionPath = connectionsRootPath + "/add-connection"; -export const editConnectionPath = connectionsRootPath + "/edit-connection"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; const connectionsRoutes: Routes = [ - { path: connectionsRootPath, component: ConnectionsComponent }, - { path: addConnectionPath, component: AddConnectionComponent }, - { path: editConnectionPath, component: EditConnectionComponent } + { path: ConnectionsConstants.connectionsRootRoute, component: ConnectionsComponent }, + { path: ConnectionsConstants.addConnectionRoute, component: AddConnectionComponent }, + { path: ConnectionsConstants.editConnectionRoute, component: EditConnectionComponent } ]; @NgModule({ @@ -40,5 +37,4 @@ const connectionsRoutes: Routes = [ RouterModule ] }) - export class ConnectionsRoutingModule {} diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index c10b07eb..7738fe66 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -17,9 +17,9 @@ import { Component, ViewChild } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; -import { addConnectionPath, connectionsRootPath, editConnectionPath } from "@connections/connections-routing.module"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { NewConnection } from "@connections/shared/new-connection.model"; import { ArrayUtils } from "@core/utils/array-utils"; import { AbstractPageComponent } from "@shared/abstract-page.component"; @@ -29,6 +29,7 @@ import { LayoutType } from "@shared/layout-type.enum"; import { SortDirection } from "@shared/sort-direction.enum"; @Component({ + moduleId: module.id, selector: "app-connections", templateUrl: "./connections.component.html", styleUrls: ["./connections.component.css"], @@ -36,7 +37,7 @@ import { SortDirection } from "@shared/sort-direction.enum"; }) export class ConnectionsComponent extends AbstractPageComponent { - public addConnectionLink: string = addConnectionPath; + public readonly addConnectionLink: string = ConnectionsConstants.addConnectionPath; private allConnections: Connection[] = []; private filteredConnections: Connection[] = []; @@ -155,7 +156,7 @@ export class ConnectionsComponent extends AbstractPageComponent { } public onEdit(connName: string): void { - const link: string[] = [ editConnectionPath ]; + const link: string[] = [ ConnectionsConstants.editConnectionPath ]; this.router.navigate(link); } @@ -209,7 +210,7 @@ export class ConnectionsComponent extends AbstractPageComponent { .subscribe( () => { this.removeConnectionFromList(selectedConn); - const link: string[] = [ connectionsRootPath ]; + const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; console.log("[CreateApiPageComponent] Navigating to: %o", link); this.router.navigate(link); } diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.ts index 807a6c74..202a9429 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.ts +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.ts @@ -18,19 +18,20 @@ import { Component } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { Router } from "@angular/router"; -import { connectionsRootPath } from "@connections/connections-routing.module"; import { ConnectionService } from "@connections/shared/connection.service"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { NewConnection } from "@connections/shared/new-connection.model"; import { AbstractPageComponent } from "@shared/abstract-page.component"; @Component({ + moduleId: module.id, selector: "app-edit-connection", templateUrl: "./edit-connection.component.html", styleUrls: ["./edit-connection.component.css"] }) export class EditConnectionComponent extends AbstractPageComponent { - public connectionsLink = connectionsRootPath; + public readonly connectionsLink = ConnectionsConstants.connectionsRootPath; private router: Router; private connectionService: ConnectionService; diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html index 05e92068..5ec6aa63 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html @@ -5,25 +5,25 @@

    Connection Properties

    - +
    - +
    - +
    - +

    diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts index 126a0da2..e1a92aab 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts @@ -17,10 +17,11 @@ import { Component, EventEmitter, Output } from "@angular/core"; import { Router } from "@angular/router"; -import { connectionsRootPath } from "@connections/connections-routing.module"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { NewConnection } from "@connections/shared/new-connection.model"; @Component({ + moduleId: module.id, selector: "app-add-connection-form", templateUrl: "./add-connection-form.component.html", styleUrls: ["./add-connection-form.component.css"] @@ -37,6 +38,34 @@ export class AddConnectionFormComponent { this.router = router; } + /** + * @returns {string} the name of the connection + */ + public get connectionName(): string { + return this.model.getName(); + } + + /** + * @returns {string} the driver name of the connection + */ + public get connectionDriverName(): string { + return this.model.getDriverName(); + } + + /** + * @returns {boolean} true if a JDBC connection + */ + public get connectionIsJdbc(): boolean { + return this.model.isJdbc(); + } + + /** + * @returns {string} the JNDI name of the connection + */ + public get connectionJndiName(): string { + return this.model.getJndiName(); + } + public currentConnection(): string { return JSON.stringify(this.model); } @@ -58,7 +87,7 @@ export class AddConnectionFormComponent { } public cancelAdd(): void { - const link: string[] = [ connectionsRootPath ]; + const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; this.router.navigate(link); } diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index d0b23b1f..495dd9d0 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -20,8 +20,9 @@ import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { NewConnection } from "@connections/shared/new-connection.model"; import { ApiService } from "@core/api.service"; -import { komodoWorkspaceUrl } from "@core/api.service"; +import { environment } from "@environments/environment"; import { Observable } from "rxjs/Observable"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; @Injectable() export class ConnectionService extends ApiService { @@ -39,7 +40,7 @@ export class ConnectionService extends ApiService { */ public getAllConnections(): Observable { return this.http - .get(komodoWorkspaceUrl + "/connections", this.getAuthRequestOptions()) + .get(environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath, this.getAuthRequestOptions()) .map((response) => { const connections = response.json(); return connections.map((connection) => Connection.create( connection )); @@ -54,7 +55,8 @@ export class ConnectionService extends ApiService { */ public createConnection(connection: NewConnection): Observable { return this.http - .post(komodoWorkspaceUrl + "/connections/" + connection.getName(), connection, this.getAuthRequestOptions()) + .post(environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath + "/" + connection.getName(), + connection, this.getAuthRequestOptions()) .map((response) => { return new Connection(); }) @@ -68,7 +70,8 @@ export class ConnectionService extends ApiService { */ public deleteConnection(connection: NewConnection): Observable { return this.http - .delete(komodoWorkspaceUrl + "/connections/" + connection.getName(), this.getAuthRequestOptions()) + .delete(environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath + "/" + connection.getName(), + this.getAuthRequestOptions()) .map((response) => null) .catch(this.handleError); } diff --git a/ngapp/src/app/connections/shared/connections-constants.ts b/ngapp/src/app/connections/shared/connections-constants.ts new file mode 100644 index 00000000..17d5f152 --- /dev/null +++ b/ngapp/src/app/connections/shared/connections-constants.ts @@ -0,0 +1,24 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, / + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class ConnectionsConstants { + + public static readonly connectionsRootRoute = "connections"; + public static readonly connectionsRootPath = "/" + ConnectionsConstants.connectionsRootRoute; + + public static readonly addConnectionRoute = ConnectionsConstants.connectionsRootRoute + "/add-connection"; + public static readonly addConnectionPath = ConnectionsConstants.connectionsRootPath + "/add-connection"; + + public static readonly editConnectionRoute = ConnectionsConstants.connectionsRootRoute + "/edit-connection"; + public static readonly editConnectionPath = ConnectionsConstants.connectionsRootPath + "/edit-connection"; + +} diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index 96ef2e3c..cdc4b8a4 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -17,15 +17,12 @@ import { Injectable } from "@angular/core"; import {Headers, RequestOptions} from "@angular/http"; -import { environment } from "@environments/environment"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; import { ErrorObservable } from "rxjs/observable/ErrorObservable"; -export const komodoWorkspaceUrl = environment.komodoWorkspaceUrl; - @Injectable() export class ApiService { diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts index d9a049fc..f08508d3 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts @@ -23,6 +23,4 @@ import {Component} from "@angular/core"; templateUrl: "breadcrumbs.component.html", styleUrls: ["breadcrumbs.component.css"] }) -export class BreadcrumbsComponent { - -} +export class BreadcrumbsComponent {} diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index 8dd65775..234e8504 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -15,8 +15,10 @@ * limitations under the License. */ +import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { Component, OnInit } from "@angular/core"; import { NavigationEnd, Router } from "@angular/router"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; /** * Models the menus off the main left-hand vertical nav. @@ -33,6 +35,7 @@ enum VerticalNavType { }) export class VerticalNavComponent implements OnInit { + public menuTypes: any = VerticalNavType; public currentMenu: VerticalNavType = VerticalNavType.Home; private router: Router; @@ -84,7 +87,7 @@ export class VerticalNavComponent implements OnInit { */ private onActivitiesClick(): void { this.currentMenu = VerticalNavType.Activities; - const link: string[] = [ "/activities" ]; + const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; this.router.navigate(link); } @@ -93,7 +96,7 @@ export class VerticalNavComponent implements OnInit { */ private onConnectionsClick(): void { this.currentMenu = VerticalNavType.Connections; - const link: string[] = [ "/connections" ]; + const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; this.router.navigate(link); } diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index 1c44c54e..0aa072e5 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { ConnectionsConstants } from "@connections/shared/connections-constants"; // The file contents for the current environment will overwrite these during build. // The build system defaults to the dev environment which uses `environment.ts`, but if you do @@ -24,7 +25,7 @@ export const environment = { production: false, // the home page path - homePagePath: "/connections", + homePagePath: ConnectionsConstants.connectionsRootPath, // REST URL - Komodo workspace komodoWorkspaceUrl: "https://localhost:8443/vdb-builder/v1/workspace", From 9199d5a52b730224f04400c506e0a8fa8e159118 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 9 Oct 2017 10:53:34 -0500 Subject: [PATCH 012/205] Added set methods for model objects used in the forms. --- .../add-activity-form.component.ts | 29 +++++++++++++++++++ .../add-connection-form.component.ts | 28 ++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts index 3cc72898..3d1772a4 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts @@ -22,6 +22,7 @@ import { EventEmitter } from "@angular/core"; import { Output } from "@angular/core"; import { Router } from "@angular/router"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { de } from "ngx-bootstrap/locale"; @Component({ moduleId: module.id, @@ -48,6 +49,13 @@ export class AddActivityFormComponent { return this.model.getDescription(); } + /** + * @param {string} description the new activity description + */ + public set activityDescription( description: string ) { + this.model.setDescription( description ); + } + /** * @returns {string} the activity name */ @@ -55,6 +63,13 @@ export class AddActivityFormComponent { return this.model.getName(); } + /** + * @param {string} name the new activity name + */ + public set activityName( name: string ) { + this.model.setName( name ); + } + /** * @returns {string} the activity's source connection */ @@ -62,6 +77,13 @@ export class AddActivityFormComponent { return this.model.getSourceConnection(); } + /** + * @param {string} source the new activity source + */ + public set activitySource( source: NewConnection ) { + this.model.setSourceConnection( source ); + } + /** * @returns {string} the activity's target connection */ @@ -69,6 +91,13 @@ export class AddActivityFormComponent { return this.model.getTargetConnection(); } + /** + * @param {string} target the new activity target + */ + public set activityTarget( target: NewConnection ) { + this.model.setTargetConnection( target ); + } + public get currentActivity(): string { return JSON.stringify(this.model); } diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts index e1a92aab..f9e22c02 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts @@ -45,6 +45,13 @@ export class AddConnectionFormComponent { return this.model.getName(); } + /** + * @param {string} name the new connection name + */ + public set connectionName( name: string ) { + this.model.setName( name ); + } + /** * @returns {string} the driver name of the connection */ @@ -52,6 +59,13 @@ export class AddConnectionFormComponent { return this.model.getDriverName(); } + /** + * @param {string} driverName the new connection driver name + */ + public set connectionDriverName( driverName: string ) { + this.model.setDriverName( driverName ); + } + /** * @returns {boolean} true if a JDBC connection */ @@ -59,6 +73,13 @@ export class AddConnectionFormComponent { return this.model.isJdbc(); } + /** + * @param {boolean} isJdbc true if the new connection is a JDBC connection + */ + public set connectionIsJdbc( isJdbc: boolean ) { + this.model.setJdbc( isJdbc ); + } + /** * @returns {string} the JNDI name of the connection */ @@ -66,6 +87,13 @@ export class AddConnectionFormComponent { return this.model.getJndiName(); } + /** + * @param {string} jndiName the new connection JNDI name + */ + public set connectionJndiName( jndiName: string ) { + this.model.setJndiName( jndiName ); + } + public currentConnection(): string { return JSON.stringify(this.model); } From 4914207d97bd8f273003ee993de1e2d2eadad0d8 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 9 Oct 2017 16:56:35 -0500 Subject: [PATCH 013/205] Addition of Property Form --- .../app/activities/activities.component.html | 4 +- .../add-activity/add-activity.component.html | 4 +- .../app/activities/shared/activity.model.ts | 4 +- .../add-connection.component.html | 6 +- .../add-connection.component.ts | 2 +- .../connections/connections.component.html | 4 +- .../src/app/connections/connections.module.ts | 2 + .../edit-connection.component.html | 9 +- .../edit-connection.component.ts | 45 ++-- .../connections/shared/connection.model.ts | 4 +- .../connections/shared/connection.service.ts | 20 +- .../core/breadcrumbs/breadcrumbs.component.ts | 2 +- .../property-definition.model.ts | 252 ++++++++++++++++++ .../property-form-property.component.css | 0 .../property-form-property.component.html | 19 ++ .../property-form-property.component.spec.ts | 25 ++ .../property-form-property.component.ts | 40 +++ .../property-form/property-form.component.css | 0 .../property-form.component.html | 16 ++ .../property-form.component.spec.ts | 25 ++ .../property-form/property-form.component.ts | 65 +++++ ngapp/src/app/shared/shared.module.ts | 14 +- .../app/shared/validators/name-validator.ts | 9 + 23 files changed, 529 insertions(+), 42 deletions(-) create mode 100644 ngapp/src/app/shared/property-form/property-definition.model.ts create mode 100644 ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.css create mode 100644 ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html create mode 100644 ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts create mode 100644 ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts create mode 100644 ngapp/src/app/shared/property-form/property-form.component.css create mode 100644 ngapp/src/app/shared/property-form/property-form.component.html create mode 100644 ngapp/src/app/shared/property-form/property-form.component.spec.ts create mode 100644 ngapp/src/app/shared/property-form/property-form.component.ts create mode 100644 ngapp/src/app/shared/validators/name-validator.ts diff --git a/ngapp/src/app/activities/activities.component.html b/ngapp/src/app/activities/activities.component.html index 00566588..b2451ec6 100644 --- a/ngapp/src/app/activities/activities.component.html +++ b/ngapp/src/app/activities/activities.component.html @@ -1,9 +1,9 @@
    - +
  • -
    +
    diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.html b/ngapp/src/app/activities/add-activity/add-activity.component.html index 40204d82..87ded917 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.html +++ b/ngapp/src/app/activities/add-activity/add-activity.component.html @@ -1,9 +1,9 @@
    - +
  • -
    +
    diff --git a/ngapp/src/app/activities/shared/activity.model.ts b/ngapp/src/app/activities/shared/activity.model.ts index 32d64d14..6378560e 100644 --- a/ngapp/src/app/activities/shared/activity.model.ts +++ b/ngapp/src/app/activities/shared/activity.model.ts @@ -25,7 +25,7 @@ export class Activity { * @param {Object} json the JSON representation of a Activity * @returns {Activity} the new Activity (never null) */ - public static create( json: Object = {} ): Activity { + public static create( json: object = {} ): Activity { const activity = new Activity(); activity.setValues( json ); return activity; @@ -81,7 +81,7 @@ export class Activity { * Set all object values using the supplied Activity json * @param {Object} values */ - public setValues(values: Object = {}): void { + public setValues(values: object = {}): void { Object.assign(this, values); } } diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index f3a8c469..c3b22e22 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -1,9 +1,9 @@
    - -
  • + +
  • -
    +
    diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ngapp/src/app/connections/add-connection/add-connection.component.ts index f797c14b..52cb44e9 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.ts @@ -33,7 +33,7 @@ import { AbstractPageComponent } from "@shared/abstract-page.component"; }) export class AddConnectionComponent extends AbstractPageComponent { - public readonly addConnectionLink = ConnectionsConstants.addConnectionPath; + public readonly connectionsLink = ConnectionsConstants.connectionsRootPath; private router: Router; private connectionService: ConnectionService; diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index 24826296..9e48cabb 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -1,9 +1,9 @@
    - +
  • -
    +
    diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index b2eea625..56921641 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -49,6 +49,8 @@ import { SharedModule } from "@shared/shared.module"; ], providers: [ ConnectionService + ], + exports: [ ] }) export class ConnectionsModule { } diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.html b/ngapp/src/app/connections/edit-connection/edit-connection.component.html index 37e19af2..f4550b53 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.html +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.html @@ -1,13 +1,16 @@
    - +
  • -
    +
    -

    Edit Connection

    +

    Connection Properties

    +
    +
    +
    + (editActivity)="onEdit($event)" (startActivity)="onStart($event)" (deleteActivity)="onDelete($event)" + (activitySelected)="onSelected($event)" (activityDeselected)="onDeselected($event)"> + (editActivity)="onEdit($event)" (startActivity)="onStart($event)" (deleteActivity)="onDelete($event)" + (activitySelected)="onSelected($event)" (activityDeselected)="onDeselected($event)">
    @@ -102,6 +102,6 @@

    - +

    Do you really want to delete the selected Activity?

    diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts index 2eb9437c..2e559287 100644 --- a/ngapp/src/app/activities/activities.component.spec.ts +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -18,7 +18,9 @@ describe("ActivitiesComponent", () => { imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], declarations: [ ActivitiesComponent, ActivitiesListComponent, ActivitiesCardsComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index 6352d7e9..d66859b6 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -81,7 +81,9 @@ export class ActivitiesComponent extends AbstractPageComponent { public onEdit(activityName: string): void { const link: string[] = [ ActivitiesConstants.editActivityPath ]; - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); } public onDelete(activityName: string): void { @@ -157,7 +159,7 @@ export class ActivitiesComponent extends AbstractPageComponent { /** * Called to doDelete all selected APIs. */ - public deleteActivity(): void { + public onDeleteActivity(): void { const selectedActivity = this.filterActivities().find((x) => x.getId() === this.activityNameForDelete); const activityToDelete: NewActivity = new NewActivity(); diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts index abc3400d..599796fa 100644 --- a/ngapp/src/app/activities/activities.module.ts +++ b/ngapp/src/app/activities/activities.module.ts @@ -27,6 +27,7 @@ import { NgModule } from "@angular/core"; import { FormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; import { ConnectionsModule } from "@connections/connections.module"; +import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; @NgModule({ @@ -34,6 +35,7 @@ import { SharedModule } from "@shared/shared.module"; ActivitiesRoutingModule, CommonModule, ConnectionsModule, + CoreModule, SharedModule, RouterModule, FormsModule diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.css b/ngapp/src/app/activities/add-activity/add-activity.component.css index 4508ce85..fb12bd19 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.css +++ b/ngapp/src/app/activities/add-activity/add-activity.component.css @@ -2,7 +2,7 @@ padding: 15px } -.add-activity-form .form-instructions { +.add-activity-form /*.form-instructions*/ { font-size: 15px; padding-top: 10px } diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.html b/ngapp/src/app/activities/add-activity/add-activity.component.html index 87ded917..89deb300 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.html +++ b/ngapp/src/app/activities/add-activity/add-activity.component.html @@ -10,7 +10,7 @@

    Add Activity

    - +
    diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 6f83ea28..048727b2 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -20,7 +20,9 @@ describe("AddActivityComponent", () => { { provide: ActivityService, useClass: MockActivityService }, ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.ts b/ngapp/src/app/activities/add-activity/add-activity.component.ts index c247d99f..ac48be27 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.ts @@ -57,7 +57,9 @@ export class AddActivityComponent extends AbstractPageComponent { this.activityService.createActivity(activity); const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; this.logger.log("[AddActivityComponent] Navigating to: %o", link); - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); } } diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.css b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.css index ccc697d4..9061d0cf 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.css +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.css @@ -2,29 +2,36 @@ select { width: auto; } +/* .create-activity-form-panel.dragging { border: 1px dashed #39a5dc; background-color: #eef; } +*/ .create-activity-form-panel { padding-top: 25px; } +/* span.disabled { color: #999; } +*/ .dropdown ul { max-height: 250px; overflow: auto; } +/* div.spinner { display: inline-block; margin-right: 5px; } +*/ +/* .platform-toggle { display: inline-block; text-align: center; @@ -48,13 +55,18 @@ div.spinner { opacity: 0.6; cursor: not-allowed; } +*/ .platform-toggle span.fa { font-size: 32px; } +/* .platform-toggle span.lbl { font-size: 14px; } +*/ +/* .account-link-warning { margin-top: 10px; } +*/ diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts index b97472f0..76123eaa 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts @@ -13,7 +13,9 @@ describe("AddActivityFormComponent", () => { imports: [ CoreModule, FormsModule, RouterTestingModule ], declarations: [ AddActivityFormComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts index 28cb994a..e8b39ba4 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts @@ -122,7 +122,9 @@ export class AddActivityFormComponent { public cancelAdd(): void { const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); } } diff --git a/ngapp/src/app/app.component.spec.ts b/ngapp/src/app/app.component.spec.ts index 184f0bbf..0cc4a0d9 100644 --- a/ngapp/src/app/app.component.spec.ts +++ b/ngapp/src/app/app.component.spec.ts @@ -10,7 +10,9 @@ describe("AppComponent", () => { declarations: [ AppComponent ], - }).compileComponents(); + }).compileComponents().then(() => { + // nothing to do + }); })); it("should create the app", async(() => { diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.css b/ngapp/src/app/connections/add-connection/add-connection.component.css index 77de754d..a9b865e5 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.css +++ b/ngapp/src/app/connections/add-connection/add-connection.component.css @@ -2,7 +2,7 @@ padding: 15px } -.add-connection-form .form-instructions { +.add-connection-form /*.form-instructions*/ { font-size: 15px; padding-top: 10px } diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index c3b22e22..7576883d 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -10,7 +10,7 @@

    Add Connection

    - +
    diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index ad0ca88c..04a3b256 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -20,7 +20,9 @@ describe("AddConnectionComponent", () => { { provide: ConnectionService, useClass: MockConnectionService }, ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ngapp/src/app/connections/add-connection/add-connection.component.ts index cb821e14..309d10d0 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.ts @@ -61,7 +61,9 @@ export class AddConnectionComponent extends AbstractPageComponent { this.form.connectionCreated(); const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; this.logger.log("[AddConnectionComponent] Navigating to: %o", link); - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); } ); diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.css b/ngapp/src/app/connections/connections-cards/connections-cards.component.css index 8956339e..61b8ac9e 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.css +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.css @@ -27,7 +27,7 @@ .connection-card { -webkit-transition: background-color 300ms; -moz-transition: background-color 300ms; - -ms-transition: background-color 300ms; + //-ms-transition: background-color 300ms; -o-transition: background-color 300ms; transition: background-color 300ms; height: 220px; @@ -40,10 +40,12 @@ background-color: rgb(221, 234, 255); } +/* .connection-description { font-size: 13px; overflow-y: auto; } +*/ .connection-card .connection-tags { margin-bottom: 8px; @@ -52,7 +54,7 @@ font-weight: bold; margin-right: 5px; } -.connection-card .connection-tags .connection-tag { +.connection-card .connection-tags /*.connection-tag*/ { margin-right: 5px; border: 1px solid #ccc; -webkit-border-radius: 2px; @@ -60,7 +62,7 @@ border-radius: 2px; padding: 2px 4px; } -.connection-card .connection-tags .connection-tag:hover { +.connection-card .connection-tags /*.connection-tag:hover*/ { cursor: pointer; background-color: #0088ce; border-color: #00659c; diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts index 555d014f..6d60bc2c 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts @@ -11,7 +11,9 @@ describe("ConnectionsCardsComponent", () => { imports: [ RouterTestingModule ], declarations: [ ConnectionsCardsComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.css b/ngapp/src/app/connections/connections-list/connections-list.component.css index 14cedd29..45813472 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.css +++ b/ngapp/src/app/connections/connections-list/connections-list.component.css @@ -2,7 +2,7 @@ .list-group-item { -webkit-transition: background-color 300ms; -moz-transition: background-color 300ms; - -ms-transition: background-color 300ms; + //-ms-transition: background-color 300ms; -o-transition: background-color 300ms; transition: background-color 300ms; } @@ -20,7 +20,7 @@ font-weight: bold; margin-right: 5px; } -.list-group-item .connection-tags .connection-tag { +.list-group-item .connection-tags /*.connection-tag*/ { margin-right: 5px; border: 1px solid #ccc; -webkit-border-radius: 2px; @@ -28,7 +28,7 @@ border-radius: 2px; padding: 2px 4px; } -.list-group-item .connection-tags .connection-tag:hover { +.list-group-item .connection-tags /*.connection-tag:hover*/ { cursor: pointer; background-color: #0088ce; border-color: #00659c; diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts index 60c27bf5..b0bad59a 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts +++ b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts @@ -11,7 +11,9 @@ describe("ConnectionsListComponent", () => { imports: [ RouterTestingModule ], declarations: [ ConnectionsListComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index 9e48cabb..96b2b28e 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -90,11 +90,11 @@

    + (editConnection)="onEdit($event)" (pingConnection)="onPing($event)" (deleteConnection)="onDelete($event)" + (connectionSelected)="onSelected($event)" (connectionDeselected)="onDeselected($event)"> + (editConnection)="onEdit($event)" (pingConnection)="onPing($event)" (deleteConnection)="onDelete($event)" + (connectionSelected)="onSelected($event)" (connectionDeselected)="onDeselected($event)">

    @@ -102,6 +102,6 @@

    - +

    Do you really want to delete the selected Connection?

    diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index c7c8aca4..658cf807 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -18,7 +18,9 @@ describe("ConnectionsComponent", () => { imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], declarations: [ ConnectionsComponent, ConnectionsListComponent, ConnectionsCardsComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index f6b82743..1d75907c 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -134,7 +134,9 @@ export class ConnectionsComponent extends AbstractPageComponent { public onEdit(connName: string): void { const link: string[] = [ ConnectionsConstants.editConnectionPath ]; - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); } public onDelete(connName: string): void { @@ -171,7 +173,7 @@ export class ConnectionsComponent extends AbstractPageComponent { /** * Called to doDelete all selected APIs. */ - public deleteConnection(): void { + public onDeleteConnection(): void { const selectedConn = this.filterConnections().find((x) => x.getId() === this.connectionNameForDelete); // const itemsToDelete: Connection[] = ArrayUtils.intersect(this.selectedConnections, this.filteredConnections); @@ -189,7 +191,9 @@ export class ConnectionsComponent extends AbstractPageComponent { this.removeConnectionFromList(selectedConn); const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; this.logger.log("[CreateApiPageComponent] Navigating to: %o", link); - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); } ); } diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 523541e4..56921641 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -27,12 +27,14 @@ import { ConnectionsComponent } from "@connections/connections.component"; import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; import { ConnectionService } from "@connections/shared/connection.service"; +import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; @NgModule({ imports: [ ConnectionsRoutingModule, CommonModule, + CoreModule, SharedModule, FormsModule, RouterModule diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.css b/ngapp/src/app/connections/edit-connection/edit-connection.component.css index 73a87d5c..1561fd4c 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.css +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.css @@ -2,7 +2,7 @@ padding: 15px } -.edit-connection-form .form-instructions { +.edit-connection-form /*.form-instructions*/ { font-size: 15px; padding-top: 10px } diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts index 431cff4d..749a83fb 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts @@ -21,7 +21,9 @@ describe("EditConnectionComponent", () => { { provide: ConnectionService, useClass: MockConnectionService }, ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css index 491084a8..c6783af4 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css @@ -2,29 +2,36 @@ select { width: auto; } +/* .create-connection-form-panel.dragging { border: 1px dashed #39a5dc; background-color: #eef; } +*/ .create-connection-form-panel { padding-top: 25px; } +/* span.disabled { color: #999; } +*/ .dropdown ul { max-height: 250px; overflow: auto; } +/* div.spinner { display: inline-block; margin-right: 5px; } +*/ +/* .platform-toggle { display: inline-block; text-align: center; @@ -58,3 +65,4 @@ div.spinner { .account-link-warning { margin-top: 10px; } +*/ diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts index 2f52da6d..66affc9a 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts @@ -12,7 +12,9 @@ describe("AddConnectionFormComponent", () => { imports: [ FormsModule, RouterTestingModule ], declarations: [ AddConnectionFormComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts index 54a5a12a..a4e037d0 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts @@ -29,7 +29,7 @@ import { LoggerService } from "@core/logger.service"; }) export class AddConnectionFormComponent { - private creatingConnection = false; + private creating = false; private logger: LoggerService; private model = new NewConnection(); private router: Router; @@ -113,19 +113,28 @@ export class AddConnectionFormComponent { this.logger.log("[AddConnectionFormComponent] Firing create-connection event: %o", connection); - this.creatingConnection = true; + this.creating = true; this.createConnection.emit(connection); } public cancelAdd(): void { const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); + } + + /** + * @returns {boolean} 'true' if the connection is being created + */ + public get creatingConnection(): boolean { + return this.creating; } /** * Called when the connection has been created. */ public connectionCreated(): void { - this.creatingConnection = false; + this.creating = false; } } diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css index f0673af3..5f1b677d 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css @@ -1,3 +1,5 @@ +/* .studio-breadcrumb { color: inherit; } +*/ diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts index ac1e2d9b..3c490b83 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts @@ -11,7 +11,9 @@ describe("BreadcrumbComponent", () => { imports: [ RouterTestingModule ], declarations: [ BreadcrumbComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts index aea8e021..2cea6f65 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts @@ -9,7 +9,9 @@ describe("BreadcrumbsComponent", () => { TestBed.configureTestingModule({ declarations: [ BreadcrumbsComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index fae5ef5d..3f77f98a 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -16,9 +16,10 @@ */ import { CommonModule } from "@angular/common"; -import { NgModule} from "@angular/core"; +import { NgModule, Optional, SkipSelf } from "@angular/core"; import {HttpModule} from "@angular/http"; import {RouterModule} from "@angular/router"; +import { ApiService } from "@core/api.service"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; import { LoggerService } from "@core/logger.service"; @@ -44,7 +45,16 @@ import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component" VerticalNavComponent ], providers: [ + ApiService, LoggerService ] }) -export class CoreModule { } +export class CoreModule { + + constructor( @Optional() @SkipSelf() parentModule: CoreModule ) { + if ( parentModule ) { + throw new Error( "CoreModule is already loaded and should only be mported by the AppModule." ); + } + } + +} diff --git a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts index 454cc499..743e2c8e 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts @@ -9,7 +9,9 @@ describe("NavHeaderComponent", () => { TestBed.configureTestingModule({ declarations: [ NavHeaderComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.less b/ngapp/src/app/core/vertical-nav/vertical-nav.component.less index dd4b3984..a79e36a9 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.less +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.less @@ -53,7 +53,7 @@ padding: 15px; -webkit-transition: left 200ms; -moz-transition: left 200ms; - -ms-transition: left 200ms; + //-ms-transition: left 200ms; -o-transition: left 200ms; transition: left 200ms; } diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts index 2e155a86..f312cbf7 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts @@ -11,7 +11,9 @@ describe("VerticalNavComponent", () => { imports: [RouterTestingModule], declarations: [ VerticalNavComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index cec7bbbc..f0404faa 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -91,7 +91,9 @@ export class VerticalNavComponent implements OnInit { private onActivitiesClick(): void { this.currentMenu = VerticalNavType.Activities; const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); } /** @@ -100,7 +102,9 @@ export class VerticalNavComponent implements OnInit { private onConnectionsClick(): void { this.currentMenu = VerticalNavType.Connections; const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; - this.router.navigate(link); + this.router.navigate(link).then(() => { + // nothing to do + }); } /** diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts index fecdd15c..932c770b 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts @@ -11,7 +11,9 @@ describe("ConfirmDeleteComponent", () => { imports: [ModalModule.forRoot()], declarations: [ ConfirmDeleteComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/shared/identifiable.ts b/ngapp/src/app/shared/identifiable.ts index c81fbf5f..66e7223a 100644 --- a/ngapp/src/app/shared/identifiable.ts +++ b/ngapp/src/app/shared/identifiable.ts @@ -22,6 +22,7 @@ export interface Identifiable< T > { /** * @returns {T} the object identifier (can be null) + * @template T the identifier type */ getId(): T; diff --git a/ngapp/src/app/shared/page-error/page-error.component.spec.ts b/ngapp/src/app/shared/page-error/page-error.component.spec.ts index 94b65b0e..f237e4c7 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.spec.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.spec.ts @@ -11,7 +11,9 @@ describe("PageErrorComponent", () => { imports: [ HttpModule ], declarations: [ PageErrorComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts b/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts index ca583db0..078092d5 100644 --- a/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts +++ b/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts @@ -9,7 +9,9 @@ describe("PageNotFoundComponent", () => { TestBed.configureTestingModule({ declarations: [ PageNotFoundComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/shared/property-form/property-definition.model.ts b/ngapp/src/app/shared/property-form/property-definition.model.ts index 9550b942..8c194be2 100644 --- a/ngapp/src/app/shared/property-form/property-definition.model.ts +++ b/ngapp/src/app/shared/property-form/property-definition.model.ts @@ -46,6 +46,7 @@ export class PropertyDefinition { /** * @returns {T} the property value (can be null) + * @template T the type of the value */ public getValue(): T { return this.value; @@ -152,6 +153,7 @@ export class PropertyDefinition { /** * @param {T} value the property value + * @template T the type of the value */ public setValue( value?: T ): void { this.value = value ? value : null; diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html index 70ad85fa..07ef24ac 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html @@ -4,12 +4,13 @@
    + [id]="property.getId()" type="text" title="A text value"> + [id]="property.getId()" type="checkbox" title="A boolean value"> - diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts index 35acec5e..175fd33a 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts @@ -12,7 +12,9 @@ describe("PropertyFormPropertyComponent", () => { imports: [ ReactiveFormsModule ], declarations: [ PropertyFormPropertyComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/shared/property-form/property-form.component.spec.ts b/ngapp/src/app/shared/property-form/property-form.component.spec.ts index da56634d..06b2710c 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.spec.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.spec.ts @@ -13,7 +13,9 @@ describe("PropertyFormComponent", () => { imports: [ FormsModule ], declarations: [ PropertyFormComponent, PropertyFormPropertyComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/typings.d.ts b/ngapp/src/typings.d.ts index ef5c7bd6..e20662ca 100644 --- a/ngapp/src/typings.d.ts +++ b/ngapp/src/typings.d.ts @@ -1,4 +1,5 @@ /* SystemJS module definition */ +// noinspection ES6ConvertVarToLetConst declare var module: NodeModule; interface NodeModule { id: string; From 64c86935cfdcad4184ef9cd671dbb555b36789e5 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Wed, 11 Oct 2017 17:27:22 -0500 Subject: [PATCH 017/205] fixes some unit tests --- .../app/activities/shared/activity.service.spec.ts | 6 ++++-- .../add-connection-form.component.spec.ts | 10 ++++++---- .../app/connections/shared/connection.service.spec.ts | 6 ++++-- ngapp/src/app/core/api.service.spec.ts | 6 ++++-- .../app/core/nav-header/nav-header.component.spec.ts | 11 +++++++---- .../core/vertical-nav/vertical-nav.component.spec.ts | 11 +++++++---- 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/ngapp/src/app/activities/shared/activity.service.spec.ts b/ngapp/src/app/activities/shared/activity.service.spec.ts index 64e8f7e6..9ed7161e 100644 --- a/ngapp/src/app/activities/shared/activity.service.spec.ts +++ b/ngapp/src/app/activities/shared/activity.service.spec.ts @@ -1,16 +1,18 @@ import { ActivityService } from "@activities/shared/activity.service"; import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; +import { LoggerService } from "@core/logger.service"; describe("ActivityService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], - providers: [ActivityService] + providers: [ActivityService, LoggerService] }); }); - it("should be created", inject([ActivityService], (service: ActivityService) => { + it("should be created", inject([ActivityService, LoggerService], + (service: ActivityService, logger: LoggerService) => { expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts index 66affc9a..b6979f2b 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts @@ -1,7 +1,8 @@ -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; import {FormsModule} from "@angular/forms"; import {RouterTestingModule} from "@angular/router/testing"; import {AddConnectionFormComponent} from "./add-connection-form.component"; +import { LoggerService } from "@core/logger.service"; describe("AddConnectionFormComponent", () => { let component: AddConnectionFormComponent; @@ -10,7 +11,8 @@ describe("AddConnectionFormComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ FormsModule, RouterTestingModule ], - declarations: [ AddConnectionFormComponent ] + declarations: [ AddConnectionFormComponent ], + providers: [ LoggerService ] }) .compileComponents().then(() => { // nothing to do @@ -23,7 +25,7 @@ describe("AddConnectionFormComponent", () => { fixture.detectChanges(); }); - it("should be created", () => { + it("should be created", inject([ LoggerService ], ( logger: LoggerService ) => { expect(component).toBeTruthy(); - }); + })); }); diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ngapp/src/app/connections/shared/connection.service.spec.ts index 36c64aac..53c6e5c8 100644 --- a/ngapp/src/app/connections/shared/connection.service.spec.ts +++ b/ngapp/src/app/connections/shared/connection.service.spec.ts @@ -2,16 +2,18 @@ import {inject, TestBed} from "@angular/core/testing"; import {HttpModule} from "@angular/http"; import {ConnectionService} from "./connection.service"; +import { LoggerService } from "@core/logger.service"; describe("ConnectionService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], - providers: [ConnectionService] + providers: [ConnectionService, LoggerService] }); }); - it("should be created", inject([ConnectionService], (service: ConnectionService) => { + it("should be created", inject([ConnectionService, LoggerService], + (service: ConnectionService, logger: LoggerService ) => { expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/api.service.spec.ts b/ngapp/src/app/core/api.service.spec.ts index adb65131..6203f07d 100644 --- a/ngapp/src/app/core/api.service.spec.ts +++ b/ngapp/src/app/core/api.service.spec.ts @@ -1,16 +1,18 @@ import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; import { ApiService } from "@core/api.service"; +import { LoggerService } from "@core/logger.service"; describe("ApiService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpModule], - providers: [ApiService] + providers: [ApiService, LoggerService] }); }); - it("should be created", inject([ApiService], (service: ApiService) => { + it("should be created", inject([ApiService, LoggerService], + (service: ApiService, logger: LoggerService) => { expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts index 743e2c8e..c5db5107 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts @@ -1,5 +1,6 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; +import { LoggerService } from "@core/logger.service"; describe("NavHeaderComponent", () => { let component: NavHeaderComponent; @@ -7,7 +8,8 @@ describe("NavHeaderComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ NavHeaderComponent ] + declarations: [ NavHeaderComponent ], + providers: [ LoggerService ] }) .compileComponents().then(() => { // nothing to do @@ -20,7 +22,8 @@ describe("NavHeaderComponent", () => { fixture.detectChanges(); }); - it("should be created", () => { + it("should be created", inject([ LoggerService ], + (logger: LoggerService ) => { expect(component).toBeTruthy(); - }); + })); }); diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts index f312cbf7..f4b5a82b 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts @@ -1,6 +1,7 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; +import { LoggerService } from "@core/logger.service"; describe("VerticalNavComponent", () => { let component: VerticalNavComponent; @@ -9,7 +10,8 @@ describe("VerticalNavComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [RouterTestingModule], - declarations: [ VerticalNavComponent ] + declarations: [ VerticalNavComponent ], + providers: [ LoggerService ] }) .compileComponents().then(() => { // nothing to do @@ -22,7 +24,8 @@ describe("VerticalNavComponent", () => { fixture.detectChanges(); }); - it("should be created", () => { + it("should be created", inject([ LoggerService ], + (logger: LoggerService ) => { expect(component).toBeTruthy(); - }); + })); }); From 7e7ca3a2904f197768ee5aa698a719d74201b9b1 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 12 Oct 2017 11:11:36 -0500 Subject: [PATCH 018/205] Upgrade to latest version of tslint --- ngapp/package-lock.json | 37 +++++++------------ ngapp/package.json | 4 +- .../activities-cards.component.spec.ts | 6 +-- .../activities-list.component.spec.ts | 6 +-- .../activities/activities.component.spec.ts | 20 +++++----- .../add-activity.component.spec.ts | 18 ++++----- .../shared/mock-activity.service.ts | 12 +++--- .../add-connection.component.spec.ts | 18 ++++----- .../connections/connections.component.spec.ts | 20 +++++----- .../edit-connection.component.spec.ts | 20 +++++----- .../add-connection-form.component.spec.ts | 6 +-- .../shared/connection.service.spec.ts | 7 ++-- .../shared/mock-connection.service.ts | 8 ++-- ngapp/src/app/core/api.service.ts | 2 +- .../breadcrumb/breadcrumb.component.spec.ts | 6 +-- .../breadcrumb/breadcrumb.component.ts | 2 +- .../core/breadcrumbs/breadcrumbs.component.ts | 2 +- ngapp/src/app/core/core.module.ts | 4 +- .../nav-header/nav-header.component.spec.ts | 2 +- .../core/nav-header/nav-header.component.ts | 2 +- .../vertical-nav.component.spec.ts | 2 +- .../src/app/shared/abstract-page.component.ts | 6 +-- .../confirm-delete.component.ts | 4 +- ngapp/src/app/shared/identifiable.ts | 2 +- .../shared/page-error/page-error.component.ts | 2 +- .../property-definition.model.ts | 4 +- .../property-form-property.component.ts | 19 +++++++++- .../property-form.component.spec.ts | 22 +++++++++-- .../app/shared/validators/name-validator.ts | 19 +++++++++- ngapp/tslint.json | 9 ++--- 30 files changed, 163 insertions(+), 128 deletions(-) diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index b8ee70d8..1c446176 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -225,9 +225,9 @@ } }, "@types/node": { - "version": "6.0.88", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.88.tgz", - "integrity": "sha512-bYDPZTX0/s1aihdjLuAgogUAT5M+TpoWChEMea2p0yOcfn5bu3k6cJb9cp6nw268XeSNIGGr+4+/8V5K6BGzLQ==", + "version": "6.0.89", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.89.tgz", + "integrity": "sha512-Z/67L97+6H1qJiEEHSN1SQapkWjDss1D90rAnFcQ6UxKkah9juzotK5UNEP1bDv/0lJ3NAQTnVfc/JWdgCGruA==", "dev": true }, "@types/q": { @@ -7085,7 +7085,7 @@ "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", "dev": true, "requires": { - "@types/node": "6.0.88", + "@types/node": "6.0.89", "@types/q": "0.0.32", "@types/selenium-webdriver": "2.53.42", "blocking-proxy": "0.0.5", @@ -8858,38 +8858,27 @@ "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=" }, "tslint": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.3.2.tgz", - "integrity": "sha1-5WRZ+wlacwfxA7hAUhdPXju+9u0=", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz", + "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=", "dev": true, "requires": { "babel-code-frame": "6.26.0", "colors": "1.1.2", + "commander": "2.11.0", "diff": "3.3.1", "glob": "7.1.2", - "optimist": "0.6.1", + "minimatch": "3.0.4", "resolve": "1.4.0", "semver": "5.4.1", "tslib": "1.7.1", - "tsutils": "2.10.0" - }, - "dependencies": { - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "0.0.8", - "wordwrap": "0.0.3" - } - } + "tsutils": "2.12.1" } }, "tsutils": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.10.0.tgz", - "integrity": "sha1-rpRRHfJlbrBuRCQFb7pcOIiHBAw=", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.12.1.tgz", + "integrity": "sha1-9Nlc4zkciXHkblTEzw7bCiHdWyQ=", "dev": true, "requires": { "tslib": "1.7.1" diff --git a/ngapp/package.json b/ngapp/package.json index 71bf8330..ae8f8c79 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -32,7 +32,7 @@ "@angular/language-service": "^4.2.4", "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", - "@types/node": "~6.0.60", + "@types/node": "^6.0.89", "codelyzer": "~3.1.1", "jasmine-core": "~2.6.2", "jasmine-spec-reporter": "~4.1.0", @@ -44,7 +44,7 @@ "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.1.2", "ts-node": "~3.2.0", - "tslint": "~5.3.2", + "tslint": "~5.7.0", "typescript": "~2.3.3" } } diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts index c7c73eb4..4b099a3e 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts @@ -1,6 +1,6 @@ -import {ActivitiesCardsComponent} from "@activities/activities-cards/activities-cards.component"; -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; -import {RouterModule} from "@angular/router"; +import { ActivitiesCardsComponent } from "@activities/activities-cards/activities-cards.component"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterModule } from "@angular/router"; describe("ActivitiesCardsComponent", () => { let component: ActivitiesCardsComponent; diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts index 325c1f04..b0b4f442 100644 --- a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts +++ b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts @@ -1,6 +1,6 @@ -import {ActivitiesListComponent} from "@activities/activities-list/activities-list.component"; -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; -import {RouterModule} from "@angular/router"; +import { ActivitiesListComponent } from "@activities/activities-list/activities-list.component"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterModule } from "@angular/router"; describe("ActivitiesListComponent", () => { let component: ActivitiesListComponent; diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts index 2e559287..09c246a8 100644 --- a/ngapp/src/app/activities/activities.component.spec.ts +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -1,13 +1,13 @@ -import {ActivitiesCardsComponent} from "@activities/activities-cards/activities-cards.component"; -import {ActivitiesListComponent} from "@activities/activities-list/activities-list.component"; -import {ActivitiesComponent} from "@activities/activities.component"; -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; -import {FormsModule} from "@angular/forms"; -import {HttpModule} from "@angular/http"; -import {RouterTestingModule} from "@angular/router/testing"; -import {CoreModule} from "@core/core.module"; -import {SharedModule} from "@shared/shared.module"; -import {ModalModule} from "ngx-bootstrap"; +import { ActivitiesCardsComponent } from "@activities/activities-cards/activities-cards.component"; +import { ActivitiesListComponent } from "@activities/activities-list/activities-list.component"; +import { ActivitiesComponent } from "@activities/activities.component"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { RouterTestingModule } from "@angular/router/testing"; +import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { ModalModule } from "ngx-bootstrap"; describe("ActivitiesComponent", () => { let component: ActivitiesComponent; diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 048727b2..9d6a6f0b 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -1,12 +1,12 @@ -import {AddActivityComponent} from "@activities/add-activity/add-activity.component"; -import {ActivityService} from "@activities/shared/activity.service"; -import {AddActivityFormComponent} from "@activities/shared/add-activity-form/add-activity-form.component"; -import {MockActivityService} from "@activities/shared/mock-activity.service"; -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; -import {FormsModule} from "@angular/forms"; -import {HttpModule} from "@angular/http"; -import {RouterTestingModule} from "@angular/router/testing"; -import {CoreModule} from "@core/core.module"; +import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; +import { ActivityService } from "@activities/shared/activity.service"; +import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; +import { MockActivityService } from "@activities/shared/mock-activity.service"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { RouterTestingModule } from "@angular/router/testing"; +import { CoreModule } from "@core/core.module"; describe("AddActivityComponent", () => { let component: AddActivityComponent; diff --git a/ngapp/src/app/activities/shared/mock-activity.service.ts b/ngapp/src/app/activities/shared/mock-activity.service.ts index a983c80a..53fe4598 100644 --- a/ngapp/src/app/activities/shared/mock-activity.service.ts +++ b/ngapp/src/app/activities/shared/mock-activity.service.ts @@ -1,9 +1,9 @@ -import {Activity } from "@activities/shared/activity.model"; -import {NewActivity } from "@activities/shared/new-activity.model"; -import {Injectable } from "@angular/core"; -import {Http} from "@angular/http"; -import {Connection} from "@connections/shared/connection.model"; -import {NewConnection} from "@connections/shared/new-connection.model"; +import { Activity } from "@activities/shared/activity.model"; +import { NewActivity } from "@activities/shared/new-activity.model"; +import { Injectable } from "@angular/core"; +import { Http } from "@angular/http"; +import { Connection } from "@connections/shared/connection.model"; +import { NewConnection } from "@connections/shared/new-connection.model"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 04a3b256..6d996ee2 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -1,12 +1,12 @@ -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; -import {FormsModule} from "@angular/forms"; -import {HttpModule} from "@angular/http"; -import {RouterTestingModule} from "@angular/router/testing"; -import {AddConnectionFormComponent} from "@connections/shared/add-connection-form/add-connection-form.component"; -import {ConnectionService} from "@connections/shared/connection.service"; -import {MockConnectionService} from "@connections/shared/mock-connection.service"; -import {CoreModule} from "@core/core.module"; -import {AddConnectionComponent} from "./add-connection.component"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { RouterTestingModule } from "@angular/router/testing"; +import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; +import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { CoreModule } from "@core/core.module"; describe("AddConnectionComponent", () => { let component: AddConnectionComponent; diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index 658cf807..e3c3c1a0 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -1,13 +1,13 @@ -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; -import {FormsModule} from "@angular/forms"; -import {HttpModule} from "@angular/http"; -import {RouterTestingModule} from "@angular/router/testing"; -import {ConnectionsCardsComponent} from "@connections/connections-cards/connections-cards.component"; -import {ConnectionsListComponent} from "@connections/connections-list/connections-list.component"; -import {ConnectionsComponent} from "@connections/connections.component"; -import {CoreModule} from "@core/core.module"; -import {SharedModule} from "@shared/shared.module"; -import {ModalModule} from "ngx-bootstrap"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; +import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; +import { ConnectionsComponent } from "@connections/connections.component"; +import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { ModalModule } from "ngx-bootstrap"; describe("ConnectionsComponent", () => { let component: ConnectionsComponent; diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts index 749a83fb..531a69dd 100644 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts +++ b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts @@ -1,13 +1,13 @@ -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; -import {ReactiveFormsModule} from "@angular/forms"; -import {HttpModule} from "@angular/http"; -import {RouterTestingModule} from "@angular/router/testing"; -import {ConnectionService} from "@connections/shared/connection.service"; -import {MockConnectionService} from "@connections/shared/mock-connection.service"; -import {CoreModule} from "@core/core.module"; -import {PropertyFormPropertyComponent} from "@shared/property-form/property-form-property/property-form-property.component"; -import {PropertyFormComponent} from "@shared/property-form/property-form.component"; -import {EditConnectionComponent} from "./edit-connection.component"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { ReactiveFormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { CoreModule } from "@core/core.module"; +import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; +import { PropertyFormComponent } from "@shared/property-form/property-form.component"; +import { EditConnectionComponent } from "./edit-connection.component"; describe("EditConnectionComponent", () => { let component: EditConnectionComponent; diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts index b6979f2b..bd3417a6 100644 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts +++ b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts @@ -1,7 +1,7 @@ import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; -import {FormsModule} from "@angular/forms"; -import {RouterTestingModule} from "@angular/router/testing"; -import {AddConnectionFormComponent} from "./add-connection-form.component"; +import { FormsModule } from "@angular/forms"; +import { RouterTestingModule } from "@angular/router/testing"; +import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; import { LoggerService } from "@core/logger.service"; describe("AddConnectionFormComponent", () => { diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ngapp/src/app/connections/shared/connection.service.spec.ts index 53c6e5c8..b17ce8df 100644 --- a/ngapp/src/app/connections/shared/connection.service.spec.ts +++ b/ngapp/src/app/connections/shared/connection.service.spec.ts @@ -1,7 +1,6 @@ -import {inject, TestBed} from "@angular/core/testing"; - -import {HttpModule} from "@angular/http"; -import {ConnectionService} from "./connection.service"; +import { inject, TestBed } from "@angular/core/testing"; +import { HttpModule } from "@angular/http"; +import { ConnectionService } from "@connections/shared/connection.service"; import { LoggerService } from "@core/logger.service"; describe("ConnectionService", () => { diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 7728d0f5..2ea45ccf 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -1,7 +1,7 @@ -import {Injectable } from "@angular/core"; -import {Http} from "@angular/http"; -import {Connection} from "@connections/shared/connection.model"; -import {NewConnection} from "@connections/shared/new-connection.model"; +import { Injectable } from "@angular/core"; +import { Http } from "@angular/http"; +import { Connection } from "@connections/shared/connection.model"; +import { NewConnection } from "@connections/shared/new-connection.model"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index ed43e897..7f63c46b 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -16,7 +16,7 @@ */ import { Injectable } from "@angular/core"; -import {Headers, RequestOptions} from "@angular/http"; +import { Headers, RequestOptions } from "@angular/http"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts index 3c490b83..5441208a 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts @@ -1,6 +1,6 @@ -import {async, ComponentFixture, TestBed} from "@angular/core/testing"; -import {RouterTestingModule} from "@angular/router/testing"; -import {BreadcrumbComponent} from "./breadcrumb.component"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterTestingModule } from "@angular/router/testing"; +import { BreadcrumbComponent } from "./breadcrumb.component"; describe("BreadcrumbComponent", () => { let component: BreadcrumbComponent; diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts index 0c58cbff..26e5febe 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import {Component, Input} from "@angular/core"; +import { Component, Input } from "@angular/core"; @Component({ moduleId: module.id, diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts index f40dafcd..2dfca8c4 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import {Component} from "@angular/core"; +import { Component } from "@angular/core"; @Component({ moduleId: module.id, diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 3f77f98a..e876d73b 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -17,8 +17,8 @@ import { CommonModule } from "@angular/common"; import { NgModule, Optional, SkipSelf } from "@angular/core"; -import {HttpModule} from "@angular/http"; -import {RouterModule} from "@angular/router"; +import { HttpModule } from "@angular/http"; +import { RouterModule } from "@angular/router"; import { ApiService } from "@core/api.service"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; diff --git a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts index c5db5107..6767a9f5 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts @@ -1,6 +1,6 @@ import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; -import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; import { LoggerService } from "@core/logger.service"; +import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; describe("NavHeaderComponent", () => { let component: NavHeaderComponent; diff --git a/ngapp/src/app/core/nav-header/nav-header.component.ts b/ngapp/src/app/core/nav-header/nav-header.component.ts index a0e0fb97..b9fc0fe0 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import {Component} from "@angular/core"; +import { Component } from "@angular/core"; import { LoggerService } from "@core/logger.service"; @Component({ diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts index f4b5a82b..b3029da0 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts @@ -1,7 +1,7 @@ import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; -import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; import { LoggerService } from "@core/logger.service"; +import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; describe("VerticalNavComponent", () => { let component: VerticalNavComponent; diff --git a/ngapp/src/app/shared/abstract-page.component.ts b/ngapp/src/app/shared/abstract-page.component.ts index e514d96b..70298999 100644 --- a/ngapp/src/app/shared/abstract-page.component.ts +++ b/ngapp/src/app/shared/abstract-page.component.ts @@ -15,11 +15,11 @@ * limitations under the License. */ -import {OnInit} from "@angular/core"; -import {ActivatedRoute} from "@angular/router"; +import { OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/combineLatest"; -import {Observable} from "rxjs/Observable"; +import { Observable } from "rxjs/Observable"; export abstract class AbstractPageComponent implements OnInit { diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts index bbd56a21..c4a86e47 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import {Component, EventEmitter, Output, QueryList, ViewChildren} from "@angular/core"; -import {ModalDirective} from "ngx-bootstrap"; +import { Component, EventEmitter, Output, QueryList, ViewChildren } from "@angular/core"; +import { ModalDirective } from "ngx-bootstrap"; @Component({ moduleId: module.id, diff --git a/ngapp/src/app/shared/identifiable.ts b/ngapp/src/app/shared/identifiable.ts index 66e7223a..b5726ae1 100644 --- a/ngapp/src/app/shared/identifiable.ts +++ b/ngapp/src/app/shared/identifiable.ts @@ -21,8 +21,8 @@ export interface Identifiable< T > { /** + * @typedef { object } T the type of the property that is used to identify the object * @returns {T} the object identifier (can be null) - * @template T the identifier type */ getId(): T; diff --git a/ngapp/src/app/shared/page-error/page-error.component.ts b/ngapp/src/app/shared/page-error/page-error.component.ts index 01bc073a..4f1ce727 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import {Component, Input} from "@angular/core"; +import { Component, Input } from "@angular/core"; @Component({ moduleId: module.id, diff --git a/ngapp/src/app/shared/property-form/property-definition.model.ts b/ngapp/src/app/shared/property-form/property-definition.model.ts index 8c194be2..ecd79fbb 100644 --- a/ngapp/src/app/shared/property-form/property-definition.model.ts +++ b/ngapp/src/app/shared/property-form/property-definition.model.ts @@ -45,8 +45,8 @@ export class PropertyDefinition { } /** + * @typedef { object } T the type of the property being queried * @returns {T} the property value (can be null) - * @template T the type of the value */ public getValue(): T { return this.value; @@ -152,8 +152,8 @@ export class PropertyDefinition { } /** + * @typedef { object } T the type of the property being set * @param {T} value the property value - * @template T the type of the value */ public setValue( value?: T ): void { this.value = value ? value : null; diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts index 0857af51..00c5ccac 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts @@ -1,5 +1,22 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Component, Input } from "@angular/core"; -import {AbstractControl, FormGroup} from "@angular/forms"; +import { AbstractControl, FormGroup } from "@angular/forms"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; diff --git a/ngapp/src/app/shared/property-form/property-form.component.spec.ts b/ngapp/src/app/shared/property-form/property-form.component.spec.ts index 06b2710c..6130d0c9 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.spec.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.spec.ts @@ -1,8 +1,24 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import {FormsModule} from "@angular/forms"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; -import { PropertyFormComponent } from "./property-form.component"; +import { PropertyFormComponent } from "@shared/property-form/property-form.component"; describe("PropertyFormComponent", () => { let component: PropertyFormComponent; diff --git a/ngapp/src/app/shared/validators/name-validator.ts b/ngapp/src/app/shared/validators/name-validator.ts index db7edf33..fca0d405 100644 --- a/ngapp/src/app/shared/validators/name-validator.ts +++ b/ngapp/src/app/shared/validators/name-validator.ts @@ -1,4 +1,21 @@ -import {AbstractControl} from "@angular/forms"; +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbstractControl } from "@angular/forms"; // TODO this is a sample validator. export function validateName(control: AbstractControl): any { diff --git a/ngapp/tslint.json b/ngapp/tslint.json index 5c976599..2845ac89 100644 --- a/ngapp/tslint.json +++ b/ngapp/tslint.json @@ -68,7 +68,7 @@ "no-access-missing-member": true, "no-arg": true, "no-bitwise": true, - "no-consecutive-blank-lines": true, + "no-consecutive-blank-lines": [ true ], "no-console": [ true, "debug", @@ -79,7 +79,7 @@ ], "no-construct": true, "no-debugger": true, - "no-duplicate-imports": true, + "no-duplicate-imports": false, "no-duplicate-super": true, "no-empty": true, "no-empty-interface": true, @@ -101,10 +101,7 @@ "no-unnecessary-initializer": true, "no-unused-expression": true, "no-use-before-declare": true, - "no-var-keyword": [ - true, - "as-needed" - ], + "no-var-keyword": true, "object-literal-key-quotes": false, "object-literal-sort-keys": false, "one-line": [ From 2929088ec5b36c1e3e55d3d495f92bb1eed3012f Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 16 Oct 2017 14:04:23 -0500 Subject: [PATCH 019/205] Incorporates patternfly-ng wizard --- ngapp/package-lock.json | 1511 +++++------------ ngapp/package.json | 1 + .../activities-cards.component.html | 10 +- .../activities-list.component.html | 10 +- .../add-connection-wizard.component.css | 18 + .../add-connection-wizard.component.html | 111 ++ .../add-connection-wizard.component.spec.ts | 36 + .../add-connection-wizard.component.ts | 392 +++++ .../add-connection.component.css | 12 - .../add-connection.component.html | 7 +- .../add-connection.component.spec.ts | 16 +- .../add-connection.component.ts | 67 +- .../connections-cards.component.html | 11 +- .../connections-cards.component.ts | 5 - .../connections-list.component.html | 11 +- .../connections-list.component.ts | 5 - .../connections/connections-routing.module.ts | 6 +- .../connections/connections.component.html | 4 +- .../app/connections/connections.component.ts | 7 - .../src/app/connections/connections.module.ts | 17 +- .../edit-connection.component.css | 12 - .../edit-connection.component.html | 21 - .../edit-connection.component.spec.ts | 38 - .../edit-connection.component.ts | 75 - .../add-connection-form.component.css | 68 - .../add-connection-form.component.html | 43 - .../add-connection-form.component.spec.ts | 31 - .../add-connection-form.component.ts | 140 -- .../connections/shared/connection.service.ts | 15 + .../shared/connections-constants.ts | 4 - .../shared/new-connection.model.ts | 12 +- .../shared/template-definition.model.ts | 87 + .../property-definition.model.ts | 3 + .../property-form-property.component.html | 3 + .../property-form-property.component.ts | 1 + .../property-form.component.html | 11 +- .../property-form/property-form.component.ts | 40 +- ngapp/src/app/shared/shared.module.ts | 3 +- 38 files changed, 1220 insertions(+), 1644 deletions(-) create mode 100644 ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.css create mode 100644 ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html create mode 100644 ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts create mode 100644 ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts delete mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.css delete mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.html delete mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts delete mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.ts delete mode 100644 ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css delete mode 100644 ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html delete mode 100644 ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts delete mode 100644 ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts create mode 100644 ngapp/src/app/connections/shared/template-definition.model.ts diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index 1c446176..ad5956a6 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -114,7 +114,6 @@ "version": "4.4.4", "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.4.4.tgz", "integrity": "sha1-BjCApJfZF1OWglBQIixxfaGE9s8=", - "dev": true, "requires": { "@angular/tsc-wrapped": "4.4.4", "minimist": "1.2.0", @@ -124,8 +123,7 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, @@ -175,6 +173,16 @@ "tslib": "1.7.1" } }, + "@angular/platform-server": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-4.4.4.tgz", + "integrity": "sha1-c+5B+hzshij8wDF0cnsnywAxsio=", + "requires": { + "parse5": "3.0.2", + "tslib": "1.7.1", + "xhr2": "0.1.4" + } + }, "@angular/router": { "version": "4.4.4", "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.4.4.tgz", @@ -187,7 +195,6 @@ "version": "4.4.4", "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.4.4.tgz", "integrity": "sha1-mEGCHlVha4JsoWAlD+heFfx0/8M=", - "dev": true, "requires": { "tsickle": "0.21.6" } @@ -352,6 +359,16 @@ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, + "angular-tree-component": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/angular-tree-component/-/angular-tree-component-4.1.0.tgz", + "integrity": "sha1-bPQhg4KRnJbmRacbUNffXJOySjs=", + "requires": { + "lodash": "4.17.4", + "mobx": "3.1.11", + "mobx-angular": "1.5.0" + } + }, "ansi-escapes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", @@ -1063,6 +1080,14 @@ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", "dev": true }, + "c3": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.18.tgz", + "integrity": "sha512-37TiFeCrbe69gg7SxFpTBOLDwulnk+opKp1AFDi43mONtErpRoUIZfGSimGiSYQmNu6Zh9W2yNOx0066UikqSg==", + "requires": { + "d3": "3.5.17" + } + }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", @@ -1182,7 +1207,6 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -1846,6 +1870,11 @@ "es5-ext": "0.10.30" } }, + "d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -2751,1049 +2780,150 @@ "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "fileset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", - "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", - "dev": true, - "requires": { - "glob": "7.1.2", - "minimatch": "3.0.4" - } - }, - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true, - "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.3.1", - "unpipe": "1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", - "dev": true, - "requires": { - "null-check": "1.0.0" - } - }, - "fs-extra": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", - "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", - "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.7.0", - "node-pre-gyp": "0.6.36" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.36", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "7.1.2", + "minimatch": "3.0.4" + } + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, - "optional": true, "requires": { - "string-width": "1.0.2" + "isarray": "1.0.0" } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true } } }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "1.0.0" + } + }, + "fs-extra": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -5410,8 +4540,7 @@ "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" }, "lodash.assign": { "version": "4.2.0", @@ -5757,8 +4886,7 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mixin-object": { "version": "2.0.1", @@ -5782,11 +4910,25 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" } }, + "mobx": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-3.1.11.tgz", + "integrity": "sha1-QAsePACkJJ3+Num8oo7zbwV9Sig=" + }, + "mobx-angular": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mobx-angular/-/mobx-angular-1.5.0.tgz", + "integrity": "sha1-bIBkg+v30WHltfUEjtwwD4UhyAw=" + }, + "moment": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz", + "integrity": "sha1-/tlQYGPzaxDwZsi1mhRNf66+HYI=" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6358,6 +5500,14 @@ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, + "parse5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.2.tgz", + "integrity": "sha1-Be/1fw70V3+xRKefi5qWemzERRA=", + "requires": { + "@types/node": "6.0.89" + } + }, "parsejson": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", @@ -6447,6 +5597,261 @@ "pinkie-promise": "2.0.1" } }, + "patternfly": { + "version": "3.27.7", + "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.27.7.tgz", + "integrity": "sha1-okEYcgvBPuu+b9bkgP2m65kBLaQ=", + "requires": { + "bootstrap": "3.3.7", + "bootstrap-datepicker": "1.6.4", + "bootstrap-select": "1.12.4", + "bootstrap-switch": "3.3.4", + "bootstrap-touchspin": "3.1.1", + "c3": "0.4.17", + "d3": "3.5.17", + "datatables.net": "1.10.15", + "datatables.net-colreorder": "1.3.3", + "datatables.net-colreorder-bs": "1.3.3", + "datatables.net-select": "1.2.2", + "drmonty-datatables-colvis": "1.1.2", + "eonasdan-bootstrap-datetimepicker": "4.17.47", + "font-awesome": "4.7.0", + "google-code-prettify": "1.0.5", + "jquery": "3.2.1", + "jquery-match-height": "0.7.2", + "moment": "2.14.1", + "moment-timezone": "0.4.1", + "patternfly-bootstrap-combobox": "1.1.7", + "patternfly-bootstrap-treeview": "2.1.5" + }, + "dependencies": { + "bootstrap": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz", + "integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E=" + }, + "bootstrap-datepicker": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.6.4.tgz", + "integrity": "sha1-iJ6+ztjqov8V7B8nPksHUxzEPaA=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "bootstrap-select": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.12.4.tgz", + "integrity": "sha1-fxXTwM6XiGjZwJxw+WYk9V+gLuE=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "bootstrap-switch": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/bootstrap-switch/-/bootstrap-switch-3.3.4.tgz", + "integrity": "sha1-cOCusqh3wNx2aZHeEI4hcPwpov8=", + "optional": true + }, + "bootstrap-touchspin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bootstrap-touchspin/-/bootstrap-touchspin-3.1.1.tgz", + "integrity": "sha1-l3nerHKq9Xfl52K4USx0fIcdlZc=", + "optional": true + }, + "c3": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.17.tgz", + "integrity": "sha512-41T3yS3jq1XgA7ruvV1wFVEK1E2az2iUAqS7hU5de62JVrjPyxWqIPu8AHlKpShZxJbD+DXLRkQHfOLASYyqyg==", + "optional": true, + "requires": { + "d3": "3.5.17" + } + }, + "d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=", + "optional": true + }, + "datatables.net": { + "version": "1.10.15", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.15.tgz", + "integrity": "sha1-x4kHe7/jhedf9aIz+l8jJRpy32g=", + "requires": { + "jquery": "3.2.1" + } + }, + "datatables.net-bs": { + "version": "1.10.15", + "resolved": "https://registry.npmjs.org/datatables.net-bs/-/datatables.net-bs-1.10.15.tgz", + "integrity": "sha1-ssImEAfYTKW1q/VsGO3CJ+DaGk0=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "datatables.net-colreorder": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/datatables.net-colreorder/-/datatables.net-colreorder-1.3.3.tgz", + "integrity": "sha1-/HYuNQ+UIkyyzUXCuWImGg//73I=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "datatables.net-colreorder-bs": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/datatables.net-colreorder-bs/-/datatables.net-colreorder-bs-1.3.3.tgz", + "integrity": "sha1-Op3LCN7r612FQHlZHgbkk615OlM=", + "optional": true, + "requires": { + "datatables.net-bs": "1.10.15", + "datatables.net-colreorder": "1.3.3", + "jquery": "3.2.1" + } + }, + "datatables.net-select": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/datatables.net-select/-/datatables.net-select-1.2.2.tgz", + "integrity": "sha1-llF5P1KJn05XRcByCCHouChvv0U=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "drmonty-datatables-colvis": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/drmonty-datatables-colvis/-/drmonty-datatables-colvis-1.1.2.tgz", + "integrity": "sha1-lque37SGQ8wu3aP4e4iTPN7oEnw=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "eonasdan-bootstrap-datetimepicker": { + "version": "4.17.47", + "resolved": "https://registry.npmjs.org/eonasdan-bootstrap-datetimepicker/-/eonasdan-bootstrap-datetimepicker-4.17.47.tgz", + "integrity": "sha1-ekmXAEQGUnbnll79Fvgic1IZ5zU=", + "optional": true, + "requires": { + "bootstrap": "3.3.7", + "jquery": "3.2.1", + "moment": "2.14.1", + "moment-timezone": "0.4.1" + } + }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, + "google-code-prettify": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/google-code-prettify/-/google-code-prettify-1.0.5.tgz", + "integrity": "sha1-n0d/Ik2/piNy5e+AOn4VdBBAAIQ=", + "optional": true + }, + "jquery": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", + "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" + }, + "jquery-match-height": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/jquery-match-height/-/jquery-match-height-0.7.2.tgz", + "integrity": "sha1-+NnzulMU2qsQnPB0CGdL4gS+Xw4=", + "optional": true + }, + "moment": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz", + "integrity": "sha1-s1snxH5X7S3ccAU9awe+zbKRdBw=" + }, + "moment-timezone": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.4.1.tgz", + "integrity": "sha1-gfWYw61eIs2teWtn7NjYjQ9bqgY=", + "optional": true, + "requires": { + "moment": "2.14.1" + } + }, + "patternfly-bootstrap-combobox": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/patternfly-bootstrap-combobox/-/patternfly-bootstrap-combobox-1.1.7.tgz", + "integrity": "sha1-al48zRFwwhs8S0qhaKdBPh3btuE=", + "optional": true + }, + "patternfly-bootstrap-treeview": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/patternfly-bootstrap-treeview/-/patternfly-bootstrap-treeview-2.1.5.tgz", + "integrity": "sha1-TCnyWC+4ovKPCpKPLw0yTSHWmQ0=", + "optional": true, + "requires": { + "bootstrap": "3.3.7", + "jquery": "3.2.1" + } + } + } + }, + "patternfly-ng": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-0.13.1.tgz", + "integrity": "sha1-1DYXTcCqqllUc6UG1o0Kc/432Qo=", + "requires": { + "@angular/animations": "4.4.4", + "@angular/common": "4.4.4", + "@angular/compiler": "4.4.4", + "@angular/compiler-cli": "4.4.4", + "@angular/core": "4.4.4", + "@angular/forms": "4.4.4", + "@angular/http": "4.4.4", + "@angular/platform-browser": "4.4.4", + "@angular/platform-browser-dynamic": "4.4.4", + "@angular/platform-server": "4.4.4", + "@angular/router": "4.4.4", + "angular-tree-component": "4.1.0", + "c3": "0.4.18", + "core-js": "2.4.1", + "moment": "2.17.1", + "ngx-bootstrap": "1.8.0", + "patternfly": "3.27.7", + "rxjs": "5.4.3", + "zone.js": "0.8.4" + }, + "dependencies": { + "core-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=" + }, + "ngx-bootstrap": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-1.8.0.tgz", + "integrity": "sha512-y4+9cQkCAZ8C2iHfGC9PMu6tqHqDPyZN0ejz4fDwWljAUtxqXqwUgPKAnebkckdLw/EFmozgvf27ouVqhDA+CA==", + "requires": { + "moment": "2.18.1" + }, + "dependencies": { + "moment": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", + "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" + } + } + }, + "zone.js": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.4.tgz", + "integrity": "sha1-zECuWhyHlgHF67oglrXIDwxMNgI=" + } + } + }, "pbkdf2": { "version": "3.0.14", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", @@ -7466,8 +6871,7 @@ "reflect-metadata": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.10.tgz", - "integrity": "sha1-tPg3BEFqytiZiMmxVjXUfgO5NEo=", - "dev": true + "integrity": "sha1-tPg3BEFqytiZiMmxVjXUfgO5NEo=" }, "regenerate": { "version": "1.3.3", @@ -8199,8 +7603,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-loader": { "version": "0.2.1", @@ -8246,7 +7649,6 @@ "version": "0.4.18", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, "requires": { "source-map": "0.5.7" } @@ -8836,7 +8238,6 @@ "version": "0.21.6", "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.21.6.tgz", "integrity": "sha1-U7Abl5xcE/2xOvs/uVgXflmRWI0=", - "dev": true, "requires": { "minimist": "1.2.0", "mkdirp": "0.5.1", @@ -8847,8 +8248,7 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, @@ -9728,6 +9128,11 @@ "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=", "dev": true }, + "xhr2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz", + "integrity": "sha1-f4dliEdxbbUCYyOBL4GMras4el8=" + }, "xml-char-classes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", diff --git a/ngapp/package.json b/ngapp/package.json index ae8f8c79..c4ca6315 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -23,6 +23,7 @@ "@angular/router": "^4.2.4", "core-js": "^2.4.1", "ngx-bootstrap": "^1.9.3", + "patternfly-ng": "^0.13.1", "rxjs": "^5.4.2", "zone.js": "^0.8.14" }, diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.html b/ngapp/src/app/activities/activities-cards/activities-cards.component.html index a96ebbfa..3a2e409a 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.html +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.html @@ -12,13 +12,11 @@


    -
    - Source: - {{ activity.getSourceConnection() }}    +
    + Source:  {{ activity.getSourceConnection() }}
    -
    - Target: - {{ activity.getSourceConnection() }}    +
    + Target:  {{ activity.getTargetConnection() }}
    -
    - Source: - {{ activity.getSourceConnection() }}    +
    + Source:  {{ activity.getSourceConnection() }}    
    -
    - Target: - {{ activity.getTargetConnection() }}    +
    + Target:  {{ activity.getTargetConnection() }}
    + + + +

    {{ step1InstructionMessage }}

    +
    +
    +
    +
    +
    + +
    + +
    {{ getBasicPropertyErrorMessage("driver") }}
    +
    +
    + +
    + +
    + +
    {{ getBasicPropertyErrorMessage("name") }}
    +
    +
    +
    + +
    + +
    {{ getBasicPropertyErrorMessage("jndi") }}
    +
    +
    +
    +
    + + + + +

    {{ step2InstructionMessage }}

    +
    +
    +
    +
    + +
    +
    + + + + + + +

    {{ step3InstructionMessage }}

    +

    Connection Properties:

    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +

    Connection Detail Required Properties:

    +
    +
    +
    + + +
    +
    +
    +
    + + +
    + +
    +
    +

    Creation in progress

    +

    The connection is being created.

    +
    + +
    +
    +

    Creation was successful

    +

    The connection was created successfully. Click on the button to see all connections.

    + View All Connections +
    + +
    +
    +

    Creation failed

    +

    The connection creation failed. Correct any properties and retry.

    +
    +
    +
    +
    + diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts new file mode 100644 index 00000000..b0f193d7 --- /dev/null +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts @@ -0,0 +1,36 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import {FormGroup, FormsModule, ReactiveFormsModule} from "@angular/forms"; +import {RouterTestingModule} from "@angular/router/testing"; +import {CoreModule} from "@core/core.module"; +import {PropertyFormPropertyComponent} from "@shared/property-form/property-form-property/property-form-property.component"; +import {PropertyFormComponent} from "@shared/property-form/property-form.component"; +import {SharedModule} from "@shared/shared.module"; +import {PatternFlyNgModule, WizardConfig, WizardStepComponent} from "patternfly-ng"; +import { AddConnectionWizardComponent } from "./add-connection-wizard.component"; + +describe("AddConnectionWizardComponent", () => { + let component: AddConnectionWizardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], + declarations: [ AddConnectionWizardComponent, FormGroup, PropertyFormComponent, PropertyFormPropertyComponent, + WizardConfig, WizardStepComponent ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddConnectionWizardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts new file mode 100644 index 00000000..5d9cdfdc --- /dev/null +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -0,0 +1,392 @@ +import { + Component, + OnInit, + ViewChild, + ViewEncapsulation, +} from "@angular/core"; + +import { FormControl, FormGroup} from "@angular/forms"; +import { AbstractControl } from "@angular/forms"; +import { Validators } from "@angular/forms"; +import { Router } from "@angular/router"; +import { ConnectionService} from "@connections/shared/connection.service"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { NewConnection } from "@connections/shared/new-connection.model"; +import { TemplateDefinition} from "@connections/shared/template-definition.model"; +import { LoggerService } from "@core/logger.service"; +import { PropertyDefinition } from "@shared/property-form/property-definition.model"; +import {PropertyFormComponent} from "@shared/property-form/property-form.component"; +import { WizardComponent } from "patternfly-ng"; +import { WizardEvent } from "patternfly-ng"; +import { WizardStepConfig } from "patternfly-ng"; +import { WizardConfig } from "patternfly-ng"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-add-connection-wizard", + templateUrl: "./add-connection-wizard.component.html" +}) +export class AddConnectionWizardComponent implements OnInit { + public readonly connectionSummaryLink: string = ConnectionsConstants.connectionsRootPath; + + // Wizard Config + public wizardConfig: WizardConfig; + + @ViewChild("wizard") private wizard: WizardComponent; + @ViewChild(PropertyFormComponent) private detailPropForm: PropertyFormComponent; + + private connectionService: ConnectionService; + private allTemplates: TemplateDefinition[] = []; + private templatesLoaded = false; + private detailPropertiesLoaded = false; + private basicPropertyForm: FormGroup; + private detailProperties: Array> = []; + private requiredPropValues: Array<[string, string]> = []; + + private createComplete = true; + private createSuccessful = false; + + // Wizard Step 1 + private step1Config: WizardStepConfig; + + // Wizard Step 2 + private step2Config: WizardStepConfig; + + // Wizard Step 3 + private step3Config: WizardStepConfig; + private step3aConfig: WizardStepConfig; + private step3bConfig: WizardStepConfig; + private logger: LoggerService; + private router: Router; + + constructor( router: Router, connectionService: ConnectionService, logger: LoggerService ) { + this.connectionService = connectionService; + this.router = router; + this.logger = logger; + this.createBasicPropertyForm(); + } + + /* + * Initialization + */ + public ngOnInit(): void { + // Step 1 - Basic Properties + this.step1Config = { + id: "step1", + priority: 0, + title: "Basic Properties", + allowClickNav: false + } as WizardStepConfig; + + // Step 2 - Advanced Properties + this.step2Config = { + id: "step2", + priority: 0, + title: "Detail Properties", + allowClickNav: false + } as WizardStepConfig; + + // Step 3 - Review and Create + this.step3Config = { + id: "step3", + priority: 2, + title: "Review and Create", + allowClickNav: false + } as WizardStepConfig; + this.step3aConfig = { + id: "step3a", + priority: 0, + title: "Review", + allowClickNav: false + } as WizardStepConfig; + this.step3bConfig = { + id: "step3b", + priority: 1, + title: "Create", + allowClickNav: false + } as WizardStepConfig; + + // Wizard Configuration + this.wizardConfig = { + embedInPage: true, + loadingTitle: "Add Connection Wizard loading", + loadingSecondaryInfo: "Please wait for the wizard to finish loading...", + title: "Add Connection", + sidebarStyleClass: "example-wizard-sidebar", + stepStyleClass: "example-wizard-step" + } as WizardConfig; + + // Load the templates for the first step + this.templatesLoaded = false; + this.connectionService + .getConnectionTemplates() + .subscribe( + (templates) => { + this.allTemplates = templates; + this.templatesLoaded = true; + }, + (error) => { + this.logger.error("[AddConnectionWizardComponent] Error getting templates: %o", error); + } + ); + + this.setNavAway(false); + } + + // ---------------- + // Public Methods + // ---------------- + + /* + * Return the name valid state + */ + public get nameValid(): boolean { + return this.basicPropertyForm.controls["name"].valid; + } + + /* + * Return the driver valid state + */ + public get driverValid(): boolean { + return this.basicPropertyForm.controls["driver"].valid; + } + + /* + * Return the jndi valid state + */ + public get jndiValid(): boolean { + return this.basicPropertyForm.controls["jndi"].valid; + } + + /* + * Step 1 instruction message + */ + public get step1InstructionMessage(): string { + if (!this.driverValid) { + return "Please select a Connection type"; + } else if (!this.nameValid) { + return "Please enter a name for the Connection"; + } else if (!this.jndiValid) { + return "Please enter a JNDI identifier for the Connection"; + } else { + return "When finished entering properties, click Next to continue"; + } + } + + /* + * Step 2 instruction message + */ + public get step2InstructionMessage(): string { + return "Enter advanced properties for the Connection, then click Next to continue"; + } + + /* + * Step 3 instruction message + */ + public get step3InstructionMessage(): string { + return "Review your entries. When finished, click Create to create the Connection"; + } + + /* + * Return the name error message if invalid + */ + public getBasicPropertyErrorMessage( name: string ): string { + const control: AbstractControl = this.basicPropertyForm.controls[name]; + if (control.invalid) { + // The first error found is returned + if (control.errors.required) { + return name + " is a required property"; + } + } + return ""; + } + + /* + * Return the array of template names + */ + public get templateNames(): string[] { + const templateNames: string[] = []; + for ( const templ of this.allTemplates ) { + templateNames.push(templ.getId()); + } + return templateNames.sort(); + } + + public nextClicked($event: WizardEvent): void { + // When leaving page 1, load the driver-specific property definitions + if ($event.step.config.id === "step1") { + this.loadPropertyDefinitions(this.basicPropertyForm.controls["driver"].value); + } + } + + public cancelClicked($event: WizardEvent): void { + const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; + this.logger.log("[AddConnectionWizardComponent] Navigating to: %o", link); + this.router.navigate(link).then(() => { + // nothing to do + }); + } + + /* + * Return the array of [name,value] for the required properties. + * So that the current required property entries can be shown on page 3 (review) + */ + public get requiredPropertyValues(): Array<[string, string]> { + return this.requiredPropValues; + } + + /* + * Create the Connection via komodo REST interface, + * using the currently entered properties + */ + public createConnection(): void { + this.createComplete = false; + this.wizardConfig.done = true; + + const connection: NewConnection = new NewConnection(); + + // Connection basic properties from step 1 + connection.setName(this.connectionName); + connection.setJndiName(this.connectionJndiName); + connection.setDriverName(this.connectionDriverName); + connection.setJdbc(this.isJdbc); + + // Connection advanced properties from step 2 + const propMap: Map = this.detailPropForm.propertyValuesNonDefault; + connection.setProperties(propMap); + + this.connectionService + .createConnection(connection) + .subscribe( + () => { + this.createComplete = true; + this.createSuccessful = true; + this.step3bConfig.nextEnabled = false; + }, + (error) => { + this.createComplete = true; + this.createSuccessful = false; + } + ); + } + + public stepChanged($event: WizardEvent): void { + if ($event.step.config.id === "step1") { + this.updatePage1ValidStatus(); + } else if ($event.step.config.id === "step3a") { + this.wizardConfig.nextTitle = "Create"; + this.updateRequiredPropertyValues(); + } else if ($event.step.config.id === "step3b") { + // Note: The next button is not disabled by default when wizard is done + this.step3Config.nextEnabled = false; + } else { + this.wizardConfig.nextTitle = "Next >"; + } + } + + public updatePage1ValidStatus( ): void { + this.step1Config.nextEnabled = this.basicPropertyForm.valid; + this.setNavAway(this.step1Config.nextEnabled); + } + + /** + * @returns {string} the name of the connection + */ + public get connectionName(): string { + return this.basicPropertyForm.controls["name"].value; + } + + /** + * @returns {string} the driver name of the connection + */ + public get connectionDriverName(): string { + return this.basicPropertyForm.controls["driver"].value; + } + + /** + * @returns {string} the JNDI name of the connection + */ + public get connectionJndiName(): string { + return this.basicPropertyForm.controls["jndi"].value; + } + + /** + * @returns {boolean} 'true' if connection is JDBC + */ + public get isJdbc(): boolean { + return true; + } + + // ---------------- + // Private Methods + // ---------------- + + /* + * Create the BasicProperty form (page 1) + */ + private createBasicPropertyForm(): void { + this.basicPropertyForm = new FormGroup({ + name: new FormControl("", Validators.required), + jndi: new FormControl("", Validators.required), + driver: new FormControl("", Validators.required) + }); + this.onChanges(); + } + + /* + * React to basic property changes - update the page 1 status + */ + private onChanges(): void { + this.basicPropertyForm.valueChanges.subscribe((val) => { + this.updatePage1ValidStatus( ); + }); + } + + private setNavAway(allow: boolean): void { + this.step1Config.allowNavAway = allow; + } + + /** + * Load the driver-specific property definitions + */ + private loadPropertyDefinitions( driverName ): void { + this.detailPropertiesLoaded = false; + const that = this; + this.connectionService + .getConnectionTemplateProperties(driverName) + .subscribe( + (props) => { + that.detailProperties = props; + this.detailPropertiesLoaded = true; + }, + (error) => { + this.logger.error("[AddConnectionWizardComponent] Error: %o", error); + // this.error(error); + this.detailPropertiesLoaded = false; + } + ); + } + + /** + * @returns {PropertyDefinition[]} the property definitions (can be null) + */ + private getPropertyDefinitions(): Array> { + return this.detailProperties; + } + + /** + * Generates array of required property values when page 3 (Review) is shown + */ + private updateRequiredPropertyValues(): void { + const propMap: Map = new Map(); + for (const property of this.detailProperties) { + if (property.isRequired()) { + const name = property.getId(); + const theValue = this.detailPropForm.getPropertyValue(name); + propMap.set(name, theValue); + } + } + this.requiredPropValues = Array.from(propMap); + } + +} diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.css b/ngapp/src/app/connections/add-connection/add-connection.component.css index a9b865e5..e69de29b 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.css +++ b/ngapp/src/app/connections/add-connection/add-connection.component.css @@ -1,12 +0,0 @@ -.add-connection-form { - padding: 15px -} - -.add-connection-form /*.form-instructions*/ { - font-size: 15px; - padding-top: 10px -} - -.add-connection-form .form-instructions ol { - padding-left: 20px; -} diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index 7576883d..a1d573d2 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -7,10 +7,11 @@
    -

    Add Connection

    +

    -
    - + +
    +
    diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 6d996ee2..1395eb59 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -1,12 +1,9 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { FormsModule } from "@angular/forms"; -import { HttpModule } from "@angular/http"; + import { RouterTestingModule } from "@angular/router/testing"; -import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; -import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AddConnectionWizardComponent } from "@connections/add-connection-wizard/add-connection-wizard.component"; import { CoreModule } from "@core/core.module"; +import { AddConnectionComponent } from "./add-connection.component"; describe("AddConnectionComponent", () => { let component: AddConnectionComponent; @@ -14,11 +11,8 @@ describe("AddConnectionComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, HttpModule, RouterTestingModule ], - declarations: [ AddConnectionComponent, AddConnectionFormComponent ], - providers: [ - { provide: ConnectionService, useClass: MockConnectionService }, - ] + imports: [ CoreModule, RouterTestingModule ], + declarations: [ AddConnectionComponent, AddConnectionWizardComponent ] }) .compileComponents().then(() => { // nothing to do diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ngapp/src/app/connections/add-connection/add-connection.component.ts index 309d10d0..738e69da 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.ts @@ -1,72 +1,21 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component } from "@angular/core"; -import { ViewChild } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { Router } from "@angular/router"; -import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { ConnectionsConstants } from "@connections/shared/connections-constants"; -import { NewConnection } from "@connections/shared/new-connection.model"; -import { LoggerService } from "@core/logger.service"; -import { AbstractPageComponent } from "@shared/abstract-page.component"; +import { Component, OnInit } from "@angular/core"; +import {ConnectionsConstants} from "@connections/shared/connections-constants"; @Component({ - moduleId: module.id, - selector: "app-add-connection", + selector: "app-add-connection-page", templateUrl: "./add-connection.component.html", styleUrls: ["./add-connection.component.css"] }) -export class AddConnectionComponent extends AbstractPageComponent { +export class AddConnectionComponent implements OnInit { public readonly connectionsLink = ConnectionsConstants.connectionsRootPath; - private router: Router; - private connectionService: ConnectionService; - - @ViewChild(AddConnectionFormComponent) private form: AddConnectionFormComponent; - - constructor(router: Router, route: ActivatedRoute, connectionService: ConnectionService, logger: LoggerService ) { - super(route, logger); - this.router = router; - this.connectionService = connectionService; + constructor() { + // Nothing } - /** - * Called when the Add Connection form (component) emits a "add-connection" event. This is bound to - * from the add-connection.page.html template. - * @param {NewConnection} connection - */ - public onCreateConnection(connection: NewConnection): void { - this.logger.log("[AddConnectionComponent] onCreateConnection(): " + JSON.stringify(connection)); - this.connectionService - .createConnection(connection) - .subscribe( - () => { - this.form.connectionCreated(); - const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; - this.logger.log("[AddConnectionComponent] Navigating to: %o", link); - this.router.navigate(link).then(() => { - // nothing to do - }); - } - ); - + public ngOnInit(): void { + // Nothing } } diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.html b/ngapp/src/app/connections/connections-cards/connections-cards.component.html index 184bc372..6a1ac4e1 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.html +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.html @@ -9,16 +9,13 @@

    {{ connection.getId() }} -


    -
    - JNDI: - {{ connection.getJndiName() }}    +
    + JNDI:  {{ connection.getJndiName() }}
    -
    - Driver: - {{ connection.getDriverName() }}    +
    + Driver:  {{ connection.getDriverName() }}
    -
    - JNDI: - {{ connection.getDriverName() }}    +
    + JNDI:  {{ connection.getJndiName() }}    
    -
    - Driver: - {{ connection.getDriverName() }}    +
    + Driver:  {{ connection.getDriverName() }}
    diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 1d75907c..cda917d3 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -132,13 +132,6 @@ export class ConnectionsComponent extends AbstractPageComponent { // this.selectedConnections.splice(this.selectedConnections.indexOf(connection), 1); } - public onEdit(connName: string): void { - const link: string[] = [ ConnectionsConstants.editConnectionPath ]; - this.router.navigate(link).then(() => { - // nothing to do - }); - } - public onDelete(connName: string): void { this.connectionNameForDelete = connName; this.confirmDeleteDialog.open(); diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 56921641..20458a0d 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -17,18 +17,18 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; -import { FormsModule } from "@angular/forms"; +import {FormsModule, ReactiveFormsModule} from "@angular/forms"; import { RouterModule } from "@angular/router"; -import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; import { ConnectionsComponent } from "@connections/connections.component"; -import { EditConnectionComponent } from "@connections/edit-connection/edit-connection.component"; -import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; import { ConnectionService } from "@connections/shared/connection.service"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { AddConnectionComponent } from "./add-connection/add-connection.component"; +import { AddConnectionWizardComponent } from "./add-connection-wizard/add-connection-wizard.component"; @NgModule({ imports: [ @@ -37,15 +37,16 @@ import { SharedModule } from "@shared/shared.module"; CoreModule, SharedModule, FormsModule, - RouterModule + ReactiveFormsModule, + RouterModule, + PatternFlyNgModule ], declarations: [ - AddConnectionComponent, - AddConnectionFormComponent, ConnectionsCardsComponent, ConnectionsComponent, ConnectionsListComponent, - EditConnectionComponent + AddConnectionWizardComponent, + AddConnectionComponent ], providers: [ ConnectionService diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.css b/ngapp/src/app/connections/edit-connection/edit-connection.component.css deleted file mode 100644 index 1561fd4c..00000000 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.css +++ /dev/null @@ -1,12 +0,0 @@ -.edit-connection-form { - padding: 15px -} - -.edit-connection-form /*.form-instructions*/ { - font-size: 15px; - padding-top: 10px -} - -.edit-connection-form .form-instructions ol { - padding-left: 20px; -} diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.html b/ngapp/src/app/connections/edit-connection/edit-connection.component.html deleted file mode 100644 index f4550b53..00000000 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.html +++ /dev/null @@ -1,21 +0,0 @@ -
    -
    - -
  • -
  • -
    -
    -
    -
    -

    Connection Properties

    -
    -
    - -
    - -
    -
    diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts deleted file mode 100644 index 531a69dd..00000000 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { ReactiveFormsModule } from "@angular/forms"; -import { HttpModule } from "@angular/http"; -import { RouterTestingModule } from "@angular/router/testing"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { MockConnectionService } from "@connections/shared/mock-connection.service"; -import { CoreModule } from "@core/core.module"; -import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; -import { PropertyFormComponent } from "@shared/property-form/property-form.component"; -import { EditConnectionComponent } from "./edit-connection.component"; - -describe("EditConnectionComponent", () => { - let component: EditConnectionComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ CoreModule, HttpModule, ReactiveFormsModule, RouterTestingModule ], - declarations: [ EditConnectionComponent, PropertyFormComponent, PropertyFormPropertyComponent ], - providers: [ - { provide: ConnectionService, useClass: MockConnectionService }, - ] - }) - .compileComponents().then(() => { - // nothing to do - }); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(EditConnectionComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should be created", () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.ts b/ngapp/src/app/connections/edit-connection/edit-connection.component.ts deleted file mode 100644 index 76ac0b06..00000000 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ViewChild } from "@angular/core"; -import { Component } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { Router } from "@angular/router"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { ConnectionsConstants } from "@connections/shared/connections-constants"; -import { LoggerService } from "@core/logger.service"; -import { AbstractPageComponent } from "@shared/abstract-page.component"; -import { PropertyDefinition } from "@shared/property-form/property-definition.model"; -import { PropertyFormComponent } from "@shared/property-form/property-form.component"; - -@Component({ - moduleId: module.id, - selector: "app-edit-connection", - templateUrl: "./edit-connection.component.html", - styleUrls: ["./edit-connection.component.css"] -}) -export class EditConnectionComponent extends AbstractPageComponent { - - public readonly connectionsLink: string = ConnectionsConstants.connectionsRootPath; - - private router: Router; - private connectionService: ConnectionService; - private properties: Array> = []; - @ViewChild(PropertyFormComponent) private connectionForm: PropertyFormComponent; - - constructor(router: Router, route: ActivatedRoute, connectionService: ConnectionService, logger: LoggerService) { - super(route, logger); - this.router = router; - this.connectionService = connectionService; - } - - public loadAsyncPageData(): void { - const that = this; - this.connectionService - .getConnectionTemplateProperties("h2") - .subscribe( - (props) => { - that.properties = props; - that.connectionForm.setFormProperties(that.properties); - that.connectionForm.updateForm(); - console.log("[AddConnectionComponent] Navigating to: %o"); - }, - (error) => { - console.error("[ConnectionsComponent] Error getting connections."); - this.error(error); - } - ); - } - - /** - * @returns {PropertyDefinition[]} the property definitions (can be null) - */ - public getPropertyDefinitions(): Array> { - return this.properties; - } - -} diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css deleted file mode 100644 index c6783af4..00000000 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.css +++ /dev/null @@ -1,68 +0,0 @@ -select { - width: auto; -} - -/* -.create-connection-form-panel.dragging { - border: 1px dashed #39a5dc; - background-color: #eef; -} -*/ - -.create-connection-form-panel { - padding-top: 25px; -} - -/* -span.disabled { - color: #999; -} -*/ - -.dropdown ul { - max-height: 250px; - overflow: auto; -} - -/* -div.spinner { - display: inline-block; - margin-right: 5px; -} -*/ - -/* -.platform-toggle { - display: inline-block; - text-align: center; - cursor: pointer; - border: 1px solid transparent; - padding: 5px; - margin-right: 8px; - border-radius: 3px; -} -.platform-toggle:hover { - border: 1px solid #bee1f4; - background-color: #def3ff; -} -.platform-toggle.selected { - background-color: #0088ce; - color: white; - cursor: default; - border: 1px solid transparent; -} -.platform-toggle.disabled { - opacity: 0.6; - cursor: not-allowed; -} -.platform-toggle span.fa { - font-size: 32px; -} -.platform-toggle span.lbl { - font-size: 14px; -} - -.account-link-warning { - margin-top: 10px; -} -*/ diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html deleted file mode 100644 index dbeebae0..00000000 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.html +++ /dev/null @@ -1,43 +0,0 @@ -
    -

    Connection Properties

    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
    diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts deleted file mode 100644 index bd3417a6..00000000 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; -import { FormsModule } from "@angular/forms"; -import { RouterTestingModule } from "@angular/router/testing"; -import { AddConnectionFormComponent } from "@connections/shared/add-connection-form/add-connection-form.component"; -import { LoggerService } from "@core/logger.service"; - -describe("AddConnectionFormComponent", () => { - let component: AddConnectionFormComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ FormsModule, RouterTestingModule ], - declarations: [ AddConnectionFormComponent ], - providers: [ LoggerService ] - }) - .compileComponents().then(() => { - // nothing to do - }); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AddConnectionFormComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should be created", inject([ LoggerService ], ( logger: LoggerService ) => { - expect(component).toBeTruthy(); - })); -}); diff --git a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts b/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts deleted file mode 100644 index a4e037d0..00000000 --- a/ngapp/src/app/connections/shared/add-connection-form/add-connection-form.component.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, EventEmitter, Output } from "@angular/core"; -import { Router } from "@angular/router"; -import { ConnectionsConstants } from "@connections/shared/connections-constants"; -import { NewConnection } from "@connections/shared/new-connection.model"; -import { LoggerService } from "@core/logger.service"; - -@Component({ - moduleId: module.id, - selector: "app-add-connection-form", - templateUrl: "./add-connection-form.component.html", - styleUrls: ["./add-connection-form.component.css"] -}) -export class AddConnectionFormComponent { - - private creating = false; - private logger: LoggerService; - private model = new NewConnection(); - private router: Router; - - @Output() private createConnection = new EventEmitter(); - - constructor( router: Router, logger: LoggerService ) { - this.router = router; - this.logger = logger; - } - - /** - * @returns {string} the name of the connection - */ - public get connectionName(): string { - return this.model.getName(); - } - - /** - * @param {string} name the new connection name - */ - public set connectionName( name: string ) { - this.model.setName( name ); - } - - /** - * @returns {string} the driver name of the connection - */ - public get connectionDriverName(): string { - return this.model.getDriverName(); - } - - /** - * @param {string} driverName the new connection driver name - */ - public set connectionDriverName( driverName: string ) { - this.model.setDriverName( driverName ); - } - - /** - * @returns {boolean} true if a JDBC connection - */ - public get connectionIsJdbc(): boolean { - return this.model.isJdbc(); - } - - /** - * @param {boolean} isJdbc true if the new connection is a JDBC connection - */ - public set connectionIsJdbc( isJdbc: boolean ) { - this.model.setJdbc( isJdbc ); - } - - /** - * @returns {string} the JNDI name of the connection - */ - public get connectionJndiName(): string { - return this.model.getJndiName(); - } - - /** - * @param {string} jndiName the new connection JNDI name - */ - public set connectionJndiName( jndiName: string ) { - this.model.setJndiName( jndiName ); - } - - public currentConnection(): string { - return JSON.stringify(this.model); - } - - /** - * Called when the user clicks the "Create Connection" submit button on the form. - */ - public onCreateConnection(): void { - const connection: NewConnection = new NewConnection(); - connection.setName(this.model.getName()); - connection.setJndiName(this.model.getJndiName()); - connection.setDriverName(this.model.getDriverName()); - connection.setJdbc(this.model.isJdbc()); - - this.logger.log("[AddConnectionFormComponent] Firing create-connection event: %o", connection); - - this.creating = true; - this.createConnection.emit(connection); - } - - public cancelAdd(): void { - const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; - this.router.navigate(link).then(() => { - // nothing to do - }); - } - - /** - * @returns {boolean} 'true' if the connection is being created - */ - public get creatingConnection(): boolean { - return this.creating; - } - - /** - * Called when the connection has been created. - */ - public connectionCreated(): void { - this.creating = false; - } -} diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index 256f431a..d401ad08 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -20,6 +20,7 @@ import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { TemplateDefinition } from "@connections/shared/template-definition.model"; import { ApiService } from "@core/api.service"; import { LoggerService } from "@core/logger.service"; import { environment } from "@environments/environment"; @@ -78,6 +79,20 @@ export class ConnectionService extends ApiService { .catch(this.handleError); } + /** + * Get the connection templates from the komodo rest interface + * @returns {Observable>>} + */ + public getConnectionTemplates(): Observable { + return this.http + .get( environment.komodoTeiidUrl + "/templates", this.getAuthRequestOptions()) + .map((response) => { + const templates = response.json(); + return templates.map((template) => TemplateDefinition.create( template )); + }) + .catch(this.handleError); + } + /** * Get the connection template property definitions from the komodo rest interface * @param {string} templateName diff --git a/ngapp/src/app/connections/shared/connections-constants.ts b/ngapp/src/app/connections/shared/connections-constants.ts index 17d5f152..571694ed 100644 --- a/ngapp/src/app/connections/shared/connections-constants.ts +++ b/ngapp/src/app/connections/shared/connections-constants.ts @@ -17,8 +17,4 @@ export class ConnectionsConstants { public static readonly addConnectionRoute = ConnectionsConstants.connectionsRootRoute + "/add-connection"; public static readonly addConnectionPath = ConnectionsConstants.connectionsRootPath + "/add-connection"; - - public static readonly editConnectionRoute = ConnectionsConstants.connectionsRootRoute + "/edit-connection"; - public static readonly editConnectionPath = ConnectionsConstants.connectionsRootPath + "/edit-connection"; - } diff --git a/ngapp/src/app/connections/shared/new-connection.model.ts b/ngapp/src/app/connections/shared/new-connection.model.ts index 903eee0a..2a36cfd7 100644 --- a/ngapp/src/app/connections/shared/new-connection.model.ts +++ b/ngapp/src/app/connections/shared/new-connection.model.ts @@ -106,7 +106,17 @@ export class NewConnection { jndiName: this.jndiName, driverName: this.driverName, jdbc: this.jdbc, - parameters: this.properties + parameters: this.strMapToObj(this.properties) }; } + + private strMapToObj(strMap: Map): any { + const obj = Object.create(null); + for (const [k, v] of Array.from(strMap)) { + // We don’t escape the key '__proto__' + // which can cause problems on older engines + obj[k] = v; + } + return obj; + } } diff --git a/ngapp/src/app/connections/shared/template-definition.model.ts b/ngapp/src/app/connections/shared/template-definition.model.ts new file mode 100644 index 00000000..f707fbd2 --- /dev/null +++ b/ngapp/src/app/connections/shared/template-definition.model.ts @@ -0,0 +1,87 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class TemplateDefinition { + private keng__id: string; + private isJdbc: boolean; + private entries: string[]; + + /** + * @param {Object} json the JSON representation of a Template + * @returns {TemplateDefinition} the new TemplateDefinition (never null) + */ + public static create( json: object = {} ): TemplateDefinition { + const template = new TemplateDefinition(); + template.setValues( json ); + return template; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the property id + */ + public getId(): string { + return this.keng__id; + } + + /** + * @returns {boolean} 'true' if jdbc + */ + public getJdbc(): boolean { + return this.isJdbc; + } + + /** + * @returns {string[]} the array of entries + */ + public getEntries(): string[] { + return this.entries; + } + + /** + * @param {string} id the property id + */ + public setId( id?: string ): void { + this.keng__id = id ? id : null; + } + + /** + * @param {boolean} jdbc 'true' if template is jdbc + */ + public setJdbc( jdbc?: boolean ): void { + this.isJdbc = jdbc ? jdbc : null; + } + + /** + * @param {string[]} entries the array of entries + */ + public setEntries( entries?: string[] ): void { + this.entries = entries ? entries : null; + } + + /** + * Set all object values using the supplied Template json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/shared/property-form/property-definition.model.ts b/ngapp/src/app/shared/property-form/property-definition.model.ts index ecd79fbb..011cce13 100644 --- a/ngapp/src/app/shared/property-form/property-definition.model.ts +++ b/ngapp/src/app/shared/property-form/property-definition.model.ts @@ -102,6 +102,9 @@ export class PropertyDefinition { if (this.isConstrainedToAllowedValues()) { return "dropdown"; } else if (className === "java.lang.String") { + if (this.isMasked() || this.getId() === "password") { + return "maskedTextbox"; + } return "textbox"; } else if (className === "java.lang.Boolean") { return "checkbox"; diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html index 07ef24ac..96702d1d 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html @@ -6,6 +6,9 @@ + + diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts index 00c5ccac..ab5a00b1 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts @@ -26,6 +26,7 @@ import { PropertyDefinition } from "@shared/property-form/property-definition.mo }) export class PropertyFormPropertyComponent { + @Input() private property: PropertyDefinition; @Input() private form: FormGroup; diff --git a/ngapp/src/app/shared/property-form/property-form.component.html b/ngapp/src/app/shared/property-form/property-form.component.html index 6f486ca0..95ac15ae 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.html +++ b/ngapp/src/app/shared/property-form/property-form.component.html @@ -1,16 +1,7 @@
    -
    - +
    - -
    - -
    - -
    - Saved the following values
    {{ payLoad }} -
    diff --git a/ngapp/src/app/shared/property-form/property-form.component.ts b/ngapp/src/app/shared/property-form/property-form.component.ts index 3fd0c1f1..a7de629d 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.ts @@ -1,6 +1,7 @@ import { Component, Input, OnInit } from "@angular/core"; import { FormControl, FormGroup, Validators } from "@angular/forms"; +import {ObjectUtils} from "@core/utils/object-utils"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; @Component({ @@ -12,7 +13,6 @@ export class PropertyFormComponent implements OnInit { @Input() private formProperties: Array> = []; private form: FormGroup; - private payLoad = ""; constructor( ) { // Nothing to do @@ -26,14 +26,44 @@ export class PropertyFormComponent implements OnInit { this.form = this.toFormGroup(this.formProperties); } - public onSubmit(): void { - this.payLoad = JSON.stringify(this.form.value); - } - public setFormProperties( props: Array> ): void { this.formProperties = props; } + /* + * Get the properties from the form that have values that aren't default values + */ + public get propertyValuesNonDefault(): Map { + const propertyMap: Map = new Map(); + for (const property of this.formProperties) { + const theValue = this.form.controls[property.getId()].value; + if (!ObjectUtils.isNullOrUndefined(theValue)) { + if (typeof theValue === "string" && theValue.length > 0) { + if (theValue !== property.theDefaultValue) { + propertyMap.set(property.getId(), theValue); + } + } else if (typeof theValue === "boolean") { + if (theValue.toString() !== property.theDefaultValue) { + propertyMap.set(property.getId(), theValue.toString()); + } + } + } + } + return propertyMap; + } + + /* + * Get the property value + */ + public getPropertyValue(name: string): string { + const theValue = this.form.controls[name].value; + if (typeof theValue === "string") { + return theValue; + } else { + return theValue.toString(); + } + } + /* NOTE: The appropriate Validators for properties are applied in this function. Angular has a number of built-in validators. For a complete listing of the built-in validators, go here : https://angular.io/api/forms/Validators diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index 9b12a962..b9d82c4f 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -43,7 +43,8 @@ import { PropertyFormComponent } from "./property-form/property-form.component"; ConfirmDeleteComponent, PageErrorComponent, PageNotFoundComponent, - PropertyFormComponent + PropertyFormComponent, + PropertyFormPropertyComponent ] }) export class SharedModule { From 1bb8dcb45b525d73461bded596d2ce6c1a5e5668 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 16 Oct 2017 17:16:04 -0500 Subject: [PATCH 020/205] Merge pull request #17 from mdrillin/WizardAddition Incorporates patternfly-ng wizard --- ngapp/messages.xlf | 471 +++++ ngapp/package-lock.json | 1627 +++++++++++++---- ngapp/package.json | 24 +- .../activities-cards.component.html | 4 +- .../activities-cards.component.ts | 2 +- .../activities-list.component.html | 4 +- .../activities-list.component.ts | 2 +- .../app/activities/activities.component.html | 18 +- .../add-activity/add-activity.component.html | 6 +- .../add-activity-form.component.html | 8 +- .../add-activity-form.component.ts | 2 +- ngapp/src/app/app.component.ts | 4 +- .../add-connection-wizard.component.ts | 18 +- .../add-connection.component.html | 5 +- .../add-connection.component.ts | 1 + .../connections-cards.component.html | 4 +- .../connections-cards.component.ts | 2 +- .../connections-list.component.html | 7 +- .../connections-list.component.ts | 2 +- .../connections/connections.component.html | 22 +- .../edit-connection.component.html | 21 + .../connections/shared/connection.service.ts | 2 +- .../breadcrumb/breadcrumb.component.ts | 2 +- .../core/nav-header/nav-header.component.html | 20 +- .../vertical-nav/vertical-nav.component.html | 4 +- .../vertical-nav/vertical-nav.component.ts | 4 +- .../confirm-delete.component.html | 6 +- .../page-error/page-error.component.html | 38 +- .../page-not-found.component.html | 2 +- .../property-form-property.component.ts | 4 +- .../property-form/property-form.component.ts | 4 +- ngapp/src/index.html | 2 +- ngapp/src/locale/README.md | 1 + 33 files changed, 1866 insertions(+), 477 deletions(-) create mode 100644 ngapp/messages.xlf create mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.html create mode 100644 ngapp/src/locale/README.md diff --git a/ngapp/messages.xlf b/ngapp/messages.xlf new file mode 100644 index 00000000..465e769c --- /dev/null +++ b/ngapp/messages.xlf @@ -0,0 +1,471 @@ + + + + + + Confirm Delete + + src/app/shared/confirm-delete/confirm-delete.component.ts + 9 + + + + Cancel + + src/app/shared/confirm-delete/confirm-delete.component.ts + 15 + + + + Delete + + src/app/shared/confirm-delete/confirm-delete.component.ts + 16 + + + + Activities + + src/app/activities/activities.component.ts + 13 + + + + Name + + src/app/activities/activities.component.ts + 19 + + + + Add Activity + + src/app/activities/activities.component.ts + 31 + + + + No Activities Found + + src/app/activities/activities.component.ts + 57 + + + + + No Activities were found - please click below to create a new Activity! + + + src/app/activities/activities.component.ts + 58 + + + + No Activities matched the filter!  Please try changing your filter criteria.. + + src/app/activities/activities.component.ts + 71 + + + + Loading Activities... + + src/app/activities/activities.component.ts + 82 + + + + Do you really want to delete the selected Activity? + + src/app/activities/activities.component.ts + 106 + + + + Name + + src/app/activities/shared/add-activity-form/add-activity-form.component.ts + 6 + + + + Source Connection + + src/app/activities/shared/add-activity-form/add-activity-form.component.ts + 18 + + + + Target Connection + + src/app/activities/shared/add-activity-form/add-activity-form.component.ts + 24 + + + + Cancel + + src/app/activities/shared/add-activity-form/add-activity-form.component.ts + 38 + + + + Add Activity + + src/app/activities/add-activity/add-activity.component.ts + 10 + + + + Source: + + src/app/activities/activities-cards/activities-cards.component.ts + 16 + + + + Target: + + src/app/activities/activities-cards/activities-cards.component.ts + 19 + + + + Source: + + src/app/activities/activities-list/activities-list.component.ts + 18 + + + + Target: + + src/app/activities/activities-list/activities-list.component.ts + 21 + + + + JNDI: + + src/app/connections/connections-cards/connections-cards.component.ts + 15 + + + + Driver: + + src/app/connections/connections-cards/connections-cards.component.ts + 18 + + + + JNDI: + + src/app/connections/connections-list/connections-list.component.ts + 18 + + + + Driver: + + src/app/connections/connections-list/connections-list.component.ts + 21 + + + + Ping + + src/app/connections/connections-list/connections-list.component.ts + 34 + + + + Edit + + src/app/connections/connections-list/connections-list.component.ts + 35 + + + + Delete + + src/app/connections/connections-list/connections-list.component.ts + 36 + + + + Connections + + src/app/connections/connections.component.ts + 13 + + + + Name + + src/app/connections/connections.component.ts + 19 + + + + Add Connection + + src/app/connections/connections.component.ts + 31 + + + src/app/connections/connections.component.ts + 63 + + + + Connections found + (out of total) + + src/app/connections/connections.component.ts + 42 + + + + No Connections Found + + src/app/connections/connections.component.ts + 57 + + + + + No Connections were found - please click below to create a new Connection! + + + src/app/connections/connections.component.ts + 58 + + + + No Connections matched the filter!  Please try changing your filter criteria... + + src/app/connections/connections.component.ts + 71 + + + + Do you really want to delete the selected Connection? + + src/app/connections/connections.component.ts + 106 + + + + BeETLe Studio + + src/app/core/nav-header/nav-header.component.ts + 4 + + + src/app/core/nav-header/nav-header.component.ts + 32 + + + + About + + src/app/core/nav-header/nav-header.component.ts + 16 + + + + Logout + + src/app/core/nav-header/nav-header.component.ts + 18 + + + + Version + + src/app/core/nav-header/nav-header.component.ts + 36 + + + + Built On + + src/app/core/nav-header/nav-header.component.ts + 40 + + + + Project URL + + src/app/core/nav-header/nav-header.component.ts + 44 + + + + + © 2016 Red Hat, Inc (JBoss Middleware) + + + src/app/core/nav-header/nav-header.component.ts + 50 + + + + Activities + + src/app/core/vertical-nav/vertical-nav.component.ts + 7 + + + + Connections + + src/app/core/vertical-nav/vertical-nav.component.ts + 12 + + + + Server Error Encountered + + src/app/shared/page-error/page-error.component.ts + 11 + + + + + Error was encountered communicating with the server. Please reload the page. + + + src/app/shared/page-error/page-error.component.ts + 15 + + + + Reload Page + + src/app/shared/page-error/page-error.component.ts + 19 + + + src/app/shared/page-error/page-error.component.ts + 66 + + + src/app/shared/page-error/page-error.component.ts + 85 + + + src/app/shared/page-error/page-error.component.ts + 108 + + + + Server Error Details + + src/app/shared/page-error/page-error.component.ts + 23 + + + + Toggle Details + + src/app/shared/page-error/page-error.component.ts + 28 + + + + Page Not Found + + src/app/shared/page-error/page-error.component.ts + 37 + + + src/app/shared/page-not-found/page-not-found.component.ts + 1 + + + + + You attempted to navigate to a page that does not exist! Please hit the back button + or go back to home (button below). + + + src/app/shared/page-error/page-error.component.ts + 41 + + + + Back to Home + + src/app/shared/page-error/page-error.component.ts + 46 + + + + Data Already Exists + + src/app/shared/page-error/page-error.component.ts + 56 + + + + + It appears you attempted to add or create something that already exists. Instead of adding it again, + try finding the existing resource and editing. + + + src/app/shared/page-error/page-error.component.ts + 60 + + + + Connection Error + + src/app/shared/page-error/page-error.component.ts + 76 + + + + (Could Not Reach Server) + + src/app/shared/page-error/page-error.component.ts + 77 + + + + + We couldn't reach the server. Try reloading the page in a few minutes or check your internet connection. + + + src/app/shared/page-error/page-error.component.ts + 81 + + + + Unexpected Error on Page + + src/app/shared/page-error/page-error.component.ts + 95 + + + + + Something unexpected happened. Please try reloading the page, or you could just go back to Home. + See the buttons below... + + + src/app/shared/page-error/page-error.component.ts + 102 + + + + Back to Dashboard + + src/app/shared/page-error/page-error.component.ts + 107 + + + + + diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index ad5956a6..de5e15d5 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -16,9 +16,9 @@ } }, "@angular/animations": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.4.4.tgz", - "integrity": "sha1-ovk1NgQ0er4V35gpIFiEL1Lwi8I=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.4.5.tgz", + "integrity": "sha1-WlpVHXV+WlVgCY9vhTXBAtk5VNc=", "requires": { "tslib": "1.7.1" } @@ -95,27 +95,27 @@ } }, "@angular/common": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.4.4.tgz", - "integrity": "sha1-rgqBiqoMaj8JAee4C9lOHCLrk2U=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.4.5.tgz", + "integrity": "sha1-vVF53JIq2/TD6m37Gec8uEn/3Dc=", "requires": { "tslib": "1.7.1" } }, "@angular/compiler": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.4.4.tgz", - "integrity": "sha1-Mm6wAp2aNUGqyhJN75rcUcNvK0E=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.4.5.tgz", + "integrity": "sha1-hyGlkQ8rtS8J4tQEytJk817eWQI=", "requires": { "tslib": "1.7.1" } }, "@angular/compiler-cli": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.4.4.tgz", - "integrity": "sha1-BjCApJfZF1OWglBQIixxfaGE9s8=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.4.5.tgz", + "integrity": "sha1-YfoDNqzRogjF8cXG1N9nnpmVMkg=", "requires": { - "@angular/tsc-wrapped": "4.4.4", + "@angular/tsc-wrapped": "4.4.5", "minimist": "1.2.0", "reflect-metadata": "0.1.10" }, @@ -128,47 +128,47 @@ } }, "@angular/core": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.4.4.tgz", - "integrity": "sha1-vTfs9UFY+XSJmWyThr0iL4CjL1w=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.4.5.tgz", + "integrity": "sha1-VKy8vaEXGfiDx4apBpdKvrEy8aA=", "requires": { "tslib": "1.7.1" } }, "@angular/forms": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.4.4.tgz", - "integrity": "sha1-TbN5BQm2sQ8duKfBt/Uhh89kz9Q=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.4.5.tgz", + "integrity": "sha1-6VUghiMqqyzh0I7xmLYiBOoTxDs=", "requires": { "tslib": "1.7.1" } }, "@angular/http": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.4.4.tgz", - "integrity": "sha1-Zn+vYWu2JBaOr65u6S5euiOp0fI=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.4.5.tgz", + "integrity": "sha1-LHNe2EJAH8I1ZBkmjiiNzyOW6E8=", "requires": { "tslib": "1.7.1" } }, "@angular/language-service": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-4.4.4.tgz", - "integrity": "sha1-D2hgUuOVDBkSjxO3Qp/BS6/mm9Q=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-4.4.5.tgz", + "integrity": "sha1-zO8Tm40+FoSwGvo1xvvyFy4rtnY=", "dev": true }, "@angular/platform-browser": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.4.4.tgz", - "integrity": "sha1-o4mOLnup2E/6DUcUTGlxF5x1ruY=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.4.5.tgz", + "integrity": "sha1-dOuRwLdYEm8m1T7lbHz0ZovZysU=", "requires": { "tslib": "1.7.1" } }, "@angular/platform-browser-dynamic": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.4.4.tgz", - "integrity": "sha1-w8nrhUpShVagcFQSeTLlJ/qTLhQ=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.4.5.tgz", + "integrity": "sha1-d029wdkPd12/HjGfbtQrJgYjth8=", "requires": { "tslib": "1.7.1" } @@ -184,17 +184,17 @@ } }, "@angular/router": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.4.4.tgz", - "integrity": "sha1-e+ORCW6EPLPgT58F0dZaiN+bx88=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.4.5.tgz", + "integrity": "sha1-9zEwz0h9mjLMGYiv2llmX0Siiok=", "requires": { "tslib": "1.7.1" } }, "@angular/tsc-wrapped": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.4.4.tgz", - "integrity": "sha1-mEGCHlVha4JsoWAlD+heFfx0/8M=", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.4.5.tgz", + "integrity": "sha1-MKDLtDpmOqddyphIlL5IE3eN3Jw=", "requires": { "tsickle": "0.21.6" } @@ -234,8 +234,7 @@ "@types/node": { "version": "6.0.89", "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.89.tgz", - "integrity": "sha512-Z/67L97+6H1qJiEEHSN1SQapkWjDss1D90rAnFcQ6UxKkah9juzotK5UNEP1bDv/0lJ3NAQTnVfc/JWdgCGruA==", - "dev": true + "integrity": "sha512-Z/67L97+6H1qJiEEHSN1SQapkWjDss1D90rAnFcQ6UxKkah9juzotK5UNEP1bDv/0lJ3NAQTnVfc/JWdgCGruA==" }, "@types/q": { "version": "0.0.32", @@ -1207,6 +1206,7 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", + "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2812,118 +2812,1009 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "1.0.0" + } + }, + "fs-extra": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", + "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.7.0", + "node-pre-gyp": "0.6.36" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.36", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", "dev": true, + "optional": true, "requires": { - "isarray": "1.0.0" + "extsprintf": "1.0.2" } } } }, - "finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.3.1", - "unpipe": "1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", - "dev": true, - "requires": { - "null-check": "1.0.0" - } - }, - "fs-extra": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", - "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -5597,230 +6488,28 @@ "pinkie-promise": "2.0.1" } }, - "patternfly": { - "version": "3.27.7", - "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.27.7.tgz", - "integrity": "sha1-okEYcgvBPuu+b9bkgP2m65kBLaQ=", - "requires": { - "bootstrap": "3.3.7", - "bootstrap-datepicker": "1.6.4", - "bootstrap-select": "1.12.4", - "bootstrap-switch": "3.3.4", - "bootstrap-touchspin": "3.1.1", - "c3": "0.4.17", - "d3": "3.5.17", - "datatables.net": "1.10.15", - "datatables.net-colreorder": "1.3.3", - "datatables.net-colreorder-bs": "1.3.3", - "datatables.net-select": "1.2.2", - "drmonty-datatables-colvis": "1.1.2", - "eonasdan-bootstrap-datetimepicker": "4.17.47", - "font-awesome": "4.7.0", - "google-code-prettify": "1.0.5", - "jquery": "3.2.1", - "jquery-match-height": "0.7.2", - "moment": "2.14.1", - "moment-timezone": "0.4.1", - "patternfly-bootstrap-combobox": "1.1.7", - "patternfly-bootstrap-treeview": "2.1.5" - }, - "dependencies": { - "bootstrap": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz", - "integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E=" - }, - "bootstrap-datepicker": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.6.4.tgz", - "integrity": "sha1-iJ6+ztjqov8V7B8nPksHUxzEPaA=", - "optional": true, - "requires": { - "jquery": "3.2.1" - } - }, - "bootstrap-select": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.12.4.tgz", - "integrity": "sha1-fxXTwM6XiGjZwJxw+WYk9V+gLuE=", - "optional": true, - "requires": { - "jquery": "3.2.1" - } - }, - "bootstrap-switch": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/bootstrap-switch/-/bootstrap-switch-3.3.4.tgz", - "integrity": "sha1-cOCusqh3wNx2aZHeEI4hcPwpov8=", - "optional": true - }, - "bootstrap-touchspin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bootstrap-touchspin/-/bootstrap-touchspin-3.1.1.tgz", - "integrity": "sha1-l3nerHKq9Xfl52K4USx0fIcdlZc=", - "optional": true - }, - "c3": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.17.tgz", - "integrity": "sha512-41T3yS3jq1XgA7ruvV1wFVEK1E2az2iUAqS7hU5de62JVrjPyxWqIPu8AHlKpShZxJbD+DXLRkQHfOLASYyqyg==", - "optional": true, - "requires": { - "d3": "3.5.17" - } - }, - "d3": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=", - "optional": true - }, - "datatables.net": { - "version": "1.10.15", - "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.15.tgz", - "integrity": "sha1-x4kHe7/jhedf9aIz+l8jJRpy32g=", - "requires": { - "jquery": "3.2.1" - } - }, - "datatables.net-bs": { - "version": "1.10.15", - "resolved": "https://registry.npmjs.org/datatables.net-bs/-/datatables.net-bs-1.10.15.tgz", - "integrity": "sha1-ssImEAfYTKW1q/VsGO3CJ+DaGk0=", - "optional": true, - "requires": { - "datatables.net": "1.10.15", - "jquery": "3.2.1" - } - }, - "datatables.net-colreorder": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/datatables.net-colreorder/-/datatables.net-colreorder-1.3.3.tgz", - "integrity": "sha1-/HYuNQ+UIkyyzUXCuWImGg//73I=", - "optional": true, - "requires": { - "datatables.net": "1.10.15", - "jquery": "3.2.1" - } - }, - "datatables.net-colreorder-bs": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/datatables.net-colreorder-bs/-/datatables.net-colreorder-bs-1.3.3.tgz", - "integrity": "sha1-Op3LCN7r612FQHlZHgbkk615OlM=", - "optional": true, - "requires": { - "datatables.net-bs": "1.10.15", - "datatables.net-colreorder": "1.3.3", - "jquery": "3.2.1" - } - }, - "datatables.net-select": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/datatables.net-select/-/datatables.net-select-1.2.2.tgz", - "integrity": "sha1-llF5P1KJn05XRcByCCHouChvv0U=", - "optional": true, - "requires": { - "datatables.net": "1.10.15", - "jquery": "3.2.1" - } - }, - "drmonty-datatables-colvis": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/drmonty-datatables-colvis/-/drmonty-datatables-colvis-1.1.2.tgz", - "integrity": "sha1-lque37SGQ8wu3aP4e4iTPN7oEnw=", - "optional": true, - "requires": { - "jquery": "3.2.1" - } - }, - "eonasdan-bootstrap-datetimepicker": { - "version": "4.17.47", - "resolved": "https://registry.npmjs.org/eonasdan-bootstrap-datetimepicker/-/eonasdan-bootstrap-datetimepicker-4.17.47.tgz", - "integrity": "sha1-ekmXAEQGUnbnll79Fvgic1IZ5zU=", - "optional": true, - "requires": { - "bootstrap": "3.3.7", - "jquery": "3.2.1", - "moment": "2.14.1", - "moment-timezone": "0.4.1" - } - }, - "font-awesome": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", - "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" - }, - "google-code-prettify": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/google-code-prettify/-/google-code-prettify-1.0.5.tgz", - "integrity": "sha1-n0d/Ik2/piNy5e+AOn4VdBBAAIQ=", - "optional": true - }, - "jquery": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", - "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" - }, - "jquery-match-height": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/jquery-match-height/-/jquery-match-height-0.7.2.tgz", - "integrity": "sha1-+NnzulMU2qsQnPB0CGdL4gS+Xw4=", - "optional": true - }, - "moment": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz", - "integrity": "sha1-s1snxH5X7S3ccAU9awe+zbKRdBw=" - }, - "moment-timezone": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.4.1.tgz", - "integrity": "sha1-gfWYw61eIs2teWtn7NjYjQ9bqgY=", - "optional": true, - "requires": { - "moment": "2.14.1" - } - }, - "patternfly-bootstrap-combobox": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/patternfly-bootstrap-combobox/-/patternfly-bootstrap-combobox-1.1.7.tgz", - "integrity": "sha1-al48zRFwwhs8S0qhaKdBPh3btuE=", - "optional": true - }, - "patternfly-bootstrap-treeview": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/patternfly-bootstrap-treeview/-/patternfly-bootstrap-treeview-2.1.5.tgz", - "integrity": "sha1-TCnyWC+4ovKPCpKPLw0yTSHWmQ0=", - "optional": true, - "requires": { - "bootstrap": "3.3.7", - "jquery": "3.2.1" - } - } - } - }, "patternfly-ng": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-0.13.1.tgz", - "integrity": "sha1-1DYXTcCqqllUc6UG1o0Kc/432Qo=", - "requires": { - "@angular/animations": "4.4.4", - "@angular/common": "4.4.4", - "@angular/compiler": "4.4.4", - "@angular/compiler-cli": "4.4.4", - "@angular/core": "4.4.4", - "@angular/forms": "4.4.4", - "@angular/http": "4.4.4", - "@angular/platform-browser": "4.4.4", - "@angular/platform-browser-dynamic": "4.4.4", + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-0.13.3.tgz", + "integrity": "sha1-6lsP+7USZRmj5cDYZMtfx5bvBbQ=", + "requires": { + "@angular/animations": "4.4.5", + "@angular/common": "4.4.5", + "@angular/compiler": "4.4.5", + "@angular/compiler-cli": "4.4.5", + "@angular/core": "4.4.5", + "@angular/forms": "4.4.5", + "@angular/http": "4.4.5", + "@angular/platform-browser": "4.4.5", + "@angular/platform-browser-dynamic": "4.4.5", "@angular/platform-server": "4.4.4", - "@angular/router": "4.4.4", + "@angular/router": "4.4.5", "angular-tree-component": "4.1.0", "c3": "0.4.18", "core-js": "2.4.1", "moment": "2.17.1", "ngx-bootstrap": "1.8.0", - "patternfly": "3.27.7", + "patternfly": "3.28.1", "rxjs": "5.4.3", "zone.js": "0.8.4" }, @@ -5845,6 +6534,208 @@ } } }, + "patternfly": { + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.28.1.tgz", + "integrity": "sha1-UPt1s4SpebxIkQzZ53E36ENzhjs=", + "requires": { + "bootstrap": "3.3.7", + "bootstrap-datepicker": "1.6.4", + "bootstrap-select": "1.12.4", + "bootstrap-switch": "3.3.4", + "bootstrap-touchspin": "3.1.1", + "c3": "0.4.17", + "d3": "3.5.17", + "datatables.net": "1.10.15", + "datatables.net-colreorder": "1.3.3", + "datatables.net-colreorder-bs": "1.3.3", + "datatables.net-select": "1.2.2", + "drmonty-datatables-colvis": "1.1.2", + "eonasdan-bootstrap-datetimepicker": "4.17.47", + "font-awesome": "4.7.0", + "google-code-prettify": "1.0.5", + "jquery": "3.2.1", + "jquery-match-height": "0.7.2", + "moment": "2.14.1", + "moment-timezone": "0.4.1", + "patternfly-bootstrap-combobox": "1.1.7", + "patternfly-bootstrap-treeview": "2.1.5" + }, + "dependencies": { + "bootstrap": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz", + "integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E=" + }, + "bootstrap-datepicker": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.6.4.tgz", + "integrity": "sha1-iJ6+ztjqov8V7B8nPksHUxzEPaA=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "bootstrap-select": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.12.4.tgz", + "integrity": "sha1-fxXTwM6XiGjZwJxw+WYk9V+gLuE=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "bootstrap-switch": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/bootstrap-switch/-/bootstrap-switch-3.3.4.tgz", + "integrity": "sha1-cOCusqh3wNx2aZHeEI4hcPwpov8=", + "optional": true + }, + "bootstrap-touchspin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bootstrap-touchspin/-/bootstrap-touchspin-3.1.1.tgz", + "integrity": "sha1-l3nerHKq9Xfl52K4USx0fIcdlZc=", + "optional": true + }, + "c3": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.17.tgz", + "integrity": "sha512-41T3yS3jq1XgA7ruvV1wFVEK1E2az2iUAqS7hU5de62JVrjPyxWqIPu8AHlKpShZxJbD+DXLRkQHfOLASYyqyg==", + "optional": true, + "requires": { + "d3": "3.5.17" + } + }, + "d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=", + "optional": true + }, + "datatables.net": { + "version": "1.10.15", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.15.tgz", + "integrity": "sha1-x4kHe7/jhedf9aIz+l8jJRpy32g=", + "requires": { + "jquery": "3.2.1" + } + }, + "datatables.net-bs": { + "version": "1.10.15", + "resolved": "https://registry.npmjs.org/datatables.net-bs/-/datatables.net-bs-1.10.15.tgz", + "integrity": "sha1-ssImEAfYTKW1q/VsGO3CJ+DaGk0=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "datatables.net-colreorder": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/datatables.net-colreorder/-/datatables.net-colreorder-1.3.3.tgz", + "integrity": "sha1-/HYuNQ+UIkyyzUXCuWImGg//73I=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "datatables.net-colreorder-bs": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/datatables.net-colreorder-bs/-/datatables.net-colreorder-bs-1.3.3.tgz", + "integrity": "sha1-Op3LCN7r612FQHlZHgbkk615OlM=", + "optional": true, + "requires": { + "datatables.net-bs": "1.10.15", + "datatables.net-colreorder": "1.3.3", + "jquery": "3.2.1" + } + }, + "datatables.net-select": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/datatables.net-select/-/datatables.net-select-1.2.2.tgz", + "integrity": "sha1-llF5P1KJn05XRcByCCHouChvv0U=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "drmonty-datatables-colvis": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/drmonty-datatables-colvis/-/drmonty-datatables-colvis-1.1.2.tgz", + "integrity": "sha1-lque37SGQ8wu3aP4e4iTPN7oEnw=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "eonasdan-bootstrap-datetimepicker": { + "version": "4.17.47", + "resolved": "https://registry.npmjs.org/eonasdan-bootstrap-datetimepicker/-/eonasdan-bootstrap-datetimepicker-4.17.47.tgz", + "integrity": "sha1-ekmXAEQGUnbnll79Fvgic1IZ5zU=", + "optional": true, + "requires": { + "bootstrap": "3.3.7", + "jquery": "3.2.1", + "moment": "2.14.1", + "moment-timezone": "0.4.1" + } + }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, + "google-code-prettify": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/google-code-prettify/-/google-code-prettify-1.0.5.tgz", + "integrity": "sha1-n0d/Ik2/piNy5e+AOn4VdBBAAIQ=", + "optional": true + }, + "jquery": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", + "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" + }, + "jquery-match-height": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/jquery-match-height/-/jquery-match-height-0.7.2.tgz", + "integrity": "sha1-+NnzulMU2qsQnPB0CGdL4gS+Xw4=", + "optional": true + }, + "moment": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz", + "integrity": "sha1-s1snxH5X7S3ccAU9awe+zbKRdBw=" + }, + "moment-timezone": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.4.1.tgz", + "integrity": "sha1-gfWYw61eIs2teWtn7NjYjQ9bqgY=", + "optional": true, + "requires": { + "moment": "2.14.1" + } + }, + "patternfly-bootstrap-combobox": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/patternfly-bootstrap-combobox/-/patternfly-bootstrap-combobox-1.1.7.tgz", + "integrity": "sha1-al48zRFwwhs8S0qhaKdBPh3btuE=", + "optional": true + }, + "patternfly-bootstrap-treeview": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/patternfly-bootstrap-treeview/-/patternfly-bootstrap-treeview-2.1.5.tgz", + "integrity": "sha1-TCnyWC+4ovKPCpKPLw0yTSHWmQ0=", + "optional": true, + "requires": { + "bootstrap": "3.3.7", + "jquery": "3.2.1" + } + } + } + }, "zone.js": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.4.tgz", @@ -7901,6 +8792,12 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -7928,12 +8825,6 @@ } } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/ngapp/package.json b/ngapp/package.json index c4ca6315..7089f755 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -12,25 +12,25 @@ }, "private": true, "dependencies": { - "@angular/animations": "^4.2.4", - "@angular/common": "^4.2.4", - "@angular/compiler": "^4.2.4", - "@angular/core": "^4.2.4", - "@angular/forms": "^4.2.4", - "@angular/http": "^4.2.4", - "@angular/platform-browser": "^4.2.4", - "@angular/platform-browser-dynamic": "^4.2.4", - "@angular/router": "^4.2.4", + "@angular/animations": "^4.4.5", + "@angular/common": "^4.4.5", + "@angular/compiler": "^4.4.5", + "@angular/core": "^4.4.5", + "@angular/forms": "^4.4.5", + "@angular/http": "^4.4.5", + "@angular/platform-browser": "^4.4.5", + "@angular/platform-browser-dynamic": "^4.4.5", + "@angular/router": "^4.4.5", "core-js": "^2.4.1", "ngx-bootstrap": "^1.9.3", - "patternfly-ng": "^0.13.1", + "patternfly-ng": "^0.13.3", "rxjs": "^5.4.2", "zone.js": "^0.8.14" }, "devDependencies": { "@angular/cli": "1.3.2", - "@angular/compiler-cli": "^4.2.4", - "@angular/language-service": "^4.2.4", + "@angular/compiler-cli": "^4.4.5", + "@angular/language-service": "^4.4.5", "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", "@types/node": "^6.0.89", diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.html b/ngapp/src/app/activities/activities-cards/activities-cards.component.html index 3a2e409a..d18a6518 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.html +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.html @@ -13,10 +13,10 @@


    - Source:  {{ activity.getSourceConnection() }} + Source:  {{ activity.getSourceConnection() }}
    - Target:  {{ activity.getTargetConnection() }} + Target:  {{ activity.getTargetConnection() }}
    +
    +
    diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index d401ad08..cf70d648 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -33,7 +33,7 @@ export class ConnectionService extends ApiService { private http: Http; constructor( http: Http, logger: LoggerService ) { - super( logger ); + super( logger ); this.http = http; } diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts index 26e5febe..e949b7df 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts @@ -27,6 +27,6 @@ export class BreadcrumbComponent { @Input() private label: string; @Input() private icon: string; - @Input() private route: string[]; + @Input() public route: string[]; } diff --git a/ngapp/src/app/core/nav-header/nav-header.component.html b/ngapp/src/app/core/nav-header/nav-header.component.html index 063af975..fb7ac1b2 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.html +++ b/ngapp/src/app/core/nav-header/nav-header.component.html @@ -1,7 +1,7 @@
    diff --git a/ngapp/src/app/shared/page-error/page-error.component.html b/ngapp/src/app/shared/page-error/page-error.component.html index b48ece70..63235d91 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.html +++ b/ngapp/src/app/shared/page-error/page-error.component.html @@ -8,24 +8,24 @@

    - Server Error Encountered + Server Error Encountered

    -

    +

    Error was encountered communicating with the server. Please reload the page.

    - +

    -

    Server Error Details

    +

    Server Error Details

    {{ stackTrace() }}
    @@ -34,16 +34,16 @@

    Server Error Details

    - Page Not Found + Page Not Found

    -

    +

    You attempted to navigate to a page that does not exist! Please hit the back button or go back to home (button below).

    @@ -53,17 +53,17 @@

    - Data Already Exists + Data Already Exists

    -

    +

    It appears you attempted to add or create something that already exists. Instead of adding it again, try finding the existing resource and editing.

    Back to Home - +

    @@ -73,16 +73,16 @@

    - Connection Error - (Could Not Reach Server) + Connection Error + (Could Not Reach Server)

    -

    +

    We couldn't reach the server. Try reloading the page in a few minutes or check your internet connection.

    - +
    @@ -92,20 +92,20 @@

    - Unexpected Error on Page + Unexpected Error on Page ( {{ errorMessage() }} )

    -

    +

    Something unexpected happened. Please try reloading the page, or you could just go back to Home. See the buttons below...

    - Back to Dashboard - + Back to Dashboard +
    diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.html b/ngapp/src/app/shared/page-not-found/page-not-found.component.html index 5727cb89..fbe549a3 100644 --- a/ngapp/src/app/shared/page-not-found/page-not-found.component.html +++ b/ngapp/src/app/shared/page-not-found/page-not-found.component.html @@ -1 +1 @@ -

    Page not found

    +

    Page not found

    diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts index ab5a00b1..5f3a80a1 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts @@ -27,8 +27,8 @@ import { PropertyDefinition } from "@shared/property-form/property-definition.mo export class PropertyFormPropertyComponent { - @Input() private property: PropertyDefinition; - @Input() private form: FormGroup; + @Input() public property: PropertyDefinition; + @Input() public form: FormGroup; /* * Return the property valid state diff --git a/ngapp/src/app/shared/property-form/property-form.component.ts b/ngapp/src/app/shared/property-form/property-form.component.ts index a7de629d..b6ba28f7 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.ts @@ -11,8 +11,8 @@ import { PropertyDefinition } from "@shared/property-form/property-definition.mo }) export class PropertyFormComponent implements OnInit { - @Input() private formProperties: Array> = []; - private form: FormGroup; + @Input() public formProperties: Array> = []; + public form: FormGroup; constructor( ) { // Nothing to do diff --git a/ngapp/src/index.html b/ngapp/src/index.html index ea27c496..2d2765b9 100644 --- a/ngapp/src/index.html +++ b/ngapp/src/index.html @@ -2,7 +2,7 @@ - BeetleStudio + Beetle Studio diff --git a/ngapp/src/locale/README.md b/ngapp/src/locale/README.md new file mode 100644 index 00000000..95265770 --- /dev/null +++ b/ngapp/src/locale/README.md @@ -0,0 +1 @@ +* messages.{languageCode}.xlf files go here From bd28704c21a8bf8cf72b78c1a72f748557372f40 Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Wed, 18 Oct 2017 13:56:18 -0500 Subject: [PATCH 021/205] Merge branch 'master' of https://github.com/teiid/beetle-studio into add_i18n --- ngapp/{src => }/locale/README.md | 0 ngapp/locale/messages.es.xlf | 616 +++++++++++++++++++++++++++++++ 2 files changed, 616 insertions(+) rename ngapp/{src => }/locale/README.md (100%) create mode 100644 ngapp/locale/messages.es.xlf diff --git a/ngapp/src/locale/README.md b/ngapp/locale/README.md similarity index 100% rename from ngapp/src/locale/README.md rename to ngapp/locale/README.md diff --git a/ngapp/locale/messages.es.xlf b/ngapp/locale/messages.es.xlf new file mode 100644 index 00000000..9b96ac97 --- /dev/null +++ b/ngapp/locale/messages.es.xlf @@ -0,0 +1,616 @@ + + + + + + Confirm Delete + Confirmar Eliminación + + src/app/shared/confirm-delete/confirm-delete.component.ts + 9 + + + + Cancel + Cancelar + + src/app/shared/confirm-delete/confirm-delete.component.ts + 15 + + + + Delete + Borrar + + src/app/shared/confirm-delete/confirm-delete.component.ts + 16 + + + + Activities + Ocupaciones + + src/app/activities/activities.component.ts + 13 + + + + Name + Nombre + + src/app/activities/activities.component.ts + 19 + + + + Add Activity + Agregar Actividad + + src/app/activities/activities.component.ts + 31 + + + + No Activities Found + Sin Actividades + + src/app/activities/activities.component.ts + 57 + + + + + No Activities were found - please click below to create a new Activity! + + No se encontraron actividades: haga clic a continuación para crear una nueva actividad! + + src/app/activities/activities.component.ts + 58 + + + + No Activities matched the filter!  Please try changing your filter criteria.. + No Activities matched the filter!  Please try changing your filter criteria.. + + src/app/activities/activities.component.ts + 71 + + + + Loading Activities... + Cargando actividades ... + + src/app/activities/activities.component.ts + 81 + + + + Do you really want to delete the selected Activity? + ¿Realmente quieres eliminar la actividad seleccionada? + + src/app/activities/activities.component.ts + 106 + + + + Name + Nombre + + src/app/activities/shared/add-activity-form/add-activity-form.component.ts + 6 + + + + Source Connection + Conexión de fuente + + src/app/activities/shared/add-activity-form/add-activity-form.component.ts + 18 + + + + Target Connection + Conexión de destino + + src/app/activities/shared/add-activity-form/add-activity-form.component.ts + 24 + + + + Cancel + Cancelar + + src/app/activities/shared/add-activity-form/add-activity-form.component.ts + 38 + + + + Add Activity + Agregar actividad + + src/app/activities/add-activity/add-activity.component.ts + 10 + + + + Source: + Fuente: + + src/app/activities/activities-cards/activities-cards.component.ts + 16 + + + + Target: + Objetivo: + + src/app/activities/activities-cards/activities-cards.component.ts + 20 + + + + Source: + Fuente: + + src/app/activities/activities-list/activities-list.component.ts + 18 + + + + Target: + Objetivo: + + src/app/activities/activities-list/activities-list.component.ts + 22 + + + + Connection Properties + Propiedades de conexión + + src/app/connections/shared/add-connection-form/add-connection-form.component.ts + 2 + + Properties for a connection + Connection Properties + + + Name + Nombre + + src/app/connections/shared/add-connection-form/add-connection-form.component.ts + 6 + + + + JNDI Name + Nombre JNDI + + src/app/connections/shared/add-connection-form/add-connection-form.component.ts + 12 + + + + Driver + Conductor + + src/app/connections/shared/add-connection-form/add-connection-form.component.ts + 18 + + + + JDBC + JDBC + + src/app/connections/shared/add-connection-form/add-connection-form.component.ts + 24 + + + + Create Connection + Crear Conexión + + src/app/connections/shared/add-connection-form/add-connection-form.component.ts + 34 + + + + Creating + Crear + + src/app/connections/shared/add-connection-form/add-connection-form.component.ts + 36 + + + + Cancel + Cancelar + + src/app/connections/shared/add-connection-form/add-connection-form.component.ts + 38 + + + + Add Connection + Agregar Conexión + + src/app/connections/add-connection/add-connection.component.ts + 10 + + + + JNDI: + JNDI: + + src/app/connections/connections-cards/connections-cards.component.ts + 16 + + + + Driver: + Conductor: + + src/app/connections/connections-cards/connections-cards.component.ts + 20 + + + + JNDI: + JNDI: + + src/app/connections/connections-list/connections-list.component.ts + 18 + + + + Driver: + Conductor: + + src/app/connections/connections-list/connections-list.component.ts + 22 + + + + Ping + Silbido + + src/app/connections/connections-list/connections-list.component.ts + 34 + + + + Edit + Editar + + src/app/connections/connections-list/connections-list.component.ts + 35 + + + + Delete + Borrar + + src/app/connections/connections-list/connections-list.component.ts + 36 + + + + Connections + Conexiones + + src/app/connections/connections.component.ts + 13 + + + + Name + Nombre + + src/app/connections/connections.component.ts + 19 + + + + Add Connection + Agregar Conexión + + src/app/connections/connections.component.ts + 31 + + + src/app/connections/connections.component.ts + 63 + + + + Connections found + (out of total) + Connections found + (fuera de total) + + src/app/connections/connections.component.ts + 42 + + + + No Connections Found + Sin Conexiones Encontradas + + src/app/connections/connections.component.ts + 57 + + + + + No Connections were found - please click below to create a new Connection! + + No se encontraron conexiones: ¡haga clic a continuación para crear una nueva conexión! + + src/app/connections/connections.component.ts + 58 + + + + No Connections matched the filter!  Please try changing your filter criteria... + Sin conexiones coincidió con el filtro! Intente cambiar sus criterios de filtro ... + + src/app/connections/connections.component.ts + 71 + + + + Do you really want to delete the selected Connection? + ¿Realmente quieres eliminar la conexión seleccionada? + + src/app/connections/connections.component.ts + 106 + + + + Edit Connection + Editar Conexión + + src/app/connections/edit-connection/edit-connection.component.ts + 10 + + + + BeETLe Studio + BeETLE Studio + + src/app/core/nav-header/nav-header.component.ts + 4 + + + src/app/core/nav-header/nav-header.component.ts + 32 + + + + About + Acerca de + + src/app/core/nav-header/nav-header.component.ts + 16 + + + + Logout + Cerrar Sesión + + src/app/core/nav-header/nav-header.component.ts + 18 + + + + version + versión + + src/app/core/nav-header/nav-header.component.ts + 36 + + + + Built On + Construida Sobre + + src/app/core/nav-header/nav-header.component.ts + 40 + + + + Project URL + URL del proyecto + + src/app/core/nav-header/nav-header.component.ts + 44 + + + + + © 2016 Red Hat, Inc (JBoss Middleware) + + © 2016 Red Hat, Inc (JBoss Middleware) + + src/app/core/nav-header/nav-header.component.ts + 50 + + + + Activities + Ocupaciones + + src/app/core/vertical-nav/vertical-nav.component.ts + 7 + + + + Connections + Conexiones + + src/app/core/vertical-nav/vertical-nav.component.ts + 12 + + + + Server Error Encountered + Error del servidor encontrado + + src/app/shared/page-error/page-error.component.ts + 11 + + + + + Error was encountered communicating with the server. Please reload the page. + + Se ha encontrado un error al comunicarse con el servidor. Por favor recarga la página. + + src/app/shared/page-error/page-error.component.ts + 15 + + + + Reload Page + Recargar Página + + src/app/shared/page-error/page-error.component.ts + 19 + + + src/app/shared/page-error/page-error.component.ts + 66 + + + src/app/shared/page-error/page-error.component.ts + 85 + + + src/app/shared/page-error/page-error.component.ts + 108 + + + + Server Error Details + Detalles de error del servidor + + src/app/shared/page-error/page-error.component.ts + 23 + + + + Toggle Details + Toggle Details + + src/app/shared/page-error/page-error.component.ts + 28 + + + + Page Not Found + Página No Encontrada + + src/app/shared/page-error/page-error.component.ts + 37 + + + src/app/shared/page-not-found/page-not-found.component.ts + 1 + + + + + You attempted to navigate to a page that does not exist! Please hit the back button + or go back to home (button below). + + ¡Intentaste navegar a una página que no existe! Por favor, presiona el botón Atrás o regrese a su hogar (botón a continuación).. + + src/app/shared/page-error/page-error.component.ts + 41 + + + + Back to Home + De Vuelta a Casa + + src/app/shared/page-error/page-error.component.ts + 46 + + + + Data Already Exists + Los Datos Ya Existen + + src/app/shared/page-error/page-error.component.ts + 56 + + + + + It appears you attempted to add or create something that already exists. Instead of adding it again, + try finding the existing resource and editing. + + Parece que intentaste agregar o crear algo que ya existe. En lugar de agregarlo nuevamente, + intenta encontrar el recurso y la edición existentes. + + src/app/shared/page-error/page-error.component.ts + 60 + + + + Connection Error + Error de Conexión + + src/app/shared/page-error/page-error.component.ts + 76 + + + + (Could Not Reach Server) + (No se pudo alcanzar el servidor) + + src/app/shared/page-error/page-error.component.ts + 77 + + + + + We couldn't reach the server. Try reloading the page in a few minutes or check your internet connection. + + No pudimos llegar al servidor. Intente volver a cargar la página en unos pocos minutos o consulte su conexión a Internet. + + src/app/shared/page-error/page-error.component.ts + 81 + + + + Unexpected Error on Page + Error Inesperado en la Página + + src/app/shared/page-error/page-error.component.ts + 95 + + + + + Something unexpected happened. Please try reloading the page, or you could just go back to Home. + See the buttons below... + + Algo inesperado sucedió. Intente volver a cargar la página o simplemente vuelva a Inicio. + Mira los botones a continuación ... + + src/app/shared/page-error/page-error.component.ts + 102 + + + + Back to Dashboard + Volver al Tablero + + src/app/shared/page-error/page-error.component.ts + 107 + + + + + From c25147835c69b812542401f29412e634b39cf46d Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Wed, 18 Oct 2017 15:33:40 -0500 Subject: [PATCH 022/205] Initial maven build work --- ngapp/package-lock.json | 1020 ++++++++++++++++- .../activities-cards.component.ts | 14 +- .../activities-list.component.ts | 14 +- .../activities/activities-routing.module.ts | 2 +- .../add-activity-form.component.ts | 15 +- ngapp/src/app/app.component.ts | 22 +- .../add-connection-wizard.component.ts | 47 +- .../add-connection.component.ts | 20 +- .../connections-cards.component.ts | 12 +- .../connections-list.component.ts | 16 +- .../connections/connections-routing.module.ts | 2 +- .../src/app/connections/connections.module.ts | 4 +- .../breadcrumb/breadcrumb.component.ts | 4 +- .../vertical-nav/vertical-nav.component.ts | 48 +- .../confirm-delete.component.ts | 4 +- .../shared/page-error/page-error.component.ts | 4 +- .../property-form/property-form.component.ts | 21 +- ngapp/src/environments/environment.prod.ts | 32 +- 18 files changed, 1189 insertions(+), 112 deletions(-) diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index de5e15d5..d85aaa69 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -20,7 +20,7 @@ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.4.5.tgz", "integrity": "sha1-WlpVHXV+WlVgCY9vhTXBAtk5VNc=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/cli": { @@ -99,7 +99,7 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.4.5.tgz", "integrity": "sha1-vVF53JIq2/TD6m37Gec8uEn/3Dc=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/compiler": { @@ -107,7 +107,7 @@ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.4.5.tgz", "integrity": "sha1-hyGlkQ8rtS8J4tQEytJk817eWQI=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/compiler-cli": { @@ -132,7 +132,7 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.4.5.tgz", "integrity": "sha1-VKy8vaEXGfiDx4apBpdKvrEy8aA=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/forms": { @@ -140,7 +140,7 @@ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.4.5.tgz", "integrity": "sha1-6VUghiMqqyzh0I7xmLYiBOoTxDs=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/http": { @@ -148,7 +148,7 @@ "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.4.5.tgz", "integrity": "sha1-LHNe2EJAH8I1ZBkmjiiNzyOW6E8=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/language-service": { @@ -162,7 +162,7 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.4.5.tgz", "integrity": "sha1-dOuRwLdYEm8m1T7lbHz0ZovZysU=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/platform-browser-dynamic": { @@ -170,7 +170,7 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.4.5.tgz", "integrity": "sha1-d029wdkPd12/HjGfbtQrJgYjth8=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/platform-server": { @@ -179,7 +179,7 @@ "integrity": "sha1-c+5B+hzshij8wDF0cnsnywAxsio=", "requires": { "parse5": "3.0.2", - "tslib": "1.7.1", + "tslib": "1.8.0", "xhr2": "0.1.4" } }, @@ -188,7 +188,7 @@ "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.4.5.tgz", "integrity": "sha1-9zEwz0h9mjLMGYiv2llmX0Siiok=", "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "@angular/tsc-wrapped": { @@ -3058,6 +3058,996 @@ "dev": true, "optional": true }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.36", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "1.0.0" + } + }, + "fs-extra": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", + "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.7.0", + "node-pre-gyp": "0.6.36" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, "code-point-at": { "version": "1.1.0", "bundled": true, @@ -9144,9 +10134,9 @@ } }, "tslib": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", - "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.0.tgz", + "integrity": "sha512-ymKWWZJST0/CkgduC2qkzjMOWr4bouhuURNXCn/inEX0L57BnRG6FhX76o7FOnsjHazCjfU2LKeSrlS2sIKQJg==" }, "tslint": { "version": "5.7.0", @@ -9162,7 +10152,7 @@ "minimatch": "3.0.4", "resolve": "1.4.0", "semver": "5.4.1", - "tslib": "1.7.1", + "tslib": "1.8.0", "tsutils": "2.12.1" } }, @@ -9172,7 +10162,7 @@ "integrity": "sha1-9Nlc4zkciXHkblTEzw7bCiHdWyQ=", "dev": true, "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "tty-browserify": { diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.ts index 284b78d7..81546199 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.ts +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.ts @@ -30,13 +30,13 @@ import { Output } from "@angular/core"; export class ActivitiesCardsComponent { @Input() public activities: Activity[]; - @Input() private selectedActivities: Activity[]; - @Output() private activitySelected: EventEmitter = new EventEmitter(); - @Output() private activityDeselected: EventEmitter = new EventEmitter(); - @Output() private tagSelected: EventEmitter = new EventEmitter(); - @Output() private startActivity: EventEmitter = new EventEmitter(); - @Output() private editActivity: EventEmitter = new EventEmitter(); - @Output() private deleteActivity: EventEmitter = new EventEmitter(); + @Input() public selectedActivities: Activity[]; + @Output() public activitySelected: EventEmitter = new EventEmitter(); + @Output() public activityDeselected: EventEmitter = new EventEmitter(); + @Output() public tagSelected: EventEmitter = new EventEmitter(); + @Output() public startActivity: EventEmitter = new EventEmitter(); + @Output() public editActivity: EventEmitter = new EventEmitter(); + @Output() public deleteActivity: EventEmitter = new EventEmitter(); /** * Constructor. diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.ts b/ngapp/src/app/activities/activities-list/activities-list.component.ts index 7bd2e705..0b35602c 100644 --- a/ngapp/src/app/activities/activities-list/activities-list.component.ts +++ b/ngapp/src/app/activities/activities-list/activities-list.component.ts @@ -30,13 +30,13 @@ import { Output } from "@angular/core"; export class ActivitiesListComponent { @Input() public activities: Activity[]; - @Input() private selectedActivities: Activity[]; - @Output() private activitySelected: EventEmitter = new EventEmitter(); - @Output() private activityDeselected: EventEmitter = new EventEmitter(); - @Output() private tagSelected: EventEmitter = new EventEmitter(); - @Output() private editActivity: EventEmitter = new EventEmitter(); - @Output() private startActivity: EventEmitter = new EventEmitter(); - @Output() private deleteActivity: EventEmitter = new EventEmitter(); + @Input() public selectedActivities: Activity[]; + @Output() public activitySelected: EventEmitter = new EventEmitter(); + @Output() public activityDeselected: EventEmitter = new EventEmitter(); + @Output() public tagSelected: EventEmitter = new EventEmitter(); + @Output() public editActivity: EventEmitter = new EventEmitter(); + @Output() public startActivity: EventEmitter = new EventEmitter(); + @Output() public deleteActivity: EventEmitter = new EventEmitter(); /** * Constructor. diff --git a/ngapp/src/app/activities/activities-routing.module.ts b/ngapp/src/app/activities/activities-routing.module.ts index 79528fdc..894d1cb5 100644 --- a/ngapp/src/app/activities/activities-routing.module.ts +++ b/ngapp/src/app/activities/activities-routing.module.ts @@ -25,7 +25,7 @@ const activitiesRoutes: Routes = [ @NgModule({ imports: [ - RouterModule.forRoot( activitiesRoutes ) + RouterModule.forChild( activitiesRoutes ) ], exports: [ RouterModule diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts index 1375fb10..5d6fcb28 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.ts @@ -32,13 +32,13 @@ import { LoggerService } from "@core/logger.service"; }) export class AddActivityFormComponent { - public creatingActivity = false; + @Output() public createActivity = new EventEmitter(); + private model = new NewActivity(); + private creating = false; private logger: LoggerService; private router: Router; - @Output() private createActivity = new EventEmitter(); - constructor( router: Router, logger: LoggerService ) { this.router = router; this.logger = logger; @@ -104,6 +104,13 @@ export class AddActivityFormComponent { return JSON.stringify(this.model); } + /** + * @returns {boolean} 'true' if the activity is being created + */ + public get creatingActivity(): boolean { + return this.creating; + } + /** * Called when the user clicks the "Create Activity" submit button on the form. */ @@ -116,7 +123,7 @@ export class AddActivityFormComponent { this.logger.log("[AddActivityFormComponent] Firing create-activity event: %o", activity); - this.creatingActivity = true; + this.creating = true; this.createActivity.emit(activity); } diff --git a/ngapp/src/app/app.component.ts b/ngapp/src/app/app.component.ts index 769de486..dc2d80dd 100644 --- a/ngapp/src/app/app.component.ts +++ b/ngapp/src/app/app.component.ts @@ -25,12 +25,26 @@ import { Component } from "@angular/core"; }) export class AppComponent { - public routerOutletWrapperId: string; - public routerOutletWrapperClass: string; + private routerOutletDivId: string; + private routerOutletDivClass: string; constructor() { - this.routerOutletWrapperId = "studio-page-body"; - this.routerOutletWrapperClass = ""; + this.routerOutletDivId = "studio-page-body"; + this.routerOutletDivClass = ""; + } + + /** + * @returns {string} the identifier of the div containing the router outlet + */ + public get routerOutletWrapperId(): string { + return this.routerOutletDivId; + } + + /** + * @returns {string} the class name of the div containing the router outlet + */ + public get routerOutletWrapperClass(): string { + return this.routerOutletDivClass; } } diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index b75469a7..f8200bf1 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -1,3 +1,20 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Component, OnInit, @@ -5,17 +22,17 @@ import { ViewEncapsulation, } from "@angular/core"; -import { FormControl, FormGroup} from "@angular/forms"; +import { FormControl, FormGroup } from "@angular/forms"; import { AbstractControl } from "@angular/forms"; import { Validators } from "@angular/forms"; import { Router } from "@angular/router"; -import { ConnectionService} from "@connections/shared/connection.service"; +import { ConnectionService } from "@connections/shared/connection.service"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { NewConnection } from "@connections/shared/new-connection.model"; -import { TemplateDefinition} from "@connections/shared/template-definition.model"; +import { TemplateDefinition } from "@connections/shared/template-definition.model"; import { LoggerService } from "@core/logger.service"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; -import {PropertyFormComponent} from "@shared/property-form/property-form.component"; +import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { WizardComponent } from "patternfly-ng"; import { WizardEvent } from "patternfly-ng"; import { WizardStepConfig } from "patternfly-ng"; @@ -32,19 +49,12 @@ export class AddConnectionWizardComponent implements OnInit { // Wizard Config public wizardConfig: WizardConfig; - @ViewChild("wizard") private wizard: WizardComponent; - @ViewChild(PropertyFormComponent) private detailPropForm: PropertyFormComponent; - - private connectionService: ConnectionService; - private allTemplates: TemplateDefinition[] = []; - public templatesLoaded = false; - public detailPropertiesLoaded = false; - private basicPropertyForm: FormGroup; - private detailProperties: Array> = []; - private requiredPropValues: Array<[string, string]> = []; - + public basicPropertyForm: FormGroup; public createComplete = true; public createSuccessful = false; + public detailPropertiesLoaded = false; + public requiredPropValues: Array<[string, string]> = []; + public templatesLoaded = false; // Wizard Step 1 public step1Config: WizardStepConfig; @@ -56,6 +66,13 @@ export class AddConnectionWizardComponent implements OnInit { public step3Config: WizardStepConfig; public step3aConfig: WizardStepConfig; public step3bConfig: WizardStepConfig; + + @ViewChild("wizard") public wizard: WizardComponent; + @ViewChild(PropertyFormComponent) public detailPropForm: PropertyFormComponent; + + private connectionService: ConnectionService; + private allTemplates: TemplateDefinition[] = []; + private detailProperties: Array> = []; private logger: LoggerService; private router: Router; diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ngapp/src/app/connections/add-connection/add-connection.component.ts index 4fd3de3e..947a782d 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.ts @@ -1,5 +1,22 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Component, OnInit } from "@angular/core"; -import {ConnectionsConstants} from "@connections/shared/connections-constants"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; @Component({ selector: "app-add-connection-page", @@ -9,6 +26,7 @@ import {ConnectionsConstants} from "@connections/shared/connections-constants"; export class AddConnectionComponent implements OnInit { public readonly connectionsLink = ConnectionsConstants.connectionsRootPath; + public pageError: any = ""; constructor() { diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts index 68c2798e..b4a76458 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts @@ -27,12 +27,12 @@ import { Connection } from "@connections/shared/connection.model"; export class ConnectionsCardsComponent { @Input() public connections: Connection[]; - @Input() private selectedConnections: Connection[]; - @Output() private connectionSelected: EventEmitter = new EventEmitter(); - @Output() private connectionDeselected: EventEmitter = new EventEmitter(); - @Output() private tagSelected: EventEmitter = new EventEmitter(); - @Output() private pingConnection: EventEmitter = new EventEmitter(); - @Output() private deleteConnection: EventEmitter = new EventEmitter(); + @Input() public selectedConnections: Connection[]; + @Output() public connectionSelected: EventEmitter = new EventEmitter(); + @Output() public connectionDeselected: EventEmitter = new EventEmitter(); + @Output() public tagSelected: EventEmitter = new EventEmitter(); + @Output() public pingConnection: EventEmitter = new EventEmitter(); + @Output() public deleteConnection: EventEmitter = new EventEmitter(); /** * Constructor. diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.ts b/ngapp/src/app/connections/connections-list/connections-list.component.ts index bac909e3..830a1d5c 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.ts +++ b/ngapp/src/app/connections/connections-list/connections-list.component.ts @@ -27,15 +27,15 @@ import { Connection } from "@connections/shared/connection.model"; }) export class ConnectionsListComponent { - private router: Router; - @Input() public connections: Connection[]; - @Input() private selectedConnections: Connection[]; - @Output() private connectionSelected: EventEmitter = new EventEmitter(); - @Output() private connectionDeselected: EventEmitter = new EventEmitter(); - @Output() private tagSelected: EventEmitter = new EventEmitter(); - @Output() private pingConnection: EventEmitter = new EventEmitter(); - @Output() private deleteConnection: EventEmitter = new EventEmitter(); + @Input() public selectedConnections: Connection[]; + @Output() public connectionSelected: EventEmitter = new EventEmitter(); + @Output() public connectionDeselected: EventEmitter = new EventEmitter(); + @Output() public tagSelected: EventEmitter = new EventEmitter(); + @Output() public pingConnection: EventEmitter = new EventEmitter(); + @Output() public deleteConnection: EventEmitter = new EventEmitter(); + + private router: Router; /** * Constructor. diff --git a/ngapp/src/app/connections/connections-routing.module.ts b/ngapp/src/app/connections/connections-routing.module.ts index a8fb2541..5b3092d9 100644 --- a/ngapp/src/app/connections/connections-routing.module.ts +++ b/ngapp/src/app/connections/connections-routing.module.ts @@ -29,7 +29,7 @@ const connectionsRoutes: Routes = [ @NgModule({ imports: [ - RouterModule.forRoot( connectionsRoutes ) + RouterModule.forChild( connectionsRoutes ) ], exports: [ RouterModule diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 20458a0d..875d7eaf 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -17,7 +17,7 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; -import {FormsModule, ReactiveFormsModule} from "@angular/forms"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; @@ -27,8 +27,8 @@ import { ConnectionService } from "@connections/shared/connection.service"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; -import { AddConnectionComponent } from "./add-connection/add-connection.component"; import { AddConnectionWizardComponent } from "./add-connection-wizard/add-connection-wizard.component"; +import { AddConnectionComponent } from "./add-connection/add-connection.component"; @NgModule({ imports: [ diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts index e949b7df..de3cf5de 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts @@ -25,8 +25,8 @@ import { Component, Input } from "@angular/core"; }) export class BreadcrumbComponent { - @Input() private label: string; - @Input() private icon: string; + @Input() public label: string; + @Input() public icon: string; @Input() public route: string[]; } diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index 5e8ce258..36270c72 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -57,19 +57,25 @@ export class VerticalNavComponent implements OnInit { } /** - * Returns true if the currently active route is /activities/* - * @returns {boolean} + * Called when the user clicks the vertical menu Activities item. */ - private isActivitiesRoute(): boolean { - return this.router.isActive( "/activities", true ); + public onActivitiesClick(): void { + this.currentMenu = VerticalNavType.Activities; + const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; + this.router.navigate(link).then(() => { + // nothing to do + }); } - /** - * Returns true if the currently active route is /connections/* - * @returns {boolean} - */ - private isConnectionsRoute(): boolean { - return this.router.isActive("/connections", true); + /** + * Called when the user clicks the vertical menu Connections item. + */ + public onConnectionsClick(): void { + this.currentMenu = VerticalNavType.Connections; + const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; + this.router.navigate(link).then(() => { + // nothing to do + }); } /** @@ -85,28 +91,6 @@ export class VerticalNavComponent implements OnInit { */ } - /** - * Called when the user clicks the vertical menu Activities item. - */ - public onActivitiesClick(): void { - this.currentMenu = VerticalNavType.Activities; - const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; - this.router.navigate(link).then(() => { - // nothing to do - }); - } - - /** - * Called when the user clicks the vertical menu Connections item. - */ - public onConnectionsClick(): void { - this.currentMenu = VerticalNavType.Connections; - const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; - this.router.navigate(link).then(() => { - // nothing to do - }); - } - /** * Toggles a sub-menu off the main vertical left-hand menu bar. If the sub-menu is * already selected, it de-selects it. diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts index c4a86e47..730facb0 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts @@ -29,8 +29,8 @@ export class ConfirmDeleteComponent { protected dialogIsOpen = false; - @Output() private deleteSelected: EventEmitter = new EventEmitter(); - @ViewChildren("confirmDeleteModal") private confirmDeleteModal: QueryList; + @Output() public deleteSelected: EventEmitter = new EventEmitter(); + @ViewChildren("confirmDeleteModal") public confirmDeleteModal: QueryList; /** * Called to open the dialog. diff --git a/ngapp/src/app/shared/page-error/page-error.component.ts b/ngapp/src/app/shared/page-error/page-error.component.ts index 4f1ce727..6e1f8163 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.ts @@ -25,11 +25,11 @@ import { Component, Input } from "@angular/core"; }) export class PageErrorComponent { + @Input() public error: any = ""; + private eobj: any = null; private showDetails = false; - @Input() private error: any = ""; - /** * Returns whether details should be shown. */ diff --git a/ngapp/src/app/shared/property-form/property-form.component.ts b/ngapp/src/app/shared/property-form/property-form.component.ts index b6ba28f7..6ebe5e22 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.ts @@ -1,7 +1,24 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Component, Input, OnInit } from "@angular/core"; -import { FormControl, FormGroup, Validators } from "@angular/forms"; +import { Form, FormControl, FormGroup, Validators } from "@angular/forms"; -import {ObjectUtils} from "@core/utils/object-utils"; +import { ObjectUtils } from "@core/utils/object-utils"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; @Component({ diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts index 3612073b..1995209a 100644 --- a/ngapp/src/environments/environment.prod.ts +++ b/ngapp/src/environments/environment.prod.ts @@ -1,3 +1,33 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConnectionsConstants } from "@connections/shared/connections-constants"; + export const environment = { - production: true + + production: true, + + // the home page path + homePagePath: ConnectionsConstants.connectionsRootPath, + + // REST URL - Komodo workspace + komodoWorkspaceUrl: "https://localhost:8443/vdb-builder/v1/workspace", + + // REST URL - Komodo teiid server + komodoTeiidUrl: "https://localhost:8443/vdb-builder/v1/teiid", + }; From d4ddd1aef993a45affde72df19df52b114dfdaa7 Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Wed, 18 Oct 2017 16:44:53 -0500 Subject: [PATCH 023/205] Issue 21- Added missing translations --- ngapp/locale/messages.es.xlf | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ngapp/locale/messages.es.xlf b/ngapp/locale/messages.es.xlf index 9b96ac97..482b3159 100644 --- a/ngapp/locale/messages.es.xlf +++ b/ngapp/locale/messages.es.xlf @@ -81,7 +81,7 @@ Cargando actividades ... src/app/activities/activities.component.ts - 81 + 82 @@ -145,7 +145,7 @@ Objetivo: src/app/activities/activities-cards/activities-cards.component.ts - 20 + 19 @@ -161,7 +161,7 @@ Objetivo: src/app/activities/activities-list/activities-list.component.ts - 22 + 21 @@ -243,7 +243,7 @@ JNDI: src/app/connections/connections-cards/connections-cards.component.ts - 16 + 15 @@ -251,7 +251,7 @@ Conductor: src/app/connections/connections-cards/connections-cards.component.ts - 20 + 18 @@ -267,7 +267,7 @@ Conductor: src/app/connections/connections-list/connections-list.component.ts - 22 + 21 @@ -403,7 +403,7 @@ - version + Version versión src/app/core/nav-header/nav-header.component.ts @@ -436,7 +436,7 @@ 50 - + Activities Ocupaciones @@ -444,7 +444,7 @@ 7 - + Connections Conexiones @@ -545,7 +545,7 @@ 56 - + It appears you attempted to add or create something that already exists. Instead of adding it again, try finding the existing resource and editing. @@ -591,7 +591,7 @@ 95 - + Something unexpected happened. Please try reloading the page, or you could just go back to Home. See the buttons below... From 328763c662d332f277536d3dbcb76ce0550b5a6e Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 19 Oct 2017 09:32:04 -0500 Subject: [PATCH 024/205] Updates to Unit Tests --- .../activities-cards.component.css | 2 +- .../activities-cards.component.html | 2 +- .../activities-list.component.css | 5 +- .../app/activities/activities.component.html | 4 +- .../activities/activities.component.spec.ts | 83 ++++++++++++++++++- .../app/activities/activities.component.ts | 77 ++++++++++++----- .../shared/mock-activity.service.ts | 48 +++++------ .../add-connection-wizard.component.spec.ts | 23 ++--- .../add-connection.component.spec.ts | 12 ++- .../connections-cards.component.css | 2 +- .../connections-cards.component.html | 2 +- .../connections-list.component.css | 5 +- .../connections-list.component.html | 1 - .../connections/connections.component.html | 4 +- .../connections/connections.component.spec.ts | 83 ++++++++++++++++++- .../app/connections/connections.component.ts | 74 ++++++++++------- .../src/app/connections/connections.module.ts | 4 +- .../shared/mock-connection.service.ts | 22 ++++- .../property-form-property.component.spec.ts | 22 +++-- .../property-form-property.component.ts | 8 ++ .../property-form.component.spec.ts | 4 +- 21 files changed, 370 insertions(+), 117 deletions(-) diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.css b/ngapp/src/app/activities/activities-cards/activities-cards.component.css index cd893700..d5b6ec28 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.css +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.css @@ -31,7 +31,7 @@ //-ms-transition: background-color 300ms; -o-transition: background-color 300ms; transition: background-color 300ms; - height: 220px; + height: 160px; } .activity-card:hover { background-color: rgb(237, 237, 237); diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.html b/ngapp/src/app/activities/activities-cards/activities-cards.component.html index d18a6518..783cec38 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.html +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.html @@ -1,7 +1,7 @@
    -
    +
    diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.css b/ngapp/src/app/activities/activities-list/activities-list.component.css index d3d18292..982b2a44 100644 --- a/ngapp/src/app/activities/activities-list/activities-list.component.css +++ b/ngapp/src/app/activities/activities-list/activities-list.component.css @@ -1,4 +1,7 @@ - +.list-view-pf-main-info { + padding-bottom: 5px; + padding-top: 5px; +} .list-group-item { -webkit-transition: background-color 300ms; -moz-transition: background-color 300ms; diff --git a/ngapp/src/app/activities/activities.component.html b/ngapp/src/app/activities/activities.component.html index 8d933edb..b21f81c3 100644 --- a/ngapp/src/app/activities/activities.component.html +++ b/ngapp/src/app/activities/activities.component.html @@ -32,8 +32,8 @@

    Activities

      -
    • -
    • +
    • +
    diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts index 09c246a8..a221e422 100644 --- a/ngapp/src/app/activities/activities.component.spec.ts +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -1,9 +1,12 @@ import { ActivitiesCardsComponent } from "@activities/activities-cards/activities-cards.component"; import { ActivitiesListComponent } from "@activities/activities-list/activities-list.component"; import { ActivitiesComponent } from "@activities/activities.component"; +import { ActivityService } from "@activities/shared/activity.service"; +import { MockActivityService } from "@activities/shared/mock-activity.service"; import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; +import { By } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; @@ -15,8 +18,11 @@ describe("ActivitiesComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], - declarations: [ ActivitiesComponent, ActivitiesListComponent, ActivitiesCardsComponent ] + imports: [CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule], + declarations: [ActivitiesComponent, ActivitiesListComponent, ActivitiesCardsComponent], + providers: [ + {provide: ActivityService, useClass: MockActivityService} + ] }) .compileComponents().then(() => { // nothing to do @@ -32,4 +38,77 @@ describe("ActivitiesComponent", () => { it("should be created", () => { expect(component).toBeTruthy(); }); + + it("should have Activities Title", () => { + // query for the title

    by CSS element selector + const de = fixture.debugElement.query(By.css("h2")); + const el = de.nativeElement; + expect(el.textContent).toEqual("Activities"); + }); + + it("should have Toolbar", () => { + // query for the toolbar by css classname + const de = fixture.debugElement.query(By.css(".toolbar-pf")); + expect(de).toBeDefined(); + }); + + it("should have Activities", () => { + // Check component object + const activities = component.allActivities; + expect(activities.length).toEqual(3); + + // Check html has the same number of activity cards + const cardDebugElems = fixture.debugElement.queryAll(By.css(".activity-card-title")); + expect(cardDebugElems).toBeDefined(); + expect(cardDebugElems.length).toEqual(3); + }); + + it("should have initial card layout", () => { + // app-activities-cards should be present + let debugEl = fixture.debugElement.query(By.css("app-activities-cards")); + const element = debugEl.nativeElement; + expect(element).toBeDefined(); + + // app-activities-list should not be present + debugEl = fixture.debugElement.query(By.css("app-activities-list")); + expect(debugEl).toBeNull(); + }); + + it("should toggle layout", () => { + // Initial layout should be Card Layout + let cardDebugElem = fixture.debugElement.query(By.css("app-activities-cards")); + let listDebugElem = fixture.debugElement.query(By.css("app-activities-list")); + expect(cardDebugElem).toBeDefined(); + expect(listDebugElem).toBeNull(); + const cardElem = cardDebugElem.nativeElement; + expect(cardElem).toBeDefined(); + + // Change the layout to ListLayout + component.setListLayout(); + fixture.detectChanges(); + + // Verify that the layout has changed + cardDebugElem = fixture.debugElement.query(By.css("app-activities-cards")); + listDebugElem = fixture.debugElement.query(By.css("app-activities-list")); + expect(cardDebugElem).toBeNull(); + expect(listDebugElem).toBeDefined(); + const listElem = listDebugElem.nativeElement; + expect(listElem).toBeDefined(); + }); + + it("should filter activities", () => { + // Expect 3 activities initially. + let activities = component.filteredActivities; + expect(activities.length).toEqual(3); + + // Set a name filter which satisfies none of the activities + component.nameFilter = "g"; + component.filterActivities(); + fixture.detectChanges(); + + // Now expect 0 activities match + activities = component.filteredActivities; + expect(activities.length).toEqual(0); + }); + }); diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index d66859b6..8c3f0d67 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -42,15 +42,15 @@ export class ActivitiesComponent extends AbstractPageComponent { public readonly addActivityLink = ActivitiesConstants.addActivityPath; - private allActivities: Activity[] = []; - private filteredActivities: Activity[] = []; - private selectedActivities: Activity[] = []; + private allActs: Activity[] = []; + private filteredActs: Activity[] = []; + private selectedActs: Activity[] = []; private activityNameForDelete: string; private router: Router; private activityService: ActivityService; private filter: IdFilter = new IdFilter(); private layout: LayoutType = LayoutType.CARD; - private sortDirection: SortDirection; + private sortDirection: SortDirection = SortDirection.ASC; @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; @@ -62,20 +62,20 @@ export class ActivitiesComponent extends AbstractPageComponent { } public loadAsyncPageData(): void { - this.allActivities = this.activityService.getAllActivities(); - this.filteredActivities = this.filterActivities(); + this.allActs = this.activityService.getAllActivities(); + this.filteredActs = this.filterActivities(); this.loaded("activities"); } public onSelected(activity: Activity): void { // Only allow one item to be selected - this.selectedActivities.shift(); - this.selectedActivities.push(activity); + this.selectedActs.shift(); + this.selectedActs.push(activity); } public onDeselected(activity: Activity): void { // Only one item is selected at a time - this.selectedActivities.shift(); + this.selectedActs.shift(); // this.selectedConnections.splice(this.selectedConnections.indexOf(connection), 1); } @@ -96,7 +96,18 @@ export class ActivitiesComponent extends AbstractPageComponent { } public isFiltered(): boolean { - return this.allActivities.length !== this.filteredActivities.length; + return this.allActs.length !== this.filteredActs.length; + } + + public get nameFilter(): string { + return this.filter.getPattern(); + } + + /** + * @param {string} pattern the new pattern for the connection name filter (can be null or empty) + */ + public set nameFilter( pattern: string ) { + this.filter.setFilter( pattern ); } public toggleSortDirection(): void { @@ -142,17 +153,37 @@ export class ActivitiesComponent extends AbstractPageComponent { } /** - * @returns {string} the pattern the activity names are being matched to (can be null or empty) + * @returns {Activity[]} the array of all activities */ - public get nameFilter(): string { - return this.filter.getPattern(); + public get allActivities(): Activity[] { + return this.allActs; + } + + /** + * @returns {Activity[]} the array of filtered activities + */ + public get filteredActivities(): Activity[] { + return this.filteredActs; } - public onListLayout(): void { + /** + * @returns {Activity[]} the array of selected activities + */ + public get selectedActivities(): Activity[] { + return this.selectedActs; + } + + /** + * Set the layout type to LIST + */ + public setListLayout(): void { this.layout = LayoutType.LIST; } - public onCardLayout(): void { + /** + * Set the layout type to CARD + */ + public setCardLayout(): void { this.layout = LayoutType.CARD; } @@ -185,15 +216,15 @@ export class ActivitiesComponent extends AbstractPageComponent { /** * Filters and sorts the list of activities based on the user input */ - private filterActivities(): Activity[] { + public filterActivities(): Activity[] { // Clear the array first. - this.filteredActivities.splice(0, this.filteredActivities.length); - for (const activity of this.allActivities) { + this.filteredActs.splice(0, this.filteredActs.length); + for (const activity of this.allActs) { if (this.filter.accepts(activity)) { - this.filteredActivities.push(activity); + this.filteredActs.push(activity); } } - this.filteredActivities.sort( (a1: Activity, a2: Activity) => { + this.filteredActs.sort( (a1: Activity, a2: Activity) => { let rval: number = a1.getId().localeCompare(a2.getId()); if (this.sortDirection === SortDirection.DESC) { rval *= -1; @@ -201,13 +232,13 @@ export class ActivitiesComponent extends AbstractPageComponent { return rval; }); - this.selectedActivities = ArrayUtils.intersect(this.selectedActivities, this.filteredActivities); + this.selectedActs = ArrayUtils.intersect(this.selectedActs, this.filteredActs); - return this.filteredActivities; + return this.filteredActs; } private removeActivityFromList(activity: Activity): void { - this.allActivities.splice(this.allActivities.indexOf(activity), 1); + this.allActs.splice(this.allActs.indexOf(activity), 1); this.filterActivities(); } } diff --git a/ngapp/src/app/activities/shared/mock-activity.service.ts b/ngapp/src/app/activities/shared/mock-activity.service.ts index 53fe4598..f24b47bf 100644 --- a/ngapp/src/app/activities/shared/mock-activity.service.ts +++ b/ngapp/src/app/activities/shared/mock-activity.service.ts @@ -1,22 +1,24 @@ import { Activity } from "@activities/shared/activity.model"; +import { ActivityService } from "@activities/shared/activity.service"; import { NewActivity } from "@activities/shared/new-activity.model"; import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; @Injectable() -export class MockActivityService { +export class MockActivityService extends ActivityService { - private activity1 = new Activity(); - private activity2 = new Activity(); - private activity3 = new Activity(); - private activities: Activity[] = [this.activity1, this.activity2, this.activity3]; - private newActivity1 = new NewActivity(); + private act1 = new Activity(); + private act2 = new Activity(); + private act3 = new Activity(); + private acts: Activity[] = [this.act1, this.act2, this.act3]; + private newAct1 = new NewActivity(); private newConnection = new NewConnection(); private conn1 = new Connection(); @@ -24,32 +26,30 @@ export class MockActivityService { private conn3 = new Connection(); private conns: Connection[] = [this.conn1, this.conn2, this.conn3]; - private http: Http; - - constructor( http: Http ) { - this.http = http; - this.activity1.setId("activity1"); - this.activity1.setSourceConnection("activity1SrcConn"); - this.activity1.setTargetConnection("activity1TgtConn"); - this.activity2.setId("activity2"); - this.activity2.setSourceConnection("activity2SrcConn"); - this.activity2.setTargetConnection("activity2TgtConn"); - this.activity3.setId("activity3"); - this.activity3.setSourceConnection("activity3SrcConn"); - this.activity3.setTargetConnection("activity3TgtConn"); - this.newActivity1.setName("newActivity1"); + constructor( http: Http, logger: LoggerService ) { + super(http, logger); + this.act1.setId("activity1"); + this.act1.setSourceConnection("activity1SrcConn"); + this.act1.setTargetConnection("activity1TgtConn"); + this.act2.setId("activity2"); + this.act2.setSourceConnection("activity2SrcConn"); + this.act2.setTargetConnection("activity2TgtConn"); + this.act3.setId("activity3"); + this.act3.setSourceConnection("activity3SrcConn"); + this.act3.setTargetConnection("activity3TgtConn"); + this.newAct1.setName("newActivity1"); const srcConn = new NewConnection(); srcConn.setName("new1Src"); srcConn.setJndiName("new1SrcJndi"); srcConn.setDriverName("new1SrcDriver"); srcConn.setJdbc(true); - this.newActivity1.setSourceConnection(srcConn); + this.newAct1.setSourceConnection(srcConn); const tgtConn = new NewConnection(); tgtConn.setName("new1Tgt"); tgtConn.setJndiName("new1TgtJndi"); tgtConn.setDriverName("new1TgtDriver"); tgtConn.setJdbc(false); - this.newActivity1.setTargetConnection(tgtConn); + this.newAct1.setTargetConnection(tgtConn); } @@ -58,7 +58,7 @@ export class MockActivityService { * @returns {Activity[]} */ public getAllActivities(): Activity[] { - return this.activities; + return this.acts; } /** @@ -67,7 +67,7 @@ export class MockActivityService { * @returns {Activity} */ public createActivity(activity: NewActivity): NewActivity { - return this.newActivity1; + return this.newAct1; } /** diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts index b0f193d7..b6ef21cd 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts @@ -1,12 +1,13 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import {FormGroup, FormsModule, ReactiveFormsModule} from "@angular/forms"; -import {RouterTestingModule} from "@angular/router/testing"; -import {CoreModule} from "@core/core.module"; -import {PropertyFormPropertyComponent} from "@shared/property-form/property-form-property/property-form-property.component"; -import {PropertyFormComponent} from "@shared/property-form/property-form.component"; -import {SharedModule} from "@shared/shared.module"; -import {PatternFlyNgModule, WizardConfig, WizardStepComponent} from "patternfly-ng"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { CoreModule } from "@core/core.module"; +import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; +import { PropertyFormComponent } from "@shared/property-form/property-form.component"; +import { PatternFlyNgModule } from "patternfly-ng"; import { AddConnectionWizardComponent } from "./add-connection-wizard.component"; describe("AddConnectionWizardComponent", () => { @@ -15,9 +16,11 @@ describe("AddConnectionWizardComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], - declarations: [ AddConnectionWizardComponent, FormGroup, PropertyFormComponent, PropertyFormPropertyComponent, - WizardConfig, WizardStepComponent ] + imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], + declarations: [ AddConnectionWizardComponent, PropertyFormComponent, PropertyFormPropertyComponent ], + providers: [ + { provide: ConnectionService, useClass: MockConnectionService }, + ] }) .compileComponents().then(() => { // nothing to do diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 1395eb59..426ab3a2 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -1,8 +1,11 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { AddConnectionWizardComponent } from "@connections/add-connection-wizard/add-connection-wizard.component"; import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { PatternFlyNgModule } from "patternfly-ng"; import { AddConnectionComponent } from "./add-connection.component"; describe("AddConnectionComponent", () => { @@ -11,7 +14,7 @@ describe("AddConnectionComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, RouterTestingModule ], + imports: [ CoreModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], declarations: [ AddConnectionComponent, AddConnectionWizardComponent ] }) .compileComponents().then(() => { @@ -25,7 +28,8 @@ describe("AddConnectionComponent", () => { fixture.detectChanges(); }); - it("should be created", () => { - expect(component).toBeTruthy(); - }); + // TODO: Figure out how to setup this test. + // it("should be created", () => { + // expect(component).toBeTruthy(); + // }); }); diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.css b/ngapp/src/app/connections/connections-cards/connections-cards.component.css index 61b8ac9e..a9f61fef 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.css +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.css @@ -30,7 +30,7 @@ //-ms-transition: background-color 300ms; -o-transition: background-color 300ms; transition: background-color 300ms; - height: 220px; + height: 160px; } .connection-card:hover { background-color: rgb(237, 237, 237); diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.html b/ngapp/src/app/connections/connections-cards/connections-cards.component.html index 043273c4..4a423f65 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.html +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.html @@ -1,7 +1,7 @@
    -
    +
    diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.css b/ngapp/src/app/connections/connections-list/connections-list.component.css index 45813472..ccc88b6f 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.css +++ b/ngapp/src/app/connections/connections-list/connections-list.component.css @@ -1,4 +1,7 @@ - +.list-view-pf-main-info { + padding-bottom: 5px; + padding-top: 5px; +} .list-group-item { -webkit-transition: background-color 300ms; -moz-transition: background-color 300ms; diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.html b/ngapp/src/app/connections/connections-list/connections-list.component.html index 5918a8d8..da8c3ca3 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.html +++ b/ngapp/src/app/connections/connections-list/connections-list.component.html @@ -32,7 +32,6 @@ -
    diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index a9435733..4c7f7097 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -32,8 +32,8 @@

    Connections

      -
    • -
    • +
    • +
    diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index e3c3c1a0..21904b7b 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -1,10 +1,13 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; +import { By } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; import { ConnectionsComponent } from "@connections/connections.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { ModalModule } from "ngx-bootstrap"; @@ -16,10 +19,13 @@ describe("ConnectionsComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], - declarations: [ ConnectionsComponent, ConnectionsListComponent, ConnectionsCardsComponent ] + declarations: [ ConnectionsComponent, ConnectionsListComponent, ConnectionsCardsComponent ], + providers: [ + { provide: ConnectionService, useValue: MockConnectionService }, + ] }) .compileComponents().then(() => { - // nothing to do + // Nothing }); })); @@ -32,4 +38,77 @@ describe("ConnectionsComponent", () => { it("should be created", () => { expect(component).toBeTruthy(); }); + + it("should have Connections Title", () => { + // query for the title

    by CSS element selector + const de = fixture.debugElement.query(By.css("h2")); + const el = de.nativeElement; + expect(el.textContent).toEqual("Connections"); + }); + + it("should have Toolbar", () => { + // query for the toolbar by css classname + const de = fixture.debugElement.query(By.css(".toolbar-pf")); + expect(de).toBeDefined(); + }); + + // it("should have Connections", () => { + // // Check component object + // const connections = component.allConnections; + // expect(connections.length).toEqual(3); + // + // // Check html has the same number of connection cards + // const cardDebugElems = fixture.debugElement.queryAll(By.css(".connection-card-title")); + // expect(cardDebugElems).toBeDefined(); + // expect(cardDebugElems.length).toEqual(3); + // }); + + // it("should have initial card layout", () => { + // // app-connections-cards should be present + // let debugEl = fixture.debugElement.query(By.css("app-connections-cards")); + // const element = debugEl.nativeElement; + // expect(element).toBeDefined(); + // + // // app-connections-list should not be present + // debugEl = fixture.debugElement.query(By.css("app-connections-list")); + // expect(debugEl).toBeNull(); + // }); + + // it("should toggle layout", () => { + // // Initial layout should be Card Layout + // let cardDebugElem = fixture.debugElement.query(By.css("app-connections-cards")); + // let listDebugElem = fixture.debugElement.query(By.css("app-connections-list")); + // expect(cardDebugElem).toBeDefined(); + // expect(listDebugElem).toBeNull(); + // const cardElem = cardDebugElem.nativeElement; + // expect(cardElem).toBeDefined(); + // + // // Change the layout to ListLayout + // component.setListLayout(); + // fixture.detectChanges(); + // + // // Verify that the layout has changed + // cardDebugElem = fixture.debugElement.query(By.css("app-connections-cards")); + // listDebugElem = fixture.debugElement.query(By.css("app-connections-list")); + // expect(cardDebugElem).toBeNull(); + // expect(listDebugElem).toBeDefined(); + // const listElem = listDebugElem.nativeElement; + // expect(listElem).toBeDefined(); + // }); + + // it("should filter connections", () => { + // // Expect 3 connections initially. + // let connections = component.filteredConnections; + // expect(connections.length).toEqual(3); + // + // // Set a name filter which satisfies none of the connections + // component.nameFilter = "g"; + // component.filterConnections(); + // fixture.detectChanges(); + // + // // Now expect 0 activities match + // connections = component.filteredConnections; + // expect(connections.length).toEqual(0); + // }); + }); diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index cda917d3..077c9c6a 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -40,15 +40,15 @@ export class ConnectionsComponent extends AbstractPageComponent { public readonly addConnectionLink: string = ConnectionsConstants.addConnectionPath; - private allConnections: Connection[] = []; - private filteredConnections: Connection[] = []; - private selectedConnections: Connection[] = []; + private allConns: Connection[] = []; + private filteredConns: Connection[] = []; + private selectedConns: Connection[] = []; private connectionNameForDelete: string; private router: Router; private connectionService: ConnectionService; private filter: IdFilter = new IdFilter(); private layout: LayoutType = LayoutType.CARD; - private sortDirection: SortDirection; + private sortDirection: SortDirection = SortDirection.ASC; @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; @@ -63,8 +63,8 @@ export class ConnectionsComponent extends AbstractPageComponent { .getAllConnections() .subscribe( (connections) => { - this.allConnections = connections; - this.filteredConnections = this.filterConnections(); + this.allConns = connections; + this.filteredConns = this.filterConnections(); this.loaded("connections"); }, (error) => { @@ -103,17 +103,24 @@ export class ConnectionsComponent extends AbstractPageComponent { } /** - * @returns {string} the pattern the connection names are being matched to (can be null or empty) + * @returns {Connection[]} the array of all connections */ - public get nameFilter(): string { - return this.filter.getPattern(); + public get allConnections(): Connection[] { + return this.allConns; } /** - * @param {string} pattern the new pattern for the connection name filter (can be null or empty) + * @returns {Connection[]} the array of filtered connections */ - public set nameFilter( pattern: string ) { - this.filter.setFilter( pattern ); + public get filteredConnections(): Connection[] { + return this.filteredConns; + } + + /** + * @returns {Connection[]} the array of selected connections + */ + public get selectedConnections(): Connection[] { + return this.selectedConns; } public onPing( connName: string): void { @@ -122,14 +129,14 @@ export class ConnectionsComponent extends AbstractPageComponent { public onSelected(connection: Connection): void { // Only allow one item to be selected - this.selectedConnections.shift(); - this.selectedConnections.push(connection); + this.selectedConns.shift(); + this.selectedConns.push(connection); } public onDeselected(connection: Connection): void { // Only one item is selected at a time - this.selectedConnections.shift(); - // this.selectedConnections.splice(this.selectedConnections.indexOf(connection), 1); + this.selectedConns.shift(); + // this.selectedConns.splice(this.selectedConns.indexOf(connection), 1); } public onDelete(connName: string): void { @@ -138,7 +145,18 @@ export class ConnectionsComponent extends AbstractPageComponent { } public isFiltered(): boolean { - return this.allConnections.length !== this.filteredConnections.length; + return this.allConns.length !== this.filteredConns.length; + } + + public get nameFilter(): string { + return this.filter.getPattern(); + } + + /** + * @param {string} pattern the new pattern for the connection name filter (can be null or empty) + */ + public set nameFilter( pattern: string ) { + this.filter.setFilter( pattern ); } public toggleSortDirection(): void { @@ -155,11 +173,11 @@ export class ConnectionsComponent extends AbstractPageComponent { this.filterConnections(); } - public onListLayout(): void { + public setListLayout(): void { this.layout = LayoutType.LIST; } - public onCardLayout(): void { + public setCardLayout(): void { this.layout = LayoutType.CARD; } @@ -169,7 +187,7 @@ export class ConnectionsComponent extends AbstractPageComponent { public onDeleteConnection(): void { const selectedConn = this.filterConnections().find((x) => x.getId() === this.connectionNameForDelete); - // const itemsToDelete: Connection[] = ArrayUtils.intersect(this.selectedConnections, this.filteredConnections); + // const itemsToDelete: Connection[] = ArrayUtils.intersect(this.selectedConns, this.filteredConns); // const selectedConn = itemsToDelete[0]; const connectionToDelete: NewConnection = new NewConnection(); @@ -194,15 +212,15 @@ export class ConnectionsComponent extends AbstractPageComponent { /** * Filters and sorts the list of connections based on the user input */ - private filterConnections(): Connection[] { + public filterConnections(): Connection[] { // Clear the array first. - this.filteredConnections.splice(0, this.filteredConnections.length); - for (const connection of this.allConnections) { + this.filteredConns.splice(0, this.filteredConns.length); + for (const connection of this.allConns) { if (this.filter.accepts(connection)) { - this.filteredConnections.push(connection); + this.filteredConns.push(connection); } } - this.filteredConnections.sort( (c1: Connection, c2: Connection) => { + this.filteredConns.sort( (c1: Connection, c2: Connection) => { let rval: number = c1.getId().localeCompare(c2.getId()); if (this.sortDirection === SortDirection.DESC) { rval *= -1; @@ -210,13 +228,13 @@ export class ConnectionsComponent extends AbstractPageComponent { return rval; }); - this.selectedConnections = ArrayUtils.intersect(this.selectedConnections, this.filteredConnections); + this.selectedConns = ArrayUtils.intersect(this.selectedConns, this.filteredConns); - return this.filteredConnections; + return this.filteredConns; } private removeConnectionFromList(connection: Connection): void { - this.allConnections.splice(this.allConnections.indexOf(connection), 1); + this.allConns.splice(this.allConns.indexOf(connection), 1); this.filterConnections(); } } diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 875d7eaf..db685be6 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -24,6 +24,7 @@ import { ConnectionsListComponent } from "@connections/connections-list/connecti import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; import { ConnectionsComponent } from "@connections/connections.component"; import { ConnectionService } from "@connections/shared/connection.service"; +import {MockConnectionService} from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -49,7 +50,8 @@ import { AddConnectionComponent } from "./add-connection/add-connection.componen AddConnectionComponent ], providers: [ - ConnectionService + ConnectionService, + MockConnectionService ], exports: [ ] diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 2ea45ccf..78c64994 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -1,7 +1,10 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; +import { ConnectionService } from "@connections/shared/connection.service"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { TemplateDefinition } from "@connections/shared/template-definition.model"; +import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; @@ -9,17 +12,20 @@ import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; @Injectable() -export class MockConnectionService { +export class MockConnectionService extends ConnectionService { private newConnection = new NewConnection(); private conn1 = new Connection(); private conn2 = new Connection(); private conn3 = new Connection(); private conns: Connection[] = [this.conn1, this.conn2, this.conn3]; - private http: Http; + private templ1 = new TemplateDefinition(); + private templ2 = new TemplateDefinition(); + private templ3 = new TemplateDefinition(); + private templs: TemplateDefinition[] = [this.templ1, this.templ2, this.templ3]; - constructor( http: Http ) { - this.http = http; + constructor( http: Http, logger: LoggerService ) { + super(http, logger); } /** @@ -48,4 +54,12 @@ export class MockConnectionService { return Observable.of(this.newConnection); } + /** + * Get the connection templates from the komodo rest interface + * @returns {Observable>>} + */ + public getConnectionTemplates(): Observable { + return Observable.of(this.templs); + } + } diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts index 175fd33a..576927b4 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts @@ -1,6 +1,8 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { ReactiveFormsModule } from "@angular/forms"; +import {FormBuilder, FormsModule, ReactiveFormsModule, Validators} from "@angular/forms"; +import { FormGroup } from "@angular/forms"; +import { PropertyDefinition } from "@shared/property-form/property-definition.model"; import { PropertyFormPropertyComponent } from "./property-form-property.component"; describe("PropertyFormPropertyComponent", () => { @@ -9,21 +11,29 @@ describe("PropertyFormPropertyComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ ReactiveFormsModule ], - declarations: [ PropertyFormPropertyComponent ] + imports: [ FormsModule, ReactiveFormsModule ], + declarations: [ PropertyFormPropertyComponent ], + providers: [ FormBuilder ] }) .compileComponents().then(() => { // nothing to do }); })); + // TODO: Figure out how to setup this test beforeEach(() => { fixture = TestBed.createComponent(PropertyFormPropertyComponent); component = fixture.componentInstance; + component.setPropertyDefinition(new PropertyDefinition()); + const fb = new FormBuilder(); + const fg: FormGroup = fb.group({ + name: ["name", Validators.required] + }); + component.setFormGroup(fg); fixture.detectChanges(); }); - it("should be created", () => { - expect(component).toBeTruthy(); - }); + // it("should be created", () => { + // expect(component).toBeTruthy(); + // }); }); diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts index 5f3a80a1..b3a9fda1 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts @@ -30,6 +30,14 @@ export class PropertyFormPropertyComponent { @Input() public property: PropertyDefinition; @Input() public form: FormGroup; + public setPropertyDefinition(prop: PropertyDefinition): void { + this.property = prop; + } + + public setFormGroup(fg: FormGroup): void { + this.form = fg; + } + /* * Return the property valid state */ diff --git a/ngapp/src/app/shared/property-form/property-form.component.spec.ts b/ngapp/src/app/shared/property-form/property-form.component.spec.ts index 6130d0c9..821dc23a 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.spec.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.spec.ts @@ -16,7 +16,7 @@ */ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { FormsModule } from "@angular/forms"; +import { ReactiveFormsModule } from "@angular/forms"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; @@ -26,7 +26,7 @@ describe("PropertyFormComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule ], + imports: [ ReactiveFormsModule ], declarations: [ PropertyFormComponent, PropertyFormPropertyComponent ] }) .compileComponents().then(() => { From 432deae35f1fe02c0378c0a563efa2a01aebd304 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 20 Oct 2017 14:32:13 -0500 Subject: [PATCH 025/205] Initial draft of readme, style guide, and IDE developer guides. --- ngapp/package-lock.json | 1554 +++-------------- ngapp/package.json | 29 +- .../add-connection-wizard.component.spec.ts | 14 +- .../connections-list.component.html | 1 - .../connections/connections-routing.module.ts | 2 +- .../property-form/property-form.component.ts | 2 +- 6 files changed, 306 insertions(+), 1296 deletions(-) diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index d85aaa69..59e40042 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -16,9 +16,9 @@ } }, "@angular/animations": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.4.5.tgz", - "integrity": "sha1-WlpVHXV+WlVgCY9vhTXBAtk5VNc=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.4.6.tgz", + "integrity": "sha1-+mYYmaik44y3xYPHpcl85l1ZKjU=", "requires": { "tslib": "1.8.0" } @@ -73,7 +73,7 @@ "raw-loader": "0.5.1", "resolve": "1.4.0", "rsvp": "3.6.2", - "rxjs": "5.4.3", + "rxjs": "5.5.0", "sass-loader": "6.0.6", "script-loader": "0.7.1", "semver": "5.4.1", @@ -95,27 +95,27 @@ } }, "@angular/common": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.4.5.tgz", - "integrity": "sha1-vVF53JIq2/TD6m37Gec8uEn/3Dc=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-4.4.6.tgz", + "integrity": "sha1-S4FCByTggooOg5uVpV6xp+g5GPI=", "requires": { "tslib": "1.8.0" } }, "@angular/compiler": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.4.5.tgz", - "integrity": "sha1-hyGlkQ8rtS8J4tQEytJk817eWQI=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.4.6.tgz", + "integrity": "sha1-LuH68lt1fh0SiXkHS+f65SmzvCA=", "requires": { "tslib": "1.8.0" } }, "@angular/compiler-cli": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.4.5.tgz", - "integrity": "sha1-YfoDNqzRogjF8cXG1N9nnpmVMkg=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.4.6.tgz", + "integrity": "sha1-uv09HiYOmQh+uajPdTLb1gOrubE=", "requires": { - "@angular/tsc-wrapped": "4.4.5", + "@angular/tsc-wrapped": "4.4.6", "minimist": "1.2.0", "reflect-metadata": "0.1.10" }, @@ -128,55 +128,55 @@ } }, "@angular/core": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.4.5.tgz", - "integrity": "sha1-VKy8vaEXGfiDx4apBpdKvrEy8aA=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.4.6.tgz", + "integrity": "sha1-EwMf0Q3P5DiHVBmzjyESCVi8I1Q=", "requires": { "tslib": "1.8.0" } }, "@angular/forms": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.4.5.tgz", - "integrity": "sha1-6VUghiMqqyzh0I7xmLYiBOoTxDs=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-4.4.6.tgz", + "integrity": "sha1-/mSs5CQ1wbgPSQNLfEHOjK8UpEo=", "requires": { "tslib": "1.8.0" } }, "@angular/http": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.4.5.tgz", - "integrity": "sha1-LHNe2EJAH8I1ZBkmjiiNzyOW6E8=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-4.4.6.tgz", + "integrity": "sha1-CvaAxnEL3AJtlA4iXP0PalwAXQw=", "requires": { "tslib": "1.8.0" } }, "@angular/language-service": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-4.4.5.tgz", - "integrity": "sha1-zO8Tm40+FoSwGvo1xvvyFy4rtnY=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-4.4.6.tgz", + "integrity": "sha1-SY7OlcX2BmQDv5/TxYMa9CtFYYs=", "dev": true }, "@angular/platform-browser": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.4.5.tgz", - "integrity": "sha1-dOuRwLdYEm8m1T7lbHz0ZovZysU=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-4.4.6.tgz", + "integrity": "sha1-qYOcVH4bZU+h0kqJeAyLpquNzOA=", "requires": { "tslib": "1.8.0" } }, "@angular/platform-browser-dynamic": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.4.5.tgz", - "integrity": "sha1-d029wdkPd12/HjGfbtQrJgYjth8=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.4.6.tgz", + "integrity": "sha1-TT2aanvyzz3kBYphWuBZ7/ZB+jY=", "requires": { "tslib": "1.8.0" } }, "@angular/platform-server": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-4.4.4.tgz", - "integrity": "sha1-c+5B+hzshij8wDF0cnsnywAxsio=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-4.4.6.tgz", + "integrity": "sha1-QxJI9IkaY1x2rRWhfQPpyH4aODc=", "requires": { "parse5": "3.0.2", "tslib": "1.8.0", @@ -184,17 +184,17 @@ } }, "@angular/router": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.4.5.tgz", - "integrity": "sha1-9zEwz0h9mjLMGYiv2llmX0Siiok=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-4.4.6.tgz", + "integrity": "sha1-D2rSmuD/jSyeo3m9MgRHIXt+yGY=", "requires": { "tslib": "1.8.0" } }, "@angular/tsc-wrapped": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.4.5.tgz", - "integrity": "sha1-MKDLtDpmOqddyphIlL5IE3eN3Jw=", + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.4.6.tgz", + "integrity": "sha1-Fnh8u/UL3H5zgSOxnDJSfyROF40=", "requires": { "tsickle": "0.21.6" } @@ -232,9 +232,9 @@ } }, "@types/node": { - "version": "6.0.89", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.89.tgz", - "integrity": "sha512-Z/67L97+6H1qJiEEHSN1SQapkWjDss1D90rAnFcQ6UxKkah9juzotK5UNEP1bDv/0lJ3NAQTnVfc/JWdgCGruA==" + "version": "6.0.90", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.90.tgz", + "integrity": "sha512-tXoGRVdi7wZX7P1VWoV9Wfk0uYDOAHdEYXAttuWgSrN76Q32wQlSrMX0Rgyv3RTEaQY2ZLQrzYHVM2e8rfo8sA==" }, "@types/q": { "version": "0.0.32", @@ -3058,996 +3058,6 @@ "dev": true, "optional": true }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.36", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - } - } - }, - "finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.3.1", - "unpipe": "1.0.0" - } - }, - "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "1.0.2" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", - "dev": true, - "requires": { - "null-check": "1.0.0" - } - }, - "fs-extra": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", - "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", - "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.7.0", - "node-pre-gyp": "0.6.36" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, "code-point-at": { "version": "1.1.0", "bundled": true, @@ -4693,14 +3703,6 @@ } } }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, "string-width": { "version": "1.0.2", "bundled": true, @@ -4712,6 +3714,14 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, "stringstream": { "version": "0.0.5", "bundled": true, @@ -7386,7 +6396,7 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.2.tgz", "integrity": "sha1-Be/1fw70V3+xRKefi5qWemzERRA=", "requires": { - "@types/node": "6.0.89" + "@types/node": "6.0.90" } }, "parsejson": { @@ -7478,29 +6488,231 @@ "pinkie-promise": "2.0.1" } }, + "patternfly": { + "version": "3.28.3", + "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.28.3.tgz", + "integrity": "sha1-/klrjTOPxdlOMko4KuvC+lLEDvM=", + "requires": { + "bootstrap": "3.3.7", + "bootstrap-datepicker": "1.6.4", + "bootstrap-select": "1.12.4", + "bootstrap-switch": "3.3.4", + "bootstrap-touchspin": "3.1.1", + "c3": "0.4.17", + "d3": "3.5.17", + "datatables.net": "1.10.15", + "datatables.net-colreorder": "1.3.3", + "datatables.net-colreorder-bs": "1.3.3", + "datatables.net-select": "1.2.2", + "drmonty-datatables-colvis": "1.1.2", + "eonasdan-bootstrap-datetimepicker": "4.17.47", + "font-awesome": "4.7.0", + "google-code-prettify": "1.0.5", + "jquery": "3.2.1", + "jquery-match-height": "0.7.2", + "moment": "2.14.1", + "moment-timezone": "0.4.1", + "patternfly-bootstrap-combobox": "1.1.7", + "patternfly-bootstrap-treeview": "2.1.5" + }, + "dependencies": { + "bootstrap": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz", + "integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E=" + }, + "bootstrap-datepicker": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.6.4.tgz", + "integrity": "sha1-iJ6+ztjqov8V7B8nPksHUxzEPaA=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "bootstrap-select": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.12.4.tgz", + "integrity": "sha1-fxXTwM6XiGjZwJxw+WYk9V+gLuE=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "bootstrap-switch": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/bootstrap-switch/-/bootstrap-switch-3.3.4.tgz", + "integrity": "sha1-cOCusqh3wNx2aZHeEI4hcPwpov8=", + "optional": true + }, + "bootstrap-touchspin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bootstrap-touchspin/-/bootstrap-touchspin-3.1.1.tgz", + "integrity": "sha1-l3nerHKq9Xfl52K4USx0fIcdlZc=", + "optional": true + }, + "c3": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.17.tgz", + "integrity": "sha512-41T3yS3jq1XgA7ruvV1wFVEK1E2az2iUAqS7hU5de62JVrjPyxWqIPu8AHlKpShZxJbD+DXLRkQHfOLASYyqyg==", + "optional": true, + "requires": { + "d3": "3.5.17" + } + }, + "d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=", + "optional": true + }, + "datatables.net": { + "version": "1.10.15", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.15.tgz", + "integrity": "sha1-x4kHe7/jhedf9aIz+l8jJRpy32g=", + "requires": { + "jquery": "3.2.1" + } + }, + "datatables.net-bs": { + "version": "1.10.15", + "resolved": "https://registry.npmjs.org/datatables.net-bs/-/datatables.net-bs-1.10.15.tgz", + "integrity": "sha1-ssImEAfYTKW1q/VsGO3CJ+DaGk0=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "datatables.net-colreorder": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/datatables.net-colreorder/-/datatables.net-colreorder-1.3.3.tgz", + "integrity": "sha1-/HYuNQ+UIkyyzUXCuWImGg//73I=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "datatables.net-colreorder-bs": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/datatables.net-colreorder-bs/-/datatables.net-colreorder-bs-1.3.3.tgz", + "integrity": "sha1-Op3LCN7r612FQHlZHgbkk615OlM=", + "optional": true, + "requires": { + "datatables.net-bs": "1.10.15", + "datatables.net-colreorder": "1.3.3", + "jquery": "3.2.1" + } + }, + "datatables.net-select": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/datatables.net-select/-/datatables.net-select-1.2.2.tgz", + "integrity": "sha1-llF5P1KJn05XRcByCCHouChvv0U=", + "optional": true, + "requires": { + "datatables.net": "1.10.15", + "jquery": "3.2.1" + } + }, + "drmonty-datatables-colvis": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/drmonty-datatables-colvis/-/drmonty-datatables-colvis-1.1.2.tgz", + "integrity": "sha1-lque37SGQ8wu3aP4e4iTPN7oEnw=", + "optional": true, + "requires": { + "jquery": "3.2.1" + } + }, + "eonasdan-bootstrap-datetimepicker": { + "version": "4.17.47", + "resolved": "https://registry.npmjs.org/eonasdan-bootstrap-datetimepicker/-/eonasdan-bootstrap-datetimepicker-4.17.47.tgz", + "integrity": "sha1-ekmXAEQGUnbnll79Fvgic1IZ5zU=", + "optional": true, + "requires": { + "bootstrap": "3.3.7", + "jquery": "3.2.1", + "moment": "2.14.1", + "moment-timezone": "0.4.1" + } + }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, + "google-code-prettify": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/google-code-prettify/-/google-code-prettify-1.0.5.tgz", + "integrity": "sha1-n0d/Ik2/piNy5e+AOn4VdBBAAIQ=", + "optional": true + }, + "jquery": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", + "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" + }, + "jquery-match-height": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/jquery-match-height/-/jquery-match-height-0.7.2.tgz", + "integrity": "sha1-+NnzulMU2qsQnPB0CGdL4gS+Xw4=", + "optional": true + }, + "moment": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz", + "integrity": "sha1-s1snxH5X7S3ccAU9awe+zbKRdBw=" + }, + "moment-timezone": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.4.1.tgz", + "integrity": "sha1-gfWYw61eIs2teWtn7NjYjQ9bqgY=", + "optional": true, + "requires": { + "moment": "2.14.1" + } + }, + "patternfly-bootstrap-combobox": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/patternfly-bootstrap-combobox/-/patternfly-bootstrap-combobox-1.1.7.tgz", + "integrity": "sha1-al48zRFwwhs8S0qhaKdBPh3btuE=", + "optional": true + }, + "patternfly-bootstrap-treeview": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/patternfly-bootstrap-treeview/-/patternfly-bootstrap-treeview-2.1.5.tgz", + "integrity": "sha1-TCnyWC+4ovKPCpKPLw0yTSHWmQ0=", + "optional": true, + "requires": { + "bootstrap": "3.3.7", + "jquery": "3.2.1" + } + } + } + }, "patternfly-ng": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-0.13.3.tgz", - "integrity": "sha1-6lsP+7USZRmj5cDYZMtfx5bvBbQ=", - "requires": { - "@angular/animations": "4.4.5", - "@angular/common": "4.4.5", - "@angular/compiler": "4.4.5", - "@angular/compiler-cli": "4.4.5", - "@angular/core": "4.4.5", - "@angular/forms": "4.4.5", - "@angular/http": "4.4.5", - "@angular/platform-browser": "4.4.5", - "@angular/platform-browser-dynamic": "4.4.5", - "@angular/platform-server": "4.4.4", - "@angular/router": "4.4.5", + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-0.13.5.tgz", + "integrity": "sha1-cgEAhzryqsIWB/gejevSW2M30Ic=", + "requires": { + "@angular/animations": "4.4.6", + "@angular/common": "4.4.6", + "@angular/compiler": "4.4.6", + "@angular/compiler-cli": "4.4.6", + "@angular/core": "4.4.6", + "@angular/forms": "4.4.6", + "@angular/http": "4.4.6", + "@angular/platform-browser": "4.4.6", + "@angular/platform-browser-dynamic": "4.4.6", + "@angular/platform-server": "4.4.6", + "@angular/router": "4.4.6", "angular-tree-component": "4.1.0", "c3": "0.4.18", "core-js": "2.4.1", "moment": "2.17.1", "ngx-bootstrap": "1.8.0", - "patternfly": "3.28.1", - "rxjs": "5.4.3", + "patternfly": "3.28.3", + "rxjs": "5.5.0", "zone.js": "0.8.4" }, "dependencies": { @@ -7524,208 +6736,6 @@ } } }, - "patternfly": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.28.1.tgz", - "integrity": "sha1-UPt1s4SpebxIkQzZ53E36ENzhjs=", - "requires": { - "bootstrap": "3.3.7", - "bootstrap-datepicker": "1.6.4", - "bootstrap-select": "1.12.4", - "bootstrap-switch": "3.3.4", - "bootstrap-touchspin": "3.1.1", - "c3": "0.4.17", - "d3": "3.5.17", - "datatables.net": "1.10.15", - "datatables.net-colreorder": "1.3.3", - "datatables.net-colreorder-bs": "1.3.3", - "datatables.net-select": "1.2.2", - "drmonty-datatables-colvis": "1.1.2", - "eonasdan-bootstrap-datetimepicker": "4.17.47", - "font-awesome": "4.7.0", - "google-code-prettify": "1.0.5", - "jquery": "3.2.1", - "jquery-match-height": "0.7.2", - "moment": "2.14.1", - "moment-timezone": "0.4.1", - "patternfly-bootstrap-combobox": "1.1.7", - "patternfly-bootstrap-treeview": "2.1.5" - }, - "dependencies": { - "bootstrap": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz", - "integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E=" - }, - "bootstrap-datepicker": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.6.4.tgz", - "integrity": "sha1-iJ6+ztjqov8V7B8nPksHUxzEPaA=", - "optional": true, - "requires": { - "jquery": "3.2.1" - } - }, - "bootstrap-select": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.12.4.tgz", - "integrity": "sha1-fxXTwM6XiGjZwJxw+WYk9V+gLuE=", - "optional": true, - "requires": { - "jquery": "3.2.1" - } - }, - "bootstrap-switch": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/bootstrap-switch/-/bootstrap-switch-3.3.4.tgz", - "integrity": "sha1-cOCusqh3wNx2aZHeEI4hcPwpov8=", - "optional": true - }, - "bootstrap-touchspin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bootstrap-touchspin/-/bootstrap-touchspin-3.1.1.tgz", - "integrity": "sha1-l3nerHKq9Xfl52K4USx0fIcdlZc=", - "optional": true - }, - "c3": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.17.tgz", - "integrity": "sha512-41T3yS3jq1XgA7ruvV1wFVEK1E2az2iUAqS7hU5de62JVrjPyxWqIPu8AHlKpShZxJbD+DXLRkQHfOLASYyqyg==", - "optional": true, - "requires": { - "d3": "3.5.17" - } - }, - "d3": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=", - "optional": true - }, - "datatables.net": { - "version": "1.10.15", - "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.15.tgz", - "integrity": "sha1-x4kHe7/jhedf9aIz+l8jJRpy32g=", - "requires": { - "jquery": "3.2.1" - } - }, - "datatables.net-bs": { - "version": "1.10.15", - "resolved": "https://registry.npmjs.org/datatables.net-bs/-/datatables.net-bs-1.10.15.tgz", - "integrity": "sha1-ssImEAfYTKW1q/VsGO3CJ+DaGk0=", - "optional": true, - "requires": { - "datatables.net": "1.10.15", - "jquery": "3.2.1" - } - }, - "datatables.net-colreorder": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/datatables.net-colreorder/-/datatables.net-colreorder-1.3.3.tgz", - "integrity": "sha1-/HYuNQ+UIkyyzUXCuWImGg//73I=", - "optional": true, - "requires": { - "datatables.net": "1.10.15", - "jquery": "3.2.1" - } - }, - "datatables.net-colreorder-bs": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/datatables.net-colreorder-bs/-/datatables.net-colreorder-bs-1.3.3.tgz", - "integrity": "sha1-Op3LCN7r612FQHlZHgbkk615OlM=", - "optional": true, - "requires": { - "datatables.net-bs": "1.10.15", - "datatables.net-colreorder": "1.3.3", - "jquery": "3.2.1" - } - }, - "datatables.net-select": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/datatables.net-select/-/datatables.net-select-1.2.2.tgz", - "integrity": "sha1-llF5P1KJn05XRcByCCHouChvv0U=", - "optional": true, - "requires": { - "datatables.net": "1.10.15", - "jquery": "3.2.1" - } - }, - "drmonty-datatables-colvis": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/drmonty-datatables-colvis/-/drmonty-datatables-colvis-1.1.2.tgz", - "integrity": "sha1-lque37SGQ8wu3aP4e4iTPN7oEnw=", - "optional": true, - "requires": { - "jquery": "3.2.1" - } - }, - "eonasdan-bootstrap-datetimepicker": { - "version": "4.17.47", - "resolved": "https://registry.npmjs.org/eonasdan-bootstrap-datetimepicker/-/eonasdan-bootstrap-datetimepicker-4.17.47.tgz", - "integrity": "sha1-ekmXAEQGUnbnll79Fvgic1IZ5zU=", - "optional": true, - "requires": { - "bootstrap": "3.3.7", - "jquery": "3.2.1", - "moment": "2.14.1", - "moment-timezone": "0.4.1" - } - }, - "font-awesome": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", - "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" - }, - "google-code-prettify": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/google-code-prettify/-/google-code-prettify-1.0.5.tgz", - "integrity": "sha1-n0d/Ik2/piNy5e+AOn4VdBBAAIQ=", - "optional": true - }, - "jquery": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", - "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" - }, - "jquery-match-height": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/jquery-match-height/-/jquery-match-height-0.7.2.tgz", - "integrity": "sha1-+NnzulMU2qsQnPB0CGdL4gS+Xw4=", - "optional": true - }, - "moment": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz", - "integrity": "sha1-s1snxH5X7S3ccAU9awe+zbKRdBw=" - }, - "moment-timezone": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.4.1.tgz", - "integrity": "sha1-gfWYw61eIs2teWtn7NjYjQ9bqgY=", - "optional": true, - "requires": { - "moment": "2.14.1" - } - }, - "patternfly-bootstrap-combobox": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/patternfly-bootstrap-combobox/-/patternfly-bootstrap-combobox-1.1.7.tgz", - "integrity": "sha1-al48zRFwwhs8S0qhaKdBPh3btuE=", - "optional": true - }, - "patternfly-bootstrap-treeview": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/patternfly-bootstrap-treeview/-/patternfly-bootstrap-treeview-2.1.5.tgz", - "integrity": "sha1-TCnyWC+4ovKPCpKPLw0yTSHWmQ0=", - "optional": true, - "requires": { - "bootstrap": "3.3.7", - "jquery": "3.2.1" - } - } - } - }, "zone.js": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.4.tgz", @@ -8371,7 +7381,7 @@ "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", "dev": true, "requires": { - "@types/node": "6.0.89", + "@types/node": "6.0.90", "@types/q": "0.0.32", "@types/selenium-webdriver": "2.53.42", "blocking-proxy": "0.0.5", @@ -8987,9 +7997,9 @@ } }, "rxjs": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz", - "integrity": "sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.0.tgz", + "integrity": "sha512-vmvP5y/oJIJmXKHY36PIjVeI/46Sny6BMBa7/ou2zsNz1PiqU/Gtcz1GujnHz5Qlxncv+J9VlWmttnshqFj3Kg==", "requires": { "symbol-observable": "1.0.4" } @@ -9782,12 +8792,6 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -9815,6 +8819,12 @@ } } }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/ngapp/package.json b/ngapp/package.json index 7089f755..5c58e093 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -12,28 +12,29 @@ }, "private": true, "dependencies": { - "@angular/animations": "^4.4.5", - "@angular/common": "^4.4.5", - "@angular/compiler": "^4.4.5", - "@angular/core": "^4.4.5", - "@angular/forms": "^4.4.5", - "@angular/http": "^4.4.5", - "@angular/platform-browser": "^4.4.5", - "@angular/platform-browser-dynamic": "^4.4.5", - "@angular/router": "^4.4.5", + "@angular/animations": "^4.4.6", + "@angular/common": "^4.4.6", + "@angular/compiler": "^4.4.6", + "@angular/core": "^4.4.6", + "@angular/forms": "^4.4.6", + "@angular/http": "^4.4.6", + "@angular/platform-browser": "^4.4.6", + "@angular/platform-browser-dynamic": "^4.4.6", + "@angular/router": "^4.4.6", "core-js": "^2.4.1", "ngx-bootstrap": "^1.9.3", - "patternfly-ng": "^0.13.3", - "rxjs": "^5.4.2", + "patternfly": "^3.28.3", + "patternfly-ng": "^0.13.5", + "rxjs": "^5.5.0", "zone.js": "^0.8.14" }, "devDependencies": { "@angular/cli": "1.3.2", - "@angular/compiler-cli": "^4.4.5", - "@angular/language-service": "^4.4.5", + "@angular/compiler-cli": "^4.4.6", + "@angular/language-service": "^4.4.6", "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", - "@types/node": "^6.0.89", + "@types/node": "^6.0.90", "codelyzer": "~3.1.1", "jasmine-core": "~2.6.2", "jasmine-spec-reporter": "~4.1.0", diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts index b0f193d7..e2fd7475 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts @@ -1,12 +1,12 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import {FormGroup, FormsModule, ReactiveFormsModule} from "@angular/forms"; -import {RouterTestingModule} from "@angular/router/testing"; -import {CoreModule} from "@core/core.module"; -import {PropertyFormPropertyComponent} from "@shared/property-form/property-form-property/property-form-property.component"; -import {PropertyFormComponent} from "@shared/property-form/property-form.component"; -import {SharedModule} from "@shared/shared.module"; -import {PatternFlyNgModule, WizardConfig, WizardStepComponent} from "patternfly-ng"; +import { FormGroup, FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { RouterTestingModule } from "@angular/router/testing"; +import { CoreModule } from "@core/core.module"; +import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; +import { PropertyFormComponent } from "@shared/property-form/property-form.component"; +import { SharedModule } from "@shared/shared.module"; +import { PatternFlyNgModule, WizardConfig, WizardStepComponent } from "patternfly-ng"; import { AddConnectionWizardComponent } from "./add-connection-wizard.component"; describe("AddConnectionWizardComponent", () => { diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.html b/ngapp/src/app/connections/connections-list/connections-list.component.html index 5918a8d8..da8c3ca3 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.html +++ b/ngapp/src/app/connections/connections-list/connections-list.component.html @@ -32,7 +32,6 @@ -

    diff --git a/ngapp/src/app/connections/connections-routing.module.ts b/ngapp/src/app/connections/connections-routing.module.ts index 5b3092d9..2ad68d98 100644 --- a/ngapp/src/app/connections/connections-routing.module.ts +++ b/ngapp/src/app/connections/connections-routing.module.ts @@ -18,7 +18,7 @@ import { NgModule } from "@angular/core"; import { RouterModule } from "@angular/router"; import { Routes } from "@angular/router"; -import { AddConnectionComponent} from "@connections/add-connection/add-connection.component"; +import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; import { ConnectionsComponent } from "@connections/connections.component"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; diff --git a/ngapp/src/app/shared/property-form/property-form.component.ts b/ngapp/src/app/shared/property-form/property-form.component.ts index 6ebe5e22..4efed025 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.ts @@ -16,7 +16,7 @@ */ import { Component, Input, OnInit } from "@angular/core"; -import { Form, FormControl, FormGroup, Validators } from "@angular/forms"; +import { FormControl, FormGroup, Validators } from "@angular/forms"; import { ObjectUtils } from "@core/utils/object-utils"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; From 52665245e439c04b1b1ac4770225f226ac14985b Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 23 Oct 2017 12:14:35 -0500 Subject: [PATCH 026/205] Needed to update the patternfly css links to get the connection wizard to show --- .../add-connection-wizard/add-connection-wizard.component.ts | 2 -- ngapp/src/index.html | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index f8200bf1..b465492c 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -129,8 +129,6 @@ export class AddConnectionWizardComponent implements OnInit { loadingTitle: "Add Connection Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", title: "Add Connection", - sidebarStyleClass: "example-wizard-sidebar", - stepStyleClass: "example-wizard-step" } as WizardConfig; // Load the templates for the first step diff --git a/ngapp/src/index.html b/ngapp/src/index.html index 2d2765b9..1209d7aa 100644 --- a/ngapp/src/index.html +++ b/ngapp/src/index.html @@ -8,8 +8,8 @@ - - + + From 98580eaefc5085d9ae6b407e6ef34436d7f498b6 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 24 Oct 2017 15:45:30 -0500 Subject: [PATCH 027/205] Connections test seems to be using the mock service now. --- .../connections/connections.component.spec.ts | 61 ++++++++++--------- .../app/connections/connections.component.ts | 19 +++++- 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index 21904b7b..4175c1f9 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -19,21 +19,22 @@ describe("ConnectionsComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], - declarations: [ ConnectionsComponent, ConnectionsListComponent, ConnectionsCardsComponent ], - providers: [ - { provide: ConnectionService, useValue: MockConnectionService }, - ] - }) - .compileComponents().then(() => { - // Nothing + declarations: [ ConnectionsComponent, ConnectionsListComponent, ConnectionsCardsComponent ] + }); + + // use mock service + TestBed.overrideComponent( ConnectionsComponent, { + set: { + providers: [ + { provide: ConnectionService, useClass: MockConnectionService }, + ] + } }); - })); - beforeEach(() => { fixture = TestBed.createComponent(ConnectionsComponent); component = fixture.componentInstance; fixture.detectChanges(); - }); + })); it("should be created", () => { expect(component).toBeTruthy(); @@ -52,27 +53,27 @@ describe("ConnectionsComponent", () => { expect(de).toBeDefined(); }); - // it("should have Connections", () => { - // // Check component object - // const connections = component.allConnections; - // expect(connections.length).toEqual(3); - // - // // Check html has the same number of connection cards - // const cardDebugElems = fixture.debugElement.queryAll(By.css(".connection-card-title")); - // expect(cardDebugElems).toBeDefined(); - // expect(cardDebugElems.length).toEqual(3); - // }); + it("should have Connections", () => { + // Check component object + const connections = component.allConnections; + expect(connections.length).toEqual(3); - // it("should have initial card layout", () => { - // // app-connections-cards should be present - // let debugEl = fixture.debugElement.query(By.css("app-connections-cards")); - // const element = debugEl.nativeElement; - // expect(element).toBeDefined(); - // - // // app-connections-list should not be present - // debugEl = fixture.debugElement.query(By.css("app-connections-list")); - // expect(debugEl).toBeNull(); - // }); + // Check html has the same number of connection cards + const cardDebugElems = fixture.debugElement.queryAll(By.css(".connection-card-title")); + expect(cardDebugElems).toBeDefined(); + expect(cardDebugElems.length).toEqual(3); + }); + + it("should have initial card layout", () => { + // app-connections-cards should be present + let debugEl = fixture.debugElement.query(By.css("app-connections-cards")); + const element = debugEl.nativeElement; + expect(element).toBeDefined(); + + // app-connections-list should not be present + debugEl = fixture.debugElement.query(By.css("app-connections-list")); + expect(debugEl).toBeNull(); + }); // it("should toggle layout", () => { // // Initial layout should be Card Layout diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 077c9c6a..33ef5692 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -221,10 +221,25 @@ export class ConnectionsComponent extends AbstractPageComponent { } } this.filteredConns.sort( (c1: Connection, c2: Connection) => { - let rval: number = c1.getId().localeCompare(c2.getId()); - if (this.sortDirection === SortDirection.DESC) { + let rval = 0; + + if ( c1.getId() ) { + if ( c2.getId() ) { + // both connections have an ID + rval = c1.getId().localeCompare( c2.getId() ); + } else { + // c2 does not have an ID + rval = 1; + } + } else if ( c2.getId() ) { + // c1 does not have an ID and c2 does + rval = -1; + } + + if ( this.sortDirection === SortDirection.DESC ) { rval *= -1; } + return rval; }); From 6aaca0ab38a3de0770cd9c885086e25845f325d8 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Wed, 25 Oct 2017 16:50:57 -0500 Subject: [PATCH 028/205] - created an enum for a property definition control type - moved the getControlType() function from the property definition model into the PropertyControlType enum - changed html switch to use the enum --- .../property-control-type.enum.ts | 74 +++++++++++++++++++ .../property-definition.model.ts | 18 ----- .../property-form-property.component.html | 10 +-- .../property-form-property.component.ts | 3 + ngapp/tslint.json | 1 + 5 files changed, 83 insertions(+), 23 deletions(-) create mode 100644 ngapp/src/app/shared/property-form/property-control-type.enum.ts diff --git a/ngapp/src/app/shared/property-form/property-control-type.enum.ts b/ngapp/src/app/shared/property-form/property-control-type.enum.ts new file mode 100644 index 00000000..f3f9c1a4 --- /dev/null +++ b/ngapp/src/app/shared/property-form/property-control-type.enum.ts @@ -0,0 +1,74 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PropertyDefinition } from "@shared/property-form/property-definition.model"; + +/** + * An enumeration of control types for a property. + */ + +export enum PropertyControlType { + + /** + * Render the property as a checkbox. + */ + CHECKBOX, + + /** + * Render the property as a dropdown. + */ + DROPDOWN, + + /** + * Render the property as a masked textbox. + */ + PASSWORD, + + /** + * Render the property as a textbox. + */ + TEXT + +} + +/** + * Namespace to allow methods on the enum. + */ +export namespace PropertyControlType { + + /** + * @param {PropertyDefinition} propDefn the property whose control type is being requested + * @returns {PropertyControlType} the control type to render the property value + */ + export function toControlType( propDefn: PropertyDefinition< any > ): PropertyControlType { + if ( propDefn.isConstrainedToAllowedValues() ) { + return PropertyControlType.DROPDOWN; + } + + if ( propDefn.getTypeClassName() === "java.lang.Boolean" ) { + return PropertyControlType.CHECKBOX; + } + + if ( propDefn.isMasked() || propDefn.getId() === "password" ) { + return PropertyControlType.PASSWORD; + } + + // defaults to a text control + return PropertyControlType.TEXT; + } + +} diff --git a/ngapp/src/app/shared/property-form/property-definition.model.ts b/ngapp/src/app/shared/property-form/property-definition.model.ts index 011cce13..60c8bf55 100644 --- a/ngapp/src/app/shared/property-form/property-definition.model.ts +++ b/ngapp/src/app/shared/property-form/property-definition.model.ts @@ -94,24 +94,6 @@ export class PropertyDefinition { return this.typeClassName; } - /** - * @returns {string} the type of control for this property definition - */ - public getControlType(): string { - const className = this.getTypeClassName(); - if (this.isConstrainedToAllowedValues()) { - return "dropdown"; - } else if (className === "java.lang.String") { - if (this.isMasked() || this.getId() === "password") { - return "maskedTextbox"; - } - return "textbox"; - } else if (className === "java.lang.Boolean") { - return "checkbox"; - } - return "textbox"; - } - /** * @returns {boolean} 'true' if required */ diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html index 96702d1d..6bf149fb 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html @@ -1,18 +1,18 @@
    -
    +
    - - - - diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts index b3a9fda1..5fdcc192 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts @@ -19,6 +19,7 @@ import { Component, Input } from "@angular/core"; import { AbstractControl, FormGroup } from "@angular/forms"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; +import { PropertyControlType } from "@shared/property-form/property-control-type.enum"; @Component({ selector: "app-form-property", @@ -27,6 +28,8 @@ import { PropertyDefinition } from "@shared/property-form/property-definition.mo export class PropertyFormPropertyComponent { + public controlType = PropertyControlType; // need local ref of enum for html to use + @Input() public property: PropertyDefinition; @Input() public form: FormGroup; diff --git a/ngapp/tslint.json b/ngapp/tslint.json index 2845ac89..b9fedaaa 100644 --- a/ngapp/tslint.json +++ b/ngapp/tslint.json @@ -91,6 +91,7 @@ "ignore-params" ], "no-misused-new": true, + "no-namespace": false, "no-non-null-assertion": true, "no-parameter-properties": true, "no-shadowed-variable": true, From 2b6576b7119653865ca099ade9be5c9081b0c1ac Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 26 Oct 2017 13:57:31 -0500 Subject: [PATCH 029/205] Updates to property form and wizard --- .../activities/activities.component.spec.ts | 22 +++--- .../add-connection-wizard.component.html | 9 +-- .../add-connection-wizard.component.ts | 61 ++++++++++++---- .../connections/connections.component.spec.ts | 72 +++++++++---------- .../shared/mock-connection.service.ts | 3 + .../property-form-property.component.html | 8 +-- .../property-form/property-form.component.ts | 13 +++- 7 files changed, 117 insertions(+), 71 deletions(-) diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts index a221e422..9059e043 100644 --- a/ngapp/src/app/activities/activities.component.spec.ts +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -19,21 +19,23 @@ describe("ActivitiesComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule], - declarations: [ActivitiesComponent, ActivitiesListComponent, ActivitiesCardsComponent], - providers: [ - {provide: ActivityService, useClass: MockActivityService} - ] - }) - .compileComponents().then(() => { - // nothing to do + declarations: [ActivitiesComponent, ActivitiesListComponent, ActivitiesCardsComponent] + }); + + // use mock service + TestBed.overrideComponent( ActivitiesComponent, { + set: { + providers: [ + { provide: ActivityService, useClass: MockActivityService }, + ] + } }); - })); - beforeEach(() => { fixture = TestBed.createComponent(ActivitiesComponent); component = fixture.componentInstance; fixture.detectChanges(); - }); + + })); it("should be created", () => { expect(component).toBeTruthy(); diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html index 5a0e72d6..c24c7270 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html @@ -14,7 +14,7 @@

    {{ step1InstructionMessage }}

    -
    +
    {{ getBasicPropertyErrorMessage("name") }}
    -
    +
    {{ getBasicPropertyErrorMessage("jndi") }}
    @@ -48,7 +48,8 @@

    {{ step2InstructionMessage }}

    - +
    diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index b465492c..f9ee9d02 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -53,6 +53,7 @@ export class AddConnectionWizardComponent implements OnInit { public createComplete = true; public createSuccessful = false; public detailPropertiesLoaded = false; + public detailPropertiesLoadedType = ""; public requiredPropValues: Array<[string, string]> = []; public templatesLoaded = false; @@ -106,7 +107,7 @@ export class AddConnectionWizardComponent implements OnInit { // Step 3 - Review and Create this.step3Config = { id: "step3", - priority: 2, + priority: 0, title: "Review and Create", allowClickNav: false } as WizardStepConfig; @@ -129,6 +130,7 @@ export class AddConnectionWizardComponent implements OnInit { loadingTitle: "Add Connection Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", title: "Add Connection", + contentHeight: "500px" } as WizardConfig; // Load the templates for the first step @@ -151,7 +153,6 @@ export class AddConnectionWizardComponent implements OnInit { // ---------------- // Public Methods // ---------------- - /* * Return the name valid state */ @@ -230,7 +231,10 @@ export class AddConnectionWizardComponent implements OnInit { public nextClicked($event: WizardEvent): void { // When leaving page 1, load the driver-specific property definitions if ($event.step.config.id === "step1") { - this.loadPropertyDefinitions(this.basicPropertyForm.controls["driver"].value); + const selectedDriver = this.basicPropertyForm.controls["driver"].value; + if(!this.detailPropertiesLoaded || (this.detailPropertiesLoadedType!==selectedDriver)) { + this.loadPropertyDefinitions(selectedDriver); + } } } @@ -299,9 +303,20 @@ export class AddConnectionWizardComponent implements OnInit { } } - public updatePage1ValidStatus( ): void { - this.step1Config.nextEnabled = this.basicPropertyForm.valid; - this.setNavAway(this.step1Config.nextEnabled); + /** + * Handler for property form initialization + * @param {boolean} isValid form valid state + */ + public onDetailPropertyInit(isValid: boolean): void { + this.updatePage2ValidStatus(isValid); + } + + /** + * Handler for property form changes + * @param {boolean} isValid form valid state + */ + public onDetailPropertyChanged(isValid: boolean): void { + this.updatePage2ValidStatus(isValid); } /** @@ -345,13 +360,7 @@ export class AddConnectionWizardComponent implements OnInit { jndi: new FormControl("", Validators.required), driver: new FormControl("", Validators.required) }); - this.onChanges(); - } - - /* - * React to basic property changes - update the page 1 status - */ - private onChanges(): void { + // Responds to basic property changes - updates the page status this.basicPropertyForm.valueChanges.subscribe((val) => { this.updatePage1ValidStatus( ); }); @@ -361,6 +370,16 @@ export class AddConnectionWizardComponent implements OnInit { this.step1Config.allowNavAway = allow; } + private updatePage1ValidStatus( ): void { + this.step1Config.nextEnabled = this.basicPropertyForm.valid; + this.setNavAway(this.step1Config.nextEnabled); + } + + private updatePage2ValidStatus(formValid: boolean): void { + this.step2Config.nextEnabled = formValid; + this.setNavAway(this.step2Config.nextEnabled); + } + /** * Load the driver-specific property definitions */ @@ -371,8 +390,22 @@ export class AddConnectionWizardComponent implements OnInit { .getConnectionTemplateProperties(driverName) .subscribe( (props) => { - that.detailProperties = props; + // Sort the properties. (Required properties first) + const firstProps: any[] = []; + const nextProps: any[] = []; + let sortedProps: any[] = []; + for (const prop of props) { + if (prop.isRequired()) { + firstProps.push(prop); + } else { + nextProps.push(prop); + } + } + sortedProps = firstProps.concat(nextProps); + + that.detailProperties = sortedProps; this.detailPropertiesLoaded = true; + this.detailPropertiesLoadedType = driverName; }, (error) => { this.logger.error("[AddConnectionWizardComponent] Error: %o", error); diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index 4175c1f9..757dfb21 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -75,41 +75,41 @@ describe("ConnectionsComponent", () => { expect(debugEl).toBeNull(); }); - // it("should toggle layout", () => { - // // Initial layout should be Card Layout - // let cardDebugElem = fixture.debugElement.query(By.css("app-connections-cards")); - // let listDebugElem = fixture.debugElement.query(By.css("app-connections-list")); - // expect(cardDebugElem).toBeDefined(); - // expect(listDebugElem).toBeNull(); - // const cardElem = cardDebugElem.nativeElement; - // expect(cardElem).toBeDefined(); - // - // // Change the layout to ListLayout - // component.setListLayout(); - // fixture.detectChanges(); - // - // // Verify that the layout has changed - // cardDebugElem = fixture.debugElement.query(By.css("app-connections-cards")); - // listDebugElem = fixture.debugElement.query(By.css("app-connections-list")); - // expect(cardDebugElem).toBeNull(); - // expect(listDebugElem).toBeDefined(); - // const listElem = listDebugElem.nativeElement; - // expect(listElem).toBeDefined(); - // }); - - // it("should filter connections", () => { - // // Expect 3 connections initially. - // let connections = component.filteredConnections; - // expect(connections.length).toEqual(3); - // - // // Set a name filter which satisfies none of the connections - // component.nameFilter = "g"; - // component.filterConnections(); - // fixture.detectChanges(); - // - // // Now expect 0 activities match - // connections = component.filteredConnections; - // expect(connections.length).toEqual(0); - // }); + it("should toggle layout", () => { + // Initial layout should be Card Layout + let cardDebugElem = fixture.debugElement.query(By.css("app-connections-cards")); + let listDebugElem = fixture.debugElement.query(By.css("app-connections-list")); + expect(cardDebugElem).toBeDefined(); + expect(listDebugElem).toBeNull(); + const cardElem = cardDebugElem.nativeElement; + expect(cardElem).toBeDefined(); + + // Change the layout to ListLayout + component.setListLayout(); + fixture.detectChanges(); + + // Verify that the layout has changed + cardDebugElem = fixture.debugElement.query(By.css("app-connections-cards")); + listDebugElem = fixture.debugElement.query(By.css("app-connections-list")); + expect(cardDebugElem).toBeNull(); + expect(listDebugElem).toBeDefined(); + const listElem = listDebugElem.nativeElement; + expect(listElem).toBeDefined(); + }); + + it("should filter connections", () => { + // Expect 3 connections initially. + let connections = component.filteredConnections; + expect(connections.length).toEqual(3); + + // Set a name filter which satisfies none of the connections + component.nameFilter = "g"; + component.filterConnections(); + fixture.detectChanges(); + + // Now expect 0 activities match + connections = component.filteredConnections; + expect(connections.length).toEqual(0); + }); }); diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 78c64994..e4354b84 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -26,6 +26,9 @@ export class MockConnectionService extends ConnectionService { constructor( http: Http, logger: LoggerService ) { super(http, logger); + this.conn1.setId("conn1"); + this.conn2.setId("conn2"); + this.conn3.setId("conn3"); } /** diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html index 6bf149fb..cecad09e 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html @@ -1,16 +1,16 @@
    -
    +
    + [id]="property.getId()" type="text" title="A text value" [(ngModel)]="property.theDefaultValue"> + [id]="property.getId()" type="password" title="A text value" [(ngModel)]="property.theDefaultValue"> + [id]="property.getId()" type="checkbox" title="A boolean value" [(ngModel)]="property.theDefaultValue"> +
    {{ getBasicPropertyErrorMessage("name") }}
    +
    +
    +
    + +
    + +
    {{ getBasicPropertyErrorMessage("sourceConnection") }}
    +
    +
    +
    + +
    + +
    {{ getBasicPropertyErrorMessage("targetConnection") }}
    +
    +
    + + + + + + + + +

    {{ step2InstructionMessage }}

    +

    Activity Properties:

    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    + +
    +
    +

    Creation in progress

    +

    The activity is being created.

    +
    + +
    +
    +

    Creation was successful

    +

    The activity was created successfully. Click on the button to see all activities.

    + View All Activities +
    + +
    +
    +

    Creation failed

    +

    The activity creation failed. Correct any properties and retry.

    +
    +
    +
    +
    + diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts new file mode 100644 index 00000000..d12f238e --- /dev/null +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts @@ -0,0 +1,39 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { RouterTestingModule } from "@angular/router/testing"; +import { ActivityService } from "@activities/shared/activity.service"; +import { MockActivityService } from "@activities/shared/mock-activity.service"; +import { CoreModule } from "@core/core.module"; +import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; +import { PropertyFormComponent } from "@shared/property-form/property-form.component"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { AddActivityWizardComponent } from "./add-activity-wizard.component"; + +describe("AddActivityWizardComponent", () => { + let component: AddActivityWizardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], + declarations: [ AddActivityWizardComponent, PropertyFormComponent, PropertyFormPropertyComponent ], + providers: [ + { provide: ActivityService, useClass: MockActivityService }, + ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddActivityWizardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts new file mode 100644 index 00000000..715d09f0 --- /dev/null +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts @@ -0,0 +1,325 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Component, + OnInit, + ViewChild, + ViewEncapsulation, +} from "@angular/core"; + +import { FormControl, FormGroup } from "@angular/forms"; +import { AbstractControl } from "@angular/forms"; +import { Validators } from "@angular/forms"; +import { Router } from "@angular/router"; +import { ActivityService } from "@activities/shared/activity.service"; +import { ActivitiesConstants } from "@activities/shared/activities-constants"; +import { NewActivity } from "@activities/shared/new-activity.model"; +import { LoggerService } from "@core/logger.service"; +import { WizardComponent } from "patternfly-ng"; +import { WizardEvent } from "patternfly-ng"; +import { WizardStepConfig } from "patternfly-ng"; +import { WizardConfig } from "patternfly-ng"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { Connection } from "@connections/shared/connection.model"; +import {NewConnection} from "@connections/shared/new-connection.model"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-add-activity-wizard", + templateUrl: "./add-activity-wizard.component.html" +}) +export class AddActivityWizardComponent implements OnInit { + public readonly activitySummaryLink: string = ActivitiesConstants.activitiesRootPath; + + // Wizard Config + public wizardConfig: WizardConfig; + + public basicPropertyForm: FormGroup; + public createComplete = true; + public createSuccessful = false; + public connectionsLoaded = false; + + // Wizard Step 1 + public step1Config: WizardStepConfig; + + // Wizard Step 2 + public step2Config: WizardStepConfig; + public step2aConfig: WizardStepConfig; + public step2bConfig: WizardStepConfig; + + @ViewChild("wizard") public wizard: WizardComponent; + + private activityService: ActivityService; + private connectionService: ConnectionService; + private allConnections: Connection[] = []; + private logger: LoggerService; + private router: Router; + + constructor( router: Router, activityService: ActivityService, connectionService: ConnectionService, logger: LoggerService ) { + this.activityService = activityService; + this.connectionService = connectionService; + this.router = router; + this.logger = logger; + this.createBasicPropertyForm(); + } + + /* + * Initialization + */ + public ngOnInit(): void { + // Step 1 - Basic Properties + this.step1Config = { + id: "step1", + priority: 0, + title: "Basic Properties", + allowClickNav: false + } as WizardStepConfig; + + // Step 2 - Review and Create + this.step2Config = { + id: "step2", + priority: 2, + title: "Review and Create", + allowClickNav: false + } as WizardStepConfig; + this.step2aConfig = { + id: "step2a", + priority: 0, + title: "Review", + allowClickNav: false + } as WizardStepConfig; + this.step2bConfig = { + id: "step2b", + priority: 1, + title: "Create", + allowClickNav: false + } as WizardStepConfig; + + // Wizard Configuration + this.wizardConfig = { + embedInPage: true, + loadingTitle: "Add Activity Wizard loading", + loadingSecondaryInfo: "Please wait for the wizard to finish loading...", + title: "Add Activity", + contentHeight: "500px" + } as WizardConfig; + + // Load the connections for the first step + this.connectionsLoaded = false; + this.connectionService + .getAllConnections() + .subscribe( + (conns) => { + this.allConnections = conns; + this.connectionsLoaded = true; + }, + (error) => { + this.logger.error("[AddActivityWizardComponent] Error getting connections: %o", error); + } + ); + + this.setNavAway(false); + } + + // ---------------- + // Public Methods + // ---------------- + + /* + * Return the name valid state + */ + public get nameValid(): boolean { + return this.basicPropertyForm.controls["name"].valid; + } + + /* + * Return the source connection valid state + */ + public get sourceConnectionValid(): boolean { + return this.basicPropertyForm.controls["sourceConnection"].valid; + } + + /* + * Return the target connection valid state + */ + public get targetConnectionValid(): boolean { + return this.basicPropertyForm.controls["targetConnection"].valid; + } + + /* + * Step 1 instruction message + */ + public get step1InstructionMessage(): string { + if (!this.nameValid) { + return "Please enter a name for the Activity"; + } else if (!this.sourceConnectionValid) { + return "Please choose a source connection for the Activity"; + } else if (!this.targetConnectionValid) { + return "Please choose a target connection for the Activity"; + } else { + return "When finished entering properties, click Next to continue"; + } + } + + /* + * Step 2 instruction message + */ + public get step2InstructionMessage(): string { + return "Review your entries. When finished, click Create to create the Activity"; + } + + /* + * Return the name error message if invalid + */ + public getBasicPropertyErrorMessage( name: string ): string { + const control: AbstractControl = this.basicPropertyForm.controls[name]; + if (control.invalid) { + // The first error found is returned + if (control.errors.required) { + return name + " is a required property"; + } + } + return ""; + } + + public nextClicked($event: WizardEvent): void { + // Nothing to do + } + + public cancelClicked($event: WizardEvent): void { + const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; + this.logger.log("[AddActivityWizardComponent] Navigating to: %o", link); + this.router.navigate(link).then(() => { + // nothing to do + }); + } + + /* + * Create the Activity via komodo REST interface, + * using the currently entered properties + */ + public createActivity(): void { + this.createComplete = false; + this.wizardConfig.done = true; + + const activity: NewActivity = new NewActivity(); + + // Activity basic properties from step 1 + activity.setName(this.activityName); + let srcConn: NewConnection = new NewConnection(); + srcConn.setName(this.sourceConnectionName); + activity.setSourceConnection(srcConn); + let tgtConn: NewConnection = new NewConnection(); + tgtConn.setName(this.targetConnectionName); + activity.setTargetConnection(tgtConn); + + this.activityService + .createActivity(activity) + .subscribe( + () => { + this.createComplete = true; + this.createSuccessful = true; + this.step2bConfig.nextEnabled = false; + }, + (error) => { + this.createComplete = true; + this.createSuccessful = false; + } + ); + } + + public stepChanged($event: WizardEvent): void { + if ($event.step.config.id === "step1") { + this.updatePage1ValidStatus(); + } else if ($event.step.config.id === "step2a") { + this.wizardConfig.nextTitle = "Create"; + } else if ($event.step.config.id === "step2b") { + // Note: The next button is not disabled by default when wizard is done + this.step2Config.nextEnabled = false; + } else { + this.wizardConfig.nextTitle = "Next >"; + } + } + + public updatePage1ValidStatus( ): void { + this.step1Config.nextEnabled = this.basicPropertyForm.valid; + this.setNavAway(this.step1Config.nextEnabled); + } + + /** + * @returns {string} the name of the activity + */ + public get activityName(): string { + return this.basicPropertyForm.controls["name"].value; + } + + /** + * @returns {string} the source connection name of the activity + */ + public get sourceConnectionName(): string { + return this.basicPropertyForm.controls["sourceConnection"].value; + } + + /** + * @returns {string} the target connection name of the activity + */ + public get targetConnectionName(): string { + return this.basicPropertyForm.controls["targetConnection"].value; + } + + /* + * Return the array of connection names + */ + public get connectionNames(): string[] { + const connNames: string[] = []; + for ( const conn of this.allConnections ) { + connNames.push(conn.getId()); + } + return connNames.sort(); + } + + // ---------------- + // Private Methods + // ---------------- + + /* + * Create the BasicProperty form (page 1) + */ + private createBasicPropertyForm(): void { + this.basicPropertyForm = new FormGroup({ + name: new FormControl("", Validators.required), + sourceConnection: new FormControl("", Validators.required), + targetConnection: new FormControl("", Validators.required), + }); + this.onChanges(); + } + + /* + * React to basic property changes - update the page 1 status + */ + private onChanges(): void { + this.basicPropertyForm.valueChanges.subscribe((val) => { + this.updatePage1ValidStatus( ); + }); + } + + private setNavAway(allow: boolean): void { + this.step1Config.allowNavAway = allow; + } + +} diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.css b/ngapp/src/app/activities/add-activity/add-activity.component.css index fb12bd19..e69de29b 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.css +++ b/ngapp/src/app/activities/add-activity/add-activity.component.css @@ -1,12 +0,0 @@ -.add-activity-form { - padding: 15px -} - -.add-activity-form /*.form-instructions*/ { - font-size: 15px; - padding-top: 10px -} - -.add-activity-form .form-instructions ol { - padding-left: 20px; -} diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.html b/ngapp/src/app/activities/add-activity/add-activity.component.html index 97bb9a49..c65310ee 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.html +++ b/ngapp/src/app/activities/add-activity/add-activity.component.html @@ -1,16 +1,19 @@
    -
  • -
  • +
  • +
  • -

    Add Activity

    +

    -
    - + +
    +
    + + diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 9d6a6f0b..f401f4b9 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -1,12 +1,12 @@ -import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; -import { ActivityService } from "@activities/shared/activity.service"; -import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; -import { MockActivityService } from "@activities/shared/mock-activity.service"; import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { FormsModule } from "@angular/forms"; -import { HttpModule } from "@angular/http"; + +import { ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; +import { AddActivityWizardComponent } from "@activities/add-activity-wizard/add-activity-wizard.component"; import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { AddActivityComponent } from "./add-activity.component"; describe("AddActivityComponent", () => { let component: AddActivityComponent; @@ -14,13 +14,10 @@ describe("AddActivityComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, HttpModule, RouterTestingModule ], - declarations: [ AddActivityComponent, AddActivityFormComponent ], - providers: [ - { provide: ActivityService, useClass: MockActivityService }, - ] + imports: [ CoreModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], + declarations: [ AddActivityComponent, AddActivityWizardComponent ] }) - .compileComponents().then(() => { + .compileComponents().then(() => { // nothing to do }); })); @@ -31,7 +28,8 @@ describe("AddActivityComponent", () => { fixture.detectChanges(); }); - it("should be created", () => { - expect(component).toBeTruthy(); - }); + // TODO: Figure out how to setup this test. + // it("should be created", () => { + // expect(component).toBeTruthy(); + // }); }); diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.ts b/ngapp/src/app/activities/add-activity/add-activity.component.ts index ac48be27..08e915ff 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.ts @@ -15,51 +15,26 @@ * limitations under the License. */ +import { Component, OnInit } from "@angular/core"; import { ActivitiesConstants } from "@activities/shared/activities-constants"; -import { ActivityService } from "@activities/shared/activity.service"; -import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; -import { NewActivity } from "@activities/shared/new-activity.model"; -import { Component } from "@angular/core"; -import { ViewChild } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { Router } from "@angular/router"; -import { LoggerService } from "@core/logger.service"; -import { AbstractPageComponent } from "@shared/abstract-page.component"; @Component({ - moduleId: module.id, - selector: "app-add-activity", + selector: "app-add-activity-page", templateUrl: "./add-activity.component.html", styleUrls: ["./add-activity.component.css"] }) -export class AddActivityComponent extends AbstractPageComponent { +export class AddActivityComponent implements OnInit { public readonly activitiesLink = ActivitiesConstants.activitiesRootPath; - private router: Router; - private activityService: ActivityService; + public pageError: any = ""; - @ViewChild(AddActivityFormComponent) private form: AddActivityFormComponent; - - constructor(router: Router, route: ActivatedRoute, activityService: ActivityService, logger: LoggerService ) { - super(route, logger); - this.router = router; - this.activityService = activityService; + constructor() { + // Nothing } - /** - * Called when the Add Activity form (component) emits a "add-activity" event. This is bound to - * from the add-activity.page.html template. - * @param {NewActivity} activity - */ - public onCreateActivity(activity: NewActivity): void { - this.logger.log("[AddActivityComponent] onCreateActivity(): " + JSON.stringify(activity)); - this.activityService.createActivity(activity); - const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; - this.logger.log("[AddActivityComponent] Navigating to: %o", link); - this.router.navigate(link).then(() => { - // nothing to do - }); + public ngOnInit(): void { + // Nothing } } diff --git a/ngapp/src/app/activities/shared/activity.service.ts b/ngapp/src/app/activities/shared/activity.service.ts index c0ab89f5..41196549 100644 --- a/ngapp/src/app/activities/shared/activity.service.ts +++ b/ngapp/src/app/activities/shared/activity.service.ts @@ -19,53 +19,29 @@ import { Activity } from "@activities/shared/activity.model"; import { NewActivity } from "@activities/shared/new-activity.model"; import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; -import { NewConnection } from "@connections/shared/new-connection.model"; import { ApiService } from "@core/api.service"; import { LoggerService } from "@core/logger.service"; +import { Observable } from "rxjs/Observable"; @Injectable() export class ActivityService extends ApiService { - private activity1 = new Activity(); - private activity2 = new Activity(); - private activity3 = new Activity(); - private activities: Activity[] = [this.activity1, this.activity2, this.activity3]; - private newActivity1 = new NewActivity(); private http: Http; constructor( http: Http, logger: LoggerService ) { super( logger ); this.http = http; - this.activity1.setId("activity1"); - this.activity1.setSourceConnection("activity1SrcConn"); - this.activity1.setTargetConnection("activity1TgtConn"); - this.activity2.setId("activity2"); - this.activity2.setSourceConnection("activity2SrcConn"); - this.activity2.setTargetConnection("activity2TgtConn"); - this.activity3.setId("activity3"); - this.activity3.setSourceConnection("activity3SrcConn"); - this.activity3.setTargetConnection("activity3TgtConn"); - this.newActivity1.setName("newActivity1"); - const srcConn = new NewConnection(); - srcConn.setName("new1Src"); - srcConn.setJndiName("new1SrcJndi"); - srcConn.setDriverName("new1SrcDriver"); - srcConn.setJdbc(true); - this.newActivity1.setSourceConnection(srcConn); - const tgtConn = new NewConnection(); - tgtConn.setName("new1Tgt"); - tgtConn.setJndiName("new1TgtJndi"); - tgtConn.setDriverName("new1TgtDriver"); - tgtConn.setJdbc(false); - this.newActivity1.setTargetConnection(tgtConn); } /** * Get the activities from the komodo rest interface * @returns {Activity[]} */ - public getAllActivities(): Activity[] { - return this.activities; + public getAllActivities(): Observable { + let activities = JSON.parse(localStorage.getItem('activities')); + + if (!activities) activities = []; + return Observable.of(this.convertObjectArray(activities)); /* return this.http .get(komodoWorkspaceUrl + '/activities', this.getAuthRequestOptions()) @@ -82,9 +58,19 @@ export class ActivityService extends ApiService { * @param {NewActivity} activity * @returns {Activity} */ - public createActivity(activity: NewActivity): NewActivity { + public createActivity(activity: NewActivity): Observable { + let act = new Activity(); + act.setId(activity.getName()); + act.setSourceConnection(activity.getSourceConnection().getName()); + act.setTargetConnection(activity.getTargetConnection().getName()); + + let activities = JSON.parse(localStorage.getItem('activities')); + if (!activities) activities = []; + activities.push(act); + localStorage.setItem('activities', JSON.stringify(activities)); + // TODO implement createActivity() - return this.newActivity1; + return Observable.of(activity); /* return this.http .post(komodoWorkspaceUrl + '/activities/' + activity.name, activity, this.getAuthRequestOptions()) @@ -99,7 +85,15 @@ export class ActivityService extends ApiService { * Delete an activity via the komodo rest interface * @param {NewActivity} activity */ - public deleteActivity(activity: NewActivity): NewActivity { + public deleteActivity(activity: NewActivity): Observable { + let activities = JSON.parse(localStorage.getItem('activities')); + if (!activities) activities = []; + + let indexOfDeleted = activities.findIndex(i => i.keng__id === activity.getName()); + activities.splice(indexOfDeleted,1); + + localStorage.setItem('activities', JSON.stringify(activities)); + // TODO implement deleteActivity() /* return this.http @@ -107,7 +101,25 @@ export class ActivityService extends ApiService { .map(response => null) .catch(this.handleError); */ - return null; + return Observable.of(null); } + /* + * TODO: Remove after komodo REST is available + * This is a helper method to convert Object array to Activity array. + * This can be removed once we connect to the komodo rest service + */ + private convertObjectArray(objArray: [any]): Activity[] { + let activityArray = []; + + for (const obj of objArray) { + let act: Activity = new Activity(); + act.setId(obj.keng__id); + act.setSourceConnection(obj.dv__sourceConnection); + act.setTargetConnection(obj.dv__targetConnection); + activityArray.push(act); + } + + return activityArray; + } } diff --git a/ngapp/src/app/activities/shared/mock-activity.service.ts b/ngapp/src/app/activities/shared/mock-activity.service.ts index f24b47bf..15bc2ae0 100644 --- a/ngapp/src/app/activities/shared/mock-activity.service.ts +++ b/ngapp/src/app/activities/shared/mock-activity.service.ts @@ -3,13 +3,13 @@ import { ActivityService } from "@activities/shared/activity.service"; import { NewActivity } from "@activities/shared/new-activity.model"; import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; -import { Connection } from "@connections/shared/connection.model"; import { NewConnection } from "@connections/shared/new-connection.model"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; +import {Observable} from "rxjs/Observable"; @Injectable() export class MockActivityService extends ActivityService { @@ -20,12 +20,6 @@ export class MockActivityService extends ActivityService { private acts: Activity[] = [this.act1, this.act2, this.act3]; private newAct1 = new NewActivity(); - private newConnection = new NewConnection(); - private conn1 = new Connection(); - private conn2 = new Connection(); - private conn3 = new Connection(); - private conns: Connection[] = [this.conn1, this.conn2, this.conn3]; - constructor( http: Http, logger: LoggerService ) { super(http, logger); this.act1.setId("activity1"); @@ -57,8 +51,8 @@ export class MockActivityService extends ActivityService { * Get the activities from the komodo rest interface * @returns {Activity[]} */ - public getAllActivities(): Activity[] { - return this.acts; + public getAllActivities(): Observable { + return Observable.of(this.acts); } /** @@ -66,16 +60,16 @@ export class MockActivityService extends ActivityService { * @param {NewActivity} activity * @returns {Activity} */ - public createActivity(activity: NewActivity): NewActivity { - return this.newAct1; + public createActivity(activity: NewActivity): Observable { + return Observable.of(this.newAct1); } /** * Delete an activity via the komodo rest interface * @param {NewActivity} activity */ - public deleteActivity(activity: NewActivity): NewActivity { - return null; + public deleteActivity(activity: NewActivity): Observable { + return Observable.of(null); } } diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index f9ee9d02..35d689cb 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -393,7 +393,6 @@ export class AddConnectionWizardComponent implements OnInit { // Sort the properties. (Required properties first) const firstProps: any[] = []; const nextProps: any[] = []; - let sortedProps: any[] = []; for (const prop of props) { if (prop.isRequired()) { firstProps.push(prop); @@ -401,9 +400,8 @@ export class AddConnectionWizardComponent implements OnInit { nextProps.push(prop); } } - sortedProps = firstProps.concat(nextProps); - that.detailProperties = sortedProps; + that.detailProperties = firstProps.concat(nextProps); this.detailPropertiesLoaded = true; this.detailPropertiesLoadedType = driverName; }, diff --git a/ngapp/src/app/shared/property-form/property-form.component.ts b/ngapp/src/app/shared/property-form/property-form.component.ts index 76bd57a9..955099a2 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.ts @@ -17,7 +17,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { FormControl, FormGroup, Validators } from "@angular/forms"; -import { Observable } from "rxjs/Observable"; import { ObjectUtils } from "@core/utils/object-utils"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; From 30771081c662005c66ceb9e36f0fedd603df2bb5 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 27 Oct 2017 15:52:58 -0500 Subject: [PATCH 031/205] fixes unit test --- .../add-activity-wizard/add-activity-wizard.component.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts index d12f238e..af53d5d3 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts @@ -9,6 +9,8 @@ import { PropertyFormPropertyComponent } from "@shared/property-form/property-fo import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddActivityWizardComponent } from "./add-activity-wizard.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; describe("AddActivityWizardComponent", () => { let component: AddActivityWizardComponent; @@ -20,6 +22,7 @@ describe("AddActivityWizardComponent", () => { declarations: [ AddActivityWizardComponent, PropertyFormComponent, PropertyFormPropertyComponent ], providers: [ { provide: ActivityService, useClass: MockActivityService }, + { provide: ConnectionService, useClass: MockConnectionService } ] }) .compileComponents().then(() => { From 817c6b8360d9a95aebdb6e89103c4f7721fa4047 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 30 Oct 2017 10:59:19 -0500 Subject: [PATCH 032/205] Fix issue with service construction --- .../app/activities/activities.component.ts | 3 +-- .../add-activity-wizard.component.ts | 1 + .../add-activity.component.spec.ts | 21 ++++++++++++------- .../add-connection.component.spec.ts | 18 +++++++++------- .../connections-list.component.html | 2 -- .../app/connections/connections.component.ts | 3 +-- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index aca33f4d..c2643e76 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -35,8 +35,7 @@ import { SortDirection } from "@shared/sort-direction.enum"; moduleId: module.id, selector: "app-activities", templateUrl: "./activities.component.html", - styleUrls: ["./activities.component.css"], - providers: [ ActivityService ] + styleUrls: ["./activities.component.css"] }) export class ActivitiesComponent extends AbstractPageComponent { diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts index 715d09f0..92363561 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts @@ -246,6 +246,7 @@ export class AddActivityWizardComponent implements OnInit { public stepChanged($event: WizardEvent): void { if ($event.step.config.id === "step1") { this.updatePage1ValidStatus(); + this.wizardConfig.nextTitle = "Next >"; } else if ($event.step.config.id === "step2a") { this.wizardConfig.nextTitle = "Create"; } else if ($event.step.config.id === "step2b") { diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index f401f4b9..74333747 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -1,12 +1,16 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { ReactiveFormsModule } from "@angular/forms"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { AddActivityWizardComponent } from "@activities/add-activity-wizard/add-activity-wizard.component"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddActivityComponent } from "./add-activity.component"; +import { ActivityService } from "@activities/shared/activity.service"; +import { MockActivityService } from "@activities/shared/mock-activity.service"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; describe("AddActivityComponent", () => { let component: AddActivityComponent; @@ -14,8 +18,12 @@ describe("AddActivityComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], - declarations: [ AddActivityComponent, AddActivityWizardComponent ] + imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], + declarations: [ AddActivityComponent, AddActivityWizardComponent ], + providers: [ + { provide: ActivityService, useClass: MockActivityService }, + { provide: ConnectionService, useClass: MockConnectionService } + ] }) .compileComponents().then(() => { // nothing to do @@ -28,8 +36,7 @@ describe("AddActivityComponent", () => { fixture.detectChanges(); }); - // TODO: Figure out how to setup this test. - // it("should be created", () => { - // expect(component).toBeTruthy(); - // }); + it("should be created", () => { + expect(component).toBeTruthy(); + }); }); diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 426ab3a2..10d05c0d 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -1,12 +1,14 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { ReactiveFormsModule } from "@angular/forms"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { AddConnectionWizardComponent } from "@connections/add-connection-wizard/add-connection-wizard.component"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddConnectionComponent } from "./add-connection.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; describe("AddConnectionComponent", () => { let component: AddConnectionComponent; @@ -14,8 +16,11 @@ describe("AddConnectionComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], - declarations: [ AddConnectionComponent, AddConnectionWizardComponent ] + imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], + declarations: [ AddConnectionComponent, AddConnectionWizardComponent ], + providers: [ + { provide: ConnectionService, useClass: MockConnectionService }, + ] }) .compileComponents().then(() => { // nothing to do @@ -28,8 +33,7 @@ describe("AddConnectionComponent", () => { fixture.detectChanges(); }); - // TODO: Figure out how to setup this test. - // it("should be created", () => { - // expect(component).toBeTruthy(); - // }); + it("should be created", () => { + expect(component).toBeTruthy(); + }); }); diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.html b/ngapp/src/app/connections/connections-list/connections-list.component.html index da8c3ca3..97fc8e3d 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.html +++ b/ngapp/src/app/connections/connections-list/connections-list.component.html @@ -29,8 +29,6 @@
    - -
    diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 33ef5692..698e21fe 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -33,8 +33,7 @@ import { SortDirection } from "@shared/sort-direction.enum"; moduleId: module.id, selector: "app-connections", templateUrl: "./connections.component.html", - styleUrls: ["./connections.component.css"], - providers: [ConnectionService] + styleUrls: ["./connections.component.css"] }) export class ConnectionsComponent extends AbstractPageComponent { From 6398f0c66598efdfe13e5ffd2090e194f4301b28 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 30 Oct 2017 11:36:26 -0500 Subject: [PATCH 033/205] Karma tests are now being run with the maven build. --- ngapp/karma.conf.js | 28 +-- ngapp/package-lock.json | 448 +++++++++++++++++++++++++++++++++++++--- ngapp/package.json | 8 +- ngapp/src/polyfills.ts | 28 +-- 4 files changed, 445 insertions(+), 67 deletions(-) diff --git a/ngapp/karma.conf.js b/ngapp/karma.conf.js index af139fad..76d98137 100644 --- a/ngapp/karma.conf.js +++ b/ngapp/karma.conf.js @@ -7,27 +7,17 @@ module.exports = function (config) { frameworks: ['jasmine', '@angular/cli'], plugins: [ require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), + require('karma-phantomjs-launcher' ), + require('karma-junit-reporter'), require('@angular/cli/plugins/karma') ], - client:{ - clearContext: false // leave Jasmine Spec Runner output visible in browser + junitReporter : { + // .../beetle-studio/target/karma-reports/*.xml + outputDir : '../../target/karma-reports/' }, - coverageIstanbulReporter: { - reports: [ 'html', 'lcovonly' ], - fixWebpackSourcePaths: true - }, - angularCli: { - environment: 'dev' - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false + reporters: ['junit'], + autoWatch: false, + browsers: [ 'PhantomJS' ], + singleRun: true }); }; diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index 59e40042..823a5559 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -73,7 +73,7 @@ "raw-loader": "0.5.1", "resolve": "1.4.0", "rsvp": "3.6.2", - "rxjs": "5.5.0", + "rxjs": "5.5.2", "sass-loader": "6.0.6", "script-loader": "0.7.1", "semver": "5.4.1", @@ -1504,6 +1504,49 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, "connect": { "version": "3.6.5", "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz", @@ -2408,6 +2451,12 @@ "event-emitter": "0.3.5" } }, + "es6-promise": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", + "integrity": "sha1-eILzCt3lskDM+n99eMVIMwlRrkI=", + "dev": true + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -2732,6 +2781,44 @@ "webpack-sources": "1.0.1" } }, + "extract-zip": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.5.tgz", + "integrity": "sha1-maBnNbbqIOqbcF13ms/8yHz/BEA=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "debug": "2.2.0", + "mkdirp": "0.5.0", + "yauzl": "2.4.1" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -2759,6 +2846,15 @@ "websocket-driver": "0.7.0" } }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "1.2.0" + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -4105,6 +4201,16 @@ "minimalistic-assert": "1.0.0" } }, + "hasha": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "dev": true, + "requires": { + "is-stream": "1.1.0", + "pinkie-promise": "2.0.1" + } + }, "hawk": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", @@ -5303,6 +5409,34 @@ "karma-jasmine": "1.1.0" } }, + "karma-junit-reporter": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-1.2.0.tgz", + "integrity": "sha1-T5xAzt+xo5X4rvh2q/lhiZF8Y5Y=", + "dev": true, + "requires": { + "path-is-absolute": "1.0.1", + "xmlbuilder": "8.2.2" + }, + "dependencies": { + "xmlbuilder": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz", + "integrity": "sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=", + "dev": true + } + } + }, + "karma-phantomjs-launcher": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", + "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=", + "dev": true, + "requires": { + "lodash": "4.17.4", + "phantomjs-prebuilt": "2.1.15" + } + }, "karma-source-map-support": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.2.0.tgz", @@ -5312,6 +5446,12 @@ "source-map-support": "0.4.18" } }, + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -5321,6 +5461,15 @@ "is-buffer": "1.1.5" } }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, "lazy-cache": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", @@ -6489,21 +6638,21 @@ } }, "patternfly": { - "version": "3.28.3", - "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.28.3.tgz", - "integrity": "sha1-/klrjTOPxdlOMko4KuvC+lLEDvM=", + "version": "3.29.9", + "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.29.9.tgz", + "integrity": "sha1-HNS16+pmhFJ/Cgeamve3TDmCf7w=", "requires": { "bootstrap": "3.3.7", "bootstrap-datepicker": "1.6.4", "bootstrap-select": "1.12.4", "bootstrap-switch": "3.3.4", "bootstrap-touchspin": "3.1.1", - "c3": "0.4.17", + "c3": "0.4.18", "d3": "3.5.17", - "datatables.net": "1.10.15", + "datatables.net": "1.10.16", "datatables.net-colreorder": "1.3.3", "datatables.net-colreorder-bs": "1.3.3", - "datatables.net-select": "1.2.2", + "datatables.net-select": "1.2.3", "drmonty-datatables-colvis": "1.1.2", "eonasdan-bootstrap-datetimepicker": "4.17.47", "font-awesome": "4.7.0", @@ -6552,9 +6701,9 @@ "optional": true }, "c3": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.17.tgz", - "integrity": "sha512-41T3yS3jq1XgA7ruvV1wFVEK1E2az2iUAqS7hU5de62JVrjPyxWqIPu8AHlKpShZxJbD+DXLRkQHfOLASYyqyg==", + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.18.tgz", + "integrity": "sha512-37TiFeCrbe69gg7SxFpTBOLDwulnk+opKp1AFDi43mONtErpRoUIZfGSimGiSYQmNu6Zh9W2yNOx0066UikqSg==", "optional": true, "requires": { "d3": "3.5.17" @@ -6567,20 +6716,20 @@ "optional": true }, "datatables.net": { - "version": "1.10.15", - "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.15.tgz", - "integrity": "sha1-x4kHe7/jhedf9aIz+l8jJRpy32g=", + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.16.tgz", + "integrity": "sha1-SwUtEIKCQmG2ju2dInQbcR09JGk=", "requires": { "jquery": "3.2.1" } }, "datatables.net-bs": { - "version": "1.10.15", - "resolved": "https://registry.npmjs.org/datatables.net-bs/-/datatables.net-bs-1.10.15.tgz", - "integrity": "sha1-ssImEAfYTKW1q/VsGO3CJ+DaGk0=", + "version": "1.10.16", + "resolved": "https://registry.npmjs.org/datatables.net-bs/-/datatables.net-bs-1.10.16.tgz", + "integrity": "sha1-sIVPWzdPcTrj20FWx86op2DD3nY=", "optional": true, "requires": { - "datatables.net": "1.10.15", + "datatables.net": "1.10.16", "jquery": "3.2.1" } }, @@ -6590,7 +6739,7 @@ "integrity": "sha1-/HYuNQ+UIkyyzUXCuWImGg//73I=", "optional": true, "requires": { - "datatables.net": "1.10.15", + "datatables.net": "1.10.16", "jquery": "3.2.1" } }, @@ -6600,18 +6749,18 @@ "integrity": "sha1-Op3LCN7r612FQHlZHgbkk615OlM=", "optional": true, "requires": { - "datatables.net-bs": "1.10.15", + "datatables.net-bs": "1.10.16", "datatables.net-colreorder": "1.3.3", "jquery": "3.2.1" } }, "datatables.net-select": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/datatables.net-select/-/datatables.net-select-1.2.2.tgz", - "integrity": "sha1-llF5P1KJn05XRcByCCHouChvv0U=", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/datatables.net-select/-/datatables.net-select-1.2.3.tgz", + "integrity": "sha1-fCcugXMqQSFOEBtlb1Ul037Dcog=", "optional": true, "requires": { - "datatables.net": "1.10.15", + "datatables.net": "1.10.16", "jquery": "3.2.1" } }, @@ -6691,9 +6840,9 @@ } }, "patternfly-ng": { - "version": "0.13.5", - "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-0.13.5.tgz", - "integrity": "sha1-cgEAhzryqsIWB/gejevSW2M30Ic=", + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-0.13.7.tgz", + "integrity": "sha1-JZCSKRk1MbiEWzk51msBaU8dy2w=", "requires": { "@angular/animations": "4.4.6", "@angular/common": "4.4.6", @@ -6711,8 +6860,8 @@ "core-js": "2.4.1", "moment": "2.17.1", "ngx-bootstrap": "1.8.0", - "patternfly": "3.28.3", - "rxjs": "5.5.0", + "patternfly": "3.29.9", + "rxjs": "5.5.2", "zone.js": "0.8.4" }, "dependencies": { @@ -6756,12 +6905,213 @@ "sha.js": "2.4.9" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "phantomjs-prebuilt": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.15.tgz", + "integrity": "sha1-IPhugtM0nFBZF1J3RbekEeCLOQM=", + "dev": true, + "requires": { + "es6-promise": "4.0.5", + "extract-zip": "1.6.5", + "fs-extra": "1.0.0", + "hasha": "2.2.0", + "kew": "0.7.0", + "progress": "1.1.8", + "request": "2.81.0", + "request-progress": "2.0.1", + "which": "1.2.14" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1" + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + } + } + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -7365,6 +7715,12 @@ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", @@ -7895,6 +8251,15 @@ "uuid": "3.1.0" } }, + "request-progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "dev": true, + "requires": { + "throttleit": "1.0.0" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7997,9 +8362,9 @@ } }, "rxjs": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.0.tgz", - "integrity": "sha512-vmvP5y/oJIJmXKHY36PIjVeI/46Sny6BMBa7/ou2zsNz1PiqU/Gtcz1GujnHz5Qlxncv+J9VlWmttnshqFj3Kg==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz", + "integrity": "sha512-oRYoIKWBU3Ic37fLA5VJu31VqQO4bWubRntcHSJ+cwaDQBwdnZ9x4zmhJfm/nFQ2E82/I4loSioHnACamrKGgA==", "requires": { "symbol-observable": "1.0.4" } @@ -9000,6 +9365,12 @@ } } }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -9207,6 +9578,12 @@ "mime-types": "2.1.17" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, "typescript": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.3.4.tgz", @@ -10148,6 +10525,15 @@ } } }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "1.0.1" + } + }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", diff --git a/ngapp/package.json b/ngapp/package.json index 5c58e093..2b7f34a9 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -23,9 +23,9 @@ "@angular/router": "^4.4.6", "core-js": "^2.4.1", "ngx-bootstrap": "^1.9.3", - "patternfly": "^3.28.3", - "patternfly-ng": "^0.13.5", - "rxjs": "^5.5.0", + "patternfly": "^3.29.9", + "patternfly-ng": "^0.13.7", + "rxjs": "^5.5.2", "zone.js": "^0.8.14" }, "devDependencies": { @@ -44,6 +44,8 @@ "karma-coverage-istanbul-reporter": "^1.2.1", "karma-jasmine": "~1.1.0", "karma-jasmine-html-reporter": "^0.2.2", + "karma-junit-reporter": "^1.2.0", + "karma-phantomjs-launcher": "^1.0.4", "protractor": "~5.1.2", "ts-node": "~3.2.0", "tslint": "~5.7.0", diff --git a/ngapp/src/polyfills.ts b/ngapp/src/polyfills.ts index 94a3027e..de45784c 100644 --- a/ngapp/src/polyfills.ts +++ b/ngapp/src/polyfills.ts @@ -19,20 +19,20 @@ */ // IE9, IE10 and IE11 requires all of the following polyfills. -// import 'core-js/es6/symbol'; -// import 'core-js/es6/object'; -// import 'core-js/es6/function'; -// import 'core-js/es6/parse-int'; -// import 'core-js/es6/parse-float'; -// import 'core-js/es6/number'; -// import 'core-js/es6/math'; -// import 'core-js/es6/string'; -// import 'core-js/es6/date'; -// import 'core-js/es6/array'; -// import 'core-js/es6/regexp'; -// import 'core-js/es6/map'; -// import 'core-js/es6/weak-map'; -// import 'core-js/es6/set'; +import "core-js/es6/array"; +import "core-js/es6/date"; +import "core-js/es6/function"; +import "core-js/es6/map"; +import "core-js/es6/math"; +import "core-js/es6/number"; +import "core-js/es6/object"; +import "core-js/es6/parse-float"; +import "core-js/es6/parse-int"; +import "core-js/es6/regexp"; +import "core-js/es6/set"; +import "core-js/es6/string"; +import "core-js/es6/symbol"; +import "core-js/es6/weak-map"; /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. From 7e0b2e3321b2a0eb753e69672cddb6db3791d27d Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 31 Oct 2017 14:59:10 -0500 Subject: [PATCH 034/205] Miscellaneous Fixes - fixed issue where class instance variables were not accessed correctly from callback handlers - changed type of "any" to "Response" when error responses are being used - fixed some TSLint warnings - fixed issue in ConnectionService where catch blocks were not calling the handleError method correctly - made ApiService an "abstract" class and made it no longer injectable - added 2 developer notes --- ngapp/karma.conf.js | 3 ++ .../app/activities/activities.component.ts | 21 +++++---- ngapp/src/app/activities/activities.module.ts | 8 ++-- .../add-activity-wizard.component.spec.ts | 8 ++-- .../add-activity-wizard.component.ts | 43 ++++++++++--------- .../add-activity.component.spec.ts | 10 ++--- .../add-activity/add-activity.component.ts | 2 +- .../app/activities/shared/activity.service.ts | 34 +++++++++------ .../shared/mock-activity.service.ts | 2 +- .../add-connection-wizard.component.ts | 35 ++++++++------- .../add-connection.component.spec.ts | 4 +- .../app/connections/connections.component.ts | 19 ++++---- .../src/app/connections/connections.module.ts | 4 +- .../shared/connection.service.spec.ts | 2 +- .../connections/shared/connection.service.ts | 10 ++--- ngapp/src/app/core/api.service.spec.ts | 14 ++++-- ngapp/src/app/core/api.service.ts | 11 +++-- ngapp/src/app/core/core.module.ts | 2 - .../vertical-nav/vertical-nav.component.ts | 3 +- .../src/app/shared/abstract-page.component.ts | 15 ++++--- .../confirm-delete.component.ts | 5 ++- .../page-error/page-error.component.spec.ts | 3 +- .../shared/page-error/page-error.component.ts | 5 ++- .../property-form-property.component.spec.ts | 2 +- .../property-form-property.component.ts | 2 +- .../property-form/property-form.component.ts | 3 +- 26 files changed, 155 insertions(+), 115 deletions(-) diff --git a/ngapp/karma.conf.js b/ngapp/karma.conf.js index 76d98137..eacfd9f6 100644 --- a/ngapp/karma.conf.js +++ b/ngapp/karma.conf.js @@ -15,6 +15,9 @@ module.exports = function (config) { // .../beetle-studio/target/karma-reports/*.xml outputDir : '../../target/karma-reports/' }, + angularCli: { + environment: 'dev' + }, reporters: ['junit'], autoWatch: false, browsers: [ 'PhantomJS' ], diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index c2643e76..6d37cced 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -61,17 +61,19 @@ export class ActivitiesComponent extends AbstractPageComponent { } public loadAsyncPageData(): void { + const self = this; + this.activityService .getAllActivities() .subscribe( (activities) => { - this.allActs = activities; - this.filteredActs = this.filterActivities(); - this.loaded("activities"); + self.allActs = activities; + self.filteredActs = this.filterActivities(); + self.loaded("activities"); }, (error) => { - this.logger.error("[ActivitiesComponent] Error getting activities."); - this.error(error); + self.logger.error("[ActivitiesComponent] Error getting activities."); + self.error(error); } ); } @@ -208,14 +210,17 @@ export class ActivitiesComponent extends AbstractPageComponent { // Note: we can only doDelete selected items that we can see in the UI. this.logger.log("[ActivitiesPageComponent] Deleting selected Activity."); // this.activityService.deleteActivity(activityToDelete); + + const self = this; + this.activityService .deleteActivity(activityToDelete) .subscribe( () => { - this.removeActivityFromList(selectedActivity); + self.removeActivityFromList(selectedActivity); const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; - this.logger.log("[ActivitiesComponent] Navigating to: %o", link); - this.router.navigate(link).then(() => { + self.logger.log("[ActivitiesComponent] Navigating to: %o", link); + self.router.navigate(link).then(() => { // nothing to do }); } diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts index 0273f1bd..7cbe3baf 100644 --- a/ngapp/src/app/activities/activities.module.ts +++ b/ngapp/src/app/activities/activities.module.ts @@ -19,18 +19,19 @@ import { ActivitiesCardsComponent } from "@activities/activities-cards/activitie import { ActivitiesListComponent } from "@activities/activities-list/activities-list.component"; import { ActivitiesRoutingModule } from "@activities/activities-routing.module"; import { ActivitiesComponent } from "@activities/activities.component"; +import { AddActivityWizardComponent } from "@activities/add-activity-wizard/add-activity-wizard.component"; import { AddActivityComponent } from "@activities/add-activity/add-activity.component"; import { ActivityService } from "@activities/shared/activity.service"; import { AddActivityFormComponent } from "@activities/shared/add-activity-form/add-activity-form.component"; import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; +import { ReactiveFormsModule } from "@angular/forms"; import { FormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; +import { LoggerService } from "@core/logger.service"; import { SharedModule } from "@shared/shared.module"; -import { AddActivityWizardComponent } from './add-activity-wizard/add-activity-wizard.component'; -import { ReactiveFormsModule } from "@angular/forms"; import { PatternFlyNgModule } from "patternfly-ng"; @NgModule({ @@ -55,7 +56,8 @@ import { PatternFlyNgModule } from "patternfly-ng"; AddActivityWizardComponent ], providers: [ - ActivityService + ActivityService, + LoggerService ] }) export class ActivitiesModule {} diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts index af53d5d3..f17ce2de 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts @@ -1,16 +1,16 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { FormsModule, ReactiveFormsModule } from "@angular/forms"; -import { RouterTestingModule } from "@angular/router/testing"; import { ActivityService } from "@activities/shared/activity.service"; import { MockActivityService } from "@activities/shared/mock-activity.service"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddActivityWizardComponent } from "./add-activity-wizard.component"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { MockConnectionService } from "@connections/shared/mock-connection.service"; describe("AddActivityWizardComponent", () => { let component: AddActivityWizardComponent; diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts index 92363561..b3cf601f 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts @@ -22,21 +22,21 @@ import { ViewEncapsulation, } from "@angular/core"; +import { ActivitiesConstants } from "@activities/shared/activities-constants"; +import { ActivityService } from "@activities/shared/activity.service"; +import { NewActivity } from "@activities/shared/new-activity.model"; import { FormControl, FormGroup } from "@angular/forms"; -import { AbstractControl } from "@angular/forms"; import { Validators } from "@angular/forms"; +import { AbstractControl } from "@angular/forms"; import { Router } from "@angular/router"; -import { ActivityService } from "@activities/shared/activity.service"; -import { ActivitiesConstants } from "@activities/shared/activities-constants"; -import { NewActivity } from "@activities/shared/new-activity.model"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { NewConnection } from "@connections/shared/new-connection.model"; import { LoggerService } from "@core/logger.service"; -import { WizardComponent } from "patternfly-ng"; -import { WizardEvent } from "patternfly-ng"; import { WizardStepConfig } from "patternfly-ng"; import { WizardConfig } from "patternfly-ng"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { Connection } from "@connections/shared/connection.model"; -import {NewConnection} from "@connections/shared/new-connection.model"; +import { WizardEvent } from "patternfly-ng"; +import { WizardComponent } from "patternfly-ng"; @Component({ encapsulation: ViewEncapsulation.None, @@ -121,15 +121,16 @@ export class AddActivityWizardComponent implements OnInit { // Load the connections for the first step this.connectionsLoaded = false; + const self = this; this.connectionService .getAllConnections() .subscribe( (conns) => { - this.allConnections = conns; - this.connectionsLoaded = true; + self.allConnections = conns; + self.connectionsLoaded = true; }, (error) => { - this.logger.error("[AddActivityWizardComponent] Error getting connections: %o", error); + self.logger.error("[AddActivityWizardComponent] Error getting connections: %o", error); } ); @@ -221,24 +222,25 @@ export class AddActivityWizardComponent implements OnInit { // Activity basic properties from step 1 activity.setName(this.activityName); - let srcConn: NewConnection = new NewConnection(); + const srcConn: NewConnection = new NewConnection(); srcConn.setName(this.sourceConnectionName); activity.setSourceConnection(srcConn); - let tgtConn: NewConnection = new NewConnection(); + const tgtConn: NewConnection = new NewConnection(); tgtConn.setName(this.targetConnectionName); activity.setTargetConnection(tgtConn); + const self = this; this.activityService .createActivity(activity) .subscribe( () => { - this.createComplete = true; - this.createSuccessful = true; - this.step2bConfig.nextEnabled = false; + self.createComplete = true; + self.createSuccessful = true; + self.step2bConfig.nextEnabled = false; }, (error) => { - this.createComplete = true; - this.createSuccessful = false; + self.createComplete = true; + self.createSuccessful = false; } ); } @@ -314,8 +316,9 @@ export class AddActivityWizardComponent implements OnInit { * React to basic property changes - update the page 1 status */ private onChanges(): void { + const self = this; this.basicPropertyForm.valueChanges.subscribe((val) => { - this.updatePage1ValidStatus( ); + self.updatePage1ValidStatus( ); }); } diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 74333747..841dfa9b 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -1,16 +1,16 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { AddActivityWizardComponent } from "@activities/add-activity-wizard/add-activity-wizard.component"; +import { ActivityService } from "@activities/shared/activity.service"; +import { MockActivityService } from "@activities/shared/mock-activity.service"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; -import { AddActivityWizardComponent } from "@activities/add-activity-wizard/add-activity-wizard.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddActivityComponent } from "./add-activity.component"; -import { ActivityService } from "@activities/shared/activity.service"; -import { MockActivityService } from "@activities/shared/mock-activity.service"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { MockConnectionService } from "@connections/shared/mock-connection.service"; describe("AddActivityComponent", () => { let component: AddActivityComponent; diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.ts b/ngapp/src/app/activities/add-activity/add-activity.component.ts index 08e915ff..6e5bdccc 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import { Component, OnInit } from "@angular/core"; import { ActivitiesConstants } from "@activities/shared/activities-constants"; +import { Component, OnInit } from "@angular/core"; @Component({ selector: "app-add-activity-page", diff --git a/ngapp/src/app/activities/shared/activity.service.ts b/ngapp/src/app/activities/shared/activity.service.ts index 41196549..1ce32055 100644 --- a/ngapp/src/app/activities/shared/activity.service.ts +++ b/ngapp/src/app/activities/shared/activity.service.ts @@ -21,6 +21,7 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { ApiService } from "@core/api.service"; import { LoggerService } from "@core/logger.service"; +import "rxjs/add/observable/of"; import { Observable } from "rxjs/Observable"; @Injectable() @@ -38,9 +39,10 @@ export class ActivityService extends ApiService { * @returns {Activity[]} */ public getAllActivities(): Observable { - let activities = JSON.parse(localStorage.getItem('activities')); - - if (!activities) activities = []; + let activities = JSON.parse(localStorage.getItem("activities")); + if (!activities) { + activities = []; + } return Observable.of(this.convertObjectArray(activities)); /* return this.http @@ -59,15 +61,17 @@ export class ActivityService extends ApiService { * @returns {Activity} */ public createActivity(activity: NewActivity): Observable { - let act = new Activity(); + const act = new Activity(); act.setId(activity.getName()); act.setSourceConnection(activity.getSourceConnection().getName()); act.setTargetConnection(activity.getTargetConnection().getName()); - let activities = JSON.parse(localStorage.getItem('activities')); - if (!activities) activities = []; + let activities = JSON.parse(localStorage.getItem("activities")); + if (!activities) { + activities = []; + } activities.push(act); - localStorage.setItem('activities', JSON.stringify(activities)); + localStorage.setItem("activities", JSON.stringify(activities)); // TODO implement createActivity() return Observable.of(activity); @@ -86,13 +90,15 @@ export class ActivityService extends ApiService { * @param {NewActivity} activity */ public deleteActivity(activity: NewActivity): Observable { - let activities = JSON.parse(localStorage.getItem('activities')); - if (!activities) activities = []; + let activities = JSON.parse(localStorage.getItem("activities")); + if (!activities) { + activities = []; + } - let indexOfDeleted = activities.findIndex(i => i.keng__id === activity.getName()); - activities.splice(indexOfDeleted,1); + const indexOfDeleted = activities.findIndex((i) => i.keng__id === activity.getName()); + activities.splice(indexOfDeleted, 1); - localStorage.setItem('activities', JSON.stringify(activities)); + localStorage.setItem("activities", JSON.stringify(activities)); // TODO implement deleteActivity() /* @@ -110,10 +116,10 @@ export class ActivityService extends ApiService { * This can be removed once we connect to the komodo rest service */ private convertObjectArray(objArray: [any]): Activity[] { - let activityArray = []; + const activityArray = []; for (const obj of objArray) { - let act: Activity = new Activity(); + const act: Activity = new Activity(); act.setId(obj.keng__id); act.setSourceConnection(obj.dv__sourceConnection); act.setTargetConnection(obj.dv__targetConnection); diff --git a/ngapp/src/app/activities/shared/mock-activity.service.ts b/ngapp/src/app/activities/shared/mock-activity.service.ts index 15bc2ae0..aab8caa7 100644 --- a/ngapp/src/app/activities/shared/mock-activity.service.ts +++ b/ngapp/src/app/activities/shared/mock-activity.service.ts @@ -9,7 +9,7 @@ import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; -import {Observable} from "rxjs/Observable"; +import { Observable } from "rxjs/Observable"; @Injectable() export class MockActivityService extends ActivityService { diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index 35d689cb..5b907fe5 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -135,15 +135,16 @@ export class AddConnectionWizardComponent implements OnInit { // Load the templates for the first step this.templatesLoaded = false; + const self = this; this.connectionService .getConnectionTemplates() .subscribe( (templates) => { - this.allTemplates = templates; - this.templatesLoaded = true; + self.allTemplates = templates; + self.templatesLoaded = true; }, (error) => { - this.logger.error("[AddConnectionWizardComponent] Error getting templates: %o", error); + self.logger.error("[AddConnectionWizardComponent] Error getting templates: %o", error); } ); @@ -232,7 +233,7 @@ export class AddConnectionWizardComponent implements OnInit { // When leaving page 1, load the driver-specific property definitions if ($event.step.config.id === "step1") { const selectedDriver = this.basicPropertyForm.controls["driver"].value; - if(!this.detailPropertiesLoaded || (this.detailPropertiesLoadedType!==selectedDriver)) { + if (!this.detailPropertiesLoaded || (this.detailPropertiesLoadedType !== selectedDriver)) { this.loadPropertyDefinitions(selectedDriver); } } @@ -274,17 +275,18 @@ export class AddConnectionWizardComponent implements OnInit { const propMap: Map = this.detailPropForm.propertyValuesNonDefault; connection.setProperties(propMap); + const self = this; this.connectionService .createConnection(connection) .subscribe( () => { - this.createComplete = true; - this.createSuccessful = true; - this.step3bConfig.nextEnabled = false; + self.createComplete = true; + self.createSuccessful = true; + self.step3bConfig.nextEnabled = false; }, (error) => { - this.createComplete = true; - this.createSuccessful = false; + self.createComplete = true; + self.createSuccessful = false; } ); } @@ -361,8 +363,9 @@ export class AddConnectionWizardComponent implements OnInit { driver: new FormControl("", Validators.required) }); // Responds to basic property changes - updates the page status + const self = this; this.basicPropertyForm.valueChanges.subscribe((val) => { - this.updatePage1ValidStatus( ); + self.updatePage1ValidStatus( ); }); } @@ -385,7 +388,7 @@ export class AddConnectionWizardComponent implements OnInit { */ private loadPropertyDefinitions( driverName ): void { this.detailPropertiesLoaded = false; - const that = this; + const self = this; this.connectionService .getConnectionTemplateProperties(driverName) .subscribe( @@ -401,14 +404,14 @@ export class AddConnectionWizardComponent implements OnInit { } } - that.detailProperties = firstProps.concat(nextProps); - this.detailPropertiesLoaded = true; - this.detailPropertiesLoadedType = driverName; + self.detailProperties = firstProps.concat(nextProps); + self.detailPropertiesLoaded = true; + self.detailPropertiesLoadedType = driverName; }, (error) => { - this.logger.error("[AddConnectionWizardComponent] Error: %o", error); + self.logger.error("[AddConnectionWizardComponent] Error: %o", error); // this.error(error); - this.detailPropertiesLoaded = false; + self.detailPropertiesLoaded = false; } ); } diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 10d05c0d..bed73a77 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -3,12 +3,12 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { AddConnectionWizardComponent } from "@connections/add-connection-wizard/add-connection-wizard.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddConnectionComponent } from "./add-connection.component"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { MockConnectionService } from "@connections/shared/mock-connection.service"; describe("AddConnectionComponent", () => { let component: AddConnectionComponent; diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 698e21fe..8c1e0d53 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -58,17 +58,19 @@ export class ConnectionsComponent extends AbstractPageComponent { } public loadAsyncPageData(): void { + const self = this; + this.connectionService .getAllConnections() .subscribe( (connections) => { - this.allConns = connections; - this.filteredConns = this.filterConnections(); - this.loaded("connections"); + self.allConns = connections; + self.filteredConns = this.filterConnections(); + self.loaded("connections"); }, (error) => { - this.logger.error("[ConnectionsComponent] Error getting connections."); - this.error(error); + self.logger.error("[ConnectionsComponent] Error getting connections."); + self.error(error); } ); } @@ -194,14 +196,15 @@ export class ConnectionsComponent extends AbstractPageComponent { // Note: we can only doDelete selected items that we can see in the UI. this.logger.log("[ConnectionsPageComponent] Deleting selected Connection."); + const self = this; this.connectionService .deleteConnection(connectionToDelete) .subscribe( () => { - this.removeConnectionFromList(selectedConn); + self.removeConnectionFromList(selectedConn); const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; - this.logger.log("[CreateApiPageComponent] Navigating to: %o", link); - this.router.navigate(link).then(() => { + self.logger.log("[CreateApiPageComponent] Navigating to: %o", link); + self.router.navigate(link).then(() => { // nothing to do }); } diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index db685be6..0e029bc3 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -24,8 +24,8 @@ import { ConnectionsListComponent } from "@connections/connections-list/connecti import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; import { ConnectionsComponent } from "@connections/connections.component"; import { ConnectionService } from "@connections/shared/connection.service"; -import {MockConnectionService} from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; +import { LoggerService } from "@core/logger.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddConnectionWizardComponent } from "./add-connection-wizard/add-connection-wizard.component"; @@ -51,7 +51,7 @@ import { AddConnectionComponent } from "./add-connection/add-connection.componen ], providers: [ ConnectionService, - MockConnectionService + LoggerService ], exports: [ ] diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ngapp/src/app/connections/shared/connection.service.spec.ts index b17ce8df..3e03e5bf 100644 --- a/ngapp/src/app/connections/shared/connection.service.spec.ts +++ b/ngapp/src/app/connections/shared/connection.service.spec.ts @@ -12,7 +12,7 @@ describe("ConnectionService", () => { }); it("should be created", inject([ConnectionService, LoggerService], - (service: ConnectionService, logger: LoggerService ) => { + (service: ConnectionService ) => { expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index cf70d648..84eac05e 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -48,7 +48,7 @@ export class ConnectionService extends ApiService { const connections = response.json(); return connections.map((connection) => Connection.create( connection )); }) - .catch(this.handleError); + .catch( ( error ) => this.handleError( error ) ); } /** @@ -63,7 +63,7 @@ export class ConnectionService extends ApiService { .map((response) => { return new Connection(); }) - .catch(this.handleError); + .catch( ( error ) => this.handleError( error ) ); } /** @@ -76,7 +76,7 @@ export class ConnectionService extends ApiService { .delete(environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath + "/" + connection.getName(), this.getAuthRequestOptions()) .map((response) => null) - .catch(this.handleError); + .catch( ( error ) => this.handleError( error ) ); } /** @@ -90,7 +90,7 @@ export class ConnectionService extends ApiService { const templates = response.json(); return templates.map((template) => TemplateDefinition.create( template )); }) - .catch(this.handleError); + .catch( ( error ) => this.handleError( error ) ); } /** @@ -105,7 +105,7 @@ export class ConnectionService extends ApiService { const entries = response.json() as Array>; return entries.map((entry) => PropertyDefinition.create( entry )); }) - .catch(this.handleError); + .catch( ( error ) => this.handleError( error ) ); } } diff --git a/ngapp/src/app/core/api.service.spec.ts b/ngapp/src/app/core/api.service.spec.ts index 6203f07d..aeaa50d0 100644 --- a/ngapp/src/app/core/api.service.spec.ts +++ b/ngapp/src/app/core/api.service.spec.ts @@ -7,12 +7,20 @@ describe("ApiService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpModule], - providers: [ApiService, LoggerService] + providers: [LoggerService] }); }); - it("should be created", inject([ApiService, LoggerService], - (service: ApiService, logger: LoggerService) => { + it("should be created", inject([LoggerService], + (service: MockService ) => { expect(service).toBeTruthy(); })); }); + +class MockService extends ApiService { + + constructor( logger: LoggerService ) { + super( logger ); + } + +} diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index 7f63c46b..293020e8 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -16,7 +16,7 @@ */ import { Injectable } from "@angular/core"; -import { Headers, RequestOptions } from "@angular/http"; +import { Headers, RequestOptions, Response } from "@angular/http"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; @@ -24,10 +24,9 @@ import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; import { ErrorObservable } from "rxjs/observable/ErrorObservable"; -@Injectable() -export class ApiService { +export abstract class ApiService { - private logger: LoggerService; + protected logger: LoggerService; constructor( logger: LoggerService ) { this.logger = logger; @@ -43,8 +42,8 @@ export class ApiService { return new RequestOptions({ headers }); } - protected handleError(error: Response | any): ErrorObservable { - this.logger.error("ApiService::handleError", error); + protected handleError(error: Response): ErrorObservable { + this.logger.error( this.constructor.name + "::handleError" ); return Observable.throw(error); } diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index e876d73b..cae741da 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -19,7 +19,6 @@ import { CommonModule } from "@angular/common"; import { NgModule, Optional, SkipSelf } from "@angular/core"; import { HttpModule } from "@angular/http"; import { RouterModule } from "@angular/router"; -import { ApiService } from "@core/api.service"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; import { LoggerService } from "@core/logger.service"; @@ -45,7 +44,6 @@ import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component" VerticalNavComponent ], providers: [ - ApiService, LoggerService ] }) diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index 36270c72..fe3094d6 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -49,9 +49,10 @@ export class VerticalNavComponent implements OnInit { public ngOnInit(): void { this.logger.log("Subscribing to router events."); + const self = this; this.router.events.subscribe((event) => { if (event instanceof NavigationEnd) { - this.onShadeClick(); + self.onShadeClick(); } }); } diff --git a/ngapp/src/app/shared/abstract-page.component.ts b/ngapp/src/app/shared/abstract-page.component.ts index 70298999..235a603f 100644 --- a/ngapp/src/app/shared/abstract-page.component.ts +++ b/ngapp/src/app/shared/abstract-page.component.ts @@ -16,6 +16,7 @@ */ import { OnInit } from "@angular/core"; +import { Response } from "@angular/http"; import { ActivatedRoute } from "@angular/router"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/combineLatest"; @@ -24,9 +25,9 @@ import { Observable } from "rxjs/Observable"; export abstract class AbstractPageComponent implements OnInit { public dataLoaded: Map = new Map(); - public pageError: any; + public pageError: Response; protected route: ActivatedRoute; - protected logger: LoggerService; + public logger: LoggerService; /** * C'tor. @@ -44,26 +45,30 @@ export abstract class AbstractPageComponent implements OnInit { */ public ngOnInit(): void { const combined = Observable.combineLatest(this.route.params, this.route.queryParams, (params, qparams) => ({params, qparams})); + const self = this; combined.subscribe( (ap) => { - this.loadAsyncPageData(ap.params, ap.qparams); + self.loadAsyncPageData(ap.params, ap.qparams); }); } /** * Called to kick off loading the page's async data. Subclasses should * override to provide page-specific data loading. + * + * If you are referencing the component instance in the callback handler code, make sure to save the component + * reference in a constant and use that object in the handler code. * @param pathParams * @param queryParams */ public loadAsyncPageData(pathParams: any, queryParams: any): void { - // TODO is this method needed + // nothing to do } /** * Called by a subclass (page) to report an error during loading of data. * @param error */ - public error(error: any): void { + public error(error: Response): void { this.logger.error(" Error: %o", error); this.pageError = error; } diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts index 730facb0..d301cb4a 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts @@ -37,9 +37,10 @@ export class ConfirmDeleteComponent { */ public open(): void { this.dialogIsOpen = true; + const self = this; this.confirmDeleteModal.changes.subscribe( (thing) => { - if (this.confirmDeleteModal.first) { - this.confirmDeleteModal.first.show(); + if (self.confirmDeleteModal.first) { + self.confirmDeleteModal.first.show(); } }); } diff --git a/ngapp/src/app/shared/page-error/page-error.component.spec.ts b/ngapp/src/app/shared/page-error/page-error.component.spec.ts index f237e4c7..a086b02c 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.spec.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.spec.ts @@ -1,5 +1,5 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { HttpModule } from "@angular/http"; +import { HttpModule, Response, ResponseOptions } from "@angular/http"; import { PageErrorComponent } from "@shared/page-error/page-error.component"; describe("PageErrorComponent", () => { @@ -19,6 +19,7 @@ describe("PageErrorComponent", () => { beforeEach(() => { fixture = TestBed.createComponent(PageErrorComponent); component = fixture.componentInstance; + component.error = new Response( new ResponseOptions( { status: 404 } ) ); fixture.detectChanges(); }); diff --git a/ngapp/src/app/shared/page-error/page-error.component.ts b/ngapp/src/app/shared/page-error/page-error.component.ts index 6e1f8163..df27c3a7 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.ts @@ -16,6 +16,7 @@ */ import { Component, Input } from "@angular/core"; +import { Response } from "@angular/http"; @Component({ moduleId: module.id, @@ -25,7 +26,7 @@ import { Component, Input } from "@angular/core"; }) export class PageErrorComponent { - @Input() public error: any = ""; + @Input() public error: Response; private eobj: any = null; private showDetails = false; @@ -48,7 +49,7 @@ export class PageErrorComponent { * Returns the error code. */ public errorCode(): number { - return this.error.status; + return this.error ? this.error.status : 0; } /** diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts index 576927b4..8f830ba7 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts @@ -1,6 +1,6 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import {FormBuilder, FormsModule, ReactiveFormsModule, Validators} from "@angular/forms"; +import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from "@angular/forms"; import { FormGroup } from "@angular/forms"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; import { PropertyFormPropertyComponent } from "./property-form-property.component"; diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts index 5fdcc192..c55cf7d2 100644 --- a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts +++ b/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts @@ -18,8 +18,8 @@ import { Component, Input } from "@angular/core"; import { AbstractControl, FormGroup } from "@angular/forms"; -import { PropertyDefinition } from "@shared/property-form/property-definition.model"; import { PropertyControlType } from "@shared/property-form/property-control-type.enum"; +import { PropertyDefinition } from "@shared/property-form/property-definition.model"; @Component({ selector: "app-form-property", diff --git a/ngapp/src/app/shared/property-form/property-form.component.ts b/ngapp/src/app/shared/property-form/property-form.component.ts index 955099a2..3acdaf3f 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.ts @@ -44,8 +44,9 @@ export class PropertyFormComponent implements OnInit { public ngOnInit(): void { this.form = this.toFormGroup(this.formProperties); this.formInitialized.emit(this.form.valid); + const self = this; this.form.valueChanges.subscribe((val) => { - this.formChanged.emit(this.form.valid); + self.formChanged.emit(this.form.valid); }); } From 4a9d9284a575572ae1da136d3f8d78e1a2144bda Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 31 Oct 2017 16:02:12 -0500 Subject: [PATCH 035/205] Update karma.conf.js Adding back 'progress' as one of the "reporters" so that when running `ng test` in a terminal you get feedback on test executions and pass/fails. --- ngapp/karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngapp/karma.conf.js b/ngapp/karma.conf.js index eacfd9f6..bdca91d4 100644 --- a/ngapp/karma.conf.js +++ b/ngapp/karma.conf.js @@ -18,7 +18,7 @@ module.exports = function (config) { angularCli: { environment: 'dev' }, - reporters: ['junit'], + reporters: ['junit', 'progress'], autoWatch: false, browsers: [ 'PhantomJS' ], singleRun: true From 043be9709bc8643134b0f3b8870a7123bc3331a6 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Wed, 1 Nov 2017 12:23:27 -0500 Subject: [PATCH 036/205] Changes to the summary pages name filter behavior - filtering of items now occurs as the user is typing in the filter (no longer need to hit enter) - added a compareTo funtion to the Identifiable interface so Connection and Activity now implement - added sort functions to Connection and Activity - summary page name filter now accepts the '*' wildcard --- .../app/activities/activities.component.html | 2 +- .../app/activities/activities.component.ts | 12 +++-- .../app/activities/shared/activity.model.ts | 44 ++++++++++++++++++- .../connections/connections.component.html | 2 +- .../app/connections/connections.component.ts | 27 +++--------- .../connections/shared/connection.model.ts | 40 +++++++++++++++++ ngapp/src/app/shared/id-filter.ts | 15 +++++-- ngapp/src/app/shared/identifiable.ts | 7 +++ 8 files changed, 113 insertions(+), 36 deletions(-) diff --git a/ngapp/src/app/activities/activities.component.html b/ngapp/src/app/activities/activities.component.html index b21f81c3..4246ff2a 100644 --- a/ngapp/src/app/activities/activities.component.html +++ b/ngapp/src/app/activities/activities.component.html @@ -14,7 +14,7 @@

    Activities

    -
    +
    diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index 6d37cced..3aa3afc9 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -119,6 +119,7 @@ export class ActivitiesComponent extends AbstractPageComponent { */ public set nameFilter( pattern: string ) { this.filter.setFilter( pattern ); + this.filterActivities(); } public toggleSortDirection(): void { @@ -233,19 +234,16 @@ export class ActivitiesComponent extends AbstractPageComponent { public filterActivities(): Activity[] { // Clear the array first. this.filteredActs.splice(0, this.filteredActs.length); + + // filter for (const activity of this.allActs) { if (this.filter.accepts(activity)) { this.filteredActs.push(activity); } } - this.filteredActs.sort( (a1: Activity, a2: Activity) => { - let rval: number = a1.getId().localeCompare(a2.getId()); - if (this.sortDirection === SortDirection.DESC) { - rval *= -1; - } - return rval; - }); + // sort + Activity.sort( this.filteredActs, this.sortDirection ); this.selectedActs = ArrayUtils.intersect(this.selectedActs, this.filteredActs); return this.filteredActs; diff --git a/ngapp/src/app/activities/shared/activity.model.ts b/ngapp/src/app/activities/shared/activity.model.ts index 6378560e..7c8c32fe 100644 --- a/ngapp/src/app/activities/shared/activity.model.ts +++ b/ngapp/src/app/activities/shared/activity.model.ts @@ -15,7 +15,10 @@ * limitations under the License. */ -export class Activity { +import { Identifiable } from "@shared/identifiable"; +import { SortDirection } from "@shared/sort-direction.enum"; + +export class Activity implements Identifiable< string > { private keng__id: string; private dv__sourceConnection: string; @@ -31,10 +34,49 @@ export class Activity { return activity; } + /** + * @param {Activity[]} activities the activities being sorted + * @param {SortDirection} sortDirection the sort direction + */ + public static sort( activities: Activity[], + sortDirection: SortDirection ): void { + activities.sort( ( thisActivity: Activity, thatActivity: Activity ) => { + const result = thisActivity.compareTo( thatActivity ); + + if ( sortDirection === SortDirection.DESC ) { + return result * -1; + } + + return result; + } ); + } + constructor() { // nothing to do } + /** + * See {Identifiable}. + */ + public compareTo( that: Activity ): number { + let result = 0; + + if ( this.getId() ) { + if ( that.getId() ) { + // both have an ID + result = this.getId().localeCompare( that.getId() ); + } else { + // thatItem does not have an ID + result = 1; + } + } else if ( that.getId() ) { + // thisItem does not have an ID and thatItem does + result = -1; + } + + return result; + } + /** * @returns {string} the activity identifier (can be null) */ diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index 4c7f7097..b361ed07 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -14,7 +14,7 @@

    Connections

    - +
    diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 8c1e0d53..0352fbc0 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -158,6 +158,7 @@ export class ConnectionsComponent extends AbstractPageComponent { */ public set nameFilter( pattern: string ) { this.filter.setFilter( pattern ); + this.filterConnections(); } public toggleSortDirection(): void { @@ -217,34 +218,16 @@ export class ConnectionsComponent extends AbstractPageComponent { public filterConnections(): Connection[] { // Clear the array first. this.filteredConns.splice(0, this.filteredConns.length); + + // filter for (const connection of this.allConns) { if (this.filter.accepts(connection)) { this.filteredConns.push(connection); } } - this.filteredConns.sort( (c1: Connection, c2: Connection) => { - let rval = 0; - - if ( c1.getId() ) { - if ( c2.getId() ) { - // both connections have an ID - rval = c1.getId().localeCompare( c2.getId() ); - } else { - // c2 does not have an ID - rval = 1; - } - } else if ( c2.getId() ) { - // c1 does not have an ID and c2 does - rval = -1; - } - - if ( this.sortDirection === SortDirection.DESC ) { - rval *= -1; - } - - return rval; - }); + // sort + Connection.sort( this.filteredConns, this.sortDirection ); this.selectedConns = ArrayUtils.intersect(this.selectedConns, this.filteredConns); return this.filteredConns; diff --git a/ngapp/src/app/connections/shared/connection.model.ts b/ngapp/src/app/connections/shared/connection.model.ts index 8594f053..a37d2d65 100644 --- a/ngapp/src/app/connections/shared/connection.model.ts +++ b/ngapp/src/app/connections/shared/connection.model.ts @@ -16,6 +16,7 @@ */ import { Identifiable } from "@shared/identifiable"; +import { SortDirection } from "@shared/sort-direction.enum"; export class Connection implements Identifiable< string > { @@ -34,10 +35,49 @@ export class Connection implements Identifiable< string > { return conn; } + /** + * @param {Connection[]} connections the connections being sorted + * @param {SortDirection} sortDirection the sort direction + */ + public static sort( connections: Connection[], + sortDirection: SortDirection ): void { + connections.sort( ( thisConnection: Connection, thatConnection: Connection ) => { + const result = thisConnection.compareTo( thatConnection ); + + if ( sortDirection === SortDirection.DESC ) { + return result * -1; + } + + return result; + } ); + } + constructor() { // nothing to do } + /** + * See {Identifiable}. + */ + public compareTo( that: Connection ): number { + let result = 0; + + if ( this.getId() ) { + if ( that.getId() ) { + // both have an ID + result = this.getId().localeCompare( that.getId() ); + } else { + // thatItem does not have an ID + result = 1; + } + } else if ( that.getId() ) { + // thisItem does not have an ID and thatItem does + result = -1; + } + + return result; + } + /** * @returns {string} the connection driver name (can be null) */ diff --git a/ngapp/src/app/shared/id-filter.ts b/ngapp/src/app/shared/id-filter.ts index 44180eaf..0c958b13 100644 --- a/ngapp/src/app/shared/id-filter.ts +++ b/ngapp/src/app/shared/id-filter.ts @@ -19,9 +19,13 @@ import { Identifiable } from "@shared/identifiable"; const emptyPattern = ""; +/** + * A string identifier filter. + */ export class IdFilter { private pattern: string = emptyPattern; + private regex: string = emptyPattern; constructor() { // nothing to do @@ -32,13 +36,12 @@ export class IdFilter { * @returns {boolean} true if the ID matches the filter */ public accepts( obj: Identifiable< string > ): boolean { - if ( this.pattern === "" ) { + if ( this.pattern === emptyPattern ) { return true; } - const id: string = obj.getId().toLocaleLowerCase(); - const localized: string = this.pattern.toLocaleLowerCase(); - return id.indexOf( localized ) >= 0; + const id: string = obj.getId(); + return id.match( this.regex ) != null; } /** @@ -53,6 +56,7 @@ export class IdFilter { */ public reset(): void { this.pattern = emptyPattern; + this.regex = emptyPattern; } /** @@ -61,8 +65,11 @@ export class IdFilter { public setFilter( pattern?: string ): void { if ( pattern ) { this.pattern = pattern; + this.regex = pattern.replace( ".", "\\." ); + this.regex = "^" + this.regex.replace( "*", ".*" ); } else { this.pattern = emptyPattern; + this.regex = emptyPattern; } } diff --git a/ngapp/src/app/shared/identifiable.ts b/ngapp/src/app/shared/identifiable.ts index b5726ae1..a1480cf9 100644 --- a/ngapp/src/app/shared/identifiable.ts +++ b/ngapp/src/app/shared/identifiable.ts @@ -20,6 +20,13 @@ */ export interface Identifiable< T > { + /** + * @typedef { object } T the type of the property that is used to identify the object + * @param {Identifiable} that the object being compared to + * @returns {number} 0 if IDs are equal, -1 if this ID is less than, or 1 if this ID is greater than + */ + compareTo( that: Identifiable< T > ): number; + /** * @typedef { object } T the type of the property that is used to identify the object * @returns {T} the object identifier (can be null) From e2cb4bdcb36a6b562375b10f12bb75810f9680ef Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 31 Oct 2017 09:10:42 -0500 Subject: [PATCH 037/205] Addition of Dataservice Wizard --- .../add-activity-wizard.component.ts | 1 + ngapp/src/app/app-routing.module.ts | 2 + ngapp/src/app/app.module.ts | 4 + .../add-connection-wizard.component.ts | 1 + .../add-connection.component.html | 4 +- .../connections/connections.component.spec.ts | 2 +- ngapp/src/app/core/api.service.ts | 1 - .../vertical-nav/vertical-nav.component.html | 5 + .../vertical-nav/vertical-nav.component.ts | 16 +- .../add-dataservice-wizard.component.css | 5 + .../add-dataservice-wizard.component.html | 78 +++++ .../add-dataservice-wizard.component.spec.ts | 42 +++ .../add-dataservice-wizard.component.ts | 321 ++++++++++++++++++ .../add-dataservice.component.css | 0 .../add-dataservice.component.html | 18 + .../add-dataservice.component.spec.ts | 42 +++ .../add-dataservice.component.ts | 40 +++ .../dataservices-cards.component.css | 70 ++++ .../dataservices-cards.component.html | 29 ++ .../dataservices-cards.component.spec.ts | 28 ++ .../dataservices-cards.component.ts | 65 ++++ .../dataservices-list.component.css | 39 +++ .../dataservices-list.component.html | 33 ++ .../dataservices-list.component.spec.ts | 28 ++ .../dataservices-list.component.ts | 68 ++++ .../dataservices-routing.module.ts | 38 +++ .../dataservices/dataservices.component.css | 57 ++++ .../dataservices/dataservices.component.html | 107 ++++++ .../dataservices.component.spec.ts | 115 +++++++ .../dataservices/dataservices.component.ts | 252 ++++++++++++++ .../app/dataservices/dataservices.module.ts | 59 ++++ .../dataservices/shared/dataservice.model.ts | 89 +++++ .../shared/dataservice.service.spec.ts | 18 + .../shared/dataservice.service.ts | 80 +++++ .../shared/dataservices-constants.ts | 20 ++ .../shared/mock-dataservice.service.ts | 55 +++ .../shared/new-dataservice.model.ts | 60 ++++ ngapp/tsconfig.json | 1 + 38 files changed, 1887 insertions(+), 6 deletions(-) create mode 100644 ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css create mode 100644 ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html create mode 100644 ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts create mode 100644 ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts create mode 100644 ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.css create mode 100644 ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html create mode 100644 ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts create mode 100644 ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.ts create mode 100644 ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css create mode 100644 ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html create mode 100644 ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts create mode 100644 ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts create mode 100644 ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css create mode 100644 ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html create mode 100644 ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts create mode 100644 ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts create mode 100644 ngapp/src/app/dataservices/dataservices-routing.module.ts create mode 100644 ngapp/src/app/dataservices/dataservices.component.css create mode 100644 ngapp/src/app/dataservices/dataservices.component.html create mode 100644 ngapp/src/app/dataservices/dataservices.component.spec.ts create mode 100644 ngapp/src/app/dataservices/dataservices.component.ts create mode 100644 ngapp/src/app/dataservices/dataservices.module.ts create mode 100644 ngapp/src/app/dataservices/shared/dataservice.model.ts create mode 100644 ngapp/src/app/dataservices/shared/dataservice.service.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/dataservice.service.ts create mode 100644 ngapp/src/app/dataservices/shared/dataservices-constants.ts create mode 100644 ngapp/src/app/dataservices/shared/mock-dataservice.service.ts create mode 100644 ngapp/src/app/dataservices/shared/new-dataservice.model.ts diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts index b3cf601f..c27f3395 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts @@ -239,6 +239,7 @@ export class AddActivityWizardComponent implements OnInit { self.step2bConfig.nextEnabled = false; }, (error) => { + self.logger.error("[AddActivityWizardComponent] Error: %o", error); self.createComplete = true; self.createSuccessful = false; } diff --git a/ngapp/src/app/app-routing.module.ts b/ngapp/src/app/app-routing.module.ts index 40fae7ab..b49afffa 100644 --- a/ngapp/src/app/app-routing.module.ts +++ b/ngapp/src/app/app-routing.module.ts @@ -20,6 +20,7 @@ import { NgModule } from "@angular/core"; import { RouterModule } from "@angular/router"; import { Routes } from "@angular/router"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { environment } from "@environments/environment"; import { PageNotFoundComponent } from "@shared/page-not-found/page-not-found.component"; @@ -27,6 +28,7 @@ const appRoutes: Routes = [ { path: "", redirectTo: environment.homePagePath, pathMatch: "full" }, { path: ConnectionsConstants.connectionsRootRoute, loadChildren: "@connections/connections.module#ConnectionsModule" }, { path: ActivitiesConstants.activitiesRootRoute, loadChildren: "@activities/activities.module#ActivitiesModule" }, + { path: DataservicesConstants.dataservicesRootRoute, loadChildren: "@dataservices/dataservices.module#DataservicesModule" }, { path: "**", component: PageNotFoundComponent }, // always last ]; diff --git a/ngapp/src/app/app.module.ts b/ngapp/src/app/app.module.ts index f1acc022..ffe2ca9d 100644 --- a/ngapp/src/app/app.module.ts +++ b/ngapp/src/app/app.module.ts @@ -25,6 +25,8 @@ import { AppComponent } from "@app/app.component"; import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; +import { DataservicesModule } from "@dataservices/dataservices.module"; +import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.module"; import { SharedModule } from "@shared/shared.module"; @NgModule({ @@ -36,10 +38,12 @@ import { SharedModule } from "@shared/shared.module"; BrowserModule, ConnectionsModule, CoreModule, + DataservicesModule, RouterModule, SharedModule, ActivitiesRoutingModule, ConnectionsRoutingModule, + DataservicesRoutingModule, AppRoutingModule // last so its routes are check after all other routes ], providers: [], diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index 5b907fe5..aecaace3 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -285,6 +285,7 @@ export class AddConnectionWizardComponent implements OnInit { self.step3bConfig.nextEnabled = false; }, (error) => { + self.logger.error("[AddConnectionWizardComponent] Error: %o", error); self.createComplete = true; self.createSuccessful = false; } diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index 983950e3..250c1ea7 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -1,8 +1,8 @@
    -
  • -
  • +
  • +
  • diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index 757dfb21..99eb20d0 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -107,7 +107,7 @@ describe("ConnectionsComponent", () => { component.filterConnections(); fixture.detectChanges(); - // Now expect 0 activities match + // Now expect 0 connections match connections = component.filteredConnections; expect(connections.length).toEqual(0); }); diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index 293020e8..0e95798c 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -15,7 +15,6 @@ * limitations under the License. */ -import { Injectable } from "@angular/core"; import { Headers, RequestOptions, Response } from "@angular/http"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/throw"; diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html index e20bf9da..80963454 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html @@ -6,6 +6,11 @@
    Activities
    +
    + +
    DataServices
    +
    diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index fe3094d6..275511d7 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -19,13 +19,14 @@ import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { Component, OnInit } from "@angular/core"; import { NavigationEnd, Router } from "@angular/router"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { LoggerService } from "@core/logger.service"; /** * Models the menus off the main left-hand vertical nav. */ enum VerticalNavType { - Home, Activities, Connections + Home, Activities, Connections, Dataservices } @Component({ @@ -79,7 +80,18 @@ export class VerticalNavComponent implements OnInit { }); } - /** + /** + * Called when the user clicks the vertical menu Dataservices item. + */ + public onDataservicesClick(): void { + this.currentMenu = VerticalNavType.Dataservices; + const link: string[] = [ DataservicesConstants.dataservicesRootPath ]; + this.router.navigate(link).then(() => { + // nothing to do + }); + } + + /** * Called when the user clicks the vertical menu shade (the grey shaded area behind the submenu div that * is displayed when a sub-menu is selected). Clicking the shade makes the sub-menu div go away. */ diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css new file mode 100644 index 00000000..0f0ecbda --- /dev/null +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css @@ -0,0 +1,5 @@ +.wizard-pf-failed-icon { + color: #9c3535; + font-size: 67px; + line-height: 67px; +} diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html new file mode 100644 index 00000000..51c22fa3 --- /dev/null +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html @@ -0,0 +1,78 @@ + + + + + +

    {{ step1InstructionMessage }}

    +
    +
    +
    + +
    + +
    + +
    {{ getBasicPropertyErrorMessage("name") }}
    +
    +
    +
    + +
    + +
    {{ getBasicPropertyErrorMessage("connection") }}
    +
    +
    + +
    + + + + + + +

    {{ step2InstructionMessage }}

    +

    Dataservice Properties:

    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    + +
    +
    +

    Creation in progress

    +

    The dataservice is being created.

    +
    + +
    +
    +

    Creation was successful

    +

    The dataservice was created successfully. Click on the button to see all dataservices.

    + View All Dataservices +
    + +
    +
    +

    Creation failed

    +

    The dataservice creation failed. Correct any properties and retry.

    +
    +
    +
    +
    +
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts new file mode 100644 index 00000000..be3c7a2d --- /dev/null +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -0,0 +1,42 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { RouterTestingModule } from "@angular/router/testing"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { CoreModule } from "@core/core.module"; +import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; +import { PropertyFormComponent } from "@shared/property-form/property-form.component"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { AddDataserviceWizardComponent } from "./add-dataservice-wizard.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; + +describe("AddDataserviceWizardComponent", () => { + let component: AddDataserviceWizardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], + declarations: [ AddDataserviceWizardComponent, PropertyFormComponent, PropertyFormPropertyComponent ], + providers: [ + { provide: DataserviceService, useClass: MockDataserviceService }, + { provide: ConnectionService, useClass: MockConnectionService }, + ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddDataserviceWizardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts new file mode 100644 index 00000000..cc347b06 --- /dev/null +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -0,0 +1,321 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Component, + OnInit, + ViewChild, + ViewEncapsulation, +} from "@angular/core"; + +import { FormControl, FormGroup } from "@angular/forms"; +import { AbstractControl } from "@angular/forms"; +import { Validators } from "@angular/forms"; +import { Router } from "@angular/router"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; +import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; +import { LoggerService } from "@core/logger.service"; +import { WizardComponent } from "patternfly-ng"; +import { WizardEvent } from "patternfly-ng"; +import { WizardStepConfig } from "patternfly-ng"; +import { WizardConfig } from "patternfly-ng"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-add-dataservice-wizard", + templateUrl: "./add-dataservice-wizard.component.html" +}) +export class AddDataserviceWizardComponent implements OnInit { + public readonly dataserviceSummaryLink: string = DataservicesConstants.dataservicesRootPath; + + // Wizard Config + public wizardConfig: WizardConfig; + + public basicPropertyForm: FormGroup; + public createComplete = true; + public createSuccessful = false; + public connectionsLoaded = false; + + // Wizard Step 1 + public step1Config: WizardStepConfig; + + // Wizard Step 2 + public step2Config: WizardStepConfig; + public step2aConfig: WizardStepConfig; + public step2bConfig: WizardStepConfig; + + @ViewChild("wizard") public wizard: WizardComponent; + + private connectionService: ConnectionService; + private dataserviceService: DataserviceService; + private allConnections: Connection[] = []; + private logger: LoggerService; + private router: Router; + + constructor( router: Router, connectionService: ConnectionService, dataserviceService: DataserviceService, logger: LoggerService ) { + this.connectionService = connectionService; + this.dataserviceService = dataserviceService; + this.router = router; + this.logger = logger; + this.createBasicPropertyForm(); + } + + /* + * Initialization + */ + public ngOnInit(): void { + // Step 1 - Basic Properties + this.step1Config = { + id: "step1", + priority: 0, + title: "Basic Properties", + allowClickNav: false + } as WizardStepConfig; + + // Step 2 - Review and Create + this.step2Config = { + id: "step2", + priority: 0, + title: "Review and Create", + allowClickNav: false + } as WizardStepConfig; + this.step2aConfig = { + id: "step2a", + priority: 0, + title: "Review", + allowClickNav: false + } as WizardStepConfig; + this.step2bConfig = { + id: "step2b", + priority: 1, + title: "Create", + allowClickNav: false + } as WizardStepConfig; + + // Wizard Configuration + this.wizardConfig = { + embedInPage: true, + loadingTitle: "Add Dataservice Wizard loading", + loadingSecondaryInfo: "Please wait for the wizard to finish loading...", + title: "Add Dataservice", + contentHeight: "500px" + } as WizardConfig; + + // Load the connections for the first step + this.connectionsLoaded = false; + const self = this; + this.connectionService + .getAllConnections() + .subscribe( + (conns) => { + self.allConnections = conns; + self.connectionsLoaded = true; + }, + (error) => { + self.logger.error("[AddDataserviceWizardComponent] Error getting connections: %o", error); + } + ); + + this.setNavAway(false); + } + + // ---------------- + // Public Methods + // ---------------- + /* + * Return the name valid state + */ + public get nameValid(): boolean { + return this.basicPropertyForm.controls["name"].valid; + } + + /* + * Return the connection valid state + */ + public get connectionValid(): boolean { + return this.basicPropertyForm.controls["connection"].valid; + } + + /* + * Step 1 instruction message + */ + public get step1InstructionMessage(): string { + if (!this.nameValid) { + return "Please enter a name for the Dataservice"; + } else if (!this.connectionValid) { + return "Please choose a connection for the Dataservice"; + } else { + return "When finished entering properties, click Next to continue"; + } + } + + /* + * Step 2 instruction message + */ + public get step2InstructionMessage(): string { + return "Review your entries. When finished, click Create to create the Dataservice"; + } + + /* + * Return the name error message if invalid + */ + public getBasicPropertyErrorMessage( name: string ): string { + const control: AbstractControl = this.basicPropertyForm.controls[name]; + if (control.invalid) { + // The first error found is returned + if (control.errors.required) { + return name + " is a required property"; + } + } + return ""; + } + + public nextClicked($event: WizardEvent): void { + // When leaving page 1, load the driver-specific property definitions + if ($event.step.config.id === "step1") { + } + } + + public cancelClicked($event: WizardEvent): void { + const link: string[] = [ DataservicesConstants.dataservicesRootPath ]; + this.logger.log("[AddDataserviceWizardComponent] Navigating to: %o", link); + this.router.navigate(link).then(() => { + // nothing to do + }); + } + + /* + * Create the Dataservice via komodo REST interface, + * using the currently entered properties + */ + public createDataservice(): void { + this.createComplete = false; + this.wizardConfig.done = true; + + const dataservice: NewDataservice = new NewDataservice(); + + // Dataservice basic properties from step 1 + dataservice.setId(this.dataserviceName); + + const self = this; + this.dataserviceService + .createDataservice(dataservice) + .subscribe( + () => { + self.createComplete = true; + self.createSuccessful = true; + self.step2bConfig.nextEnabled = false; + }, + (error) => { + self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); + self.createComplete = true; + self.createSuccessful = false; + } + ); + } + + public stepChanged($event: WizardEvent): void { + if ($event.step.config.id === "step1") { + this.updatePage1ValidStatus(); + this.wizardConfig.nextTitle = "Next >"; + } else if ($event.step.config.id === "step2a") { + this.wizardConfig.nextTitle = "Create"; + } else if ($event.step.config.id === "step2b") { + // Note: The next button is not disabled by default when wizard is done + this.step2Config.nextEnabled = false; + } else { + this.wizardConfig.nextTitle = "Next >"; + } + } + + /** + * Handler for property form initialization + * @param {boolean} isValid form valid state + */ + public onDetailPropertyInit(isValid: boolean): void { + this.updatePage2ValidStatus(isValid); + } + + /** + * Handler for property form changes + * @param {boolean} isValid form valid state + */ + public onDetailPropertyChanged(isValid: boolean): void { + this.updatePage2ValidStatus(isValid); + } + + /** + * @returns {string} the name of the dataservice + */ + public get dataserviceName(): string { + return this.basicPropertyForm.controls["name"].value; + } + + /** + * @returns {string} the connection name of the dataservice + */ + public get connectionName(): string { + return this.basicPropertyForm.controls["connection"].value; + } + + /* + * Return the array of connection names + */ + public get connectionNames(): string[] { + const connNames: string[] = []; + for ( const conn of this.allConnections ) { + connNames.push(conn.getId()); + } + return connNames.sort(); + } + + // ---------------- + // Private Methods + // ---------------- + + /* + * Create the BasicProperty form (page 1) + */ + private createBasicPropertyForm(): void { + this.basicPropertyForm = new FormGroup({ + name: new FormControl("", Validators.required), + connection: new FormControl("", Validators.required) + }); + // Responds to basic property changes - updates the page status + this.basicPropertyForm.valueChanges.subscribe((val) => { + this.updatePage1ValidStatus( ); + }); + } + + private setNavAway(allow: boolean): void { + this.step1Config.allowNavAway = allow; + } + + private updatePage1ValidStatus( ): void { + this.step1Config.nextEnabled = this.basicPropertyForm.valid; + this.setNavAway(this.step1Config.nextEnabled); + } + + private updatePage2ValidStatus(formValid: boolean): void { + this.step2Config.nextEnabled = formValid; + this.setNavAway(this.step2Config.nextEnabled); + } + +} diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.css b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html new file mode 100644 index 00000000..be280356 --- /dev/null +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html @@ -0,0 +1,18 @@ +
    +
    + +
  • +
  • +
    +
    +
    +
    +

    +
    + +
    + +
    +
    +
    + diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts new file mode 100644 index 00000000..eff5b9f8 --- /dev/null +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -0,0 +1,42 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { RouterTestingModule } from "@angular/router/testing"; +import { AddDataserviceWizardComponent } from "@dataservices/add-dataservice-wizard/add-dataservice-wizard.component"; +import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { AddDataserviceComponent } from "./add-dataservice.component"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; + +describe("AddDataserviceComponent", () => { + let component: AddDataserviceComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], + declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent ], + providers: [ + { provide: DataserviceService, useClass: MockDataserviceService }, + { provide: ConnectionService, useClass: MockConnectionService } + ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddDataserviceComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.ts new file mode 100644 index 00000000..d5b96f24 --- /dev/null +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit } from "@angular/core"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; + +@Component({ + selector: "app-add-dataservice-page", + templateUrl: "./add-dataservice.component.html", + styleUrls: ["./add-dataservice.component.css"] +}) +export class AddDataserviceComponent implements OnInit { + + public readonly dataservicesLink = DataservicesConstants.dataservicesRootPath; + + public pageError: any = ""; + + constructor() { + // Nothing + } + + public ngOnInit(): void { + // Nothing + } + +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css new file mode 100644 index 00000000..64e6b57d --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css @@ -0,0 +1,70 @@ +.container-cards-pf { + padding: 0; + margin-top: 0; +} + +.row-cards-pf { + padding: 0; +} + +.dataservice-card-action-icon { + cursor: pointer; +} + +.dataservice-card-icon { + border: 2px solid #39a5dc; + border-radius: 50%; + padding: 5px; + margin-right: 10px; + width: 32px; +} + +.dataservice-card .dataservice-card-title { + font-size: 16px; + font-weight: bold; +} + +.dataservice-card { + -webkit-transition: background-color 300ms; + -moz-transition: background-color 300ms; + //-ms-transition: background-color 300ms; + -o-transition: background-color 300ms; + transition: background-color 300ms; + height: 160px; +} +.dataservice-card:hover { + background-color: rgb(237, 237, 237); +} + +.dataservice-card.active { + background-color: rgb(221, 234, 255); +} + +/* +.dataservice-description { + font-size: 13px; + overflow-y: auto; +} +*/ + +.dataservice-card .dataservice-tags { + margin-bottom: 8px; +} +.dataservice-card .dataservice-tags .dataservice-tags-label { + font-weight: bold; + margin-right: 5px; +} +.dataservice-card .dataservice-tags /*.dataservice-tag*/ { + margin-right: 5px; + border: 1px solid #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + padding: 2px 4px; +} +.dataservice-card .dataservice-tags /*.dataservice-tag:hover*/ { + cursor: pointer; + background-color: #0088ce; + border-color: #00659c; + color: white; +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html new file mode 100644 index 00000000..98f74c50 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html @@ -0,0 +1,29 @@ +
    +
    + +
    +
    +
    + +

    + + {{ dataservice.getId() }} + +

    +
    + +
    +
    +
    + +
    +
    diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts new file mode 100644 index 00000000..c701242b --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts @@ -0,0 +1,28 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterTestingModule } from "@angular/router/testing"; +import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; + +describe("DataservicesCardsComponent", () => { + let component: DataservicesCardsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ RouterTestingModule ], + declarations: [ DataservicesCardsComponent ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DataservicesCardsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts new file mode 100644 index 00000000..c3aa26d6 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; + +@Component({ + moduleId: module.id, + selector: "app-dataservices-cards", + templateUrl: "dataservices-cards.component.html", + styleUrls: ["dataservices-cards.component.css"] +}) +export class DataservicesCardsComponent { + + @Input() public dataservices: Dataservice[]; + @Input() public selectedDataservices: Dataservice[]; + @Output() public dataserviceSelected: EventEmitter = new EventEmitter(); + @Output() public dataserviceDeselected: EventEmitter = new EventEmitter(); + @Output() public tagSelected: EventEmitter = new EventEmitter(); + @Output() public deleteDataservice: EventEmitter = new EventEmitter(); + + /** + * Constructor. + */ + constructor() { + // nothing to do + } + + public toggleDataserviceSelected(dataservice: Dataservice): void { + if (this.isSelected(dataservice)) { + this.dataserviceDeselected.emit(dataservice); + } else { + this.dataserviceSelected.emit(dataservice); + } + } + + public isSelected(dataservice: Dataservice): boolean { + return this.selectedDataservices.indexOf(dataservice) !== -1; + } + + public onDeleteDataservice(dataserviceName: string): void { + this.deleteDataservice.emit(dataserviceName); + } + + public onSelectTag(tag: string, event: MouseEvent): void { + event.stopPropagation(); + event.preventDefault(); + this.tagSelected.emit(tag); + } + +} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css new file mode 100644 index 00000000..e84a38a3 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css @@ -0,0 +1,39 @@ +.list-view-pf-main-info { + padding-bottom: 5px; + padding-top: 5px; +} +.list-group-item { + -webkit-transition: background-color 300ms; + -moz-transition: background-color 300ms; + //-ms-transition: background-color 300ms; + -o-transition: background-color 300ms; + transition: background-color 300ms; +} +.list-group-item, .list-group-item:first-child { + margin-bottom: 5px; + border-top: 1px solid rgb(57, 165, 220); +} +.list-group-item.active { + background-color: #ffffff; +} + +.list-group-item .dataservice-tags { +} +.list-group-item .dataservice-tags .dataservice-tags-label { + font-weight: bold; + margin-right: 5px; +} +.list-group-item .dataservice-tags /*.dataservice-tag*/ { + margin-right: 5px; + border: 1px solid #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + padding: 2px 4px; +} +.list-group-item .dataservice-tags /*.dataservice-tag:hover*/ { + cursor: pointer; + background-color: #0088ce; + border-color: #00659c; + color: white; +} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html new file mode 100644 index 00000000..04e91f78 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -0,0 +1,33 @@ +
    +
    +
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    +
    +
    +
    diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts new file mode 100644 index 00000000..8a5fe78e --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts @@ -0,0 +1,28 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterTestingModule } from "@angular/router/testing"; +import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; + +describe("DataservicesListComponent", () => { + let component: DataservicesListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ RouterTestingModule ], + declarations: [ DataservicesListComponent ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DataservicesListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts new file mode 100644 index 00000000..699d7055 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts @@ -0,0 +1,68 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { Router } from "@angular/router"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; + +@Component({ + moduleId: module.id, + selector: "app-dataservices-list", + templateUrl: "dataservices-list.component.html", + styleUrls: ["dataservices-list.component.css"] +}) +export class DataservicesListComponent { + + @Input() public dataservices: Dataservice[]; + @Input() public selectedDataservices: Dataservice[]; + @Output() public dataserviceSelected: EventEmitter = new EventEmitter(); + @Output() public dataserviceDeselected: EventEmitter = new EventEmitter(); + @Output() public tagSelected: EventEmitter = new EventEmitter(); + @Output() public deleteDataservice: EventEmitter = new EventEmitter(); + + private router: Router; + + /** + * Constructor. + */ + constructor(router: Router) { + this.router = router; + } + + public toggleDataserviceSelected(dataservice: Dataservice): void { + if (this.isSelected(dataservice)) { + this.dataserviceDeselected.emit(dataservice); + } else { + this.dataserviceSelected.emit(dataservice); + } + } + + public isSelected(dataservice: Dataservice): boolean { + return this.selectedDataservices.indexOf(dataservice) !== -1; + } + + public onDeleteDataservice(dataserviceName: string): void { + this.deleteDataservice.emit(dataserviceName); + } + + public onSelectTag(tag: string, event: MouseEvent): void { + event.stopPropagation(); + event.preventDefault(); + this.tagSelected.emit(tag); + } + +} diff --git a/ngapp/src/app/dataservices/dataservices-routing.module.ts b/ngapp/src/app/dataservices/dataservices-routing.module.ts new file mode 100644 index 00000000..7494aff7 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-routing.module.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { Routes } from "@angular/router"; +import { AddDataserviceComponent } from "@dataservices/add-dataservice/add-dataservice.component"; +import { DataservicesComponent } from "@dataservices/dataservices.component"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; + +const dataservicesRoutes: Routes = [ + { path: DataservicesConstants.dataservicesRootRoute, component: DataservicesComponent }, + { path: DataservicesConstants.addDataserviceRoute, component: AddDataserviceComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forChild( dataservicesRoutes ) + ], + exports: [ + RouterModule + ] +}) +export class DataservicesRoutingModule {} diff --git a/ngapp/src/app/dataservices/dataservices.component.css b/ngapp/src/app/dataservices/dataservices.component.css new file mode 100644 index 00000000..c3505e40 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices.component.css @@ -0,0 +1,57 @@ +.toolbar-pf { + margin-top: 5px; +} + +.toolbar-pf form { + margin-bottom: 0; +} + +.toolbar-pf-results { + margin-top: 0; +} + +.dataservice-list-items { + margin-top: 10px +} + +.dataservice-list-dataservices .toolbar-pf { + background-color: transparent; +} + +.dataservice-list-dataservices .toolbar-pf .toolbar-pf-results { + background-color: white; +} + +a.clear-filters { + cursor: pointer; +} + +.toolbar-pf-view-selector { + float: right; +} + +.toolbar-pf-view-selector li a { + cursor: pointer; + color: #333; +} + +.toolbar-pf-view-selector li a:hover { + color: #0088ce; +} + +.dataservice-list-items .empty-state { + text-align: center; +} + +.blank-slate-pf { + background-color: white; + width: 50%; + min-width: 500px; + margin-left: auto; + margin-right: auto; + margin-top: 15px; +} + +.dataservice-list-items .none-matched-state .alert { + background-color: white; +} diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html new file mode 100644 index 00000000..7fce43ae --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -0,0 +1,107 @@ +
    + +
    + +
  • +
    +
    + + + +
    +
    +

    Dataservices

    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
      +
    • +
    • +
    +
    +
    +
    +
    +
    {{ filteredDataservices.length }} Dataservices found + (out of {{ + allDataservices.length }} total)
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +

    No Dataservices Found

    +

    + No Dataservices were found - please click below to create a new Dataservice! +

    +
    + +
    +
    +
    +
    +
    + + No Dataservices matched the filter!  Please try changing your filter criteria... +
    +
    + + +
    +
    +
    +
    +
    +

    + Loading Dataservices... +

    +
    +
    +
    +
    +
    + + +
    + + +
    + +
    + +
    + +
    + +

    Do you really want to delete the selected Dataservice?

    +
    diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts new file mode 100644 index 00000000..5f8bbab1 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -0,0 +1,115 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { By } from "@angular/platform-browser"; +import { RouterTestingModule } from "@angular/router/testing"; +import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; +import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; +import { DataservicesComponent } from "@dataservices/dataservices.component"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { ModalModule } from "ngx-bootstrap"; + +describe("DataservicesComponent", () => { + let component: DataservicesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], + declarations: [ DataservicesComponent, DataservicesListComponent, DataservicesCardsComponent ] + }); + + // use mock service + TestBed.overrideComponent( DataservicesComponent, { + set: { + providers: [ + { provide: DataserviceService, useClass: MockDataserviceService }, + ] + } + }); + + fixture = TestBed.createComponent(DataservicesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + })); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); + + it("should have Dataservices Title", () => { + // query for the title

    by CSS element selector + const de = fixture.debugElement.query(By.css("h2")); + const el = de.nativeElement; + expect(el.textContent).toEqual("Dataservices"); + }); + + it("should have Toolbar", () => { + // query for the toolbar by css classname + const de = fixture.debugElement.query(By.css(".toolbar-pf")); + expect(de).toBeDefined(); + }); + + it("should have Dataservices", () => { + // Check component object + const dataservices = component.allDataservices; + expect(dataservices.length).toEqual(3); + + // Check html has the same number of dataservice cards + const cardDebugElems = fixture.debugElement.queryAll(By.css(".dataservice-card-title")); + expect(cardDebugElems).toBeDefined(); + expect(cardDebugElems.length).toEqual(3); + }); + + it("should have initial card layout", () => { + // app-dataservices-cards should be present + let debugEl = fixture.debugElement.query(By.css("app-dataservices-cards")); + const element = debugEl.nativeElement; + expect(element).toBeDefined(); + + // app-dataservices-list should not be present + debugEl = fixture.debugElement.query(By.css("app-dataservices-list")); + expect(debugEl).toBeNull(); + }); + + it("should toggle layout", () => { + // Initial layout should be Card Layout + let cardDebugElem = fixture.debugElement.query(By.css("app-dataservices-cards")); + let listDebugElem = fixture.debugElement.query(By.css("app-dataservices-list")); + expect(cardDebugElem).toBeDefined(); + expect(listDebugElem).toBeNull(); + const cardElem = cardDebugElem.nativeElement; + expect(cardElem).toBeDefined(); + + // Change the layout to ListLayout + component.setListLayout(); + fixture.detectChanges(); + + // Verify that the layout has changed + cardDebugElem = fixture.debugElement.query(By.css("app-dataservices-cards")); + listDebugElem = fixture.debugElement.query(By.css("app-dataservices-list")); + expect(cardDebugElem).toBeNull(); + expect(listDebugElem).toBeDefined(); + const listElem = listDebugElem.nativeElement; + expect(listElem).toBeDefined(); + }); + + it("should filter dataservices", () => { + // Expect 3 dataservices initially. + let dataservices = component.filteredDataservices; + expect(dataservices.length).toEqual(3); + + // Set a name filter which satisfies none of the dataservices + component.nameFilter = "g"; + component.filterDataservices(); + fixture.detectChanges(); + + // Now expect 0 services match + dataservices = component.filteredDataservices; + expect(dataservices.length).toEqual(0); + }); + +}); diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts new file mode 100644 index 00000000..7a9a76d4 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -0,0 +1,252 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, ViewChild } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; +import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; +import { LoggerService } from "@core/logger.service"; +import { ArrayUtils } from "@core/utils/array-utils"; +import { AbstractPageComponent } from "@shared/abstract-page.component"; +import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { IdFilter } from "@shared/id-filter"; +import { LayoutType } from "@shared/layout-type.enum"; +import { SortDirection } from "@shared/sort-direction.enum"; + +@Component({ + moduleId: module.id, + selector: "app-dataservices", + templateUrl: "./dataservices.component.html", + styleUrls: ["./dataservices.component.css"] +}) +export class DataservicesComponent extends AbstractPageComponent { + + public readonly addDataserviceLink: string = DataservicesConstants.addDataservicePath; + + private allServices: Dataservice[] = []; + private filteredServices: Dataservice[] = []; + private selectedServices: Dataservice[] = []; + private dataserviceNameForDelete: string; + private router: Router; + private dataserviceService: DataserviceService; + private filter: IdFilter = new IdFilter(); + private layout: LayoutType = LayoutType.CARD; + private sortDirection: SortDirection = SortDirection.ASC; + + @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; + + constructor(router: Router, route: ActivatedRoute, dataserviceService: DataserviceService, logger: LoggerService) { + super(route, logger); + this.router = router; + this.dataserviceService = dataserviceService; + } + + public loadAsyncPageData(): void { + const self = this; + this.dataserviceService + .getAllDataservices() + .subscribe( + (dataservices) => { + self.allServices = dataservices; + self.filteredServices = this.filterDataservices(); + self.loaded("dataservices"); + }, + (error) => { + self.logger.error("[DataservicesComponent] Error getting dataservices."); + self.error(error); + } + ); + } + + /** + * @returns {boolean} true if dataservices are being represented by cards + */ + public get isCardLayout(): boolean { + return this.layout === LayoutType.CARD; + } + + /** + * @returns {boolean} true if dataservices are being represented by items in a list + */ + public get isListLayout(): boolean { + return this.layout === LayoutType.LIST; + } + + /** + * @returns {boolean} true if sorting dataservice names in ascending order + */ + public get isSortAscending(): boolean { + return this.sortDirection === SortDirection.ASC; + } + + /** + * @returns {boolean} true if sorting dataservice names in descending order + */ + public get isSortDescending(): boolean { + return this.sortDirection === SortDirection.DESC; + } + + /** + * @returns {Dataservice[]} the array of all dataservices + */ + public get allDataservices(): Dataservice[] { + return this.allServices; + } + + /** + * @returns {Dataservice[]} the array of filtered dataservices + */ + public get filteredDataservices(): Dataservice[] { + return this.filteredServices; + } + + /** + * @returns {Dataservice[]} the array of selected dataservices + */ + public get selectedDataservices(): Dataservice[] { + return this.selectedServices; + } + + public onSelected(dataservice: Dataservice): void { + // Only allow one item to be selected + this.selectedServices.shift(); + this.selectedServices.push(dataservice); + } + + public onDeselected(dataservice: Dataservice): void { + // Only one item is selected at a time + this.selectedServices.shift(); + // this.selectedServices.splice(this.selectedServices.indexOf(dataservice), 1); + } + + public onDelete(svcName: string): void { + this.dataserviceNameForDelete = svcName; + this.confirmDeleteDialog.open(); + } + + public isFiltered(): boolean { + return this.allServices.length !== this.filteredServices.length; + } + + public get nameFilter(): string { + return this.filter.getPattern(); + } + + /** + * @param {string} pattern the new pattern for the dataservice name filter (can be null or empty) + */ + public set nameFilter( pattern: string ) { + this.filter.setFilter( pattern ); + } + + public toggleSortDirection(): void { + if (this.sortDirection === SortDirection.ASC) { + this.sortDirection = SortDirection.DESC; + } else { + this.sortDirection = SortDirection.ASC; + } + this.filterDataservices(); + } + + public clearFilters(): void { + this.filter.reset(); + this.filterDataservices(); + } + + public setListLayout(): void { + this.layout = LayoutType.LIST; + } + + public setCardLayout(): void { + this.layout = LayoutType.CARD; + } + + /** + * Called to doDelete all selected APIs. + */ + public onDeleteDataservice(): void { + const selectedService = this.filterDataservices().find((x) => x.getId() === this.dataserviceNameForDelete); + + // const itemsToDelete: Dataservice[] = ArrayUtils.intersect(this.selectedServices, this.filteredServices); + // const selectedService = itemsToDelete[0]; + + const dataserviceToDelete: NewDataservice = new NewDataservice(); + dataserviceToDelete.setId(selectedService.getId()); + + // Note: we can only doDelete selected items that we can see in the UI. + this.logger.log("[DataservicesPageComponent] Deleting selected Dataservice."); + const self = this; + this.dataserviceService + .deleteDataservice(dataserviceToDelete) + .subscribe( + () => { + self.removeDataserviceFromList(selectedService); + const link: string[] = [ DataservicesConstants.dataservicesRootPath ]; + self.logger.log("[CreateApiPageComponent] Navigating to: %o", link); + self.router.navigate(link).then(() => { + // nothing to do + }); + } + ); + } + + /** + * Filters and sorts the list of dataservices based on the user input + */ + public filterDataservices(): Dataservice[] { + // Clear the array first. + this.filteredServices.splice(0, this.filteredServices.length); + for (const dataservice of this.allServices) { + if (this.filter.accepts(dataservice)) { + this.filteredServices.push(dataservice); + } + } + this.filteredServices.sort( (c1: Dataservice, c2: Dataservice) => { + let rval = 0; + + if ( c1.getId() ) { + if ( c2.getId() ) { + // both dataservices have an ID + rval = c1.getId().localeCompare( c2.getId() ); + } else { + // c2 does not have an ID + rval = 1; + } + } else if ( c2.getId() ) { + // c1 does not have an ID and c2 does + rval = -1; + } + + if ( this.sortDirection === SortDirection.DESC ) { + rval *= -1; + } + + return rval; + }); + + this.selectedServices = ArrayUtils.intersect(this.selectedServices, this.filteredServices); + + return this.filteredServices; + } + + private removeDataserviceFromList(dataservice: Dataservice): void { + this.allServices.splice(this.allServices.indexOf(dataservice), 1); + this.filterDataservices(); + } +} diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts new file mode 100644 index 00000000..b9e91610 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { RouterModule } from "@angular/router"; +import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; +import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; +import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.module"; +import { DataservicesComponent } from "@dataservices/dataservices.component"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { CoreModule } from "@core/core.module"; +import { SharedModule } from "@shared/shared.module"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { AddDataserviceWizardComponent } from "./add-dataservice-wizard/add-dataservice-wizard.component"; +import { AddDataserviceComponent } from "./add-dataservice/add-dataservice.component"; +import { LoggerService } from "@core/logger.service"; + +@NgModule({ + imports: [ + DataservicesRoutingModule, + CommonModule, + CoreModule, + SharedModule, + FormsModule, + ReactiveFormsModule, + RouterModule, + PatternFlyNgModule + ], + declarations: [ + DataservicesCardsComponent, + DataservicesComponent, + DataservicesListComponent, + AddDataserviceWizardComponent, + AddDataserviceComponent + ], + providers: [ + DataserviceService, + LoggerService + ], + exports: [ + ] +}) +export class DataservicesModule { } diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts new file mode 100644 index 00000000..53f473bc --- /dev/null +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -0,0 +1,89 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Identifiable } from "@shared/identifiable"; + +export class Dataservice implements Identifiable< string > { + + private keng__id: string; + private tko__description: string; + + /** + * @param {Object} json the JSON representation of a Dataservice + * @returns {Dataservice} the new Dataservice (never null) + */ + public static create( json: object = {} ): Dataservice { + const svc = new Dataservice(); + svc.setValues( json ); + return svc; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the dataservice identifier (can be null) + */ + public getId(): string { + return this.keng__id; + } + + /** + * @returns {string} the dataservice description (can be null) + */ + public getDescription(): string { + return this.tko__description; + } + + /** + * @returns {string} the dataservice dataPath (can be null) + */ + public getDataPath(): string { + return "/tko:komodo/tko:workspace/dsbUser/" + this.keng__id; + } + + /** + * @returns {string} the dataservice type name (can be null) + */ + public getType(): string { + return "Dataservice"; + } + + /** + * @param {string} id the dataservice identifier (optional) + */ + public setId( id?: string ): void { + this.keng__id = id ? id : null; + } + + /** + * @param {string} id the dataservice description (optional) + */ + public setDescription( description?: string ): void { + this.tko__description = description ? description : null; + } + + /** + * Set all object values using the supplied Dataservice json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts b/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts new file mode 100644 index 00000000..ea4f4099 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts @@ -0,0 +1,18 @@ +import { inject, TestBed } from "@angular/core/testing"; +import { HttpModule } from "@angular/http"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { LoggerService } from "@core/logger.service"; + +describe("DataserviceService", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ HttpModule ], + providers: [DataserviceService, LoggerService] + }); + }); + + it("should be created", inject([DataserviceService, LoggerService], + ( service: DataserviceService ) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts new file mode 100644 index 00000000..2d564259 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -0,0 +1,80 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from "@angular/core"; +import { Http } from "@angular/http"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; +import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; +import { ApiService } from "@core/api.service"; +import { LoggerService } from "@core/logger.service"; +import { environment } from "@environments/environment"; +import { Observable } from "rxjs/Observable"; + +@Injectable() +export class DataserviceService extends ApiService { + + private http: Http; + + constructor( http: Http, logger: LoggerService ) { + super( logger ); + this.http = http; + } + + /** + * Get the dataservices from the komodo rest interface + * @returns {Observable} + */ + public getAllDataservices(): Observable { + return this.http + .get(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath, this.getAuthRequestOptions()) + .map((response) => { + const dataservices = response.json(); + return dataservices.map((dataservice) => Dataservice.create( dataservice )); + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Create a dataservice via the komodo rest interface + * @param {NewDataservice} dataservice + * @returns {Observable} + */ + public createDataservice(dataservice: NewDataservice): Observable { + return this.http + .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/" + dataservice.getId(), + dataservice, this.getAuthRequestOptions()) + .map((response) => { + return new Dataservice(); + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Delete a dataservice via the komodo rest interface + * @param {NewDataservice} dataservice + * @returns {Observable} + */ + public deleteDataservice(dataservice: NewDataservice): Observable { + return this.http + .delete(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/" + dataservice.getId(), + this.getAuthRequestOptions()) + .map((response) => null) + .catch( ( error ) => this.handleError( error ) ); + } + +} diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ngapp/src/app/dataservices/shared/dataservices-constants.ts new file mode 100644 index 00000000..3c99d8f4 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/dataservices-constants.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, / + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class DataservicesConstants { + + public static readonly dataservicesRootRoute = "dataservices"; + public static readonly dataservicesRootPath = "/" + DataservicesConstants.dataservicesRootRoute; + + public static readonly addDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/add-dataservice"; + public static readonly addDataservicePath = DataservicesConstants.dataservicesRootPath + "/add-dataservice"; +} diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts new file mode 100644 index 00000000..2a85806c --- /dev/null +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -0,0 +1,55 @@ +import { Injectable } from "@angular/core"; +import { Http } from "@angular/http"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; +import { LoggerService } from "@core/logger.service"; +import "rxjs/add/observable/of"; +import "rxjs/add/observable/throw"; +import "rxjs/add/operator/catch"; +import "rxjs/add/operator/map"; +import { Observable } from "rxjs/Observable"; + +@Injectable() +export class MockDataserviceService extends DataserviceService { + + private newDataservice = new NewDataservice(); + private serv1 = new Dataservice(); + private serv2 = new Dataservice(); + private serv3 = new Dataservice(); + private services: Dataservice[] = [this.serv1, this.serv2, this.serv3]; + + constructor( http: Http, logger: LoggerService ) { + super(http, logger); + this.serv1.setId("serv1"); + this.serv2.setId("serv2"); + this.serv3.setId("serv3"); + } + + /** + * Get the dataservices from the komodo rest interface + * @returns {Observable} + */ + public getAllDataservices(): Observable { + return Observable.of(this.services); + } + + /** + * Create a dataservice via the komodo rest interface + * @param {NewDataservice} dataservice + * @returns {Observable} + */ + public createDataservice(dataservice: NewDataservice): Observable { + return Observable.of(this.newDataservice); + } + + /** + * Delete a dataservice via the komodo rest interface + * @param {NewDataservice} dataservice + * @returns {Observable} + */ + public deleteDataservice(dataservice: NewDataservice): Observable { + return Observable.of(this.newDataservice); + } + +} diff --git a/ngapp/src/app/dataservices/shared/new-dataservice.model.ts b/ngapp/src/app/dataservices/shared/new-dataservice.model.ts new file mode 100644 index 00000000..499b6c27 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/new-dataservice.model.ts @@ -0,0 +1,60 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class NewDataservice { + + private keng__id: string; + private keng__dataPath: string; + private keng__kType: string; + private tko__description: string; + + /** + * Constructor + */ + constructor() { + this.keng__kType = "Dataservice"; + } + + /** + * @returns {string} the dataservice name (can be null) + */ + public getId(): string { + return this.keng__id; + } + + /** + * @returns {string} the dataservice description (can be null) + */ + public getDescription(): string { + return this.tko__description; + } + + /** + * @param {string} name the dataservice name + */ + public setId( name: string ): void { + this.keng__id = name; + this.keng__dataPath = "/tko:komodo/tko:workspace/dsbUser/" + name; + } + + /** + * @param {string} description the dataservice description (optional) + */ + public setDescription( description?: string ): void { + this.tko__description = description ? description : null; + } +} diff --git a/ngapp/tsconfig.json b/ngapp/tsconfig.json index 107cad33..ca20e4b5 100644 --- a/ngapp/tsconfig.json +++ b/ngapp/tsconfig.json @@ -7,6 +7,7 @@ "@app/*": ["app/*"], "@connections/*": ["app/connections/*"], "@core/*": ["app/core/*"], + "@dataservices/*": ["app/dataservices/*"], "@environments/*": ["environments/*"], "@shared/*": ["app/shared/*"] }, From 628e569e0bd3345c6020c260a3bdf8b8d074335d Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Wed, 1 Nov 2017 15:57:14 -0500 Subject: [PATCH 038/205] removing activities from the app --- ngapp/src/app/app-routing.module.ts | 2 -- ngapp/src/app/app.module.ts | 4 ---- .../vertical-nav/vertical-nav.component.html | 5 ---- .../vertical-nav/vertical-nav.component.ts | 14 +---------- .../dataservices/shared/dataservice.model.ts | 24 ++++++++++++++++++- 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/ngapp/src/app/app-routing.module.ts b/ngapp/src/app/app-routing.module.ts index b49afffa..e6757aaa 100644 --- a/ngapp/src/app/app-routing.module.ts +++ b/ngapp/src/app/app-routing.module.ts @@ -15,7 +15,6 @@ * limitations under the License. */ -import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { NgModule } from "@angular/core"; import { RouterModule } from "@angular/router"; import { Routes } from "@angular/router"; @@ -27,7 +26,6 @@ import { PageNotFoundComponent } from "@shared/page-not-found/page-not-found.com const appRoutes: Routes = [ { path: "", redirectTo: environment.homePagePath, pathMatch: "full" }, { path: ConnectionsConstants.connectionsRootRoute, loadChildren: "@connections/connections.module#ConnectionsModule" }, - { path: ActivitiesConstants.activitiesRootRoute, loadChildren: "@activities/activities.module#ActivitiesModule" }, { path: DataservicesConstants.dataservicesRootRoute, loadChildren: "@dataservices/dataservices.module#DataservicesModule" }, { path: "**", component: PageNotFoundComponent }, // always last ]; diff --git a/ngapp/src/app/app.module.ts b/ngapp/src/app/app.module.ts index ffe2ca9d..873965d9 100644 --- a/ngapp/src/app/app.module.ts +++ b/ngapp/src/app/app.module.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -import { ActivitiesRoutingModule } from "@activities/activities-routing.module"; -import { ActivitiesModule } from "@activities/activities.module"; import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; import { RouterModule } from "@angular/router"; @@ -34,14 +32,12 @@ import { SharedModule } from "@shared/shared.module"; AppComponent ], imports: [ - ActivitiesModule, BrowserModule, ConnectionsModule, CoreModule, DataservicesModule, RouterModule, SharedModule, - ActivitiesRoutingModule, ConnectionsRoutingModule, DataservicesRoutingModule, AppRoutingModule // last so its routes are check after all other routes diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html index 80963454..946dcee9 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html @@ -1,11 +1,6 @@
    -
    - -
    Activities
    -
    diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index 275511d7..673f6d64 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -15,7 +15,6 @@ * limitations under the License. */ -import { ActivitiesConstants } from "@activities/shared/activities-constants"; import { Component, OnInit } from "@angular/core"; import { NavigationEnd, Router } from "@angular/router"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; @@ -26,7 +25,7 @@ import { LoggerService } from "@core/logger.service"; * Models the menus off the main left-hand vertical nav. */ enum VerticalNavType { - Home, Activities, Connections, Dataservices + Home, Connections, Dataservices } @Component({ @@ -58,17 +57,6 @@ export class VerticalNavComponent implements OnInit { }); } - /** - * Called when the user clicks the vertical menu Activities item. - */ - public onActivitiesClick(): void { - this.currentMenu = VerticalNavType.Activities; - const link: string[] = [ ActivitiesConstants.activitiesRootPath ]; - this.router.navigate(link).then(() => { - // nothing to do - }); - } - /** * Called when the user clicks the vertical menu Connections item. */ diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 53f473bc..628fb979 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -36,6 +36,28 @@ export class Dataservice implements Identifiable< string > { // nothing to do } + /** + * See {Identifiable}. + */ + public compareTo( that: Dataservice ): number { + let result = 0; + + if ( this.getId() ) { + if ( that.getId() ) { + // both have an ID + result = this.getId().localeCompare( that.getId() ); + } else { + // thatItem does not have an ID + result = 1; + } + } else if ( that.getId() ) { + // thisItem does not have an ID and thatItem does + result = -1; + } + + return result; + } + /** * @returns {string} the dataservice identifier (can be null) */ @@ -72,7 +94,7 @@ export class Dataservice implements Identifiable< string > { } /** - * @param {string} id the dataservice description (optional) + * @param {string} description the dataservice description (optional) */ public setDescription( description?: string ): void { this.tko__description = description ? description : null; From ae734eee1596a2c46e6469e6660375b9571d665f Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Wed, 1 Nov 2017 16:42:03 -0500 Subject: [PATCH 039/205] Modify Dataservices page to use new name filter - changed dataservices model, html, and component to use new name filter logic - fixed some TSLint warnings and errors --- ngapp/src/app/app.module.ts | 2 +- .../vertical-nav/vertical-nav.component.ts | 8 ++--- .../add-dataservice-wizard.component.spec.ts | 6 ++-- .../add-dataservice-wizard.component.ts | 5 +-- .../add-dataservice.component.spec.ts | 10 +++--- .../dataservices/dataservices.component.html | 2 +- .../dataservices.component.spec.ts | 2 +- .../dataservices/dataservices.component.ts | 31 +++++-------------- .../app/dataservices/dataservices.module.ts | 4 +-- .../dataservices/shared/dataservice.model.ts | 18 +++++++++++ .../shared/dataservice.service.spec.ts | 2 +- .../shared/dataservice.service.ts | 4 +-- .../shared/mock-dataservice.service.ts | 2 +- 13 files changed, 49 insertions(+), 47 deletions(-) diff --git a/ngapp/src/app/app.module.ts b/ngapp/src/app/app.module.ts index 873965d9..a5548801 100644 --- a/ngapp/src/app/app.module.ts +++ b/ngapp/src/app/app.module.ts @@ -23,8 +23,8 @@ import { AppComponent } from "@app/app.component"; import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; -import { DataservicesModule } from "@dataservices/dataservices.module"; import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.module"; +import { DataservicesModule } from "@dataservices/dataservices.module"; import { SharedModule } from "@shared/shared.module"; @NgModule({ diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index 673f6d64..1ef63974 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -18,8 +18,8 @@ import { Component, OnInit } from "@angular/core"; import { NavigationEnd, Router } from "@angular/router"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; -import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { LoggerService } from "@core/logger.service"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; /** * Models the menus off the main left-hand vertical nav. @@ -80,9 +80,9 @@ export class VerticalNavComponent implements OnInit { } /** - * Called when the user clicks the vertical menu shade (the grey shaded area behind the submenu div that - * is displayed when a sub-menu is selected). Clicking the shade makes the sub-menu div go away. - */ + * Called when the user clicks the vertical menu shade (the grey shaded area behind the submenu div that + * is displayed when a sub-menu is selected). Clicking the shade makes the sub-menu div go away. + */ private onShadeClick(): void { /* this.subMenuOut = false; diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index be3c7a2d..187953c6 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -2,15 +2,15 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { CoreModule } from "@core/core.module"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; -import { CoreModule } from "@core/core.module"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard.component"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { MockConnectionService } from "@connections/shared/mock-connection.service"; describe("AddDataserviceWizardComponent", () => { let component: AddDataserviceWizardComponent; diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index cc347b06..8f55b84e 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -23,15 +23,15 @@ import { } from "@angular/core"; import { FormControl, FormGroup } from "@angular/forms"; -import { AbstractControl } from "@angular/forms"; import { Validators } from "@angular/forms"; +import { AbstractControl } from "@angular/forms"; import { Router } from "@angular/router"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; +import { LoggerService } from "@core/logger.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; -import { LoggerService } from "@core/logger.service"; import { WizardComponent } from "patternfly-ng"; import { WizardEvent } from "patternfly-ng"; import { WizardStepConfig } from "patternfly-ng"; @@ -190,6 +190,7 @@ export class AddDataserviceWizardComponent implements OnInit { public nextClicked($event: WizardEvent): void { // When leaving page 1, load the driver-specific property definitions if ($event.step.config.id === "step1") { + // TODO implement nextClicked } } diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index eff5b9f8..e24a7a6c 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -2,15 +2,15 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; -import { AddDataserviceWizardComponent } from "@dataservices/add-dataservice-wizard/add-dataservice-wizard.component"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; +import { AddDataserviceWizardComponent } from "@dataservices/add-dataservice-wizard/add-dataservice-wizard.component"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceComponent } from "./add-dataservice.component"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { MockConnectionService } from "@connections/shared/mock-connection.service"; describe("AddDataserviceComponent", () => { let component: AddDataserviceComponent; diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 7fce43ae..a5d81858 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -14,7 +14,7 @@

    Dataservices

    -
    +
    diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index 5f8bbab1..6b4f2ec6 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -3,12 +3,12 @@ import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; import { By } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; +import { CoreModule } from "@core/core.module"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; import { DataservicesComponent } from "@dataservices/dataservices.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; -import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { ModalModule } from "ngx-bootstrap"; diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 7a9a76d4..32ba59df 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -17,12 +17,12 @@ import { Component, ViewChild } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; +import { LoggerService } from "@core/logger.service"; +import { ArrayUtils } from "@core/utils/array-utils"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; -import { LoggerService } from "@core/logger.service"; -import { ArrayUtils } from "@core/utils/array-utils"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { IdFilter } from "@shared/id-filter"; @@ -153,6 +153,7 @@ export class DataservicesComponent extends AbstractPageComponent { */ public set nameFilter( pattern: string ) { this.filter.setFilter( pattern ); + this.filterDataservices(); } public toggleSortDirection(): void { @@ -212,34 +213,16 @@ export class DataservicesComponent extends AbstractPageComponent { public filterDataservices(): Dataservice[] { // Clear the array first. this.filteredServices.splice(0, this.filteredServices.length); + + // filter for (const dataservice of this.allServices) { if (this.filter.accepts(dataservice)) { this.filteredServices.push(dataservice); } } - this.filteredServices.sort( (c1: Dataservice, c2: Dataservice) => { - let rval = 0; - - if ( c1.getId() ) { - if ( c2.getId() ) { - // both dataservices have an ID - rval = c1.getId().localeCompare( c2.getId() ); - } else { - // c2 does not have an ID - rval = 1; - } - } else if ( c2.getId() ) { - // c1 does not have an ID and c2 does - rval = -1; - } - - if ( this.sortDirection === SortDirection.DESC ) { - rval *= -1; - } - - return rval; - }); + // sort + Dataservice.sort( this.filteredDataservices, this.sortDirection ); this.selectedServices = ArrayUtils.intersect(this.selectedServices, this.filteredServices); return this.filteredServices; diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index b9e91610..ddb71f41 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -19,17 +19,17 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; +import { CoreModule } from "@core/core.module"; +import { LoggerService } from "@core/logger.service"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.module"; import { DataservicesComponent } from "@dataservices/dataservices.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { CoreModule } from "@core/core.module"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard/add-dataservice-wizard.component"; import { AddDataserviceComponent } from "./add-dataservice/add-dataservice.component"; -import { LoggerService } from "@core/logger.service"; @NgModule({ imports: [ diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 628fb979..764c28d5 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -16,6 +16,7 @@ */ import { Identifiable } from "@shared/identifiable"; +import { SortDirection } from "@shared/sort-direction.enum"; export class Dataservice implements Identifiable< string > { @@ -32,6 +33,23 @@ export class Dataservice implements Identifiable< string > { return svc; } + /** + * @param {Dataservice[]} dataservices the dataservices being sorted + * @param {SortDirection} sortDirection the sort direction + */ + public static sort( dataservices: Dataservice[], + sortDirection: SortDirection ): void { + dataservices.sort( ( thisDataservice: Dataservice, thatDataservice: Dataservice ) => { + const result = thisDataservice.compareTo( thatDataservice ); + + if ( sortDirection === SortDirection.DESC ) { + return result * -1; + } + + return result; + } ); + } + constructor() { // nothing to do } diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts b/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts index ea4f4099..2660f714 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts @@ -1,7 +1,7 @@ import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { LoggerService } from "@core/logger.service"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; describe("DataserviceService", () => { beforeEach(() => { diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 2d564259..c6565e96 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -17,11 +17,11 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; +import { ApiService } from "@core/api.service"; +import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; -import { ApiService } from "@core/api.service"; -import { LoggerService } from "@core/logger.service"; import { environment } from "@environments/environment"; import { Observable } from "rxjs/Observable"; diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 2a85806c..c95ee5d9 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -1,9 +1,9 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; +import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; -import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; From 2cea7d5be3b836dcd4514e21357b9f8bd2aca770 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 2 Nov 2017 14:07:39 -0500 Subject: [PATCH 040/205] Improve error handling --- .../app/activities/activities.component.ts | 6 ++- .../add-activity-wizard.component.html | 20 ++++++++-- .../add-activity-wizard.component.ts | 19 ++++++--- .../app/activities/shared/activity.service.ts | 25 ------------ .../add-connection-wizard.component.html | 40 ++++++++++++++++--- .../add-connection-wizard.component.ts | 39 +++++++++++------- .../app/connections/connections.component.ts | 14 +++---- .../connections/shared/connection.service.ts | 18 +++++---- .../shared/mock-connection.service.ts | 14 +++---- .../add-dataservice-wizard.component.html | 20 ++++++++-- .../add-dataservice-wizard.component.ts | 24 +++++++---- .../dataservices/dataservices.component.ts | 14 +++---- .../shared/dataservice.service.ts | 18 +++++---- .../shared/mock-dataservice.service.ts | 15 ++++--- .../src/app/shared/abstract-page.component.ts | 11 ++++- 15 files changed, 181 insertions(+), 116 deletions(-) diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index 3aa3afc9..ff9fabf4 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -72,8 +72,7 @@ export class ActivitiesComponent extends AbstractPageComponent { self.loaded("activities"); }, (error) => { - self.logger.error("[ActivitiesComponent] Error getting activities."); - self.error(error); + self.error(error, "Error getting activities"); } ); } @@ -224,6 +223,9 @@ export class ActivitiesComponent extends AbstractPageComponent { self.router.navigate(link).then(() => { // nothing to do }); + }, + (error) => { + self.error(error, "Error deleting the activity"); } ); } diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.html b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.html index d1c97090..38d9b58d 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.html +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.html @@ -7,11 +7,25 @@ -

    {{ step1InstructionMessage }}

    -
    +
    - + +
    +
    +

    + + Step Initialization Error +

    +
    +
    +

    + Could not load the connections. Please Try relaunching the wizard or check the console log. +

    +
    +
    +

    {{ step1InstructionMessage }}

    +
    diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts index c27f3395..71d5532c 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts @@ -41,7 +41,8 @@ import { WizardComponent } from "patternfly-ng"; @Component({ encapsulation: ViewEncapsulation.None, selector: "app-add-activity-wizard", - templateUrl: "./add-activity-wizard.component.html" + templateUrl: "./add-activity-wizard.component.html", + styleUrls: ["./add-activity-wizard.component.css"] }) export class AddActivityWizardComponent implements OnInit { public readonly activitySummaryLink: string = ActivitiesConstants.activitiesRootPath; @@ -52,7 +53,8 @@ export class AddActivityWizardComponent implements OnInit { public basicPropertyForm: FormGroup; public createComplete = true; public createSuccessful = false; - public connectionsLoaded = false; + public connectionsLoading = true; + public connectionsLoadSuccess = false; // Wizard Step 1 public step1Config: WizardStepConfig; @@ -116,21 +118,26 @@ export class AddActivityWizardComponent implements OnInit { loadingTitle: "Add Activity Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", title: "Add Activity", - contentHeight: "500px" + contentHeight: "500px", + done: false } as WizardConfig; // Load the connections for the first step - this.connectionsLoaded = false; + this.connectionsLoading = true; + this.connectionsLoadSuccess = false; const self = this; this.connectionService .getAllConnections() .subscribe( (conns) => { self.allConnections = conns; - self.connectionsLoaded = true; + self.connectionsLoading = false; + self.connectionsLoadSuccess = true; }, (error) => { self.logger.error("[AddActivityWizardComponent] Error getting connections: %o", error); + self.connectionsLoading = false; + self.connectionsLoadSuccess = false; } ); @@ -216,7 +223,6 @@ export class AddActivityWizardComponent implements OnInit { */ public createActivity(): void { this.createComplete = false; - this.wizardConfig.done = true; const activity: NewActivity = new NewActivity(); @@ -242,6 +248,7 @@ export class AddActivityWizardComponent implements OnInit { self.logger.error("[AddActivityWizardComponent] Error: %o", error); self.createComplete = true; self.createSuccessful = false; + self.step2bConfig.nextEnabled = false; } ); } diff --git a/ngapp/src/app/activities/shared/activity.service.ts b/ngapp/src/app/activities/shared/activity.service.ts index 1ce32055..18bc7305 100644 --- a/ngapp/src/app/activities/shared/activity.service.ts +++ b/ngapp/src/app/activities/shared/activity.service.ts @@ -44,15 +44,6 @@ export class ActivityService extends ApiService { activities = []; } return Observable.of(this.convertObjectArray(activities)); - /* - return this.http - .get(komodoWorkspaceUrl + '/activities', this.getAuthRequestOptions()) - .map(response => { - const activities = response.json(); - return activities.map((activity) => {const activ = new Activity(); activ.setValues(activity); return activ; }); - }) - .catch(this.handleError); - */ } /** @@ -73,16 +64,7 @@ export class ActivityService extends ApiService { activities.push(act); localStorage.setItem("activities", JSON.stringify(activities)); - // TODO implement createActivity() return Observable.of(activity); - /* - return this.http - .post(komodoWorkspaceUrl + '/activities/' + activity.name, activity, this.getAuthRequestOptions()) - .map(response => { - return new Activity(); - }) - .catch(this.handleError); - */ } /** @@ -100,13 +82,6 @@ export class ActivityService extends ApiService { localStorage.setItem("activities", JSON.stringify(activities)); - // TODO implement deleteActivity() - /* - return this.http - .doDelete(komodoWorkspaceUrl + '/activities/' + activity.name, this.getAuthRequestOptions()) - .map(response => null) - .catch(this.handleError); - */ return Observable.of(null); } diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html index c24c7270..db4d0ce1 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html @@ -7,11 +7,25 @@ -

    {{ step1InstructionMessage }}

    -
    +
    - + +
    +
    +

    + + Step Initialization Error +

    +
    +
    +

    + Could not load the connection types. Please Try relaunching the wizard or check the console log. +

    +
    +
    +

    {{ step1InstructionMessage }}

    +
    @@ -43,11 +57,25 @@

    {{ step1InstructionMessage }}

    -

    {{ step2InstructionMessage }}

    -
    +
    -
    + +
    +
    +

    + + Step Initialization Error +

    +
    +
    +

    + Could not load the detail properties. Please Try relaunching the wizard or check the console log. +

    +
    +
    +

    {{ step2InstructionMessage }}

    +
    diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index aecaace3..5b864442 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -41,7 +41,8 @@ import { WizardConfig } from "patternfly-ng"; @Component({ encapsulation: ViewEncapsulation.None, selector: "app-add-connection-wizard", - templateUrl: "./add-connection-wizard.component.html" + templateUrl: "./add-connection-wizard.component.html", + styleUrls: ["./add-connection-wizard.component.css"] }) export class AddConnectionWizardComponent implements OnInit { public readonly connectionSummaryLink: string = ConnectionsConstants.connectionsRootPath; @@ -52,10 +53,12 @@ export class AddConnectionWizardComponent implements OnInit { public basicPropertyForm: FormGroup; public createComplete = true; public createSuccessful = false; - public detailPropertiesLoaded = false; + public detailPropertiesLoading = true; + public detailPropertiesLoadSuccess = false; public detailPropertiesLoadedType = ""; public requiredPropValues: Array<[string, string]> = []; - public templatesLoaded = false; + public templatesLoading = true; + public templatesLoadSuccess = false; // Wizard Step 1 public step1Config: WizardStepConfig; @@ -130,21 +133,26 @@ export class AddConnectionWizardComponent implements OnInit { loadingTitle: "Add Connection Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", title: "Add Connection", - contentHeight: "500px" + contentHeight: "500px", + done: false } as WizardConfig; // Load the templates for the first step - this.templatesLoaded = false; + this.templatesLoading = true; + this.templatesLoadSuccess = true; const self = this; this.connectionService .getConnectionTemplates() .subscribe( (templates) => { self.allTemplates = templates; - self.templatesLoaded = true; + self.templatesLoading = false; + self.templatesLoadSuccess = true; }, (error) => { self.logger.error("[AddConnectionWizardComponent] Error getting templates: %o", error); + self.templatesLoading = false; + self.templatesLoadSuccess = false; } ); @@ -233,7 +241,7 @@ export class AddConnectionWizardComponent implements OnInit { // When leaving page 1, load the driver-specific property definitions if ($event.step.config.id === "step1") { const selectedDriver = this.basicPropertyForm.controls["driver"].value; - if (!this.detailPropertiesLoaded || (this.detailPropertiesLoadedType !== selectedDriver)) { + if (!this.detailPropertiesLoadSuccess || (this.detailPropertiesLoadedType !== selectedDriver)) { this.loadPropertyDefinitions(selectedDriver); } } @@ -261,7 +269,7 @@ export class AddConnectionWizardComponent implements OnInit { */ public createConnection(): void { this.createComplete = false; - this.wizardConfig.done = true; + this.createSuccessful = false; const connection: NewConnection = new NewConnection(); @@ -279,15 +287,16 @@ export class AddConnectionWizardComponent implements OnInit { this.connectionService .createConnection(connection) .subscribe( - () => { + (wasSuccess) => { self.createComplete = true; - self.createSuccessful = true; + self.createSuccessful = wasSuccess; self.step3bConfig.nextEnabled = false; }, (error) => { self.logger.error("[AddConnectionWizardComponent] Error: %o", error); self.createComplete = true; self.createSuccessful = false; + self.step3bConfig.nextEnabled = false; } ); } @@ -388,7 +397,8 @@ export class AddConnectionWizardComponent implements OnInit { * Load the driver-specific property definitions */ private loadPropertyDefinitions( driverName ): void { - this.detailPropertiesLoaded = false; + this.detailPropertiesLoading = false; + this.detailPropertiesLoadSuccess = false; const self = this; this.connectionService .getConnectionTemplateProperties(driverName) @@ -406,13 +416,14 @@ export class AddConnectionWizardComponent implements OnInit { } self.detailProperties = firstProps.concat(nextProps); - self.detailPropertiesLoaded = true; + self.detailPropertiesLoading = false; + self.detailPropertiesLoadSuccess = true; self.detailPropertiesLoadedType = driverName; }, (error) => { self.logger.error("[AddConnectionWizardComponent] Error: %o", error); - // this.error(error); - self.detailPropertiesLoaded = false; + self.detailPropertiesLoading = false; + self.detailPropertiesLoadSuccess = false; } ); } diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 0352fbc0..24421138 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -20,7 +20,6 @@ import { ActivatedRoute, Router } from "@angular/router"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; -import { NewConnection } from "@connections/shared/new-connection.model"; import { LoggerService } from "@core/logger.service"; import { ArrayUtils } from "@core/utils/array-utils"; import { AbstractPageComponent } from "@shared/abstract-page.component"; @@ -69,8 +68,7 @@ export class ConnectionsComponent extends AbstractPageComponent { self.loaded("connections"); }, (error) => { - self.logger.error("[ConnectionsComponent] Error getting connections."); - self.error(error); + self.error(error, "Error getting connections"); } ); } @@ -192,22 +190,22 @@ export class ConnectionsComponent extends AbstractPageComponent { // const itemsToDelete: Connection[] = ArrayUtils.intersect(this.selectedConns, this.filteredConns); // const selectedConn = itemsToDelete[0]; - const connectionToDelete: NewConnection = new NewConnection(); - connectionToDelete.setName(selectedConn.getId()); - // Note: we can only doDelete selected items that we can see in the UI. this.logger.log("[ConnectionsPageComponent] Deleting selected Connection."); const self = this; this.connectionService - .deleteConnection(connectionToDelete) + .deleteConnection(selectedConn.getId()) .subscribe( - () => { + (wasSuccess) => { self.removeConnectionFromList(selectedConn); const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; self.logger.log("[CreateApiPageComponent] Navigating to: %o", link); self.router.navigate(link).then(() => { // nothing to do }); + }, + (error) => { + self.error(error, "Error deleting the connection"); } ); } diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index 84eac05e..60f2e4c9 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -54,28 +54,30 @@ export class ConnectionService extends ApiService { /** * Create a connection via the komodo rest interface * @param {NewConnection} connection - * @returns {Observable} + * @returns {Observable} */ - public createConnection(connection: NewConnection): Observable { + public createConnection(connection: NewConnection): Observable { return this.http .post(environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath + "/" + connection.getName(), connection, this.getAuthRequestOptions()) .map((response) => { - return new Connection(); + return response.ok; }) .catch( ( error ) => this.handleError( error ) ); } /** * Delete a connection via the komodo rest interface - * @param {NewConnection} connection - * @returns {Observable} + * @param {string} connectionId + * @returns {Observable} */ - public deleteConnection(connection: NewConnection): Observable { + public deleteConnection(connectionId: string): Observable { return this.http - .delete(environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath + "/" + connection.getName(), + .delete(environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath + "/" + connectionId, this.getAuthRequestOptions()) - .map((response) => null) + .map((response) => { + return response.ok; + }) .catch( ( error ) => this.handleError( error ) ); } diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index e4354b84..e896826b 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -42,19 +42,19 @@ export class MockConnectionService extends ConnectionService { /** * Create a connection via the komodo rest interface * @param {NewConnection} connection - * @returns {Observable} + * @returns {Observable} */ - public createConnection(connection: NewConnection): Observable { - return Observable.of(this.newConnection); + public createConnection(connection: NewConnection): Observable { + return Observable.of(true); } /** * Delete a connection via the komodo rest interface - * @param {NewConnection} connection - * @returns {Observable} + * @param {string} connectionId + * @returns {Observable} */ - public deleteConnection(connection: NewConnection): Observable { - return Observable.of(this.newConnection); + public deleteConnection(connectionId: string): Observable { + return Observable.of(true); } /** diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html index 51c22fa3..4cd14c23 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html @@ -7,11 +7,25 @@ -

    {{ step1InstructionMessage }}

    -
    +
    - + +
    +
    +

    + + Step Initialization Error +

    +
    +
    +

    + Could not load the connections. Please Try relaunching the wizard or check the console log. +

    +
    +
    +

    {{ step1InstructionMessage }}

    +
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 8f55b84e..af1ada77 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -40,7 +40,8 @@ import { WizardConfig } from "patternfly-ng"; @Component({ encapsulation: ViewEncapsulation.None, selector: "app-add-dataservice-wizard", - templateUrl: "./add-dataservice-wizard.component.html" + templateUrl: "./add-dataservice-wizard.component.html", + styleUrls: ["./add-dataservice-wizard.component.css"] }) export class AddDataserviceWizardComponent implements OnInit { public readonly dataserviceSummaryLink: string = DataservicesConstants.dataservicesRootPath; @@ -51,7 +52,8 @@ export class AddDataserviceWizardComponent implements OnInit { public basicPropertyForm: FormGroup; public createComplete = true; public createSuccessful = false; - public connectionsLoaded = false; + public connectionsLoading = true; + public connectionsLoadSuccess = false; // Wizard Step 1 public step1Config: WizardStepConfig; @@ -115,21 +117,26 @@ export class AddDataserviceWizardComponent implements OnInit { loadingTitle: "Add Dataservice Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", title: "Add Dataservice", - contentHeight: "500px" + contentHeight: "500px", + done: false } as WizardConfig; // Load the connections for the first step - this.connectionsLoaded = false; + this.connectionsLoading = true; + this.connectionsLoadSuccess = false; const self = this; this.connectionService .getAllConnections() .subscribe( (conns) => { self.allConnections = conns; - self.connectionsLoaded = true; + self.connectionsLoading = false; + self.connectionsLoadSuccess = true; }, (error) => { self.logger.error("[AddDataserviceWizardComponent] Error getting connections: %o", error); + self.connectionsLoading = false; + self.connectionsLoadSuccess = false; } ); @@ -208,7 +215,7 @@ export class AddDataserviceWizardComponent implements OnInit { */ public createDataservice(): void { this.createComplete = false; - this.wizardConfig.done = true; + this.createSuccessful = false; const dataservice: NewDataservice = new NewDataservice(); @@ -219,15 +226,16 @@ export class AddDataserviceWizardComponent implements OnInit { this.dataserviceService .createDataservice(dataservice) .subscribe( - () => { + (wasSuccess) => { self.createComplete = true; - self.createSuccessful = true; + self.createSuccessful = wasSuccess; self.step2bConfig.nextEnabled = false; }, (error) => { self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); self.createComplete = true; self.createSuccessful = false; + self.step2bConfig.nextEnabled = false; } ); } diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 32ba59df..965d34fd 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -22,7 +22,6 @@ import { ArrayUtils } from "@core/utils/array-utils"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; -import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { IdFilter } from "@shared/id-filter"; @@ -68,8 +67,7 @@ export class DataservicesComponent extends AbstractPageComponent { self.loaded("dataservices"); }, (error) => { - self.logger.error("[DataservicesComponent] Error getting dataservices."); - self.error(error); + self.error(error, "Error getting dataservices"); } ); } @@ -187,22 +185,22 @@ export class DataservicesComponent extends AbstractPageComponent { // const itemsToDelete: Dataservice[] = ArrayUtils.intersect(this.selectedServices, this.filteredServices); // const selectedService = itemsToDelete[0]; - const dataserviceToDelete: NewDataservice = new NewDataservice(); - dataserviceToDelete.setId(selectedService.getId()); - // Note: we can only doDelete selected items that we can see in the UI. this.logger.log("[DataservicesPageComponent] Deleting selected Dataservice."); const self = this; this.dataserviceService - .deleteDataservice(dataserviceToDelete) + .deleteDataservice(selectedService.getId()) .subscribe( - () => { + (wasSuccess) => { self.removeDataserviceFromList(selectedService); const link: string[] = [ DataservicesConstants.dataservicesRootPath ]; self.logger.log("[CreateApiPageComponent] Navigating to: %o", link); self.router.navigate(link).then(() => { // nothing to do }); + }, + (error) => { + self.error(error, "Error deleting the dataservice"); } ); } diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index c6565e96..c241dc45 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -52,28 +52,30 @@ export class DataserviceService extends ApiService { /** * Create a dataservice via the komodo rest interface * @param {NewDataservice} dataservice - * @returns {Observable} + * @returns {Observable} */ - public createDataservice(dataservice: NewDataservice): Observable { + public createDataservice(dataservice: NewDataservice): Observable { return this.http .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/" + dataservice.getId(), dataservice, this.getAuthRequestOptions()) .map((response) => { - return new Dataservice(); + return response.ok; }) .catch( ( error ) => this.handleError( error ) ); } /** * Delete a dataservice via the komodo rest interface - * @param {NewDataservice} dataservice - * @returns {Observable} + * @param {string} dataserviceId + * @returns {Observable} */ - public deleteDataservice(dataservice: NewDataservice): Observable { + public deleteDataservice(dataserviceId: string): Observable { return this.http - .delete(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/" + dataservice.getId(), + .delete(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/" + dataserviceId, this.getAuthRequestOptions()) - .map((response) => null) + .map((response) => { + return response.ok; + }) .catch( ( error ) => this.handleError( error ) ); } diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index c95ee5d9..11425eeb 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -13,7 +13,6 @@ import { Observable } from "rxjs/Observable"; @Injectable() export class MockDataserviceService extends DataserviceService { - private newDataservice = new NewDataservice(); private serv1 = new Dataservice(); private serv2 = new Dataservice(); private serv3 = new Dataservice(); @@ -37,19 +36,19 @@ export class MockDataserviceService extends DataserviceService { /** * Create a dataservice via the komodo rest interface * @param {NewDataservice} dataservice - * @returns {Observable} + * @returns {Observable} */ - public createDataservice(dataservice: NewDataservice): Observable { - return Observable.of(this.newDataservice); + public createDataservice(dataservice: NewDataservice): Observable { + return Observable.of(true); } /** * Delete a dataservice via the komodo rest interface - * @param {NewDataservice} dataservice - * @returns {Observable} + * @param {string} dataserviceId + * @returns {Observable} */ - public deleteDataservice(dataservice: NewDataservice): Observable { - return Observable.of(this.newDataservice); + public deleteDataservice(dataserviceId: string): Observable { + return Observable.of(true); } } diff --git a/ngapp/src/app/shared/abstract-page.component.ts b/ngapp/src/app/shared/abstract-page.component.ts index 235a603f..e75cc6c5 100644 --- a/ngapp/src/app/shared/abstract-page.component.ts +++ b/ngapp/src/app/shared/abstract-page.component.ts @@ -67,9 +67,16 @@ export abstract class AbstractPageComponent implements OnInit { /** * Called by a subclass (page) to report an error during loading of data. * @param error + * @param errorMsg optional message for the logger */ - public error(error: Response): void { - this.logger.error(" Error: %o", error); + public error(error: Response, errorMsg?: string): void { + let logMessage = "[" + this.constructor.name + "] "; + if (errorMsg) { + logMessage = logMessage.concat(errorMsg + ": %o"); + } else { + logMessage = logMessage.concat(" Error: %o"); + } + this.logger.error(logMessage, error); this.pageError = error; } From e9e867d597bd450b1d489775744d2f6dae705183 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 16 Nov 2017 09:27:27 -0600 Subject: [PATCH 041/205] mods to dataservice creation process --- .../app/activities/activities.component.ts | 1 + .../shared/activity.service.spec.ts | 5 +- .../app/activities/shared/activity.service.ts | 5 +- .../shared/mock-activity.service.ts | 22 +- .../add-connection-wizard.component.ts | 10 +- .../connections/shared/connection.model.ts | 15 + .../shared/connection.service.spec.ts | 5 +- .../connections/shared/connection.service.ts | 49 ++- .../shared/jdbc-table-filter.model.ts | 105 ++++++ .../shared/mock-connection.service.ts | 22 +- .../shared/new-connection.model.ts | 6 +- .../connections/shared/schema-info.model.ts | 91 +++++ ngapp/src/app/core/api.service.spec.ts | 7 +- ngapp/src/app/core/api.service.ts | 16 +- .../src/app/core/app-settings.service.spec.ts | 15 + ngapp/src/app/core/app-settings.service.ts | 57 +++ ngapp/src/app/core/core.module.ts | 2 + .../add-dataservice-wizard.component.html | 60 ++-- .../add-dataservice-wizard.component.spec.ts | 8 +- .../add-dataservice-wizard.component.ts | 257 +++++++++----- .../add-dataservice.component.spec.ts | 10 +- .../connection-table-selector.component.css | 20 ++ .../connection-table-selector.component.html | 54 +++ ...onnection-table-selector.component.spec.ts | 39 +++ .../connection-table-selector.component.ts | 199 +++++++++++ .../dataservices-cards.component.html | 7 +- .../dataservices-cards.component.ts | 10 + .../dataservices-list.component.html | 6 +- .../dataservices-list.component.ts | 20 +- .../dataservices/dataservices.component.html | 8 +- .../dataservices.component.spec.ts | 7 +- .../dataservices/dataservices.component.ts | 8 + .../app/dataservices/dataservices.module.ts | 8 +- .../jdbc-table-selector.component.css | 28 ++ .../jdbc-table-selector.component.html | 105 ++++++ .../jdbc-table-selector.component.spec.ts | 38 ++ .../jdbc-table-selector.component.ts | 302 ++++++++++++++++ .../shared/catalog-schema.model.ts | 91 +++++ .../dataservices/shared/dataservice.model.ts | 18 +- .../shared/dataservice.service.spec.ts | 9 +- .../shared/dataservice.service.ts | 118 ++++++- .../shared/mock-dataservice.service.ts | 23 +- .../dataservices/shared/mock-vdb.service.ts | 162 +++++++++ .../dataservices/shared/name-value.model.ts | 31 ++ .../shared/new-dataservice.model.ts | 19 +- .../app/dataservices/shared/table-selector.ts | 44 +++ .../app/dataservices/shared/table.model.ts | 104 ++++++ .../shared/vdb-model-source.model.ts | 114 ++++++ .../dataservices/shared/vdb-model.model.ts | 110 ++++++ .../dataservices/shared/vdb-status.model.ts | 151 ++++++++ .../src/app/dataservices/shared/vdb.model.ts | 201 +++++++++++ .../dataservices/shared/vdb.service.spec.ts | 19 + .../app/dataservices/shared/vdb.service.ts | 326 ++++++++++++++++++ .../app/dataservices/shared/vdbs-constants.ts | 32 ++ ngapp/src/app/shared/loading-state.enum.ts | 38 ++ ngapp/src/main.ts | 17 + 56 files changed, 3075 insertions(+), 179 deletions(-) create mode 100644 ngapp/src/app/connections/shared/jdbc-table-filter.model.ts create mode 100644 ngapp/src/app/connections/shared/schema-info.model.ts create mode 100644 ngapp/src/app/core/app-settings.service.spec.ts create mode 100644 ngapp/src/app/core/app-settings.service.ts create mode 100644 ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css create mode 100644 ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html create mode 100644 ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts create mode 100644 ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts create mode 100644 ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css create mode 100644 ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html create mode 100644 ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts create mode 100644 ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts create mode 100644 ngapp/src/app/dataservices/shared/catalog-schema.model.ts create mode 100644 ngapp/src/app/dataservices/shared/mock-vdb.service.ts create mode 100644 ngapp/src/app/dataservices/shared/name-value.model.ts create mode 100644 ngapp/src/app/dataservices/shared/table-selector.ts create mode 100644 ngapp/src/app/dataservices/shared/table.model.ts create mode 100644 ngapp/src/app/dataservices/shared/vdb-model-source.model.ts create mode 100644 ngapp/src/app/dataservices/shared/vdb-model.model.ts create mode 100644 ngapp/src/app/dataservices/shared/vdb-status.model.ts create mode 100644 ngapp/src/app/dataservices/shared/vdb.model.ts create mode 100644 ngapp/src/app/dataservices/shared/vdb.service.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/vdb.service.ts create mode 100644 ngapp/src/app/dataservices/shared/vdbs-constants.ts create mode 100644 ngapp/src/app/shared/loading-state.enum.ts diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index ff9fabf4..8a511e7d 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -101,6 +101,7 @@ export class ActivitiesComponent extends AbstractPageComponent { this.confirmDeleteDialog.open(); } + // noinspection JSMethodCanBeStatic public onStart(activityName: string): void { alert("Start activity " + activityName); } diff --git a/ngapp/src/app/activities/shared/activity.service.spec.ts b/ngapp/src/app/activities/shared/activity.service.spec.ts index 9ed7161e..7e7bf0dd 100644 --- a/ngapp/src/app/activities/shared/activity.service.spec.ts +++ b/ngapp/src/app/activities/shared/activity.service.spec.ts @@ -1,17 +1,18 @@ import { ActivityService } from "@activities/shared/activity.service"; import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; describe("ActivityService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], - providers: [ActivityService, LoggerService] + providers: [ActivityService, AppSettingsService, LoggerService] }); }); - it("should be created", inject([ActivityService, LoggerService], + it("should be created", inject([ActivityService, AppSettingsService, LoggerService], (service: ActivityService, logger: LoggerService) => { expect(service).toBeTruthy(); })); diff --git a/ngapp/src/app/activities/shared/activity.service.ts b/ngapp/src/app/activities/shared/activity.service.ts index 18bc7305..0601e583 100644 --- a/ngapp/src/app/activities/shared/activity.service.ts +++ b/ngapp/src/app/activities/shared/activity.service.ts @@ -20,6 +20,7 @@ import { NewActivity } from "@activities/shared/new-activity.model"; import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { ApiService } from "@core/api.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; import { Observable } from "rxjs/Observable"; @@ -29,8 +30,8 @@ export class ActivityService extends ApiService { private http: Http; - constructor( http: Http, logger: LoggerService ) { - super( logger ); + constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { + super( appSettings, logger ); this.http = http; } diff --git a/ngapp/src/app/activities/shared/mock-activity.service.ts b/ngapp/src/app/activities/shared/mock-activity.service.ts index aab8caa7..cac16331 100644 --- a/ngapp/src/app/activities/shared/mock-activity.service.ts +++ b/ngapp/src/app/activities/shared/mock-activity.service.ts @@ -1,9 +1,27 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Activity } from "@activities/shared/activity.model"; import { ActivityService } from "@activities/shared/activity.service"; import { NewActivity } from "@activities/shared/new-activity.model"; import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; @@ -20,8 +38,8 @@ export class MockActivityService extends ActivityService { private acts: Activity[] = [this.act1, this.act2, this.act3]; private newAct1 = new NewActivity(); - constructor( http: Http, logger: LoggerService ) { - super(http, logger); + constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { + super(http, appSettings, logger); this.act1.setId("activity1"); this.act1.setSourceConnection("activity1SrcConn"); this.act1.setTargetConnection("activity1TgtConn"); diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index 5b864442..5d47ea6d 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -356,7 +356,15 @@ export class AddConnectionWizardComponent implements OnInit { * @returns {boolean} 'true' if connection is JDBC */ public get isJdbc(): boolean { - return true; + const driver = this.connectionDriverName; + let jdbc = true; + // TODO: this needs to be a hooked up to komodo call instead + if (driver === null || driver === "cassandra" || driver === "file" || driver === "google" + || driver === "ldap" || driver === "mongodb" || driver === "salesforce" + || driver === "salesforce-34" || driver === "solr" || driver === "webservice") { + jdbc = false; + } + return jdbc; } // ---------------- diff --git a/ngapp/src/app/connections/shared/connection.model.ts b/ngapp/src/app/connections/shared/connection.model.ts index a37d2d65..382eca29 100644 --- a/ngapp/src/app/connections/shared/connection.model.ts +++ b/ngapp/src/app/connections/shared/connection.model.ts @@ -23,6 +23,7 @@ export class Connection implements Identifiable< string > { private keng__id: string; private dv__jndiName: string; private dv__driverName: string; + private dv__type: boolean; private keng__properties: Map< string, string > = new Map< string, string >(); /** @@ -99,6 +100,13 @@ export class Connection implements Identifiable< string > { return this.dv__jndiName; } + /** + * @returns {boolean} the jdbc status (true == jdbc) + */ + public isJdbc(): boolean { + return this.dv__type; + } + /** * @returns {Map} the connection properties (never null) */ @@ -127,6 +135,13 @@ export class Connection implements Identifiable< string > { this.dv__jndiName = jndiName ? jndiName : null; } + /** + * @param {boolean} jdbc the jdbc state + */ + public setJdbc( jdbc: boolean ): void { + this.dv__type = jdbc; + } + /** * @param {Map} props the connection properties (optional) */ diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ngapp/src/app/connections/shared/connection.service.spec.ts index 3e03e5bf..30ee6b1c 100644 --- a/ngapp/src/app/connections/shared/connection.service.spec.ts +++ b/ngapp/src/app/connections/shared/connection.service.spec.ts @@ -1,17 +1,18 @@ import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; import { ConnectionService } from "@connections/shared/connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; describe("ConnectionService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], - providers: [ConnectionService, LoggerService] + providers: [AppSettingsService, ConnectionService, LoggerService] }); }); - it("should be created", inject([ConnectionService, LoggerService], + it("should be created", inject([ConnectionService, AppSettingsService, LoggerService], (service: ConnectionService ) => { expect(service).toBeTruthy(); })); diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index 60f2e4c9..5ba653f4 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -19,9 +19,12 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { SchemaInfo } from "@connections/shared/schema-info.model"; import { TemplateDefinition } from "@connections/shared/template-definition.model"; import { ApiService } from "@core/api.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { environment } from "@environments/environment"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; @@ -32,8 +35,8 @@ export class ConnectionService extends ApiService { private http: Http; - constructor( http: Http, logger: LoggerService ) { - super( logger ); + constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { + super( appSettings, logger ); this.http = http; } @@ -83,7 +86,7 @@ export class ConnectionService extends ApiService { /** * Get the connection templates from the komodo rest interface - * @returns {Observable>>} + * @returns {Observable} */ public getConnectionTemplates(): Observable { return this.http @@ -110,4 +113,44 @@ export class ConnectionService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Get the schema infos for a Jdbc Connection + * @param {string} connectionId + * @returns {Observable} + */ + public getConnectionSchemaInfos(connectionId: string): Observable { + return this.http + .get( environment.komodoTeiidUrl + "/connections/" + connectionId + "/JdbcCatalogSchema", this.getAuthRequestOptions()) + .map((response) => { + const infos = response.json(); + return infos.map((info) => SchemaInfo.create( info )); + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Get the tables for the specified input (connection and filters) for a Jdbc Connection + * @param {JdbcTableFilter} tableFilter + * @returns {Observable} + */ + public getJdbcConnectionTables(tableFilter: JdbcTableFilter): Observable { + return this.http + .post( environment.komodoTeiidUrl + "/connections/Tables", tableFilter, this.getAuthRequestOptions()) + .map((response) => { + const info = response.json(); + const tableNames = []; + let i = 1; + let tableKey = "Table" + i; + let tableName = info.Information[tableKey]; + while ( tableName && tableName.length > 0 ) { + tableNames.push(tableName); + i++; + tableKey = "Table" + i; + tableName = info.Information[tableKey]; + } + return tableNames; + }) + .catch( ( error ) => this.handleError( error ) ); + } + } diff --git a/ngapp/src/app/connections/shared/jdbc-table-filter.model.ts b/ngapp/src/app/connections/shared/jdbc-table-filter.model.ts new file mode 100644 index 00000000..76e10714 --- /dev/null +++ b/ngapp/src/app/connections/shared/jdbc-table-filter.model.ts @@ -0,0 +1,105 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The JDBC table filter model. + */ +export class JdbcTableFilter { + private dataSourceName: string; + private catalogFilter = "%"; + private schemaFilter = "%"; + private tableFilter = "%"; + + /** + * @param {Object} json the JSON representation of a JdbcTableFilter + * @returns {JdbcTableFilter} the new JdbcTableFilter (never null) + */ + public static create( json: object = {} ): JdbcTableFilter { + const template = new JdbcTableFilter(); + template.setValues( json ); + return template; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the connection name + */ + public getConnectionName(): string { + return this.dataSourceName; + } + + /** + * @returns {string} the catalog filter + */ + public getCatalogFilter(): string { + return this.catalogFilter; + } + + /** + * @returns {string} the schema filter + */ + public getSchemaFilter(): string { + return this.schemaFilter; + } + + /** + * @returns {string} the table filter + */ + public getTableFilter(): string { + return this.tableFilter; + } + + /** + * @param {string} name the connection name + */ + public setConnectionName( name: string ): void { + this.dataSourceName = name; + } + + /** + * @param {string} filter the catalog filter + */ + public setCatalogFilter( filter?: string ): void { + this.catalogFilter = filter ? filter : "%"; + } + + /** + * @param {string} filter the schema filter + */ + public setSchemaFilter( filter?: string ): void { + this.schemaFilter = filter ? filter : "%"; + } + + /** + * @param {string} filter the table filter + */ + public setTableFilter( filter?: string ): void { + this.tableFilter = filter ? filter : "%"; + } + + /** + * Set all object values using the supplied Template json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index e896826b..a442e1e8 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -1,9 +1,27 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { NewConnection } from "@connections/shared/new-connection.model"; import { TemplateDefinition } from "@connections/shared/template-definition.model"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; @@ -24,8 +42,8 @@ export class MockConnectionService extends ConnectionService { private templ3 = new TemplateDefinition(); private templs: TemplateDefinition[] = [this.templ1, this.templ2, this.templ3]; - constructor( http: Http, logger: LoggerService ) { - super(http, logger); + constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { + super(http, appSettings, logger); this.conn1.setId("conn1"); this.conn2.setId("conn2"); this.conn3.setId("conn3"); diff --git a/ngapp/src/app/connections/shared/new-connection.model.ts b/ngapp/src/app/connections/shared/new-connection.model.ts index 2a36cfd7..e2240322 100644 --- a/ngapp/src/app/connections/shared/new-connection.model.ts +++ b/ngapp/src/app/connections/shared/new-connection.model.ts @@ -87,10 +87,10 @@ export class NewConnection { } /** - * @param {boolean} isJdbc the jdbc status (optional) + * @param {boolean} isJdbc the jdbc state */ - public setJdbc( isJdbc?: boolean ): void { - this.jdbc = isJdbc ? isJdbc : true; + public setJdbc( isJdbc ): void { + this.jdbc = isJdbc; } /** diff --git a/ngapp/src/app/connections/shared/schema-info.model.ts b/ngapp/src/app/connections/shared/schema-info.model.ts new file mode 100644 index 00000000..6cad92d3 --- /dev/null +++ b/ngapp/src/app/connections/shared/schema-info.model.ts @@ -0,0 +1,91 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * SchemaInfo model - returned from the komodo rest call. The type of info will be + * 'Catalog' or 'Schema'. + */ +export class SchemaInfo { + private name: string; + private type: string; + private schemaNames: string[]; + + /** + * @param {Object} json the JSON representation of a Template + * @returns {TemplateDefinition} the new TemplateDefinition (never null) + */ + public static create( json: object = {} ): SchemaInfo { + const template = new SchemaInfo(); + template.setValues( json ); + return template; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the info name + */ + public getName(): string { + return this.name; + } + + /** + * @returns {string} the info type + */ + public getType(): string { + return this.type; + } + + /** + * @returns {string[]} the array of schema Names + */ + public getSchemaNames(): string[] { + return this.schemaNames; + } + + /** + * @param {string} name the info name + */ + public setId( name?: string ): void { + this.name = name ? name : null; + } + + /** + * @param {string} type the info type + */ + public setType( type?: string ): void { + this.type = type ? type : null; + } + + /** + * @param {string[]} schemaNames the array of schema names + */ + public setSchemaNames( schemaNames?: string[] ): void { + this.schemaNames = schemaNames ? schemaNames : null; + } + + /** + * Set all object values using the supplied Template json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/core/api.service.spec.ts b/ngapp/src/app/core/api.service.spec.ts index aeaa50d0..c4776cb1 100644 --- a/ngapp/src/app/core/api.service.spec.ts +++ b/ngapp/src/app/core/api.service.spec.ts @@ -1,13 +1,14 @@ import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; import { ApiService } from "@core/api.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; describe("ApiService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpModule], - providers: [LoggerService] + providers: [AppSettingsService, LoggerService] }); }); @@ -19,8 +20,8 @@ describe("ApiService", () => { class MockService extends ApiService { - constructor( logger: LoggerService ) { - super( logger ); + constructor( appSettings: AppSettingsService, logger: LoggerService ) { + super( appSettings, logger ); } } diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index 0e95798c..f2fb54cc 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -16,6 +16,7 @@ */ import { Headers, RequestOptions, Response } from "@angular/http"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; @@ -25,9 +26,11 @@ import { ErrorObservable } from "rxjs/observable/ErrorObservable"; export abstract class ApiService { + protected appSettings: AppSettingsService; protected logger: LoggerService; - constructor( logger: LoggerService ) { + constructor( appSettings: AppSettingsService, logger: LoggerService ) { + this.appSettings = appSettings; this.logger = logger; } @@ -37,10 +40,19 @@ export abstract class ApiService { * @returns {RequestOptions} */ protected getAuthRequestOptions(): RequestOptions { - const headers = new Headers({ "Authorization": "Basic " + btoa("dsbUser:1demo-user1") }); + const userPasswordStr = this.appSettings.getKomodoUser() + ":" + this.appSettings.getKomodoUserPassword(); + const headers = new Headers({ "Authorization": "Basic " + btoa(userPasswordStr) }); return new RequestOptions({ headers }); } + /** + * Get the current user workspace path + * @returns {string} the current user workspace path + */ + protected getKomodoUserWorkspacePath(): string { + return this.appSettings.getKomodoUserWorkspacePath(); + } + protected handleError(error: Response): ErrorObservable { this.logger.error( this.constructor.name + "::handleError" ); return Observable.throw(error); diff --git a/ngapp/src/app/core/app-settings.service.spec.ts b/ngapp/src/app/core/app-settings.service.spec.ts new file mode 100644 index 00000000..e37b3acb --- /dev/null +++ b/ngapp/src/app/core/app-settings.service.spec.ts @@ -0,0 +1,15 @@ +import { inject, TestBed } from "@angular/core/testing"; + +import { AppSettingsService } from "./app-settings.service"; + +describe("AppSettingsService", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [AppSettingsService] + }); + }); + + it("should be created", inject([AppSettingsService], (service: AppSettingsService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/ngapp/src/app/core/app-settings.service.ts b/ngapp/src/app/core/app-settings.service.ts new file mode 100644 index 00000000..086a2b88 --- /dev/null +++ b/ngapp/src/app/core/app-settings.service.ts @@ -0,0 +1,57 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from "@angular/core"; + +@Injectable() +export class AppSettingsService { + + private readonly komodoRoot = "tko:komodo/tko:workspace"; + + // TODO: temporary location for user and password + private readonly komodoUser = "dsbUser"; + private readonly komodoUserPassword = "1demo-user1"; + + constructor() { + // Nothing to do + } + + /* + * Get the komodo workspace path for the current user + * @returns {string} the komodo workspace path + */ + public getKomodoUserWorkspacePath( ): string { + return this.komodoRoot + "/" + this.komodoUser; + } + + /* + * Get the logged in komodo user + * @returns {string} the komodo user + */ + public getKomodoUser( ): string { + return this.komodoUser; + } + + /* + * Get the logged in komodo user password + * @returns {string} the komodo user password + */ + public getKomodoUserPassword( ): string { + return this.komodoUserPassword; + } + +} diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index cae741da..1268a617 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -19,6 +19,7 @@ import { CommonModule } from "@angular/common"; import { NgModule, Optional, SkipSelf } from "@angular/core"; import { HttpModule } from "@angular/http"; import { RouterModule } from "@angular/router"; +import { AppSettingsService } from "@core/app-settings.service"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; import { LoggerService } from "@core/logger.service"; @@ -44,6 +45,7 @@ import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component" VerticalNavComponent ], providers: [ + AppSettingsService, LoggerService ] }) diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html index 4cd14c23..ba0fd630 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html @@ -3,29 +3,12 @@ (onCancel)="cancelClicked($event)" (onNext)="nextClicked($event)" (onStepChange)="stepChanged($event)"> - - - + + + -
    -
    -
    - -
    -
    -

    - - Step Initialization Error -

    -
    -
    -

    - Could not load the connections. Please Try relaunching the wizard or check the console log. -

    -
    -
    -

    {{ step1InstructionMessage }}

    - +

    {{ step1InstructionMessage }}

    +
    @@ -33,39 +16,44 @@

    {{ step1Instruction
    {{ getBasicPropertyErrorMessage("name") }}

    -
    - +
    +
    - -
    {{ getBasicPropertyErrorMessage("connection") }}
    +
    + + + + +

    {{ step2InstructionMessage }}

    + +
    - + - - - -

    {{ step2InstructionMessage }}

    + + + +

    {{ step3InstructionMessage }}

    Dataservice Properties:

    +
    - - + +
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index 187953c6..1919579d 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -5,8 +5,12 @@ import { RouterTestingModule } from "@angular/router/testing"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; +import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; +import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -19,10 +23,12 @@ describe("AddDataserviceWizardComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], - declarations: [ AddDataserviceWizardComponent, PropertyFormComponent, PropertyFormPropertyComponent ], + declarations: [ AddDataserviceWizardComponent, ConnectionTableSelectorComponent, JdbcTableSelectorComponent, + PropertyFormComponent, PropertyFormPropertyComponent ], providers: [ { provide: DataserviceService, useClass: MockDataserviceService }, { provide: ConnectionService, useClass: MockConnectionService }, + { provide: VdbService, useClass: MockVdbService }, ] }) .compileComponents().then(() => { diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index af1ada77..8f8339d5 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -26,16 +26,20 @@ import { FormControl, FormGroup } from "@angular/forms"; import { Validators } from "@angular/forms"; import { AbstractControl } from "@angular/forms"; import { Router } from "@angular/router"; -import { Connection } from "@connections/shared/connection.model"; -import { ConnectionService } from "@connections/shared/connection.service"; import { LoggerService } from "@core/logger.service"; +import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; +import { VdbStatus } from "@dataservices/shared/vdb-status.model"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; +import { LoadingState } from "@shared/loading-state.enum"; import { WizardComponent } from "patternfly-ng"; import { WizardEvent } from "patternfly-ng"; import { WizardStepConfig } from "patternfly-ng"; import { WizardConfig } from "patternfly-ng"; +import { Subscription } from "rxjs/Subscription"; @Component({ encapsulation: ViewEncapsulation.None, @@ -45,6 +49,7 @@ import { WizardConfig } from "patternfly-ng"; }) export class AddDataserviceWizardComponent implements OnInit { public readonly dataserviceSummaryLink: string = DataservicesConstants.dataservicesRootPath; + public loadingState = LoadingState; // need local ref of enum for html to use // Wizard Config public wizardConfig: WizardConfig; @@ -52,28 +57,32 @@ export class AddDataserviceWizardComponent implements OnInit { public basicPropertyForm: FormGroup; public createComplete = true; public createSuccessful = false; - public connectionsLoading = true; - public connectionsLoadSuccess = false; + public tableSelectorLoadingState = LoadingState.LOADING; // Wizard Step 1 public step1Config: WizardStepConfig; // Wizard Step 2 public step2Config: WizardStepConfig; - public step2aConfig: WizardStepConfig; - public step2bConfig: WizardStepConfig; + + // Wizard Step 3 + public step3Config: WizardStepConfig; + public step3aConfig: WizardStepConfig; + public step3bConfig: WizardStepConfig; @ViewChild("wizard") public wizard: WizardComponent; + @ViewChild(ConnectionTableSelectorComponent) public tableSelector: ConnectionTableSelectorComponent; - private connectionService: ConnectionService; private dataserviceService: DataserviceService; - private allConnections: Connection[] = []; + private vdbService: VdbService; private logger: LoggerService; private router: Router; + private deploymentChangeSubscription: Subscription; - constructor( router: Router, connectionService: ConnectionService, dataserviceService: DataserviceService, logger: LoggerService ) { - this.connectionService = connectionService; + constructor( router: Router, dataserviceService: DataserviceService, + logger: LoggerService, vdbService: VdbService ) { this.dataserviceService = dataserviceService; + this.vdbService = vdbService; this.router = router; this.logger = logger; this.createBasicPropertyForm(); @@ -83,29 +92,37 @@ export class AddDataserviceWizardComponent implements OnInit { * Initialization */ public ngOnInit(): void { - // Step 1 - Basic Properties + // Step 1 - Name and Description this.step1Config = { id: "step1", priority: 0, - title: "Basic Properties", + title: "Name and Description", allowClickNav: false } as WizardStepConfig; - // Step 2 - Review and Create + // Step 2 - Tables this.step2Config = { id: "step2", priority: 0, + title: "Table Selection", + allowClickNav: false + } as WizardStepConfig; + + // Step 3 - Review and Create + this.step3Config = { + id: "step3", + priority: 0, title: "Review and Create", allowClickNav: false } as WizardStepConfig; - this.step2aConfig = { - id: "step2a", + this.step3aConfig = { + id: "step3a", priority: 0, title: "Review", allowClickNav: false } as WizardStepConfig; - this.step2bConfig = { - id: "step2b", + this.step3bConfig = { + id: "step3b", priority: 1, title: "Create", allowClickNav: false @@ -121,43 +138,40 @@ export class AddDataserviceWizardComponent implements OnInit { done: false } as WizardConfig; - // Load the connections for the first step - this.connectionsLoading = true; - this.connectionsLoadSuccess = false; - const self = this; - this.connectionService - .getAllConnections() - .subscribe( - (conns) => { - self.allConnections = conns; - self.connectionsLoading = false; - self.connectionsLoadSuccess = true; - }, - (error) => { - self.logger.error("[AddDataserviceWizardComponent] Error getting connections: %o", error); - self.connectionsLoading = false; - self.connectionsLoadSuccess = false; - } - ); - + this.tableSelectorLoadingState = LoadingState.LOADING; this.setNavAway(false); } // ---------------- // Public Methods // ---------------- - /* - * Return the name valid state + + /** + * Determine if table selector is loading */ - public get nameValid(): boolean { - return this.basicPropertyForm.controls["name"].valid; + public get tableSelectorLoading( ): boolean { + return this.tableSelectorLoadingState === LoadingState.LOADING; + } + + /** + * Determine if table selector is loaded and valid + */ + public get tableSelectorLoadedValid( ): boolean { + return this.tableSelectorLoadingState === LoadingState.LOADED_VALID; + } + + /** + * Determine if table selector is loaded and invalid + */ + public get tableSelectorLoadedInvalid( ): boolean { + return this.tableSelectorLoadingState === LoadingState.LOADED_INVALID; } /* - * Return the connection valid state + * Return the name valid state */ - public get connectionValid(): boolean { - return this.basicPropertyForm.controls["connection"].valid; + public get nameValid(): boolean { + return this.basicPropertyForm.controls["name"].valid; } /* @@ -166,10 +180,8 @@ export class AddDataserviceWizardComponent implements OnInit { public get step1InstructionMessage(): string { if (!this.nameValid) { return "Please enter a name for the Dataservice"; - } else if (!this.connectionValid) { - return "Please choose a connection for the Dataservice"; } else { - return "When finished entering properties, click Next to continue"; + return "Click Next to continue"; } } @@ -177,6 +189,17 @@ export class AddDataserviceWizardComponent implements OnInit { * Step 2 instruction message */ public get step2InstructionMessage(): string { + if (!this.tableSelector.valid) { + return "Please select tables for the Dataservice"; + } else { + return "Select tables, then click Next to continue"; + } + } + + /* + * Step 3 instruction message + */ + public get step3InstructionMessage(): string { return "Review your entries. When finished, click Create to create the Dataservice"; } @@ -195,7 +218,6 @@ export class AddDataserviceWizardComponent implements OnInit { } public nextClicked($event: WizardEvent): void { - // When leaving page 1, load the driver-specific property definitions if ($event.step.config.id === "step1") { // TODO implement nextClicked } @@ -217,59 +239,85 @@ export class AddDataserviceWizardComponent implements OnInit { this.createComplete = false; this.createSuccessful = false; - const dataservice: NewDataservice = new NewDataservice(); + const sourceVdbName = this.tableSelector.getSelectedTables()[0].getConnection().getId() + VdbsConstants.SOURCE_VDB_SUFFIX; - // Dataservice basic properties from step 1 - dataservice.setId(this.dataserviceName); + // Before polling, subscribe to get status event + this.deploymentChangeSubscription = this.vdbService.deploymentStatus.subscribe((status) => { + this.onSourceVdbDeploymentStateChanged(status); + }); const self = this; - this.dataserviceService - .createDataservice(dataservice) + this.vdbService + .deployVdbForTable(this.tableSelector.getSelectedTables()[0]) .subscribe( (wasSuccess) => { - self.createComplete = true; - self.createSuccessful = wasSuccess; - self.step2bConfig.nextEnabled = false; + // Deployment succeeded - wait for source vdb to become active + if (wasSuccess) { + self.vdbService.pollForActiveVdb(sourceVdbName, 30, 5); + } else { + self.createComplete = true; + self.createSuccessful = false; + self.step3bConfig.nextEnabled = false; + self.vdbService.deploymentStatus.unsubscribe(); + } }, (error) => { self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); self.createComplete = true; self.createSuccessful = false; - self.step2bConfig.nextEnabled = false; + self.step3bConfig.nextEnabled = false; + self.vdbService.deploymentStatus.unsubscribe(); } ); } + /* + * Listens for the source VDB deployment completion. If the source VDB is active, proceed with + * creation of the Dataservice + * @param status the VDB deployment status + */ + public onSourceVdbDeploymentStateChanged(status: VdbStatus): void { + // if null received, ignore + if (!status) { + return; + // non-null received, unsubscribe to stop any further notifications + } else { + // Got the status change, unsubscribe + this.deploymentChangeSubscription.unsubscribe(); + } + + if (this.tableSelector.hasSelectedConnection()) { + const selectedConnectionName = this.tableSelector.selectedConnection.getId(); + const selectedVdbName = selectedConnectionName + VdbsConstants.SOURCE_VDB_SUFFIX; + if (selectedVdbName === status.getName()) { + if (status.isActive()) { + this.createDataserviceForSingleTable(); + } else if (status.isFailed()) { + this.createComplete = true; + this.createSuccessful = false; + this.step3bConfig.nextEnabled = false; + } + } + } + } + public stepChanged($event: WizardEvent): void { if ($event.step.config.id === "step1") { this.updatePage1ValidStatus(); this.wizardConfig.nextTitle = "Next >"; - } else if ($event.step.config.id === "step2a") { + } else if ($event.step.config.id === "step2") { + this.updatePage2ValidStatus(); + this.wizardConfig.nextTitle = "Next >"; + } else if ($event.step.config.id === "step3a") { this.wizardConfig.nextTitle = "Create"; - } else if ($event.step.config.id === "step2b") { + } else if ($event.step.config.id === "step3b") { // Note: The next button is not disabled by default when wizard is done - this.step2Config.nextEnabled = false; + this.step3Config.nextEnabled = false; } else { this.wizardConfig.nextTitle = "Next >"; } } - /** - * Handler for property form initialization - * @param {boolean} isValid form valid state - */ - public onDetailPropertyInit(isValid: boolean): void { - this.updatePage2ValidStatus(isValid); - } - - /** - * Handler for property form changes - * @param {boolean} isValid form valid state - */ - public onDetailPropertyChanged(isValid: boolean): void { - this.updatePage2ValidStatus(isValid); - } - /** * @returns {string} the name of the dataservice */ @@ -278,21 +326,15 @@ export class AddDataserviceWizardComponent implements OnInit { } /** - * @returns {string} the connection name of the dataservice + * @returns {string} the description of the dataservice */ - public get connectionName(): string { - return this.basicPropertyForm.controls["connection"].value; + public get dataserviceDescription(): string { + return this.basicPropertyForm.controls["description"].value; } - /* - * Return the array of connection names - */ - public get connectionNames(): string[] { - const connNames: string[] = []; - for ( const conn of this.allConnections ) { - connNames.push(conn.getId()); - } - return connNames.sort(); + public updatePage2ValidStatus( ): void { + this.step2Config.nextEnabled = this.tableSelector.valid(); + this.setNavAway(this.step2Config.nextEnabled); } // ---------------- @@ -305,7 +347,7 @@ export class AddDataserviceWizardComponent implements OnInit { private createBasicPropertyForm(): void { this.basicPropertyForm = new FormGroup({ name: new FormControl("", Validators.required), - connection: new FormControl("", Validators.required) + description: new FormControl("") }); // Responds to basic property changes - updates the page status this.basicPropertyForm.valueChanges.subscribe((val) => { @@ -322,9 +364,40 @@ export class AddDataserviceWizardComponent implements OnInit { this.setNavAway(this.step1Config.nextEnabled); } - private updatePage2ValidStatus(formValid: boolean): void { - this.step2Config.nextEnabled = formValid; - this.setNavAway(this.step2Config.nextEnabled); - } + /* + * Create the Dataservice for the selected source table. This is invoked + * only after the source VDB has successfully deployed. + */ + private createDataserviceForSingleTable(): void { + const dataservice: NewDataservice = new NewDataservice(); + // Dataservice basic properties from step 1 + dataservice.setId(this.dataserviceName); + dataservice.setDescription(this.dataserviceDescription); + + const self = this; + this.dataserviceService + .createDataserviceForSingleTable(dataservice, this.tableSelector.getSelectedTables()[0]) + .subscribe( + (wasSuccess) => { + // Deployment succeeded - wait for source vdb to become active + if (wasSuccess) { + self.createComplete = true; + self.createSuccessful = true; + self.step3bConfig.nextEnabled = false; + } else { + self.createComplete = true; + self.createSuccessful = false; + self.step3bConfig.nextEnabled = false; + } + }, + (error) => { + self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); + self.createComplete = true; + self.createSuccessful = false; + self.step3bConfig.nextEnabled = false; + } + ); + + } } diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index e24a7a6c..68c62313 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -6,8 +6,12 @@ import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { CoreModule } from "@core/core.module"; import { AddDataserviceWizardComponent } from "@dataservices/add-dataservice-wizard/add-dataservice-wizard.component"; +import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; +import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceComponent } from "./add-dataservice.component"; @@ -19,10 +23,12 @@ describe("AddDataserviceComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], - declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent ], + declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent, + ConnectionTableSelectorComponent, JdbcTableSelectorComponent ], providers: [ { provide: DataserviceService, useClass: MockDataserviceService }, - { provide: ConnectionService, useClass: MockConnectionService } + { provide: ConnectionService, useClass: MockConnectionService }, + { provide: VdbService, useClass: MockVdbService } ] }) .compileComponents().then(() => { diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css new file mode 100644 index 00000000..0c2aff39 --- /dev/null +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css @@ -0,0 +1,20 @@ +.list-div { + position: relative; + height: 100%; + max-height: 300px; + overflow-y: auto; +} + +.connection-list .list-view-pf-main-info { + padding-top: 0.5em; + padding-bottom: 0.5em; +} + +.connection-list .list-group-item-heading { + font-size: 12px; + margin-right: 5px; +} + +.connection-list .list-view-pf-description { + width: 95%; +} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html new file mode 100644 index 00000000..e678327b --- /dev/null +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -0,0 +1,54 @@ +
    + + + +
    + Connections +
    + +
    +
    +
    + + Problem Loading Connections! +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + {{ connection.getId() }} +
    +
    +
    +
    +
    +
    +
    + + + + + + +
    + +
    +
    +
    + + Non-JDBC Connections are not supported +
    +
    +
    +
    + + Please select a Connection +
    +
    +
    diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts new file mode 100644 index 00000000..3a024a67 --- /dev/null +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -0,0 +1,39 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; +import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; + +describe("ConnectionTableSelectorComponent", () => { + let component: ConnectionTableSelectorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ FormsModule, HttpModule ], + declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent ], + providers: [ + AppSettingsService, LoggerService, + { provide: ConnectionService, useClass: MockConnectionService }, + ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConnectionTableSelectorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts new file mode 100644 index 00000000..fe69a34b --- /dev/null +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -0,0 +1,199 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ViewChild } from "@angular/core"; +import { Output } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { LoggerService } from "@core/logger.service"; +import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; +import { Table } from "@dataservices/shared/table.model"; +import { LoadingState } from "@shared/loading-state.enum"; + +@Component({ + selector: "app-connection-table-selector", + templateUrl: "./connection-table-selector.component.html", + styleUrls: ["./connection-table-selector.component.css"] +}) +export class ConnectionTableSelectorComponent implements OnInit { + + @Output() public tableSelectionChanged: EventEmitter = new EventEmitter(); + + @ViewChild(JdbcTableSelectorComponent) public jdbcTableSelector: JdbcTableSelectorComponent; + + private connectionService: ConnectionService; + private allConnections: Connection[] = []; + private selectedConn: Connection; + private connectionLoadingState: LoadingState = LoadingState.LOADING; + private logger: LoggerService; + + constructor( connectionService: ConnectionService, logger: LoggerService ) { + this.connectionService = connectionService; + this.logger = logger; + } + + /* + * Component initialization + */ + public ngOnInit(): void { + // Load the connections + this.connectionLoadingState = LoadingState.LOADING; + const self = this; + this.connectionService + .getAllConnections() + .subscribe( + (conns) => { + self.allConnections = conns; + self.connectionLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.logger.error("[ConnectionTableSelectorComponent] Error getting connections: %o", error); + self.connectionLoadingState = LoadingState.LOADED_INVALID; + } + ); + } + + /** + * Toggles the selection + * @param {Connection} connection the connection whose selection changed + */ + public toggleConnectionSelected(connection: Connection): void { + // Connection currently selected, so deselect it + if (this.isConnectionSelected(connection)) { + this.selectedConn = null; + } else { + // Connection not currently selected or nothing selected, so select it. + this.selectedConn = connection; + } + // Set the specific selector with the current connection + if (this.jdbcTableSelector) { + if (this.selectedConn && this.selectedConn.isJdbc()) { + this.jdbcTableSelector.setConnection(connection); + } else { + this.jdbcTableSelector.setConnection(null); + } + } + } + + /** + * Respond to child table selection changes by propagating up my parent + */ + public onTableSelectionChanged( ): void { + this.tableSelectionChanged.emit(); + } + + /** + * selector is valid if at least one table is selected. + * @returns {boolean} the selector status (true if one or more tables selected) + */ + public valid( ): boolean { + return this.getSelectedTables().length > 0; + } + + /** + * Determine if connections are loading + */ + public get connectionsLoading( ): boolean { + return this.connectionLoadingState === LoadingState.LOADING; + } + + /** + * Determine if connections are loaded and valid + */ + public get connectionsLoadedValid( ): boolean { + return this.connectionLoadingState === LoadingState.LOADED_VALID; + } + + /** + * Determine if connections are loaded and invalid + */ + public get connectionsLoadedInvalid( ): boolean { + return this.connectionLoadingState === LoadingState.LOADED_INVALID; + } + + /** + * Determine if the supplied connection is currently selected. + * @param {Connection} connection the connection + * @returns {boolean} true if the connection is selected + */ + public isConnectionSelected(connection: Connection): boolean { + return this.selectedConn && this.selectedConn === connection; + } + + /** + * Determine if a JDBC connection is currently selected + * @returns {boolean} true if a JDBC connection is selected + */ + public hasJdbcConnectionSelected(): boolean { + return (this.selectedConn && this.selectedConn.isJdbc()); + } + + /** + * Determine if a non-JDBC connection is currently selected + * @returns {boolean} true if a non-JDBC connection is selected + */ + public hasNonJdbcConnectionSelected(): boolean { + return (this.selectedConn && !this.selectedConn.isJdbc()); + } + + /** + * Determine if anything is selected + * @returns {boolean} true if a connection is selected + */ + public hasSelectedConnection( ): boolean { + return this.selectedConn !== null; + } + + /** + * Get the currently selected Connection + * @returns {Connection} the current selection (may be null) + */ + public get selectedConnection( ): Connection { + return this.selectedConn; + } + + /** + * Set the currently selected Connection + * @param {Connection} conn the current selection (may be null) + */ + public set selectedConnection(conn: Connection) { + this.selectedConn = conn; + } + + /* + * Return all available Connections + * @returns {Connection[]} the list of all Connections + */ + public getAllConnections(): Connection[] { + return this.allConnections; + } + + /* + * Return all currently selected Tables + * @returns {Table[]} the list of selected Tables + */ + public getSelectedTables(): Table[] { + const selectedTables = []; + if (this.jdbcTableSelector) { + return this.jdbcTableSelector.getSelectedTables(); + } + return selectedTables; + } + +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html index 98f74c50..9781c35a 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html @@ -9,11 +9,16 @@

    {{ dataservice.getId() }} + +


    +
    + {{ dataservice.getDescription() }} +
    -
    + (testDataservice)="onTest($event)" (publishDataservice)="onPublish($event)" (deleteDataservice)="onDelete($event)" + (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)"> + (testDataservice)="onTest($event)" (publishDataservice)="onPublish($event)" (deleteDataservice)="onDelete($event)" + (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)">
    diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index 6b4f2ec6..5364a9c3 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -9,6 +9,8 @@ import { DataservicesListComponent } from "@dataservices/dataservices-list/datas import { DataservicesComponent } from "@dataservices/dataservices.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { SharedModule } from "@shared/shared.module"; import { ModalModule } from "ngx-bootstrap"; @@ -19,7 +21,10 @@ describe("DataservicesComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], - declarations: [ DataservicesComponent, DataservicesListComponent, DataservicesCardsComponent ] + declarations: [ DataservicesComponent, DataservicesListComponent, DataservicesCardsComponent ], + providers: [ + { provide: VdbService, useClass: MockVdbService }, + ] }); // use mock service diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 965d34fd..691e1e8d 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -133,6 +133,14 @@ export class DataservicesComponent extends AbstractPageComponent { // this.selectedServices.splice(this.selectedServices.indexOf(dataservice), 1); } + public onTest(svcName: string): void { + alert("Test Dataservice " + svcName); + } + + public onPublish(svcName: string): void { + alert("Publish Dataservice " + svcName); + } + public onDelete(svcName: string): void { this.dataserviceNameForDelete = svcName; this.confirmDeleteDialog.open(); diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index ddb71f41..3a06f3c2 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -26,10 +26,13 @@ import { DataservicesListComponent } from "@dataservices/dataservices-list/datas import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.module"; import { DataservicesComponent } from "@dataservices/dataservices.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard/add-dataservice-wizard.component"; import { AddDataserviceComponent } from "./add-dataservice/add-dataservice.component"; +import { ConnectionTableSelectorComponent } from "./connection-table-selector/connection-table-selector.component"; +import { JdbcTableSelectorComponent } from "./jdbc-table-selector/jdbc-table-selector.component"; @NgModule({ imports: [ @@ -47,10 +50,13 @@ import { AddDataserviceComponent } from "./add-dataservice/add-dataservice.compo DataservicesComponent, DataservicesListComponent, AddDataserviceWizardComponent, - AddDataserviceComponent + AddDataserviceComponent, + ConnectionTableSelectorComponent, + JdbcTableSelectorComponent ], providers: [ DataserviceService, + VdbService, LoggerService ], exports: [ diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css new file mode 100644 index 00000000..7298d607 --- /dev/null +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css @@ -0,0 +1,28 @@ +.list-div { + position: relative; + height: 100%; + max-height: 300px; + overflow-y: auto; +} + +.jdbc-list .list-view-pf-main-info { + padding-top: 0.5em; + padding-bottom: 0.5em; +} + +.jdbc-list .list-view-pf-checkbox { + padding-top: 0; + padding-bottom: 0; + margin-top: 0; + margin-right: 5px; + margin-bottom: 0; +} + +.jdbc-list .list-group-item-heading { + font-size: 12px; + margin-right: 5px; +} + +.jdbc-list .list-view-pf-description { + width: 95%; +} diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html new file mode 100644 index 00000000..772e9be4 --- /dev/null +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -0,0 +1,105 @@ + + + +
    + Schemas +
    +
    + Tables +
    +
    + Selections +
    + + + +
    + +
    +
    +
    + + Unable to load schema +
    +
    +
    +
    + + No schema available +
    +
    +
    +
    +
    +
    +
    +
    +
    + {{ schema.getDisplayName() }} +
    +
    +
    +
    +
    +
    +
    + + + +
    + +
    +
    +
    + + Unable to load tables +
    +
    +
    +
    + + No tables available +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + {{ table.getName() }} +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    + + No tables selected +
    +
    +
    +
    +
    +
    +
    +
    +
    + {{ table.getName() }} +
    +
    +
    +
    +
    +
    +
    diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts new file mode 100644 index 00000000..0a474d3f --- /dev/null +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -0,0 +1,38 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { JdbcTableSelectorComponent } from "./jdbc-table-selector.component"; + +describe("JdbcTableSelectorComponent", () => { + let component: JdbcTableSelectorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ FormsModule, HttpModule ], + declarations: [ JdbcTableSelectorComponent ], + providers: [ + AppSettingsService, LoggerService, + { provide: ConnectionService, useClass: MockConnectionService }, + ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(JdbcTableSelectorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts new file mode 100644 index 00000000..20c20343 --- /dev/null +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -0,0 +1,302 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { Output } from "@angular/core"; +import { Input } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; +import { SchemaInfo } from "@connections/shared/schema-info.model"; +import { LoggerService } from "@core/logger.service"; +import { CatalogSchema } from "@dataservices/shared/catalog-schema.model"; +import { TableSelector } from "@dataservices/shared/table-selector"; +import { Table } from "@dataservices/shared/table.model"; +import { LoadingState } from "@shared/loading-state.enum"; + +@Component({ + selector: "app-jdbc-table-selector", + templateUrl: "./jdbc-table-selector.component.html", + styleUrls: ["./jdbc-table-selector.component.css"] +}) + +export class JdbcTableSelectorComponent implements OnInit, TableSelector { + + @Input() public connection: Connection; + @Output() public tableSelectionChanged: EventEmitter = new EventEmitter(); + + private connectionService: ConnectionService; + private logger: LoggerService; + private schemas: CatalogSchema[] = []; + private tables: Table[] = []; + private selectedSchemas: CatalogSchema[] = []; + private schemaLoadingState: LoadingState = LoadingState.LOADING; + private tableLoadingState: LoadingState = LoadingState.LOADING; + + constructor( connectionService: ConnectionService, logger: LoggerService ) { + this.connectionService = connectionService; + this.logger = logger; + } + + public ngOnInit(): void { + // Load the schema info for a connection + this.setConnection(this.connection); + } + + /* + * Set the connection for this jdbc table selector + * @param {Connection} conn the jdbc connection + */ + public setConnection(conn: Connection): void { + if (conn && conn.isJdbc()) { + this.connection = conn; + // Load the schema info for a connection + this.schemas = []; + this.schemaLoadingState = LoadingState.LOADING; + const self = this; + this.connectionService + .getConnectionSchemaInfos(this.connection.getId()) + .subscribe( + (infos) => { + self.generateSchemaNames(infos); + self.schemaLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.logger.error("[JdbcTableSelectorComponent] Error getting schemas: %o", error); + self.schemaLoadingState = LoadingState.LOADED_INVALID; + } + ); + } else { + this.schemas = []; + this.schemaLoadingState = LoadingState.LOADING; + } + } + + /* + * Toggle the schema selection + * @param {CatalogSchema} schema the schema that has been selected or deselected + */ + public toggleSchemaSelected(schema: CatalogSchema): void { + if (this.isSchemaSelected(schema)) { + this.selectedSchemas.shift(); + // Deselection of schema clears tables + this.tables = []; + this.selectedTablesChanged(); + } else { + // Only allow one item to be selected + this.selectedSchemas.shift(); + this.selectedSchemas.push(schema); + const filterInfo = new JdbcTableFilter(); + filterInfo.setConnectionName(this.connection.getId()); + filterInfo.setCatalogFilter(schema.getCatalogName()); + filterInfo.setSchemaFilter(schema.getName()); + filterInfo.setTableFilter("%"); + this.loadTablesForSchema(filterInfo); + } + } + + /* + * Determines if the provided schema is selected + * @param {CatalogSchema} schema the CatalogSchema to check + */ + public isSchemaSelected(schema: CatalogSchema): boolean { + return this.selectedSchemas.indexOf(schema) !== -1; + } + + /* + * Returns the currently selected schema. + * @returns {CatalogSchema} the selected schema + */ + public get selectedSchema( ): CatalogSchema { + return this.selectedSchemas[0]; + } + + /* + * Returns the currently selected schema. + * @returns {CatalogSchema} the selected schema + */ + public get hasSelectedSchema( ): boolean { + return this.selectedSchemas.length > 0; + } + + /** + * Determine if schemas are loading + */ + public get schemasLoading( ): boolean { + return this.schemaLoadingState === LoadingState.LOADING; + } + + /** + * Determine if schemas are loaded, valid and not empty + */ + public get schemasLoadedValidNotEmpty( ): boolean { + return (this.schemaLoadingState === LoadingState.LOADED_VALID) && this.schemas.length > 0; + } + + /** + * Determine if schemas are loaded, valid but empty + */ + public get schemasLoadedValidEmpty( ): boolean { + return (this.schemaLoadingState === LoadingState.LOADED_VALID) && this.schemas.length === 0; + } + + /** + * Determine if schemas are loaded and invalid + */ + public get schemasLoadedInvalid( ): boolean { + return this.schemaLoadingState === LoadingState.LOADED_INVALID; + } + + /* + * Get all schemas + * @returns {CatalogSchema[]} the array of schema + */ + public getSchemas(): CatalogSchema[] { + return this.schemas; + } + + /** + * Determine if tables are loading + */ + public get tablesLoading( ): boolean { + return this.tableLoadingState === LoadingState.LOADING; + } + + /** + * Determine if tables are loaded, valid and not empty + */ + public get tablesLoadedValidNotEmpty( ): boolean { + return (this.tableLoadingState === LoadingState.LOADED_VALID) && this.tables.length > 0; + } + + /** + * Determine if tables are loaded, valid but empty + */ + public get tablesLoadedValidEmpty( ): boolean { + return (this.tableLoadingState === LoadingState.LOADED_VALID) && this.tables.length === 0; + } + + /** + * Determine if tables are loaded and invalid + */ + public get tablesLoadedInvalid( ): boolean { + return this.tableLoadingState === LoadingState.LOADED_INVALID; + } + + /* + * Get all tables + * @returns {Table[]} the current tables for the selected schema + */ + public getTables(): Table[] { + return this.tables; + } + + /* + * Determine if any tables are currently selected + * @returns {boolean} true if one or more tables are selected + */ + public hasSelectedTables(): boolean { + return this.getSelectedTables().length > 0; + } + + /* + * Get the array of currently selected Tables + * @returns {Table[]} the array of selected Tables + */ + public getSelectedTables(): Table[] { + const selectedTables = []; + for ( const tbl of this.getTables() ) { + if (tbl.selected) { + selectedTables.push(tbl); + } + } + return selectedTables; + } + + /* + * Handler for changes in table selection + */ + public selectedTablesChanged( ): void { + this.tableSelectionChanged.emit(); + } + + /* + * Builds the array of CatalogSchema items from the SchemaInfo coming from + * the Komodo rest call + * @param {SchemaInfo[]} infos the array of SchemaInfo from komodo + */ + private generateSchemaNames(infos: SchemaInfo[]): void { + for (const info of infos) { + const infoName = info.getName(); + const infoType = info.getType(); + const schemaNames = info.getSchemaNames(); + if (infoType === "Catalog") { + if (schemaNames && schemaNames.length > 0) { + for (const sName of schemaNames) { + const item: CatalogSchema = new CatalogSchema(); + item.setName(sName); + item.setType("Schema"); + item.setCatalogName(infoName); + this.schemas.push(item); + } + } else { + const item: CatalogSchema = new CatalogSchema(); + item.setName(infoName); + item.setType("Catalog"); + this.schemas.push(item); + } + } else if (infoType === "Schema") { + const item: CatalogSchema = new CatalogSchema(); + item.setName(infoName); + item.setType("Schema"); + this.schemas.push(item); + } + } + } + + /* + * Populates tables array, given the supplied JdbcTableFilter + * @para {JdbcTableFilter} tableFilter the filters for getting tables + */ + private loadTablesForSchema(tableFilter: JdbcTableFilter): void { + // Load the table names for the selected Connection and Schema + this.tables = []; + this.tableLoadingState = LoadingState.LOADING; + const self = this; + this.connectionService + .getJdbcConnectionTables(tableFilter) + .subscribe( + (tableNames) => { + for ( const tName of tableNames ) { + const table = new Table(); + table.setName(tName); + table.setConnection(self.connection); + table.setCatalogName(self.selectedSchema.getCatalogName()); + table.setSchemaName(self.selectedSchema.getName()); + self.tables.push(table); + } + self.tableLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.logger.error("[JdbcTableSelectorComponent] Error getting tables: %o", error); + self.tableLoadingState = LoadingState.LOADED_INVALID; + } + ); + } + +} diff --git a/ngapp/src/app/dataservices/shared/catalog-schema.model.ts b/ngapp/src/app/dataservices/shared/catalog-schema.model.ts new file mode 100644 index 00000000..540161cb --- /dev/null +++ b/ngapp/src/app/dataservices/shared/catalog-schema.model.ts @@ -0,0 +1,91 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * CatalogSchema model. The type will be 'Catalog' or 'Schema'. For Schema, the catalogName may + * or may not be set depending on whether Catalogs are supported. + */ +export class CatalogSchema { + private name: string; + private type: string; + private catalogName: string; + + constructor() { + // nothing to do + } + + /** + * @returns {string} the info name + */ + public getName(): string { + return this.name; + } + + /** + * @returns {string} the info type + */ + public getType(): string { + return this.type; + } + + /** + * @returns {string} the catalog name + */ + public getCatalogName(): string { + return this.catalogName; + } + + /** + * @returns {string} the display name + */ + public getDisplayName(): string { + const type = this.getType(); + if ( type === "Catalog" ) { + return this.getName(); + } else if ( type === "Schema" ) { + const catalog = this.getCatalogName(); + if ( catalog && catalog.length > 0 ) { + return catalog + "." + this.getName(); + } else { + return this.getName(); + } + } + return this.catalogName; + } + + /** + * @param {string} name the name + */ + public setName( name?: string ): void { + this.name = name ? name : null; + } + + /** + * @param {string} type the type + */ + public setType( type?: string ): void { + this.type = type ? type : null; + } + + /** + * @param {string} name the name of the catalog + */ + public setCatalogName( name?: string ): void { + this.catalogName = name ? name : null; + } + +} diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 764c28d5..ce8ef1b2 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -15,6 +15,8 @@ * limitations under the License. */ +import { ReflectiveInjector } from "@angular/core"; +import { AppSettingsService } from "@core/app-settings.service"; import { Identifiable } from "@shared/identifiable"; import { SortDirection } from "@shared/sort-direction.enum"; @@ -22,6 +24,7 @@ export class Dataservice implements Identifiable< string > { private keng__id: string; private tko__description: string; + private appSettings: AppSettingsService; /** * @param {Object} json the JSON representation of a Dataservice @@ -50,8 +53,9 @@ export class Dataservice implements Identifiable< string > { } ); } - constructor() { - // nothing to do + constructor( ) { + const injector = ReflectiveInjector.resolveAndCreate([AppSettingsService]); + this.appSettings = injector.get(AppSettingsService); } /** @@ -94,7 +98,7 @@ export class Dataservice implements Identifiable< string > { * @returns {string} the dataservice dataPath (can be null) */ public getDataPath(): string { - return "/tko:komodo/tko:workspace/dsbUser/" + this.keng__id; + return this.appSettings.getKomodoUserWorkspacePath() + "/" + this.keng__id; } /** @@ -118,6 +122,14 @@ export class Dataservice implements Identifiable< string > { this.tko__description = description ? description : null; } + // overrides toJSON - we do not want the appSettings + public toJSON(): {} { + return { + keng__id: this.keng__id, + tko__description: this.tko__description + }; + } + /** * Set all object values using the supplied Dataservice json * @param {Object} values diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts b/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts index 2660f714..a2ad1c0c 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts @@ -1,17 +1,22 @@ import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; describe("DataserviceService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], - providers: [DataserviceService, LoggerService] + providers: [DataserviceService, AppSettingsService, LoggerService, + { provide: VdbService, useClass: MockVdbService } + ] }); }); - it("should be created", inject([DataserviceService, LoggerService], + it("should be created", inject([DataserviceService, AppSettingsService, LoggerService], ( service: DataserviceService ) => { expect(service).toBeTruthy(); })); diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index c241dc45..407b990c 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -18,21 +18,29 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { ApiService } from "@core/api.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; +import { Table } from "@dataservices/shared/table.model"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { environment } from "@environments/environment"; import { Observable } from "rxjs/Observable"; @Injectable() export class DataserviceService extends ApiService { + public serviceVdbSuffix = "VDB"; // Don't change - must match komodo naming convention + private http: Http; + private vdbService: VdbService; - constructor( http: Http, logger: LoggerService ) { - super( logger ); + constructor( http: Http, vdbService: VdbService, appSettings: AppSettingsService, logger: LoggerService ) { + super( appSettings, logger ); this.http = http; + this.vdbService = vdbService; } /** @@ -57,7 +65,87 @@ export class DataserviceService extends ApiService { public createDataservice(dataservice: NewDataservice): Observable { return this.http .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/" + dataservice.getId(), - dataservice, this.getAuthRequestOptions()) + dataservice, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Create a dataservice via the komodo rest interface + * @param {string} dataserviceName, + * @param {string} tablePath, + * @param {string} modelSourcePath, + * @returns {Observable} + */ + public setServiceVdbForSingleTable(dataserviceName: string, tablePath: string, modelSourcePath: string): Observable { + return this.http + .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/ServiceVdbForSingleTable", + { dataserviceName, tablePath, modelSourcePath}, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Create a readonly datarole for the dataservice + * @param {string} dataserviceName, + * @param {string} model1Name, + * @returns {Observable} + */ + public createReadonlyDataRole(dataserviceName: string, model1Name: string): Observable { + const serviceVdbName = dataserviceName + this.serviceVdbSuffix; + const READ_ONLY_DATA_ROLE_NAME = VdbsConstants.DEFAULT_READONLY_DATA_ROLE; + const VIEW_MODEL = VdbsConstants.SERVICE_VIEW_MODEL_NAME; + const userWorkspacePath = this.getKomodoUserWorkspacePath(); + + // The payload for the rest call + const payload = { + "keng__id": READ_ONLY_DATA_ROLE_NAME, + "keng__kType": "VdbDataRole", + "keng__dataPath": userWorkspacePath + "/" + serviceVdbName + "/vdb:dataRoles/" + READ_ONLY_DATA_ROLE_NAME, + "vdb__dataRole": READ_ONLY_DATA_ROLE_NAME, + "vdb__description": "The default read-only access data role.", + "vdb__grantAll": false, + "vdb__anyAuthenticated": true, + "vdb__allowCreateTemporaryTables": false, + "vdb__permissions": [ + { + "keng__id": VIEW_MODEL, + "keng__kType": "VdbPermission", + "keng__dataPath": userWorkspacePath + "/" + serviceVdbName + "/vdb:dataRoles/" + READ_ONLY_DATA_ROLE_NAME + + "/vdb:permissions/" + VIEW_MODEL, + "vdb__permission": VIEW_MODEL, + "vdb__allowAlter": false, + "vdb__allowCreate": false, + "vdb__allowDelete": false, + "vdb__allowExecute": false, + "vdb__allowRead": true, + "vdb__allowUpdate": false + }, + { + "keng__id": model1Name, + "keng__kType": "VdbPermission", + "keng__dataPath": userWorkspacePath + "/" + serviceVdbName + "/vdb:dataRoles/" + READ_ONLY_DATA_ROLE_NAME + + "/vdb:permissions/" + model1Name, + "vdb__permission": model1Name, + "vdb__allowAlter": false, + "vdb__allowCreate": false, + "vdb__allowDelete": false, + "vdb__allowExecute": false, + "vdb__allowRead": true, + "vdb__allowUpdate": false + } + ] + }; + const url = environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath + "/" + serviceVdbName + + "/VdbDataRoles/" + READ_ONLY_DATA_ROLE_NAME; + const paystr = JSON.stringify(payload); + + return this.http + .post(url, paystr, this.getAuthRequestOptions()) .map((response) => { return response.ok; }) @@ -79,4 +167,28 @@ export class DataserviceService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Create a dataservice which is a straight passthru to the supplied tables + * @param {NewDataservice} dataservice + * @param {Table} sourceTable + * @returns {Observable} + */ + public createDataserviceForSingleTable(dataservice: NewDataservice, sourceTable: Table): Observable { + const connectionName = sourceTable.getConnection().getId(); + const sourceVdbName = connectionName + VdbsConstants.SOURCE_VDB_SUFFIX; + const sourceModelName = connectionName; + const vdbPath = this.getKomodoUserWorkspacePath() + "/" + sourceVdbName; + const tablePath = vdbPath + "/" + sourceModelName + "/" + sourceTable.getName(); + const modelSourcePath = vdbPath + "/" + sourceModelName + "/vdb:sources/" + sourceModelName; + + // Chain the individual calls together in series to build the DataService + return this.createDataservice(dataservice) + .flatMap((res) => this.vdbService.updateVdbModelFromTeiid(sourceVdbName, sourceModelName, + sourceVdbName, sourceModelName)) + .flatMap((res) => this.setServiceVdbForSingleTable(dataservice.getId(), tablePath, modelSourcePath)) + .flatMap((res) => this.createReadonlyDataRole(dataservice.getId(), sourceModelName)) + .flatMap((res) => this.vdbService.undeployVdb(sourceVdbName)) + .flatMap((res) => this.vdbService.deleteVdb(sourceVdbName)); + } + } diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 11425eeb..b4cf6907 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -1,9 +1,28 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; +import { VdbService } from "@dataservices/shared/vdb.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; @@ -18,8 +37,8 @@ export class MockDataserviceService extends DataserviceService { private serv3 = new Dataservice(); private services: Dataservice[] = [this.serv1, this.serv2, this.serv3]; - constructor( http: Http, logger: LoggerService ) { - super(http, logger); + constructor( http: Http, vdbService: VdbService, appSettings: AppSettingsService, logger: LoggerService ) { + super(http, vdbService, appSettings, logger); this.serv1.setId("serv1"); this.serv2.setId("serv2"); this.serv3.setId("serv3"); diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts new file mode 100644 index 00000000..e45ad2c3 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -0,0 +1,162 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from "@angular/core"; +import { Http } from "@angular/http"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { Table } from "@dataservices/shared/table.model"; +import { VdbModelSource } from "@dataservices/shared/vdb-model-source.model"; +import { VdbModel } from "@dataservices/shared/vdb-model.model"; +import { VdbStatus } from "@dataservices/shared/vdb-status.model"; +import { Vdb } from "@dataservices/shared/vdb.model"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import "rxjs/add/observable/of"; +import "rxjs/add/observable/throw"; +import "rxjs/add/operator/catch"; +import "rxjs/add/operator/map"; +import { Observable } from "rxjs/Observable"; + +@Injectable() +export class MockVdbService extends VdbService { + + private vdb1 = new Vdb(); + private vdb2 = new Vdb(); + private vdb3 = new Vdb(); + private vdbs: Vdb[] = [this.vdb1, this.vdb2, this.vdb3]; + + private vdbStatus1 = new VdbStatus(); + private vdbStatus2 = new VdbStatus(); + private vdbStatus3 = new VdbStatus(); + private statuses: VdbStatus[] = [this.vdbStatus1, this.vdbStatus3, this.vdbStatus3]; + + constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { + super(http, appSettings, logger); + this.vdb1.setId("serv1"); + this.vdb2.setId("serv2"); + this.vdb3.setId("serv3"); + } + + /** + * Get the vdbs from the komodo rest interface + * @returns {Observable} + */ + public getVdbs(): Observable { + return Observable.of(this.vdbs); + } + + /** + * Get the vdbs from the komodo rest interface + * @returns {Observable} + */ + public getTeiidVdbStatuses(): Observable { + return Observable.of(this.statuses); + } + + /** + * Create a vdb via the komodo rest interface + * @param {Vdb} vdb + * @returns {Observable} + */ + public createVdb(vdb: Vdb): Observable { + return Observable.of(true); + } + + /** + * Create a vdb via the komodo rest interface + * @param {string} vdbName + * @param {VdbModel} vdbModel + * @returns {Observable} + */ + public createVdbModel(vdbName: string, vdbModel: VdbModel): Observable { + return Observable.of(true); + } + + /** + * Create a vdbModelSource via the komodo rest interface + * @param {string} vdbName the vdb name + * @param {string} modelName the model name + * @param {VdbModelSource} vdbModelSource the modelsource name + * @returns {Observable} + */ + public createVdbModelSource(vdbName: string, modelName: string, vdbModelSource: VdbModelSource): Observable { + return Observable.of(true); + } + + /** + * Delete a vdb via the komodo rest interface + * @param {string} vdbId + * @returns {Observable} + */ + public deleteVdb(vdbId: string): Observable { + return Observable.of(true); + } + + /** + * Deploys the workspace VDB with the provided name + * @param {string} vdbName + * @returns {Observable} + */ + public deployVdb(vdbName: string): Observable { + return Observable.of(true); + } + + /** + * Undeploy a vdb from the teiid server + * @param {string} vdbId + * @returns {Observable} + */ + public undeployVdb(vdbId: string): Observable { + return Observable.of(true); + } + + /** + * Update the specified repo VDB Model using the DDL from the specified Teiid VDB + * @param {string} vdbName the VDB in the repo to update + * @param {string} modelName the Model withing the specified repo VDB + * @param {string} teiidVdbName the deployed teiid VDB name + * @param {string} teiidModelName the teiid VDB Model name + * @returns {Observable} + */ + public updateVdbModelFromTeiid(vdbName: string, modelName: string, + teiidVdbName: string, teiidModelName: string): Observable { + return Observable.of(true); + } + + /** + * Polls the server for the specified VDB. Polling will terminate if + * (1) The VDB is active + * (2) The VDB is in a failed state + * (3) The polling duration has lapsed + * @param {string} vdbName the name of the VDB + * @param {number} pollDurationSec the duration (sec) to poll the server + * @param {number} pollIntervalSec the interval (sec) between polling attempts + */ + public pollForActiveVdb(vdbName: string, pollDurationSec: number, pollIntervalSec: number): void { + return; + } + + /** + * Create and deploy a VDB for the provided table + * @param {Table} table + * @returns {Observable} + */ + public deployVdbForTable(table: Table): Observable { + return Observable.of(true); + } + +} diff --git a/ngapp/src/app/dataservices/shared/name-value.model.ts b/ngapp/src/app/dataservices/shared/name-value.model.ts new file mode 100644 index 00000000..9c6dc97c --- /dev/null +++ b/ngapp/src/app/dataservices/shared/name-value.model.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A model for holding simple name-value pairs. + */ +export class NameValue { + + private name: string; + private value: string; + + constructor(name: string, value: string) { + this.name = name; + this.value = value; + } + +} diff --git a/ngapp/src/app/dataservices/shared/new-dataservice.model.ts b/ngapp/src/app/dataservices/shared/new-dataservice.model.ts index 499b6c27..d3d01cea 100644 --- a/ngapp/src/app/dataservices/shared/new-dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/new-dataservice.model.ts @@ -14,6 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { ReflectiveInjector } from "@angular/core"; +import { AppSettingsService } from "@core/app-settings.service"; export class NewDataservice { @@ -21,12 +23,15 @@ export class NewDataservice { private keng__dataPath: string; private keng__kType: string; private tko__description: string; + private appSettings: AppSettingsService; /** * Constructor */ - constructor() { + constructor( ) { this.keng__kType = "Dataservice"; + const injector = ReflectiveInjector.resolveAndCreate([AppSettingsService]); + this.appSettings = injector.get(AppSettingsService); } /** @@ -48,7 +53,7 @@ export class NewDataservice { */ public setId( name: string ): void { this.keng__id = name; - this.keng__dataPath = "/tko:komodo/tko:workspace/dsbUser/" + name; + this.keng__dataPath = this.appSettings.getKomodoUserWorkspacePath() + "/" + name; } /** @@ -57,4 +62,14 @@ export class NewDataservice { public setDescription( description?: string ): void { this.tko__description = description ? description : null; } + + // overrides toJSON - we do not want the appSettings + public toJSON(): {} { + return { + keng__id: this.keng__id, + keng__dataPath: this.keng__dataPath, + keng__kType: this.keng__kType, + tko__description: this.tko__description + }; + } } diff --git a/ngapp/src/app/dataservices/shared/table-selector.ts b/ngapp/src/app/dataservices/shared/table-selector.ts new file mode 100644 index 00000000..7be5a5cc --- /dev/null +++ b/ngapp/src/app/dataservices/shared/table-selector.ts @@ -0,0 +1,44 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Connection } from "@connections/shared/connection.model"; +import { Table } from "@dataservices/shared/table.model"; + +/** + * The table selector interface + */ +export interface TableSelector { + + /* + * Set the connection for this jdbc table selector + * @param {Connection} conn the jdbc connection + */ + setConnection(conn: Connection): void; + + /* + * Determine if any tables are currently selected + * @returns {boolean} true if one or more tables are selected + */ + hasSelectedTables( ): boolean; + + /* + * Get the array of currently selected Tables + * @returns {Table[]} the array of selected Tables (never null, but may be empty) + */ + getSelectedTables(): Table[]; + +} diff --git a/ngapp/src/app/dataservices/shared/table.model.ts b/ngapp/src/app/dataservices/shared/table.model.ts new file mode 100644 index 00000000..983641ec --- /dev/null +++ b/ngapp/src/app/dataservices/shared/table.model.ts @@ -0,0 +1,104 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Connection } from "@connections/shared/connection.model"; + +/** + * Table model + */ +export class Table { + private name: string; + private connection: Connection; + private catalogName: string; + private schemaName: string; + private isSelected = false; + + constructor() { + // nothing to do + } + + /** + * @returns {string} the table name + */ + public getName(): string { + return this.name; + } + + /** + * @param {string} name the table name + */ + public setName( name?: string ): void { + this.name = name ? name : null; + } + + /** + * @returns {Connection} the connection for the table + */ + public getConnection(): Connection { + return this.connection; + } + + /** + * @param {string} connection the connection for the table + */ + public setConnection( connection?: Connection ): void { + this.connection = connection ? connection : null; + } + + /** + * @returns {string} the catalog name for the table + */ + public getCatalogName(): string { + return this.catalogName; + } + + /** + * @param {string} catalogName the connection name for the table + */ + public setCatalogName( catalogName?: string ): void { + this.catalogName = catalogName ? catalogName : null; + } + + /** + * @returns {string} the schema name for the table + */ + public getSchemaName(): string { + return this.schemaName; + } + + /** + * @param {string} schemaName the schema name for the table + */ + public setSchemaName( schemaName?: string ): void { + this.schemaName = schemaName ? schemaName : null; + } + + /** + * @returns {boolean} true if selected + */ + public get selected(): boolean { + return this.isSelected; + } + + /** + * @param {boolean} selected 'true' if selected + */ + public set selected( selected: boolean ) { + this.isSelected = selected; + } + +} diff --git a/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts b/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts new file mode 100644 index 00000000..b0fae2eb --- /dev/null +++ b/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts @@ -0,0 +1,114 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * VdbModelSource model + */ +export class VdbModelSource { + + private keng__id: string; + private keng__dataPath: string; + private keng__kType = "VdbModelSource"; + private vdb__sourceJndiName: string; + private vdb__sourceTranslator: string; + + /** + * @param {Object} json the JSON representation of a VdbModelSource + * @returns {VdbModelSource} the new VdbModelSource (never null) + */ + public static create( json: object = {} ): VdbModelSource { + const vdbModelSource = new VdbModelSource(); + vdbModelSource.setValues( json ); + return vdbModelSource; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the vdbModelSource identifier (can be null) + */ + public getId(): string { + return this.keng__id; + } + + /** + * @returns {string} the vdbModelSource dataPath (can be null) + */ + public getDataPath(): string { + return this.keng__dataPath; + } + + /** + * @returns {string} the vdbModelSource type name (can be null) + */ + public getType(): string { + return this.keng__kType; + } + + /** + * @returns {string} the jndi name (can be null) + */ + public getJndiName(): string { + return this.vdb__sourceJndiName; + } + + /** + * @returns {string} the translator name (can be null) + */ + public getTranslatorName(): string { + return this.vdb__sourceTranslator; + } + + /** + * @param {string} id the vdbModelSource identifier (optional) + */ + public setId( id?: string ): void { + this.keng__id = id ? id : null; + } + + /** + * @param {string} dataPath the vdbModelSource dataPath (optional) + */ + public setDataPath( dataPath?: string ): void { + this.keng__dataPath = dataPath ? dataPath : null; + } + + /** + * @param {string} jndiName the jndi name (optional) + */ + public setJndiName( jndiName?: string ): void { + this.vdb__sourceJndiName = jndiName ? jndiName : null; + } + + /** + * @param {string} translator the translator name (optional) + */ + public setTranslatorName( translator?: string ): void { + this.vdb__sourceTranslator = translator ? translator : null; + } + + /** + * Set all object values using the supplied VdbModelSource json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/dataservices/shared/vdb-model.model.ts b/ngapp/src/app/dataservices/shared/vdb-model.model.ts new file mode 100644 index 00000000..215972cf --- /dev/null +++ b/ngapp/src/app/dataservices/shared/vdb-model.model.ts @@ -0,0 +1,110 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NameValue } from "@dataservices/shared/name-value.model"; + +/** + * VdbModel model + */ +export class VdbModel { + + private keng__id: string; + private keng__dataPath: string; + private keng__kType = "VdbModel"; + private mmcore__modelType: string; + // noinspection JSMismatchedCollectionQueryUpdate + private keng__properties: NameValue[] = []; + + /** + * @param {Object} json the JSON representation of a VdbModel + * @returns {VdbModel} the new VdbModel (never null) + */ + public static create( json: object = {} ): VdbModel { + const vdbModel = new VdbModel(); + vdbModel.setValues( json ); + return vdbModel; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the vdbModel identifier (can be null) + */ + public getId(): string { + return this.keng__id; + } + + /** + * @returns {string} the vdbModel dataPath (can be null) + */ + public getDataPath(): string { + return this.keng__dataPath; + } + + /** + * @returns {string} the vdbModel type name (can be null) + */ + public getType(): string { + return this.keng__kType; + } + + /** + * @returns {string} the vdbModel model type + */ + public getModelType(): string { + return this.mmcore__modelType; + } + + /** + * @param {string} id the vdbModel identifier (optional) + */ + public setId( id?: string ): void { + this.keng__id = id ? id : null; + } + + /** + * @param {string} dataPath the vdbModel dataPath (optional) + */ + public setDataPath( dataPath?: string ): void { + this.keng__dataPath = dataPath ? dataPath : null; + } + + /** + * @param {string} modelType the vdbModel type + */ + public setModelType( modelType: string ): void { + this.mmcore__modelType = modelType; + } + + /** + * @param {NameValue[]} props the model properties (optional) + */ + public setProperties( props?: NameValue[] ): void { + this.keng__properties = props ? props : null; + } + + /** + * Set all object values using the supplied VdbModel json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/dataservices/shared/vdb-status.model.ts b/ngapp/src/app/dataservices/shared/vdb-status.model.ts new file mode 100644 index 00000000..2b310105 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/vdb-status.model.ts @@ -0,0 +1,151 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * VdbStatus model + */ +export class VdbStatus { + + private name: string; + private deployedName: string; + private version = "1"; + private active = false; + private loading = false; + private failed = false; + private errors: string[] = []; + + /** + * @param {Object} json the JSON representation of a VdbStatus + * @returns {VdbStatus} the new VdbStatus (never null) + */ + public static create( json: object = {} ): VdbStatus { + const vdbStatus = new VdbStatus(); + vdbStatus.setValues( json ); + return vdbStatus; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the vdbStatus name + */ + public getName(): string { + return this.name; + } + + /** + * @returns {string} the vdbStatus deployedName + */ + public getDeployedName(): string { + return this.deployedName; + } + + /** + * @returns {string} the vdbStatus version (can be null) + */ + public getVersion(): string { + return this.version; + } + + /** + * @returns {boolean} the vdbStatus active state + */ + public isActive(): boolean { + return this.active; + } + + /** + * @returns {boolean} the vdbStatus loading state + */ + public isLoading(): boolean { + return this.loading; + } + + /** + * @returns {boolean} the vdbStatus failed state + */ + public isFailed(): boolean { + return this.failed; + } + + /** + * @returns {string[]} the errors (never null) + */ + public getErrors(): string[] { + return this.errors; + } + + /** + * @param {string} name the vdbStatus name + */ + public setName( name: string ): void { + this.name = name; + } + + /** + * @param {string} deployedName the vdbStatus deployedName + */ + public setDeployedName( deployedName: string ): void { + this.deployedName = deployedName; + } + + /** + * @param {string} version the vdbStatus version (optional) + */ + public setVersion( version?: string ): void { + this.version = version ? version : "1"; + } + + /** + * @param {boolean} active the active state + */ + public setActive( active: boolean ): void { + this.active = active; + } + + /** + * @param {boolean} loading the loading state + */ + public setLoading( loading: boolean ): void { + this.loading = loading; + } + + /** + * @param {boolean} failed the failed state + */ + public setFailed( failed: boolean ): void { + this.failed = failed; + } + + /** + * @param {[string]} errors the status errors + */ + public setErrors( errors: string[] ): void { + this.errors = errors; + } + + /** + * Set all object values using the supplied VdbStatus json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/dataservices/shared/vdb.model.ts b/ngapp/src/app/dataservices/shared/vdb.model.ts new file mode 100644 index 00000000..6df84a81 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/vdb.model.ts @@ -0,0 +1,201 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Identifiable } from "@shared/identifiable"; +import { SortDirection } from "@shared/sort-direction.enum"; + +/** + * Vdb model + */ +export class Vdb implements Identifiable< string > { + + private keng__id: string; + private vdb__description: string; + private keng__dataPath: string; + private keng__kType = "Vdb"; + private vdb__name: string; + private vdb__originalFile: string; + private vdb__preview: boolean; + private vdb__version: string; + + /** + * @param {Object} json the JSON representation of a Vdb + * @returns {Vdb} the new Vdb (never null) + */ + public static create( json: object = {} ): Vdb { + const vdb = new Vdb(); + vdb.setValues( json ); + return vdb; + } + + /** + * @param {Vdb[]} vdbs the vdbs being sorted + * @param {SortDirection} sortDirection the sort direction + */ + public static sort( vdbs: Vdb[], + sortDirection: SortDirection ): void { + vdbs.sort( ( thisVdb: Vdb, thatVdb: Vdb ) => { + const result = thisVdb.compareTo( thatVdb ); + + if ( sortDirection === SortDirection.DESC ) { + return result * -1; + } + + return result; + } ); + } + + constructor() { + // nothing to do + } + + /** + * See {Identifiable}. + */ + public compareTo( that: Vdb ): number { + let result = 0; + + if ( this.getId() ) { + if ( that.getId() ) { + // both have an ID + result = this.getId().localeCompare( that.getId() ); + } else { + // thatItem does not have an ID + result = 1; + } + } else if ( that.getId() ) { + // thisItem does not have an ID and thatItem does + result = -1; + } + + return result; + } + + /** + * @returns {string} the vdb identifier (can be null) + */ + public getId(): string { + return this.keng__id; + } + + /** + * @returns {string} the vdb name (can be null) + */ + public getName(): string { + return this.vdb__name; + } + + /** + * @returns {string} the vdb description (can be null) + */ + public getDescription(): string { + return this.vdb__description; + } + + /** + * @returns {string} the vdb dataPath (can be null) + */ + public getDataPath(): string { + return this.keng__dataPath; + } + + /** + * @returns {string} the vdb originalFile (can be null) + */ + public getOriginalFile(): string { + return this.vdb__originalFile; + } + + /** + * @returns {string} the vdb type name (can be null) + */ + public getType(): string { + return this.keng__kType; + } + + /** + * @returns {boolean} the vdb preview status + */ + public isPreview(): boolean { + return this.vdb__preview; + } + + /** + * @returns {string} the vdb type name (can be null) + */ + public getVersion(): string { + return this.vdb__version; + } + + /** + * @param {string} id the vdb identifier (optional) + */ + public setId( id?: string ): void { + this.keng__id = id ? id : null; + } + + /** + * @param {string} name the vdb name (optional) + */ + public setName( name?: string ): void { + this.vdb__name = name ? name : null; + } + + /** + * @param {string} description the vdb description (optional) + */ + public setDescription( description?: string ): void { + this.vdb__description = description ? description : null; + } + + /** + * @param {string} dataPath the vdb dataPath (optional) + */ + public setDataPath( dataPath?: string ): void { + this.keng__dataPath = dataPath ? dataPath : null; + } + + /** + * @param {string} originalFile the vdb originalFile (optional) + */ + public setOriginalFile( originalFile?: string ): void { + this.vdb__originalFile = originalFile ? originalFile : null; + } + + /** + * @param {boolean} preview the vdb preview status + */ + public setPreview( preview: boolean ): void { + this.vdb__preview = preview; + } + + /** + * @param {string} version the vdb version + */ + public setVersion( version?: string ): void { + this.vdb__version = version; + } + + /** + * Set all object values using the supplied Vdb json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/dataservices/shared/vdb.service.spec.ts b/ngapp/src/app/dataservices/shared/vdb.service.spec.ts new file mode 100644 index 00000000..9d121ec7 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/vdb.service.spec.ts @@ -0,0 +1,19 @@ +import { inject, TestBed } from "@angular/core/testing"; +import { HttpModule } from "@angular/http"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; + +describe("VdbService", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ HttpModule ], + providers: [VdbService, AppSettingsService, LoggerService] + }); + }); + + it("should be created", inject([VdbService, AppSettingsService, LoggerService], + ( service: VdbService ) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts new file mode 100644 index 00000000..3bc6f5fd --- /dev/null +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -0,0 +1,326 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from "@angular/core"; +import { Http } from "@angular/http"; +import { Connection } from "@connections/shared/connection.model"; +import { ApiService } from "@core/api.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { NameValue } from "@dataservices/shared/name-value.model"; +import { Table } from "@dataservices/shared/table.model"; +import { VdbModelSource } from "@dataservices/shared/vdb-model-source.model"; +import { VdbModel } from "@dataservices/shared/vdb-model.model"; +import { VdbStatus } from "@dataservices/shared/vdb-status.model"; +import { Vdb } from "@dataservices/shared/vdb.model"; +import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; +import { environment } from "@environments/environment"; +import { ReplaySubject } from "rxjs/ReplaySubject"; +import { Observable } from "rxjs/Rx"; +import { Subject } from "rxjs/Subject"; +import { Subscription } from "rxjs/Subscription"; + +@Injectable() +/** + * VdbService + */ +export class VdbService extends ApiService { + + // Observable deployment status + // Using replay status with cache of 1, so subscribers dont get an initial value on subscription + public deploymentStatus: Subject = new ReplaySubject(1); + + private http: Http; + private deploymentSubscription: Subscription; + + constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { + super( appSettings, logger ); + this.http = http; + } + + /** + * Get the vdbs from the komodo rest interface + * @returns {Observable} + */ + public getVdbs(): Observable { + return this.http + .get(environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath, this.getAuthRequestOptions()) + .map((response) => { + const vdbs = response.json(); + return vdbs.map((vdb) => Vdb.create( vdb )); + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Get the vdbs from the komodo rest interface + * @returns {Observable} + */ + public getTeiidVdbStatuses(): Observable { + return this.http + .get(environment.komodoTeiidUrl + VdbsConstants.statusPath + VdbsConstants.vdbsRootPath, this.getAuthRequestOptions()) + .map((response) => { + const vdbStatuses = response.json(); + return vdbStatuses.vdbs.map((vdbStatus) => VdbStatus.create( vdbStatus )); + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Create a vdb via the komodo rest interface + * @param {Vdb} vdb + * @returns {Observable} + */ + public createVdb(vdb: Vdb): Observable { + return this.http + .post(environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath + "/" + vdb.getId(), + vdb, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Create a vdb via the komodo rest interface + * @param {string} vdbName + * @param {VdbModel} vdbModel + * @returns {Observable} + */ + public createVdbModel(vdbName: string, vdbModel: VdbModel): Observable { + const str = JSON.stringify(vdbModel); + return this.http + .post(environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath + "/" + vdbName + + VdbsConstants.vdbModelsRootPath + "/" + vdbModel.getId(), + str, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Create a vdbModelSource via the komodo rest interface + * @param {string} vdbName the vdb name + * @param {string} modelName the model name + * @param {VdbModelSource} vdbModelSource the modelsource name + * @returns {Observable} + */ + public createVdbModelSource(vdbName: string, modelName: string, vdbModelSource: VdbModelSource): Observable { + return this.http + .post(environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath + "/" + vdbName + + VdbsConstants.vdbModelsRootPath + "/" + modelName + + VdbsConstants.vdbModelSourcesRootPath + "/" + vdbModelSource.getId(), + vdbModelSource, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Delete a vdb via the komodo rest interface + * @param {string} vdbId + * @returns {Observable} + */ + public deleteVdb(vdbId: string): Observable { + return this.http + .delete(environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath + "/" + vdbId, + this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Deploys the workspace VDB with the provided name + * @param {string} vdbName + * @returns {Observable} + */ + public deployVdb(vdbName: string): Observable { + const vdbPath = this.getKomodoUserWorkspacePath() + "/" + vdbName; + return this.http + .post(environment.komodoTeiidUrl + VdbsConstants.vdbRootPath, + { path: vdbPath}, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Undeploy a vdb from the teiid server + * @param {string} vdbId + * @returns {Observable} + */ + public undeployVdb(vdbId: string): Observable { + return this.http + .delete(environment.komodoTeiidUrl + VdbsConstants.vdbsRootPath + "/" + vdbId, + this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Update the specified repo VDB Model using the DDL from the specified Teiid VDB + * @param {string} vdbName the VDB in the repo to update + * @param {string} modelName the Model withing the specified repo VDB + * @param {string} teiidVdbName the deployed teiid VDB name + * @param {string} teiidModelName the teiid VDB Model name + * @returns {Observable} + */ + public updateVdbModelFromTeiid(vdbName: string, modelName: string, + teiidVdbName: string, teiidModelName: string): Observable { + return this.http + .post(environment.komodoTeiidUrl + VdbsConstants.vdbsRootPath + "/ModelFromTeiidDdl", + { vdbName, modelName, teiidVdbName, teiidModelName }, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + + /** + * Polls the server for the specified VDB. Polling will terminate if + * (1) The VDB is active + * (2) The VDB is in a failed state + * (3) The polling duration has lapsed + * @param {string} vdbName the name of the VDB + * @param {number} pollDurationSec the duration (sec) to poll the server + * @param {number} pollIntervalSec the interval (sec) between polling attempts + */ + public pollForActiveVdb(vdbName: string, pollDurationSec: number, pollIntervalSec: number): void { + const pollIntervalMillis = pollIntervalSec * 1000; + const pollIterations = pollDurationSec / pollIntervalSec; + + let pollCount = 0; + const self = this; + // start a timer after one second + const timer = Observable.timer(1000, pollIntervalMillis); + this.deploymentSubscription = timer.subscribe((t: any) => { + this.getTeiidVdbStatuses() + .subscribe( + (resp) => { + for ( const vdbStatus of resp ) { + if ( vdbStatus.getName() !== vdbName ) { + continue; + } + if ( vdbStatus.isActive() ) { + self.broadcastDeploymentChange(vdbStatus); + } else if ( vdbStatus.isFailed() ) { + self.broadcastDeploymentChange(vdbStatus); + } + } + pollCount++; + if (pollCount > pollIterations) { + // Timed out status + const status: VdbStatus = new VdbStatus(); + status.setName(vdbName); + status.setActive(false); + status.setLoading(false); + status.setFailed(true); + const errors: string[] = []; + errors.push("Deployment polling timed out"); + status.setErrors(errors); + // broadcast the status + self.broadcastDeploymentChange(status); + } + }, + (error) => { + // Error status + const status: VdbStatus = new VdbStatus(); + status.setName(vdbName); + status.setActive(false); + status.setLoading(false); + status.setFailed(true); + const errors: string[] = []; + errors.push("Deployment failed"); + status.setErrors(errors); + // Broadcast the status + self.broadcastDeploymentChange(status); + } + ); + }); + } + + /** + * Create and deploy a VDB for the provided table + * @param {Table} table + * @returns {Observable} + */ + public deployVdbForTable(table: Table): Observable { + const connection: Connection = table.getConnection(); + + // VDB to create + const vdb = new Vdb(); + const vdbName = connection.getId() + VdbsConstants.SOURCE_VDB_SUFFIX; + const connName = connection.getId(); + vdb.setName(vdbName); + vdb.setId(vdbName); + const vdbPath = this.getKomodoUserWorkspacePath() + "/" + vdbName; + vdb.setDataPath(vdbPath); + vdb.setOriginalFile(vdbPath); + vdb.setDescription(vdbName + " description"); + + // VDB Model to create + const vdbModel = new VdbModel(); + vdbModel.setId(connName); + vdbModel.setDataPath(vdbPath + "/" + connName); + vdbModel.setModelType("PHYSICAL"); + // Filter values for the model + let catName = table.getCatalogName(); + let schemaName = table.getSchemaName(); + let tableName = table.getName(); + catName = (!catName || catName.length < 1) ? "%" : catName; + schemaName = (!schemaName || schemaName.length < 1) ? "%" : schemaName; + tableName = (!tableName || tableName.length < 1) ? "%" : tableName; + // Set the importer properties for the physical model + const props: NameValue[] = []; + props.push(new NameValue("importer.TableTypes", "TABLE")); + props.push(new NameValue("importer.UseFullSchemaName", "false")); + props.push(new NameValue("importer.UseQualifiedName", "false")); + props.push(new NameValue("importer.UseCatalogName", "false")); + props.push(new NameValue("importer.catalog", catName)); + props.push(new NameValue("importer.schemaPattern", schemaName)); + props.push(new NameValue("importer.tableNamePattern", tableName)); + vdbModel.setProperties(props); + + // VdbModelSource to create + const vdbModelSource = new VdbModelSource(); + vdbModelSource.setId(connName); + vdbModelSource.setDataPath(vdbPath + "/" + connName + "/vdb:sources/" + connName); + vdbModelSource.setJndiName(connection.getJndiName()); + vdbModelSource.setTranslatorName(connection.getDriverName()); + + // Chain the individual calls together in series to build the Vdb and deploy it + return this.createVdb(vdb) + .flatMap((res) => this.createVdbModel(vdb.getId(), vdbModel)) + .flatMap((res) => this.createVdbModelSource(vdb.getId(), vdbModel.getId(), vdbModelSource)) + .flatMap((res) => this.deployVdb(vdb.getId())); + } + + // Broadcast of the deployment status changes + private broadcastDeploymentChange(status: VdbStatus): void { + this.deploymentSubscription.unsubscribe(); + this.deploymentStatus.next(status); + this.deploymentStatus.next(null); + } + +} diff --git a/ngapp/src/app/dataservices/shared/vdbs-constants.ts b/ngapp/src/app/dataservices/shared/vdbs-constants.ts new file mode 100644 index 00000000..30129915 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/vdbs-constants.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, / + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class VdbsConstants { + + public static readonly SERVICE_VIEW_MODEL_NAME = "views"; // ** must match KomodoDataserviceService.SERVICE_VDB_VIEW_MODEL ** + public static readonly SOURCE_VDB_SUFFIX = "SvcSource"; + public static readonly DEFAULT_READONLY_DATA_ROLE = "DefaultReadOnlyDataRole"; + + public static readonly statusPath = "/status"; + + public static readonly vdbRootRoute = "vdb"; + public static readonly vdbRootPath = "/" + VdbsConstants.vdbRootRoute; + + public static readonly vdbsRootRoute = "vdbs"; + public static readonly vdbsRootPath = "/" + VdbsConstants.vdbsRootRoute; + + public static readonly vdbModelsRootRoute = "Models"; + public static readonly vdbModelsRootPath = "/" + VdbsConstants.vdbModelsRootRoute; + + public static readonly vdbModelSourcesRootRoute = "VdbModelSources"; + public static readonly vdbModelSourcesRootPath = "/" + VdbsConstants.vdbModelSourcesRootRoute; +} diff --git a/ngapp/src/app/shared/loading-state.enum.ts b/ngapp/src/app/shared/loading-state.enum.ts new file mode 100644 index 00000000..f367589f --- /dev/null +++ b/ngapp/src/app/shared/loading-state.enum.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * An enumeration of loading state + */ +export enum LoadingState { + + /** + * loading + */ + LOADING, + + /** + * loaded and valid + */ + LOADED_VALID, + + /** + * loaded and invalid + */ + LOADED_INVALID + +} diff --git a/ngapp/src/main.ts b/ngapp/src/main.ts index 26d51333..b4662e5b 100644 --- a/ngapp/src/main.ts +++ b/ngapp/src/main.ts @@ -1,3 +1,20 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import { enableProdMode } from "@angular/core"; import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; import { AppModule } from "@app/app.module"; From 3a39f38fa356f86b8e7f47225368e850f8c527ee Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 21 Nov 2017 16:27:57 -0600 Subject: [PATCH 042/205] Initial commit of export and test features --- ngapp/locale/messages.es.xlf | 4 +- ngapp/messages.xlf | 2 +- .../app/activities/activities.component.html | 2 +- .../add-activity/add-activity.component.html | 2 +- .../add-connection.component.html | 2 +- .../connections/connections.component.html | 2 +- ngapp/src/app/core/app-settings.service.ts | 29 +++- .../core/nav-header/nav-header.component.html | 4 +- .../add-dataservice-wizard.component.html | 10 +- .../add-dataservice-wizard.component.ts | 15 ++ .../add-dataservice.component.html | 2 +- .../dataservices-cards.component.html | 6 +- .../dataservices-list.component.html | 10 +- .../dataservices-routing.module.ts | 4 +- .../dataservices/dataservices.component.html | 11 +- .../dataservices.component.spec.ts | 3 +- .../dataservices/dataservices.component.ts | 39 ++++- .../app/dataservices/dataservices.module.ts | 6 +- .../dataservices/shared/column-data.model.ts | 58 +++++++ .../dataservices/shared/dataservice.model.ts | 82 ++++++++- .../shared/dataservice.service.ts | 102 ++++++++++++ .../shared/dataservices-constants.ts | 8 + .../shared/mock-dataservice.service.ts | 17 ++ .../shared/query-results.model.ts | 83 ++++++++++ .../app/dataservices/shared/row-data.model.ts | 42 +++++ .../sql-control/sql-control.component.css | 23 +++ .../sql-control/sql-control.component.html | 36 ++++ .../sql-control/sql-control.component.spec.ts | 41 +++++ .../sql-control/sql-control.component.ts | 155 ++++++++++++++++++ .../test-dataservice.component.css | 0 .../test-dataservice.component.html | 30 ++++ .../test-dataservice.component.spec.ts | 40 +++++ .../test-dataservice.component.ts | 73 +++++++++ .../confirm-delete.component.html | 2 +- ngapp/src/environments/environment.prod.ts | 3 + ngapp/src/environments/environment.ts | 3 + 36 files changed, 921 insertions(+), 30 deletions(-) create mode 100644 ngapp/src/app/dataservices/shared/column-data.model.ts create mode 100644 ngapp/src/app/dataservices/shared/query-results.model.ts create mode 100644 ngapp/src/app/dataservices/shared/row-data.model.ts create mode 100644 ngapp/src/app/dataservices/sql-control/sql-control.component.css create mode 100644 ngapp/src/app/dataservices/sql-control/sql-control.component.html create mode 100644 ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts create mode 100644 ngapp/src/app/dataservices/sql-control/sql-control.component.ts create mode 100644 ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.css create mode 100644 ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html create mode 100644 ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts create mode 100644 ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts diff --git a/ngapp/locale/messages.es.xlf b/ngapp/locale/messages.es.xlf index 482b3159..96e6232c 100644 --- a/ngapp/locale/messages.es.xlf +++ b/ngapp/locale/messages.es.xlf @@ -375,8 +375,8 @@ - BeETLe Studio - BeETLE Studio + Beetle Studio + BeetlE Studio src/app/core/nav-header/nav-header.component.ts 4 diff --git a/ngapp/messages.xlf b/ngapp/messages.xlf index 465e769c..ce23c9a4 100644 --- a/ngapp/messages.xlf +++ b/ngapp/messages.xlf @@ -257,7 +257,7 @@ - BeETLe Studio + Beetle Studio src/app/core/nav-header/nav-header.component.ts 4 diff --git a/ngapp/src/app/activities/activities.component.html b/ngapp/src/app/activities/activities.component.html index 4246ff2a..b8997308 100644 --- a/ngapp/src/app/activities/activities.component.html +++ b/ngapp/src/app/activities/activities.component.html @@ -9,7 +9,7 @@
    -
    +

    Activities

    diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.html b/ngapp/src/app/activities/add-activity/add-activity.component.html index c65310ee..cff708ed 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.html +++ b/ngapp/src/app/activities/add-activity/add-activity.component.html @@ -6,7 +6,7 @@
    -
    +

    diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index 250c1ea7..40cba9b4 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -6,7 +6,7 @@
    -
    +

    diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index b361ed07..b7437b35 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -9,7 +9,7 @@
    -
    +

    Connections

    diff --git a/ngapp/src/app/core/app-settings.service.ts b/ngapp/src/app/core/app-settings.service.ts index 086a2b88..bb644950 100644 --- a/ngapp/src/app/core/app-settings.service.ts +++ b/ngapp/src/app/core/app-settings.service.ts @@ -20,14 +20,33 @@ import { Injectable } from "@angular/core"; @Injectable() export class AppSettingsService { + // ** Dont change git keys - must match Komodo rest call parameters ** + public readonly GIT_REPO_BRANCH_KEY = "repo-branch-property"; + public readonly GIT_REPO_AUTHOR_NAME_KEY = "author-name-property"; + public readonly GIT_REPO_AUTHOR_EMAIL_KEY = "author-email-property"; + public readonly GIT_REPO_USERNAME_KEY = "repo-username-property"; + public readonly GIT_REPO_PASSWORD_KEY = "repo-password-property"; + public readonly GIT_REPO_PATH_KEY = "repo-path-property"; + public readonly GIT_REPO_FILE_PATH_KEY = "file-path-property"; + private readonly komodoRoot = "tko:komodo/tko:workspace"; // TODO: temporary location for user and password private readonly komodoUser = "dsbUser"; private readonly komodoUserPassword = "1demo-user1"; + // Map to maintain the target git repository properties + private readonly gitRepoProperties: Map; + constructor() { - // Nothing to do + // TODO: The git repository properties will be picked up based on the Openshift install location + this.gitRepoProperties = new Map(); + this.gitRepoProperties.set(this.GIT_REPO_PATH_KEY, "https://github.com/GIT_USER/GIT_REPO"); + this.gitRepoProperties.set(this.GIT_REPO_BRANCH_KEY, "master"); + this.gitRepoProperties.set(this.GIT_REPO_USERNAME_KEY, "MY_USER"); + this.gitRepoProperties.set(this.GIT_REPO_PASSWORD_KEY, "MY_PASS"); + this.gitRepoProperties.set(this.GIT_REPO_AUTHOR_NAME_KEY, "MY_USER"); + this.gitRepoProperties.set(this.GIT_REPO_AUTHOR_EMAIL_KEY, "USER@SOMEWHERE.COM"); } /* @@ -54,4 +73,12 @@ export class AppSettingsService { return this.komodoUserPassword; } + /* + * Get the git repository property for the supplied property key + * @returns {string} the git repository property + */ + public getGitRepoProperty(propertyKey: string): string { + return this.gitRepoProperties.get(propertyKey); + } + } diff --git a/ngapp/src/app/core/nav-header/nav-header.component.html b/ngapp/src/app/core/nav-header/nav-header.component.html index fb7ac1b2..2ada621f 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.html +++ b/ngapp/src/app/core/nav-header/nav-header.component.html @@ -1,7 +1,7 @@
    -
    -
    diff --git a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts index 6767a9f5..1886d9b1 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts @@ -1,6 +1,13 @@ import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; import { LoggerService } from "@core/logger.service"; import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; +import { AboutService } from "@core/about-dialog/about.service"; +import { AboutDialogComponent } from "@core/about-dialog/about-dialog.component"; +import { MockAboutService } from "@core/about-dialog/mock-about.service"; +import { BsModalService } from "ngx-bootstrap/modal"; +import { ModalModule } from "ngx-bootstrap"; +import { HttpModule } from "@angular/http"; +import { AppSettingsService } from "@core/app-settings.service"; describe("NavHeaderComponent", () => { let component: NavHeaderComponent; @@ -8,14 +15,24 @@ describe("NavHeaderComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ NavHeaderComponent ], - providers: [ LoggerService ] + imports: [ HttpModule, ModalModule.forRoot() ], + declarations: [ NavHeaderComponent, AboutDialogComponent ], + providers: [ AboutService, AppSettingsService, BsModalService, LoggerService ] }) .compileComponents().then(() => { // nothing to do }); })); + // use mock service + TestBed.overrideComponent( AboutDialogComponent, { + set: { + providers: [ + { provide: AboutService, useClass: MockAboutService }, + ] + } + }); + beforeEach(() => { fixture = TestBed.createComponent(NavHeaderComponent); component = fixture.componentInstance; diff --git a/ngapp/src/app/core/nav-header/nav-header.component.ts b/ngapp/src/app/core/nav-header/nav-header.component.ts index b9fc0fe0..d3f7b3e9 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.ts @@ -15,8 +15,13 @@ * limitations under the License. */ -import { Component } from "@angular/core"; +import { Component, TemplateRef } from "@angular/core"; import { LoggerService } from "@core/logger.service"; +import { BsModalRef } from "ngx-bootstrap/modal/modal-options.class"; +import { BsModalService } from "ngx-bootstrap/modal"; +import { AboutEvent } from "@core/about-dialog/about-event"; +import { AboutService } from "@core/about-dialog/about.service"; +import { About } from "@core/about-dialog/about.model"; @Component({ moduleId: module.id, @@ -26,33 +31,37 @@ import { LoggerService } from "@core/logger.service"; }) export class NavHeaderComponent { - private version = "N/A"; - private builtOn: Date = new Date(); + private aboutRef: BsModalRef; private logger: LoggerService; - private projectUrl = "http://jboss.org/teiiddesigner/"; - private userId = "user"; + private modalService: BsModalService; + private aboutService: AboutService; + public aboutInfo: About; - constructor( logger: LoggerService ) { + constructor( logger: LoggerService, + modalService: BsModalService, + aboutService: AboutService ) { this.logger = logger; - - // TODO this does not work - if (window["BeetleStudio"]) { - this.logger.log("[NavHeaderComponent] Found app info: %o", window["BeetleStudio"]); - this.version = window["BeetleStudio"].version; - this.builtOn = new Date(window["BeetleStudio"].builtOn); - this.projectUrl = window["BeetleStudio"].url; - } else { - this.logger.log("[NavHeaderComponent] App info not found."); - } + this.modalService = modalService; + this.aboutService = aboutService; } - public user(): string { - // TODO implement user() - return this.userId; + public closeAbout( $event: AboutEvent ): void { + this.aboutRef.hide(); } - public logout(): void { - // TODO implement logout() + public openAbout( template: TemplateRef< any > ): void { + const self = this; + + this.aboutService.getAboutInformation().subscribe( + ( result ) => { + self.aboutInfo = result; + }, + ( error ) => { + this.logger.error( error, "Error getting about information."); + } + ); + + this.aboutRef = this.modalService.show( template ); } } diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts index be1d7613..1b77bb04 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts @@ -224,13 +224,13 @@ export class SqlControlComponent implements OnInit { const column = { canAutoResize: true, draggable: false, // flexGrow: rowNumHeader.length, - maxWidth: 50, - minWidth: 50, + maxWidth: 60, + minWidth: 60, name: rowNumHeader, prop: rowNumHeader, resizable: true, sortable: true, - width: 50 }; + width: 60 }; this.columns.push( column ); // diff --git a/ngapp/src/assets/redhat-iot.png b/ngapp/src/assets/redhat-iot.png new file mode 100644 index 0000000000000000000000000000000000000000..2198fffa34716daa5782e70ff73952aa13975767 GIT binary patch literal 7078 zcmX|GWmr_v)}9%pYiLAj=o%VnP|28cIP*Lb_ABkrKc0 ze)qXQ_Bm(AdG}sxzbl?+#b|3P6XMa}0RR9(n2Lff`W=pL!8lmxXP#S2DF6U`;;3)z zZLFa#VdL(~Yh~+hZO7~H>VcjI0HkF7J*;e;?YtSS?HnB4q?wM}x|kRpZKauvL^Sv{ zJml?OIjRK0?eqdQ^=$&3ZNzPvWM%NA{3Xx;u6Ev5jQ*}JZe9}p(oFxsl|X<08|GtT z{Ld0^XK5y54Q)nwceov+2(Jh)Ka&g|qZHiMUP4zv>Aydtd(up=yuCdn`1t(%{CNF@ zc-`R+d;;R);(Yvqe1d{d^a`j~fSb3KKh({O`5(mpV<^~p*}xq=ydB-$82@2fS-bmq zOEWR?{o91^zq_E1%lE(YqC5YS*v<_tCLApfjcWNGT20}O^77hVy2^5lFh%*N0^(1f zLIrsR000i84|0rKL5KXCtdM-)TN-@)SV%<_wMeawJ*nyhwOviX`EZ8L`NrjPhVUGh znPSX)3;YLA(|1!&CRP(uvL_dr4pS=Ii=)yxcOAbokEE#M#m&B{K> zIiHczRTh#leWj<#o}1sXvuzDEu)~<_30(0C(AZ&@{SgL zlku~mjw6_dmVYy%XC^+I<21Rqlr&7tr7xevLlpN;uS@JS_Gbf<;$!M0a)f*;=T408 zl+8mA z&U9@*TJYF+?4Y%n#m+zA#oSS6(150c|sP{dBUyegL|FWFGlqWK*X|V!=OK5VnIF zfY#KsFHlcVf}4h~2q@Bs?m=R(dv2*&Pa1!$mK5Yd9nlkE6d{Ue-J%vriydzE*qNe7 z2|JjsgyrEwNuMXVF(C`bO`;OBsU=0-7TvL`-i8=%aPoi>OF{M!GTP|0s?eC00tHgc zp65VeRbU49by-`7v=ePA{KZjbBZbSZ$lY@@Wh+y8@KMda?Z#_Yy=QpvkXQyyJf7*jUtY2gyux<2Ndh0Z*(EFJ{RyltKy{%BA8*m;Wr0TJ>x`M8#ik_ zvN$$^q_4-V^pM%*rS7&vjrN&w^?I{$MYD>GTdJq(7-&4W{*+t=+w7d4qxmw;+g9wX}cE^zK71U5<~a zy|XlmcOpycA3N}aYU+!VDSif>a4pc$KF)1IYmFIayCq-+U%#NlPIW z#d*(ytP-^xcY;mrsf_Q|?h@GU5vq%rnPj?b^cN*xW6j!y$S`~g#7H&M15i8guVcuZ z74Ya-%4a);l8IA3_q@+&Ln6Z$4=nOiP_*(OBeo(AR$dnxbIr~h#}6xR&$(eds!dtH zyWDrk1sBpQE?m{IrkU@w$(1=Ve}KA_^JM<=s3lE~_jT)B`I?bglr0ajV#`?TIqc_- z6=#qIRA1;8rH@vVRkEDc-@}|1CtOy?O8Co5`hpuDNnr=WfF?Tv$~VoNEJbNN!P3mB z++=#!Q*+VJ3m^vN4w>BpJ)6RKk=`&ND9k(~Y4nZ`s=6{wy7{Wa47sC4{yb)8Uvm`` zbCbY&tlubGs1Cq&AYI|?ym>pNZf}w_#i2`r9^k23Ed40D6NDmD#f_cD$;7?KrC_pv z6DoBkn|U7{6D4GfF)VAC7(JrKAsv+%Ru{Y2hy~GCd?pJTKs= ztVTMUr|-3{P?-(+^vl(G}C-l#FA5I9s?N< za+8NpxieO&NUZ?OQ*7~n)e~<)&vClfI$w5%ZUTY=+sIpb^IBP@jWkYY04wo^DlB-3 zME8R85s}EkpE^!;nZLUTI$q}_@WrTB876Uvm~iNh*G}cUfjQb{dQz45X(gt1Dyp-* zKqZ&ZqWBlm5B%=K%)W{hWssQ!Trj?ObI^V~7Z{+~HTx=m_LY75;CI%KwiTwIvvOXK z!$>XEht}Ur`Z!ToDP`MtL3Dv@riwYhCPh=@lHf3NftBx^IM+8#N4{2JdsqhjMJG7M&E!bw3SuPa+aHC2Pzx47iwy3SvUw5X6hW!~5>NeW%M% zQQs@8{Bc_0saqZmH!7j4zZ;7`MhnN!)U7zVC+d1Q1C7sDV|v@C&1ElQ#yx506d96= z2<_aonB%_ZIMuY-p6^+f-TyKa$~N za>!lHxDak_=DCEsBbZq9+*g0bP}MumZv{i3-1!{YOC4FEfB#xf!gwWXvMfZWt$zpf zew55ibJd9dz!a_T4qn9i0pb%-IQuM|mEFu{(L)i#siT;BuzP5)obWeXwQX!@yXxsn z_p0K_eaNNyk8Krs&~&q?m+2gZ;zQco115SnommZ~rNCK(jdp0FD3Vlfws-9L=98$W zFU_RgriC*tJ-0NsX%|PkawNV!5Ar*h*5M2%9pieG6wZf$Th~yoDi7dGU?k;Q7BaZ#D{8(N26YVz5HOm*c=$Qp!!{m&;b95J|fPY@NxA z$*Y2MSWDH;&H8)ICx*8_^@ZWTj6q=UdErEmIx|9>FH&i)*(Jb<4SiSFY74t1oBjw( z3wNr!z_#n-$;MwSF(w~bwpoknq(r<12H8YP{r=R;6n(1Pd>j`%I~S!E@HZT{1vE=~ zQ24C6A3Ct6^t|@2eKCv9K&prFW0CDDSjPAAnt?(gg7~I8^|$wl(>W*6?@P2#vW$&{ z+`!K{x$ZVaanwY5a z<5ikBM+1A~9E|GkuQUKNPh(!L)kjQw< zWspeREzeH$jYkH&+PJMZ)wW5|_uHQ8`ZCqH(bP?4Xgy5L{>(yA4>qp&!NiS7ei(e~ z4CDpT<1`{D6EfN#`79TrO{&^1&L&D6DUrI-{-B2&98T3ekwT!jb=!M%UUxPNIgsI7 z8KC|a`Da?{k#*VJcW4u>X3MP@smTM7@XUHiD>92e5t8xnTFP^etP#G$2%IS_Jb$_S z`QGk~HImX+X(;G$hNDv^clGq{m13nMIK4{qOmEO$-%*Zo!5ph?=Z>U+jHFp_SE7w44i{P9~-NY z!m)-*q*z7g>jH{AR2Al$^A!PGOLX_8l}N%vXoJ68hCe#(X*Ubpefw6RVsGEdN^zh( z0kh6*)*V#vS|kP0?x;I8tf9Wvk4shBA;`u7DmmJ>bM}*5_%eT8(#Bj;o1SB7E5B>! z*|DSDT4s$MeJA(wiK#+367|fe#@eR!aEZ?RMQiK|xkaJUd`e?Dt9XJ!}#A zskrdh+aIc=LeQAu27-rlddT{OouX>m3j)9u6J~~(8%203=SP4+#unQV zJI7g-Yn@_|$#mIPxgcRhZ)KgD>gHHyF2CB_Sx9_IvVpTcBz%XaR})NG2kNW9{FMM$ zc648_kM@PHoT{>dAWG0MSNHrfz5|{!AO$LidsZ_IpWuTMJ1m%0IvN{}H>O4&kT1Q3?yASxyeA4J3=YGqd4eevioJf+cD!6?KaxK7>+<&8 zo@MC!_p++CBZ+tF(ICO@c#nERmDZBUk zaJw;Y(_79%dQsx6lI^Uk5-bM>NHyhEY*%7U)GJkd;J3}e7p6bAY~JbI$ht}AexmMfv@?D^3I#(Fj8H4_}m!{CQg<0X9p z`{vt%q@<)XX65)t2fU-nP}s1Vx}Bma+mNmh3>UI6>tTbA1jIAbi2Xgnua&4LuVpTZ z0Z%tWLJSJ>^72F^B_#__mcM@e+Jr_aIyySig(V%tQbOk&;ajTvhs`T)UajVDURO=# zm{|UEzhj?m`-J6Rv1EFS`xmY0g{~~-HUzbU#YlejKJ&`Gi(%v!)~EMheGS!;{d3_U zFTJwn(K1tM=4UyW#HwgwV&VvR@!~~CKtO=c($bQ=lE6MIp%BlR^|*M<;BZqBLF{zi z=Kc}Y_~_t&05&!0c{6^7H$(3s-m;T^a& zOY(HRd8Gc-WRybzFV!sBX4|98=jv25hz!kFYYTre3FHa;>QJ{PP9Z>)(OtKYhBEf^ z-o@_Z8_HN#F0#(Lx;o$6i(SKI)gOLHLXnTzimiJ@pzx=q4JLyP7w-n9MDA1SMdW=lbkVA0k;wXT~mzL?LWBmiLQ_tn0k+ zPztA>OMicVt3(!WA<N;Dq7QS$JHSf|?(>BSGpoeIo zc&5FthI7hsGO7LO%{%lQuSuQl!uCi;HO=*>m(|rit>*8xGaa3roEDl~%?_^)7uu4O zlSMEwF>!BhZa%iRw{IRC9O#$-q?z)#2<))_b9+hQ+a~SU9f28u=6$G{Wb?w|QnUNY z>HYov)PrVKXQxc@oC_93QwU+t1_yH03M(`j+{Vb9F}(&({wO!rZgZqG-eMA@;za z9ukSDI4~%(TbpW_Dj(F0!51BPmN?zU0t<@i*0d@>F17hFy!YJlBV9i^=E=Ji4WoGI zh|_ubl78RELly%oia-l!NM>36O`BpBx>*=m@Ug0j_o?f=f{#z*%9x~tg#TgVOiz-D zj!s^n=}BlXp47~-J8nSo7&r1T;sc6~M2$*rkeo<87dUFY8%Uk}UR-{PNX~g96zZAL3g3<{Lv8 zeelWiE@Ge2OmXY2?;n_ig!BN`5BE1#gHSFmt^}Q}RH512za(dyvt+1hBy&d>K;Z~N zA(w*l;U08a*xqi=W8R`oPCpOvVR#^8*sjzX!m8wty;6V{5=wMjenaNlX-p< zYAb1pSr^IiMTHvDNBpz=-SyuXShePI*g=?FmUR(h780? zfI{ep_rl1pMJ?&iG&e+vq#y?|{tyH(pv+&jWhS1*)YNpg#gm!lebm-as*T_qdM8E% z%Bj&1&9ht>&6qVmb^KVCWb;v3dDR3ZB_$g$R#Yt>aSCZ{WM+7b6uf;1(wy#C5tv58_ajN1*DhM zBOe)vAzG60o>-|vTc1Rn4GX|boU;LX#hQdcA-@4KKtn}N=0F6v9syp$dv#v&&%xUf zj9+AoZ1<;D1eM%d zzkcv&AxR{7od|+Z>y9Qf3YN(k7#NsM&ddycg?6BJlD-EeI+iXgIqYx10t>fNY_PL8 zV0`3EnT5ajvfMXdMG_0=Dv^Z~xc&tx0?djELiHJc5RWLqHdIM!;GV|(R#l2Dq}eHVZ-U<3QXfx1C*(V0|Cx3I&`+##_kD3)4xU^l+4A_F4R!XqQx$G@;QzM6DJDXGkk-GBr0T-%$t85A1W&u p&I?Nd9W{xg%LD&v1O?%Lv1`sDjoUw;9sVn?!4x$Ws^lyq{tpa~Qy~BV literal 0 HcmV?d00001 diff --git a/ngapp/src/assets/teiid-lizard-gradient-bgd.png b/ngapp/src/assets/teiid-lizard-gradient-bgd.png new file mode 100644 index 0000000000000000000000000000000000000000..fa7eb424527364e31746bebc06f9fbe1aa10b042 GIT binary patch literal 27918 zcmdp7<8vk5*S+zLZQHhOJDJ#%iEZ=7nqXp2FmWcfZD(TJ#+&EE@1J zH?WQ}x-I|!Jo-8}j-mM= zc&X`@o|Pd20Wr?9mxcP1q!*7Rzlyi&;-od)ZOQGv)ZTfbEu6EOw=&U9Q$vIWkmNGS z0x^z|tR8XV-6dR7akx;S{ZEl?@m)x$q^;t=OsHnvd_K6l508 zs-*-L2!;TN)h7vUG@=e|`~KY=f7fg9JRE$QeC_yqfH3*_8q2POm~X4gAfd}R7|M{p z06>gK1pomA30R(YivVa)6C#BUM5(};ezzDUAu0?gFdPhnqYe@CgEnzV(~Q422o8pdY1?g-@4=+q{_T&WaeoM&#rY*S zVB(1=>RQ<23`2zGW*I<)1%@xtEoBlY>}(jEc!^DQ4uAsm3|~KyAJPT7cf(2kH36)W zt#L@(cWO0+=p>*SWx8PUJ&3a}@Iu996rc!^90O1xG;mG^c3H8>3% zYe*idC~j`PqlnE}rlW|Jgl;H=dM_9`LLh_)E_|=gwjSF)adO-dcx^;|1(2=Z6=JM-l-aIUav) zKiva)XtEA174mY);&czSUR1lcM1y^hd8UJ|ydV#bB3Vz(c5e}-6?kBf;yz5*KX5+Z zNzQTugm(Hh7ezC1RS~1xX8^i`enwPT(q<7UI!z{tkt1VZ8L+<1z8K2%QeEUQwu7(F z?+L?JH#2ycfVh*&EL@VWV2|>VF)*U(hLI=Ykadg8@S_|jK8E7tq2^K6eYOtE+K`>U zez!PJOo!ew-m8C*6e?T=4HE#I&LVJwSdav84%1^kpBFkO-xWbyEV>c57QT=@l3;_c z85A$91*n6(wh$>e?9!rqkIPR(#PO4VKAw-HV-%h)EqPqXq}11I*)EZCdG_YkFXvw zkOzJ@17I2t+5`%FvfVtv4H6@iHALw1|jrq%w zSAL)?f4Ey#3DNKjY>d#?SO!%L)F^6-Zivh-&{025%};y|e!GkrUkyVpKE&MQ~E&)PvVaGQScpiZ;5Ll?J&m@!02 zYf-9CB7rdKHmZU{rKb+p?Z+j`!;q=$>n?O+>zmC1v9hGNO*w&pgAm)zsuVCI7Ojus z$x**a#&bZV*{0H+$u!c8Pg=T{Phz;qy5ak>@ZwiNY8BxXSk$p-(@Gu_xVGCDWP8$q8mLPU zS0%P-sKoe^7NO6J*?0vleTkICX(t%L_D?DCZ`{u|axa`(aDe&tX`?TX$BP`z0gqZa z7pUJUYB4fC?V%~nYzu*}fbn;xSviKFA3OBT2+}gPM`Sr4s{NZXPYh$Pp^xfR!c?98 z8Nig(^v67fPKU8;mllE_;<}*Mp!A3&m2Y+H2__Seo{=b<|0c69zCt_10v^=z5(QiW zPML(zi*vrv6}*$w@EOtpBEfAOBFRR4R5r?PbBFl9TmIt)6LEOzn=5Rxt?u}HV*H2m zjtUa$xdmsM`txVfg=8#w_(S=z`eN}y@idJHi%nd_r(q!Pp(&4qBmh7Mfgr>!#wQXu zMI8AICxpuAa+bhjOvi%Q53TTfkCRnd+^#zq&BneD>q-aQ7_0&g+&GqFU>!8y;W1FFKIYVA;okPyDI2Z{!9{>cBX?5fTrTJ8L* z0R^K-RxKX$0 zCHNtSlXv5!Q1(#B_N$I(8fda^7BH4jO`$U~Jp4ljaCl_C9iJiqEhzLXFhnjc$ax72 z*;t?(`~mPC46f~ax{fu!e1>l5$G53Kc$(`!ZWsPAA_V+g7^yOZkrw3|M>>br6rB)R z07uCUoO7nb?{tNQ*`>h>Kebr2O>hJIw4HE=@(e#CN~M2lH>@{&aUj>hxTp5t<>26U z=U1eZKGFzGe_Ef~VPDrEQfLB2BGsNSTgf=!zhzZ4-(Um6fh6K#n?Z1ivSba|#(&<} zL_pO?JB8%BloNwy6R|{SCR~d@KXJ7sAy4BA)53_o@qum6ZdT>VP7N)8Ybzl!ZSP5`odE zc2}>Vyh~uPZW282Y}YQ&GU7#xfYaAVb00DgML#f<8Jim{OvFOfpC33t%r-P=oJkG~ z?imZvM&E(w&*}bR8gXKf;OvUs(RAQkjnC~^sp%C7Z+5f2JB?-OyfZ|8mtIT4tX`+# z22GUIUZ{(1kl;O+cUhEP!-F&AqYp|1!dKnRs($!vbLzcfMo}@rXs>h%-97xKs3bho zV3l{6n9ej*Ef~ub%^8A6I^XHHn||JB4j<9$ni40qBVv*plIi}AT z_>AOa+ftJAjpy6=Z+1w80^NJCu5=La>GZWEJb0Wp-#AtSb>|b}r7%pODuE(JD1k~m zw{f`nD9@Vm6~gu@EP2YXRc$8%?RSHpHQ!h8Li_k=1plUaIW3Xx?YDL@of|GY&cuNB zp|aWf`sExzaYp0RS0vqsB$0~j1waH1ot|jaARtvB1vNMr4G9JW%Ig$1J~60>rkhEd zyigJZNzs2vUU=}7CCvdY%R)y>-E9&2bikL>^WSWPdV>+|pfW=#D+wAwONW4-d0M6B zex4@8>5q1@lz273Xg%}P#Z6Bsy;0S&5h0i$v=~s%$6Yda_TnfdE%uZtHz>RW>ujTq z_|tovk-?|~wZ|Bk;@-e_+=^7a6e9XA$GYFoN^|iIQVxihsdqIle`)%DKu8iAn9$e7 zsHUDY)5hU2ljr~MbTIxxd#hmvv|Yk4rojMqwPjC|X!ch{hs`@WL%V^F zj|{Op>yxDb?Ps(A!XYLUDm0Cv;>2AE|EHkk*u$?b?xu!dR%nAIR+BfNzEh7Y!igRn zVA)7B%0PnB}G{?1^x5XCe3e|Yv3SiQ4 z9z^&R8lhN9=ZO*us!CoII_LTRN^MNV$iA#;&5V{q@qId5{XrjbQbn)rSl;Yh|L0ro z0JmoZ4$h{X?9T~Ndv~gf=l4dOUJnJg$=({%&6ba+URSf?r-O}%i6WUw{KZk zX%!c6HY~JFiyr=6H>2#$O)|I##i`A}eL>5;;U_5Af=fvW5;Zto);-U!bIdIC$^Xz3 z?hDM5AtEslNa96kJo-kGa(vlyQ7x`yT?)HGrV_8nqUa!olNR)5tv(#ysgIA#p862e zwofuYV&34*w4#|wBlL%SdPCuJT?Ur8Nzk-b75X$y9_g+_opRZU z4|LM$vG7@Plak6P%8IF>tt@m^%KPOS8vJ^FyjWcCQq~TTlS^U>4pG4xm-a8|7o-?* zQJgyprp#13^lzav8(8)Ghw$yHtzm}=3P-S^;vmGS6=UPQ^AO20ffR?lO5Op<$LT*55|VwyUl1)m{AX{2tofeUj9h#k5hu z1;P5}Mf7^|QSjf!QD|yH2QmZ%C8jJ5= zIe&zRMaYTeO($li#iJ`9VdL<(H|6|1kZRgt8b7_ix=SJSqs#tnJqLr9+?y1H0K>o! z7|-i(>b)lVViq$nX%LA#q*CLsdL-fVe|ZK|@wMe!*fg;#3oQ|AK<=5XcVb1y{1kt&S2N z-N5e2hY^|%C+U{oAYJ9YSZ3C!UK%qkNSKmpcOl*!4!a{k0Ft2OA}NBh|{rG zY31ocy^sALUDcXC%RgEsEFXfG>%G+V(mgo@uTCK44Ho` z(y5~n>vrjOX_`~+_6dS7iE4(i@xqQV_wwykKtMq%P;_V zx0~Gox~;un2@>BKe}?pgA>A7Y(QOa?ySX{{4Z|W0 zyy?w!@qb=oyA8pf7oZ|)R15yfq^SV41-{e)_9LP{X|LCTvyiE|6A-6Q-eEI)# z0i+S#`REUCiAsKXTWYE`a^Qm>Abr1Z>*QaBa?wD|R z;zv*LVhCA*2EI@#v|(6_wSG&63Wk=sL)XU!lHUbn*Y83YBRs6m89R|MqQ-#qvo+-*@bM1?E(92xr2LpcKu+btqbk-L7Tk5$D%fMkxLCEi*MN;;#xe%g#Qtcpz<~hp$h>{T2jxuwMfmgom3c6}aDG?mTuq zuawO6dB2h_4HwiMM+TSRH6F*5RxF)s95U;lew<|5jqtml3-6pj$nxVc9nXa@Ql%DnJJeHI z?TEIp71o&ge zb9xAuLu{S;>!76W&u4=IbCt zc>S)sUjKXrWJ!V?Y9UCFJm2!-HxryASXh-*IQIvp%K$WWyohj*!or8W0B~}bagQ8y zw2@>-3{0a$$rU=fV^C^+SmWeO8fY&&j%Wm|V{QF+cGu3i46M7L6EuUL0Xz z8@h0$GsLu2qQoy97o49!3tkJ6ph6R)!h@hVS8)02eJ$tPVodu@Z%u@DpdWpR;7f7t zPi8!Fx?h&nP|Wmgvp^#gh6Wda14Lw^0TET?wt7Hu;(O-&EQ9zg`9Qr6ldB$4p+Lm=|kY-0py zgQv@Zs#m|XqW=*_sw7tMu)J&Wg7*68Y!M55{c0r-y1~9>MkWn?y7V@kerUm{2-pE? zt1o0>ca|9`;Jb@W=4lzW5bgVBX@$M*5Bu00WJUPG8WQZUG>;=_3t-A|f>TpV+D3*{ z+(Kmoli>j;!D|3IYMfQ~!Vpgl1GKeK6$Y>|=OdM|=%6NU_Jjh_%nf45nC$Z}@ns>b1n*SR!jm23nwTG}7QRpt2JT zG-xKOQRGm++ey9$$+phEXJFYK!7|eOLmXdXm%`gDvxCffqMOZ ze9kfID!tW!DF#PNYpu)UFzg#ov&(B7oXUWv3{cdjf_TmSOfue-Sc%_D0Gt%jRR|3RjLpe)&(Q5vm-1nLoO&Z7v^WmiZ{|_&`~HV)pBnpJ zOBFE{orL(#_tEJuh;ng(?=>N8^SB5qv6fL(4l5`JMz|fJ;`(H>9w8)tx~*+4Wba8j zOYt=r1A|f*(-VPnxB?@F<_Cx3s+#;MK?UV96Qg2%WoEMSCp!IOW@J7M&vAI5a`>e~_{6Duj-NJ5G!lT@8l5 zNXpZ`1v^W#5$>CYOFuq>&)1NwJo?&Ed6xsTH=nG?a#=X28=>!3XwC=wf!)GaO z(POFFv$yLG_PlHW9ytDP+W2y%o=b6AE#Nu4)KX1D%x&m`mdW9dLi|Pa2+he-G{Nhx z{%-YlRHJrNraXO|eo;AL3cxmfnFypVx(VjUp(sgNH%MuMTwj7DW%EXm)Rz)D_fQ4o zC5(Yu=7D7XG`mG(0rjkp*1K<|@uBnNwO`#SSiR;_Jwb#EOknj70F;+^Yp2Acioci` zZyM5^t0I)6%rA194qZ4i=(QlxFWO2d+J!WLM+cd#%2MYAY_c&JH4@3ERZGQR{9|$M zH~!*aCa;qQIt`Av7?NOS2(+}cI6USgYIAd2$k1zL^ysmeBSA;o&2d5mvnp+$0KD=u z>xY^WQbBH*&W(<|Ff@5XbTO1gj!-;&$4S}uQD%X|P)kZR{xORBRTK6!LFk`QtPx@W z4z4CTkM-B`*9u8JL~cZW$63qk(q;uBcjR|x=_YK;iNk7z&}AWI?AAsT{2 z*qvUe7J%zTDZ+zHLQBFxh_KSt;rfzmktzIi6L1M;HYS4cTvt>6gZYNN?{`&|_;bPE z!Z$s3FaeT4Y5g*H6DV3OLsSqJR_H<*tU#!5cx6jMyxeb+Xj2V4RMsU@*Zxet)frZ( zL}9A1=#&%#A3F7qyXk=ND*d*{hCadV@^a&|;d~q}SHNQBTBrs6VnJmkWC+ZIq{`g% z`fOBe=3mo^6GRmZID;is6`jD@jp8c`ueId+ZTFg^;UEbz6xeKW8p*t3%-98(e0IW( zJ@a{OP4Yctf<|B{cYr*6dDCV8Za|mwVM5Tqkf?(6-(r^Rtyl-olqJ8hEEPFd7+i18 zDso$Ld@MStarhd3{6P(AtBv^d#Z*&k->Q-?BX6phlq>QvnAJ#6*!U6?`v^G7py~;* z1mY6a26=AuJHAGs$tP5)BA!dv;HtJs3~RFhQL{i!Xp%2c6TE#|l(CFBNs!ureVCW$ z-U4zp{J&lR zM#e9{`5lMd8^`W=tS+ptfnOd|qaZ8spI$aH z)WsZ++L0g?Nl_a!^m31L(J$?8Pnnu1p*%7wA}0l{#>T#5I3@+D7LbSL22-ApnGDj- zX}7oWx2FnW5k(b?8@Hdvw56h5osbPU4S}kX&UssQp(%9N)a;?9Ml|)rT3bd*RIaV=oqqLlO1<^kOJH6~df%P7)?D8Y%$?3TbQze_9nq2IW$Uw6y12Lv2j zqhHwkc(%s|OF?N8Ry|4sdO>KM+Zyx?8fl=AOR~u-_bh)3^!T4D^J1X zi;Jdwq-DAHzE9W*f3stEy-0~2+Q@Q)(_j6DvKmEsxing(=%4ZjC&)1%vq-@>+i&uA zAw~YTx@9q&0=+6}yh-_Za7$~{m8>(VHwhaqx{z3qn#I_qL;tATZ+op+o|Lhm7zj zKQH{?0P9Il59PbHq@D|WgUD8mH^sU=HWPoq+kp*prWQot{8H2JPk%r63q4|nV}F|L zt*8RyQIKDS{p$qpy>;0LAEX@v((v;sXmwwhWGXG4Y}ZkT+8E(OB#?`{DWSOHFP+Ec zW7QgwKq!s8CX4fTZug;yL-J~MrFmp3G|B$aGy;1IEF@NKw3SV7Kr+p>CLh3=!FDf$ z_sXoFF-r2eIE!X886iR`lGorF6_i$;*N%Q5 zG6c!AMZ>I9Q5SQL7$vv=ms_?U-k3a!3vZ~^ZtL2+#`~O#!LSvr(d~XF>ECxG zG0o}X<)xIg9zB`Vh;{Yhym$+r)D|xDZ7U%uBL|O@A1yze$sF)AezPk^|Slz zt`8g@3nnl0ksaUy%ktA#IyO?64PXNKZWS{!tnf?7?QCl^tijAh$;X{mq;4t1lY6-& z8xu%u3I4F0MMM}?K!StNLkzV4)#125R~|gU%UgE(IML!jOyNhIgk%a#hGEPj1w)8j zb25!i01KJcv*ckQ)P z*={Gxa)8nD#S8$ZV62ST36-e7?{+EWmi-&h{|)@hi0t@}Gw!!yK??T!hV zR(fu9GWEkh*KJ?f(T3!F zbJlXsNkYCdvR78g5wC3+`zPK!3L*I@*WMkztkC=3?2!^RsJ+1wF*+)m2J%L}E>$lN zF!BqII`O^G^-eBdE8KWfOyF}0AD1|YIG6y$Ar|>)$j=f5CE-5Q?PrhE{hsnT&aMO#4H)S`Jy1DU{G;D z49fhD*3_2jD}-}Fj_w8AROsar+)msOvYQ{WFmqd97e0RMRMh1Nb=CBixFIrLENx^g zxs60c(LzB%l|j7Ri`irnpK{p`v?A)MXm0{o+!d&ZR_8eBUQ+ijc|Bg7V5nn=m(T8- zGq!5VY8)dENWZEHsc&f!!beRummlQu!Rkq@W-nL2jEvmA!SCD!ZB5fP7IdQ{Snri@ z3Y@Ig6syS=Ime*{FXgu88@MK-p+B+qU+&9L9Q$+JP>Y=geBF(kLAMpIdp1&&fVs>&gP#Q0A>jx zGrC%?=3yR*cs$1eq1W*}2^p!u87`eKX1|u|&yuXov;;jLp%lRzNvhVL-=HZMOO~uN9kuoYtE`gClh=JWjs38BOor zgM;hq9E#xXi7VKo_q!|dH)&Pnd|kBz@kD~HUoIJpk?%8NYPCMPE?C9z(q)@@A3y?ay;>}j!r_MECFX&UN?i9I6%hEpuW|2;-Sb5-<{HK z#c=yig^iYYs}vsoedVv#aB-n3YU1V}M%77^zrg`Kbxf;`wRN0#F(Ke3^qwDYbAwh z|FG1zGUXyPQEbXe<1#VBIQ&3?ToR$th*6DuP}8p7{Q0rg_9>WOQgSY_!uvMCIhWIQ zbhi5_Ntdkf8dijN{?!0fmm9EuYvQK(%_waw4C3bk5HgsC@jQq~u#LPjqSkc;j-av% zJ#@>VPu z1>XAzvB!2=x6oNj6UcI*qY!typkCBkBAWety))nXLN##eR9M%l#JFj+3kTH~3MkSp zV|HEobI83ai6Pb?IzRy1C6XxF>pQn?7vMj_`FT1aM;057dtB!EUS?EZ5PVih=7ff< zv(vGul%Oj0v*&=LdD%hi=+sTsWm=zo#x&(` zoV)X^Jq-;SW|&jdvLKaz<|p50T!?&&NQ1M$T~GsW#>aB+ zpDru+(=MtjClazxxN}>MKMW}){d;($Tku6xh=p{Pj=bMim;cVGt2xvA&)D#V?r>e2m#G54)xK34?m*xSTRJsL>ZIPTF(8PU4jd!mH2J8b0I< zJtb!vmMy@Vv(fXoDCORK{?+DdWC|sRyy1e%Z=w+J`<(5A!qCc#42?2k6}uPBlNlsx zJpjNS4AiE*HgIOpkALaAN?^x8SXAzGegP3LaQ@Y4ZKkEHq+!O7?|7K;V#s6cPVIr| z-dMU;uibYbfOJIZh68xoPrL^7CE&IgR}$wvwmuikw>QdFwE3*2vCurrGt+=${F6 zQ5!^xJ=gK!Cjde$8xea|Odb5egz}*)cTr1Xr_#_`l8Yv%A^ocLV2se(3)Ug;)|WZy zR2nn}M(OiG=-6v{(+D!&$(s0Y%%`MaK!S^MaBz^J08NLlL;=9XKZfxtG>~Gz|L~UA zZ6{$h<_;r!M3RwFDa5UE{CSC?-Csa@*stkmG)Ff($u`l>TPa=9{>E?o+dr%8M14pM zn?}X{UFKuM;g`n|ewm}qNN zN@lCxtpIeaogAHlxzhV;*7*n}Ly=;+I-6`V^dHhX>Zj$DL%hzc% z8M}SvJ(i!!6|%oJ;LdSV(V>i{>ln1zapjjcip-0b42ukPEN&L@nJ1%q#8fhpwf_FY z>HWI8I!33{`w|m0YC_>9*!)ljn#%SVbb9?~&mGe8nv*7%pH$^p*Hymga!WXcJg0NB z^#Sn`Oa~X-L-OmF-purLq#`~SDauIL9n-|7=WFbt{rP684gPosC&~?%dt$a7wPz(z zLPjY%5#CsMNcc!jechn&j9XvS`fSD zVgQN+ZCa2(+BHm%x=nN zyi4Y~PFebqPEu2`ke`}<;_|-veY=L}>13cQoUlLA3ANUl&2q3~gOk7fCA6Vi#b79} zYzVRALk6tha~vmRsMz#AT#*^uTzB#Y%<)5xIVdjn-xO@{=*Guy}oGLy!C3>5~ zyp1FNR~?jb_zNYSmNRFu5HQ@T=reoKdU+o-VduKFMf$$2Bqt^>kN?BwN3Hz?-*-~P zP!!i&3%mDS#Y1}{p`s#5a5RmiyOQ8vfZQPz7fse<+GY93;Tz(VVJKd(ioAlD^12ih z_(LV%*hq^Gw3nD8lWcvjIkS@!w|&?N0qraOp4+^8DE=%#(uWR87xf~Y`ii~!~-cL1PMS}YCJvu(L z$AgS(MvTXXR|}u-?t?q9V?lzee+C!V7|5zBpb6tnqs+jKnkf6=;$A*P$!YfUi)llYF+)r zJM%XF9^X;g`QC%ZiHdhx>%+VhkH3&sdLknb;YG6(NfGqeAI+tc6-l{a!{wFo{JnY^ z?vn>#zNK5p%x|_+AZ0)Q{YM=(bHLTWu_M%h>2t&%BuD};NU|tuwjd-Nr-zPg?#p$4 zt}W!)Oab@d#vYabg1P(r@OV)za5bJMG+?ypbvv~bhoeuhm9#>(fCdFK$y&prRE zb@DDl2Dus(dKu6iW>C>8JfIwj%bVE$hvo6v^XX7=QAu7|?Z_RzB*6R@=mJS5g;(MN zZDRyOd7XTqQOB6z$(9L2Xl-h+=wzSVTuKpc${d|7fgO+T@cwAC-=f{+NLUG~wsN0q z6gErC;um%OOOZMkuU#jPmRE18sYggFLL%i#Mj(&V-Iwy@@A11c)Zd|f6+~T*2bd)16=DUclRt5+jY&9QmhoTfUKrU)GY7$} zE=`fie9edFNs#=Z%S@uR!>R1JySrp|Ea(6 z`;Pr%{q8+pM6Sdu57WpjP}*A#Z6l}th~TauVBpu|DB%@Ps}v~S2=U+8(QuJxy~u3)Q`T{5@*rkl3C)*z~^>)BT$K&saJ)Koj)XEIX=Q`ceL zrU0Mq`+*?Q2Z{`Zw{b5Vx3kMJpf`ATTl*^Xb7Sz9JmTR8&9UnIfpd$inf5c(%7-=e zz1Q9sL;Od}Cu+G-z0Hz=G9jxS9zLhv?rUS|7AsVx=cJ9{#v~zC(zsvLV5KTUL6m=AGOA{udmN7R?-WfzpNQbSh(#+FBy8@R8}zks$=FI8RMtU z9<#zB5DK_e#a)nuL@`-}A|w=S(0)(P@4%Z;6||7YMZM)1`W^uLwVlB}OkTTkCAG!F zh%y`jA0cfiq;=JsLAQC?l_;vs{l}M+Fw@*Fa`%*;)w_$omCkaTc?lwAvl_Nd$78}X zY4>JNo}+?XT;SjBQI8}r`>TXP?|3apB_V=I_0U6LDVegbKY9V9D@1B&6u}5LnBTkO zmQ6kTJzYj99E=p)S1Rxp_L?)G%Y`IlYM4N{a!uY!5%1Om;CXrLP-Xr5eiMZ0;NY_U z)?})nP~d`%SKsm-(JHTR^fq~=dcCvUbOe2B!+T;c$7>}=-Tmj~YsAn#U!@x2AkGQ? zuPrBPqlaF6qxaIO<f3pV>STgO+kyC#t zX7xy`+ILhEoeH7Jz`&?RlKZ3HP^i(80B~mAma{@W{}dxH=Oub}`C~*bO1fL|Z|i2K z+}kwTpGTI^YhOCN;*>uhVwTs@1qAymP5AbqAy7r#xLf&%gbNs0{3TYtL09J9FPvBr z`}!VSO{_f-8m$(t{j{@-pvFtj{^@s9!U&_(`BGAvZ*5n-@m9fZW#IU5y)ce|VSEtE zciH}XYaF3V-piQefXN2kr~B+uTZp>HxEQwp$$I2w0#~y!c6-K5n#L}Or1uw6{1Ck2 z9ABqRiI4o@8$&=$80BsuF>Lzv47O2+xxm3^sjmcy!r|BUHB%&UInb3C71d*XOvNJG zOhE57{**e_E?z9A_1Ut4>`7)XtdkDJi@O4&jWikv+vKb8qKSnT~ zUtsOBpvx2Tg8nYIDbBO`y_nsIl)++XCp|A0m;kjy=K zJq&hY6pYOQv9KN-Ai`8sC~jWgS(A@NAe^oA&X}f#(bXGapqOA1$97Z5yVWZEjKs8g zYatWc>)CnbL{-QT;bl!CsTUu2CEs-s9mmsU2hVF{3^bOB_EBv4$K<)rH1>>|)kNuG zo(5wA%j4FzWFFXyq8A=cx*g|{4YtXW$4}YWKn@k}K>Qyjqde#fS={Aq7MD`(HtNE^ znB1?)6D)l&N)n#K-Ze+#%O+`^eOP2oVxrQe09mysQNU5+m-;NOTxiV;kO1!`^lpW)jZ!l3{l9t7P{- zb+(VvYsVJ3++}Y!yN>uVo~R!e?CRI~x_JNiw()y*gVM3(-?ST{H%|;7lhOQwc3_ZS z8#kT?Df$s%j;Xm;Hf#4cA{*%;mY_j%0>>mBj+nh(6Ev9NvjRi1VLn+J+G{@r9%Kr` z5jw!xy1Fb{q8st-=FqHKGP?7H`+QPNR2{A0Uwwu;I1W?sM9^<0c`{l5T)2iQSXG+q z*!=#c)9=qI4)MKoU)t!$>|Q-}thWF)JEC&Ot2L`uXVaR~>83MAuc}}>L6c+8ZTxc) zH3@20vII#udtS|lB96%A^Z9eze}fP3Y7&!MNXT^~cwr9i7JgDVs|5#jVPSK_dx>5J zAOiOKJQc*S3GY`)Fo_cxu;2U$sZU#=U4ByDRM?lgVRmh z{ke0*ijr==S^r=pIw#Z3V8=3hO1>uj>On5CgVk3KdG)ZuwH|?06(&nq2E(lfL&eP- zreSHDN(_or?3|qnT!C!fQgO!HoC2B;B0$mRh^k8=dv)rWPz&5&WGNwe`dVRNP35x7 z3J2P9ij!-^srHb&(?*y7E|K6ES34|ujRo`kAYQ88Xt`T?t?GI!N*18IINfNxHSrV9 zW)0?_qpEfRpMzuuIAGL~rmt8<8x24pT1L0FmSu%N!Gd7f zk&Q#?pS0*Ngfidn=Q<2!H6{m(Bkxa>0A1dh!4iEHjieW#b5(s8GSuA0|x_Eo2f;dKjh@z5U{biJttG&4*lp5 zJF-zRrt4^oE=i9hFqC5J?wqVlg5a8T{Dmc_8tUq8TPE?11hDskZCOW%`P1{H%LOiA z8XYWPtHgt1Mv} ze_y|?A=}A6118Ewf0Pnk)j3c7wetiDRwDa z>v~(O&NkFD+P|-qWLZ=+c@%_-sM6qNe(TVL2^l(Ht)FsL_$sNq9rZLn#?>2LdFm^q zpM6Kgg_PzEMh_3YZvu?(gw{fHQ?ijJbWzdNg9FUTohX+uFyU|`^Nb15m-`ElmXCbi ztq!zL*qNu|`4>}Bf-9JF@{Bml$mHd()4g>=50sDJQ2X;6&k9O(F6ALb$f_g2d?B{P z!26?Yvc zZJ+(f9ZXF-Lp!Ho=>WR>A@Kn`+xWSC0^l9tyOo&5V%xm*-!x=&vsT@Bz-})AANAA9{FIaBQAlinW)X z3;t)vD)ko!k`Dyy$Z(?*XTECJaf}wZ+v-Ui3TCIxlLnPhlWa?`_B}U~4zRkba&0Z9 zx^%@bOR%#m8E)ZQ1;D4x-zVN@1JXSuthdJJQh)Nj#Yj?*+56*NvgV#xGNSQ(9SRnaaZky2aQ@eZ$!m)D~<>WwAH79&ySCTCnClI?+p(5l7O6#6ALs; zO|*jvdR*_4F)eYC;!{)kF3*!*-2%=JSyX7RMAZ|M&PREAkUUq5YEiGz1e?;T$;*d_Xjk9SGVojFhX|`nU zz3=wgFObat*{9_ruWi;fh{DYJckW>vpWhF94NS}9w({LvU3r>v!73A)J`UG3ywmbjRyO#PKnva^6a@7J9@)Sw7hk$|(Dj^7t@9mNpLJcJ4wwdJZmckSFSFt!j)fj*|FiCT1ou{;ue!_--}FtwS!_ zF6tiZJWH#KUC2OQ6zS-AfaBYipP~InS)6iWU8B;8*tlgFQIU>{+v^c8;O^Z!{F!9-#1D`)C6X^|A-L<4T2S@ zW$4*tVncxkI6xv?h^d6HkH4JAP^6eYZ7KRa_OcRk!BXJK(a~aNXKHk>L z&I6h!p;kW#RUw^@fwrP)fuxT>%cQsGXu(iX#OEMPbj|gFcR3?>=_|$X1zUN7+DzBw zeH~-&MF9Wv;Sc`DmS#l4Q}T;MVzc?1%gJo=r4wSR-ixb`UK!#@I7C?Ui+rL{XzE1f z=EdRE3GiDVD)KkKt};;94%;PLe|@Jo7|Omy$5PM>+}70*ijt{TH#L`4(!~e^78K=* zBD(`?*y?NwxO^T%5RWKsUl>i!hC<6OJD;fmL`U+A;GmLpNgMx5?>=-8=TP-vjJ&UTzjlU zb!&;xzMZpg6%HuIUTt_+h&j%xEAMV|^!)|>{Pz2^<11BrIAtb{Kkw&`e^;z~T!Oy) zNcQqVNSynfpMHo;#>Xv9AT#y##W$CEvC9R`3o*;EgwW&$5u^MOM>o^UxB3Xn!BNej!5)`Rw-~AJv~(|@PY(1uyTHsDxpG?C zyX`XYlL+Um629!BuD#oUQ5AGCa9>HZAB}0Ugml?V^_cC&pM8pUxiT>CYw~E7Um+wk z)|x}Hoh9!iOj(1PmVQ*<<3z>lAkrh^r0Uu@0Q3xMUzSI&>pV){D^nuXF6z)6R@0wl zVNb7`AV?>BOCu<=dNx$u)X!`iNU*phZ5=h7!H+cvpr(1>tg6EuAOG_c!XFvQ28kFH z^fwc4mw5T+M{-|`=O*=7v8;^jHs_wsKLoTf8K@gj-?-qQ%7F_rr0|q+e*e_&MJV4>}ZMxyqWftPG862;5U_+b}onJG!Pg6a4PP%tGdzsAqJ2^@aV{C z_Dw$($kL`+GTXZ;ci+xhh@L!e#-+vRXw4i9e8^kQV19(14IPju^p7jE&5C6>yE%t} z?V)->g6+!m>$_;X&r}Sj#s~xrCaUl#4Yc^CNde$rs&7~oAQT*7nDr=L_!lehc;!js zU@tF!I$mdQ6I)KoZ^*~bQu5Ni!4Oh!GDYl?Ip8q*ZTqB%g1|g^hCpf{77j#E!q?+P z_c;ni$q#argtWgB3@J1}K~WI$drHheR=ckhV@}d@4q_Q8>bOFS*z^_C9+4r@!YHzS z6M|Z=KeI=aTrkn08d9_>5~gapcu@-11^xhZ6h~B=9zRj{|8y&^e_O~# zx|qO_Azw1=iI`qV%3?r+f1wm!wlqhYKE3!{pR8V_JHX5r>SXlyP zz)O)4XSd+3z_7uW9p3!q4Y|;K7jeoCclj*8Aw*cS1B%~8sC=aQQn|zu}5Y_oO0QxZWE@`i7o}SOhZR}qQ{jZXjqzyplkim_ALYZR4GHWCm1MFlsQ91Bfc8a${8weWI^=-+$Ux+gnJ9uFC9wpwWP+4x zSJZ~!=!4>~6mwAkK>RMcRIR}lhc?TxZ-iF>!v|JVeB>S z=N@JnSk0zn?}k@iu85oK{kiyuECc&A%~XU%7j}H&?@0*>)?aC4Q0t~dt?}LDCfvRR zAvMUC)AfLh_L}!!uB4-C!_JR<6uGg9f2)XksUCPN<(5Wj)=&h3>Hj(v#)kkl5FPR9 zMP5~ATVaq^{Ae*V+z4gF)PtXdkze?43NCq4(l-O!)lq$U=q_IeWg-`47A2M1u9DNs zF{;roiAT$yEIt<&$QpC$_}SVaHHRRS#0eap+b)kU8~`W+o*lz zQdjTGR6h6b)N{F?O|4=wK!b`ifkxvxrcKdDs~S#!zF z&5Wr?dO&t)vsKWQi&6{-uY^IQMTy*6EDZkinh9G<(j<6B;bCYB1Eq-&6;b1i*SjmK*z#(7 z!9&L(GU;Q3^ay)HZX%@|E;Cs07{1U(mk@~~A2gP<$vsA#VOk@H3eQ&zao6 z1~e5MD#!Aq`!pJ|al0UErKoLxLtbvJERyJwosk=bZQRiyEm3f>RLCSNVS4cS5a9j} zBCg=8BDgUK7oW%SO&UxtW~xS&tm{I%J&7WndXRcRss@J;vxD=?VJPK0?J8&McB&fp zwgq#e7Zn#Usys*DpXvx_NcNUoYrM!pV3uI}YFYr!Ga;risaUfS&M zHE*f?B)s4kKeUk7hhswVEX2g}8N`No1as92;5l=k{y*5H(Z8)%OPdFcDsaJ7N#ab% zMuKP|ttE*EVx>qnQA!A9r6^U>(UZu#O*DfFZ1@5VSf3^Z+@MPr|8lP4tK@nt^}2 z2wP?wgwewXnVl!!J$Ao$QCk^rUKQ5&So{iuI&WL{H7xB6FUUVX_jW&6(2QPjs{?|x zwx|aK-4O2RXnK}o_ZTO!nD)8b*My9%Cxob^9h0T* z*!<%YQQ1K2zmhYUi3qjXIW&q2#9o>DFFuhn9g}6PVSl*T6d~i&%ImK3?d`{+VJV23 zdx@L7dDS|G2rDofR2t2;GnMsNIEi1a_X@g16t8AqrZ{v_)1S;l8d8CO`=X%wSsp^c zl6KNMx3{9tCO4%ugr_0AL6Z*;G6%AUE82vJB_CYiXEtupdoj3dJ0LV{xo-l|01j|> zq6)s^BQ~&ta9w1#uiO4!KYzElF=`pI2te z(p^Szw*4@-ZEC{AEpGV>rk~$Kd46HaybVn6FPil z{RGIh`*F{~=Vnn@5(Oc_5(R&q714ljZ~3KZF_?bRVP%T_DoCm$c9`_{`IA=ih<&HB zq2bhrr^i%DiqD4Etp+P8j!&L!aUY++An=%Q=!TA4?Ma;WCsQRVeIp2xiaEhc{1_*0 zD4o{}1BbY{p9(^1t1tJ-g_Tep2Zy5!2xg=O+48Q1N6Z^ZPri&QV85+T0^?i&jLhDE%-IV%jolVC2QRzk)^kW}!t zR=?{%esS`ZOcLqoseq=xwg~ExsA}2mUlctqEb_Iq!2q8~weN336*4Bl>j1_d6?1P4 z|CG))J4}DdRMX!q)}}0X(bDE`W5HhRBt4SM2pS;2OeuF8pXx8h_h~io*eV8?D%Os^ zU;$wj)HDjd4gwqhI=$dUODX;0s-OOlCU0?GWDuGDij#EAwNF?6Q`d6bu8&2+5*|=+ zMbRY{MV(}Fq?ER6IcWXXX`@}hU+2WHfba3`SV^Bb*BpJTu-n=V#p9*c(CRz##op%4 z)g5PXx3F8EZu{=6I*qJp*ThX`*7VfOYK^c!?nO0bX-iG=G#m+l1PVQf03+c!rTJ7$ zl@24{ty$UH(60$?d#tv`=4r8Rt1y`7br&Bw!ry5FHAnzAne9OU0QmyHCJnAzyg-48 zCzU#k(5Z!bu_HijcyOU%YIj;axkfdt)|>@*QUlCeVIw~`kolST>z49kgjRdXxEL0m zDo)3q@;rV<2FuQ#K8C7hSn+pSO`%9?X+XU3CUmYoU$oqIUGE*oo4M@hcX0c=(6+bv z#%dD-9!3jh8aXl`4Xkhb@UNR2&DRRHvt z4WmSo06{WxO575rc%cX=AWF1;Fc|c^0gT7!BoRZ7Og{3Fe6=AfwqYH+WA(4Q=$hYI z%~bwT_9q{|M}zI+^>)8Aqa^>e4yb@u^HQs^4cwgyAkUKTN!Dq9B4=tjO<^=oEzkDQt^}sU8z@Lq7B?njJv3 zP&LI*^+t~@!VypkPCS}kF>^M%LT<+6{VHb$^kZ3Y2)TkfyrlX|=9EJ9j5CJV zHRtn8!)rGb%CE8+oI^&rwj!cSGM>}A8HG&MwzDQHdRg#y^SQ>j{h(8^!j&ToDcc!R zh4j?0>{#3bm8K4>((j+Erh6kuvnl2<_A&Iq+mTDh3U8XD!x>*{MVN*=WjS5rve^th zr-{H)(h&X;h6$0Hk5<$rapK_aFEJV|Ff;R_)f>#kIq>=}+w*ktA_8hDp`+Sn5L6@tT_>`p~^8P_`ZGqVXA=x5W;aAv?D)AJ{)$H9}DL zq*By{m7hEuvWmgtom<8ZG1*7j%3zyB<#aP52KxL-p>?yFf~&ar5u}GHJNA(aImdWD zc`&_Awnb%6QfPOoZm}?t`Nbkc-9eh-zvi1 z=nNaIlj5GM&5jc3?E2itzvQjCS?l1AE4M{zK^?g-yEK}b-x6PQ{#PG5fYeo%DH@B9o8NA8fR^ z-q=mnp&fr5mGRizdq0^Z8gMe0F`%=tZj>$Xe6zLZY!xj%P!gR+-23$NnV9nRcK?)| z(Nkxq6JQG^X@A}5tovOc$;Afu?kcBb{jy24sp~j)wFR4<^pnk-(@vXX{(!$<_9HEu zW(c{O^n=@cqe6L70Y>oW%s`Q^e4c(qFc~bx3r`{u(;G1mpy-v;BztWtavhSD``*zC zew}XLM`Y|#;zVy}uO)rAtb~pDTUuH7X@od2A)V*GX(KFCtfZ4}jLC_AJ8Mm+rP^u? zitu0(9vhPoBgI(Rp3__dUD2-C98u~mY^qW=`chVb2muAwy*V#4A0UG&Z*&T1rhTT$ z!{Xa*pdmykB6nxhjCc>;4bz_l`TFUn&G$r0GjShli1fXwzn(hue)`b*?W5Z5iJXE}gS8@aaxwaFR(9Z`AuCtmPxgR&kh3`cuF3$385k8R?wu?V5ijk;`+r50BE>vEGEZ7XisIU>G0-w?;a2so?%-nKuY7!Oi*navr z6ZItlUdC-b3wkPG9f@-?(79rHqD^aPbi z&5mCx0If|iu2d_Cx_jo+@Cbyui5FknDX?nHn*Hr)hK8`XR%qm ze4jBtS?p44JxZ}7MM}Lux<1B2?38>eFiU?!j+Y~#e(*iAKon0>dBMmf*sAYRStT%p zOIUQw+R@0g#EMV@Q^^kvD^!`gXjs`OZm<1XAg*VvcW2KlSNmg(0X9|HY= z-daq&^Y%EMySy6Nbgn)v!j>;@>zudEwC^3@Wy999u_qEH1iz%v!2~5{_P1N1sO%4- zWg?-B-?oNH!f$BWa9PXlAG85t>G@({7AnSh z8`l>TfJ)e8MV}WFkd)=yZ)<%Fu4_>wRv|7YAN5;x>Abu*8fxxH7F zGHD(0Lg)}woq!W($U=3b;>S1{A+TaT51iX|ipX>U~!-#&w8Ixn>&+`)JM9^e} z6V(Gvj8m2f<;$ zW-&SR@0Y{#wWbIO&|tQ+uJnMzBGV)2QBe++$WOtWCm`?>8E=OQ;VmNxZ`PvMqu#gM zS`ExuZMoj7W1m^6AT%Tkm}9)h%b|}ga80vq)xUWqLjAC6c{ZBHJ&Uf(J1A<$_oU-j zf+kIk44C+Zkm{n53?JpgW_MVj_lUbA??v+?Tg$Zx#X500bYurIt^e1+eN2Hxa=l%!AUJ$s{|sL5gg96gU(~bo+}B7-v-@ zk*xUJ0^6)(*E4)%Ek|TpOz?tYmQIoNba>H^IP)(Na>-0;ZEZO3@4>FQ$M5i^ln3uz zNhHg%HO149UrxSIy4Dt7&*6&AZT>v5W+P_rVl*E0v|rkUDEn^O)+1l0HW>aY%RJ8E zp`n`M&hd(={UW)rIgau|5a_!%RXYS|PDNVC!WvkR90w;oP!m>*C=L0Ze)P1`kw44|dSQW$ejnW<|;7 zddc-cIec5DaNb3=mx%juepv1npHyvA+N(@dx`i?XasuxRnzju5^kISw8zt&qXkldB zetU3WKWsqJZ8NPfR=LVU)dZYzYhzoUwrA)hZB(8@4}ZwMZ(g2+s^ZFWOoi2W(FF~X zOjXqTR)|9U!)J*E)+1u!>GaSrf>XI0e#K)mSpG2wOana^0|R);a_b!A3Q&r*jAN9}ZjLj*Z9M&<2+KPB6N&pu0U|Eq_ye zE64H0Nuw(=-ZV{K)mV!7cG#wJuir_XeZp7$t@N^qTFQF$vWQ3?1u*vgIX%F*Jlqqu zTD_20_1Cp|su~}X%pBdi!U>Y#F#;9$72b;Fs#ht=#x6#X>B<_tge7O55Ml_HThY%x4KREd_i&>GN@T(Rav(sv8+ z{bj2oV`=~ZV0irdM!=nnAO1h_QLzHyI_~}7Ssi(^Ssebhi+`f7`^NXqZTGVCkXt{I zy*y9){8#>?{df7gjJVTxj)D`?+aW0dZW1viB5j(<%3M~3_}r0$e^mo?$X>V1HSrYj z*$>mmf#+_3*G1bl)y=?vBr?+BGLMKoi6klkaA?GKwJQOC!>DsFvu+Hy&u~>fJ`>34 zH>#FRI1KO6td90xB~dmv5piJp&!m6{?yBzwTFrdc@we^Laru+Od!yckug>W126L1D zuB3S(59Cb8BT-Jr0xWx49F2@Fo#931dZJIK#zQ2O% z1ka(?U}BhQouRX#K0G<3pcmvXe}6(0{BhMtg>0MfL`hW?$=P0kRvl9xZi|{us9?+e zA_Nr$Iack)&DDe1PiF&Ov%D79cV2n)L$;5@sQ9Vd+1)inY@e|M0C_xkXs!WE%b90ah7G4m+8U#o_QgMo#j=diaPM~51% zR->HRf~26rxWEy|n?`ImitL2z&xwlslaXc;_?x2`XbopS_PEv+EI3naX(!~r#C$6o zP9#`;agIX*Op~2g1C4F?y7clO|Foz~o|4o-=!$+^Dig{LO7)ViPpP?nGYnaWGKAJE zotTn&(@2Ar(GTeLqL)ArPGjDx$!&C zs9(MZT-QP0{8YHkvBsx=dz7!HR|>W0X-5gSh6V+nt$!uz%N;7SBjX&+L% zoFGt1bv?cEif+X84DFBZFu$&qKYdr2fXKxActnWw`~8Efw4O4plf1w!7WZko6$pTdD~vy zzHyQYA(FHXN_p^}Zw;1fcFJ=o3RgVA5KzbyOMUas!HGdD3D>O2a;OT^T``x-IEg-R z2_TFOY1hWQ_@@CK^a&dgMf5~X9hIY2FIEy(_k94e`Aa zY%z!rT34XgwIaj}t4m6b4BcUq*-`R?e+c~D;(!gPr;8T2^JXbi$y>z>94 z@|$GfT?scqq=oP=GgE=MO_}v)H1q1qo(}1E+x`)@SwexWa9tP>pS>d;7-i(b+qzZf z-e;&-f(iWN2zRb$jgw0iv%v}~2a0l;P_xE;I>GOQnDJ*#P4$Eo@%4AId-XiW;@^iT z0vyo$Z~>fIm<|h!<*Kmgs-F51prYp$K)OHqg;ax(jxJ^Yr@704LmQ4(q2w zs3G0{H-!lYaExsA$3>jo=jGi0vpmRspBqVUL1NROYfM z$?Gg2+XYfy<4yKIjuO0xmXmwM3}jJ%T-}{2MgXC;blBM!3i7UlJ=jMx;-pFSw_)V` zpzHGP{nI{zTy<&xh1dTv#C)LQfrsFq>fTP%1eTwUOA##i#WxbWAt4|`2MOZ?EV!)` z_j#5ywyM8$t=hV#5mSd4j6KA?Ln3#B$TgXCiopNd{Z=>kh&Oz+uNV=>C$$dQAgLtl zQtVkl;3bG?d#6Qex?7{;*OVh|IwY29#sL(kh}C7^hs%mPAOQ=r9JTt;Jvc58mAO&b zRlK-A@P2BdoO9AW8^X}&b&dvok2l1`A7E@cQ0y=2S492@xGMmTWMUdQc)%1}y^WLv z?CGALrWY~fhe6FZ8sb6&m7Uc7;X||g(@M_^lz-?o*@o`E$4en-w0Y}=yuk&rWQDos zf9s}&i(WkPSEQ5MDg8rbo<`3t`}eAoP~HQN;IsCJIFPx9 zePprl`tw%+Be`dh6bAZ#fdK=-W}rC{dEjJf4TebVJfzyeR?-{Kwb!;vF9 z&RJU&!3>G{$@T4#@hqR91%l!_ALE>u1ZcIUr&glVan|-{ zXPU9=i~VZ)$#8uyWrlm<(N+xQ2yDghtool# zZM`38dktzsozB`9p01i>D0OCV!H{TOhP6dlzJw70Q~O71px*29AY^Pbs6MNsFj1?u z>8<^D4UMNlpaame>>u-CmtzswFM`f9PV(V!W1=|DjGJ$!EGCpYogK(wnqp`Bi;(lb zxx&Pl4vJ=I)7jR%yDPa)(L?8cAp$ol@U#kG3|=n#j9Ez{z54lPFe9pRm$d$GA3b2- z<{$H64l#yJ%FdGPIp0f7CZ+a|9BHVtJl-55^V^Mm=Jifss6OBh)Hy@Xf3*L Date: Fri, 8 Dec 2017 09:07:23 -0600 Subject: [PATCH 050/205] Improvements to creation of dataservices --- ngapp/src/app/app.component.spec.ts | 2 +- .../about-dialog/about-dialog.component.html | 10 ++-- .../about-dialog.component.spec.ts | 10 ++-- .../about-dialog/about-dialog.component.ts | 12 ++--- .../src/app/core/about-dialog/about-event.ts | 2 +- .../src/app/core/about-dialog/about.model.ts | 12 ++--- .../core/about-dialog/about.service.spec.ts | 8 ++-- .../app/core/about-dialog/about.service.ts | 2 +- .../core/about-dialog/mock-about.service.ts | 6 +-- ngapp/src/app/core/core.module.ts | 4 +- .../nav-header/nav-header.component.spec.ts | 12 ++--- .../core/nav-header/nav-header.component.ts | 8 ++-- .../add-dataservice-wizard.component.html | 6 ++- .../add-dataservice-wizard.component.ts | 28 ++++++++++- .../app/dataservices/shared/vdb.service.ts | 47 ++++++++++++++++++- .../app/dataservices/shared/vdbs-constants.ts | 2 +- 16 files changed, 123 insertions(+), 48 deletions(-) diff --git a/ngapp/src/app/app.component.spec.ts b/ngapp/src/app/app.component.spec.ts index d426e2b6..af5ec11a 100644 --- a/ngapp/src/app/app.component.spec.ts +++ b/ngapp/src/app/app.component.spec.ts @@ -1,8 +1,8 @@ import { async, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; import { CoreModule } from "@core/core.module"; -import { AppComponent } from "./app.component"; import { ModalModule } from "ngx-bootstrap"; +import { AppComponent } from "./app.component"; describe("AppComponent", () => { beforeEach(async(() => { diff --git a/ngapp/src/app/core/about-dialog/about-dialog.component.html b/ngapp/src/app/core/about-dialog/about-dialog.component.html index 8ecc7a86..94c54881 100644 --- a/ngapp/src/app/core/about-dialog/about-dialog.component.html +++ b/ngapp/src/app/core/about-dialog/about-dialog.component.html @@ -12,15 +12,15 @@

    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index c5196808..4a61e767 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -23,8 +23,8 @@ import { } from "@angular/core"; import { FormControl, FormGroup } from "@angular/forms"; -import { Validators } from "@angular/forms"; import { AbstractControl } from "@angular/forms"; +import { Validators } from "@angular/forms"; import { Router } from "@angular/router"; import { LoggerService } from "@core/logger.service"; import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; @@ -81,6 +81,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { private router: Router; private deploymentChangeSubscription: Subscription; private sourceVdbUnderDeployment: string; + private errorDetailMessage: string; constructor(router: Router, dataserviceService: DataserviceService, notifierService: NotifierService, logger: LoggerService, vdbService: VdbService ) { @@ -277,6 +278,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { }, (error) => { self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); + self.setErrorDetails(error); self.createComplete = true; self.createSuccessful = false; self.step3bConfig.nextEnabled = false; @@ -388,6 +390,13 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.setNavAway(this.step2Config.nextEnabled); } + /** + * @returns {string} the error details message + */ + public get errorDetails(): string { + return this.errorDetailMessage; + } + // ---------------- // Private Methods // ---------------- @@ -446,12 +455,29 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { }, (error) => { self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); + self.setErrorDetails(error); self.createComplete = true; self.createSuccessful = false; self.step3bConfig.nextEnabled = false; this.step3bConfig.previousEnabled = true; } ); + } + /** + * Sets the error details for the response + * @param resp the rest call response + */ + private setErrorDetails( resp: any ): void { + // Get the error from the response json + this.errorDetailMessage = ""; + if (resp) { + this.errorDetailMessage = resp.json().error; + } + // Error visible if message has content + if (this.errorDetailMessage.length === 0) { + this.errorDetailMessage = "Please check dataservice entries and retry"; + } } + } diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 75db75ca..dc646cb5 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -64,6 +64,33 @@ export class VdbService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Determine if the workspace has a vdb with the supplied name + * @param {string} vdbName the name of the VDB + * @returns {Observable} + */ + public hasWorkspaceVdb(vdbName: string): Observable { + return this.http + .get(environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath, this.getAuthRequestOptions()) + .map((response) => { + const vdbs = response.json(); + // Determine if the vdbName exists in the list + let vdbFound = false; + for (const vdb of vdbs) { + const name = vdb.keng__id; + if (name === vdbName) { + vdbFound = true; + break; + } + } + if (vdbFound) { + return response.ok; + } + return !response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + /** * Get the vdbs from the komodo rest interface * @returns {Observable} @@ -312,10 +339,28 @@ export class VdbService extends ApiService { vdbModelSource.setTranslatorName(connection.getDriverName()); // Chain the individual calls together in series to build the Vdb and deploy it - return this.createVdb(vdb) + return this.deleteVdbIfFound(vdb.getId()) + .flatMap((res) => this.createVdb(vdb)) .flatMap((res) => this.createVdbModel(vdb.getId(), vdbModel)) .flatMap((res) => this.createVdbModelSource(vdb.getId(), vdbModel.getId(), vdbModelSource)) .flatMap((res) => this.deployVdb(vdb.getId())); } + /** + * Deletes the workspace VDB if found. Checks the workspace first, before attempting the delete. + * If the VDB is not found the delete attempt is skipped. + * @param {string} vdbName the name of the vdb + * @returns {Observable} + */ + public deleteVdbIfFound(vdbName: string): Observable { + return this.hasWorkspaceVdb(vdbName) + .switchMap( (resp) => { + if (resp === true) { + return this.deleteVdb(vdbName); + } else { + return Observable.of(true); + } + }); + } + } diff --git a/ngapp/src/app/dataservices/shared/vdbs-constants.ts b/ngapp/src/app/dataservices/shared/vdbs-constants.ts index 30129915..3ad35860 100644 --- a/ngapp/src/app/dataservices/shared/vdbs-constants.ts +++ b/ngapp/src/app/dataservices/shared/vdbs-constants.ts @@ -13,7 +13,7 @@ export class VdbsConstants { public static readonly SERVICE_VIEW_MODEL_NAME = "views"; // ** must match KomodoDataserviceService.SERVICE_VDB_VIEW_MODEL ** - public static readonly SOURCE_VDB_SUFFIX = "SvcSource"; + public static readonly SOURCE_VDB_SUFFIX = "BtlSource"; public static readonly DEFAULT_READONLY_DATA_ROLE = "DefaultReadOnlyDataRole"; public static readonly statusPath = "/status"; From 26e43f5ae501d3f4fee9241441af1114a312ef59 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 8 Dec 2017 13:30:21 -0600 Subject: [PATCH 051/205] Moves dataservice name entry to last page of wizard --- .../add-dataservice-wizard.component.html | 67 +++++-------- .../add-dataservice-wizard.component.ts | 96 +++++++------------ .../app/dataservices/shared/vdb.service.ts | 6 +- 3 files changed, 65 insertions(+), 104 deletions(-) diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html index ee9e4bbc..bc1c6c3f 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html @@ -3,59 +3,44 @@ (onCancel)="cancelClicked($event)" (onNext)="nextClicked($event)" (onStepChange)="stepChanged($event)"> - - - - -

    {{ step1InstructionMessage }}

    -
    -
    - -
    - -
    {{ getBasicPropertyErrorMessage("name") }}
    -
    -
    -
    - -
    - -
    -
    -
    -
    - + - -

    {{ step2InstructionMessage }}

    - + +

    {{ step1InstructionMessage }}

    +
    +
    - + - - - -

    {{ step3InstructionMessage }}

    -

    Dataservice Properties:

    -
    -
    - - + + + +

    {{ step2InstructionMessage }}

    +
    + +
    + +
    + +
    {{ getBasicPropertyErrorMessage("name") }}
    +
    -
    - - +
    + +
    + +
    - +
    - - + +
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 4a61e767..5e7cc3f2 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -65,11 +65,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { // Wizard Step 2 public step2Config: WizardStepConfig; - - // Wizard Step 3 - public step3Config: WizardStepConfig; - public step3aConfig: WizardStepConfig; - public step3bConfig: WizardStepConfig; + public step2aConfig: WizardStepConfig; + public step2bConfig: WizardStepConfig; @ViewChild("wizard") public wizard: WizardComponent; @ViewChild(ConnectionTableSelectorComponent) public tableSelector: ConnectionTableSelectorComponent; @@ -103,37 +100,29 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.onSourceVdbDeploymentStateChanged(status); }); - // Step 1 - Name and Description + // Step 1 - Select Tables this.step1Config = { id: "step1", priority: 0, - title: "Name and Description", + title: "Select Tables", allowClickNav: false } as WizardStepConfig; - // Step 2 - Tables + // Step 2 - Review and Create this.step2Config = { id: "step2", priority: 0, - title: "Table Selection", - allowClickNav: false - } as WizardStepConfig; - - // Step 3 - Review and Create - this.step3Config = { - id: "step3", - priority: 0, title: "Review and Create", allowClickNav: false } as WizardStepConfig; - this.step3aConfig = { - id: "step3a", + this.step2aConfig = { + id: "step2a", priority: 0, title: "Review", allowClickNav: false } as WizardStepConfig; - this.step3bConfig = { - id: "step3b", + this.step2bConfig = { + id: "step2b", priority: 1, title: "Create", allowClickNav: false @@ -193,17 +182,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { * Step 1 instruction message */ public get step1InstructionMessage(): string { - if (!this.nameValid) { - return "Please enter a name for the Dataservice"; - } else { - return "Click Next to continue"; - } - } - - /* - * Step 2 instruction message - */ - public get step2InstructionMessage(): string { if (!this.tableSelector.valid) { return "Please select tables for the Dataservice"; } else { @@ -214,8 +192,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { /* * Step 3 instruction message */ - public get step3InstructionMessage(): string { - return "Review your entries. When finished, click Create to create the Dataservice"; + public get step2InstructionMessage(): string { + return "Review selections and enter a name. Click Create to create the Dataservice"; } /* @@ -256,8 +234,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { const sourceVdbName = this.tableSelector.getSelectedTables()[0].getConnection().getId() + VdbsConstants.SOURCE_VDB_SUFFIX; - this.step3bConfig.nextEnabled = false; - this.step3bConfig.previousEnabled = false; + this.step2bConfig.nextEnabled = false; + this.step2bConfig.previousEnabled = false; this.sourceVdbUnderDeployment = sourceVdbName; const self = this; @@ -271,8 +249,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } else { self.createComplete = true; self.createSuccessful = false; - self.step3bConfig.nextEnabled = false; - self.step3bConfig.previousEnabled = true; + self.step2bConfig.nextEnabled = false; + self.step2bConfig.previousEnabled = true; self.sourceVdbUnderDeployment = null; } }, @@ -281,8 +259,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { self.setErrorDetails(error); self.createComplete = true; self.createSuccessful = false; - self.step3bConfig.nextEnabled = false; - self.step3bConfig.previousEnabled = true; + self.step2bConfig.nextEnabled = false; + self.step2bConfig.previousEnabled = true; self.sourceVdbUnderDeployment = null; } ); @@ -332,8 +310,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } else if (status.isFailed()) { this.createComplete = true; this.createSuccessful = false; - this.step3bConfig.nextEnabled = false; - this.step3bConfig.previousEnabled = true; + this.step2bConfig.nextEnabled = false; + this.step2bConfig.previousEnabled = true; } } } @@ -343,14 +321,12 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if ($event.step.config.id === "step1") { this.updatePage1ValidStatus(); this.wizardConfig.nextTitle = "Next >"; - } else if ($event.step.config.id === "step2") { - this.updatePage2ValidStatus(); - this.wizardConfig.nextTitle = "Next >"; - } else if ($event.step.config.id === "step3a") { + } else if ($event.step.config.id === "step2a") { + this.updatePage2aValidStatus(); this.wizardConfig.nextTitle = "Create"; - } else if ($event.step.config.id === "step3b") { + } else if ($event.step.config.id === "step2b") { // Note: The next button is not disabled by default when wizard is done - this.step3Config.nextEnabled = false; + this.step2Config.nextEnabled = false; } else { this.wizardConfig.nextTitle = "Next >"; } @@ -385,9 +361,9 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { return tableStr; } - public updatePage2ValidStatus( ): void { - this.step2Config.nextEnabled = this.tableSelector.valid(); - this.setNavAway(this.step2Config.nextEnabled); + public updatePage1ValidStatus( ): void { + this.step1Config.nextEnabled = this.tableSelector.valid(); + this.setNavAway(this.step1Config.nextEnabled); } /** @@ -411,7 +387,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { }); // Responds to basic property changes - updates the page status this.basicPropertyForm.valueChanges.subscribe((val) => { - this.updatePage1ValidStatus( ); + this.updatePage2aValidStatus( ); }); } @@ -419,9 +395,9 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.step1Config.allowNavAway = allow; } - private updatePage1ValidStatus( ): void { - this.step1Config.nextEnabled = this.basicPropertyForm.valid; - this.setNavAway(this.step1Config.nextEnabled); + private updatePage2aValidStatus( ): void { + this.step2aConfig.nextEnabled = this.basicPropertyForm.valid; + this.setNavAway(this.step2aConfig.nextEnabled); } /* @@ -444,13 +420,13 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if (wasSuccess) { self.createComplete = true; self.createSuccessful = true; - self.step3bConfig.nextEnabled = false; - this.step3bConfig.previousEnabled = true; + self.step2bConfig.nextEnabled = false; + this.step2bConfig.previousEnabled = true; } else { self.createComplete = true; self.createSuccessful = false; - self.step3bConfig.nextEnabled = false; - this.step3bConfig.previousEnabled = true; + self.step2bConfig.nextEnabled = false; + this.step2bConfig.previousEnabled = true; } }, (error) => { @@ -458,8 +434,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { self.setErrorDetails(error); self.createComplete = true; self.createSuccessful = false; - self.step3bConfig.nextEnabled = false; - this.step3bConfig.previousEnabled = true; + self.step2bConfig.nextEnabled = false; + this.step2bConfig.previousEnabled = true; } ); } diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index dc646cb5..e79dc1ba 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -316,10 +316,10 @@ export class VdbService extends ApiService { // Filter values for the model let catName = table.getCatalogName(); let schemaName = table.getSchemaName(); - let tableName = table.getName(); + // let tableName = table.getName(); catName = (!catName || catName.length < 1) ? "%" : catName; schemaName = (!schemaName || schemaName.length < 1) ? "%" : schemaName; - tableName = (!tableName || tableName.length < 1) ? "%" : tableName; + // tableName = (!tableName || tableName.length < 1) ? "%" : tableName; // Set the importer properties for the physical model const props: NameValue[] = []; props.push(new NameValue("importer.TableTypes", "TABLE")); @@ -328,7 +328,7 @@ export class VdbService extends ApiService { props.push(new NameValue("importer.UseCatalogName", "false")); props.push(new NameValue("importer.catalog", catName)); props.push(new NameValue("importer.schemaPattern", schemaName)); - props.push(new NameValue("importer.tableNamePattern", tableName)); + props.push(new NameValue("importer.tableNamePattern", "%")); // TODO improve tablePattern when possible vdbModel.setProperties(props); // VdbModelSource to create From 50a0903398f78fe13c9cded3b2cf879a102c03f8 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 8 Dec 2017 16:24:43 -0600 Subject: [PATCH 052/205] Styling updates to wizard table selection page --- .../connection-table-selector.component.css | 32 +++++++++++++++++++ .../connection-table-selector.component.html | 12 ++++--- .../jdbc-table-selector.component.css | 27 ++++++++++++++++ .../jdbc-table-selector.component.html | 25 +++++++++------ .../app/dataservices/shared/vdb.service.ts | 23 +++++-------- 5 files changed, 91 insertions(+), 28 deletions(-) diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css index 0c2aff39..84749021 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css @@ -18,3 +18,35 @@ .connection-list .list-view-pf-description { width: 95%; } + +.connection-list .list-group-item.active { + background-color: darkblue; + color: white; + border-color: transparent; +} + +.connection-column-title { + height: 35px; + padding-top: 7px; + border:1px solid white; + background-color: #cccccc; + padding-left: 10px; +} + +.evenRow { + background-color: #f2f2f2; +} + +.oddRow { + background-color: white; +} + +.connection-selector-container { + padding-left: 0; + padding-right: 0; +} + +.jdbc-selector-container { + padding-left: 0; + padding-right: 0; +} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index e678327b..e2385c43 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -2,8 +2,10 @@ -
    - Connections +
    +
    + Connections +
    @@ -14,7 +16,9 @@
    -
    +
    @@ -36,7 +40,7 @@ -
    +
    diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css index 7298d607..f49ad27c 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css @@ -26,3 +26,30 @@ .jdbc-list .list-view-pf-description { width: 95%; } + +.jdbc-list .list-group-item.active { + background-color: darkblue; + color: white; + border-color: transparent; +} + +.jdbc-column-title { + height: 35px; + border:1px solid white; + background-color: #cccccc; + padding-top: 7px; + padding-left: 10px; + padding-right: 0; +} + +.jdbc-column-results { + padding-left: 0; + padding-right: 0; +} + +.evenRow { + background-color: #f2f2f2; +} +.oddRow { + background-color: white; +} diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index 772e9be4..b52cec34 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -1,13 +1,13 @@ -
    +
    Schemas
    -
    +
    Tables
    -
    +
    Selections
    @@ -28,9 +28,12 @@ No schema available
    -
    +
    -
    +
    @@ -61,9 +64,11 @@ No tables available
    -
    +
    -
    +
    @@ -88,9 +93,11 @@ No tables selected
    -
    +
    -
    +
    diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index e79dc1ba..62077864 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -71,24 +71,17 @@ export class VdbService extends ApiService { */ public hasWorkspaceVdb(vdbName: string): Observable { return this.http - .get(environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath, this.getAuthRequestOptions()) + .get(environment.komodoWorkspaceUrl + VdbsConstants.vdbsRootPath + "/" + vdbName, this.getAuthRequestOptions()) .map((response) => { - const vdbs = response.json(); - // Determine if the vdbName exists in the list - let vdbFound = false; - for (const vdb of vdbs) { - const name = vdb.keng__id; - if (name === vdbName) { - vdbFound = true; - break; - } - } - if (vdbFound) { return response.ok; - } - return !response.ok; }) - .catch( ( error ) => this.handleError( error ) ); + .catch((error) => { + // VDB not found returns a 404 + if (error.status === 404) { + return Observable.of(false); + } + this.handleError( error ); + } ); } /** From 312c0b532d4d0d20cb8a8690703498ee426d3a69 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 8 Dec 2017 17:11:44 -0600 Subject: [PATCH 053/205] Issue 27 Implement Validators for name and jndi checks - New dataservice wizard now is validation the dataservice name using the Komodo REST service - Made the help icon in the nav-header a bit larger - Changed home page to Dataservice Summary --- .../core/nav-header/nav-header.component.html | 2 +- .../core/nav-header/nav-header.component.less | 4 +++ .../add-dataservice-wizard.component.html | 2 +- .../add-dataservice-wizard.component.ts | 24 ++++++++++++-- .../shared/dataservice.service.ts | 32 ++++++++++++++++++- .../shared/dataservices-constants.ts | 1 + ngapp/src/environments/environment.prod.ts | 4 +-- ngapp/src/environments/environment.ts | 4 +-- 8 files changed, 64 insertions(+), 9 deletions(-) diff --git a/ngapp/src/app/core/nav-header/nav-header.component.html b/ngapp/src/app/core/nav-header/nav-header.component.html index 94ca34e3..bb49c8dd 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.html +++ b/ngapp/src/app/core/nav-header/nav-header.component.html @@ -6,7 +6,7 @@
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 5e7cc3f2..33b06cdc 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -79,6 +79,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { private deploymentChangeSubscription: Subscription; private sourceVdbUnderDeployment: string; private errorDetailMessage: string; + public nameValidationError: string = ""; constructor(router: Router, dataserviceService: DataserviceService, notifierService: NotifierService, logger: LoggerService, vdbService: VdbService ) { @@ -171,11 +172,30 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { return this.tableSelectorLoadingState === LoadingState.LOADED_INVALID; } + public handleNameChanged( input: AbstractControl ): void { + const self = this; + + this.dataserviceService.isValidName( input.value ).subscribe( + ( errorMsg ) => { + if ( errorMsg ) { + // only update if error has changed + if ( errorMsg != self.nameValidationError ) { + self.nameValidationError = errorMsg; + } + } else { // name is valid + self.nameValidationError = ""; + } + }, + ( error ) => { + self.logger.error( "[handleNameChanged] Error: %o", error ); + } ); + } + /* * Return the name valid state */ public get nameValid(): boolean { - return this.basicPropertyForm.controls["name"].valid; + return this.nameValidationError == null || this.nameValidationError.length == 0; } /* @@ -382,7 +402,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { */ private createBasicPropertyForm(): void { this.basicPropertyForm = new FormGroup({ - name: new FormControl("", Validators.required), + name: new FormControl( "", this.handleNameChanged.bind( this ) ), description: new FormControl("") }); // Responds to basic property changes - updates the page status diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index a660cb7c..4d939ec6 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -16,7 +16,7 @@ */ import { Injectable } from "@angular/core"; -import { Http } from "@angular/http"; +import { Http} from "@angular/http"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -39,6 +39,10 @@ import { Subscription } from "rxjs/Subscription"; @Injectable() export class DataserviceService extends ApiService { + private static readonly nameValidationUrl = environment.komodoWorkspaceUrl + + DataservicesConstants.dataservicesRootPath + + "/nameValidation/"; + // Observable dataservice state changes // Using replay status with cache of 1, so subscribers dont get an initial value on subscription public dataserviceStateChange: Subject< Map > = new ReplaySubject< Map >(1); @@ -78,6 +82,32 @@ export class DataserviceService extends ApiService { return this.selectedDataservice; } + /** + * Validates the specified data service name. If the name contains valid characters and the name is unique, the + * service returns 'null'. Otherwise, a 'string' containing an error message is returned. + * + * @param {string} dataserviceName + * @returns {Observable} + */ + public isValidName( name: string ): Observable< string > { + if ( !name || name.length === 0 ) { + return Observable.of( "Dataservice name cannot be empty" ); + } + + const url = DataserviceService.nameValidationUrl + encodeURIComponent( name ); + + return this.http.get( url, this.getAuthRequestOptions() ) + .map( ( response ) => { + if ( response.ok ) { + if ( response.text() ) { + return response.text(); + } + + return ""; + } } ) + .catch( ( error ) => this.handleError( error ) ); + } + /** * Get the dataservices from the komodo rest interface * @returns {Observable} diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ngapp/src/app/dataservices/shared/dataservices-constants.ts index 24b572f9..c7edf4fb 100644 --- a/ngapp/src/app/dataservices/shared/dataservices-constants.ts +++ b/ngapp/src/app/dataservices/shared/dataservices-constants.ts @@ -25,4 +25,5 @@ export class DataservicesConstants { public static readonly testDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/test-dataservice"; public static readonly testDataservicePath = DataservicesConstants.dataservicesRootPath + "/test-dataservice"; + } diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts index d8f887c9..0532bbc8 100644 --- a/ngapp/src/environments/environment.prod.ts +++ b/ngapp/src/environments/environment.prod.ts @@ -15,14 +15,14 @@ * limitations under the License. */ -import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; export const environment = { production: true, // the home page path - homePagePath: ConnectionsConstants.connectionsRootPath, + homePagePath: DataservicesConstants.dataservicesRootPath, // REST URL - Komodo import export url komodoImportExportUrl: "https://localhost:8443/vdb-builder/v1/importexport", diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index be874037..b5154bc5 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; // The file contents for the current environment will overwrite these during build. // The build system defaults to the dev environment which uses `environment.ts`, but if you do @@ -25,7 +25,7 @@ export const environment = { production: false, // the home page path - homePagePath: ConnectionsConstants.connectionsRootPath, + homePagePath: DataservicesConstants.dataservicesRootPath, // REST URL - Komodo import export url komodoImportExportUrl: "https://localhost:8443/vdb-builder/v1/importexport", From 9bf9e7dc7f58ba74f778c5bb092aa666f94398f4 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 12 Dec 2017 08:50:52 -0600 Subject: [PATCH 054/205] changes selected table style --- .../add-dataservice-wizard.component.spec.ts | 3 +- .../add-dataservice.component.spec.ts | 3 +- ...onnection-table-selector.component.spec.ts | 3 +- .../app/dataservices/dataservices.module.ts | 4 ++- .../jdbc-table-selector.component.html | 16 ++-------- .../jdbc-table-selector.component.spec.ts | 3 +- .../selected-table.component.css | 24 ++++++++++++++ .../selected-table.component.html | 6 ++++ .../selected-table.component.spec.ts | 32 +++++++++++++++++++ .../selected-table.component.ts | 24 ++++++++++++++ .../sql-control/sql-control.component.css | 4 +++ .../sql-control/sql-control.component.ts | 6 ++-- ngapp/src/styles.css | 4 --- 13 files changed, 107 insertions(+), 25 deletions(-) create mode 100644 ngapp/src/app/dataservices/selected-table/selected-table.component.css create mode 100644 ngapp/src/app/dataservices/selected-table/selected-table.component.html create mode 100644 ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts create mode 100644 ngapp/src/app/dataservices/selected-table/selected-table.component.ts diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index 127a8484..1d0531d9 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -7,6 +7,7 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { CoreModule } from "@core/core.module"; import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; +import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -25,7 +26,7 @@ describe("AddDataserviceWizardComponent", () => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], declarations: [ AddDataserviceWizardComponent, ConnectionTableSelectorComponent, JdbcTableSelectorComponent, - PropertyFormComponent, PropertyFormPropertyComponent ], + PropertyFormComponent, PropertyFormPropertyComponent, SelectedTableComponent ], providers: [ NotifierService, { provide: DataserviceService, useClass: MockDataserviceService }, diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index bc39da93..0a9d53b8 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -8,6 +8,7 @@ import { CoreModule } from "@core/core.module"; import { AddDataserviceWizardComponent } from "@dataservices/add-dataservice-wizard/add-dataservice-wizard.component"; import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; +import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -25,7 +26,7 @@ describe("AddDataserviceComponent", () => { TestBed.configureTestingModule({ imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent, - ConnectionTableSelectorComponent, JdbcTableSelectorComponent ], + ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ NotifierService, { provide: DataserviceService, useClass: MockDataserviceService }, diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts index 3a024a67..36246b82 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -7,6 +7,7 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; +import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; describe("ConnectionTableSelectorComponent", () => { @@ -16,7 +17,7 @@ describe("ConnectionTableSelectorComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ FormsModule, HttpModule ], - declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent ], + declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ AppSettingsService, LoggerService, { provide: ConnectionService, useClass: MockConnectionService }, diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 2467a42b..c9f34203 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -36,6 +36,7 @@ import { AddDataserviceWizardComponent } from "./add-dataservice-wizard/add-data import { AddDataserviceComponent } from "./add-dataservice/add-dataservice.component"; import { ConnectionTableSelectorComponent } from "./connection-table-selector/connection-table-selector.component"; import { JdbcTableSelectorComponent } from "./jdbc-table-selector/jdbc-table-selector.component"; +import { SelectedTableComponent } from "./selected-table/selected-table.component"; import { SqlControlComponent } from "./sql-control/sql-control.component"; import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.component"; @@ -61,7 +62,8 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co ConnectionTableSelectorComponent, JdbcTableSelectorComponent, TestDataserviceComponent, - SqlControlComponent + SqlControlComponent, + SelectedTableComponent ], providers: [ DataserviceService, diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index b52cec34..b0d2f42d 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -94,19 +94,7 @@
    -
    -
    -
    -
    -
    -
    - {{ table.getName() }} -
    -
    -
    -
    -
    +
    +
    diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index 0a474d3f..18dc91f3 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -6,6 +6,7 @@ import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; import { JdbcTableSelectorComponent } from "./jdbc-table-selector.component"; describe("JdbcTableSelectorComponent", () => { @@ -15,7 +16,7 @@ describe("JdbcTableSelectorComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ FormsModule, HttpModule ], - declarations: [ JdbcTableSelectorComponent ], + declarations: [ JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ AppSettingsService, LoggerService, { provide: ConnectionService, useClass: MockConnectionService }, diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.css b/ngapp/src/app/dataservices/selected-table/selected-table.component.css new file mode 100644 index 00000000..d2b84ec2 --- /dev/null +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.css @@ -0,0 +1,24 @@ +.selected-table-card { + background-color: #f2f2f2; + border:2px dotted darkblue; + margin-top: 5px; + margin-left: 15px; + min-height: 60px; + max-height: 80px; + padding-top: 5px; + padding-right: 5px; +} + +.selected-table-name { + margin-left: 20px; + font-weight: bold; +} + +.selected-table-connection { + margin-left: 5px; +} + +.selected-table-close-icon { + cursor: pointer; + color: darkred; +} diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.html b/ngapp/src/app/dataservices/selected-table/selected-table.component.html new file mode 100644 index 00000000..8a42c9d6 --- /dev/null +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.html @@ -0,0 +1,6 @@ +
    + {{ table.getConnection().getId() }} + +
    + {{ table.name }} +
    diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts new file mode 100644 index 00000000..c28990f2 --- /dev/null +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts @@ -0,0 +1,32 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { Connection } from "../../connections/shared/connection.model"; +import { Table } from "../shared/table.model"; +import { SelectedTableComponent } from "./selected-table.component"; + +describe("SelectedTableComponent", () => { + let component: SelectedTableComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SelectedTableComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SelectedTableComponent); + component = fixture.componentInstance; + const connection = new Connection(); + connection.setId("testConn"); + const table = new Table(); + table.setConnection(connection); + component.table = table; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts new file mode 100644 index 00000000..83baf9d3 --- /dev/null +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts @@ -0,0 +1,24 @@ +import { Component, Input, OnInit } from "@angular/core"; +import { Table } from "@dataservices/shared/table.model"; + +@Component({ + selector: "app-selected-table", + templateUrl: "./selected-table.component.html", + styleUrls: ["./selected-table.component.css"] +}) +export class SelectedTableComponent implements OnInit { + + @Input() public table: Table; + + constructor() { + // nothing to do + } + + public ngOnInit(): void { + // nothing to do + } + + public onRemove(): void { + this.table.selected = false; + } +} diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.css b/ngapp/src/app/dataservices/sql-control/sql-control.component.css index 834c50e4..ccdce30c 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.css +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.css @@ -26,3 +26,7 @@ .sql-control-controls-offset input[type=number] { width: 5em; } + +.row-number-column { + text-align: center; +} diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts index 1b77bb04..c5e3489c 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Input } from "@angular/core"; +import {Input, ViewEncapsulation} from "@angular/core"; import { Component, OnInit } from "@angular/core"; import { LoggerService } from "@core/logger.service"; import { ColumnData } from "@dataservices/shared/column-data.model"; @@ -28,6 +28,7 @@ import "codemirror/addon/selection/active-line.js"; import "codemirror/mode/sql/sql.js"; @Component({ + encapsulation: ViewEncapsulation.None, selector: "app-sql-control", templateUrl: "./sql-control.component.html", styleUrls: ["./sql-control.component.css"] @@ -230,7 +231,8 @@ export class SqlControlComponent implements OnInit { prop: rowNumHeader, resizable: true, sortable: true, - width: 60 }; + width: 60, + cellClass: "row-number-column"}; this.columns.push( column ); // diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index b9f25ab8..0a7d7fd7 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -47,7 +47,3 @@ border-left: 1px solid #d8d8d8; border-right: 1px solid #d8d8d8; } - -.datatable-body-cell:first-child { - text-align: center; -} From 031c002f76d8182c2bed63e4508c2badfd5b679a Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 12 Dec 2017 13:05:39 -0600 Subject: [PATCH 055/205] Changes to the connections list in the dataservice wizard - changed the list to a datatable - some style changes to the core datatable style classes - sorting of connections is not working - next button enablement is not working once a table is elected - fixes some lint errors/warnings --- .../core/nav-header/nav-header.component.ts | 2 +- .../add-dataservice-wizard.component.spec.ts | 3 +- .../add-dataservice-wizard.component.ts | 33 ++++---- .../add-dataservice.component.spec.ts | 3 +- .../connection-table-selector.component.css | 48 ----------- .../connection-table-selector.component.html | 63 +++++++------- ...onnection-table-selector.component.spec.ts | 3 +- .../connection-table-selector.component.ts | 82 ++++++++++++------- .../selected-table.component.html | 2 +- .../shared/dataservice.service.ts | 2 +- .../sql-control/sql-control.component.ts | 2 +- ngapp/src/styles.css | 12 +++ 12 files changed, 120 insertions(+), 135 deletions(-) diff --git a/ngapp/src/app/core/nav-header/nav-header.component.ts b/ngapp/src/app/core/nav-header/nav-header.component.ts index d24f24e6..7a072b3d 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.ts @@ -31,11 +31,11 @@ import { BsModalRef } from "ngx-bootstrap/modal/modal-options.class"; }) export class NavHeaderComponent { + public aboutInfo: About; private aboutRef: BsModalRef; private logger: LoggerService; private modalService: BsModalService; private aboutService: AboutService; - public aboutInfo: About; constructor( logger: LoggerService, modalService: BsModalService, diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index 1d0531d9..fbef22b2 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -15,6 +15,7 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; +import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard.component"; @@ -24,7 +25,7 @@ describe("AddDataserviceWizardComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], + imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, NgxDatatableModule ], declarations: [ AddDataserviceWizardComponent, ConnectionTableSelectorComponent, JdbcTableSelectorComponent, PropertyFormComponent, PropertyFormPropertyComponent, SelectedTableComponent ], providers: [ diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 33b06cdc..081b0fb9 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -24,7 +24,6 @@ import { import { FormControl, FormGroup } from "@angular/forms"; import { AbstractControl } from "@angular/forms"; -import { Validators } from "@angular/forms"; import { Router } from "@angular/router"; import { LoggerService } from "@core/logger.service"; import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; @@ -71,6 +70,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { @ViewChild("wizard") public wizard: WizardComponent; @ViewChild(ConnectionTableSelectorComponent) public tableSelector: ConnectionTableSelectorComponent; + public nameValidationError = ""; private dataserviceService: DataserviceService; private notifierService: NotifierService; private vdbService: VdbService; @@ -79,7 +79,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { private deploymentChangeSubscription: Subscription; private sourceVdbUnderDeployment: string; private errorDetailMessage: string; - public nameValidationError: string = ""; constructor(router: Router, dataserviceService: DataserviceService, notifierService: NotifierService, logger: LoggerService, vdbService: VdbService ) { @@ -175,27 +174,27 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { public handleNameChanged( input: AbstractControl ): void { const self = this; - this.dataserviceService.isValidName( input.value ).subscribe( - ( errorMsg ) => { - if ( errorMsg ) { - // only update if error has changed - if ( errorMsg != self.nameValidationError ) { - self.nameValidationError = errorMsg; - } - } else { // name is valid - self.nameValidationError = ""; - } - }, - ( error ) => { - self.logger.error( "[handleNameChanged] Error: %o", error ); - } ); + this.dataserviceService.isValidName( input.value ).subscribe( + ( errorMsg ) => { + if ( errorMsg ) { + // only update if error has changed + if ( errorMsg !== self.nameValidationError ) { + self.nameValidationError = errorMsg; + } + } else { // name is valid + self.nameValidationError = ""; + } + }, + ( error ) => { + self.logger.error( "[handleNameChanged] Error: %o", error ); + } ); } /* * Return the name valid state */ public get nameValid(): boolean { - return this.nameValidationError == null || this.nameValidationError.length == 0; + return this.nameValidationError == null || this.nameValidationError.length === 0; } /* diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index 0a9d53b8..cecda7e4 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -15,6 +15,7 @@ import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { SharedModule } from "@shared/shared.module"; +import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceComponent } from "./add-dataservice.component"; @@ -24,7 +25,7 @@ describe("AddDataserviceComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], + imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule, NgxDatatableModule ], declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent, ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css index 84749021..b0ad8ed3 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css @@ -1,51 +1,3 @@ -.list-div { - position: relative; - height: 100%; - max-height: 300px; - overflow-y: auto; -} - -.connection-list .list-view-pf-main-info { - padding-top: 0.5em; - padding-bottom: 0.5em; -} - -.connection-list .list-group-item-heading { - font-size: 12px; - margin-right: 5px; -} - -.connection-list .list-view-pf-description { - width: 95%; -} - -.connection-list .list-group-item.active { - background-color: darkblue; - color: white; - border-color: transparent; -} - -.connection-column-title { - height: 35px; - padding-top: 7px; - border:1px solid white; - background-color: #cccccc; - padding-left: 10px; -} - -.evenRow { - background-color: #f2f2f2; -} - -.oddRow { - background-color: white; -} - -.connection-selector-container { - padding-left: 0; - padding-right: 0; -} - .jdbc-selector-container { padding-left: 0; padding-right: 0; diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index e2385c43..3c7be0e2 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -1,39 +1,36 @@
    - - - -
    -
    - Connections -
    -
    - -
    -
    -
    - - Problem Loading Connections! -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    - {{ connection.getId() }} -
    -
    -
    -
    -
    +
    + +
    +
    + + Problem Loading Connections!
    +
    + + + + Connections + + + + {{row.name}} + + + +
    diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts index 36246b82..04d53dd7 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -8,6 +8,7 @@ import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; +import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; describe("ConnectionTableSelectorComponent", () => { @@ -16,7 +17,7 @@ describe("ConnectionTableSelectorComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule ], + imports: [ FormsModule, HttpModule, NgxDatatableModule ], declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ AppSettingsService, LoggerService, diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index fe69a34b..15eb264d 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -15,10 +15,7 @@ * limitations under the License. */ -import { ViewChild } from "@angular/core"; -import { Output } from "@angular/core"; -import { EventEmitter } from "@angular/core"; -import { Component, OnInit } from "@angular/core"; +import { Component, EventEmitter, OnInit, Output, ViewChild, ViewEncapsulation } from "@angular/core"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { LoggerService } from "@core/logger.service"; @@ -27,6 +24,7 @@ import { Table } from "@dataservices/shared/table.model"; import { LoadingState } from "@shared/loading-state.enum"; @Component({ + encapsulation: ViewEncapsulation.None, selector: "app-connection-table-selector", templateUrl: "./connection-table-selector.component.html", styleUrls: ["./connection-table-selector.component.css"] @@ -37,6 +35,18 @@ export class ConnectionTableSelectorComponent implements OnInit { @ViewChild(JdbcTableSelectorComponent) public jdbcTableSelector: JdbcTableSelectorComponent; + public readonly nameProp = "name"; // must match html template + public rows: any[] = []; + + public readonly customClasses = { + sortAscending: "fa fa-sort-asc", + sortDescending: "fa fa-sort-desc", + pagerLeftArrow: "fa fa-chevron-left", + pagerRightArrow: "fa fa-chevron-right", + pagerPrevious: "fa fa-step-backward", + pagerNext: "fa fa-step-forward" + }; + private connectionService: ConnectionService; private allConnections: Connection[] = []; private selectedConn: Connection; @@ -61,6 +71,13 @@ export class ConnectionTableSelectorComponent implements OnInit { (conns) => { self.allConnections = conns; self.connectionLoadingState = LoadingState.LOADED_VALID; + + // load table after setting loading state so table has been constructed + self.allConnections.forEach( ( connection ) => { + const row = {}; + row[ this.nameProp ] = connection.getId(); + self.rows.push( row ); + } ); }, (error) => { self.logger.error("[ConnectionTableSelectorComponent] Error getting connections: %o", error); @@ -69,33 +86,13 @@ export class ConnectionTableSelectorComponent implements OnInit { ); } - /** - * Toggles the selection - * @param {Connection} connection the connection whose selection changed - */ - public toggleConnectionSelected(connection: Connection): void { - // Connection currently selected, so deselect it - if (this.isConnectionSelected(connection)) { - this.selectedConn = null; - } else { - // Connection not currently selected or nothing selected, so select it. - this.selectedConn = connection; - } - // Set the specific selector with the current connection - if (this.jdbcTableSelector) { - if (this.selectedConn && this.selectedConn.isJdbc()) { - this.jdbcTableSelector.setConnection(connection); - } else { - this.jdbcTableSelector.setConnection(null); - } - } - } + // callback from connections table selection + public onSelect( { selected }) { + // connection is single select so get first element + const connectionName = selected[ 0 ][ this.nameProp ]; - /** - * Respond to child table selection changes by propagating up my parent - */ - public onTableSelectionChanged( ): void { - this.tableSelectionChanged.emit(); + // find and set selected connection (see setter) + this.selectedConnection = this.allConnections.find(( conn ) => conn.getId() === connectionName ); } /** @@ -174,6 +171,18 @@ export class ConnectionTableSelectorComponent implements OnInit { */ public set selectedConnection(conn: Connection) { this.selectedConn = conn; + + // Set the specific selector with the current connection + if (this.jdbcTableSelector) { + if (this.selectedConn && this.selectedConn.isJdbc()) { + this.jdbcTableSelector.setConnection(this.selectedConnection); + } else { + this.jdbcTableSelector.setConnection(null); + } + } + + // notify upstream that connection selection has changed + this.tableSelectionChanged.emit(); } /* @@ -196,4 +205,17 @@ export class ConnectionTableSelectorComponent implements OnInit { return selectedTables; } + // used by table + public get tableMessages(): { emptyMessage: string; totalMessage: string | string } { + const msg = this.allConnections.length === 1 ? "connection" : "connections"; + + return { + // no data message + emptyMessage: "No connections found", + + // footer total message + totalMessage: msg + }; + } + } diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.html b/ngapp/src/app/dataservices/selected-table/selected-table.component.html index 8a42c9d6..28e263d5 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.html +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.html @@ -2,5 +2,5 @@ {{ table.getConnection().getId() }}
    - {{ table.name }} + {{ table.getName() }}
    diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 4d939ec6..a9ea03e6 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -16,7 +16,7 @@ */ import { Injectable } from "@angular/core"; -import { Http} from "@angular/http"; +import { Http } from "@angular/http"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts index c5e3489c..727461a4 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import {Input, ViewEncapsulation} from "@angular/core"; +import { Input, ViewEncapsulation } from "@angular/core"; import { Component, OnInit } from "@angular/core"; import { LoggerService } from "@core/logger.service"; import { ColumnData } from "@dataservices/shared/column-data.model"; diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index 0a7d7fd7..47262e20 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -38,12 +38,24 @@ background-color: white; } +.datatable-row-even:hover { + background-color: #def3ff; +} + .datatable-row-odd { background-color: #f2f2f2; } +.datatable-row-odd:hover { + background-color: #def3ff; +} + .datatable-body-cell { padding: 0.25em; border-left: 1px solid #d8d8d8; border-right: 1px solid #d8d8d8; } + +.datatable-body-row.active .datatable-row-group { + background-color: #39a5dc !important; +} From 8de66f85bbee64b49e2722ff8dbdc5f66f40493a Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 14 Dec 2017 08:41:56 -0600 Subject: [PATCH 056/205] Reorg of the AddDataservice Wizard --- .../activities-cards.component.spec.ts | 1 + .../activities-list.component.spec.ts | 1 + .../activities/activities.component.spec.ts | 7 ++ .../add-activity-wizard.component.spec.ts | 1 + .../add-activity.component.spec.ts | 1 + .../add-activity-form.component.spec.ts | 1 + ngapp/src/app/app.component.spec.ts | 1 + .../add-connection-wizard.component.spec.ts | 1 + .../add-connection.component.spec.ts | 1 + .../connections-cards.component.spec.ts | 1 + .../connections-list.component.spec.ts | 1 + .../connections/connections.component.spec.ts | 7 ++ .../about-dialog.component.spec.ts | 1 + .../core/about-dialog/about.service.spec.ts | 3 +- ngapp/src/app/core/api.service.spec.ts | 1 + .../src/app/core/app-settings.service.spec.ts | 1 + .../breadcrumb/breadcrumb.component.spec.ts | 1 + .../breadcrumbs/breadcrumbs.component.spec.ts | 1 + .../nav-header/nav-header.component.spec.ts | 1 + .../vertical-nav.component.spec.ts | 1 + .../add-dataservice-wizard.component.html | 8 +- .../add-dataservice-wizard.component.spec.ts | 1 + .../add-dataservice-wizard.component.ts | 16 ++-- .../add-dataservice.component.spec.ts | 1 + .../connection-table-selector.component.css | 9 +++ .../connection-table-selector.component.html | 34 +++++++-- ...onnection-table-selector.component.spec.ts | 10 ++- .../connection-table-selector.component.ts | 53 ++++++++++--- .../dataservices-cards.component.spec.ts | 1 + .../dataservices-list.component.spec.ts | 1 + .../dataservices.component.spec.ts | 7 ++ .../jdbc-table-selector.component.css | 4 +- .../jdbc-table-selector.component.html | 39 +++------- .../jdbc-table-selector.component.spec.ts | 10 ++- .../jdbc-table-selector.component.ts | 68 +++++++++++++---- .../selected-table.component.spec.ts | 2 +- .../selected-table.component.ts | 4 +- .../shared/dataservice.service.ts | 76 ++++++++++++++++++- .../shared/mock-dataservice.service.ts | 19 ++++- .../sql-control/sql-control.component.spec.ts | 1 + .../test-dataservice.component.spec.ts | 1 + .../confirm-delete.component.spec.ts | 1 + .../page-error/page-error.component.spec.ts | 1 + .../page-not-found.component.spec.ts | 1 + .../property-form.component.spec.ts | 1 + ngapp/src/styles.css | 3 +- 46 files changed, 323 insertions(+), 83 deletions(-) diff --git a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts index 4b099a3e..4f7928f2 100644 --- a/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts +++ b/ngapp/src/app/activities/activities-cards/activities-cards.component.spec.ts @@ -23,6 +23,7 @@ describe("ActivitiesCardsComponent", () => { }); it("should be created", () => { + console.log("========== [ActivitiesCardsComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts index b0b4f442..882b41ce 100644 --- a/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts +++ b/ngapp/src/app/activities/activities-list/activities-list.component.spec.ts @@ -23,6 +23,7 @@ describe("ActivitiesListComponent", () => { }); it("should be created", () => { + console.log("========== [ActivitiesListComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts index 9059e043..55ef0e4e 100644 --- a/ngapp/src/app/activities/activities.component.spec.ts +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -38,10 +38,12 @@ describe("ActivitiesComponent", () => { })); it("should be created", () => { + console.log("========== [ActivitiesComponent] should be created"); expect(component).toBeTruthy(); }); it("should have Activities Title", () => { + console.log("========== [ActivitiesComponent] should have Activities Title"); // query for the title

    by CSS element selector const de = fixture.debugElement.query(By.css("h2")); const el = de.nativeElement; @@ -49,12 +51,14 @@ describe("ActivitiesComponent", () => { }); it("should have Toolbar", () => { + console.log("========== [ActivitiesComponent] should have Toolbar"); // query for the toolbar by css classname const de = fixture.debugElement.query(By.css(".toolbar-pf")); expect(de).toBeDefined(); }); it("should have Activities", () => { + console.log("========== [ActivitiesComponent] should have Activities"); // Check component object const activities = component.allActivities; expect(activities.length).toEqual(3); @@ -66,6 +70,7 @@ describe("ActivitiesComponent", () => { }); it("should have initial card layout", () => { + console.log("========== [ActivitiesComponent] should have initial card layout"); // app-activities-cards should be present let debugEl = fixture.debugElement.query(By.css("app-activities-cards")); const element = debugEl.nativeElement; @@ -77,6 +82,7 @@ describe("ActivitiesComponent", () => { }); it("should toggle layout", () => { + console.log("========== [ActivitiesComponent] should toggle layout"); // Initial layout should be Card Layout let cardDebugElem = fixture.debugElement.query(By.css("app-activities-cards")); let listDebugElem = fixture.debugElement.query(By.css("app-activities-list")); @@ -99,6 +105,7 @@ describe("ActivitiesComponent", () => { }); it("should filter activities", () => { + console.log("========== [ActivitiesComponent] should filter activities"); // Expect 3 activities initially. let activities = component.filteredActivities; expect(activities.length).toEqual(3); diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts index f17ce2de..cc473270 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts @@ -37,6 +37,7 @@ describe("AddActivityWizardComponent", () => { }); it("should be created", () => { + console.log("========== [AddActivityWizardComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 841dfa9b..80c8d413 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -37,6 +37,7 @@ describe("AddActivityComponent", () => { }); it("should be created", () => { + console.log("========== [AddActivityComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts index 76123eaa..822ad1ca 100644 --- a/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts +++ b/ngapp/src/app/activities/shared/add-activity-form/add-activity-form.component.spec.ts @@ -25,6 +25,7 @@ describe("AddActivityFormComponent", () => { }); it("should be created", () => { + console.log("========== [AddActivityFormComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/app.component.spec.ts b/ngapp/src/app/app.component.spec.ts index af5ec11a..ed67d540 100644 --- a/ngapp/src/app/app.component.spec.ts +++ b/ngapp/src/app/app.component.spec.ts @@ -17,6 +17,7 @@ describe("AppComponent", () => { })); it("should create the app", async(() => { + console.log("========== [AppComponent] should be created"); const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; expect(app).toBeTruthy(); diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts index b6ef21cd..df00a2a5 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts @@ -34,6 +34,7 @@ describe("AddConnectionWizardComponent", () => { }); it("should be created", () => { + console.log("========== [AddConnectionWizardComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index bed73a77..3d5d3f26 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -34,6 +34,7 @@ describe("AddConnectionComponent", () => { }); it("should be created", () => { + console.log("========== [AddConnectionComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts index 6d60bc2c..fa4ef834 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts @@ -23,6 +23,7 @@ describe("ConnectionsCardsComponent", () => { }); it("should be created", () => { + console.log("========== [ConnectionCardsComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts index b0bad59a..761ce445 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts +++ b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts @@ -23,6 +23,7 @@ describe("ConnectionsListComponent", () => { }); it("should be created", () => { + console.log("========== [ConnectionsListComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index 99eb20d0..6584158f 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -37,10 +37,12 @@ describe("ConnectionsComponent", () => { })); it("should be created", () => { + console.log("========== [ConnectionsComponent] should be created"); expect(component).toBeTruthy(); }); it("should have Connections Title", () => { + console.log("========== [ConnectionsComponent] should have Connections Title"); // query for the title

    by CSS element selector const de = fixture.debugElement.query(By.css("h2")); const el = de.nativeElement; @@ -48,12 +50,14 @@ describe("ConnectionsComponent", () => { }); it("should have Toolbar", () => { + console.log("========== [ConnectionsComponent] should have Toolbar"); // query for the toolbar by css classname const de = fixture.debugElement.query(By.css(".toolbar-pf")); expect(de).toBeDefined(); }); it("should have Connections", () => { + console.log("========== [ConnectionsComponent] should have Connections"); // Check component object const connections = component.allConnections; expect(connections.length).toEqual(3); @@ -65,6 +69,7 @@ describe("ConnectionsComponent", () => { }); it("should have initial card layout", () => { + console.log("========== [ConnectionsComponent] should have initial card layout"); // app-connections-cards should be present let debugEl = fixture.debugElement.query(By.css("app-connections-cards")); const element = debugEl.nativeElement; @@ -76,6 +81,7 @@ describe("ConnectionsComponent", () => { }); it("should toggle layout", () => { + console.log("========== [ConnectionsComponent] should toggle layout"); // Initial layout should be Card Layout let cardDebugElem = fixture.debugElement.query(By.css("app-connections-cards")); let listDebugElem = fixture.debugElement.query(By.css("app-connections-list")); @@ -98,6 +104,7 @@ describe("ConnectionsComponent", () => { }); it("should filter connections", () => { + console.log("========== [ConnectionsComponent] should filter connections"); // Expect 3 connections initially. let connections = component.filteredConnections; expect(connections.length).toEqual(3); diff --git a/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts b/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts index b089b3e7..6515eaee 100644 --- a/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts +++ b/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts @@ -23,6 +23,7 @@ describe("AboutDialogComponent", () => { }); it("should be created", () => { + console.log("========== [AboutDialogComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/core/about-dialog/about.service.spec.ts b/ngapp/src/app/core/about-dialog/about.service.spec.ts index 082cbdc1..1ed0f108 100644 --- a/ngapp/src/app/core/about-dialog/about.service.spec.ts +++ b/ngapp/src/app/core/about-dialog/about.service.spec.ts @@ -15,6 +15,7 @@ describe("AboutService", () => { it("should be created", inject([ AboutService, AppSettingsService, LoggerService ], ( service: AboutService ) => { - expect( service ).toBeTruthy(); + console.log("========== [AboutServiceComponent] should be created"); + expect( service ).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/api.service.spec.ts b/ngapp/src/app/core/api.service.spec.ts index c4776cb1..522db18e 100644 --- a/ngapp/src/app/core/api.service.spec.ts +++ b/ngapp/src/app/core/api.service.spec.ts @@ -14,6 +14,7 @@ describe("ApiService", () => { it("should be created", inject([LoggerService], (service: MockService ) => { + console.log("========== [ApiServiceComponent] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/app-settings.service.spec.ts b/ngapp/src/app/core/app-settings.service.spec.ts index e37b3acb..a495df62 100644 --- a/ngapp/src/app/core/app-settings.service.spec.ts +++ b/ngapp/src/app/core/app-settings.service.spec.ts @@ -10,6 +10,7 @@ describe("AppSettingsService", () => { }); it("should be created", inject([AppSettingsService], (service: AppSettingsService) => { + console.log("========== [AppSettingsServiceComponent] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts index 5441208a..591b67e8 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts @@ -23,6 +23,7 @@ describe("BreadcrumbComponent", () => { }); it("should be created", () => { + console.log("========== [BreadcrumbComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts index 2cea6f65..a33ff528 100644 --- a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts +++ b/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts @@ -21,6 +21,7 @@ describe("BreadcrumbsComponent", () => { }); it("should be created", () => { + console.log("========== [BreadcrumbsComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts index 6f78ed0d..ea215c71 100644 --- a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts +++ b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts @@ -41,6 +41,7 @@ describe("NavHeaderComponent", () => { it("should be created", inject([ LoggerService ], (logger: LoggerService ) => { + console.log("========== [NavHeaderComponent] should be created"); expect(component).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts index b3029da0..26281cc1 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts @@ -26,6 +26,7 @@ describe("VerticalNavComponent", () => { it("should be created", inject([ LoggerService ], (logger: LoggerService ) => { + console.log("========== [VerticalNavComponent] should be created"); expect(component).toBeTruthy(); })); }); diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html index 6cb32c34..ecc9b918 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html @@ -9,7 +9,7 @@

    {{ step1InstructionMessage }}


    - +
    @@ -35,7 +35,11 @@

    {{ step2InstructionMessage }}

    - +
    +
    + +
    +
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index fbef22b2..f0acc9b2 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -47,6 +47,7 @@ describe("AddDataserviceWizardComponent", () => { }); it("should be created", () => { + console.log("========== [AddDataserviceWizardComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 081b0fb9..c20c5b06 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -31,6 +31,7 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { Table } from "@dataservices/shared/table.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { VdbService } from "@dataservices/shared/vdb.service"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; @@ -368,18 +369,13 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { /** * @returns {string} the selected source table names in string form */ - public get dataserviceSourceTables(): string { - let tableStr = "None"; - const tables = this.tableSelector.getSelectedTables(); - if (tables.length > 0) { - tableStr = tables[0].getConnection().getId() + " [" + tables[0].getName() + "]"; - } - if (tables.length === 2) { - tableStr = tableStr + ", " + tables[1].getConnection().getId() + " [" + tables[1].getName() + "]"; - } - return tableStr; + public get dataserviceSourceTables(): Table[] { + return this.tableSelector.getSelectedTables(); } + /** + * Updates the page1 status + */ public updatePage1ValidStatus( ): void { this.step1Config.nextEnabled = this.tableSelector.valid(); this.setNavAway(this.step1Config.nextEnabled); diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index cecda7e4..c616fb1d 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -47,6 +47,7 @@ describe("AddDataserviceComponent", () => { }); it("should be created", () => { + console.log("========== [AddDataserviceComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css index b0ad8ed3..1b182213 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css @@ -2,3 +2,12 @@ padding-left: 0; padding-right: 0; } + +.jdbc-column-title { + height: 30px; + border:1px solid white; + background-color: #cccccc; + padding-top: 5px; + padding-left: 10px; + padding-right: 0; +} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index 3c7be0e2..d8095684 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -26,7 +26,7 @@ - {{row.name}} + {{ row.name }} @@ -37,19 +37,43 @@ -
    - +
    + Table Selection
    -
    +
    + Current Selections +
    +
    + + +
    +
    Non-JDBC Connections are not supported
    -
    +
    Please select a Connection
    + + + +
    +
    + + No tables selected +
    +
    +
    +
    + +
    +
    diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts index 04d53dd7..dc9288ba 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -8,6 +8,11 @@ import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; @@ -20,8 +25,10 @@ describe("ConnectionTableSelectorComponent", () => { imports: [ FormsModule, HttpModule, NgxDatatableModule ], declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ - AppSettingsService, LoggerService, + AppSettingsService, LoggerService, NotifierService, { provide: ConnectionService, useClass: MockConnectionService }, + { provide: DataserviceService, useClass: MockDataserviceService }, + { provide: VdbService, useClass: MockVdbService } ] }) .compileComponents().then(() => { @@ -36,6 +43,7 @@ describe("ConnectionTableSelectorComponent", () => { }); it("should be created", () => { + console.log("========== [ConnectionTableSelectorComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index 15eb264d..2e52aa2d 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -20,6 +20,7 @@ import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { LoggerService } from "@core/logger.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { Table } from "@dataservices/shared/table.model"; import { LoadingState } from "@shared/loading-state.enum"; @@ -31,9 +32,8 @@ import { LoadingState } from "@shared/loading-state.enum"; }) export class ConnectionTableSelectorComponent implements OnInit { - @Output() public tableSelectionChanged: EventEmitter = new EventEmitter(); - @ViewChild(JdbcTableSelectorComponent) public jdbcTableSelector: JdbcTableSelectorComponent; + @Output() public selectedTableListUpdated: EventEmitter = new EventEmitter(); public readonly nameProp = "name"; // must match html template public rows: any[] = []; @@ -48,13 +48,16 @@ export class ConnectionTableSelectorComponent implements OnInit { }; private connectionService: ConnectionService; + private dataserviceService: DataserviceService; private allConnections: Connection[] = []; private selectedConn: Connection; private connectionLoadingState: LoadingState = LoadingState.LOADING; private logger: LoggerService; - constructor( connectionService: ConnectionService, logger: LoggerService ) { + constructor( connectionService: ConnectionService, dataserviceService: DataserviceService, + logger: LoggerService ) { this.connectionService = connectionService; + this.dataserviceService = dataserviceService; this.logger = logger; } @@ -62,6 +65,9 @@ export class ConnectionTableSelectorComponent implements OnInit { * Component initialization */ public ngOnInit(): void { + // clears table selections + this.dataserviceService.clearWizardSelectedTables(); + // Load the connections this.connectionLoadingState = LoadingState.LOADING; const self = this; @@ -87,7 +93,7 @@ export class ConnectionTableSelectorComponent implements OnInit { } // callback from connections table selection - public onSelect( { selected }) { + public onSelect( { selected }): void { // connection is single select so get first element const connectionName = selected[ 0 ][ this.nameProp ]; @@ -180,9 +186,6 @@ export class ConnectionTableSelectorComponent implements OnInit { this.jdbcTableSelector.setConnection(null); } } - - // notify upstream that connection selection has changed - this.tableSelectionChanged.emit(); } /* @@ -193,16 +196,42 @@ export class ConnectionTableSelectorComponent implements OnInit { return this.allConnections; } + /** + * Responds to table added event from the table selector. + * The table is added to the accumulator list. + * @param {Table} addedTable the table to add to the accumulator list + */ + public onTableSelectionAdded(addedTable: Table): void { + this.dataserviceService.addToWizardSelectionTables(addedTable); + this.selectedTableListUpdated.emit(); + } + + /** + * Responds to table remove event from the table selector. + * The table is removed from the accumulator list, if found. + * @param {Table} removedTable the table to remove from the accumulator list + */ + public onTableSelectionRemoved(removedTable: Table): void { + const wasRemoved = this.dataserviceService.removeFromWizardSelectionTables(removedTable); + if (wasRemoved) { + this.selectedTableListUpdated.emit(); + } + } + + /* + * Determine if any tables are currently selected + * @returns {boolean} true if one or more tables are selected + */ + public get hasSelectedTables(): boolean { + return this.getSelectedTables().length > 0; + } + /* * Return all currently selected Tables * @returns {Table[]} the list of selected Tables */ public getSelectedTables(): Table[] { - const selectedTables = []; - if (this.jdbcTableSelector) { - return this.jdbcTableSelector.getSelectedTables(); - } - return selectedTables; + return this.dataserviceService.getWizardSelectedTables(); } // used by table diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts index c701242b..1a89f696 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts @@ -23,6 +23,7 @@ describe("DataservicesCardsComponent", () => { }); it("should be created", () => { + console.log("========== [DataservicesCardsComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts index 8a5fe78e..f56d021e 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts @@ -23,6 +23,7 @@ describe("DataservicesListComponent", () => { }); it("should be created", () => { + console.log("========== [DataservicesListComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index 22c005d2..82f42894 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -51,10 +51,12 @@ describe("DataservicesComponent", () => { })); it("should be created", () => { + console.log("========== [DataservicesComponent] should be created"); expect(component).toBeTruthy(); }); it("should have Dataservices Title", () => { + console.log("========== [DataservicesComponent] should have Dataservices Title"); // query for the title

    by CSS element selector const de = fixture.debugElement.query(By.css("h2")); const el = de.nativeElement; @@ -62,12 +64,14 @@ describe("DataservicesComponent", () => { }); it("should have Toolbar", () => { + console.log("========== [DataservicesComponent] should have Toolbar"); // query for the toolbar by css classname const de = fixture.debugElement.query(By.css(".toolbar-pf")); expect(de).toBeDefined(); }); it("should have Dataservices", () => { + console.log("========== [DataservicesComponent] should have Dataservices"); // Check component object const dataservices = component.allDataservices; expect(dataservices.length).toEqual(3); @@ -79,6 +83,7 @@ describe("DataservicesComponent", () => { }); it("should have initial card layout", () => { + console.log("========== [DataservicesComponent] should have initial card layout"); // app-dataservices-cards should be present let debugEl = fixture.debugElement.query(By.css("app-dataservices-cards")); const element = debugEl.nativeElement; @@ -90,6 +95,7 @@ describe("DataservicesComponent", () => { }); it("should toggle layout", () => { + console.log("========== [DataservicesComponent] should toggle layout"); // Initial layout should be Card Layout let cardDebugElem = fixture.debugElement.query(By.css("app-dataservices-cards")); let listDebugElem = fixture.debugElement.query(By.css("app-dataservices-list")); @@ -112,6 +118,7 @@ describe("DataservicesComponent", () => { }); it("should filter dataservices", () => { + console.log("========== [DataservicesComponent] should filter dataservices"); // Expect 3 dataservices initially. let dataservices = component.filteredDataservices; expect(dataservices.length).toEqual(3); diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css index f49ad27c..dbcee4e0 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css @@ -34,10 +34,10 @@ } .jdbc-column-title { - height: 35px; + height: 20px; border:1px solid white; background-color: #cccccc; - padding-top: 7px; + padding-top: 0; padding-left: 10px; padding-right: 0; } diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index b0d2f42d..1938b242 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -1,34 +1,31 @@ -
    +
    Schemas
    -
    +
    Tables
    -
    - Selections -
    -
    +
    -
    +
    Unable to load schema
    -
    +
    No schema available
    -
    +
    -
    +
    -
    +
    Unable to load tables
    -
    +
    No tables available
    -
    +
    - +
    @@ -84,17 +81,3 @@
    - - - -
    -
    - - No tables selected -
    -
    -
    -
    - -
    -
    diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index 18dc91f3..bdd7406c 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -7,6 +7,11 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { JdbcTableSelectorComponent } from "./jdbc-table-selector.component"; describe("JdbcTableSelectorComponent", () => { @@ -18,8 +23,10 @@ describe("JdbcTableSelectorComponent", () => { imports: [ FormsModule, HttpModule ], declarations: [ JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ - AppSettingsService, LoggerService, + AppSettingsService, LoggerService, NotifierService, { provide: ConnectionService, useClass: MockConnectionService }, + { provide: DataserviceService, useClass: MockDataserviceService }, + { provide: VdbService, useClass: MockVdbService }, ] }) .compileComponents().then(() => { @@ -34,6 +41,7 @@ describe("JdbcTableSelectorComponent", () => { }); it("should be created", () => { + console.log("========== [JdbcTableSelectorComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index 20c20343..1bca40ad 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -16,15 +16,16 @@ */ import { Component, OnInit } from "@angular/core"; +import { Input } from "@angular/core"; import { EventEmitter } from "@angular/core"; import { Output } from "@angular/core"; -import { Input } from "@angular/core"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; import { LoggerService } from "@core/logger.service"; import { CatalogSchema } from "@dataservices/shared/catalog-schema.model"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { TableSelector } from "@dataservices/shared/table-selector"; import { Table } from "@dataservices/shared/table.model"; import { LoadingState } from "@shared/loading-state.enum"; @@ -38,18 +39,21 @@ import { LoadingState } from "@shared/loading-state.enum"; export class JdbcTableSelectorComponent implements OnInit, TableSelector { @Input() public connection: Connection; - @Output() public tableSelectionChanged: EventEmitter = new EventEmitter(); + @Output() public tableSelectionAdded: EventEmitter = new EventEmitter
    (); + @Output() public tableSelectionRemoved: EventEmitter
    = new EventEmitter
    (); private connectionService: ConnectionService; + private dataserviceService: DataserviceService; private logger: LoggerService; private schemas: CatalogSchema[] = []; private tables: Table[] = []; - private selectedSchemas: CatalogSchema[] = []; + private currentSchema: CatalogSchema = null; private schemaLoadingState: LoadingState = LoadingState.LOADING; private tableLoadingState: LoadingState = LoadingState.LOADING; - constructor( connectionService: ConnectionService, logger: LoggerService ) { + constructor( connectionService: ConnectionService, dataserviceService: DataserviceService, logger: LoggerService ) { this.connectionService = connectionService; + this.dataserviceService = dataserviceService; this.logger = logger; } @@ -63,10 +67,11 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { * @param {Connection} conn the jdbc connection */ public setConnection(conn: Connection): void { + this.clearSchemas(); + this.clearTables(); if (conn && conn.isJdbc()) { this.connection = conn; // Load the schema info for a connection - this.schemas = []; this.schemaLoadingState = LoadingState.LOADING; const self = this; this.connectionService @@ -82,25 +87,31 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } ); } else { - this.schemas = []; this.schemaLoadingState = LoadingState.LOADING; } } + public clearSchemas(): void { + this.schemas = []; + this.currentSchema = null; + } + + public clearTables(): void { + this.tables = []; + this.tableLoadingState = LoadingState.LOADING; + } + /* * Toggle the schema selection * @param {CatalogSchema} schema the schema that has been selected or deselected */ public toggleSchemaSelected(schema: CatalogSchema): void { if (this.isSchemaSelected(schema)) { - this.selectedSchemas.shift(); + this.currentSchema = null; // Deselection of schema clears tables this.tables = []; - this.selectedTablesChanged(); } else { - // Only allow one item to be selected - this.selectedSchemas.shift(); - this.selectedSchemas.push(schema); + this.currentSchema = schema; const filterInfo = new JdbcTableFilter(); filterInfo.setConnectionName(this.connection.getId()); filterInfo.setCatalogFilter(schema.getCatalogName()); @@ -115,7 +126,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { * @param {CatalogSchema} schema the CatalogSchema to check */ public isSchemaSelected(schema: CatalogSchema): boolean { - return this.selectedSchemas.indexOf(schema) !== -1; + return schema === this.currentSchema; } /* @@ -123,7 +134,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { * @returns {CatalogSchema} the selected schema */ public get selectedSchema( ): CatalogSchema { - return this.selectedSchemas[0]; + return this.currentSchema; } /* @@ -131,7 +142,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { * @returns {CatalogSchema} the selected schema */ public get hasSelectedSchema( ): boolean { - return this.selectedSchemas.length > 0; + return this.currentSchema != null; } /** @@ -231,8 +242,12 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { /* * Handler for changes in table selection */ - public selectedTablesChanged( ): void { - this.tableSelectionChanged.emit(); + public selectedTablesChanged(table: Table): void { + if (table.selected) { + this.tableSelectionAdded.emit(table); + } else { + this.tableSelectionRemoved.emit(table); + } } /* @@ -290,6 +305,8 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { table.setSchemaName(self.selectedSchema.getName()); self.tables.push(table); } + // select any of the tables that are already selected + self.setInitialTableSelections(); self.tableLoadingState = LoadingState.LOADED_VALID; }, (error) => { @@ -299,4 +316,23 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { ); } + private setInitialTableSelections(): void { + for ( const table of this.tables ) { + // const catName = table.getCatalogName(); + const schemaName = table.getSchemaName(); + const tableName = table.getName(); + const connName = table.getConnection().getId(); + for ( const initialTable of this.dataserviceService.getWizardSelectedTables() ) { + // const iCatName = initialTable.getCatalogName(); + const iSchemaName = initialTable.getSchemaName(); + const iTableName = initialTable.getName(); + const iConnName = initialTable.getConnection().getId(); + if (iConnName === connName && iTableName === tableName && iSchemaName === schemaName ) { + table.selected = true; + break; + } + } + } + } + } diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts index c28990f2..be27c518 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts @@ -1,6 +1,6 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { Connection } from "../../connections/shared/connection.model"; +import { Connection } from "@connections/shared/connection.model"; import { Table } from "../shared/table.model"; import { SelectedTableComponent } from "./selected-table.component"; diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts index 83baf9d3..dba7d5c7 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from "@angular/core"; +import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { Table } from "@dataservices/shared/table.model"; @Component({ @@ -9,6 +9,7 @@ import { Table } from "@dataservices/shared/table.model"; export class SelectedTableComponent implements OnInit { @Input() public table: Table; + @Output() public selectionListTableRemoved: EventEmitter
    = new EventEmitter
    (); constructor() { // nothing to do @@ -20,5 +21,6 @@ export class SelectedTableComponent implements OnInit { public onRemove(): void { this.table.selected = false; + this.selectionListTableRemoved.emit(this.table); } } diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index a9ea03e6..d73f8950 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -51,10 +51,12 @@ export class DataserviceService extends ApiService { private http: Http; private notifierService: NotifierService; + private appSettingsService: AppSettingsService; private vdbService: VdbService; private selectedDataservice: Dataservice; private cachedDataserviceStates: Map = new Map(); private updatesSubscription: Subscription; + private wizardSelectedTablesArray: Table[] = []; constructor(http: Http, vdbService: VdbService, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { @@ -62,6 +64,7 @@ export class DataserviceService extends ApiService { this.http = http; this.notifierService = notifierService; this.vdbService = vdbService; + this.appSettingsService = appSettings; // Polls to fire Dataservice state updates every minute this.pollDataserviceStatus(60); } @@ -86,7 +89,7 @@ export class DataserviceService extends ApiService { * Validates the specified data service name. If the name contains valid characters and the name is unique, the * service returns 'null'. Otherwise, a 'string' containing an error message is returned. * - * @param {string} dataserviceName + * @param {string} name the dataservice name * @returns {Observable} */ public isValidName( name: string ): Observable< string > { @@ -372,6 +375,77 @@ export class DataserviceService extends ApiService { }); } + /** + * Get the wizard table selections + * @returns {Table[]} the selections + */ + public getWizardSelectedTables( ): Table[] { + return this.wizardSelectedTablesArray; + } + + /** + * Clears the list of wizard table selections + */ + public clearWizardSelectedTables( ): void { + this.wizardSelectedTablesArray = []; + } + + /** + * Determine if the supplied table is one of the current selections in the wizard + * @param {Table} table the table + */ + public isWizardSelectedTable(table: Table): boolean { + return this.getWizardTableIndex(table) > -1; + } + + /** + * Add a table to the current wizard selections + * @param {Table} tableToAdd table to add + */ + public addToWizardSelectionTables(tableToAdd: Table): void { + if (!this.isWizardSelectedTable(tableToAdd)) { + this.wizardSelectedTablesArray.push(tableToAdd); + } + } + + /** + * Remove a table from the current wizard selections + * @param {Table} tableToRemove + * @returns {boolean} + */ + public removeFromWizardSelectionTables(tableToRemove: Table): boolean { + let wasRemoved = false; + + const index = this.getWizardTableIndex(tableToRemove); + if (index > -1) { + this.wizardSelectedTablesArray.splice(index, 1); + wasRemoved = true; + } + + return wasRemoved; + } + + /** + * Find index of the table in the wizard selected tables list. -1 if not found + * @param {Table} table + * @returns {number} + */ + private getWizardTableIndex(table: Table): number { + // supplied table and connection + const connName = table.getConnection().getId(); + const tableName = table.getName(); + let i = 0; + for (const wizTable of this.wizardSelectedTablesArray) { + const wizTableName = wizTable.getName(); + const wizConnName = wizTable.getConnection().getId(); + if (wizTableName === tableName && wizConnName === connName) { + return i; + } + i++; + } + return -1; + } + /* * Get updates for the provided array of Dataservices and broadcast the map of states * @param {Dataservice[]} services the array of Dataservices diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 794991ec..431e1d86 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -16,7 +16,7 @@ */ import { Injectable } from "@angular/core"; -import { Http } from "@angular/http"; +import { Http, Response } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; @@ -29,6 +29,7 @@ import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; +import { ErrorObservable } from "rxjs/observable/ErrorObservable"; @Injectable() export class MockDataserviceService extends DataserviceService { @@ -104,4 +105,20 @@ export class MockDataserviceService extends DataserviceService { // Nothing to do } + /** + * Query a Dataservice via the komodo rest interface + * @param {string} query the SQL query + * @param {string} dataserviceName the dataservice name + * @param {number} limit the limit for the number of result rows + * @param {number} offset the offset for the result rows + * @returns {Observable} + */ + public queryDataservice(query: string, dataserviceName: string, limit: number, offset: number): Observable { + return Observable.of(); + } + + protected handleError(error: Response): ErrorObservable { + return Observable.throw(error); + } + } diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts index 53d58283..e7d74c3c 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts @@ -41,6 +41,7 @@ describe("SqlControlComponent", () => { }); it("should be created", () => { + console.log("========== [SqlControlComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts index 79f38acc..455c3104 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts @@ -39,6 +39,7 @@ describe("TestDataserviceComponent", () => { }); it("should be created", () => { + console.log("========== [TestDataserviceComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts index 932c770b..9d7dedeb 100644 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts +++ b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts @@ -23,6 +23,7 @@ describe("ConfirmDeleteComponent", () => { }); it("should be created", () => { + console.log("========== [ConfirmDeleteComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/shared/page-error/page-error.component.spec.ts b/ngapp/src/app/shared/page-error/page-error.component.spec.ts index a086b02c..9938b625 100644 --- a/ngapp/src/app/shared/page-error/page-error.component.spec.ts +++ b/ngapp/src/app/shared/page-error/page-error.component.spec.ts @@ -24,6 +24,7 @@ describe("PageErrorComponent", () => { }); it("should be created", () => { + console.log("========== [PageErrorComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts b/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts index 078092d5..f2c135f3 100644 --- a/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts +++ b/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts @@ -21,6 +21,7 @@ describe("PageNotFoundComponent", () => { }); it("should be created", () => { + console.log("========== [PageNotFoundComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/shared/property-form/property-form.component.spec.ts b/ngapp/src/app/shared/property-form/property-form.component.spec.ts index 821dc23a..80233727 100644 --- a/ngapp/src/app/shared/property-form/property-form.component.spec.ts +++ b/ngapp/src/app/shared/property-form/property-form.component.spec.ts @@ -41,6 +41,7 @@ describe("PropertyFormComponent", () => { }); it("should be created", () => { + console.log("========== [PropertyFormComponent] should be created"); expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index 47262e20..bedc1662 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -57,5 +57,6 @@ } .datatable-body-row.active .datatable-row-group { - background-color: #39a5dc !important; + background-color: darkblue !important; + color: white; } From 1962ee65ec8e35dad95e533da7fdcf16ed467b44 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 14 Dec 2017 09:24:50 -0600 Subject: [PATCH 057/205] Connections table in dataservice wizard is not sorting - changed the way the column is defined in the html - minor changes to connections table shell styling --- .../connection-table-selector.component.html | 6 +----- ngapp/src/styles.css | 5 ++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index d8095684..e746124d 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -10,7 +10,6 @@
    - - - Connections - + {{ row.name }} diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index bedc1662..97bb11c4 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -51,7 +51,10 @@ } .datatable-body-cell { - padding: 0.25em; + padding-bottom: 0.25em; + padding-left: 1.0em; + padding-right: 0.25em; + padding-top: 0.25em; border-left: 1px solid #d8d8d8; border-right: 1px solid #d8d8d8; } From a8217bfceb488d97cb2555ad701e23d1d6641a82 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 14 Dec 2017 10:46:50 -0600 Subject: [PATCH 058/205] Minor style updates for wizard --- .../connection-table-selector.component.css | 11 ++++++++++- .../connection-table-selector.component.html | 15 ++++++++------- .../jdbc-table-selector.component.css | 9 +++++++-- .../jdbc-table-selector.component.html | 8 ++++---- .../selected-table/selected-table.component.css | 4 ++-- .../selected-table/selected-table.component.html | 2 +- ngapp/src/styles.css | 4 ++-- 7 files changed, 34 insertions(+), 19 deletions(-) diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css index 1b182213..7cd8bb9d 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css @@ -1,3 +1,8 @@ +.connection-selector-container { + padding-left: 0; + padding-right: 0; +} + .jdbc-selector-container { padding-left: 0; padding-right: 0; @@ -6,8 +11,12 @@ .jdbc-column-title { height: 30px; border:1px solid white; - background-color: #cccccc; + background-color: #bbbbbb; padding-top: 5px; padding-left: 10px; padding-right: 0; } + +.alert-padding { + padding-top: 10px; +} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index e746124d..a7f6602d 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -1,18 +1,19 @@
    -
    +
    +
    Problem Loading Connections!
    -
    +
    -
    +
    Non-JDBC Connections are not supported
    -
    +
    Please select a Connection @@ -61,13 +62,13 @@ -
    +
    No tables selected
    -
    +
    diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css index dbcee4e0..a657958c 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css @@ -28,7 +28,7 @@ } .jdbc-list .list-group-item.active { - background-color: darkblue; + background-color: #0088ce; color: white; border-color: transparent; } @@ -36,7 +36,7 @@ .jdbc-column-title { height: 20px; border:1px solid white; - background-color: #cccccc; + background-color: #dddddd; padding-top: 0; padding-left: 10px; padding-right: 0; @@ -53,3 +53,8 @@ .oddRow { background-color: white; } + +.alert-padding { + padding-top: 10px; +} + diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index 1938b242..173f6d8a 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -13,13 +13,13 @@
    -
    +
    Unable to load schema
    -
    +
    No schema available @@ -49,13 +49,13 @@
    -
    +
    Unable to load tables
    -
    +
    No tables available diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.css b/ngapp/src/app/dataservices/selected-table/selected-table.component.css index d2b84ec2..7b9de951 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.css +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.css @@ -1,8 +1,8 @@ .selected-table-card { - background-color: #f2f2f2; + background-color: #def3ff; border:2px dotted darkblue; margin-top: 5px; - margin-left: 15px; + margin-left: 0; min-height: 60px; max-height: 80px; padding-top: 5px; diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.html b/ngapp/src/app/dataservices/selected-table/selected-table.component.html index 28e263d5..78abdcf0 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.html +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.html @@ -1,4 +1,4 @@ -
    +
    {{ table.getConnection().getId() }}
    diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index 97bb11c4..238cafe2 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -15,7 +15,7 @@ .datatable-header { color: white; - background-color: #cccccc; + background-color: #bbbbbb; text-align: center; } @@ -60,6 +60,6 @@ } .datatable-body-row.active .datatable-row-group { - background-color: darkblue !important; + background-color: #0088ce !important; color: white; } From da290cc9adb3987024d6ba386ab1c9c208ce3329 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 14 Dec 2017 16:19:14 -0600 Subject: [PATCH 059/205] Refactors Wizard functions into WizardService --- .../add-dataservice-wizard.component.spec.ts | 3 +- .../add-dataservice.component.spec.ts | 3 +- ...onnection-table-selector.component.spec.ts | 6 +- .../connection-table-selector.component.ts | 16 ++-- .../dataservices-cards.component.html | 3 +- .../dataservices-list.component.css | 6 ++ .../dataservices-list.component.html | 3 +- .../app/dataservices/dataservices.module.ts | 4 +- .../jdbc-table-selector.component.spec.ts | 6 +- .../jdbc-table-selector.component.ts | 12 +-- .../shared/dataservice.service.ts | 72 ---------------- .../shared/wizard.service.spec.ts | 15 ++++ .../app/dataservices/shared/wizard.service.ts | 84 +++++++++++++++++++ 13 files changed, 134 insertions(+), 99 deletions(-) create mode 100644 ngapp/src/app/dataservices/shared/wizard.service.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/wizard.service.ts diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index f0acc9b2..6c3b2d68 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -13,6 +13,7 @@ import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.se import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { WizardService } from "@dataservices/shared/wizard.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; @@ -29,7 +30,7 @@ describe("AddDataserviceWizardComponent", () => { declarations: [ AddDataserviceWizardComponent, ConnectionTableSelectorComponent, JdbcTableSelectorComponent, PropertyFormComponent, PropertyFormPropertyComponent, SelectedTableComponent ], providers: [ - NotifierService, + NotifierService, WizardService, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: ConnectionService, useClass: MockConnectionService }, { provide: VdbService, useClass: MockVdbService }, diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index c616fb1d..5d64a3d4 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -14,6 +14,7 @@ import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.se import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { WizardService } from "@dataservices/shared/wizard.service"; import { SharedModule } from "@shared/shared.module"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -29,7 +30,7 @@ describe("AddDataserviceComponent", () => { declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent, ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ - NotifierService, + NotifierService, WizardService, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: ConnectionService, useClass: MockConnectionService }, { provide: VdbService, useClass: MockVdbService } diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts index dc9288ba..75233b4d 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -8,11 +8,10 @@ import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { WizardService } from "@dataservices/shared/wizard.service"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; @@ -25,9 +24,8 @@ describe("ConnectionTableSelectorComponent", () => { imports: [ FormsModule, HttpModule, NgxDatatableModule ], declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ - AppSettingsService, LoggerService, NotifierService, + AppSettingsService, LoggerService, NotifierService, WizardService, { provide: ConnectionService, useClass: MockConnectionService }, - { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } ] }) diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index 2e52aa2d..7fec2393 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -20,8 +20,8 @@ import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { LoggerService } from "@core/logger.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { Table } from "@dataservices/shared/table.model"; +import { WizardService } from "@dataservices/shared/wizard.service"; import { LoadingState } from "@shared/loading-state.enum"; @Component({ @@ -48,16 +48,16 @@ export class ConnectionTableSelectorComponent implements OnInit { }; private connectionService: ConnectionService; - private dataserviceService: DataserviceService; + private wizardService: WizardService; private allConnections: Connection[] = []; private selectedConn: Connection; private connectionLoadingState: LoadingState = LoadingState.LOADING; private logger: LoggerService; - constructor( connectionService: ConnectionService, dataserviceService: DataserviceService, + constructor( connectionService: ConnectionService, wizardService: WizardService, logger: LoggerService ) { this.connectionService = connectionService; - this.dataserviceService = dataserviceService; + this.wizardService = wizardService; this.logger = logger; } @@ -66,7 +66,7 @@ export class ConnectionTableSelectorComponent implements OnInit { */ public ngOnInit(): void { // clears table selections - this.dataserviceService.clearWizardSelectedTables(); + this.wizardService.clearWizardSelectedTables(); // Load the connections this.connectionLoadingState = LoadingState.LOADING; @@ -202,7 +202,7 @@ export class ConnectionTableSelectorComponent implements OnInit { * @param {Table} addedTable the table to add to the accumulator list */ public onTableSelectionAdded(addedTable: Table): void { - this.dataserviceService.addToWizardSelectionTables(addedTable); + this.wizardService.addToWizardSelectionTables(addedTable); this.selectedTableListUpdated.emit(); } @@ -212,7 +212,7 @@ export class ConnectionTableSelectorComponent implements OnInit { * @param {Table} removedTable the table to remove from the accumulator list */ public onTableSelectionRemoved(removedTable: Table): void { - const wasRemoved = this.dataserviceService.removeFromWizardSelectionTables(removedTable); + const wasRemoved = this.wizardService.removeFromWizardSelectionTables(removedTable); if (wasRemoved) { this.selectedTableListUpdated.emit(); } @@ -231,7 +231,7 @@ export class ConnectionTableSelectorComponent implements OnInit { * @returns {Table[]} the list of selected Tables */ public getSelectedTables(): Table[] { - return this.dataserviceService.getWizardSelectedTables(); + return this.wizardService.getWizardSelectedTables(); } // used by table diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html index c313f96c..abbb8c05 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html @@ -23,7 +23,8 @@


    - + +
    {{ dataservice.getDescription() }} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css index be51e979..3294415c 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css @@ -9,6 +9,12 @@ cursor: pointer; } +.dataservice-list-quicklook-disabled-icon { + margin-left: 20px; + font-size: 1.3em; + color: lightgray; +} + .list-view-pf-main-info { padding-bottom: 5px; padding-top: 5px; diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index 68758dec..63c8249a 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -25,7 +25,8 @@ {{dataservice.getServiceViewTables()[0]}}, {{dataservice.getServiceViewTables()[1]}}
    - + +
    -

    Creation in progress

    -

    The dataservice is being created.

    +

    {{ finalPageTitle }}

    +

    {{ finalPageMessage }}

    -

    Creation was successful

    -

    The dataservice was created successfully. Click on the button to see all dataservices.

    +

    {{ finalPageTitle }}

    +

    {{ finalPageMessage }}

    -

    Creation failed

    +

    {{ finalPageTitle }}

    - The dataservice creation failed! + {{ finalPageMessage }}
    {{ errorDetails }}
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index c20c5b06..a54e1a9b 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -35,6 +35,7 @@ import { Table } from "@dataservices/shared/table.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { VdbService } from "@dataservices/shared/vdb.service"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; +import { WizardService } from "@dataservices/shared/wizard.service"; import { LoadingState } from "@shared/loading-state.enum"; import { WizardComponent } from "patternfly-ng"; import { WizardEvent } from "patternfly-ng"; @@ -75,17 +76,21 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { private dataserviceService: DataserviceService; private notifierService: NotifierService; private vdbService: VdbService; + private wizardService: WizardService; private logger: LoggerService; private router: Router; private deploymentChangeSubscription: Subscription; private sourceVdbUnderDeployment: string; private errorDetailMessage: string; + private theFinalPageTitle = ""; + private theFinalPageMessage = ""; - constructor(router: Router, dataserviceService: DataserviceService, + constructor(router: Router, dataserviceService: DataserviceService, wizardService: WizardService, notifierService: NotifierService, logger: LoggerService, vdbService: VdbService ) { this.dataserviceService = dataserviceService; this.notifierService = notifierService; this.vdbService = vdbService; + this.wizardService = wizardService; this.router = router; this.logger = logger; @@ -113,7 +118,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.step2Config = { id: "step2", priority: 0, - title: "Review and Create", + title: this.step2Title, allowClickNav: false } as WizardStepConfig; this.step2aConfig = { @@ -125,20 +130,32 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.step2bConfig = { id: "step2b", priority: 1, - title: "Create", + title: this.step2bTitle, allowClickNav: false } as WizardStepConfig; // Wizard Configuration this.wizardConfig = { embedInPage: true, - loadingTitle: "Add Dataservice Wizard loading", + loadingTitle: "Dataservice Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", - title: "Add Dataservice", + title: "Dataservice Wizard", contentHeight: "500px", done: false } as WizardConfig; + if (this.wizardService.isEdit()) { + const selectedService = this.dataserviceService.getSelectedDataservice(); + const dsName = selectedService.getId(); + const dsDescr = selectedService.getDescription(); + this.basicPropertyForm.controls["name"].setValue(dsName); + this.basicPropertyForm.controls["description"].setValue(dsDescr); + this.basicPropertyForm.get("name").disable(); + this.basicPropertyForm.get("description").disable(); + } else { + this.basicPropertyForm.controls["name"].setValue(null); + this.basicPropertyForm.controls["description"].setValue(null); + } this.tableSelectorLoadingState = LoadingState.LOADING; this.setNavAway(false); } @@ -151,6 +168,13 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { // Public Methods // ---------------- + /** + * Determine if Dataservice is being edited. + */ + public get isEdit( ): boolean { + return this.wizardService.isEdit(); + } + /** * Determine if table selector is loading */ @@ -185,6 +209,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } else { // name is valid self.nameValidationError = ""; } + self.updatePage2aValidStatus(); }, ( error ) => { self.logger.error( "[handleNameChanged] Error: %o", error ); @@ -198,6 +223,22 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { return this.nameValidationError == null || this.nameValidationError.length === 0; } + /** + * Gets the Title to be displayed on the final wizard page + * @returns {string} + */ + public get finalPageTitle(): string { + return this.theFinalPageTitle; + } + + /** + * Gets the message to be displayed on the final wizard page + * @returns {string} + */ + public get finalPageMessage(): string { + return this.theFinalPageMessage; + } + /* * Step 1 instruction message */ @@ -210,9 +251,12 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } /* - * Step 3 instruction message + * Step 2 instruction message */ public get step2InstructionMessage(): string { + if (this.wizardService.isEdit()) { + return "Review selections. Click Update to update the Dataservice"; + } return "Review selections and enter a name. Click Create to create the Dataservice"; } @@ -249,13 +293,10 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { * using the currently entered properties */ public createDataservice(): void { - this.createComplete = false; - this.createSuccessful = false; + // Sets page in progress status + this.setFinalPageInProgress(); const sourceVdbName = this.tableSelector.getSelectedTables()[0].getConnection().getId() + VdbsConstants.SOURCE_VDB_SUFFIX; - - this.step2bConfig.nextEnabled = false; - this.step2bConfig.previousEnabled = false; this.sourceVdbUnderDeployment = sourceVdbName; const self = this; @@ -267,20 +308,14 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if (wasSuccess) { self.vdbService.pollForActiveVdb(sourceVdbName, 30, 5); } else { - self.createComplete = true; - self.createSuccessful = false; - self.step2bConfig.nextEnabled = false; - self.step2bConfig.previousEnabled = true; + self.setFinalPageComplete(false); self.sourceVdbUnderDeployment = null; } }, (error) => { self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); self.setErrorDetails(error); - self.createComplete = true; - self.createSuccessful = false; - self.step2bConfig.nextEnabled = false; - self.step2bConfig.previousEnabled = true; + self.setFinalPageComplete(false); self.sourceVdbUnderDeployment = null; } ); @@ -326,12 +361,13 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { const selectedVdbName = selectedConnectionName + VdbsConstants.SOURCE_VDB_SUFFIX; if (selectedVdbName === status.getName()) { if (status.isActive()) { - this.createDataserviceForSingleTable(); + if (this.wizardService.isEdit()) { + this.updateDataserviceForSingleTable(); + } else { + this.createDataserviceForSingleTable(); + } } else if (status.isFailed()) { - this.createComplete = true; - this.createSuccessful = false; - this.step2bConfig.nextEnabled = false; - this.step2bConfig.previousEnabled = true; + this.setFinalPageComplete(false); } } } @@ -343,7 +379,11 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.wizardConfig.nextTitle = "Next >"; } else if ($event.step.config.id === "step2a") { this.updatePage2aValidStatus(); - this.wizardConfig.nextTitle = "Create"; + if (this.wizardService.isEdit()) { + this.wizardConfig.nextTitle = "Update"; + } else { + this.wizardConfig.nextTitle = "Create"; + } } else if ($event.step.config.id === "step2b") { // Note: The next button is not disabled by default when wizard is done this.step2Config.nextEnabled = false; @@ -396,14 +436,21 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { * Create the BasicProperty form (page 1) */ private createBasicPropertyForm(): void { - this.basicPropertyForm = new FormGroup({ - name: new FormControl( "", this.handleNameChanged.bind( this ) ), - description: new FormControl("") - }); - // Responds to basic property changes - updates the page status - this.basicPropertyForm.valueChanges.subscribe((val) => { - this.updatePage2aValidStatus( ); - }); + if (!this.wizardService.isEdit()) { + this.basicPropertyForm = new FormGroup({ + name: new FormControl( "", this.handleNameChanged.bind( this ) ), + description: new FormControl("") + }); + // Responds to basic property changes - updates the page status + this.basicPropertyForm.valueChanges.subscribe((val) => { + this.updatePage2aValidStatus( ); + }); + } else { + this.basicPropertyForm = new FormGroup({ + name: new FormControl( "" ), + description: new FormControl("") + }); + } } private setNavAway(allow: boolean): void { @@ -411,7 +458,14 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } private updatePage2aValidStatus( ): void { - this.step2aConfig.nextEnabled = this.basicPropertyForm.valid; + if (!this.step2aConfig) { + return; + } + if (this.wizardService.isEdit()) { + this.step2aConfig.nextEnabled = true; + } else { + this.step2aConfig.nextEnabled = this.nameValid; + } this.setNavAway(this.step2aConfig.nextEnabled); } @@ -431,30 +485,111 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { .createDataserviceForSingleTable(dataservice, this.tableSelector.getSelectedTables()[0]) .subscribe( (wasSuccess) => { - // Deployment succeeded - wait for source vdb to become active - if (wasSuccess) { - self.createComplete = true; - self.createSuccessful = true; - self.step2bConfig.nextEnabled = false; - this.step2bConfig.previousEnabled = true; - } else { - self.createComplete = true; - self.createSuccessful = false; - self.step2bConfig.nextEnabled = false; - this.step2bConfig.previousEnabled = true; - } + self.setFinalPageComplete(wasSuccess); }, (error) => { self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); self.setErrorDetails(error); - self.createComplete = true; - self.createSuccessful = false; - self.step2bConfig.nextEnabled = false; - this.step2bConfig.previousEnabled = true; + self.setFinalPageComplete(false); } ); } + /** + * Update the selected Dataservice for the selected source table. This is invoked + * only after the source VDB has successfully deployed. + */ + private updateDataserviceForSingleTable(): void { + const dataservice: NewDataservice = new NewDataservice(); + + // Dataservice basic properties from step 1 + dataservice.setId(this.dataserviceName); + dataservice.setDescription(this.dataserviceDescription); + + const self = this; + this.dataserviceService + .updateDataserviceForSingleTable(dataservice, this.tableSelector.getSelectedTables()[0]) + .subscribe( + (wasSuccess) => { + self.setFinalPageComplete(wasSuccess); + }, + (error) => { + self.logger.error("[AddDataserviceWizardComponent] Error: %o", error); + self.setErrorDetails(error); + self.setFinalPageComplete(false); + } + ); + } + + /** + * Step 2 title - changes based on create or edit + * @returns {string} step 2 title + */ + private get step2Title(): string { + if (this.wizardService.isEdit()) { + return "Review and Update"; + } else { + return "Review and Create"; + } + } + + /** + * Step 2b title - changes based on create or edit + * @returns {string} step 2b title + */ + private get step2bTitle(): string { + if (this.wizardService.isEdit()) { + return "Update"; + } else { + return "Create"; + } + } + + /** + * Sets the final page in progress status + */ + private setFinalPageInProgress(): void { + this.createComplete = false; + this.createSuccessful = false; + if (this.wizardService.isEdit()) { + this.theFinalPageTitle = "Update in progress"; + this.theFinalPageMessage = "The dataservice is being updated."; + } else { + this.theFinalPageTitle = "Creation in progress"; + this.theFinalPageMessage = "The dataservice is being created."; + } + this.step2bConfig.nextEnabled = false; + this.step2bConfig.previousEnabled = false; + } + + /** + * Sets the final page completion status + * @param {boolean} wasSuccessful 'true' if the create or update was successful + */ + private setFinalPageComplete(wasSuccessful: boolean): void { + this.createComplete = true; + this.createSuccessful = wasSuccessful; + this.step2bConfig.nextEnabled = false; + this.step2bConfig.previousEnabled = true; + if (wasSuccessful) { + if (this.wizardService.isEdit()) { + this.theFinalPageTitle = "Update was successful"; + this.theFinalPageMessage = "The dataservice was updated successfully. Click on the button to see all dataservices."; + } else { + this.theFinalPageTitle = "Creation was successful"; + this.theFinalPageMessage = "The dataservice was created successfully. Click on the button to see all dataservices."; + } + } else { + if (this.wizardService.isEdit()) { + this.theFinalPageTitle = "Update failed"; + this.theFinalPageMessage = "The dataservice update failed!"; + } else { + this.theFinalPageTitle = "Creation failed"; + this.theFinalPageMessage = "The dataservice creation failed!"; + } + } + } + /** * Sets the error details for the response * @param resp the rest call response diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index a7f6602d..cfd1d2db 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -1,8 +1,8 @@
    -
    +
    -
    +
    Problem Loading Connections! diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index 7fec2393..ba8a4691 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -65,9 +65,6 @@ export class ConnectionTableSelectorComponent implements OnInit { * Component initialization */ public ngOnInit(): void { - // clears table selections - this.wizardService.clearWizardSelectedTables(); - // Load the connections this.connectionLoadingState = LoadingState.LOADING; const self = this; @@ -215,6 +212,7 @@ export class ConnectionTableSelectorComponent implements OnInit { const wasRemoved = this.wizardService.removeFromWizardSelectionTables(removedTable); if (wasRemoved) { this.selectedTableListUpdated.emit(); + this.jdbcTableSelector.deselectTable(removedTable); } } diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html index abbb8c05..ac4abb68 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html @@ -16,6 +16,8 @@

    {{ dataservice.getId() }} + + diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts index 95a7adcc..bc2a5876 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts @@ -35,6 +35,7 @@ export class DataservicesCardsComponent { @Output() public testDataservice: EventEmitter = new EventEmitter(); @Output() public publishDataservice: EventEmitter = new EventEmitter(); @Output() public deleteDataservice: EventEmitter = new EventEmitter(); + @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); /** @@ -72,6 +73,10 @@ export class DataservicesCardsComponent { this.deleteDataservice.emit(dataserviceName); } + public onEditDataservice(dataserviceName: string): void { + this.editDataservice.emit(dataserviceName); + } + public onQuickLookDataservice(dataserviceName: string): void { this.quickLookDataservice.emit(dataserviceName); } diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index 63c8249a..34ca4ea5 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -43,6 +43,8 @@ (click)="onTestDataservice(dataservice.getId())" [disabled]="!dataservice.serviceDeploymentActive">Test +

    diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts index 245b047e..a9cc3bd3 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts @@ -36,6 +36,7 @@ export class DataservicesListComponent { @Output() public testDataservice: EventEmitter = new EventEmitter(); @Output() public publishDataservice: EventEmitter = new EventEmitter(); @Output() public deleteDataservice: EventEmitter = new EventEmitter(); + @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); private router: Router; @@ -75,6 +76,10 @@ export class DataservicesListComponent { this.deleteDataservice.emit(dataserviceName); } + public onEditDataservice(dataserviceName: string): void { + this.editDataservice.emit(dataserviceName); + } + public onQuickLookDataservice(dataserviceName: string): void { this.quickLookDataservice.emit(dataserviceName); } diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index f03297e0..0dfc9be0 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -28,7 +28,7 @@

    Dataservices

    @@ -101,12 +101,12 @@

    diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index 82f42894..18e7dd36 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -13,6 +13,7 @@ import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.se import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { WizardService } from "@dataservices/shared/wizard.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; import { SharedModule } from "@shared/shared.module"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; @@ -32,6 +33,7 @@ describe("DataservicesComponent", () => { providers: [ AppSettingsService, NotifierService, + WizardService, { provide: VdbService, useClass: MockVdbService } ] }); diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 08e3efe4..fa6acfe1 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -17,6 +17,7 @@ import { Component, ViewChild } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; +import { Connection } from "@connections/shared/connection.model"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { ArrayUtils } from "@core/utils/array-utils"; @@ -25,7 +26,10 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; +import { WizardService } from "@dataservices/shared/wizard.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; @@ -43,7 +47,6 @@ import { Subscription } from "rxjs/Subscription"; }) export class DataservicesComponent extends AbstractPageComponent { - public readonly addDataserviceLink: string = DataservicesConstants.addDataservicePath; public readonly exportInProgressHeader: string = "Publishing: "; public readonly exportSuccessHeader: string = "Publish Succeeded: "; public readonly exportFailedHeader: string = "Publish Failed: "; @@ -69,12 +72,13 @@ export class DataservicesComponent extends AbstractPageComponent { private exportNotificationVisible = false; private dataserviceStateSubscription: Subscription; private notifierService: NotifierService; + private wizardService: WizardService; @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; @ViewChild(SqlControlComponent) private sqlControlComponent: SqlControlComponent; constructor(router: Router, route: ActivatedRoute, dataserviceService: DataserviceService, - logger: LoggerService, appSettingsService: AppSettingsService, + logger: LoggerService, appSettingsService: AppSettingsService, wizardService: WizardService, notifierService: NotifierService, vdbService: VdbService ) { super(route, logger); this.router = router; @@ -82,6 +86,7 @@ export class DataservicesComponent extends AbstractPageComponent { this.dataserviceService = dataserviceService; this.vdbService = vdbService; this.notifierService = notifierService; + this.wizardService = wizardService; // Register for dataservice state changes this.dataserviceStateSubscription = this.notifierService.getDataserviceStateMap().subscribe((serviceStateMap) => { this.onDataserviceStateChanged(serviceStateMap); @@ -267,6 +272,10 @@ export class DataservicesComponent extends AbstractPageComponent { ); } + /** + * Handle Delete of the specified Dataservice + * @param {string} svcName + */ public onDelete(svcName: string): void { this.setQuickLookPanelOpenState(false); @@ -274,6 +283,54 @@ export class DataservicesComponent extends AbstractPageComponent { this.confirmDeleteDialog.open(); } + /** + * Handle request for new Dataservice + */ + public onNew(): void { + this.wizardService.setEdit(false); + this.wizardService.clearWizardSelectedTables(); + + const link: string[] = [ DataservicesConstants.addDataservicePath ]; + this.logger.log("[DataservicesPageComponent] Navigating to: %o", link); + this.router.navigate(link).then(() => { + // nothing to do + }); + } + + /** + * Handle Edit of the specified Dataservice + * @param {string} svcName + */ + public onEdit(svcName: string): void { + const selectedService = this.filterDataservices().find((x) => x.getId() === svcName); + this.dataserviceService.setSelectedDataservice(selectedService); + + this.setQuickLookPanelOpenState(false); + + // Initialize the selected tables in the wizard service + this.wizardService.clearWizardSelectedTables(); + const srcTables: string[] = selectedService.getServiceViewTables(); + const selectedTables: Table[] = []; + for ( const tableStr of srcTables ) { + const subParts = tableStr.split("."); + const connectionName = subParts[0].replace(VdbsConstants.SOURCE_VDB_SUFFIX, ""); + const tableName = subParts[1]; + const conn: Connection = new Connection(); + conn.setId(connectionName); + const table: Table = new Table(); + table.setName(tableName); + table.setConnection(conn); + this.wizardService.addToWizardSelectionTables(table); + this.wizardService.setEdit(true); + } + + const link: string[] = [ DataservicesConstants.addDataservicePath ]; + this.logger.log("[DataservicesPageComponent] Navigating to: %o", link); + this.router.navigate(link).then(() => { + // nothing to do + }); + } + /* * Handle showing the QuickLook panel for the specified Dataservice */ diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index f0ac6396..d11a0864 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -250,6 +250,23 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } } + /** + * Deselects the table if one with a matching name and connection is currently selected + * @param {Table} table + */ + public deselectTable(table: Table): void { + const connName = table.getConnection().getId(); + const tableName = table.getName(); + for (const theTable of this.tables) { + const theConnName = theTable.getConnection().getId(); + const theTableName = theTable.getName(); + if (theConnName === connName && theTableName === tableName) { + theTable.selected = false; + break; + } + } + } + /* * Builds the array of CatalogSchema items from the SchemaInfo coming from * the Komodo rest call @@ -319,15 +336,15 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { private setInitialTableSelections(): void { for ( const table of this.tables ) { // const catName = table.getCatalogName(); - const schemaName = table.getSchemaName(); + // const schemaName = table.getSchemaName(); const tableName = table.getName(); const connName = table.getConnection().getId(); for ( const initialTable of this.wizardService.getWizardSelectedTables() ) { // const iCatName = initialTable.getCatalogName(); - const iSchemaName = initialTable.getSchemaName(); + // const iSchemaName = initialTable.getSchemaName(); const iTableName = initialTable.getName(); const iConnName = initialTable.getConnection().getId(); - if (iConnName === connName && iTableName === tableName && iSchemaName === schemaName ) { + if (iConnName === connName && iTableName === tableName ) { table.selected = true; break; } diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 4201f28c..35b396f2 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -274,6 +274,18 @@ export class DataserviceService extends ApiService { .flatMap((res) => this.vdbService.deleteVdb(sourceVdbName)); } + /** + * Updates a dataservice with single table source. This is simply a create, with the added step of + * deleting the existing workspace dataservice first. + * @param {NewDataservice} dataservice + * @param {Table} sourceTable + * @returns {Observable} + */ + public updateDataserviceForSingleTable(dataservice: NewDataservice, sourceTable: Table): Observable { + return this.deleteDataservice(dataservice.getId()) + .flatMap((res) => this.createDataserviceForSingleTable(dataservice, sourceTable)); + } + /** * Export a dataservice to a git repository * @param {string} dataserviceName the dataservice name diff --git a/ngapp/src/app/dataservices/shared/table-selector.ts b/ngapp/src/app/dataservices/shared/table-selector.ts index 7be5a5cc..105cfea3 100644 --- a/ngapp/src/app/dataservices/shared/table-selector.ts +++ b/ngapp/src/app/dataservices/shared/table-selector.ts @@ -23,22 +23,28 @@ import { Table } from "@dataservices/shared/table.model"; */ export interface TableSelector { - /* + /** * Set the connection for this jdbc table selector * @param {Connection} conn the jdbc connection */ setConnection(conn: Connection): void; - /* + /** * Determine if any tables are currently selected * @returns {boolean} true if one or more tables are selected */ hasSelectedTables( ): boolean; - /* + /** * Get the array of currently selected Tables * @returns {Table[]} the array of selected Tables (never null, but may be empty) */ getSelectedTables(): Table[]; + /** + * Deselect the table if a table with the same name and connection is currently selected. + * @param {Table} table the table to deselect + */ + deselectTable(table: Table): void; + } diff --git a/ngapp/src/app/dataservices/shared/wizard.service.ts b/ngapp/src/app/dataservices/shared/wizard.service.ts index 474b938e..7520d058 100644 --- a/ngapp/src/app/dataservices/shared/wizard.service.ts +++ b/ngapp/src/app/dataservices/shared/wizard.service.ts @@ -5,11 +5,27 @@ import { Table } from "@dataservices/shared/table.model"; export class WizardService { private wizardSelectedTablesArray: Table[] = []; + private edit = false; constructor() { // Nothing to do } + /** + * Sets edit mode + * @param {boolean} isEdit 'true' if editing, 'false' if not. + */ + public setEdit(isEdit: boolean): void { + this.edit = isEdit; + } + + /** + * Gets the edit mode + * @returns {boolean} 'true' if editing, 'false' if not. + */ + public isEdit(): boolean { + return this.edit; + } /** * Get the wizard table selections * @returns {Table[]} the selections diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index 238cafe2..fb7f2e90 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -51,10 +51,7 @@ } .datatable-body-cell { - padding-bottom: 0.25em; - padding-left: 1.0em; - padding-right: 0.25em; - padding-top: 0.25em; + padding: 0.25em 0.25em 0.25em 1.0em; border-left: 1px solid #d8d8d8; border-right: 1px solid #d8d8d8; } From b543c17cf498c1b1cf442497c5438452068b4baf Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 2 Jan 2018 16:30:31 -0600 Subject: [PATCH 061/205] Fixes for service editing --- .../add-dataservice-wizard.component.ts | 50 +++++------------- .../connection-table-selector.component.ts | 33 ++++++++++++ .../dataservices/dataservices.component.ts | 22 ++------ .../app/dataservices/shared/wizard.service.ts | 51 +++++++++++++++++++ 4 files changed, 99 insertions(+), 57 deletions(-) diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index a54e1a9b..cc376a6b 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -59,7 +59,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { public basicPropertyForm: FormGroup; public createComplete = true; public createSuccessful = false; - public tableSelectorLoadingState = LoadingState.LOADING; // Wizard Step 1 public step1Config: WizardStepConfig; @@ -151,12 +150,10 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.basicPropertyForm.controls["name"].setValue(dsName); this.basicPropertyForm.controls["description"].setValue(dsDescr); this.basicPropertyForm.get("name").disable(); - this.basicPropertyForm.get("description").disable(); } else { this.basicPropertyForm.controls["name"].setValue(null); this.basicPropertyForm.controls["description"].setValue(null); } - this.tableSelectorLoadingState = LoadingState.LOADING; this.setNavAway(false); } @@ -175,27 +172,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { return this.wizardService.isEdit(); } - /** - * Determine if table selector is loading - */ - public get tableSelectorLoading( ): boolean { - return this.tableSelectorLoadingState === LoadingState.LOADING; - } - - /** - * Determine if table selector is loaded and valid - */ - public get tableSelectorLoadedValid( ): boolean { - return this.tableSelectorLoadingState === LoadingState.LOADED_VALID; - } - - /** - * Determine if table selector is loaded and invalid - */ - public get tableSelectorLoadedInvalid( ): boolean { - return this.tableSelectorLoadingState === LoadingState.LOADED_INVALID; - } - public handleNameChanged( input: AbstractControl ): void { const self = this; @@ -356,20 +332,14 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.sourceVdbUnderDeployment = null; } - if (this.tableSelector && this.tableSelector.hasSelectedConnection()) { - const selectedConnectionName = this.tableSelector.selectedConnection.getId(); - const selectedVdbName = selectedConnectionName + VdbsConstants.SOURCE_VDB_SUFFIX; - if (selectedVdbName === status.getName()) { - if (status.isActive()) { - if (this.wizardService.isEdit()) { - this.updateDataserviceForSingleTable(); - } else { - this.createDataserviceForSingleTable(); - } - } else if (status.isFailed()) { - this.setFinalPageComplete(false); - } + if (status.isActive()) { + if (this.wizardService.isEdit()) { + this.updateDataserviceForSingleTable(); + } else { + this.createDataserviceForSingleTable(); } + } else if (status.isFailed()) { + this.setFinalPageComplete(false); } } @@ -598,7 +568,11 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { // Get the error from the response json this.errorDetailMessage = ""; if (resp) { - this.errorDetailMessage = resp.json().error; + try { + this.errorDetailMessage = resp.json().error; + } catch { + this.errorDetailMessage = resp.text(); + } } // Error visible if message has content if (this.errorDetailMessage.length === 0) { diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index ba8a4691..08e7dfcf 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -21,6 +21,7 @@ import { ConnectionService } from "@connections/shared/connection.service"; import { LoggerService } from "@core/logger.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { Table } from "@dataservices/shared/table.model"; +import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { WizardService } from "@dataservices/shared/wizard.service"; import { LoadingState } from "@shared/loading-state.enum"; @@ -74,6 +75,9 @@ export class ConnectionTableSelectorComponent implements OnInit { (conns) => { self.allConnections = conns; self.connectionLoadingState = LoadingState.LOADED_VALID; + if (self.wizardService.isEdit()) { + self.initEdit(); + } // load table after setting loading state so table has been constructed self.allConnections.forEach( ( connection ) => { @@ -245,4 +249,33 @@ export class ConnectionTableSelectorComponent implements OnInit { }; } + /** + * Initialization for edit mode + */ + private initEdit(): void { + // Updates current connections on wizardService + this.wizardService.setCurrentConnections(this.allConnections); + + // Initialize the selected tables in the wizard service + this.wizardService.clearWizardSelectedTables(); + const srcTables: string[] = this.wizardService.getSelectedDataservice().getServiceViewTables(); + const selectedTables: Table[] = []; + for ( const tableStr of srcTables ) { + const subParts = tableStr.split("."); + const connectionName = subParts[0].replace(VdbsConstants.SOURCE_VDB_SUFFIX, ""); + const tableName = subParts[1]; + let conn = this.wizardService.getCurrentConnection(connectionName); + if (!conn) { + conn = new Connection(); + conn.setId(connectionName); + } + const table: Table = new Table(); + table.setName(tableName); + table.setConnection(conn); + this.wizardService.addToWizardSelectionTables(table); + } + this.selectedTableListUpdated.emit(); + + } + } diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index fa6acfe1..76976e10 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -17,7 +17,6 @@ import { Component, ViewChild } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; -import { Connection } from "@connections/shared/connection.model"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { ArrayUtils } from "@core/utils/array-utils"; @@ -26,9 +25,7 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; import { NotifierService } from "@dataservices/shared/notifier.service"; -import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; -import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; import { AbstractPageComponent } from "@shared/abstract-page.component"; @@ -307,22 +304,9 @@ export class DataservicesComponent extends AbstractPageComponent { this.setQuickLookPanelOpenState(false); - // Initialize the selected tables in the wizard service - this.wizardService.clearWizardSelectedTables(); - const srcTables: string[] = selectedService.getServiceViewTables(); - const selectedTables: Table[] = []; - for ( const tableStr of srcTables ) { - const subParts = tableStr.split("."); - const connectionName = subParts[0].replace(VdbsConstants.SOURCE_VDB_SUFFIX, ""); - const tableName = subParts[1]; - const conn: Connection = new Connection(); - conn.setId(connectionName); - const table: Table = new Table(); - table.setName(tableName); - table.setConnection(conn); - this.wizardService.addToWizardSelectionTables(table); - this.wizardService.setEdit(true); - } + // Sets the selected dataservice and edit mode before transferring + this.wizardService.setSelectedDataservice(selectedService); + this.wizardService.setEdit(true); const link: string[] = [ DataservicesConstants.addDataservicePath ]; this.logger.log("[DataservicesPageComponent] Navigating to: %o", link); diff --git a/ngapp/src/app/dataservices/shared/wizard.service.ts b/ngapp/src/app/dataservices/shared/wizard.service.ts index 7520d058..cde3c605 100644 --- a/ngapp/src/app/dataservices/shared/wizard.service.ts +++ b/ngapp/src/app/dataservices/shared/wizard.service.ts @@ -1,4 +1,6 @@ import { Injectable } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; import { Table } from "@dataservices/shared/table.model"; @Injectable() @@ -6,6 +8,8 @@ export class WizardService { private wizardSelectedTablesArray: Table[] = []; private edit = false; + private currentConnections: Connection[] = []; + private selectedDataservice: Dataservice; constructor() { // Nothing to do @@ -26,6 +30,23 @@ export class WizardService { public isEdit(): boolean { return this.edit; } + + /** + * Gets the selected dataservice + * @returns {Dataservice} the selected dataservice + */ + public getSelectedDataservice(): Dataservice { + return this.selectedDataservice; + } + + /** + * Sets the selected dataservice + * @param {Dataservice} dataservice the selected dataservice + */ + public setSelectedDataservice(dataservice: Dataservice): void { + this.selectedDataservice = dataservice; + } + /** * Get the wizard table selections * @returns {Table[]} the selections @@ -76,6 +97,36 @@ export class WizardService { return wasRemoved; } + /** + * Set the current connections to the supplied array + * @param {Connection[]} conns the current array of Connections + */ + public setCurrentConnections(conns: Connection[]): void { + this.currentConnections = conns; + } + + /** + * Get the current connections array + * @returns {Connection[]} the current connections + */ + public getCurrentConnections( ): Connection[] { + return this.currentConnections; + } + + /** + * Get the current connection with the supplied name. If not found, returns null. + * @returns {Connection} the current connection + */ + public getCurrentConnection(connName: string): Connection { + // No connections, return null + if (!this.currentConnections || this.currentConnections.length === 0) { + return null; + } + + // Returns the matching connection, if found. + return this.currentConnections.find((x) => x.getId() === connName); + } + /** * Find index of the table in the wizard selected tables list. -1 if not found * @param {Table} table From 1ec832bf749f12dd248668c7082e7e31f62c52ce Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 4 Jan 2018 08:22:20 -0600 Subject: [PATCH 062/205] Convert schemas list and tables list in data service wizard to be data tables - converted schemas list to be an ngx-datatable - converted tables list to be an ngx-datatable - in connections table, now using JSON response objects as table row data instead of creating new row objects --- .../connection-table-selector.component.html | 9 +- .../connection-table-selector.component.ts | 34 ++--- .../jdbc-table-selector.component.html | 89 +++++++------ .../jdbc-table-selector.component.spec.ts | 3 +- .../jdbc-table-selector.component.ts | 122 ++++++++++++++---- 5 files changed, 164 insertions(+), 93 deletions(-) diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index cfd1d2db..6d4ab2d3 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -9,9 +9,8 @@
    - - + - {{ row.name }} + {{ row.keng__id }} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index 08e7dfcf..06319ad0 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -36,9 +36,6 @@ export class ConnectionTableSelectorComponent implements OnInit { @ViewChild(JdbcTableSelectorComponent) public jdbcTableSelector: JdbcTableSelectorComponent; @Output() public selectedTableListUpdated: EventEmitter = new EventEmitter(); - public readonly nameProp = "name"; // must match html template - public rows: any[] = []; - public readonly customClasses = { sortAscending: "fa fa-sort-asc", sortDescending: "fa fa-sort-desc", @@ -78,13 +75,6 @@ export class ConnectionTableSelectorComponent implements OnInit { if (self.wizardService.isEdit()) { self.initEdit(); } - - // load table after setting loading state so table has been constructed - self.allConnections.forEach( ( connection ) => { - const row = {}; - row[ this.nameProp ] = connection.getId(); - self.rows.push( row ); - } ); }, (error) => { self.logger.error("[ConnectionTableSelectorComponent] Error getting connections: %o", error); @@ -93,13 +83,19 @@ export class ConnectionTableSelectorComponent implements OnInit { ); } - // callback from connections table selection - public onSelect( { selected }): void { - // connection is single select so get first element - const connectionName = selected[ 0 ][ this.nameProp ]; + // callback from connection table selection + public onSelect( { selected } ): void { + // connection table is single select so use first element + const conn: Connection = selected[ 0 ]; - // find and set selected connection (see setter) - this.selectedConnection = this.allConnections.find(( conn ) => conn.getId() === connectionName ); + // only set if schema selection has changed (see setter) + if ( this.hasSelectedConnection() ) { + if ( this.selectedConn.getId() !== conn.getId() ) { + this.selectedConnection = conn; + } + } else { + this.selectedConnection = conn; + } } /** @@ -161,7 +157,7 @@ export class ConnectionTableSelectorComponent implements OnInit { * @returns {boolean} true if a connection is selected */ public hasSelectedConnection( ): boolean { - return this.selectedConn !== null; + return this.selectedConn != null; } /** @@ -236,8 +232,7 @@ export class ConnectionTableSelectorComponent implements OnInit { return this.wizardService.getWizardSelectedTables(); } - // used by table - public get tableMessages(): { emptyMessage: string; totalMessage: string | string } { + public get connectionsTableMessages(): { emptyMessage: string; totalMessage: string | string } { const msg = this.allConnections.length === 1 ? "connection" : "connections"; return { @@ -259,7 +254,6 @@ export class ConnectionTableSelectorComponent implements OnInit { // Initialize the selected tables in the wizard service this.wizardService.clearWizardSelectedTables(); const srcTables: string[] = this.wizardService.getSelectedDataservice().getServiceViewTables(); - const selectedTables: Table[] = []; for ( const tableStr of srcTables ) { const subParts = tableStr.split("."); const connectionName = subParts[0].replace(VdbsConstants.SOURCE_VDB_SUFFIX, ""); diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index 173f6d8a..ae676ca0 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -1,13 +1,4 @@ - - -
    - Schemas -
    -
    - Tables -
    -
    @@ -26,22 +17,28 @@
    -
    -
    -
    -
    -
    -
    - {{ schema.getDisplayName() }} -
    -
    -
    -
    -
    -
    + + + + {{ row.getDisplayName() }} + + +
    @@ -62,22 +59,28 @@
    -
    -
    -
    - -
    -
    -
    -
    -
    - {{ table.getName() }} -
    -
    -
    -
    -
    -
    + + + + Tables + + + {{ row.name }} + + +
    diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index 81636530..9fa5f2c7 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -11,6 +11,7 @@ import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; +import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { JdbcTableSelectorComponent } from "./jdbc-table-selector.component"; describe("JdbcTableSelectorComponent", () => { @@ -19,7 +20,7 @@ describe("JdbcTableSelectorComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule ], + imports: [ FormsModule, HttpModule, NgxDatatableModule ], declarations: [ JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ AppSettingsService, LoggerService, NotifierService, WizardService, diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index d11a0864..e2d0231e 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -42,6 +42,17 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { @Output() public tableSelectionAdded: EventEmitter
    = new EventEmitter
    (); @Output() public tableSelectionRemoved: EventEmitter
    = new EventEmitter
    (); + public selectedAllRows = false; + + public readonly customClasses = { + sortAscending: "fa fa-sort-asc", + sortDescending: "fa fa-sort-desc", + pagerLeftArrow: "fa fa-chevron-left", + pagerRightArrow: "fa fa-chevron-right", + pagerPrevious: "fa fa-step-backward", + pagerNext: "fa fa-step-forward" + }; + private connectionService: ConnectionService; private wizardService: WizardService; private logger: LoggerService; @@ -101,23 +112,18 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { this.tableLoadingState = LoadingState.LOADING; } - /* - * Toggle the schema selection - * @param {CatalogSchema} schema the schema that has been selected or deselected - */ - public toggleSchemaSelected(schema: CatalogSchema): void { - if (this.isSchemaSelected(schema)) { - this.currentSchema = null; - // Deselection of schema clears tables - this.tables = []; + // callback from schema selection in datatable + public onSchemaSelect( { selected }): void { + // schema table is single select so use first element + const schema: CatalogSchema = selected[ 0 ]; + + // only set if schema selection has changed (see setter) + if ( this.hasSelectedSchema ) { + if ( this.selectedSchema.getDisplayName() !== schema.getDisplayName() ) { + this.selectedSchema = schema; + } } else { - this.currentSchema = schema; - const filterInfo = new JdbcTableFilter(); - filterInfo.setConnectionName(this.connection.getId()); - filterInfo.setCatalogFilter(schema.getCatalogName()); - filterInfo.setSchemaFilter(schema.getName()); - filterInfo.setTableFilter("%"); - this.loadTablesForSchema(filterInfo); + this.selectedSchema = schema; } } @@ -137,6 +143,17 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { return this.currentSchema; } + public set selectedSchema( schema: CatalogSchema ) { + this.currentSchema = schema; + + const filterInfo = new JdbcTableFilter(); + filterInfo.setConnectionName(this.connection.getId()); + filterInfo.setCatalogFilter(schema.getCatalogName()); + filterInfo.setSchemaFilter(schema.getName()); + filterInfo.setTableFilter("%"); + this.loadTablesForSchema(filterInfo); + } + /* * Returns the currently selected schema. * @returns {CatalogSchema} the selected schema @@ -173,6 +190,18 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { return this.schemaLoadingState === LoadingState.LOADED_INVALID; } + public get schemaTableMessages(): { emptyMessage: string; totalMessage: string | string } { + const msg = this.schemas.length === 1 ? "schema" : "schemas"; + + return { + // no data message + emptyMessage: "No schemas found", + + // footer total message + totalMessage: msg + }; + } + /* * Get all schemas * @returns {CatalogSchema[]} the array of schema @@ -209,6 +238,18 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { return this.tableLoadingState === LoadingState.LOADED_INVALID; } + public get tableTableMessages(): { emptyMessage: string; totalMessage: string | string } { + const msg = this.tables.length === 1 ? "table" : "tables"; + + return { + // no data message + emptyMessage: "No tables found", + + // footer total message + totalMessage: msg + }; + } + /* * Get all tables * @returns {Table[]} the current tables for the selected schema @@ -222,7 +263,13 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { * @returns {boolean} true if one or more tables are selected */ public hasSelectedTables(): boolean { - return this.getSelectedTables().length > 0; + for ( const table of this.tables ) { + if ( table.selected ) { + return true; + } + } + + return false; } /* @@ -230,23 +277,50 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { * @returns {Table[]} the array of selected Tables */ public getSelectedTables(): Table[] { - const selectedTables = []; - for ( const tbl of this.getTables() ) { - if (tbl.selected) { - selectedTables.push(tbl); + return this.tables.filter( ( table ) => table.selected ); + } + + public selectAllTables(): void { + this.selectedAllRows = !this.selectedAllRows; + const self = this; + + this.tables.forEach( ( table ) => { + if ( table.selected !== self.selectedAllRows ) { + self.selectedTableChanged( table ); } - } - return selectedTables; + } ); } /* * Handler for changes in table selection */ - public selectedTablesChanged(table: Table): void { + public selectedTableChanged(table: Table): void { + table.selected = !table.selected; + if (table.selected) { this.tableSelectionAdded.emit(table); + + // check column header checkbox if all are selected + if ( !this.selectedAllRows ) { + let selectAll = true; + + for ( const tbl of this.tables ) { + if ( !tbl.selected ) { + selectAll = false; + } + } + + if ( selectAll ) { + this.selectedAllRows = true; + } + } } else { this.tableSelectionRemoved.emit(table); + + // uncheck column header checkbox if needed + if ( this.selectedAllRows ) { + this.selectedAllRows = false; + } } } From 4d729f1cd0d940f4f66d87bc35a6ea15b1bf4716 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 4 Jan 2018 15:33:52 -0600 Subject: [PATCH 063/205] Added table column filtering in the data service wizard - connection table can be filtered - schema table can be filtered - table table can be filtered - change table headers to be left aligned --- .../connection-table-selector.component.html | 18 +++- .../connection-table-selector.component.ts | 51 ++++++++-- .../jdbc-table-selector.component.html | 22 ++++- .../jdbc-table-selector.component.ts | 94 ++++++++++++++++--- ngapp/src/styles.css | 2 +- 5 files changed, 161 insertions(+), 26 deletions(-) diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index 6d4ab2d3..ccff95ea 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -9,17 +9,31 @@
    - - + + Connections + + {{ row.keng__id }} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index 06319ad0..63a9ea23 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -38,16 +38,14 @@ export class ConnectionTableSelectorComponent implements OnInit { public readonly customClasses = { sortAscending: "fa fa-sort-asc", - sortDescending: "fa fa-sort-desc", - pagerLeftArrow: "fa fa-chevron-left", - pagerRightArrow: "fa fa-chevron-right", - pagerPrevious: "fa fa-step-backward", - pagerNext: "fa fa-step-forward" + sortDescending: "fa fa-sort-desc" }; private connectionService: ConnectionService; private wizardService: WizardService; private allConnections: Connection[] = []; + private filteredConnections: Connection[] = []; + private connectionFilter = ""; private selectedConn: Connection; private connectionLoadingState: LoadingState = LoadingState.LOADING; private logger: LoggerService; @@ -71,6 +69,7 @@ export class ConnectionTableSelectorComponent implements OnInit { .subscribe( (conns) => { self.allConnections = conns; + self.filteredConnections = conns; self.connectionLoadingState = LoadingState.LOADED_VALID; if (self.wizardService.isEdit()) { self.initEdit(); @@ -233,17 +232,53 @@ export class ConnectionTableSelectorComponent implements OnInit { } public get connectionsTableMessages(): { emptyMessage: string; totalMessage: string | string } { - const msg = this.allConnections.length === 1 ? "connection" : "connections"; + const numAll = this.allConnections.length; + const numFiltered = this.filteredConnections.length; + let msg: string; + + if ( numAll === numFiltered ) { + if ( this.connectionFilter.length === 0 ) { + msg = numAll === 1 ? "connection" : "connections"; + } else { + msg = numAll === 1 ? "matched connection" : "matched connections"; + } + } else { + msg = numFiltered === 1 ? "matched connection" : "matched connections"; + } return { - // no data message - emptyMessage: "No connections found", + // message shows in an empty row in table + emptyMessage: "", // footer total message totalMessage: msg }; } + /** + * Callback when key is pressed in column filter. + */ + public connectionFilterChanged( event: any ): void { + this.connectionFilter = event.target.value; + + if ( this.connectionFilter.length !== 0 ) { + this.connectionFilter = "^" + this.connectionFilter.replace( "*", ".*" ); + } + + this.filteredConnections = this.allConnections.filter( ( connection ) => connection.getId().match( this.connectionFilter ) != null ); + } + + /** + * Called when the table is sorted. + * @param {string} thisName the connection name being sorted + * @param {string} thatName the connection name being compared to + * @returns {number} -1 if less than, 0 if equal, or 1 if greater than + */ + public connectionComparator( thisName: string, + thatName: string ): number { + return thisName.localeCompare( thatName ); + } + /** * Initialization for edit mode */ diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index ae676ca0..8e027193 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -17,23 +17,33 @@
    - + Schemas + + {{ row.getDisplayName() }} @@ -59,24 +69,32 @@
    - Tables + {{ row.name }} diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index e2d0231e..1c92a510 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -46,18 +46,18 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { public readonly customClasses = { sortAscending: "fa fa-sort-asc", - sortDescending: "fa fa-sort-desc", - pagerLeftArrow: "fa fa-chevron-left", - pagerRightArrow: "fa fa-chevron-right", - pagerPrevious: "fa fa-step-backward", - pagerNext: "fa fa-step-forward" + sortDescending: "fa fa-sort-desc" }; private connectionService: ConnectionService; private wizardService: WizardService; private logger: LoggerService; private schemas: CatalogSchema[] = []; + private filteredSchemas: CatalogSchema[] = []; + private schemaFilter = ""; private tables: Table[] = []; + private filteredTables: Table[] = []; + private tableFilter = ""; private currentSchema: CatalogSchema = null; private schemaLoadingState: LoadingState = LoadingState.LOADING; private tableLoadingState: LoadingState = LoadingState.LOADING; @@ -104,11 +104,13 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { public clearSchemas(): void { this.schemas = []; + this.filteredSchemas = []; this.currentSchema = null; } public clearTables(): void { this.tables = []; + this.filteredTables = []; this.tableLoadingState = LoadingState.LOADING; } @@ -190,18 +192,54 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { return this.schemaLoadingState === LoadingState.LOADED_INVALID; } + /** + * Callback when key is pressed in schema column filter. + */ + public schemaFilterChanged( event: any ): void { + this.schemaFilter = event.target.value; + + if ( this.schemaFilter.length !== 0 ) { + this.schemaFilter = "^" + this.schemaFilter.replace( "*", ".*" ); + } + + this.filteredSchemas = this.schemas.filter( ( schema ) => schema.getDisplayName().match( this.schemaFilter ) != null ); + } + public get schemaTableMessages(): { emptyMessage: string; totalMessage: string | string } { - const msg = this.schemas.length === 1 ? "schema" : "schemas"; + const numAll = this.schemas.length; + const numFiltered = this.filteredSchemas.length; + let msg: string; + + if ( numAll === numFiltered ) { + if ( this.schemaFilter.length === 0 ) { + msg = numAll === 1 ? "schema" : "schemas"; + } else { + msg = numAll === 1 ? "matched schema" : "matched schemas"; + } + } else { + msg = numFiltered === 1 ? "matched schema" : "matched schemas"; + } return { - // no data message - emptyMessage: "No schemas found", + // message shows in an empty row in table + emptyMessage: "", // footer total message totalMessage: msg }; } + /** + * Called when the table is sorted. + * @param {string} thisName the name being sorted + * @param {string} thatName the name being compared to + * @returns {number} -1 if less than, 0 if equal, or 1 if greater than + */ + public nameComparator( thisName: string, + thatName: string ): number { + return thisName.localeCompare( thatName ); + } + /* * Get all schemas * @returns {CatalogSchema[]} the array of schema @@ -239,17 +277,42 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } public get tableTableMessages(): { emptyMessage: string; totalMessage: string | string } { - const msg = this.tables.length === 1 ? "table" : "tables"; + const numAll = this.tables.length; + const numFiltered = this.filteredTables.length; + let msg: string; + + if ( numAll === numFiltered ) { + if ( this.tableFilter.length === 0 ) { + msg = numAll === 1 ? "table" : "tables"; + } else { + msg = numAll === 1 ? "matched table" : "matched tables"; + } + } else { + msg = numFiltered === 1 ? "matched table" : "matched tables"; + } return { - // no data message - emptyMessage: "No tables found", + // message shows in an empty row in table + emptyMessage: "", // footer total message totalMessage: msg }; } + /** + * Callback when key is pressed in table column filter. + */ + public tableFilterChanged( event: any ): void { + this.tableFilter = event.target.value; + + if ( this.tableFilter.length !== 0 ) { + this.tableFilter = "^" + this.tableFilter.replace( "*", ".*" ); + } + + this.filteredTables = this.tables.filter( ( table ) => table.getName().match( this.tableFilter ) != null ); + } + /* * Get all tables * @returns {Table[]} the current tables for the selected schema @@ -284,7 +347,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { this.selectedAllRows = !this.selectedAllRows; const self = this; - this.tables.forEach( ( table ) => { + this.filteredTables.forEach( ( table ) => { if ( table.selected !== self.selectedAllRows ) { self.selectedTableChanged( table ); } @@ -304,7 +367,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { if ( !this.selectedAllRows ) { let selectAll = true; - for ( const tbl of this.tables ) { + for ( const tbl of this.filteredTables ) { if ( !tbl.selected ) { selectAll = false; } @@ -359,18 +422,21 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { item.setType("Schema"); item.setCatalogName(infoName); this.schemas.push(item); + this.filteredSchemas.push(item); } } else { const item: CatalogSchema = new CatalogSchema(); item.setName(infoName); item.setType("Catalog"); this.schemas.push(item); + this.filteredSchemas.push(item); } } else if (infoType === "Schema") { const item: CatalogSchema = new CatalogSchema(); item.setName(infoName); item.setType("Schema"); this.schemas.push(item); + this.filteredSchemas.push(item); } } } @@ -382,6 +448,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { private loadTablesForSchema(tableFilter: JdbcTableFilter): void { // Load the table names for the selected Connection and Schema this.tables = []; + this.filteredTables = []; this.tableLoadingState = LoadingState.LOADING; const self = this; this.connectionService @@ -395,6 +462,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { table.setCatalogName(self.selectedSchema.getCatalogName()); table.setSchemaName(self.selectedSchema.getName()); self.tables.push(table); + self.filteredTables.push(table); } // select any of the tables that are already selected self.setInitialTableSelections(); diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index fb7f2e90..a2b591ef 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -16,7 +16,7 @@ .datatable-header { color: white; background-color: #bbbbbb; - text-align: center; + text-align: left; } .datatable-header-cell { From 41be2e11fc3c0833f5bfbcb82da5f747c8d5ca10 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 5 Jan 2018 09:16:44 -0600 Subject: [PATCH 064/205] Updates readmes and minor formatting change --- .../jdbc-table-selector/jdbc-table-selector.component.css | 8 ++++++++ .../jdbc-table-selector.component.html | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css index a657958c..38f859a1 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css @@ -5,6 +5,14 @@ overflow-y: auto; } +.jdbc-table-header { + margin-left: 5px; +} + +.jdbc-table-cell { + margin-left: 5px; +} + .jdbc-list .list-view-pf-main-info { padding-top: 0.5em; padding-bottom: 0.5em; diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index 8e027193..64d36d57 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -89,7 +89,7 @@ [draggable]="false" [resizeable]="false"> - Tables + Tables - {{ row.name }} + {{ row.name }} From 910406b9985161a1425ed8edbf5ef8c1976d8454 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 5 Jan 2018 14:13:20 -0600 Subject: [PATCH 065/205] Remove checkbox from JdbcTableSelectorComponent html templates - removed checkbox from JDBC tables column template - removed checkbox from JDBC tables cell template --- .../jdbc-table-selector.component.html | 14 ++--- .../jdbc-table-selector.component.ts | 60 +++++++------------ 2 files changed, 30 insertions(+), 44 deletions(-) diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index 64d36d57..4e2100a3 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -78,26 +78,26 @@ [columnMode]="'force'" [reorderable]="false" [selectionType]="'checkbox'" + (select)="tableSelectionChanged($event)" [sorts]="[{prop: 'name', dir: 'asc'}]" [cssClasses]="customClasses"> - Tables + Tables - - - {{ row.name }} + style="border:solid 1px #dddddd;padding:8px;margin:0 auto;width:100%;height:24px" + placeholder="Filter tables" + (keyup)="tableFilterChanged($event)"/> diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index 1c92a510..1d51372e 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -343,48 +343,23 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { return this.tables.filter( ( table ) => table.selected ); } - public selectAllTables(): void { - this.selectedAllRows = !this.selectedAllRows; - const self = this; + public tableSelectionChanged( event: any ): void { + const selectedTables = event.selected; + const self = this; + // sync up the UI row selections with the actual table selections this.filteredTables.forEach( ( table ) => { - if ( table.selected !== self.selectedAllRows ) { - self.selectedTableChanged( table ); - } - } ); - } - - /* - * Handler for changes in table selection - */ - public selectedTableChanged(table: Table): void { - table.selected = !table.selected; + if ( ( !table.selected && this.isSelected( selectedTables, table ) ) + || ( table.selected && !this.isSelected( selectedTables, table )) ) { + table.selected = !table.selected; - if (table.selected) { - this.tableSelectionAdded.emit(table); - - // check column header checkbox if all are selected - if ( !this.selectedAllRows ) { - let selectAll = true; - - for ( const tbl of this.filteredTables ) { - if ( !tbl.selected ) { - selectAll = false; - } - } - - if ( selectAll ) { - this.selectedAllRows = true; + if ( table.selected ) { + this.tableSelectionAdded.emit(table); + } else { + this.tableSelectionRemoved.emit(table); } } - } else { - this.tableSelectionRemoved.emit(table); - - // uncheck column header checkbox if needed - if ( this.selectedAllRows ) { - this.selectedAllRows = false; - } - } + } ); } /** @@ -404,6 +379,17 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } } + private isSelected( selectedTables: Table[], + table: Table ): boolean { + for ( const selected of selectedTables ) { + if ( selected.getName() === table.getName() ) { + return true; + } + } + + return false; + } + /* * Builds the array of CatalogSchema items from the SchemaInfo coming from * the Komodo rest call From f8fda6ca24b871f82f33ff90cfdb0a2db519920d Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Wed, 10 Jan 2018 15:41:05 -0600 Subject: [PATCH 066/205] adds support for multiple dataservice views --- .../connection-table-selector.component.html | 2 +- .../dataservices/dataservices.component.css | 6 ++ .../dataservices/dataservices.component.html | 13 ++-- .../dataservices/dataservices.component.ts | 37 ++++++++++- .../shared/dataservice.service.ts | 48 ++++++++++++++ .../shared/mock-dataservice.service.ts | 14 ++++ .../sql-control/sql-control.component.css | 38 ++++++++++- .../sql-control/sql-control.component.html | 32 ++++++++-- .../sql-control/sql-control.component.spec.ts | 11 ++++ .../sql-control/sql-control.component.ts | 64 ++++++++++++------- .../test-dataservice.component.html | 3 +- .../test-dataservice.component.ts | 28 +++++++- 12 files changed, 252 insertions(+), 44 deletions(-) diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index ccff95ea..27a584cd 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -81,7 +81,7 @@ No tables selected
    -
    +
    diff --git a/ngapp/src/app/dataservices/dataservices.component.css b/ngapp/src/app/dataservices/dataservices.component.css index c3b6406a..ef086d0f 100644 --- a/ngapp/src/app/dataservices/dataservices.component.css +++ b/ngapp/src/app/dataservices/dataservices.component.css @@ -95,3 +95,9 @@ a.clear-filters { cursor: pointer; font-size: 1.5em; } + +.quicklook-title { + margin-left: 50px; + font-size: 1.25em; + font-weight: bold; +} diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 0dfc9be0..9454607f 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -112,12 +112,15 @@


    - - - -

    Quick Look Results for Dataservice '{{ quickLookServiceName }}'

    +
    + + + Quick Look Results for Dataservice '{{ quickLookServiceName }}' + +

    - +
    diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 76976e10..9d0ea5a6 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -25,6 +25,7 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; @@ -52,6 +53,7 @@ export class DataservicesComponent extends AbstractPageComponent { private resultsAreaCss = "dataservice-summary-bottom-area-no-results"; private resultsShowing = false; private quickLookSvcName: string; + private quickLookQueryText: string; private allServices: Dataservice[] = []; private filteredServices: Dataservice[] = []; @@ -70,6 +72,8 @@ export class DataservicesComponent extends AbstractPageComponent { private dataserviceStateSubscription: Subscription; private notifierService: NotifierService; private wizardService: WizardService; + private selectedSvcViews: Table[] = []; + private allSvcViews: Table[] = []; @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; @ViewChild(SqlControlComponent) private sqlControlComponent: SqlControlComponent; @@ -186,6 +190,20 @@ export class DataservicesComponent extends AbstractPageComponent { return this.selectedServices; } + /** + * Accessor for all available service views + */ + public get allServiceViews( ): Table[] { + return this.allSvcViews; + } + + /** + * Accessor for selected service view + */ + public get selectedViews( ): Table[] { + return this.selectedSvcViews; + } + /** * @returns {string} the quick look service name */ @@ -193,6 +211,13 @@ export class DataservicesComponent extends AbstractPageComponent { return this.quickLookSvcName; } + /** + * @returns {string} the quick look service name + */ + public get quickLookSql(): string { + return this.quickLookQueryText; + } + public onSelected(dataservice: Dataservice): void { // Only allow one item to be selected this.selectedServices.shift(); @@ -232,6 +257,9 @@ export class DataservicesComponent extends AbstractPageComponent { public onTest(svcName: string): void { const selectedService = this.filterDataservices().find((x) => x.getId() === svcName); this.dataserviceService.setSelectedDataservice(selectedService); + this.allSvcViews = this.dataserviceService.getSelectedDataserviceViews(); + this.selectedSvcViews = []; + this.selectedSvcViews.push(this.allServiceViews[0]); this.setQuickLookPanelOpenState(false); @@ -321,11 +349,18 @@ export class DataservicesComponent extends AbstractPageComponent { public onQuickLook(svcName: string): void { const selectedService = this.filterDataservices().find((x) => x.getId() === svcName); this.dataserviceService.setSelectedDataservice(selectedService); + this.allSvcViews = this.dataserviceService.getSelectedDataserviceViews(); + this.selectedSvcViews = []; + this.selectedSvcViews.push(this.allServiceViews[0]); + const viewName = this.selectedSvcViews[0].getName(); + this.quickLookQueryText = "SELECT * FROM " + viewName + ";"; if (!this.resultsShowing) { this.setQuickLookPanelOpenState(true); } this.setQuickLookResults(svcName); + this.sqlControlComponent.queryText = this.quickLookQueryText; + this.sqlControlComponent.submitCurrentQuery(); } public isFiltered(): boolean { @@ -478,8 +513,6 @@ export class DataservicesComponent extends AbstractPageComponent { */ private setQuickLookResults(svcName): void { this.quickLookSvcName = svcName; - this.sqlControlComponent.initQueryText(); - this.sqlControlComponent.submitCurrentQuery(); } } diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 35b396f2..ec87dbc9 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -54,6 +54,7 @@ export class DataserviceService extends ApiService { private appSettingsService: AppSettingsService; private vdbService: VdbService; private selectedDataservice: Dataservice; + private dataserviceCurrentView: Table[] = []; private cachedDataserviceStates: Map = new Map(); private updatesSubscription: Subscription; @@ -74,6 +75,12 @@ export class DataserviceService extends ApiService { */ public setSelectedDataservice(service: Dataservice): void { this.selectedDataservice = service; + // When the dataservice is selected, init the selected view + const views: Table[] = this.getSelectedDataserviceViews(); + this.dataserviceCurrentView = []; + if (views && views.length > 0) { + this.dataserviceCurrentView.push(views[0]); + } } /** @@ -84,6 +91,47 @@ export class DataserviceService extends ApiService { return this.selectedDataservice; } + /** + * Get the current Dataservice selection's views. The table object is used for the view, + * with the Table name set to the full "modelName"."viewName" of the view. + * @returns {Table[]} the selected Dataservice views + */ + public getSelectedDataserviceViews( ): Table[] { + if (!this.selectedDataservice || this.selectedDataservice === null) { + return []; + } + + const modelName = this.selectedDataservice.getServiceViewModel(); + const serviceView = this.selectedDataservice.getServiceViewName(); + + // TODO: we will need to get multiple views when supported + const view1: Table = new Table(); + view1.setName(modelName + "." + serviceView); + + const allViews: Table[] = []; + allViews.push(view1); + + return allViews; + } + + /** + * Get the current Dataservice current view. The table object is used for the view, + * with the Table name set to the full "modelName"."viewName" of the view. + * @returns {Table[]} the Dataservice current view + */ + public getSelectedDataserviceCurrentView( ): Table[] { + return this.dataserviceCurrentView; + } + + /** + * Set the current Dataservice current view. The table object is used for the view, + * with the Table name set to the full "modelName"."viewName" of the view. + * @param {Table[]} view the current view + */ + public setSelectedDataserviceCurrentView( view: Table[] ): void { + this.dataserviceCurrentView = view; + } + /** * Validates the specified data service name. If the name contains valid characters and the name is unique, the * service returns 'null'. Otherwise, a 'string' containing an error message is returned. diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 431e1d86..80dd4d9b 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -23,6 +23,7 @@ import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; @@ -90,6 +91,19 @@ export class MockDataserviceService extends DataserviceService { return this.serv1; } + /** + * Get the views for the selected Dataservice + * @returns {Table[]} the views + */ + public getSelectedDataserviceViews(): Table[] { + const table: Table = new Table(); + table.setName("views.View1"); + const tables: Table[] = []; + tables.push(table); + + return tables; + } + /** * Updates the current Dataservice states - triggers update to be broadcast to interested components */ diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.css b/ngapp/src/app/dataservices/sql-control/sql-control.component.css index ccdce30c..aea3039b 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.css +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.css @@ -1,6 +1,23 @@ +.view-table-full-div { + padding-left: 0; + padding-right: 10px; + min-height: 240px; + max-height: 240px; + border: 1px inset grey; + overflow-y: auto; +} + +.view-table-quicklook-div { + padding-left: 0; + padding-right: 10px; + min-height: 120px; + max-height: 120px; + border: 1px inset grey; + overflow-y: auto; +} + .sql-control-control-title { - margin: 0.5em; - float: left; + margin: 5px 0 0; color: grey; font-weight: bold; } @@ -10,11 +27,14 @@ } .sql-control-editor { - clear: both; border: 1px inset grey; + margin-left: 15px; + padding-left: 0; } .sql-results-panel { + padding-left: 0; + padding-right: 0; clear: both; border: 1px inset grey; } @@ -30,3 +50,15 @@ .row-number-column { text-align: center; } + +.quicklook-sql-title { + font-size: 1.25em; + font-weight: bold; +} + +.quicklook-sql { + margin-left: 15px; + font-size: 1.15em; + font-weight: bold; + font-style: italic; +} diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.html b/ngapp/src/app/dataservices/sql-control/sql-control.component.html index 5876a8fb..5e65d6e2 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.html +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.html @@ -1,8 +1,27 @@
    -
    -
    Query Editor
    - -
    +
    +
    + + + + +
    +
    +
    + SQL:{{ queryText }} +
    @@ -31,7 +53,7 @@
    - There was an error running the Query! + Error running Query for '{{ viewName }}'
    diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts index e7d74c3c..7a578d9b 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts @@ -8,6 +8,7 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { CodemirrorModule } from "ng2-codemirror"; @@ -37,6 +38,16 @@ describe("SqlControlComponent", () => { beforeEach(() => { fixture = TestBed.createComponent(SqlControlComponent); component = fixture.componentInstance; + + // Set the inputs for the component + component.viewSql = "SELECT * FROM views.View1"; + const table = new Table(); + table.setName("views.View1"); + const tables: Table[] = []; + tables.push(table); + component.serviceViews = tables; + component.selectedViews = tables; + fixture.detectChanges(); }); diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts index 727461a4..6df35721 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts @@ -22,6 +22,7 @@ import { ColumnData } from "@dataservices/shared/column-data.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { QueryResults } from "@dataservices/shared/query-results.model"; import { RowData } from "@dataservices/shared/row-data.model"; +import { Table } from "@dataservices/shared/table.model"; import { LoadingState } from "@shared/loading-state.enum"; import "codemirror/addon/display/placeholder.js"; import "codemirror/addon/selection/active-line.js"; @@ -35,7 +36,10 @@ import "codemirror/mode/sql/sql.js"; }) export class SqlControlComponent implements OnInit { - @Input() public editorVisible = true; + @Input() public quicklook = false; + @Input() public selectedViews: Table[] = []; + @Input() public serviceViews: Table[] = []; + @Input() public viewSql = ""; public columns: any[] = []; public rows: any[] = []; @@ -50,19 +54,16 @@ export class SqlControlComponent implements OnInit { public customClasses = { sortAscending: "fa fa-sort-asc", - sortDescending: "fa fa-sort-desc", - pagerLeftArrow: "fa fa-chevron-left", - pagerRightArrow: "fa fa-chevron-right", - pagerPrevious: "fa fa-step-backward", - pagerNext: "fa fa-step-forward" + sortDescending: "fa fa-sort-desc" }; private dataserviceService: DataserviceService; private logger: LoggerService; private showResults = false; private queryResultsLoading: LoadingState; - private queryTxt: string; private queryResults: QueryResults; + private queryMap: Map = new Map(); + private previousViewName: string; constructor( dataserviceService: DataserviceService, logger: LoggerService ) { this.dataserviceService = dataserviceService; @@ -70,15 +71,29 @@ export class SqlControlComponent implements OnInit { } public ngOnInit(): void { - this.initQueryText(); + this.queryMap.clear(); + this.setQueryText(); + this.queryMap.set(this.viewName, this.queryText); + this.previousViewName = this.viewName; this.submitCurrentQuery(); } /* - * Initialize the query text based on the selected dataservice + * Handle View selection from the view table */ - public initQueryText( ): void { - this.queryTxt = this.getDataserviceInitialQueryText(); + public onViewSelect( {selected} ): void { + // Save query for current selection first + this.queryMap.set(this.previousViewName, this.queryText); + + // View table is single select so use first element + const view: Table = selected[ 0 ]; + + this.selectedViews = []; + this.selectedViews.push(view); + + this.setQueryText(); + this.previousViewName = this.viewName; + this.submitCurrentQuery(); } /* @@ -99,14 +114,14 @@ export class SqlControlComponent implements OnInit { * Get the SQL text */ public get queryText( ): string { - return this.queryTxt; + return this.viewSql; } /** * Set the SQL text */ public set queryText( sql: string ) { - this.queryTxt = sql; + this.viewSql = sql; } /** @@ -130,19 +145,20 @@ export class SqlControlComponent implements OnInit { return ( this.queryResultsLoading != null && (this.queryResultsLoading === LoadingState.LOADED_INVALID) ); } + public get viewName(): string { + return !this.selectedViews ? "" : this.selectedViews[0].getName(); + } + /* - * the selected data service query text - */ - private getDataserviceInitialQueryText(): string { - const dataservice = this.dataserviceService.getSelectedDataservice(); - const modelName = dataservice.getServiceViewModel(); - const serviceView = dataservice.getServiceViewName(); - - if ( !modelName || !serviceView ) { - return "SELECT * FROM "; + * Sets the query text based on the selected dataservice + */ + public setQueryText( ): void { + const mapEntry = this.queryMap.get(this.viewName); + if (mapEntry) { + this.viewSql = mapEntry; + } else { + this.viewSql = "SELECT * FROM " + this.viewName + ";"; } - - return "SELECT * FROM " + modelName + "." + serviceView + ";"; } /* diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html index 4eed23a2..387547e5 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html @@ -24,7 +24,8 @@

    Test Dataservice '{{ this.dataservice.getId() }}'

    - +
    diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts index beac3b60..9e9fa75f 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts @@ -5,6 +5,7 @@ import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; +import { Table } from "@dataservices/shared/table.model"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { LoadingState } from "@shared/loading-state.enum"; @@ -22,6 +23,9 @@ export class TestDataserviceComponent extends AbstractPageComponent { private dataservice: Dataservice; private dataserviceService: DataserviceService; private pageLoadingState: LoadingState = LoadingState.LOADED_VALID; + private selectedSvcViews: Table[] = []; + private allSvcViews: Table[] = []; + private quickLookQueryText: string; constructor( router: Router, route: ActivatedRoute, dataserviceService: DataserviceService, logger: LoggerService ) { super(route, logger); @@ -30,6 +34,11 @@ export class TestDataserviceComponent extends AbstractPageComponent { public loadAsyncPageData(): void { this.dataservice = this.dataserviceService.getSelectedDataservice(); + this.allSvcViews = this.dataserviceService.getSelectedDataserviceViews(); + this.selectedSvcViews = []; + this.selectedSvcViews.push(this.allSvcViews[0]); + const viewName = this.selectedSvcViews[0].getName(); + this.quickLookQueryText = "SELECT * FROM " + viewName + ";"; } /** @@ -47,10 +56,23 @@ export class TestDataserviceComponent extends AbstractPageComponent { } /** - * Determine if page has loaded but was not successful + * Accessor for all available service views */ - public get pageLoadedInvalid( ): boolean { - return this.pageLoadingState === LoadingState.LOADED_INVALID; + public get allServiceViews( ): Table[] { + return this.allSvcViews; } + /** + * Accessor for selected service view + */ + public get selectedViews( ): Table[] { + return this.selectedSvcViews; + } + + /** + * @returns {string} the quick look service name + */ + public get quickLookSql(): string { + return this.quickLookQueryText; + } } From 43639e7073dd278e10cc516f8f564ab997edcd80 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 11 Jan 2018 15:07:37 -0600 Subject: [PATCH 067/205] Changes to selected table card of the data service wizard - selected table cards are now in a scrollable div - selected table card can now be expanded to allow column selection - just using dummy column data currently until design is approved --- .../connection-table-selector.component.css | 7 ++ .../connection-table-selector.component.html | 4 +- .../jdbc-table-selector.component.html | 8 +- .../jdbc-table-selector.component.ts | 50 ++++++++--- .../app/dataservices/selected-table/column.ts | 35 ++++++++ .../selected-table.component.css | 68 +++++++++++--- .../selected-table.component.html | 90 +++++++++++++++++-- .../selected-table.component.ts | 80 ++++++++++++++++- .../app/dataservices/shared/wizard.service.ts | 5 +- 9 files changed, 309 insertions(+), 38 deletions(-) create mode 100644 ngapp/src/app/dataservices/selected-table/column.ts diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css index 7cd8bb9d..f65e3ba5 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css @@ -20,3 +20,10 @@ .alert-padding { padding-top: 10px; } + +.selected-tables-container { + background-color: #bbbbbb; + max-height: 480px; + margin-top: 0px; + overflow-y: auto; +} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index 27a584cd..e466df0b 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -81,8 +81,8 @@ No tables selected
    -
    -
    +
    +
    diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index 4e2100a3..54e8c6e7 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -78,27 +78,27 @@ [columnMode]="'force'" [reorderable]="false" [selectionType]="'checkbox'" - (select)="tableSelectionChanged($event)" [sorts]="[{prop: 'name', dir: 'asc'}]" [cssClasses]="customClasses"> - Tables + Tables + + {{ row.name }} +
    diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index 1d51372e..5ec2f77f 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -343,23 +343,48 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { return this.tables.filter( ( table ) => table.selected ); } - public tableSelectionChanged( event: any ): void { - const selectedTables = event.selected; - const self = this; + public selectAllTables(): void { + this.selectedAllRows = !this.selectedAllRows; + const self = this; - // sync up the UI row selections with the actual table selections this.filteredTables.forEach( ( table ) => { - if ( ( !table.selected && this.isSelected( selectedTables, table ) ) - || ( table.selected && !this.isSelected( selectedTables, table )) ) { - table.selected = !table.selected; + if ( table.selected !== self.selectedAllRows ) { + self.selectedTableChanged( table ); + } + } ); + } - if ( table.selected ) { - this.tableSelectionAdded.emit(table); - } else { - this.tableSelectionRemoved.emit(table); + /* + * Handler for changes in table selection + */ + public selectedTableChanged( table: Table ): void { + table.selected = !table.selected; + + if ( table.selected ) { + this.tableSelectionAdded.emit(table); + + // check column header checkbox if all are selected + if ( !this.selectedAllRows ) { + let selectAll = true; + + for ( const tbl of this.filteredTables ) { + if ( !tbl.selected ) { + selectAll = false; + } + } + + if ( selectAll ) { + this.selectedAllRows = true; } } - } ); + } else { + this.tableSelectionRemoved.emit(table); + + // uncheck column header checkbox if needed + if ( this.selectedAllRows ) { + this.selectedAllRows = false; + } + } } /** @@ -369,6 +394,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { public deselectTable(table: Table): void { const connName = table.getConnection().getId(); const tableName = table.getName(); + for (const theTable of this.tables) { const theConnName = theTable.getConnection().getId(); const theTableName = theTable.getName(); diff --git a/ngapp/src/app/dataservices/selected-table/column.ts b/ngapp/src/app/dataservices/selected-table/column.ts new file mode 100644 index 00000000..1286ecad --- /dev/null +++ b/ngapp/src/app/dataservices/selected-table/column.ts @@ -0,0 +1,35 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class Column { + + public selected = true; + public name: string; + public type: string; + public size: number; + + public constructor( name: string, + selected: boolean, + type: string, + size: number ) { + this.name = name; + this.type = type; + this.selected = selected; + this.size = size; + } + +} diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.css b/ngapp/src/app/dataservices/selected-table/selected-table.component.css index 7b9de951..68add26f 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.css +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.css @@ -1,24 +1,70 @@ -.selected-table-card { +.selected-table-card .card-pf { background-color: #def3ff; - border:2px dotted darkblue; - margin-top: 5px; - margin-left: 0; - min-height: 60px; - max-height: 80px; - padding-top: 5px; - padding-right: 5px; + margin: 0 0px 10px; + min-height: 40px; } -.selected-table-name { - margin-left: 20px; +.selected-table-name:before { + display: inline-block; + margin-bottom: 0px; + margin-right: 10px; + margin-top: 0px; + font-family: "FontAwesome"; + content: "\f0ce"; +} + +.selected-table-name .card-pf-title { + margin-bottom: 0px; + margin-left: 5px; + margin-top: 0px; + font-size: 14px; font-weight: bold; } -.selected-table-connection { +.selected-table-connection:before { + display: inline-block; + margin-bottom: 0px; + margin-left: 20px; + margin-right: 10px; + margin-top: 0px; + font-family: "FontAwesome"; + content: "\f1e6"; + color: #666666; +} + +.selected-table-connection .card-pf-subtitle { + color: #666666; + margin-bottom: 0px; margin-left: 5px; + margin-top: 0px; + font-size: 14px; } .selected-table-close-icon { cursor: pointer; color: darkred; } + +.selected-table-body .card-pf-body { + background-color: white; + margin-top: 10px !important; +} + +.selected-table-column-selection { + margin-left: 5px; + padding-top: 5px; + font-weight: bold; +} + +.seleted-table-card .pfng-card .card-pf-heading { + background-color: #def3ff; + margin-bottom: -10px !important; +} + + +.selected-table-card .pfng-card .card-pf-footer { + margin: 0 !important; + padding: 10px 0px 5px 20px; + min-height: 20px; +} + diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.html b/ngapp/src/app/dataservices/selected-table/selected-table.component.html index 78abdcf0..671aad6b 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.html +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.html @@ -1,6 +1,84 @@ -
    - {{ table.getConnection().getId() }} - -
    - {{ table.getName() }} -
    + + +

    + + {{ table.getName() }} +

    +
    {{ table.getConnection().getId() }}
    +
    +
    +
    +
    Select columns to include in the view:
    + + + + +
    {{selectedColumnCount}} of {{columnCount}} selected
    +
    +
    + + + +
    + + + + + + +
    +
    +
    +
    + + + + diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts index dba7d5c7..aee276b7 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts @@ -1,7 +1,27 @@ -import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from "@angular/core"; +import { Column } from "@dataservices/selected-table/column"; import { Table } from "@dataservices/shared/table.model"; +import { CardAction, CardConfig } from "patternfly-ng"; @Component({ + encapsulation: ViewEncapsulation.None, selector: "app-selected-table", templateUrl: "./selected-table.component.html", styleUrls: ["./selected-table.component.css"] @@ -11,16 +31,72 @@ export class SelectedTableComponent implements OnInit { @Input() public table: Table; @Output() public selectionListTableRemoved: EventEmitter
    = new EventEmitter
    (); + public columnDefinitions: Column[]; + public config: CardConfig; + public showColumns = false; + + public readonly customClasses = { + sortAscending: "fa fa-sort-asc", + sortDescending: "fa fa-sort-desc", + pagerLeftArrow: "fa fa-chevron-left", + pagerRightArrow: "fa fa-chevron-right", + pagerPrevious: "fa fa-step-backward", + pagerNext: "fa fa-step-forward" + }; + constructor() { // nothing to do } public ngOnInit(): void { - // nothing to do + this.columnDefinitions = [ + { name: "name", selected: true, type: "string", size: 25 }, + { name: "age", selected: true, type: "integer", size: 3 }, + { name: "street", selected: true, type: "string", size: 50 }, + { name: "state", selected: true, type: "string", size: 2 }, + { name: "zipcode", selected: true, type: "string", size: 9 }, + { name: "company", selected: true, type: "string", size: 50 }, + { name: "married", selected: true, type: "boolean", size: 1 }, + { name: "gender", selected: true, type: "string", size: 1 } + ]; + + this.config = { + action: { + id: "showColumns", + hypertext: this.showColumnsActionTitle, + iconStyleClass: "fa fa-columns" + }, + titleBorder: true, + noPadding: true, + topBorder: true + } as CardConfig; + } + + public get columnCount(): number { + return this.columnDefinitions.length; + } + + public handleActionSelect( $event: CardAction ): void { + this.showColumns = !this.showColumns; + $event.hypertext = this.showColumnsActionTitle; + } + + public selectedColumnChanged( column: Column ): void { + column.selected = !column.selected; + } + + public get selectedColumnCount(): number { + return this.columnDefinitions.filter( ( column ) => column.selected ).length; + } + + public get showColumnsActionTitle(): string { + return this.showColumns ? "Hide Columns" + : "Show Columns (" + this.selectedColumnCount + " of " + this.columnCount + " selected)"; } public onRemove(): void { this.table.selected = false; this.selectionListTableRemoved.emit(this.table); } + } diff --git a/ngapp/src/app/dataservices/shared/wizard.service.ts b/ngapp/src/app/dataservices/shared/wizard.service.ts index cde3c605..191b4674 100644 --- a/ngapp/src/app/dataservices/shared/wizard.service.ts +++ b/ngapp/src/app/dataservices/shared/wizard.service.ts @@ -52,7 +52,10 @@ export class WizardService { * @returns {Table[]} the selections */ public getWizardSelectedTables( ): Table[] { - return this.wizardSelectedTablesArray; + return this.wizardSelectedTablesArray.sort( + ( thisTable, thatTable ) => { + return thisTable.getName().localeCompare( thatTable.getName() ); + } ); } /** From 48f4404f7fce312569d03c17b6b13c4305f9274b Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 12 Jan 2018 09:55:43 -0600 Subject: [PATCH 068/205] Fixes some tests that broke due to PR 77 merge. Also fix bug in JDBC table header checkbox checked stataus. --- ...onnection-table-selector.component.spec.ts | 3 +- .../jdbc-table-selector.component.spec.ts | 3 +- .../jdbc-table-selector.component.ts | 29 +++++++++++++++++++ .../selected-table.component.spec.ts | 3 ++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts index 75233b4d..0e156f93 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -14,6 +14,7 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; +import { PatternFlyNgModule } from "patternfly-ng"; describe("ConnectionTableSelectorComponent", () => { let component: ConnectionTableSelectorComponent; @@ -21,7 +22,7 @@ describe("ConnectionTableSelectorComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule, NgxDatatableModule ], + imports: [ FormsModule, HttpModule, NgxDatatableModule, PatternFlyNgModule ], declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ AppSettingsService, LoggerService, NotifierService, WizardService, diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index 9fa5f2c7..c1002114 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -13,6 +13,7 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { JdbcTableSelectorComponent } from "./jdbc-table-selector.component"; +import { PatternFlyNgModule } from "patternfly-ng"; describe("JdbcTableSelectorComponent", () => { let component: JdbcTableSelectorComponent; @@ -20,7 +21,7 @@ describe("JdbcTableSelectorComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule, NgxDatatableModule ], + imports: [ FormsModule, HttpModule, NgxDatatableModule, PatternFlyNgModule ], declarations: [ JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ AppSettingsService, LoggerService, NotifierService, WizardService, diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index 5ec2f77f..357a5631 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -311,6 +311,20 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } this.filteredTables = this.tables.filter( ( table ) => table.getName().match( this.tableFilter ) != null ); + + // need to set column header checkbox state + let enable = true; + + for ( const filteredTable of this.filteredTables ) { + if ( !filteredTable.selected ) { + enable = false; + break; + } + } + + if ( this.selectedAllRows !== enable ) { + this.selectedAllRows = enable; + } } /* @@ -400,6 +414,21 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { const theTableName = theTable.getName(); if (theConnName === connName && theTableName === tableName) { theTable.selected = false; + + // need to set column header checkbox state + let enable = true; + + for ( const filteredTable of this.filteredTables ) { + if ( !filteredTable.selected ) { + enable = false; + break; + } + } + + if ( this.selectedAllRows !== enable ) { + this.selectedAllRows = enable; + } + break; } } diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts index be27c518..4815310b 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts @@ -1,6 +1,8 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { Connection } from "@connections/shared/connection.model"; +import { NgxDatatableModule } from "@swimlane/ngx-datatable"; +import { PatternFlyNgModule } from "patternfly-ng"; import { Table } from "../shared/table.model"; import { SelectedTableComponent } from "./selected-table.component"; @@ -10,6 +12,7 @@ describe("SelectedTableComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [ NgxDatatableModule, PatternFlyNgModule ], declarations: [ SelectedTableComponent ] }) .compileComponents(); From acdc3c2621f1ecde512882993e3e4940b2341c04 Mon Sep 17 00:00:00 2001 From: Ramesh Reddy Date: Fri, 12 Jan 2018 10:27:32 -0600 Subject: [PATCH 069/205] test --- ngapp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngapp/package.json b/ngapp/package.json index bfaac5a2..5b9fe10f 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -4,7 +4,7 @@ "license": "MIT", "scripts": { "ng": "ng", - "start": "ng serve", + "start": "ng serve --host 0.0.0.0 --port 8080", "build": "ng build", "test": "ng test", "lint": "ng lint", From e9b589ce357e59251ca2c87cc1e82500ec67d85b Mon Sep 17 00:00:00 2001 From: Ramesh Reddy Date: Fri, 12 Jan 2018 14:06:56 -0600 Subject: [PATCH 070/205] Disable HOST Check --- ngapp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngapp/package.json b/ngapp/package.json index 5b9fe10f..e5a1630c 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -4,7 +4,7 @@ "license": "MIT", "scripts": { "ng": "ng", - "start": "ng serve --host 0.0.0.0 --port 8080", + "start": "ng serve --host 0.0.0.0 --port 8080 --disable-host-check", "build": "ng build", "test": "ng test", "lint": "ng lint", From 4686e07efb4900b9157df37ef9ae4036aa7e8499 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 15 Jan 2018 15:15:25 -0600 Subject: [PATCH 071/205] Added some tests - added some JdbcTableSelectorComponent tests - added some SelectedTableComponent tests - modified MockConnectionService to support new tests - removed commented code from selected-table.component.html --- .../shared/mock-connection.service.ts | 81 ++++++++++++++++--- .../connection-table-selector.component.css | 2 +- ...onnection-table-selector.component.spec.ts | 2 +- .../jdbc-table-selector.component.spec.ts | 29 ++++++- .../selected-table.component.css | 20 ++--- .../selected-table.component.html | 16 ---- .../selected-table.component.spec.ts | 26 +++++- 7 files changed, 132 insertions(+), 44 deletions(-) diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index a442e1e8..40b3d25a 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -20,6 +20,7 @@ import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { SchemaInfo } from "@connections/shared/schema-info.model"; import { TemplateDefinition } from "@connections/shared/template-definition.model"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -32,21 +33,56 @@ import { Observable } from "rxjs/Observable"; @Injectable() export class MockConnectionService extends ConnectionService { - private newConnection = new NewConnection(); - private conn1 = new Connection(); - private conn2 = new Connection(); - private conn3 = new Connection(); - private conns: Connection[] = [this.conn1, this.conn2, this.conn3]; - private templ1 = new TemplateDefinition(); - private templ2 = new TemplateDefinition(); - private templ3 = new TemplateDefinition(); - private templs: TemplateDefinition[] = [this.templ1, this.templ2, this.templ3]; + public static conn1Id = "conn1"; + public static conn1 = MockConnectionService.createJdbcConnection( MockConnectionService.conn1Id ); + public static conn1SchemaInfos = [ + SchemaInfo.create( { name: "conn1SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn1CatalogInfo", type: "Catalog", schemaNames: [ "conn1CatalogSchema1", "conn1CatalogSchema1" ] } ) + ]; + public static numConn1Schemas = 3; + + public static conn2Id = "conn2"; + public static conn2 = MockConnectionService.createJdbcConnection( MockConnectionService.conn2Id ); + public static conn2SchemaInfos = [ + SchemaInfo.create( { name: "conn2CatalogInfo", type: "Catalog", schemaNames: [ "conn2CatalogSchema1", "conn2CatalogSchema1" ] } ), + SchemaInfo.create( { name: "conn2SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn2SchemaInfo2", type: "Schema" } ) + ]; + public static numConn2Schemas = 4; + + public static conn3Id = "conn3"; + public static conn3 = MockConnectionService.createJdbcConnection( MockConnectionService.conn3Id ); + public static conn3SchemaInfos = [ + SchemaInfo.create( { name: "conn3CatalogInfo", type: "Catalog", schemaNames: [ "conn3CatalogSchema1", "conn3CatalogSchema1" ] } ), + SchemaInfo.create( { name: "conn3SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ), + SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ) + ]; + public static numConn3Schemas = 5; + + public static templ1 = new TemplateDefinition(); + public static templ2 = new TemplateDefinition(); + public static templ3 = new TemplateDefinition(); + + public conns: Connection[] = [ + MockConnectionService.conn1, + MockConnectionService.conn2, + MockConnectionService.conn3 ]; + + public templs: TemplateDefinition[] = [ + MockConnectionService.templ1, + MockConnectionService.templ2, + MockConnectionService.templ3 ]; + + private static createJdbcConnection( id: string ): Connection { + const newConn = new Connection(); + newConn.setId( id ); + newConn.setJdbc( true ); + return newConn; + } constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { super(http, appSettings, logger); - this.conn1.setId("conn1"); - this.conn2.setId("conn2"); - this.conn3.setId("conn3"); } /** @@ -72,7 +108,9 @@ export class MockConnectionService extends ConnectionService { * @returns {Observable} */ public deleteConnection(connectionId: string): Observable { - return Observable.of(true); + const size = this.conns.length; + this.conns = this.conns.filter( ( conn ) => conn.getId() !== connectionId ); + return Observable.of( size === this.conns.length ); } /** @@ -83,4 +121,21 @@ export class MockConnectionService extends ConnectionService { return Observable.of(this.templs); } + public getConnectionSchemaInfos( connectionId: string): Observable< SchemaInfo[] > { + if ( connectionId === MockConnectionService.conn1Id ) { + return Observable.of( MockConnectionService.conn1SchemaInfos ); + } + + if ( connectionId === MockConnectionService.conn2Id ) { + return Observable.of( MockConnectionService.conn2SchemaInfos ); + } + + if ( connectionId === MockConnectionService.conn3Id ) { + return Observable.of( MockConnectionService.conn3SchemaInfos ); + } + + const empty: SchemaInfo[] = []; + return Observable.of( empty ); + } + } diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css index f65e3ba5..8fffc9d0 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css @@ -24,6 +24,6 @@ .selected-tables-container { background-color: #bbbbbb; max-height: 480px; - margin-top: 0px; + margin-top: 0; overflow-y: auto; } diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts index 0e156f93..963a642a 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -13,8 +13,8 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; -import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; import { PatternFlyNgModule } from "patternfly-ng"; +import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; describe("ConnectionTableSelectorComponent", () => { let component: ConnectionTableSelectorComponent; diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index c1002114..f9fea6c9 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -6,13 +6,13 @@ import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { NgxDatatableModule } from "@swimlane/ngx-datatable"; -import { JdbcTableSelectorComponent } from "./jdbc-table-selector.component"; import { PatternFlyNgModule } from "patternfly-ng"; describe("JdbcTableSelectorComponent", () => { @@ -44,4 +44,31 @@ describe("JdbcTableSelectorComponent", () => { console.log("========== [JdbcTableSelectorComponent] should be created"); expect(component).toBeTruthy(); }); + + it("should have correct number of schemas", () => { + component.connection = MockConnectionService.conn2; + component.ngOnInit(); + component.setConnection( MockConnectionService.conn1 ); + expect( component.getSchemas().length ).toBe( MockConnectionService.numConn1Schemas ); + }); + + it( "should clear schemas", () => { + component.connection = MockConnectionService.conn3; + component.ngOnInit(); + expect( component.getSchemas().length ).toBe( MockConnectionService.numConn3Schemas ); + + component.clearSchemas(); + expect( component.getSchemas().length ).toBe( 0 ); + }); + + it( "should select schema", () => { + component.connection = MockConnectionService.conn1; + component.ngOnInit(); + expect( component.selectedSchema ).toBeNull(); + expect( component.hasSelectedSchema ).toBeFalsy(); + + component.selectedSchema = component.getSchemas()[ 0 ]; + expect( component.hasSelectedSchema ).toBeTruthy(); + }); + }); diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.css b/ngapp/src/app/dataservices/selected-table/selected-table.component.css index 68add26f..00a8ce61 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.css +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.css @@ -1,32 +1,32 @@ .selected-table-card .card-pf { background-color: #def3ff; - margin: 0 0px 10px; + margin: 0 0 10px; min-height: 40px; } .selected-table-name:before { display: inline-block; - margin-bottom: 0px; + margin-bottom: 0; margin-right: 10px; - margin-top: 0px; + margin-top: 0; font-family: "FontAwesome"; content: "\f0ce"; } .selected-table-name .card-pf-title { - margin-bottom: 0px; + margin-bottom: 0; margin-left: 5px; - margin-top: 0px; + margin-top: 0; font-size: 14px; font-weight: bold; } .selected-table-connection:before { display: inline-block; - margin-bottom: 0px; + margin-bottom: 0; margin-left: 20px; margin-right: 10px; - margin-top: 0px; + margin-top: 0; font-family: "FontAwesome"; content: "\f1e6"; color: #666666; @@ -34,9 +34,9 @@ .selected-table-connection .card-pf-subtitle { color: #666666; - margin-bottom: 0px; + margin-bottom: 0; margin-left: 5px; - margin-top: 0px; + margin-top: 0; font-size: 14px; } @@ -64,7 +64,7 @@ .selected-table-card .pfng-card .card-pf-footer { margin: 0 !important; - padding: 10px 0px 5px 20px; + padding: 10px 0 5px 20px; min-height: 20px; } diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.html b/ngapp/src/app/dataservices/selected-table/selected-table.component.html index 671aad6b..d64f1725 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.html +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.html @@ -66,19 +66,3 @@
    Select columns to include in the vie - - - - diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts index 4815310b..859c933e 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts @@ -9,27 +9,49 @@ import { SelectedTableComponent } from "./selected-table.component"; describe("SelectedTableComponent", () => { let component: SelectedTableComponent; let fixture: ComponentFixture; + let htmlElem: HTMLElement; + + const connectionName = "testConnection"; + const tableName = "testTable"; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ NgxDatatableModule, PatternFlyNgModule ], declarations: [ SelectedTableComponent ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { fixture = TestBed.createComponent(SelectedTableComponent); component = fixture.componentInstance; + htmlElem = fixture.nativeElement; + const connection = new Connection(); - connection.setId("testConn"); + connection.setId( connectionName ); + const table = new Table(); table.setConnection(connection); + table.setName( tableName ); component.table = table; + fixture.detectChanges(); }); it("should be created", () => { expect(component).toBeTruthy(); }); + + it("should have correct table name", () => { + const heading = fixture.debugElement.nativeElement.querySelector( ".selected-table-name" ); + expect( heading.textContent ).toContain( tableName ); + }); + + it("should have correct connector name", () => { + const heading = fixture.debugElement.nativeElement.querySelector( ".selected-table-connection" ); + expect( heading.textContent ).toContain( connectionName ); + }); + }); From b276fa118370f77ecb484a5186e81a69d5fa2e7d Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Wed, 17 Jan 2018 11:41:08 +0000 Subject: [PATCH 072/205] Modify the npm start script for running the app * package.json * Replace the development server start command with a cli start script * start.sh * Can start server through either node or ng * Use npm start for production node execution * Use npm start -- -d for starting using 'ng serve' * server.js * Scaffold the angular compiled artefacts in the dist/ directory as static files in express to allow them to be server through node. --- ngapp/README.md | 6 +++++- ngapp/package.json | 3 ++- ngapp/server.js | 15 +++++++++++++++ ngapp/start.sh | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 ngapp/server.js create mode 100755 ngapp/start.sh diff --git a/ngapp/README.md b/ngapp/README.md index e66b7bea..d68ff074 100644 --- a/ngapp/README.md +++ b/ngapp/README.md @@ -2,9 +2,13 @@ This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.3.2. +## Running with [Nodejs](https://nodejs.org) + +Execute `npm start` to serve the Angular app using nodejs. Navigate to `http://localhost:8080`. This command is meant for production and the files in the `dist` directory will have to be recompiled for code changes to be displayed. + ## Development server -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. +Execute `npm start -- -d` for a development server. Navigate to `http://localhost:8080/`. The app will automatically reload if you change any of the source files. ## Code scaffolding diff --git a/ngapp/package.json b/ngapp/package.json index e5a1630c..1a902473 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -4,8 +4,8 @@ "license": "MIT", "scripts": { "ng": "ng", - "start": "ng serve --host 0.0.0.0 --port 8080 --disable-host-check", "build": "ng build", + "start": "./start.sh", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" @@ -23,6 +23,7 @@ "@angular/router": "^4.4.6", "@swimlane/ngx-datatable": "^11.1.5", "core-js": "^2.4.1", + "express": "^4.16.2", "ng2-codemirror": "^1.1.3", "ngx-bootstrap": "^1.9.3", "patternfly": "^3.31.0", diff --git a/ngapp/server.js b/ngapp/server.js new file mode 100644 index 00000000..15ea47ab --- /dev/null +++ b/ngapp/server.js @@ -0,0 +1,15 @@ +var express = require("express"); +var bodyParser = require("body-parser"); + +var app = express(); +app.use(bodyParser.json()); + +// Create link to Angular build directory +var distDir = __dirname + "/dist/"; +app.use(express.static(distDir)); + +// Initialize the app. +var server = app.listen(process.env.PORT || 8080, function () { + var port = server.address().port; + console.log("App now running on port", port); +}); diff --git a/ngapp/start.sh b/ngapp/start.sh new file mode 100755 index 00000000..05fa3cc9 --- /dev/null +++ b/ngapp/start.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +################# +# +# Show help and exit +# +################# +function show_help { + echo "Usage: $0 [-d] [-h]" + echo "-d: run in development mode" + echo "" + echo "To passthrough additional arguments, enter '--' followed by the extra arguments" + exit 1 +} + +# +# Determine the command line options +# +while getopts ":d" opt; +do + case $opt in + d) DEV=1 ;; + h) show_help ;; + esac +done +shift "$(expr $OPTIND - 1)" + +if [ "${DEV}" == "1" ]; then + ng serve --host 0.0.0.0 --port 8080 --disable-host-check +else + ng build && node ./server.js +fi From e0079447d6d99fa4abda05dd89173a24a695eb64 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Wed, 17 Jan 2018 16:50:06 -0600 Subject: [PATCH 073/205] Add a way to select the connection used when selecting tables of the dataservice - changed step 2a of dataservice wizard to allow user to select the connection - added a inline notification on step 1 of the dataservice wizard alerting user that multi-source is not yet supported - fixed a bug in JdbcTableSelectorComponent where the table header checkbox did not have the correct state --- .../add-dataservice-wizard.component.css | 42 ++++++++++++ .../add-dataservice-wizard.component.html | 42 ++++++++++-- .../add-dataservice-wizard.component.ts | 64 +++++++++++++++++-- .../jdbc-table-selector.component.ts | 10 +++ 4 files changed, 147 insertions(+), 11 deletions(-) diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css index 0f0ecbda..5ec44c46 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css @@ -3,3 +3,45 @@ font-size: 67px; line-height: 67px; } + +.wiz-review-table-checked:before { + display: inline-block; + margin-bottom: 0; + margin-left: 4px; + margin-right: 4px; + margin-top: 0; + font-family: "FontAwesome"; + content: "\f046"; + color: green; +} + +.wiz-review-table-checked { + margin: 4px; +} + +.wiz-review-table-unchecked:before { + display: inline-block; + margin-bottom: 0; + margin-left: 4px; + margin-right: 4px; + margin-top: 0; + font-family: "FontAwesome"; + content: "\f096"; +} + +.wiz-review-table-unchecked { + margin: 4px; +} + +.wiz-review-tables { + height: 200px; + width: 300px; + margin-left: 20px; + padding-left: 4px; + overflow: scroll; + white-space: nowrap; + border: 1px solid #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; +} diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html index bd435d95..d98adb28 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html @@ -7,6 +7,19 @@ +
    +
    +
    + + +
    +
    +
    +

    {{ step1InstructionMessage }}


    @@ -21,7 +34,7 @@

    {{ step2InstructionMessage }}


    - +
    {{ nameValidationError }}
    @@ -33,11 +46,30 @@

    {{ step2InstructionMessage }}

    -
    - +
    +
    -
    - + +
    {{ selectConnectionErrorMsg }}
    +
    +
    +
    + +
    +
    + {{ table.getName() }} ( {{ table.getConnection().getId() }} )
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index cc376a6b..42e1a10b 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -25,6 +25,7 @@ import { import { FormControl, FormGroup } from "@angular/forms"; import { AbstractControl } from "@angular/forms"; import { Router } from "@angular/router"; +import { Connection } from "@connections/shared/connection.model"; import { LoggerService } from "@core/logger.service"; import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; @@ -37,7 +38,7 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { WizardService } from "@dataservices/shared/wizard.service"; import { LoadingState } from "@shared/loading-state.enum"; -import { WizardComponent } from "patternfly-ng"; +import { NotificationType, WizardComponent } from "patternfly-ng"; import { WizardEvent } from "patternfly-ng"; import { WizardStepConfig } from "patternfly-ng"; import { WizardConfig } from "patternfly-ng"; @@ -50,8 +51,9 @@ import { Subscription } from "rxjs/Subscription"; styleUrls: ["./add-dataservice-wizard.component.css"] }) export class AddDataserviceWizardComponent implements OnInit, OnDestroy { - public readonly dataserviceSummaryLink: string = DataservicesConstants.dataservicesRootPath; - public loadingState = LoadingState; // need local ref of enum for html to use + + public emptyConnection = new Connection(); // a bogus connection used in drop down to give instructions + public readonly selectConnectionErrorMsg = "A connection must be selected"; // Wizard Config public wizardConfig: WizardConfig; @@ -62,6 +64,12 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { // Wizard Step 1 public step1Config: WizardStepConfig; + public connectionNotificationDismissable = false; + public connectionNotificationHeader = "Source Selection"; + public connectionNotificationMessage = "You can select tables from multiple connections, but currently we only support " + + " tables from a single connection (multiple connections coming soon). You will " + + "choose the connection in the next step."; + public connectionNotificationType = NotificationType.WARNING; // Wizard Step 2 public step2Config: WizardStepConfig; @@ -71,6 +79,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { @ViewChild("wizard") public wizard: WizardComponent; @ViewChild(ConnectionTableSelectorComponent) public tableSelector: ConnectionTableSelectorComponent; + public selectedConnection: Connection; public nameValidationError = ""; private dataserviceService: DataserviceService; private notifierService: NotifierService; @@ -92,6 +101,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.wizardService = wizardService; this.router = router; this.logger = logger; + this.emptyConnection.setId( " -- select a connection -- " ); + this.selectedConnection = this.emptyConnection; this.createBasicPropertyForm(); } @@ -233,7 +244,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if (this.wizardService.isEdit()) { return "Review selections. Click Update to update the Dataservice"; } - return "Review selections and enter a name. Click Create to create the Dataservice"; + return "Enter a name, select a connection, and review the table selections. Click Create to create the Dataservice"; } /* @@ -377,12 +388,53 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } /** - * @returns {string} the selected source table names in string form + * @returns {Table[]} the selected source table names in string form */ public get dataserviceSourceTables(): Table[] { return this.tableSelector.getSelectedTables(); } + /** + * + * @returns {Connection[]} the selected source table connections + */ + public get sourceTableConnections(): Connection[] { + const tables = this.tableSelector.getSelectedTables(); + const connections: Connection[] = []; + + for ( const table of tables ) { + const connection = table.getConnection(); + + if ( connections.indexOf( connection) === -1 ) { + connections.push( connection ); + } + } + + return connections; + } + + public selectedConnectionChanged( $event ): void { + // since the dropdown has a dummy first element subtract 1 + const index = $event.target.selectedIndex - 1; + this.selectedConnection = this.sourceTableConnections[ index ]; + this.updatePage2aValidStatus(); + } + + public shouldCheck( table: Table ): boolean { + if ( this.selectedConnection && ( table.getConnection() === this.selectedConnection ) ) { + return true; + } + + return false; + } + + /** + * @returns {boolean} `true` if a connection has been selected + */ + public hasSelectedConnection(): boolean { + return ( this.selectedConnection != null ) && ( this.selectedConnection !== this.emptyConnection ); + } + /** * Updates the page1 status */ @@ -434,7 +486,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if (this.wizardService.isEdit()) { this.step2aConfig.nextEnabled = true; } else { - this.step2aConfig.nextEnabled = this.nameValid; + this.step2aConfig.nextEnabled = this.nameValid && this.hasSelectedConnection(); } this.setNavAway(this.step2aConfig.nextEnabled); } diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index 357a5631..57901bcb 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -490,6 +490,7 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { // Load the table names for the selected Connection and Schema this.tables = []; this.filteredTables = []; + this.selectedAllRows = false; this.tableLoadingState = LoadingState.LOADING; const self = this; this.connectionService @@ -517,11 +518,14 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } private setInitialTableSelections(): void { + let enableSelectAll = true; + for ( const table of this.tables ) { // const catName = table.getCatalogName(); // const schemaName = table.getSchemaName(); const tableName = table.getName(); const connName = table.getConnection().getId(); + for ( const initialTable of this.wizardService.getWizardSelectedTables() ) { // const iCatName = initialTable.getCatalogName(); // const iSchemaName = initialTable.getSchemaName(); @@ -532,7 +536,13 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { break; } } + + if ( !table.selected ) { + enableSelectAll = false; + } } + + this.selectedAllRows = enableSelectAll; } } From da47f6902e3385742e05af21bd550f57cf73c350 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 22 Jan 2018 14:24:08 -0600 Subject: [PATCH 074/205] TEIIDTOOLS-324 Convert Non-Patternfly 2+ Components to Patternfly NG Components If Available - converted vertical and horizontal navbar to patternfly-ng - upgraded patternfly and patternfly-ng versions - changes to some stylesheets - deleted NavHeaderComponent (no longer needed) --- ngapp/package-lock.json | 52 ++++---- ngapp/package.json | 4 +- ngapp/src/app/app.component.html | 2 - .../add-connection.component.html | 2 +- .../connections/connections.component.html | 2 +- .../shared/connections-constants.ts | 9 ++ ngapp/src/app/core/core.module.ts | 5 +- .../core/nav-header/nav-header.component.html | 44 ------- .../core/nav-header/nav-header.component.less | 50 -------- .../nav-header/nav-header.component.spec.ts | 47 -------- .../core/nav-header/nav-header.component.ts | 67 ----------- .../vertical-nav/vertical-nav.component.css | 15 +++ .../vertical-nav/vertical-nav.component.html | 45 ++++--- .../vertical-nav/vertical-nav.component.less | 89 -------------- .../vertical-nav.component.spec.ts | 12 +- .../vertical-nav/vertical-nav.component.ts | 112 ++++++++---------- .../add-dataservice-wizard.component.css | 10 +- .../add-dataservice-wizard.component.ts | 7 +- .../add-dataservice.component.html | 2 +- .../dataservices/dataservices.component.html | 2 +- .../selected-table.component.css | 5 +- .../shared/dataservices-constants.ts | 8 ++ .../test-dataservice.component.html | 2 +- ngapp/src/assets/vdb.png | Bin 0 -> 2148 bytes 24 files changed, 157 insertions(+), 436 deletions(-) delete mode 100644 ngapp/src/app/core/nav-header/nav-header.component.html delete mode 100644 ngapp/src/app/core/nav-header/nav-header.component.less delete mode 100644 ngapp/src/app/core/nav-header/nav-header.component.spec.ts delete mode 100644 ngapp/src/app/core/nav-header/nav-header.component.ts create mode 100644 ngapp/src/app/core/vertical-nav/vertical-nav.component.css delete mode 100644 ngapp/src/app/core/vertical-nav/vertical-nav.component.less create mode 100644 ngapp/src/assets/vdb.png diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index 74512bb7..6ff4c5a5 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -366,9 +366,9 @@ "dev": true }, "angular-tree-component": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/angular-tree-component/-/angular-tree-component-6.0.0.tgz", - "integrity": "sha1-M3ADLHOEw/V895NDzyY9+cQUlv4=", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/angular-tree-component/-/angular-tree-component-6.1.0.tgz", + "integrity": "sha1-nZprKKaIHCByzWMGtVIpV56JQHE=", "optional": true, "requires": { "lodash": "4.17.4", @@ -6657,12 +6657,12 @@ } }, "patternfly": { - "version": "3.31.0", - "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.31.0.tgz", - "integrity": "sha1-Kj/9nzyUsIMUp5Kna3zuXqTic3k=", + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.37.1.tgz", + "integrity": "sha1-uYivPWcyyz0O26P347Eb8QFY7Uo=", "requires": { "bootstrap": "3.3.7", - "bootstrap-datepicker": "1.6.4", + "bootstrap-datepicker": "1.7.1", "bootstrap-sass": "3.3.7", "bootstrap-select": "1.12.4", "bootstrap-slider": "9.10.0", @@ -6671,7 +6671,7 @@ "c3": "0.4.18", "d3": "3.5.17", "datatables.net": "1.10.16", - "datatables.net-colreorder": "1.3.3", + "datatables.net-colreorder": "1.4.1", "datatables.net-colreorder-bs": "1.3.3", "datatables.net-select": "1.2.3", "drmonty-datatables-colvis": "1.1.2", @@ -6681,7 +6681,7 @@ "google-code-prettify": "1.0.5", "jquery": "3.2.1", "jquery-match-height": "0.7.2", - "moment": "2.14.1", + "moment": "2.20.1", "moment-timezone": "0.4.1", "patternfly-bootstrap-combobox": "1.1.7", "patternfly-bootstrap-treeview": "2.1.5" @@ -6693,9 +6693,9 @@ "integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E=" }, "bootstrap-datepicker": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.6.4.tgz", - "integrity": "sha1-iJ6+ztjqov8V7B8nPksHUxzEPaA=", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/bootstrap-datepicker/-/bootstrap-datepicker-1.7.1.tgz", + "integrity": "sha1-Tuf680iI2+x4NPv52+fEJ34B3a8=", "optional": true, "requires": { "jquery": "3.2.1" @@ -6768,9 +6768,9 @@ } }, "datatables.net-colreorder": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/datatables.net-colreorder/-/datatables.net-colreorder-1.3.3.tgz", - "integrity": "sha1-/HYuNQ+UIkyyzUXCuWImGg//73I=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/datatables.net-colreorder/-/datatables.net-colreorder-1.4.1.tgz", + "integrity": "sha1-OJ5LGidOIDl5o3GNhsWITQoBZrY=", "optional": true, "requires": { "datatables.net": "1.10.16", @@ -6784,7 +6784,7 @@ "optional": true, "requires": { "datatables.net-bs": "1.10.16", - "datatables.net-colreorder": "1.3.3", + "datatables.net-colreorder": "1.4.1", "jquery": "3.2.1" } }, @@ -6815,7 +6815,7 @@ "requires": { "bootstrap": "3.3.7", "jquery": "3.2.1", - "moment": "2.14.1", + "moment": "2.20.1", "moment-timezone": "0.4.1" } }, @@ -6848,9 +6848,9 @@ "optional": true }, "moment": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz", - "integrity": "sha1-s1snxH5X7S3ccAU9awe+zbKRdBw=" + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", + "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg==" }, "moment-timezone": { "version": "0.4.1", @@ -6858,7 +6858,7 @@ "integrity": "sha1-gfWYw61eIs2teWtn7NjYjQ9bqgY=", "optional": true, "requires": { - "moment": "2.14.1" + "moment": "2.20.1" } }, "patternfly-bootstrap-combobox": { @@ -6880,15 +6880,15 @@ } }, "patternfly-ng": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-2.0.0.tgz", - "integrity": "sha1-1lwcjeV7AgVdXsQSK+/vyf1DB6w=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-2.1.1.tgz", + "integrity": "sha1-kd7dyTpIUP6c538ZMj3VqMeZelo=", "requires": { - "angular-tree-component": "6.0.0", + "angular-tree-component": "6.1.0", "c3": "0.4.18", "lodash": "4.17.4", "ngx-bootstrap": "1.8.0", - "patternfly": "3.31.0" + "patternfly": "3.37.1" }, "dependencies": { "ngx-bootstrap": { diff --git a/ngapp/package.json b/ngapp/package.json index e5a1630c..2926f67e 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -25,8 +25,8 @@ "core-js": "^2.4.1", "ng2-codemirror": "^1.1.3", "ngx-bootstrap": "^1.9.3", - "patternfly": "^3.31.0", - "patternfly-ng": "^2.0.0", + "patternfly": "^3.37.1", + "patternfly-ng": "^2.1.1", "rxjs": "^5.5.5", "zone.js": "^0.8.14" }, diff --git a/ngapp/src/app/app.component.html b/ngapp/src/app/app.component.html index 362cb25d..9d0e854a 100644 --- a/ngapp/src/app/app.component.html +++ b/ngapp/src/app/app.component.html @@ -1,8 +1,6 @@
    -
    - diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index 40cba9b4..40601fa9 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -1,4 +1,4 @@ -
    +
  • diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index b7437b35..e553cdfa 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/ngapp/src/app/connections/shared/connections-constants.ts b/ngapp/src/app/connections/shared/connections-constants.ts index 571694ed..ca7c321a 100644 --- a/ngapp/src/app/connections/shared/connections-constants.ts +++ b/ngapp/src/app/connections/shared/connections-constants.ts @@ -10,6 +10,8 @@ * limitations under the License. */ +import { NavigationItemConfig } from "patternfly-ng"; + export class ConnectionsConstants { public static readonly connectionsRootRoute = "connections"; @@ -17,4 +19,11 @@ export class ConnectionsConstants { public static readonly addConnectionRoute = ConnectionsConstants.connectionsRootRoute + "/add-connection"; public static readonly addConnectionPath = ConnectionsConstants.connectionsRootPath + "/add-connection"; + + public static readonly connectionsNavItem: NavigationItemConfig = { + title: "Connections", + iconStyleClass: "fa fa-fw fa-plug", + url: ConnectionsConstants.connectionsRootPath + }; + } diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 0153e9a6..7ab84f9e 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -25,29 +25,28 @@ import { AppSettingsService } from "@core/app-settings.service"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; import { LoggerService } from "@core/logger.service"; -import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; import { ModalModule } from "ngx-bootstrap/modal"; import { BsModalService } from "ngx-bootstrap/modal"; +import { PatternFlyNgModule } from "patternfly-ng"; @NgModule({ imports: [ CommonModule, HttpModule, ModalModule, + PatternFlyNgModule, RouterModule ], declarations: [ AboutDialogComponent, BreadcrumbComponent, BreadcrumbsComponent, - NavHeaderComponent, VerticalNavComponent ], exports: [ BreadcrumbComponent, BreadcrumbsComponent, - NavHeaderComponent, VerticalNavComponent ], providers: [ diff --git a/ngapp/src/app/core/nav-header/nav-header.component.html b/ngapp/src/app/core/nav-header/nav-header.component.html deleted file mode 100644 index bb49c8dd..00000000 --- a/ngapp/src/app/core/nav-header/nav-header.component.html +++ /dev/null @@ -1,44 +0,0 @@ - diff --git a/ngapp/src/app/core/nav-header/nav-header.component.less b/ngapp/src/app/core/nav-header/nav-header.component.less deleted file mode 100644 index ea21143a..00000000 --- a/ngapp/src/app/core/nav-header/nav-header.component.less +++ /dev/null @@ -1,50 +0,0 @@ -@import "../core.less"; - -.navbar { - height: @navbar-height; -} -.navbar .navbar-header { - height: @navbar-height - 3; -} - -.navbar-help-icon { - font-size: 1.5em; -} - -.navbar .navbar-brand { - padding: 0; -} -.navbar .navbar-brand .navbar-brand-logo { - line-height: @navbar-height - 3; - font-family: 'Josefin Sans', sans-serif; - font-size: @navbar-logo-size; - font-weight: bold; - color: white; -} -.navbar .navbar-brand .navbar-brand-logo:hover { - color: gold; -} - -.navbar a.dropdown-toggle { - height: @navbar-height - 3; - line-height: 34px; - font-size: 13px; - vertical-align: middle; -} -.navbar a.dropdown-toggle .pficon { - position: initial; -} - -.navbar .dropdown-menu a { - cursor: pointer; -} -.navbar .dropdown-menu a.disabled { - cursor: not-allowed; - color: #999; -} - -.product-versions-pf table tr td { - color: white; - font-size: 13px; - padding-right: 10px; -} diff --git a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts b/ngapp/src/app/core/nav-header/nav-header.component.spec.ts deleted file mode 100644 index ea215c71..00000000 --- a/ngapp/src/app/core/nav-header/nav-header.component.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; -import { HttpModule } from "@angular/http"; -import { AboutDialogComponent } from "@core/about-dialog/about-dialog.component"; -import { AboutService } from "@core/about-dialog/about.service"; -import { MockAboutService } from "@core/about-dialog/mock-about.service"; -import { AppSettingsService } from "@core/app-settings.service"; -import { LoggerService } from "@core/logger.service"; -import { NavHeaderComponent } from "@core/nav-header/nav-header.component"; -import { ModalModule } from "ngx-bootstrap"; -import { BsModalService } from "ngx-bootstrap/modal"; - -describe("NavHeaderComponent", () => { - let component: NavHeaderComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ HttpModule, ModalModule.forRoot() ], - declarations: [ NavHeaderComponent, AboutDialogComponent ], - providers: [ AboutService, AppSettingsService, BsModalService, LoggerService ] - }) - .compileComponents().then(() => { - // nothing to do - }); - })); - - // use mock service - TestBed.overrideComponent( AboutDialogComponent, { - set: { - providers: [ - { provide: AboutService, useClass: MockAboutService }, - ] - } - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NavHeaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should be created", inject([ LoggerService ], - (logger: LoggerService ) => { - console.log("========== [NavHeaderComponent] should be created"); - expect(component).toBeTruthy(); - })); -}); diff --git a/ngapp/src/app/core/nav-header/nav-header.component.ts b/ngapp/src/app/core/nav-header/nav-header.component.ts deleted file mode 100644 index 7a072b3d..00000000 --- a/ngapp/src/app/core/nav-header/nav-header.component.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, TemplateRef } from "@angular/core"; -import { AboutEvent } from "@core/about-dialog/about-event"; -import { About } from "@core/about-dialog/about.model"; -import { AboutService } from "@core/about-dialog/about.service"; -import { LoggerService } from "@core/logger.service"; -import { BsModalService } from "ngx-bootstrap/modal"; -import { BsModalRef } from "ngx-bootstrap/modal/modal-options.class"; - -@Component({ - moduleId: module.id, - selector: "app-nav-header", - templateUrl: "./nav-header.component.html", - styleUrls: [ "./nav-header.component.less" ] -}) -export class NavHeaderComponent { - - public aboutInfo: About; - private aboutRef: BsModalRef; - private logger: LoggerService; - private modalService: BsModalService; - private aboutService: AboutService; - - constructor( logger: LoggerService, - modalService: BsModalService, - aboutService: AboutService ) { - this.logger = logger; - this.modalService = modalService; - this.aboutService = aboutService; - } - - public closeAbout( $event: AboutEvent ): void { - this.aboutRef.hide(); - } - - public openAbout( template: TemplateRef< any > ): void { - const self = this; - - this.aboutService.getAboutInformation().subscribe( - ( result ) => { - self.aboutInfo = result; - }, - ( error ) => { - this.logger.error( error, "Error getting about information."); - } - ); - - this.aboutRef = this.modalService.show( template ); - } - -} diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.css b/ngapp/src/app/core/vertical-nav/vertical-nav.component.css new file mode 100644 index 00000000..ad1dfe4a --- /dev/null +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.css @@ -0,0 +1,15 @@ +.vertical-navbar-layout { + background-color: white; + position: fixed; +} + +.app-feature-content { + margin-top: 2em; + margin-left: 200px; +} + +.navbar-brand-title { + margin-top: 5px; + font-size: 2em; + color: white; +} diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html index 946dcee9..04994f18 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html @@ -1,18 +1,31 @@ -
    - -
    -
    - -
    DataServices
    +
    + +
    + +
    -
    - -
    Connections
    -
    -
    -
    -
    - +
    +
    diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.less b/ngapp/src/app/core/vertical-nav/vertical-nav.component.less deleted file mode 100644 index a79e36a9..00000000 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.less +++ /dev/null @@ -1,89 +0,0 @@ -@import "../core.less"; - -#studio-vertical-nav { - position: absolute; - left: 0; - width: 120px; - top: @navbar-height; - bottom: 0; - background-color: white; - overflow: hidden; - z-index: 100; -} -#studio-vertical-nav .studio-nav-item { - color: #666; - border-bottom: 1px solid #ddd; - padding: 15px 10px 15px 10px; - text-align: center; - border-right: 1px solid #ddd; -} -#studio-vertical-nav .studio-nav-item-filler { - border-right: 1px solid #ddd; - height: 100%; -} -#studio-vertical-nav .studio-nav-item:hover { - background-color: rgba(0, 0, 55, .05); - cursor: pointer; -} -#studio-vertical-nav .studio-nav-item.active { - color: #0088ce; -} -#studio-vertical-nav .studio-nav-item.selected { - border-right: 1px solid white; - color: black; - background-color: white; -} -#studio-vertical-nav .studio-nav-item > span { - font-size: 22px; - display: inline-block; -} -#studio-vertical-nav .studio-nav-item > div { - font-size: 14px; -} - -#studio-vertical-nav-details { - position: absolute; - left: -160px; - width: 280px; - top: @navbar-height; - bottom: 0; - background-color: white; - border-right: 1px solid #ddd; - z-index: 99; - padding: 15px; - -webkit-transition: left 200ms; - -moz-transition: left 200ms; - //-ms-transition: left 200ms; - -o-transition: left 200ms; - transition: left 200ms; -} -#studio-vertical-nav-details.out { - left: 120px; -} -#studio-vertical-nav-details .studio-nav-detail-item h3 { - margin-top: 0; - padding-bottom: 3px; - border-bottom: 1px solid #ddd; -} -#studio-vertical-nav-details .studio-nav-detail-item p.description { - line-height: 17px; - padding: 3px; -} -#studio-vertical-nav-details .studio-nav-detail-item h4 { - font-weight: bold; - font-size: 12px; - margin-top: 20px; -} -#studio-vertical-nav-details .studio-nav-detail-item .action { - padding-left: 8px; -} - -#studio-nav-menu-shade { - position: absolute; - left: 120px; - right: 0; - top: @navbar-height; - bottom: 0; - z-index: 80; - background-color: rgba(0, 0, 0, .2); -} diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts index 26281cc1..2d7ece06 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts @@ -1,7 +1,13 @@ import { async, ComponentFixture, inject, TestBed } from "@angular/core/testing"; +import { HttpModule } from "@angular/http"; import { RouterTestingModule } from "@angular/router/testing"; +import { AboutDialogComponent } from "@core/about-dialog/about-dialog.component"; +import { AboutService } from "@core/about-dialog/about.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; +import { BsModalService, ModalModule } from "ngx-bootstrap"; +import { PatternFlyNgModule } from "patternfly-ng"; describe("VerticalNavComponent", () => { let component: VerticalNavComponent; @@ -9,9 +15,9 @@ describe("VerticalNavComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [RouterTestingModule], - declarations: [ VerticalNavComponent ], - providers: [ LoggerService ] + imports: [ HttpModule, ModalModule.forRoot(), PatternFlyNgModule, RouterTestingModule ], + declarations: [ VerticalNavComponent, AboutDialogComponent ], + providers: [ AboutService, AppSettingsService, BsModalService, LoggerService ] }) .compileComponents().then(() => { // nothing to do diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index 1ef63974..b78fe34c 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -15,97 +15,81 @@ * limitations under the License. */ -import { Component, OnInit } from "@angular/core"; -import { NavigationEnd, Router } from "@angular/router"; +import { Component, OnInit, TemplateRef, ViewEncapsulation } from "@angular/core"; +import { Router } from "@angular/router"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { AboutEvent } from "@core/about-dialog/about-event"; +import { About } from "@core/about-dialog/about.model"; +import { AboutService } from "@core/about-dialog/about.service"; import { LoggerService } from "@core/logger.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; - -/** - * Models the menus off the main left-hand vertical nav. - */ -enum VerticalNavType { - Home, Connections, Dataservices -} +import { BsModalService } from "ngx-bootstrap/modal"; +import { BsModalRef } from "ngx-bootstrap/modal/modal-options.class"; +import { NavigationItemConfig } from "patternfly-ng"; @Component({ moduleId: module.id, + encapsulation: ViewEncapsulation.None, selector: "app-vertical-nav", templateUrl: "./vertical-nav.component.html", - styleUrls: ["./vertical-nav.component.less"] + styleUrls: ["./vertical-nav.component.css"] }) export class VerticalNavComponent implements OnInit { - public menuTypes: any = VerticalNavType; - public currentMenu: VerticalNavType = VerticalNavType.Home; + public aboutInfo: About; + public navigationItems: NavigationItemConfig[]; + + private aboutRef: BsModalRef; + private aboutService: AboutService; private logger: LoggerService; + private modalService: BsModalService; private router: Router; - constructor(router: Router, logger: LoggerService) { + constructor( router: Router, + logger: LoggerService, + modalService: BsModalService, + aboutService: AboutService ) { this.router = router; this.logger = logger; + this.modalService = modalService; + this.aboutService = aboutService; } - public ngOnInit(): void { - this.logger.log("Subscribing to router events."); - const self = this; - this.router.events.subscribe((event) => { - if (event instanceof NavigationEnd) { - self.onShadeClick(); - } - }); + public closeAbout( $event: AboutEvent ): void { + this.aboutRef.hide(); } - /** - * Called when the user clicks the vertical menu Connections item. - */ - public onConnectionsClick(): void { - this.currentMenu = VerticalNavType.Connections; - const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; - this.router.navigate(link).then(() => { - // nothing to do - }); + public ngOnInit(): void { + // uncomment to debug router events + // this.router.events.subscribe((event) => { + // console.error( event ); + // }); + + this.navigationItems = [ DataservicesConstants.dataservicesNavItem, ConnectionsConstants.connectionsNavItem ]; } - /** - * Called when the user clicks the vertical menu Dataservices item. - */ - public onDataservicesClick(): void { - this.currentMenu = VerticalNavType.Dataservices; - const link: string[] = [ DataservicesConstants.dataservicesRootPath ]; - this.router.navigate(link).then(() => { + public onNavigation( $event: NavigationItemConfig ): void { + const link: string[] = [ $event.url ]; + this.router.navigate( link ).then(() => { // nothing to do }); } - /** - * Called when the user clicks the vertical menu shade (the grey shaded area behind the submenu div that - * is displayed when a sub-menu is selected). Clicking the shade makes the sub-menu div go away. - */ - private onShadeClick(): void { - /* - this.subMenuOut = false; - setTimeout(() => { - this.currentSubMenu = VerticalNavSubMenuType.None; - }, 180); - */ - } + public openAbout( template: TemplateRef< any > ): void { + const self = this; + + this.aboutService.getAboutInformation().subscribe( + ( result ) => { + self.aboutInfo = result; + }, + ( error ) => { + this.logger.error( error, "Error getting about information."); + } + ); - /** - * Toggles a sub-menu off the main vertical left-hand menu bar. If the sub-menu is - * already selected, it de-selects it. - * @param subMenu the sub-menu to toggle - */ - /* - toggleSubMenu(subMenu: VerticalNavSubMenuType): void { - if (this.subMenuOut && this.currentSubMenu === subMenu) { - this.onShadeClick(); - } else { - this.currentSubMenu = subMenu; - this.subMenuOut = true; - } - } - */ + console.error( template ); + this.aboutRef = this.modalService.show( template ); + } } diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css index 5ec44c46..254c733d 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css @@ -6,10 +6,7 @@ .wiz-review-table-checked:before { display: inline-block; - margin-bottom: 0; - margin-left: 4px; - margin-right: 4px; - margin-top: 0; + margin: 0 4px; font-family: "FontAwesome"; content: "\f046"; color: green; @@ -21,10 +18,7 @@ .wiz-review-table-unchecked:before { display: inline-block; - margin-bottom: 0; - margin-left: 4px; - margin-right: 4px; - margin-top: 0; + margin: 0 4px; font-family: "FontAwesome"; content: "\f096"; } diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 42e1a10b..2c9ebeac 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -37,7 +37,6 @@ import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { VdbService } from "@dataservices/shared/vdb.service"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { WizardService } from "@dataservices/shared/wizard.service"; -import { LoadingState } from "@shared/loading-state.enum"; import { NotificationType, WizardComponent } from "patternfly-ng"; import { WizardEvent } from "patternfly-ng"; import { WizardStepConfig } from "patternfly-ng"; @@ -421,11 +420,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } public shouldCheck( table: Table ): boolean { - if ( this.selectedConnection && ( table.getConnection() === this.selectedConnection ) ) { - return true; - } - - return false; + return !!( this.selectedConnection && ( table.getConnection() === this.selectedConnection ) ); } /** diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html index 7bd062da..2d38b360 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html @@ -1,4 +1,4 @@ -
    +
  • diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 9454607f..51245eb7 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.css b/ngapp/src/app/dataservices/selected-table/selected-table.component.css index 00a8ce61..691e2b4b 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.css +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.css @@ -23,10 +23,7 @@ .selected-table-connection:before { display: inline-block; - margin-bottom: 0; - margin-left: 20px; - margin-right: 10px; - margin-top: 0; + margin: 0 10px 0 20px; font-family: "FontAwesome"; content: "\f1e6"; color: #666666; diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ngapp/src/app/dataservices/shared/dataservices-constants.ts index c7edf4fb..895a9c85 100644 --- a/ngapp/src/app/dataservices/shared/dataservices-constants.ts +++ b/ngapp/src/app/dataservices/shared/dataservices-constants.ts @@ -1,3 +1,5 @@ +import { NavigationItemConfig } from "patternfly-ng"; + /** * @license * Copyright 2017 JBoss Inc @@ -26,4 +28,10 @@ export class DataservicesConstants { public static readonly testDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/test-dataservice"; public static readonly testDataservicePath = DataservicesConstants.dataservicesRootPath + "/test-dataservice"; + public static readonly dataservicesNavItem: NavigationItemConfig = { + title: "Data Services", + iconStyleClass: "fa fa-fw fa-table", + url: DataservicesConstants.dataservicesRootPath + }; + } diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html index 387547e5..bef82751 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html @@ -1,4 +1,4 @@ -
    +
  • diff --git a/ngapp/src/assets/vdb.png b/ngapp/src/assets/vdb.png new file mode 100644 index 0000000000000000000000000000000000000000..2a369bf42273d715c75f4a7cabf1d7d2560720c4 GIT binary patch literal 2148 zcmaJ?eLU0q9^Xi1CaJFLpv-!Zu>F3FJ+vh@Pi5|`71cdzwqFd}Z?-YkWgbEzl;ni! z7wwjEP&}l;lV;2cL9To7K*iO1cK@kE#~sVAQ>hI3KocH*s<&NSd4&A!}>ch z0j8J^g$TS95@?sgm%~$p@yL9v%Qg%(nxYjDLNYEUS{N>pQle?tkGd4?e&HIA#e9Uw z!f4n(k_uq5FmzY~VVrP)Jr8gOG0p@WNC3zLvK__&00BJcfCq^7AV6^A`BF zN%)5-Y=+0DSlSZ}8zPg5DR{hGF2~6oaj+y950c4bJm7$LaIn`R?4>ax88_NqBwfF# zz<{JYi9jq9z#`0oA~y(*l+m!-O#diBDE=%fl74EFwqf{at{4yEfQ6D4flTKAhYE$C z(NY;3`ZM4EDJ1lERS^o_27D)-Qw-Q|J|jG^yx z!hslnfrt;wr62K3CdFGMm2pKp$eTgKY87w-0iWXG3V zqLT?u1khoT%Yb>2LP#WAz;+57t3)|1O)gC?@9};QZF45YWvT>jifmrg;o8iid?tPZ` z8*J{rrm4Pm>#$|oYHMcUfs)O}FE2259O*)lvau_?Ts1e74J-ySNLJai%cfYZUS<)d@{iiS}>qD)=ybN=OlLWO8WO+wth%<N)Mt zeRaC(gmHDdtuM(0eo>Gi2%t(eUsYSZu~**8DzN6qzqToUSOLPZ^L?uPq+de|bf-3y zh;Okw#Xl*FN{6a->{e->QZE(F=c2}&?Z}gLL{DqoZ#ZW=9ovK{v#;#EnnF!)*O_4( z1iIDwz`4YT&{p%DrkqsDWJ6%*KvnFDSP8P`RvGg8k}L05mhTl`+<#D1S&U?7C0TpK zM_W#vvyL|%^b`J7GH*+|ydxMLYp_`m>Q0ioB%E&EzLS|aok34GayfIRmklUu>A*>6lTCpN1EVS>dQ!6`gTG4M z3}l=O+|ZHqEHX1d5sx+2H@a5PUN@rB=dRvZl|Fx#NjiME+{7m9EyDLe^y)pDhGY@> zW_RPQnYhL-+p%v$b6Nkqk*b(LeqU+0rk4D#+FLkl_2v8rD!##$FqKz&nX#osD!48E z#I>?)3m@HgV}8}Aj9S!2&zB_ae0X#kAJSdy<+Cy+xV57oBIt0JQBlT7ltUd+uc!O< zvyg(7kH3`;_;=ODNR;3Ft%du1)QHp4soICh%Re}@){@p&cC)E%9OQ7k+Sk!l+u5WN z&wD&>`MdI(yjQqKM!17^b@e==R;QyJ=ki@W=bVZrGy^ z6xg%&4JU46cb<ix%m(2e-8BVx9is=1*=0SMv!j9i^L RUd6(H-`m}nQRQ|p@jpm+e1iZ0 literal 0 HcmV?d00001 From 1bb974925b0e5f652c8e97778c38c975a92aec45 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Thu, 18 Jan 2018 13:21:11 +0000 Subject: [PATCH 075/205] TEIIDTOOLS-307: Connects BTL to the teiid-komodo in Openshift * environment/* * Centralises references to komodoEngine and komodoRestVersion constants * Removes references to host and port as these are now accessible using api.service * api.service.ts * Provides method for fetching the base url of the application * app-settings.service.ts * Fetches the user profile from teiid-komodo, providing BTL with the user details including their workspace. --- ngapp/src/app/core/api.service.ts | 18 +++-- ngapp/src/app/core/app-settings.service.ts | 90 +++++++++++++++++----- ngapp/src/environments/environment.prod.ts | 16 +++- ngapp/src/environments/environment.ts | 16 +++- 4 files changed, 108 insertions(+), 32 deletions(-) diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index f2fb54cc..0abff1ea 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -29,20 +29,26 @@ export abstract class ApiService { protected appSettings: AppSettingsService; protected logger: LoggerService; - constructor( appSettings: AppSettingsService, logger: LoggerService ) { + constructor( appSettings: AppSettingsService, logger: LoggerService) { this.appSettings = appSettings; this.logger = logger; } /** - * Get the Auth RequestOptions - * TODO: User and password are currently hardcoded to the DSB kit server credentials (dsbUser | 1demo-user1) + * @returns the base url of the application + */ + protected getBaseUrl(): string { + return window.location.protocol + '://' + window.location.hostname; + } + + /** + * Get the Auth RequestOptions if any + * Note: Since usage of the oauth-proxy no additional auth request options are necessary + * * @returns {RequestOptions} */ protected getAuthRequestOptions(): RequestOptions { - const userPasswordStr = this.appSettings.getKomodoUser() + ":" + this.appSettings.getKomodoUserPassword(); - const headers = new Headers({ "Authorization": "Basic " + btoa(userPasswordStr) }); - return new RequestOptions({ headers }); + return this.appSettings.getAuthRequestOptions(); } /** diff --git a/ngapp/src/app/core/app-settings.service.ts b/ngapp/src/app/core/app-settings.service.ts index d6d95b04..37244b78 100644 --- a/ngapp/src/app/core/app-settings.service.ts +++ b/ngapp/src/app/core/app-settings.service.ts @@ -16,7 +16,12 @@ */ import { Injectable } from "@angular/core"; +import { Http, Headers, RequestOptions, Response } from "@angular/http"; +import { LoggerService } from "@core/logger.service"; import { LayoutType } from "@shared/layout-type.enum"; +import { Observable } from "rxjs/Observable"; +import { ErrorObservable } from "rxjs/observable/ErrorObservable"; +import { environment } from "@environments/environment"; @Injectable() export class AppSettingsService { @@ -30,20 +35,24 @@ export class AppSettingsService { public readonly GIT_REPO_PATH_KEY = "repo-path-property"; public readonly GIT_REPO_FILE_PATH_KEY = "file-path-property"; - private readonly komodoRoot = "tko:komodo/tko:workspace"; - - // TODO: temporary location for user and password - private readonly komodoUser = "dsbUser"; - private readonly komodoUserPassword = "1demo-user1"; - // Map to maintain the target git repository properties private readonly gitRepoProperties: Map; + private static readonly userProfileUrl = environment.komodoServiceUrl + "/userProfile"; + // page layouts private svcPageLayout: LayoutType = LayoutType.CARD; private connPageLayout: LayoutType = LayoutType.CARD; - constructor() { + private http: Http; + private logger: LoggerService; + + private userProfile: Object; + + constructor(http: Http, logger: LoggerService) { + this.http = http; + this.logger = logger; + // TODO: The git repository properties will be picked up based on the Openshift install location this.gitRepoProperties = new Map(); this.gitRepoProperties.set(this.GIT_REPO_PATH_KEY, "https://github.com/GIT_USER/GIT_REPO"); @@ -52,30 +61,75 @@ export class AppSettingsService { this.gitRepoProperties.set(this.GIT_REPO_PASSWORD_KEY, "MY_PASS"); this.gitRepoProperties.set(this.GIT_REPO_AUTHOR_NAME_KEY, "MY_USER"); this.gitRepoProperties.set(this.GIT_REPO_AUTHOR_EMAIL_KEY, "USER@SOMEWHERE.COM"); + + // + // Do a call to fetch the user profile on init of service. + // The fetchProfile method returns an observable + // which we subscribe to and on completion assigns the variable + // values accordingly + // + this.fetchUserProfile().subscribe( + (profile) => { + this.userProfile = profile; + }, + (error) => { + this.logger.error( "[fetchUserProfile] Error: %o", error ); + }); } - /* - * Get the komodo workspace path for the current user - * @returns {string} the komodo workspace path + private handleError(error: Response): ErrorObservable { + this.logger.error( this.constructor.name + "::handleError" ); + return Observable.throw(error); + } + + private fetchUserProfile(): Observable { + return this.http.get(AppSettingsService.userProfileUrl, this.getAuthRequestOptions()) + .map((response) => { + const userInfo = response.json(); + return userInfo.Information; + }) + .catch((error) => this.handleError(error)); + } + + /** + * Get the Auth RequestOptions if any + * Note: Since usage of the oauth-proxy no additional auth request options are necessary + * + * @returns {RequestOptions} */ - public getKomodoUserWorkspacePath( ): string { - return this.komodoRoot + "/" + this.komodoUser; + public getAuthRequestOptions(): RequestOptions { + const headers = new Headers({}); + return new RequestOptions({ headers }); } /* * Get the logged in komodo user * @returns {string} the komodo user */ - public getKomodoUser( ): string { - return this.komodoUser; + public getKomodoUser(): string { + if (! this.userProfile) + throw new Error('Failed to retrieve the user profile so cannot provide a user name'); + + let komodoUser = this.userProfile['User Name']; + if (! komodoUser) + throw new Error('Failed to retrieve the user name from the user profile'); + + return komodoUser; } /* - * Get the logged in komodo user password - * @returns {string} the komodo user password + * Get the komodo workspace path for the current user + * @returns {string} the komodo workspace path */ - public getKomodoUserPassword( ): string { - return this.komodoUserPassword; + public getKomodoUserWorkspacePath(): string { + if (! this.userProfile) + throw new Error('Failed to retrieve the user profile so cannot provide a workspace path'); + + let workspace = this.userProfile['Workspace']; + if (! workspace) + throw new Error('Failed to retrieve the workspace path from the user profile'); + + return workspace; } /* diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts index 0532bbc8..c59cdcdf 100644 --- a/ngapp/src/environments/environment.prod.ts +++ b/ngapp/src/environments/environment.prod.ts @@ -17,23 +17,31 @@ import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; +export const komodoEngine = "vdb-builder"; + +export const komodoRestVersion = "v1"; + export const environment = { production: true, + komodoEngine: komodoEngine, + + komodoRestVersion: komodoRestVersion, + // the home page path homePagePath: DataservicesConstants.dataservicesRootPath, // REST URL - Komodo import export url - komodoImportExportUrl: "https://localhost:8443/vdb-builder/v1/importexport", + komodoImportExportUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/importexport", // REST URL - Komodo workspace - komodoWorkspaceUrl: "https://localhost:8443/vdb-builder/v1/workspace", + komodoWorkspaceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/workspace", // REST URL - Komodo teiid server - komodoTeiidUrl: "https://localhost:8443/vdb-builder/v1/teiid", + komodoTeiidUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/teiid", // REST URL - Komodo service - komodoServiceUrl: "https://localhost:8443/vdb-builder/v1/service", + komodoServiceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/service" }; diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index b5154bc5..b9045402 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -21,22 +21,30 @@ import { DataservicesConstants } from "@dataservices/shared/dataservices-constan // `ng build --env=prod` then `environment.prod.ts` will be used instead. // The list of which env maps to which file can be found in `.angular-cli.json`. +export const komodoEngine = "vdb-builder"; + +export const komodoRestVersion = "v1"; + export const environment = { production: false, + komodoEngine: komodoEngine, + + komodoRestVersion: komodoRestVersion, + // the home page path homePagePath: DataservicesConstants.dataservicesRootPath, // REST URL - Komodo import export url - komodoImportExportUrl: "https://localhost:8443/vdb-builder/v1/importexport", + komodoImportExportUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/importexport", // REST URL - Komodo workspace - komodoWorkspaceUrl: "https://localhost:8443/vdb-builder/v1/workspace", + komodoWorkspaceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/workspace", // REST URL - Komodo teiid server - komodoTeiidUrl: "https://localhost:8443/vdb-builder/v1/teiid", + komodoTeiidUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/teiid", // REST URL - Komodo service - komodoServiceUrl: "https://localhost:8443/vdb-builder/v1/service", + komodoServiceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/service" }; From 21c90dd02ab9f448467aea8bbc5cfd061baec3f8 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 25 Jan 2018 11:57:32 -0600 Subject: [PATCH 076/205] minor fix to setup script --- ngapp/src/environments/environment.prod.ts | 2 +- ngapp/src/environments/environment.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts index c59cdcdf..78e09192 100644 --- a/ngapp/src/environments/environment.prod.ts +++ b/ngapp/src/environments/environment.prod.ts @@ -39,7 +39,7 @@ export const environment = { komodoWorkspaceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/workspace", // REST URL - Komodo teiid server - komodoTeiidUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/teiid", + komodoTeiidUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/metadata", // REST URL - Komodo service komodoServiceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/service" diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index b9045402..7716d294 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -42,7 +42,7 @@ export const environment = { komodoWorkspaceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/workspace", // REST URL - Komodo teiid server - komodoTeiidUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/teiid", + komodoTeiidUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/metadata", // REST URL - Komodo service komodoServiceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/service" From fc85400b2db7c2b2f0a53c88a239b36e39459c44 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 26 Jan 2018 16:04:23 -0600 Subject: [PATCH 077/205] TEIIDTOOLS-324 Convert Non-Patternfly 2+ Components to Patternfly NG Components If Available - converted Dataservice card to patternfly-ng component - updated ngx-bootstrap - updated About dialog because of new version of ngx-bootstrap - replace component with
    @@ -53,11 +53,10 @@

    {{ step2InstructionMessage }}

    title="Select the connection whose tables will be included in the dataservice"> Connection -
    +
    @@ -66,7 +65,7 @@

    {{ step2InstructionMessage }}

    -
    +
    {{ table.getName() }} ( {{ table.getConnection().getId() }} ) diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css new file mode 100644 index 00000000..8e8ab67d --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -0,0 +1,116 @@ +:root { + --body-main-color: #dc7039; + --border-color: #39a5dc; + --border-style: double; + --border-width: 2px; + --hover-color: rgb(221, 234, 255); +} + +.dataservice-card { + -webkit-transition: background-color 300ms; + -moz-transition: background-color 300ms; +//-ms-transition: background-color 300ms; + -o-transition: background-color 300ms; + transition: background-color 300ms; + height: 160px; +} + +.dataservice-card-selected { +} + +.dataservice-card-toolbar { + border-bottom: 1px solid lightgrey; + margin-bottom: 6px; + margin-top: 0; +} + +.dataservice-card-toolbar:hover { + background-color: var(--hover-color); +} + +.dataservice-card-toolbar-kebab { + margin-left: 0 !important; + margin-right: 4px; +} + +.dataservice-card-action-icon { + color: var(--border-color); + cursor: pointer; + font-size: 1.5em; + height: 24px !important; + margin-left: 0 !important; + margin-top: 4px; + width: 24px !important; +} + +.dataservice-card-action-disabled-icon { + color: lightgray; + font-size: 1.5em; + height: 24px !important; + margin-left: 4px; + margin-top: 4px; + width: 24px !important; +} + +.dataservice-card-icon { + border: 2px solid var(--border-color); + border-radius: 60px; + display: inline-block; + padding: 0.1em 0.2em; +} + +.dataservice-card-title { + font-size: 16px; + font-weight: bold; +} + +.dataservice-card .card-pf .card-pf-heading:hover { + background-color: var(--hover-color); +} + +.dataservice-card-selected .card-pf .card-pf-heading { + border-right: var(--border-width) var(--border-style) var(--border-color); + border-left: var(--border-width) var(--border-style) var(--border-color); +} + +.dataservice-card .card-pf .card-pf-footer { + margin: 0 !important; + min-height: 20px; + padding: 10px 0 5px 20px; +} + +.dataservice-card-selected .card-pf .card-pf-footer { + border-right: var(--border-width) var(--border-style) var(--border-color); + border-left: var(--border-width) var(--border-style) var(--border-color); +} + +.dataservice-card-body .list-pf-container { + margin: 0 !important; + padding: 4px 10px; +} + +.dataservice-card-body-title { + background-color: var(--body-main-color); + color: white; + margin: 4px 4px !important; + text-align: center; +} + +div .dataservice-card-body-title { + border-right: var(--border-width) var(--border-style) var(--border-color); + border-left: var(--border-width) var(--border-style) var(--border-color); + margin: 0 !important; +} + +.dataservice-card-description { + color: slategray; + height: 50px; + margin-bottom: 8px; + overflow: scroll; + padding: 0 5px 5px 5px; +} + +.view-name { + cursor: pointer; + color: var(--body-main-color); +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html new file mode 100644 index 00000000..4d0c981c --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -0,0 +1,164 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +
    {{ description }}
    +
    +
    +
    +
    +
    Views
    +
    +
    + + +
    + {{ item }} +
    + + + + + + + +
    + +
    +
    + {{ connection.getId() }} +
    +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.spec.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.spec.ts new file mode 100644 index 00000000..4556a8e7 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.spec.ts @@ -0,0 +1,35 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterTestingModule } from "@angular/router/testing"; +import { DataserviceCardComponent } from "@dataservices/dataservices-cards/dataservice-card/dataservice-card.component"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { PatternFlyNgModule } from "patternfly-ng"; + +describe("DataserviceCardComponent", () => { + let component: DataserviceCardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ PatternFlyNgModule, RouterTestingModule ], + declarations: [ DataserviceCardComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DataserviceCardComponent); + component = fixture.componentInstance; + + const ds = new Dataservice(); + ds.setId("serv1"); + component.dataservice = ds; + + component.selectedDataservices = []; + fixture.detectChanges(); + }); + + it("should be created", () => { + console.log("========== [DataserviceCardComponent] should be created"); + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts new file mode 100644 index 00000000..6aba4919 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts @@ -0,0 +1,170 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { CardAction, CardConfig, ListConfig } from "patternfly-ng"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-dataservice-card-component", + templateUrl: "./dataservice-card.component.html", + styleUrls: ["./dataservice-card.component.css"] +}) +export class DataserviceCardComponent implements OnInit { + + public static readonly activateDataserviceEvent = "activate"; + public static readonly deleteDataserviceEvent = "delete"; + public static readonly editDataserviceEvent = "edit"; + public static readonly publishDataserviceEvent = "publish"; + public static readonly quickLookDataserviceEvent = "quickLook"; + public static readonly testDataserviceEvent = "test"; + + public readonly activateEvent = DataserviceCardComponent.activateDataserviceEvent; + public readonly deleteEvent = DataserviceCardComponent.deleteDataserviceEvent; + public readonly editEvent = DataserviceCardComponent.editDataserviceEvent; + public readonly publishEvent = DataserviceCardComponent.publishDataserviceEvent; + public readonly quickLookEvent = DataserviceCardComponent.quickLookDataserviceEvent; + public readonly testEvent = DataserviceCardComponent.testDataserviceEvent; + + @Input() public dataservice: Dataservice; + @Input() public selectedDataservices: Dataservice[]; + @Output() public cardEvent: EventEmitter< {} > = new EventEmitter< {} >(); + @Output() public selectEvent: EventEmitter< Dataservice > = new EventEmitter< Dataservice >(); + + public cardConfig: CardConfig; + public listConfig: ListConfig; + public showDetails = false; + + constructor() { + // nothing to do + } + + /** + * @returns {string} the dataservice description + */ + public get description(): string { + return this.dataservice.getDescription(); + } + + /** + * @param {string} view the view whose connections are being requested + * @returns {Connection[]} the connections of the dataservice represented by this card + */ + public getConnections( view: string ): Connection[] { + // TODO rewrite when REST functionality has been implemented + const result: Connection[] = []; + + const c1 = new Connection(); + c1.setId( "ConnectionOne" ); + result.push( c1 ); + + const c2 = new Connection(); + c2.setId( "ConnectionTwo" ); + result.push( c2 ); + + const c3 = new Connection(); + c3.setId( "ConnectionThree" ); + result.push( c3 ); + + return result; + } + + /** + * @param {Dataservice} ds the dataservice whose views are being requested + * @returns {string[]} the names of the views + */ + public getViews( ds: Dataservice ): string[] { + // TODO rewrite when REST functionality has been implemented + const result: string[] = []; + + const v1 = "ViewOne"; + result.push( v1 ); + + const v2 = "ViewTwo"; + result.push( v2 ); + + const v3 = "ViewThree"; + result.push( v3 ); + + const v4 = "ViewFour"; + result.push( v4 ); + + return result; + } + + /** + * @returns {boolean} `true` if the dataservice represented by this card is selected + */ + public isSelected(): boolean { + return this.selectedDataservices.indexOf( this.dataservice ) !== -1; + } + + public ngOnInit(): void { + this.cardConfig = { + action: { + id: "showDetails", + hypertext: this.showDetailsTitle, + iconStyleClass: "fa fa-info-circle" + }, + titleBorder: true, + noPadding: true, + topBorder: true + } as CardConfig; + + this.listConfig = { + dblClick: false, + multiSelect: false, + selectItems: false, + showCheckbox: false, + useExpandItems: false + } as ListConfig; + } + + /** + * An event handler for when a toolbar action is invoked. + * @param {string} type the type of event being processed + */ + public onClick( type: string ): void { + this.cardEvent.emit( { eventType: type, dataserviceName: this.dataservice.getId() } ); + } + + /** + * An event handler for when the card is clicked. + */ + public onSelect(): void { + this.selectEvent.emit( this.dataservice ); + } + + /** + * An event handler for footer action link. + * @param {CardAction} $event the event being processed + */ + public onShowDetails( $event: CardAction ): void { + this.showDetails = !this.showDetails; + $event.hypertext = this.showDetailsTitle; + } + + /** + * @returns {string} the footer details action text + */ + public get showDetailsTitle(): string { + return this.showDetails ? "Hide Details" : "Show Details"; + } + +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css index 57375581..8abeffb9 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css @@ -6,71 +6,3 @@ .row-cards-pf { padding: 0; } - -.dataservice-card-action-icon { - cursor: pointer; - margin-left: 10px; -} - -.dataservice-card-action-disabled-icon { - color: lightgray; - margin-left: 10px; -} - -.dataservice-card-icon { - border: 2px solid #39a5dc; - border-radius: 50%; - padding: 5px; - margin-right: 10px; - width: 32px; -} - -.dataservice-card .dataservice-card-title { - font-size: 16px; - font-weight: bold; -} - -.dataservice-card { - -webkit-transition: background-color 300ms; - -moz-transition: background-color 300ms; - //-ms-transition: background-color 300ms; - -o-transition: background-color 300ms; - transition: background-color 300ms; - height: 160px; -} -.dataservice-card:hover { - background-color: rgb(237, 237, 237); -} - -.dataservice-card.active { - background-color: rgb(221, 234, 255); -} - -/* -.dataservice-description { - font-size: 13px; - overflow-y: auto; -} -*/ - -.dataservice-card .dataservice-tags { - margin-bottom: 8px; -} -.dataservice-card .dataservice-tags .dataservice-tags-label { - font-weight: bold; - margin-right: 5px; -} -.dataservice-card .dataservice-tags /*.dataservice-tag*/ { - margin-right: 5px; - border: 1px solid #ccc; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - padding: 2px 4px; -} -.dataservice-card .dataservice-tags /*.dataservice-tag:hover*/ { - cursor: pointer; - background-color: #0088ce; - border-color: #00659c; - color: white; -} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html index ac4abb68..e0f133ca 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html @@ -1,51 +1,8 @@ -
    -
    - -
    -
    -
    - -

    - - - - - - - - {{ dataservice.getId() }} - - - - - - - - -

    -
    -
    - - -
    -
    - {{ dataservice.getDescription() }} -
    -
    - - {{dataservice.getServiceViewTables()[0]}} - {{dataservice.getServiceViewTables()[0]}}, {{dataservice.getServiceViewTables()[1]}} -
    - -
    -
    -
    - +
    +
    +
    diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts index 1a89f696..b4dbc3da 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts @@ -1,6 +1,9 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; +import { LoggerService } from "@core/logger.service"; +import { DataserviceCardComponent } from "@dataservices/dataservices-cards/dataservice-card/dataservice-card.component"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; +import { PatternFlyNgModule } from "patternfly-ng"; describe("DataservicesCardsComponent", () => { let component: DataservicesCardsComponent; @@ -8,8 +11,9 @@ describe("DataservicesCardsComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ RouterTestingModule ], - declarations: [ DataservicesCardsComponent ] + imports: [ RouterTestingModule, PatternFlyNgModule ], + declarations: [ DataservicesCardsComponent, DataserviceCardComponent ], + providers: [ LoggerService ] }) .compileComponents().then(() => { // nothing to do diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts index bc2a5876..0f0617c3 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts @@ -15,11 +15,14 @@ * limitations under the License. */ -import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { Component, EventEmitter, Input, Output, ViewEncapsulation } from "@angular/core"; +import { LoggerService } from "@core/logger.service"; +import { DataserviceCardComponent } from "@dataservices/dataservices-cards/dataservice-card/dataservice-card.component"; import { Dataservice } from "@dataservices/shared/dataservice.model"; @Component({ moduleId: module.id, + encapsulation: ViewEncapsulation.None, selector: "app-dataservices-cards", templateUrl: "dataservices-cards.component.html", styleUrls: ["dataservices-cards.component.css"] @@ -30,7 +33,6 @@ export class DataservicesCardsComponent { @Input() public selectedDataservices: Dataservice[]; @Output() public dataserviceSelected: EventEmitter = new EventEmitter(); @Output() public dataserviceDeselected: EventEmitter = new EventEmitter(); - @Output() public tagSelected: EventEmitter = new EventEmitter(); @Output() public activateDataservice: EventEmitter = new EventEmitter(); @Output() public testDataservice: EventEmitter = new EventEmitter(); @Output() public publishDataservice: EventEmitter = new EventEmitter(); @@ -38,53 +40,47 @@ export class DataservicesCardsComponent { @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); + public logger: LoggerService; + /** - * Constructor. + * @param {LoggerService} logger the logging service */ - constructor() { - // nothing to do - } - - public toggleDataserviceSelected(dataservice: Dataservice): void { - if (this.isSelected(dataservice)) { - this.dataserviceDeselected.emit(dataservice); - } else { - this.dataserviceSelected.emit(dataservice); - } - } - - public isSelected(dataservice: Dataservice): boolean { - return this.selectedDataservices.indexOf(dataservice) !== -1; - } - - public onActivateDataservice(dataserviceName: string): void { - this.activateDataservice.emit(dataserviceName); + constructor( logger: LoggerService ) { + this.logger = logger; } - public onTestDataservice(dataserviceName: string): void { - this.testDataservice.emit(dataserviceName); + public isSelected( dataservice: Dataservice ): boolean { + return this.selectedDataservices.indexOf( dataservice ) !== -1; } - public onPublishDataservice(dataserviceName: string): void { - this.publishDataservice.emit(dataserviceName); - } - - public onDeleteDataservice(dataserviceName: string): void { - this.deleteDataservice.emit(dataserviceName); - } - - public onEditDataservice(dataserviceName: string): void { - this.editDataservice.emit(dataserviceName); - } - - public onQuickLookDataservice(dataserviceName: string): void { - this.quickLookDataservice.emit(dataserviceName); + public onCardEvent( event: { eventType: string, dataserviceName: string } ): void { + switch ( event.eventType ) { + case DataserviceCardComponent.activateDataserviceEvent: + this.activateDataservice.emit( event.dataserviceName ); + break; + case DataserviceCardComponent.deleteDataserviceEvent: + this.deleteDataservice.emit( event.dataserviceName ); + break; + case DataserviceCardComponent.editDataserviceEvent: + this.editDataservice.emit( event.dataserviceName ); + break; + case DataserviceCardComponent.publishDataserviceEvent: + this.publishDataservice.emit( event.dataserviceName ); + break; + case DataserviceCardComponent.quickLookDataserviceEvent: + this.quickLookDataservice.emit( event.dataserviceName ); + break; + case DataserviceCardComponent.testDataserviceEvent: + this.testDataservice.emit( event.dataserviceName ); + break; + default: + this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); + break; + } } - public onSelectTag(tag: string, event: MouseEvent): void { - event.stopPropagation(); - event.preventDefault(); - this.tagSelected.emit(tag); + public onSelectEvent( dataservice: Dataservice ): void { + this.dataserviceSelected.emit( dataservice ); } } diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 51245eb7..030799d5 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index 18e7dd36..d399bca5 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -5,6 +5,7 @@ import { By } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { DataserviceCardComponent } from "@dataservices/dataservices-cards/dataservice-card/dataservice-card.component"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; import { DataservicesComponent } from "@dataservices/dataservices.component"; @@ -29,7 +30,11 @@ describe("DataservicesComponent", () => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), PatternFlyNgModule, RouterTestingModule, SharedModule, CodemirrorModule, NgxDatatableModule ], - declarations: [ DataservicesComponent, DataservicesListComponent, DataservicesCardsComponent, SqlControlComponent ], + declarations: [ DataservicesComponent, + DataservicesListComponent, + DataservicesCardsComponent, + DataserviceCardComponent, + SqlControlComponent ], providers: [ AppSettingsService, NotifierService, @@ -79,7 +84,7 @@ describe("DataservicesComponent", () => { expect(dataservices.length).toEqual(3); // Check html has the same number of dataservice cards - const cardDebugElems = fixture.debugElement.queryAll(By.css(".dataservice-card-title")); + const cardDebugElems = fixture.debugElement.queryAll(By.css(".dataservice-card")); expect(cardDebugElems).toBeDefined(); expect(cardDebugElems.length).toEqual(3); }); diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 9d0ea5a6..27e9838b 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -264,7 +264,7 @@ export class DataservicesComponent extends AbstractPageComponent { this.setQuickLookPanelOpenState(false); const link: string[] = [ DataservicesConstants.testDataservicePath ]; - this.logger.log("[DataservicesPageComponent] Navigating to: %o", link); + this.logger.debug("[DataservicesPageComponent] Navigating to: %o", link); this.router.navigate(link).then(() => { // nothing to do }); diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 73b95660..2745f35b 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -36,6 +36,7 @@ import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard/add-dataservice-wizard.component"; import { AddDataserviceComponent } from "./add-dataservice/add-dataservice.component"; import { ConnectionTableSelectorComponent } from "./connection-table-selector/connection-table-selector.component"; +import { DataserviceCardComponent } from "./dataservices-cards/dataservice-card/dataservice-card.component"; import { JdbcTableSelectorComponent } from "./jdbc-table-selector/jdbc-table-selector.component"; import { SelectedTableComponent } from "./selected-table/selected-table.component"; import { SqlControlComponent } from "./sql-control/sql-control.component"; @@ -64,7 +65,8 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co JdbcTableSelectorComponent, TestDataserviceComponent, SqlControlComponent, - SelectedTableComponent + SelectedTableComponent, + DataserviceCardComponent ], providers: [ DataserviceService, diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 6021b948..5c37ceec 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -15,8 +15,6 @@ * limitations under the License. */ -import { ReflectiveInjector } from "@angular/core"; -import { AppSettingsService } from "@core/app-settings.service"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; import { Identifiable } from "@shared/identifiable"; import { SortDirection } from "@shared/sort-direction.enum"; @@ -31,7 +29,6 @@ export class Dataservice implements Identifiable< string > { private serviceViewModel: string; private serviceViewTables: string[]; private deploymentState: DeploymentState = DeploymentState.LOADING; - private appSettings: AppSettingsService; /** * @param {Object} json the JSON representation of a Dataservice @@ -61,8 +58,7 @@ export class Dataservice implements Identifiable< string > { } constructor( ) { - const injector = ReflectiveInjector.resolveAndCreate([AppSettingsService]); - this.appSettings = injector.get(AppSettingsService); + // nothing to do } /** @@ -136,13 +132,6 @@ export class Dataservice implements Identifiable< string > { return this.serviceViewTables; } - /** - * @returns {string} the dataservice dataPath (can be null) - */ - public getDataPath(): string { - return this.appSettings.getKomodoUserWorkspacePath() + "/" + this.keng__id; - } - /** * @returns {string} the dataservice type name (can be null) */ diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts index 455c3104..b3f29ea6 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts @@ -1,5 +1,4 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; - import { FormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { CoreModule } from "@core/core.module"; diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index 7716d294..e454c3b2 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -28,9 +28,9 @@ export const komodoRestVersion = "v1"; export const environment = { production: false, - komodoEngine: komodoEngine, + komodoEngine, - komodoRestVersion: komodoRestVersion, + komodoRestVersion, // the home page path homePagePath: DataservicesConstants.dataservicesRootPath, From 5956771722aacdc47584ad7c9f923a125f795e69 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 30 Jan 2018 18:08:15 -0600 Subject: [PATCH 078/205] changes for local dev --- .../src/app/core/app-settings.service.spec.ts | 2 +- ngapp/src/app/core/app-settings.service.ts | 4 ++-- .../src/app/core/mock-app-settings.service.ts | 2 +- ngapp/src/environments/environment.prod.ts | 23 ++++++++++++++----- ngapp/src/environments/environment.ts | 19 +++++++++++---- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/ngapp/src/app/core/app-settings.service.spec.ts b/ngapp/src/app/core/app-settings.service.spec.ts index 36d17ee9..792aa941 100644 --- a/ngapp/src/app/core/app-settings.service.spec.ts +++ b/ngapp/src/app/core/app-settings.service.spec.ts @@ -1,5 +1,5 @@ import { inject, TestBed } from "@angular/core/testing"; -import { HttpModule} from "@angular/http"; +import { HttpModule } from "@angular/http"; import { LoggerService } from "@core/logger.service"; import { AppSettingsService } from "./app-settings.service"; diff --git a/ngapp/src/app/core/app-settings.service.ts b/ngapp/src/app/core/app-settings.service.ts index 0e091b35..d13268d5 100644 --- a/ngapp/src/app/core/app-settings.service.ts +++ b/ngapp/src/app/core/app-settings.service.ts @@ -37,7 +37,7 @@ export class AppSettingsService implements OnInit { public readonly GIT_REPO_PATH_KEY = "repo-path-property"; public readonly GIT_REPO_FILE_PATH_KEY = "file-path-property"; - protected userProfile: Object; + protected userProfile: object; // Map to maintain the target git repository properties private readonly gitRepoProperties: Map; @@ -79,7 +79,7 @@ export class AppSettingsService implements OnInit { } ); } - protected fetchUserProfile(): Observable { + protected fetchUserProfile(): Observable { return this.http.get(AppSettingsService.userProfileUrl, this.getAuthRequestOptions()) .map((response) => { const userInfo = response.json(); diff --git a/ngapp/src/app/core/mock-app-settings.service.ts b/ngapp/src/app/core/mock-app-settings.service.ts index 7c5b6dfa..dc4206d5 100644 --- a/ngapp/src/app/core/mock-app-settings.service.ts +++ b/ngapp/src/app/core/mock-app-settings.service.ts @@ -21,7 +21,7 @@ export class MockAppSettingsService extends AppSettingsService implements OnInit super( http, logger ); } - protected fetchUserProfile(): Observable< Object > { + protected fetchUserProfile(): Observable< object > { return Observable.of( this.userProfile ); } diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts index 78e09192..73c26c4f 100644 --- a/ngapp/src/environments/environment.prod.ts +++ b/ngapp/src/environments/environment.prod.ts @@ -21,27 +21,38 @@ export const komodoEngine = "vdb-builder"; export const komodoRestVersion = "v1"; +export const localKomodoPrefix = "http://localhost:8080/"; + +export const openshiftKomodoPrefix = "/"; + +// ----------------------------------------------------------- +// komodoUrlPrefix +// - openshiftKomodoPrefix (openshift deployment) +// - localKomodoPrefix (development on local teiid-komodo) +// ----------------------------------------------------------- +export const komodoUrlPrefix = openshiftKomodoPrefix; + export const environment = { production: true, - komodoEngine: komodoEngine, + komodoEngine, - komodoRestVersion: komodoRestVersion, + komodoRestVersion, // the home page path homePagePath: DataservicesConstants.dataservicesRootPath, // REST URL - Komodo import export url - komodoImportExportUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/importexport", + komodoImportExportUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/importexport", // REST URL - Komodo workspace - komodoWorkspaceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/workspace", + komodoWorkspaceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/workspace", // REST URL - Komodo teiid server - komodoTeiidUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/metadata", + komodoTeiidUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/metadata", // REST URL - Komodo service - komodoServiceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/service" + komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service" }; diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index e454c3b2..dea1a9bf 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -25,6 +25,17 @@ export const komodoEngine = "vdb-builder"; export const komodoRestVersion = "v1"; +export const localKomodoPrefix = "http://localhost:8080/"; + +export const openshiftKomodoPrefix = "/"; + +// ----------------------------------------------------------- +// komodoUrlPrefix +// - openshiftKomodoPrefix (openshift deployment) +// - localKomodoPrefix (development on local teiid-komodo) +// ----------------------------------------------------------- +export const komodoUrlPrefix = openshiftKomodoPrefix; + export const environment = { production: false, @@ -36,15 +47,15 @@ export const environment = { homePagePath: DataservicesConstants.dataservicesRootPath, // REST URL - Komodo import export url - komodoImportExportUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/importexport", + komodoImportExportUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/importexport", // REST URL - Komodo workspace - komodoWorkspaceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/workspace", + komodoWorkspaceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/workspace", // REST URL - Komodo teiid server - komodoTeiidUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/metadata", + komodoTeiidUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/metadata", // REST URL - Komodo service - komodoServiceUrl: "/" + komodoEngine + "/" + komodoRestVersion + "/service" + komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service" }; From b57b78e5a4ca8092e6d575448b8b5cd8a20c0399 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 25 Jan 2018 09:23:14 -0600 Subject: [PATCH 079/205] initial commit of multi view support --- .../add-connection-wizard.component.ts | 2 +- .../connections/shared/connection.service.ts | 28 +++++++++ .../shared/connections-constants.ts | 3 + ngapp/src/app/core/app-settings.service.ts | 8 ++- .../add-dataservice-wizard.component.ts | 28 ++++----- .../dataservices/shared/dataservice.model.ts | 16 ++--- .../shared/dataservice.service.ts | 59 +++++++++++++------ .../shared/mock-dataservice.service.ts | 8 ++- .../dataservices/shared/mock-vdb.service.ts | 4 +- .../shared/new-dataservice.model.ts | 13 ++-- .../app/dataservices/shared/vdb.service.ts | 29 ++++----- 11 files changed, 124 insertions(+), 74 deletions(-) diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index 5d47ea6d..9fd61db0 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -285,7 +285,7 @@ export class AddConnectionWizardComponent implements OnInit { const self = this; this.connectionService - .createConnection(connection) + .createAndDeployConnection(connection) .subscribe( (wasSuccess) => { self.createComplete = true; diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index 5ba653f4..49291ded 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -26,6 +26,7 @@ import { TemplateDefinition } from "@connections/shared/template-definition.mode import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { Table } from "@dataservices/shared/table.model"; import { environment } from "@environments/environment"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; import { Observable } from "rxjs/Observable"; @@ -69,6 +70,22 @@ export class ConnectionService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Deploy a connection via the komodo rest interface + * @param {string} connectionName + * @returns {Observable} + */ + public deployConnection(connectionName: string): Observable { + const connectionPath = this.getKomodoUserWorkspacePath() + "/" + connectionName; + return this.http + .post(environment.komodoTeiidUrl + ConnectionsConstants.connectionRootPath, + { path: connectionPath}, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + /** * Delete a connection via the komodo rest interface * @param {string} connectionId @@ -153,4 +170,15 @@ export class ConnectionService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Create a connection and deploy it to server via the komodo rest interface + * @param {NewConnection} connection + * @returns {Observable} + */ + public createAndDeployConnection(connection: NewConnection): Observable { + // Chain the individual calls together in series to build the DataService + return this.createConnection(connection) + .flatMap((res) => this.deployConnection(connection.getName())); + } + } diff --git a/ngapp/src/app/connections/shared/connections-constants.ts b/ngapp/src/app/connections/shared/connections-constants.ts index ca7c321a..61a7d098 100644 --- a/ngapp/src/app/connections/shared/connections-constants.ts +++ b/ngapp/src/app/connections/shared/connections-constants.ts @@ -17,6 +17,9 @@ export class ConnectionsConstants { public static readonly connectionsRootRoute = "connections"; public static readonly connectionsRootPath = "/" + ConnectionsConstants.connectionsRootRoute; + public static readonly connectionRootRoute = "connection"; + public static readonly connectionRootPath = "/" + ConnectionsConstants.connectionRootRoute; + public static readonly addConnectionRoute = ConnectionsConstants.connectionsRootRoute + "/add-connection"; public static readonly addConnectionPath = ConnectionsConstants.connectionsRootPath + "/add-connection"; diff --git a/ngapp/src/app/core/app-settings.service.ts b/ngapp/src/app/core/app-settings.service.ts index d13268d5..23b915d7 100644 --- a/ngapp/src/app/core/app-settings.service.ts +++ b/ngapp/src/app/core/app-settings.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Injectable, OnInit } from "@angular/core"; +import { Injectable } from "@angular/core"; import { Headers, Http, RequestOptions, Response } from "@angular/http"; import { LoggerService } from "@core/logger.service"; import { environment } from "@environments/environment"; @@ -24,7 +24,7 @@ import { Observable } from "rxjs/Observable"; import { ErrorObservable } from "rxjs/observable/ErrorObservable"; @Injectable() -export class AppSettingsService implements OnInit { +export class AppSettingsService { private static readonly userProfileUrl = environment.komodoServiceUrl + "/userProfile"; @@ -61,9 +61,11 @@ export class AppSettingsService implements OnInit { this.gitRepoProperties.set(this.GIT_REPO_PASSWORD_KEY, "MY_PASS"); this.gitRepoProperties.set(this.GIT_REPO_AUTHOR_NAME_KEY, "MY_USER"); this.gitRepoProperties.set(this.GIT_REPO_AUTHOR_EMAIL_KEY, "USER@SOMEWHERE.COM"); + + this.initUserProfile(); } - public ngOnInit(): void { + public initUserProfile(): void { // // Do a call to fetch the user profile on init of service. // The fetchProfile method returns an observable diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 2c9ebeac..fb436a49 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -287,7 +287,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { const self = this; this.vdbService - .deployVdbForTable(this.tableSelector.getSelectedTables()[0]) + .deployVdbForTables(this.tableSelector.getSelectedTables()) .subscribe( (wasSuccess) => { // Deployment succeeded - wait for source vdb to become active @@ -344,9 +344,9 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if (status.isActive()) { if (this.wizardService.isEdit()) { - this.updateDataserviceForSingleTable(); + this.updateDataserviceForSingleSourceTables(); } else { - this.createDataserviceForSingleTable(); + this.createDataserviceForSingleSourceTables(); } } else if (status.isFailed()) { this.setFinalPageComplete(false); @@ -487,19 +487,16 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } /* - * Create the Dataservice for the selected source table. This is invoked + * Create the Dataservice for the selected single source tables. This is invoked * only after the source VDB has successfully deployed. */ - private createDataserviceForSingleTable(): void { - const dataservice: NewDataservice = new NewDataservice(); - + private createDataserviceForSingleSourceTables(): void { // Dataservice basic properties from step 1 - dataservice.setId(this.dataserviceName); - dataservice.setDescription(this.dataserviceDescription); + const dataservice: NewDataservice = this.dataserviceService.newDataserviceInstance(this.dataserviceName, this.dataserviceDescription); const self = this; this.dataserviceService - .createDataserviceForSingleTable(dataservice, this.tableSelector.getSelectedTables()[0]) + .createDataserviceForSingleSourceTables(dataservice, this.tableSelector.getSelectedTables()) .subscribe( (wasSuccess) => { self.setFinalPageComplete(wasSuccess); @@ -513,19 +510,16 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } /** - * Update the selected Dataservice for the selected source table. This is invoked + * Update the selected Dataservice for the selected single source tables. This is invoked * only after the source VDB has successfully deployed. */ - private updateDataserviceForSingleTable(): void { - const dataservice: NewDataservice = new NewDataservice(); - + private updateDataserviceForSingleSourceTables(): void { // Dataservice basic properties from step 1 - dataservice.setId(this.dataserviceName); - dataservice.setDescription(this.dataserviceDescription); + const dataservice: NewDataservice = this.dataserviceService.newDataserviceInstance(this.dataserviceName, this.dataserviceDescription); const self = this; this.dataserviceService - .updateDataserviceForSingleTable(dataservice, this.tableSelector.getSelectedTables()[0]) + .updateDataserviceForSingleSourceTables(dataservice, this.tableSelector.getSelectedTables()) .subscribe( (wasSuccess) => { self.setFinalPageComplete(wasSuccess); diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 5c37ceec..2462daf4 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -25,7 +25,7 @@ export class Dataservice implements Identifiable< string > { private tko__description: string; private serviceVdbName: string; private serviceVdbVersion: string; - private serviceView: string; + private serviceViews: string[]; private serviceViewModel: string; private serviceViewTables: string[]; private deploymentState: DeploymentState = DeploymentState.LOADING; @@ -112,10 +112,10 @@ export class Dataservice implements Identifiable< string > { } /** - * @returns {string} the dataservice view name (can be null) + * @returns {string[]} the dataservice view names (can be null) */ - public getServiceViewName(): string { - return this.serviceView; + public getServiceViewNames(): string[] { + return this.serviceViews; } /** @@ -215,10 +215,10 @@ export class Dataservice implements Identifiable< string > { } /** - * @param {string} viewName the dataservice view name + * @param {string[]} viewNames the dataservice view names */ - public setServiceViewName( viewName: string ): void { - this.serviceView = viewName; + public setServiceViewNames( viewNames: string[] ): void { + this.serviceViews = viewNames; } /** @@ -249,7 +249,7 @@ export class Dataservice implements Identifiable< string > { tko__description: this.tko__description, serviceVdbName: this.serviceVdbName, serviceVdbVersion: this.serviceVdbVersion, - serviceView: this.serviceView, + serviceViews: this.serviceViews, serviceViewModel: this.serviceViewModel, serviceViewTables: this.serviceViewTables }; diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index ec87dbc9..46a5a0b0 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -69,6 +69,22 @@ export class DataserviceService extends ApiService { this.pollDataserviceStatus(60); } + /** + * Create and return a NewDataservice instance + * @param {string} name the dataservice name + * @param {string} description the dataservice description + * @returns {NewDataservice} the NewDataservice object + */ + public newDataserviceInstance(name: string, description: string ): NewDataservice { + const ds: NewDataservice = new NewDataservice(this.appSettingsService.getKomodoUserWorkspacePath()); + + // Set provided name and description + ds.setId(name); + ds.setDescription(description); + + return ds; + } + /** * Set the current Dataservice selection * @param {Dataservice} service the Dataservice @@ -102,14 +118,16 @@ export class DataserviceService extends ApiService { } const modelName = this.selectedDataservice.getServiceViewModel(); - const serviceView = this.selectedDataservice.getServiceViewName(); - - // TODO: we will need to get multiple views when supported - const view1: Table = new Table(); - view1.setName(modelName + "." + serviceView); + const serviceViews = this.selectedDataservice.getServiceViewNames(); + // build the views using the model and view names const allViews: Table[] = []; - allViews.push(view1); + for ( const serviceView of serviceViews ) { + const aView: Table = new Table(); + aView.setName(modelName + "." + serviceView); + + allViews.push(aView); + } return allViews; } @@ -206,14 +224,14 @@ export class DataserviceService extends ApiService { /** * Create a dataservice via the komodo rest interface * @param {string} dataserviceName, - * @param {string} tablePath, + * @param {string[]} tablePaths, * @param {string} modelSourcePath, * @returns {Observable} */ - public setServiceVdbForSingleTable(dataserviceName: string, tablePath: string, modelSourcePath: string): Observable { + public setServiceVdbForSingleSourceTables(dataserviceName: string, tablePaths: string[], modelSourcePath: string): Observable { return this.http - .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/ServiceVdbForSingleTable", - { dataserviceName, tablePath, modelSourcePath}, this.getAuthRequestOptions()) + .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/ServiceVdbForSingleSourceTables", + { dataserviceName, tablePaths, modelSourcePath}, this.getAuthRequestOptions()) .map((response) => { return response.ok; }) @@ -301,22 +319,27 @@ export class DataserviceService extends ApiService { /** * Create a dataservice which is a straight passthru to the supplied tables * @param {NewDataservice} dataservice - * @param {Table} sourceTable + * @param {Table[]} sourceTables * @returns {Observable} */ - public createDataserviceForSingleTable(dataservice: NewDataservice, sourceTable: Table): Observable { - const connectionName = sourceTable.getConnection().getId(); + public createDataserviceForSingleSourceTables(dataservice: NewDataservice, sourceTables: Table[]): Observable { + // All tables from same connection + const connectionName = sourceTables[0].getConnection().getId(); const sourceVdbName = connectionName + VdbsConstants.SOURCE_VDB_SUFFIX; const sourceModelName = connectionName; const vdbPath = this.getKomodoUserWorkspacePath() + "/" + sourceVdbName; - const tablePath = vdbPath + "/" + sourceModelName + "/" + sourceTable.getName(); + const tablePaths = []; + for ( const sourceTable of sourceTables ) { + const tablePath = vdbPath + "/" + sourceModelName + "/" + sourceTable.getName(); + tablePaths.push(tablePath); + } const modelSourcePath = vdbPath + "/" + sourceModelName + "/vdb:sources/" + sourceModelName; // Chain the individual calls together in series to build the DataService return this.createDataservice(dataservice) .flatMap((res) => this.vdbService.updateVdbModelFromTeiid(sourceVdbName, sourceModelName, sourceVdbName, sourceModelName)) - .flatMap((res) => this.setServiceVdbForSingleTable(dataservice.getId(), tablePath, modelSourcePath)) + .flatMap((res) => this.setServiceVdbForSingleSourceTables(dataservice.getId(), tablePaths, modelSourcePath)) .flatMap((res) => this.createReadonlyDataRole(dataservice.getId(), sourceModelName)) .flatMap((res) => this.vdbService.undeployVdb(sourceVdbName)) .flatMap((res) => this.vdbService.deleteVdb(sourceVdbName)); @@ -326,12 +349,12 @@ export class DataserviceService extends ApiService { * Updates a dataservice with single table source. This is simply a create, with the added step of * deleting the existing workspace dataservice first. * @param {NewDataservice} dataservice - * @param {Table} sourceTable + * @param {Table[]} sourceTables * @returns {Observable} */ - public updateDataserviceForSingleTable(dataservice: NewDataservice, sourceTable: Table): Observable { + public updateDataserviceForSingleSourceTables(dataservice: NewDataservice, sourceTables: Table[]): Observable { return this.deleteDataservice(dataservice.getId()) - .flatMap((res) => this.createDataserviceForSingleTable(dataservice, sourceTable)); + .flatMap((res) => this.createDataserviceForSingleSourceTables(dataservice, sourceTables)); } /** diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 80dd4d9b..918921bf 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -46,15 +46,17 @@ export class MockDataserviceService extends DataserviceService { this.serv1.setId("serv1"); this.serv1.setServiceViewTables(["table1", "table2"]); this.serv1.setServiceViewModel("viewModel"); - this.serv1.setServiceViewName("views"); + const viewNames: string[] = []; + viewNames.push("views"); + this.serv1.setServiceViewNames(viewNames); this.serv2.setId("serv2"); this.serv2.setServiceViewTables(["table1", "table2"]); this.serv2.setServiceViewModel("viewModel"); - this.serv2.setServiceViewName("views"); + this.serv2.setServiceViewNames(viewNames); this.serv3.setId("serv3"); this.serv3.setServiceViewTables(["table1", "table2"]); this.serv3.setServiceViewModel("viewModel"); - this.serv3.setServiceViewName("views"); + this.serv3.setServiceViewNames(viewNames); } /** diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index fe40b65f..c5b5cc6a 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -153,10 +153,10 @@ export class MockVdbService extends VdbService { /** * Create and deploy a VDB for the provided table - * @param {Table} table + * @param {Table[]} tables * @returns {Observable} */ - public deployVdbForTable(table: Table): Observable { + public deployVdbForTables(tables: Table[]): Observable { return Observable.of(true); } diff --git a/ngapp/src/app/dataservices/shared/new-dataservice.model.ts b/ngapp/src/app/dataservices/shared/new-dataservice.model.ts index d3d01cea..92781f30 100644 --- a/ngapp/src/app/dataservices/shared/new-dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/new-dataservice.model.ts @@ -14,8 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ReflectiveInjector } from "@angular/core"; -import { AppSettingsService } from "@core/app-settings.service"; export class NewDataservice { @@ -23,15 +21,14 @@ export class NewDataservice { private keng__dataPath: string; private keng__kType: string; private tko__description: string; - private appSettings: AppSettingsService; + private workspacePath: string; /** * Constructor */ - constructor( ) { + constructor(workspacePath: string) { this.keng__kType = "Dataservice"; - const injector = ReflectiveInjector.resolveAndCreate([AppSettingsService]); - this.appSettings = injector.get(AppSettingsService); + this.workspacePath = workspacePath; } /** @@ -53,7 +50,7 @@ export class NewDataservice { */ public setId( name: string ): void { this.keng__id = name; - this.keng__dataPath = this.appSettings.getKomodoUserWorkspacePath() + "/" + name; + this.keng__dataPath = this.workspacePath + "/" + name; } /** @@ -63,7 +60,7 @@ export class NewDataservice { this.tko__description = description ? description : null; } - // overrides toJSON - we do not want the appSettings + // overrides toJSON - we do not want the workspace path public toJSON(): {} { return { keng__id: this.keng__id, diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 62077864..4f4a7a36 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -283,12 +283,14 @@ export class VdbService extends ApiService { } /** - * Create and deploy a VDB for the provided table - * @param {Table} table + * Create and deploy a VDB for the provided tables. Currently we require all tables to + * be from the same connection source. + * @param {Table[]} tables * @returns {Observable} */ - public deployVdbForTable(table: Table): Observable { - const connection: Connection = table.getConnection(); + public deployVdbForTables(tables: Table[]): Observable { + // Currently requiring all tables from same connection + const connection: Connection = tables[0].getConnection(); // VDB to create const vdb = new Vdb(); @@ -306,22 +308,21 @@ export class VdbService extends ApiService { vdbModel.setId(connName); vdbModel.setDataPath(vdbPath + "/" + connName); vdbModel.setModelType("PHYSICAL"); - // Filter values for the model - let catName = table.getCatalogName(); - let schemaName = table.getSchemaName(); - // let tableName = table.getName(); - catName = (!catName || catName.length < 1) ? "%" : catName; - schemaName = (!schemaName || schemaName.length < 1) ? "%" : schemaName; - // tableName = (!tableName || tableName.length < 1) ? "%" : tableName; + + // TODO: Narrow the filters. Currently fetches entire schema. (Schema generation will be changing anyway) + const catNamePattern = "%"; + const schemaNamePattern = "%"; + const tableNamePattern = "%"; + // Set the importer properties for the physical model const props: NameValue[] = []; props.push(new NameValue("importer.TableTypes", "TABLE")); props.push(new NameValue("importer.UseFullSchemaName", "false")); props.push(new NameValue("importer.UseQualifiedName", "false")); props.push(new NameValue("importer.UseCatalogName", "false")); - props.push(new NameValue("importer.catalog", catName)); - props.push(new NameValue("importer.schemaPattern", schemaName)); - props.push(new NameValue("importer.tableNamePattern", "%")); // TODO improve tablePattern when possible + props.push(new NameValue("importer.catalog", catNamePattern)); + props.push(new NameValue("importer.schemaPattern", schemaNamePattern)); + props.push(new NameValue("importer.tableNamePattern", tableNamePattern)); vdbModel.setProperties(props); // VdbModelSource to create From f0261f7a53ae081d9c77ada4b12843fe1c35ef47 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 5 Feb 2018 16:33:01 -0600 Subject: [PATCH 080/205] minor styling changes --- .../dataservice-card.component.css | 5 ++++- .../dataservice-card.component.ts | 17 ++++------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index 8e8ab67d..8d30181d 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -19,6 +19,7 @@ } .dataservice-card-toolbar { + border-top: 1px solid lightgrey; border-bottom: 1px solid lightgrey; margin-bottom: 6px; margin-top: 0; @@ -69,6 +70,7 @@ } .dataservice-card-selected .card-pf .card-pf-heading { + border-top: var(--border-width) var(--border-style) var(--border-color); border-right: var(--border-width) var(--border-style) var(--border-color); border-left: var(--border-width) var(--border-style) var(--border-color); } @@ -82,6 +84,7 @@ .dataservice-card-selected .card-pf .card-pf-footer { border-right: var(--border-width) var(--border-style) var(--border-color); border-left: var(--border-width) var(--border-style) var(--border-color); + border-bottom: var(--border-width) var(--border-style) var(--border-color); } .dataservice-card-body .list-pf-container { @@ -106,7 +109,7 @@ div .dataservice-card-body-title { color: slategray; height: 50px; margin-bottom: 8px; - overflow: scroll; + overflow: auto; padding: 0 5px 5px 5px; } diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts index 6aba4919..decbeeae 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts @@ -90,20 +90,11 @@ export class DataserviceCardComponent implements OnInit { * @returns {string[]} the names of the views */ public getViews( ds: Dataservice ): string[] { - // TODO rewrite when REST functionality has been implemented const result: string[] = []; - const v1 = "ViewOne"; - result.push( v1 ); - - const v2 = "ViewTwo"; - result.push( v2 ); - - const v3 = "ViewThree"; - result.push( v3 ); - - const v4 = "ViewFour"; - result.push( v4 ); + for (const viewName of ds.getServiceViewNames()) { + result.push(viewName); + } return result; } @@ -124,7 +115,7 @@ export class DataserviceCardComponent implements OnInit { }, titleBorder: true, noPadding: true, - topBorder: true + topBorder: false } as CardConfig; this.listConfig = { From 6067b2e07319b0aa3dff2154201eec3e694cecbd Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Wed, 7 Feb 2018 19:26:55 +0000 Subject: [PATCH 081/205] Fixes vertical scrolling of summary item cards * Adding multiple card items to the dataservice or connection summary pages causes them to overflow off the bottom of the window. Worse still, the page body automatically displays a vertical scrollbar which, when scrolled, caused unsightly behaviour as components overlay the navbar. * Rather than the body scrolling, control the height of the item cards parent div so the scrollbar does not appear. Then allow the parent div to display the scrollbar instead. --- ngapp/src/app/activities/activities.component.css | 4 +++- ngapp/src/app/connections/connections.component.css | 4 +++- ngapp/src/app/dataservices/dataservices.component.css | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ngapp/src/app/activities/activities.component.css b/ngapp/src/app/activities/activities.component.css index fdcfb0e2..47aa258c 100644 --- a/ngapp/src/app/activities/activities.component.css +++ b/ngapp/src/app/activities/activities.component.css @@ -11,7 +11,9 @@ } .activity-list-items { - margin-top: 10px + margin-top: 10px; + height: 75vh; + overflow-y: auto; } .activity-list-activities .toolbar-pf { diff --git a/ngapp/src/app/connections/connections.component.css b/ngapp/src/app/connections/connections.component.css index f665144b..b92fbe0b 100644 --- a/ngapp/src/app/connections/connections.component.css +++ b/ngapp/src/app/connections/connections.component.css @@ -11,7 +11,9 @@ } .connection-list-items { - margin-top: 10px + margin-top: 10px; + height: 75vh; + overflow-y: auto; } .connection-list-connections .toolbar-pf { diff --git a/ngapp/src/app/dataservices/dataservices.component.css b/ngapp/src/app/dataservices/dataservices.component.css index ef086d0f..276a2323 100644 --- a/ngapp/src/app/dataservices/dataservices.component.css +++ b/ngapp/src/app/dataservices/dataservices.component.css @@ -11,7 +11,9 @@ } .dataservice-list-items { - margin-top: 10px + margin-top: 10px; + height: 75vh; + overflow-y: auto; } .dataservice-list-dataservices .toolbar-pf { From 9abf65304002dc736e7c68be26a4fa76b4552b7a Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 5 Feb 2018 16:42:11 -0600 Subject: [PATCH 082/205] Upgrade Patternfly - upgraded Patternfly to 3.1.1 - fixed some tests that were logging errors and shouldn't have been - made style changes needed due to patternfly upgrade changes --- ngapp/package-lock.json | 132 +++++++++++------ ngapp/package.json | 14 +- .../activities/activities.component.spec.ts | 3 + .../add-activity-wizard.component.spec.ts | 3 + .../add-activity.component.spec.ts | 19 +++ .../shared/activity.service.spec.ts | 7 +- ngapp/src/app/app.component.spec.ts | 5 + .../add-connection-wizard.component.spec.ts | 3 + .../add-connection.component.spec.ts | 3 + .../connections/connections.component.spec.ts | 3 + .../shared/mock-connection.service.ts | 9 ++ .../core/about-dialog/about.service.spec.ts | 8 +- ngapp/src/app/core/api.service.spec.ts | 7 +- .../src/app/core/app-settings.service.spec.ts | 2 +- ngapp/src/app/core/app-settings.service.ts | 2 +- ngapp/src/app/core/logger.service.spec.ts | 1 + .../vertical-nav/vertical-nav.component.html | 2 +- .../vertical-nav.component.spec.ts | 7 +- .../add-dataservice-wizard.component.css | 2 +- .../add-dataservice-wizard.component.spec.ts | 3 + .../add-dataservice-wizard.component.ts | 4 +- .../add-dataservice.component.spec.ts | 3 + ...onnection-table-selector.component.spec.ts | 6 +- .../dataservice-card.component.css | 140 +++++++++++------- .../dataservice-card.component.html | 13 +- .../dataservices/dataservices.component.css | 1 + .../dataservices.component.spec.ts | 12 +- .../jdbc-table-selector.component.spec.ts | 5 + .../selected-table.component.css | 41 +++-- .../selected-table.component.html | 4 +- .../selected-table.component.spec.ts | 1 + .../shared/dataservice.service.spec.ts | 4 +- .../dataservices/shared/vdb.service.spec.ts | 4 +- .../shared/wizard.service.spec.ts | 1 + .../sql-control/sql-control.component.spec.ts | 2 + .../test-dataservice.component.spec.ts | 3 + 36 files changed, 331 insertions(+), 148 deletions(-) diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index 98febc2e..b771a77e 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -91,7 +91,7 @@ "webpack-dev-middleware": "1.12.0", "webpack-dev-server": "2.5.1", "webpack-merge": "4.1.0", - "zone.js": "0.8.18" + "zone.js": "0.8.20" }, "dependencies": { "typescript": { @@ -218,9 +218,9 @@ } }, "@swimlane/ngx-datatable": { - "version": "11.1.5", - "resolved": "https://registry.npmjs.org/@swimlane/ngx-datatable/-/ngx-datatable-11.1.5.tgz", - "integrity": "sha512-BRRHMrgw9tG0BezTnfszzFTlpW9B9Zh5kyZF/pxqfJxpUsZ0aA/uXlL4cloe4+msQ6yIdu1/jhUCDInwSzmpFw==" + "version": "11.1.7", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-datatable/-/ngx-datatable-11.1.7.tgz", + "integrity": "sha512-TMDN26Q4J+Sh+OPqAx8BK5Q/3hAAmcTAUQ9wvC9nboSOAmYUaHGz8t21yGdeUtRtunIfMpjTnwLa+X2Pfoq42w==" }, "@types/jasmine": { "version": "2.5.54", @@ -614,6 +614,12 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, + "atoa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atoa/-/atoa-1.0.0.tgz", + "integrity": "sha1-DMDpGkgOc4+SPrwQNnZHF3mzSkk=", + "optional": true + }, "autoprefixer": { "version": "6.7.7", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", @@ -1364,9 +1370,9 @@ "dev": true }, "codelyzer": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-3.1.2.tgz", - "integrity": "sha1-n/HwQfubXuXb60W6hm368EmDrwQ=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.0.2.tgz", + "integrity": "sha512-nYwOr49+IV09e7C4aXkVALRz0+XpHqZiUUcxHuDZH4xP1FBcHINyr3qvVhv5Gfm7XRmoLx32tsIhrQhW/gBcog==", "dev": true, "requires": { "app-root-path": "2.0.1", @@ -1624,6 +1630,16 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "contra": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/contra/-/contra-1.9.4.tgz", + "integrity": "sha1-9TveQtfltZhcrk2ZqNYQUm3o8o0=", + "optional": true, + "requires": { + "atoa": "1.0.0", + "ticky": "1.0.1" + } + }, "convert-source-map": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", @@ -1730,6 +1746,23 @@ "which": "1.3.0" } }, + "crossvent": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/crossvent/-/crossvent-1.5.4.tgz", + "integrity": "sha1-2ixPj0DJR4JRe/K+7BBEFIGUq5I=", + "optional": true, + "requires": { + "custom-event": "1.0.0" + }, + "dependencies": { + "custom-event": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.0.tgz", + "integrity": "sha1-LkYovhncSyFLXAJjDFlx6BFhgGI=", + "optional": true + } + } + }, "cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", @@ -2211,6 +2244,16 @@ "domelementtype": "1.3.0" } }, + "dragula": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/dragula/-/dragula-3.7.2.tgz", + "integrity": "sha1-SjXJ05gf+sGpScKcpyhQWOhzk84=", + "optional": true, + "requires": { + "contra": "1.9.4", + "crossvent": "1.5.4" + } + }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", @@ -5161,9 +5204,9 @@ } }, "jasmine-core": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.6.4.tgz", - "integrity": "sha1-3skmzQqfoof7bbXHVfpIfnTOysU=", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", "dev": true }, "jasmine-spec-reporter": { @@ -5357,9 +5400,9 @@ } }, "karma-chrome-launcher": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.1.1.tgz", - "integrity": "sha1-IWh5xorATY1RQOmWGboEtZr9Rs8=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", "dev": true, "requires": { "fs-access": "1.0.1", @@ -5692,9 +5735,9 @@ } }, "make-error": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz", - "integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y=", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.3.tgz", + "integrity": "sha512-j3dZCri3cCd23wgPqK/0/KvTN8R+W6fXDqQe8BNLbTpONjbA8SPaRr+q0BQq9bx3Q/+g68/gDIh9FW3by702Tg==", "dev": true }, "map-obj": { @@ -5953,11 +5996,6 @@ "integrity": "sha1-JjjQkWGAgGk7vtAsXfjNcUtSwWc=", "optional": true }, - "moment": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6014,6 +6052,15 @@ "codemirror": "5.32.0" } }, + "ng2-dragula": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/ng2-dragula/-/ng2-dragula-1.5.0.tgz", + "integrity": "sha512-uSVq66Rv+ZhDLBGYCGZ7mTaseP7rvYJOijiQZlzfy8dxL614Sw7rhtnLqvK8nqa3tI/wVv8CEGZaZkMnWJokwQ==", + "optional": true, + "requires": { + "dragula": "3.7.2" + } + }, "ngx-bootstrap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-2.0.1.tgz", @@ -6845,25 +6892,17 @@ } }, "patternfly-ng": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-2.1.1.tgz", - "integrity": "sha1-kd7dyTpIUP6c538ZMj3VqMeZelo=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-3.1.1.tgz", + "integrity": "sha1-ZC/sm0dkiTKJJqoEFIAVpg6rWes=", "requires": { + "@swimlane/ngx-datatable": "11.1.7", "angular-tree-component": "6.1.0", "c3": "0.4.18", "lodash": "4.17.4", - "ngx-bootstrap": "1.8.0", + "ng2-dragula": "1.5.0", + "ngx-bootstrap": "2.0.1", "patternfly": "3.37.1" - }, - "dependencies": { - "ngx-bootstrap": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-1.8.0.tgz", - "integrity": "sha512-y4+9cQkCAZ8C2iHfGC9PMu6tqHqDPyZN0ejz4fDwWljAUtxqXqwUgPKAnebkckdLw/EFmozgvf27ouVqhDA+CA==", - "requires": { - "moment": "2.18.1" - } - } } }, "pbkdf2": { @@ -9351,6 +9390,12 @@ "integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=", "dev": true }, + "ticky": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ticky/-/ticky-1.0.1.tgz", + "integrity": "sha1-t8+nHnaPHJAAxJe5FRswlHxQ5G0=", + "optional": true + }, "time-stamp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz", @@ -9429,7 +9474,7 @@ "arrify": "1.0.1", "chalk": "2.1.0", "diff": "3.3.1", - "make-error": "1.3.0", + "make-error": "1.3.3", "minimist": "1.2.0", "mkdirp": "0.5.1", "source-map-support": "0.4.18", @@ -9490,13 +9535,14 @@ "integrity": "sha512-ymKWWZJST0/CkgduC2qkzjMOWr4bouhuURNXCn/inEX0L57BnRG6FhX76o7FOnsjHazCjfU2LKeSrlS2sIKQJg==" }, "tslint": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz", - "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.8.0.tgz", + "integrity": "sha1-H0mtWy53x2w69N3K5VKuTjYS6xM=", "dev": true, "requires": { "babel-code-frame": "6.26.0", - "colors": "1.1.2", + "builtin-modules": "1.1.1", + "chalk": "2.1.0", "commander": "2.11.0", "diff": "3.3.1", "glob": "7.1.2", @@ -10508,9 +10554,9 @@ "dev": true }, "zone.js": { - "version": "0.8.18", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.18.tgz", - "integrity": "sha512-knKOBQM0oea3/x9pdyDuDi7RhxDlJhOIkeixXSiTKWLgs4LpK37iBc+1HaHwzlciHUKT172CymJFKo8Xgh+44Q==" + "version": "0.8.20", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.20.tgz", + "integrity": "sha512-FXlA37ErSXCMy5RNBcGFgCI/Zivqzr0D19GuvDxhcYIJc7xkFp6c29DKyODJu0Zo+EMyur/WPPgcBh1EHjB9jA==" } } } diff --git a/ngapp/package.json b/ngapp/package.json index d2926ca6..d996cf16 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -26,10 +26,10 @@ "express": "^4.16.2", "ng2-codemirror": "^1.1.3", "ngx-bootstrap": "^2.0.1", - "patternfly": "^3.37.1", - "patternfly-ng": "^2.1.1", + "patternfly": "^3.28.0", + "patternfly-ng": "^3.1.1", "rxjs": "^5.5.5", - "zone.js": "^0.8.14" + "zone.js": "^0.8.20" }, "devDependencies": { "@angular/cli": "1.3.2", @@ -38,11 +38,11 @@ "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", "@types/node": "^6.0.92", - "codelyzer": "~3.1.1", - "jasmine-core": "~2.6.2", + "codelyzer": "~4.0.0", + "jasmine-core": "~2.8.0", "jasmine-spec-reporter": "~4.1.0", "karma": "~1.7.0", - "karma-chrome-launcher": "~2.1.1", + "karma-chrome-launcher": "~2.2.0", "karma-cli": "~1.0.1", "karma-coverage-istanbul-reporter": "^1.2.1", "karma-jasmine": "^1.1.1", @@ -51,7 +51,7 @@ "karma-phantomjs-launcher": "^1.0.4", "protractor": "~5.1.2", "ts-node": "~3.2.0", - "tslint": "~5.7.0", + "tslint": "~5.8.0", "typescript": "~2.6.2" } } diff --git a/ngapp/src/app/activities/activities.component.spec.ts b/ngapp/src/app/activities/activities.component.spec.ts index 55ef0e4e..d99de524 100644 --- a/ngapp/src/app/activities/activities.component.spec.ts +++ b/ngapp/src/app/activities/activities.component.spec.ts @@ -8,7 +8,9 @@ import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; import { By } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { SharedModule } from "@shared/shared.module"; import { ModalModule } from "ngx-bootstrap"; @@ -27,6 +29,7 @@ describe("ActivitiesComponent", () => { set: { providers: [ { provide: ActivityService, useClass: MockActivityService }, + { provide: AppSettingsService, useClass: MockAppSettingsService } ] } }); diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts index cc473270..4af03340 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts @@ -6,7 +6,9 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -21,6 +23,7 @@ describe("AddActivityWizardComponent", () => { imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], declarations: [ AddActivityWizardComponent, PropertyFormComponent, PropertyFormPropertyComponent ], providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ActivityService, useClass: MockActivityService }, { provide: ConnectionService, useClass: MockConnectionService } ] diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 80c8d413..594de437 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -7,7 +7,9 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddActivityComponent } from "./add-activity.component"; @@ -22,12 +24,29 @@ describe("AddActivityComponent", () => { declarations: [ AddActivityComponent, AddActivityWizardComponent ], providers: [ { provide: ActivityService, useClass: MockActivityService }, + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ConnectionService, useClass: MockConnectionService } ] }) .compileComponents().then(() => { // nothing to do }); + + TestBed.overrideComponent( + MockActivityService, { + set: { + providers: [ { provide: AppSettingsService, useClass: MockAppSettingsService } ] + } + } + ); + + TestBed.overrideComponent( + MockConnectionService, { + set: { + providers: [ { provide: AppSettingsService, useClass: MockAppSettingsService } ] + } + } + ); })); beforeEach(() => { diff --git a/ngapp/src/app/activities/shared/activity.service.spec.ts b/ngapp/src/app/activities/shared/activity.service.spec.ts index 7e7bf0dd..828db071 100644 --- a/ngapp/src/app/activities/shared/activity.service.spec.ts +++ b/ngapp/src/app/activities/shared/activity.service.spec.ts @@ -3,17 +3,22 @@ import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; describe("ActivityService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], - providers: [ActivityService, AppSettingsService, LoggerService] + providers: [ + ActivityService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + LoggerService] }); }); it("should be created", inject([ActivityService, AppSettingsService, LoggerService], (service: ActivityService, logger: LoggerService) => { + console.log("========== [ActivityService] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/app.component.spec.ts b/ngapp/src/app/app.component.spec.ts index ed67d540..4719131d 100644 --- a/ngapp/src/app/app.component.spec.ts +++ b/ngapp/src/app/app.component.spec.ts @@ -1,6 +1,8 @@ import { async, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { ModalModule } from "ngx-bootstrap"; import { AppComponent } from "./app.component"; @@ -11,6 +13,9 @@ describe("AppComponent", () => { declarations: [ AppComponent ], + providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService } + ] }).compileComponents().then(() => { // nothing to do }); diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts index df00a2a5..44f83e18 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts @@ -4,7 +4,9 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -19,6 +21,7 @@ describe("AddConnectionWizardComponent", () => { imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], declarations: [ AddConnectionWizardComponent, PropertyFormComponent, PropertyFormPropertyComponent ], providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ConnectionService, useClass: MockConnectionService }, ] }) diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 3d5d3f26..a0184d52 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -5,7 +5,9 @@ import { RouterTestingModule } from "@angular/router/testing"; import { AddConnectionWizardComponent } from "@connections/add-connection-wizard/add-connection-wizard.component"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddConnectionComponent } from "./add-connection.component"; @@ -19,6 +21,7 @@ describe("AddConnectionComponent", () => { imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], declarations: [ AddConnectionComponent, AddConnectionWizardComponent ], providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ConnectionService, useClass: MockConnectionService }, ] }) diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index 6584158f..b5708a94 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -8,7 +8,9 @@ import { ConnectionsListComponent } from "@connections/connections-list/connecti import { ConnectionsComponent } from "@connections/connections.component"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { SharedModule } from "@shared/shared.module"; import { ModalModule } from "ngx-bootstrap"; @@ -26,6 +28,7 @@ describe("ConnectionsComponent", () => { TestBed.overrideComponent( ConnectionsComponent, { set: { providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ConnectionService, useClass: MockConnectionService }, ] } diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 40b3d25a..47dda730 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -19,6 +19,7 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; +import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; import { NewConnection } from "@connections/shared/new-connection.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; import { TemplateDefinition } from "@connections/shared/template-definition.model"; @@ -138,4 +139,12 @@ export class MockConnectionService extends ConnectionService { return Observable.of( empty ); } + public getJdbcConnectionTables( tableFilter: JdbcTableFilter ): Observable< string[] > { + const tableNames = []; + tableNames.push( "table1" ); + tableNames.push( "table2" ); + tableNames.push( "table3" ); + return Observable.of( tableNames ); + } + } diff --git a/ngapp/src/app/core/about-dialog/about.service.spec.ts b/ngapp/src/app/core/about-dialog/about.service.spec.ts index 1ed0f108..a5730cfe 100644 --- a/ngapp/src/app/core/about-dialog/about.service.spec.ts +++ b/ngapp/src/app/core/about-dialog/about.service.spec.ts @@ -3,19 +3,23 @@ import { HttpModule } from "@angular/http"; import { AboutService } from "@core/about-dialog/about.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; describe("AboutService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], - providers: [ AboutService, AppSettingsService, LoggerService ] + providers: [ + AboutService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + LoggerService ] }); }); it("should be created", inject([ AboutService, AppSettingsService, LoggerService ], ( service: AboutService ) => { - console.log("========== [AboutServiceComponent] should be created"); + console.log("========== [AboutService] should be created"); expect( service ).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/api.service.spec.ts b/ngapp/src/app/core/api.service.spec.ts index 522db18e..0b43471e 100644 --- a/ngapp/src/app/core/api.service.spec.ts +++ b/ngapp/src/app/core/api.service.spec.ts @@ -3,18 +3,21 @@ import { HttpModule } from "@angular/http"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; describe("ApiService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpModule], - providers: [AppSettingsService, LoggerService] + providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService }, + LoggerService] }); }); it("should be created", inject([LoggerService], (service: MockService ) => { - console.log("========== [ApiServiceComponent] should be created"); + console.log("========== [ApiService] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/app-settings.service.spec.ts b/ngapp/src/app/core/app-settings.service.spec.ts index 792aa941..078da512 100644 --- a/ngapp/src/app/core/app-settings.service.spec.ts +++ b/ngapp/src/app/core/app-settings.service.spec.ts @@ -15,7 +15,7 @@ describe("AppSettingsService", () => { }); it("should be created", inject([AppSettingsService], (service: AppSettingsService) => { - console.log("========== [AppSettingsServiceComponent] should be created"); + console.log("========== [AppSettingsService] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/app-settings.service.ts b/ngapp/src/app/core/app-settings.service.ts index 23b915d7..2cec0eda 100644 --- a/ngapp/src/app/core/app-settings.service.ts +++ b/ngapp/src/app/core/app-settings.service.ts @@ -77,7 +77,7 @@ export class AppSettingsService { this.userProfile = profile; }, ( error ) => { - this.logger.error( "[fetchUserProfile] Error: %o", error ); + this.logger.error( "[fetchUserProfile] Error:", error ); } ); } diff --git a/ngapp/src/app/core/logger.service.spec.ts b/ngapp/src/app/core/logger.service.spec.ts index a7bc7ee8..97db9569 100644 --- a/ngapp/src/app/core/logger.service.spec.ts +++ b/ngapp/src/app/core/logger.service.spec.ts @@ -9,6 +9,7 @@ describe("LoggerService", () => { }); it("should be created", inject([LoggerService], ( service: LoggerService) => { + console.log("========== [LoggerService] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html index 04994f18..e66f3ff6 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html @@ -3,10 +3,10 @@ [brandSrc]="'assets/vdb.png'" [title]="'Beetle Studio'" [brandAlt]="'Beetle Studio'" - [hiddenIcons]="false" [persistentSecondary]="false" [pinnableMenus]="false" [showBadges]="false" + [showIcons]="true" [updateActiveItemsOnClick]="false" [items]="navigationItems" (onNavigationEvent)="onNavigation($event)"> diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts index 2d7ece06..e9f84163 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts @@ -5,6 +5,7 @@ import { AboutDialogComponent } from "@core/about-dialog/about-dialog.component" import { AboutService } from "@core/about-dialog/about.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; import { BsModalService, ModalModule } from "ngx-bootstrap"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -17,7 +18,11 @@ describe("VerticalNavComponent", () => { TestBed.configureTestingModule({ imports: [ HttpModule, ModalModule.forRoot(), PatternFlyNgModule, RouterTestingModule ], declarations: [ VerticalNavComponent, AboutDialogComponent ], - providers: [ AboutService, AppSettingsService, BsModalService, LoggerService ] + providers: [ + AboutService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + BsModalService, + LoggerService ] }) .compileComponents().then(() => { // nothing to do diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css index 254c733d..072d3000 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css @@ -32,7 +32,7 @@ width: 300px; margin-left: 20px; padding-left: 4px; - overflow: scroll; + overflow: auto; white-space: nowrap; border: 1px solid #ccc; -webkit-border-radius: 2px; diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index 6c3b2d68..c1ae969c 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -4,7 +4,9 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; @@ -31,6 +33,7 @@ describe("AddDataserviceWizardComponent", () => { PropertyFormComponent, PropertyFormPropertyComponent, SelectedTableComponent ], providers: [ NotifierService, WizardService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: ConnectionService, useClass: MockConnectionService }, { provide: VdbService, useClass: MockVdbService }, diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index fb436a49..0ca4df21 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -292,7 +292,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { (wasSuccess) => { // Deployment succeeded - wait for source vdb to become active if (wasSuccess) { - self.vdbService.pollForActiveVdb(sourceVdbName, 30, 5); + self.vdbService.pollForActiveVdb(sourceVdbName, 120, 5); } else { self.setFinalPageComplete(false); self.sourceVdbUnderDeployment = null; @@ -611,7 +611,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if (resp) { try { this.errorDetailMessage = resp.json().error; - } catch { + } catch ( e ) { this.errorDetailMessage = resp.text(); } } diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index 5d64a3d4..89934816 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -4,7 +4,9 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { AddDataserviceWizardComponent } from "@dataservices/add-dataservice-wizard/add-dataservice-wizard.component"; import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; @@ -31,6 +33,7 @@ describe("AddDataserviceComponent", () => { ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ NotifierService, WizardService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: ConnectionService, useClass: MockConnectionService }, { provide: VdbService, useClass: MockVdbService } diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts index 963a642a..fee59727 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -6,6 +6,7 @@ import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -25,7 +26,10 @@ describe("ConnectionTableSelectorComponent", () => { imports: [ FormsModule, HttpModule, NgxDatatableModule, PatternFlyNgModule ], declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ - AppSettingsService, LoggerService, NotifierService, WizardService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + LoggerService, + NotifierService, + WizardService, { provide: ConnectionService, useClass: MockConnectionService }, { provide: VdbService, useClass: MockVdbService } ] diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index 8d30181d..52631080 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -1,58 +1,95 @@ :root { - --body-main-color: #dc7039; + --body-background-color: #f5f5f5; + --body-main-color: #72767b; --border-color: #39a5dc; --border-style: double; --border-width: 2px; --hover-color: rgb(221, 234, 255); } +.card-pf .card-pf-body { + margin: 0; + padding: 0; +} + .dataservice-card { -webkit-transition: background-color 300ms; -moz-transition: background-color 300ms; //-ms-transition: background-color 300ms; -o-transition: background-color 300ms; transition: background-color 300ms; + margin: 0px 10px; height: 160px; } -.dataservice-card-selected { +.dataservice-card .card-pf { + margin: 0; + padding: 0 20px; } -.dataservice-card-toolbar { - border-top: 1px solid lightgrey; - border-bottom: 1px solid lightgrey; - margin-bottom: 6px; - margin-top: 0; +.dataservice-card .card-pf:hover { + background-color: var(--hover-color); } -.dataservice-card-toolbar:hover { - background-color: var(--hover-color); +.dataservice-card .card-pf .card-pf-footer { + background-color: #ececec; + min-height: 20px; + padding: 10px 0 5px 20px; } -.dataservice-card-toolbar-kebab { - margin-left: 0 !important; - margin-right: 4px; +.dataservice-card .card-pf .card-pf-heading { + border-bottom: none; + margin: 0px -20px 0px -20px; + padding: 0 20px; } -.dataservice-card-action-icon { - color: var(--border-color); - cursor: pointer; +.dataservice-card-action-disabled-icon { + color: lightgray; font-size: 1.5em; height: 24px !important; - margin-left: 0 !important; + margin-left: 4px; margin-top: 4px; width: 24px !important; } -.dataservice-card-action-disabled-icon { - color: lightgray; +.dataservice-card-action-icon { + color: var(--border-color); + cursor: pointer; font-size: 1.5em; height: 24px !important; - margin-left: 4px; + margin-left: 0 !important; margin-top: 4px; width: 24px !important; } +.dataservice-card-body { + /*background-color: #dc7039;*/ + margin: 0 -20px; +} + +.dataservice-card-body-title { + background-color: var(--body-main-color); + color: white; + margin: 0; + text-align: center; +} + +/*.dataservice-card-body-title {*/ + /*margin: 0 !important;*/ +/*}*/ + +.dataservice-card-body-title-selected { + border-left: var(--border-width) var(--border-style) var(--border-color); + border-right: var(--border-width) var(--border-style) var(--border-color); +} + +.dataservice-card-description { + color: slategray; + height: 50px; + overflow: auto; + padding: 0 5px 5px 5px; +} + .dataservice-card-icon { border: 2px solid var(--border-color); border-radius: 60px; @@ -60,25 +97,14 @@ padding: 0.1em 0.2em; } -.dataservice-card-title { - font-size: 16px; - font-weight: bold; -} - -.dataservice-card .card-pf .card-pf-heading:hover { - background-color: var(--hover-color); +.dataservice-card-selected { } .dataservice-card-selected .card-pf .card-pf-heading { border-top: var(--border-width) var(--border-style) var(--border-color); border-right: var(--border-width) var(--border-style) var(--border-color); border-left: var(--border-width) var(--border-style) var(--border-color); -} - -.dataservice-card .card-pf .card-pf-footer { - margin: 0 !important; - min-height: 20px; - padding: 10px 0 5px 20px; + padding: 0px 20px; } .dataservice-card-selected .card-pf .card-pf-footer { @@ -87,33 +113,47 @@ border-bottom: var(--border-width) var(--border-style) var(--border-color); } -.dataservice-card-body .list-pf-container { - margin: 0 !important; - padding: 4px 10px; +.dataservice-card-title { + font-size: 16px; + font-weight: bold; + margin: 10px 0 !important; } -.dataservice-card-body-title { - background-color: var(--body-main-color); - color: white; - margin: 4px 4px !important; - text-align: center; +.dataservice-card-toolbar { + border-top: 1px solid lightgrey; + border-bottom: 1px solid lightgrey; + margin-bottom: 6px; + margin-top: 0; } -div .dataservice-card-body-title { - border-right: var(--border-width) var(--border-style) var(--border-color); - border-left: var(--border-width) var(--border-style) var(--border-color); - margin: 0 !important; +.dataservice-card-toolbar-kebab { + margin-left: 0 !important; + margin-right: 4px; } -.dataservice-card-description { - color: slategray; - height: 50px; - margin-bottom: 8px; - overflow: auto; - padding: 0 5px 5px 5px; +.list-pf { + border: none; +} + +.list-pf-item { + border: none; +} + +.list-pf-item:hover { + background-color: transparent; } .view-name { cursor: pointer; color: var(--body-main-color); } + +.views-details { + background-color: var(--body-background-color); + border-bottom: 2px solid lightgrey; +} + +.views-details-selected { + border-left: var(--border-width) var(--border-style) var(--border-color); + border-right: var(--border-width) var(--border-style) var(--border-color); +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index 4d0c981c..9e4e1a73 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -119,7 +119,7 @@ title="Refresh"> -
    + @@ -129,8 +129,8 @@
    -
    Views
    -
    +
    Views
    +
    - - - - - - -
    diff --git a/ngapp/src/app/dataservices/dataservices.component.css b/ngapp/src/app/dataservices/dataservices.component.css index ef086d0f..e0530a69 100644 --- a/ngapp/src/app/dataservices/dataservices.component.css +++ b/ngapp/src/app/dataservices/dataservices.component.css @@ -11,6 +11,7 @@ } .dataservice-list-items { + background-color: #fafafa; margin-top: 10px } diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index d399bca5..03bfd1ed 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -5,6 +5,7 @@ import { By } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { DataserviceCardComponent } from "@dataservices/dataservices-cards/dataservice-card/dataservice-card.component"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; @@ -39,19 +40,12 @@ describe("DataservicesComponent", () => { AppSettingsService, NotifierService, WizardService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } ] }); - // use mock service - TestBed.overrideComponent( DataservicesComponent, { - set: { - providers: [ - { provide: DataserviceService, useClass: MockDataserviceService }, - ] - } - }); - fixture = TestBed.createComponent(DataservicesComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index f9fea6c9..193dc09b 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -6,6 +6,7 @@ import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { JdbcTableSelectorComponent } from "@dataservices/jdbc-table-selector/jdbc-table-selector.component"; import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -25,6 +26,7 @@ describe("JdbcTableSelectorComponent", () => { declarations: [ JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ AppSettingsService, LoggerService, NotifierService, WizardService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ConnectionService, useClass: MockConnectionService }, { provide: VdbService, useClass: MockVdbService }, ] @@ -46,6 +48,7 @@ describe("JdbcTableSelectorComponent", () => { }); it("should have correct number of schemas", () => { + console.log("========== [JdbcTableSelectorComponent] should have correct number of schemas"); component.connection = MockConnectionService.conn2; component.ngOnInit(); component.setConnection( MockConnectionService.conn1 ); @@ -53,6 +56,7 @@ describe("JdbcTableSelectorComponent", () => { }); it( "should clear schemas", () => { + console.log("========== [JdbcTableSelectorComponent] should clear schemas"); component.connection = MockConnectionService.conn3; component.ngOnInit(); expect( component.getSchemas().length ).toBe( MockConnectionService.numConn3Schemas ); @@ -62,6 +66,7 @@ describe("JdbcTableSelectorComponent", () => { }); it( "should select schema", () => { + console.log("========== [JdbcTableSelectorComponent] should select schema"); component.connection = MockConnectionService.conn1; component.ngOnInit(); expect( component.selectedSchema ).toBeNull(); diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.css b/ngapp/src/app/dataservices/selected-table/selected-table.component.css index 691e2b4b..088b7fe0 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.css +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.css @@ -1,7 +1,24 @@ +:root { + --body-background-color: #f5f5f5; + --body-main-color: #72767b; +} + +.card-pf .card-pf-body { + background-color: var(--body-background-color); + margin: 0; + padding: 0 10px 0 10px; +} + +.card-pf-heading { + margin: 0; + padding: 0 20px; +} + .selected-table-card .card-pf { background-color: #def3ff; - margin: 0 0 10px; + margin: 0 4px 4px 4px; min-height: 40px; + padding: 0; } .selected-table-name:before { @@ -43,25 +60,25 @@ } .selected-table-body .card-pf-body { - background-color: white; + background-color: var(--body-background-color); margin-top: 10px !important; } .selected-table-column-selection { - margin-left: 5px; - padding-top: 5px; - font-weight: bold; + background-color: var(--body-main-color); + color: white; + margin: 4px 0; + text-align: center; } -.seleted-table-card .pfng-card .card-pf-heading { - background-color: #def3ff; - margin-bottom: -10px !important; -} - - .selected-table-card .pfng-card .card-pf-footer { + background-color: #ececec; margin: 0 !important; - padding: 10px 0 5px 20px; min-height: 20px; + padding: 10px 0 5px 20px; } +.selected-tables-container { + margin-top: 0; + padding-top: 4px; +} diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.html b/ngapp/src/app/dataservices/selected-table/selected-table.component.html index d64f1725..1b95d4c0 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.html +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.html @@ -7,11 +7,11 @@

    {{ table.getName() }}

    -
    {{ table.getConnection().getId() }}
    +
    {{ table.getConnection().getId() }}
    -
    Select columns to include in the view:
    +
    Include/Exclude Columns
    { }); it("should be created", () => { + console.log("========== [SelectedTableComponent] should be created"); expect(component).toBeTruthy(); }); diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts b/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts index 6d1a9391..7b1fd68c 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts @@ -2,6 +2,7 @@ import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; @@ -13,7 +14,7 @@ describe("DataserviceService", () => { imports: [ HttpModule ], providers: [ DataserviceService, - AppSettingsService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, LoggerService, NotifierService, { provide: VdbService, useClass: MockVdbService } @@ -23,6 +24,7 @@ describe("DataserviceService", () => { it("should be created", inject([DataserviceService, AppSettingsService, LoggerService], ( service: DataserviceService ) => { + console.log("========== [DataserviceService] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/dataservices/shared/vdb.service.spec.ts b/ngapp/src/app/dataservices/shared/vdb.service.spec.ts index 4be0f0c1..55e90f94 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.spec.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.spec.ts @@ -2,6 +2,7 @@ import { inject, TestBed } from "@angular/core/testing"; import { HttpModule } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; @@ -11,7 +12,7 @@ describe("VdbService", () => { imports: [ HttpModule ], providers: [ VdbService, - AppSettingsService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, NotifierService, LoggerService ] @@ -20,6 +21,7 @@ describe("VdbService", () => { it("should be created", inject([VdbService, AppSettingsService, LoggerService], ( service: VdbService ) => { + console.log("========== [VdbService] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/dataservices/shared/wizard.service.spec.ts b/ngapp/src/app/dataservices/shared/wizard.service.spec.ts index 9315a957..1f61285a 100644 --- a/ngapp/src/app/dataservices/shared/wizard.service.spec.ts +++ b/ngapp/src/app/dataservices/shared/wizard.service.spec.ts @@ -10,6 +10,7 @@ describe("WizardService", () => { }); it("should be created", inject([WizardService], (service: WizardService) => { + console.log("========== [WizardService] should be created"); expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts index 7a578d9b..08d2302b 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts @@ -4,6 +4,7 @@ import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -26,6 +27,7 @@ describe("SqlControlComponent", () => { AppSettingsService, LoggerService, NotifierService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } ] diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts index b3f29ea6..19e2c68c 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts @@ -1,7 +1,9 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { FormsModule } from "@angular/forms"; import { RouterTestingModule } from "@angular/router/testing"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -22,6 +24,7 @@ describe("TestDataserviceComponent", () => { declarations: [ SqlControlComponent, TestDataserviceComponent ], providers: [ NotifierService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } ] From b443e7342f815063e6a3a6a257e9a3d50933bb92 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 8 Feb 2018 14:01:54 -0600 Subject: [PATCH 083/205] Change in style to modify the left and right margin of the selected table card. --- .../dataservices/selected-table/selected-table.component.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.css b/ngapp/src/app/dataservices/selected-table/selected-table.component.css index 088b7fe0..6dd395de 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.css +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.css @@ -16,7 +16,7 @@ .selected-table-card .card-pf { background-color: #def3ff; - margin: 0 4px 4px 4px; + margin: 0 0 4px 0; min-height: 40px; padding: 0; } From 702388245fc15cd42338eb22c15ffc59ae74ef74 Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Mon, 12 Feb 2018 17:29:12 -0600 Subject: [PATCH 084/205] teiidtools-339: Upgraded dataservices list to pfng and fixed layout issues related to pfng upgrade. --- .../basic-content.component.html | 16 ++ .../basic-content.component.ts | 24 +++ .../dataservices-list.component.css | 19 +++ .../dataservices-list.component.html | 94 ++++++------ .../dataservices-list.component.ts | 138 ++++++++++++++++-- .../views-content.component.html | 24 +++ .../views-content.component.ts | 60 ++++++++ .../app/dataservices/dataservices.module.ts | 4 + 8 files changed, 317 insertions(+), 62 deletions(-) create mode 100644 ngapp/src/app/dataservices/dataservices-list/basic-content.component.html create mode 100644 ngapp/src/app/dataservices/dataservices-list/basic-content.component.ts create mode 100644 ngapp/src/app/dataservices/dataservices-list/views-content.component.html create mode 100644 ngapp/src/app/dataservices/dataservices-list/views-content.component.ts diff --git a/ngapp/src/app/dataservices/dataservices-list/basic-content.component.html b/ngapp/src/app/dataservices/dataservices-list/basic-content.component.html new file mode 100644 index 00000000..deddb25a --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/basic-content.component.html @@ -0,0 +1,16 @@ +
    +
    +

    + Name +

    +

    + {{item.getId()}} +

    +

    + Description +

    +

    + {{item.getDescription()}} +

    +
    +
    diff --git a/ngapp/src/app/dataservices/dataservices-list/basic-content.component.ts b/ngapp/src/app/dataservices/dataservices-list/basic-content.component.ts new file mode 100644 index 00000000..d07cd28b --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/basic-content.component.ts @@ -0,0 +1,24 @@ +import { + Component, + Input, + OnInit, + ViewEncapsulation +} from '@angular/core'; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: 'basic-content', + templateUrl: 'basic-content.component.html' +}) +export class BasicContentComponent implements OnInit { + @Input() item: any; + + constructor() { + } + + ngOnInit(): void { + } + + ngDoCheck(): void { + } +} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css index 3294415c..9d7057a4 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css @@ -3,6 +3,14 @@ font-size: 1.7em; } +.dataservice-list-description { + color: black; +} + +.dataservice-list-name { + color: black; +} + .dataservice-list-quicklook-icon { margin-left: 20px; font-size: 1.3em; @@ -54,3 +62,14 @@ border-color: #00659c; color: white; } + +.list-pf-actions { + flex-grow: 1; + justify-content: flex-end; +} + +.close { + float: left; +} + + diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index 34ca4ea5..11c8a22f 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -1,52 +1,50 @@ -
    -
    -
    -
    - - - - - - -
    -
    -
    - -
    - {{ dataservice.getDescription() }} -
    -
    -
    -
    - - {{dataservice.getServiceViewTables()[0]}} - {{dataservice.getServiceViewTables()[0]}}, {{dataservice.getServiceViewTables()[1]}} +
    +
    +
    +
    + +
    +
    -
    - - -
    - -
    -
    -
    - - - - - + + + + + + + +
    +
    +
    {{item.getId()}}
    +
    {{item.getDescription()}}
    +
    +
    + + + + Views + + +
    +
    +
    + + + + + + + + +
    diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts index a9cc3bd3..d1f10121 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts @@ -15,18 +15,46 @@ * limitations under the License. */ -import { Component, EventEmitter, Input, Output } from "@angular/core"; -import { Router } from "@angular/router"; +import { + Component, + OnInit, + ViewEncapsulation, + EventEmitter, + Input, + Output +} from '@angular/core'; import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { LoggerService } from "@core/logger.service"; +import { Action, ActionConfig, ListConfig, ListEvent } from "patternfly-ng"; @Component({ + encapsulation: ViewEncapsulation.None, moduleId: module.id, selector: "app-dataservices-list", templateUrl: "dataservices-list.component.html", styleUrls: ["dataservices-list.component.css"] -}) -export class DataservicesListComponent { + }) +export class DataservicesListComponent implements OnInit { + public static readonly activateDataserviceEvent = "activate"; + public static readonly deleteDataserviceEvent = "delete"; + public static readonly editDataserviceEvent = "edit"; + public static readonly publishDataserviceEvent = "publish"; + public static readonly quickLookDataserviceEvent = "quickLook"; + public static readonly testDataserviceEvent = "test"; + + public readonly activateEvent = DataservicesListComponent.activateDataserviceEvent; + public readonly deleteEvent = DataservicesListComponent.deleteDataserviceEvent; + public readonly editEvent = DataservicesListComponent.editDataserviceEvent; + public readonly publishEvent = DataservicesListComponent.publishDataserviceEvent; + public readonly quickLookEvent = DataservicesListComponent.quickLookDataserviceEvent; + public readonly testEvent = DataservicesListComponent.testDataserviceEvent; + + actionConfig: ActionConfig; + actionsText: string = ''; + allItems: Dataservice[]; + items: Dataservice[]; + listConfig: ListConfig; @Input() public dataservices: Dataservice[]; @Input() public selectedDataservices: Dataservice[]; @Output() public dataserviceSelected: EventEmitter = new EventEmitter(); @@ -39,16 +67,69 @@ export class DataservicesListComponent { @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); - private router: Router; + public logger: LoggerService; /** - * Constructor. + * @param {LoggerService} logger the logging service */ - constructor(router: Router) { - this.router = router; + constructor( logger: LoggerService ) { + this.logger = logger; + } + + ngOnInit(): void { + + this.items = this.dataservices; + + this.actionConfig = { + primaryActions: [{ + id: 'edit', + title: 'Edit', + tooltip: 'Edit this data service' + }, + { + id: 'test', + title: 'Test', + tooltip: 'Test this data service' + }, + { + id: 'quickLook', + title: 'Preview', + tooltip: 'Preview this data service' + }], + moreActions: [{ + disabled: false, + id: 'activate', + title: 'Activate', + tooltip: 'Activate this data service' + }, + { + id: 'publish', + title: 'Publish', + tooltip: 'Publish this data service' + }, + { + id: 'refresh', + title: 'Refresh', + tooltip: 'Refresh this data service' + }, + { + id: 'delete', + title: 'Delete', + tooltip: 'Delete this data service' + }], + } as ActionConfig; + + this.listConfig = { + dblClick: false, + multiSelect: false, + selectItems: false, + selectionMatchProp: 'name', + showCheckbox: false, + useExpandItems: true + } as ListConfig; } - public toggleDataserviceSelected(dataservice: Dataservice): void { + public toggleDataserviceSelected(dataservice: Dataservice): void { if (this.isSelected(dataservice)) { this.dataserviceDeselected.emit(dataservice); } else { @@ -84,10 +165,39 @@ export class DataservicesListComponent { this.quickLookDataservice.emit(dataserviceName); } - // public onSelectTag(tag: string, event: MouseEvent): void { - // event.stopPropagation(); - // event.preventDefault(); - // this.tagSelected.emit(tag); - // } + ngDoCheck(): void { + } + + // Actions + + handleAction($event: Action, item: any): void { + switch ( $event.id ) { + case DataservicesListComponent.activateDataserviceEvent: + this.activateDataservice.emit( item.getId() ); + break; + case DataservicesListComponent.deleteDataserviceEvent: + this.deleteDataservice.emit( item.getId() ); + break; + case DataservicesListComponent.editDataserviceEvent: + this.editDataservice.emit( item.getId() ); + break; + case DataservicesListComponent.publishDataserviceEvent: + this.publishDataservice.emit( item.getId() ); + break; + case DataservicesListComponent.quickLookDataserviceEvent: + this.quickLookDataservice.emit( item.getId() ); + break; + case DataservicesListComponent.testDataserviceEvent: + this.testDataservice.emit( item.getId() ); + break; + default: + this.logger.error( "Unhandled event type of '" + $event.title + "'" ); + break; + } + + // handleClick($event: ListEvent): void { + // this.actionsText = $event.item.name + ' clicked\r\n' + this.actionsText; + // } + } } diff --git a/ngapp/src/app/dataservices/dataservices-list/views-content.component.html b/ngapp/src/app/dataservices/dataservices-list/views-content.component.html new file mode 100644 index 00000000..10b2bc1c --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/views-content.component.html @@ -0,0 +1,24 @@ +
    +
    +
    + + +
    + {{ item }} +
    +
    + +
    +
    + {{ connection.getId() }} +
    +
    +
    +
    +
    +
    +
    diff --git a/ngapp/src/app/dataservices/dataservices-list/views-content.component.ts b/ngapp/src/app/dataservices/dataservices-list/views-content.component.ts new file mode 100644 index 00000000..e77a137e --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/views-content.component.ts @@ -0,0 +1,60 @@ +import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { Connection } from "@connections/shared/connection.model"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { } from "@dataservices/shared/dataservice.model"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: 'views-content', + templateUrl: './views-content.component.html' +}) +export class ViewsContentComponent implements OnInit { + @Input() public item: Dataservice; + @Input() public selectedDataservices: Dataservice[]; + + + constructor() { + } + /** + * @param {string} view the view whose connections are being requested + * @returns {Connection[]} the connections of the dataservice represented by this card + */ + public getConnections( view: string ): Connection[] { + // TODO rewrite when REST functionality has been implemented + const result: Connection[] = []; + + const c1 = new Connection(); + c1.setId( "ConnectionOne" ); + result.push( c1 ); + + const c2 = new Connection(); + c2.setId( "ConnectionTwo" ); + result.push( c2 ); + + const c3 = new Connection(); + c3.setId( "ConnectionThree" ); + result.push( c3 ); + + return result; + } + + /** + * @param {Dataservice} ds the dataservice whose views are being requested + * @returns {string[]} the names of the views + */ + public getViews( ds: Dataservice ): string[] { + const result: string[] = []; + + for (const viewName of ds.getServiceViewNames()) { + result.push(viewName); + } + + return result; + } + + ngOnInit(): void { + } + + ngDoCheck(): void { + } +} diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 2745f35b..54475f01 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -41,6 +41,8 @@ import { JdbcTableSelectorComponent } from "./jdbc-table-selector/jdbc-table-sel import { SelectedTableComponent } from "./selected-table/selected-table.component"; import { SqlControlComponent } from "./sql-control/sql-control.component"; import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.component"; +import {BasicContentComponent} from "@dataservices/dataservices-list/basic-content.component"; +import {ViewsContentComponent} from "@dataservices/dataservices-list/views-content.component"; @NgModule({ imports: [ @@ -56,6 +58,8 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co CodemirrorModule ], declarations: [ + BasicContentComponent, + ViewsContentComponent, DataservicesCardsComponent, DataservicesComponent, DataservicesListComponent, From b61b416c63e174a0346b9dae2de982eba4f165df Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 12 Feb 2018 08:51:10 -0600 Subject: [PATCH 085/205] TEIIDTOOLS-309 Rework Connections Summary page in Beetle Studio - created ConnectionCardComponent - updated connection cards to patternfly-ng - increase dataservice create polling duration time to 2 minutes - created style theme - style changes to dataservice card and also changed to use theme when possible - style changes to selected table card and also changed to use theme when possible --- .../connection-card.component.css | 0 .../connection-card.component.html | 55 ++++ .../connection-card.component.spec.ts | 36 +++ .../connection-card.component.ts | 156 ++++++++++++ .../connections-cards.component.css | 62 ----- .../connections-cards.component.html | 68 ++--- .../connections-cards.component.spec.ts | 6 +- .../connections-cards.component.ts | 47 ++-- .../connection-details.component.html | 12 + .../connection-details.component.ts | 39 +++ .../connections-list.component.css | 41 +-- .../connections-list.component.html | 80 +++--- .../connections-list.component.spec.ts | 6 +- .../connections-list.component.ts | 134 ++++++++-- .../app/connections/connections.component.css | 1 + .../connections/connections.component.html | 26 +- .../connections/connections.component.spec.ts | 23 +- .../app/connections/connections.component.ts | 14 +- .../src/app/connections/connections.module.ts | 11 +- .../connections/shared/connection.model.ts | 23 ++ .../shared/connections-constants.ts | 4 + .../add-dataservice-wizard.component.ts | 2 +- .../dataservice-card.component.css | 151 ++--------- .../dataservice-card.component.html | 104 ++------ .../dataservice-card.component.spec.ts | 4 +- .../dataservice-card.component.ts | 85 +++++- .../dataservices-cards.component.ts | 6 +- .../dataservices/dataservices.component.html | 2 +- .../dataservices.component.spec.ts | 2 +- ngapp/src/environments/environment.prod.ts | 2 +- ngapp/src/environments/environment.ts | 2 +- ngapp/src/styles.css | 241 ++++++++++++++++++ 32 files changed, 995 insertions(+), 450 deletions(-) create mode 100644 ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css create mode 100644 ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html create mode 100644 ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts create mode 100644 ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts create mode 100644 ngapp/src/app/connections/connections-list/connection-details.component.html create mode 100644 ngapp/src/app/connections/connections-list/connection-details.component.ts diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html new file mode 100644 index 00000000..bfe5ddb4 --- /dev/null +++ b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html @@ -0,0 +1,55 @@ + + +
    +
    + + +
    + + + + +
    + +
    +
    {{ connection.description }}
    +
    +
    +
    +
    +
    Properties
    +
    +
    + + +
    +
    {{ item[ 0 ] }}
    +
    {{ item[ 1 ] }}
    +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts new file mode 100644 index 00000000..3bd9f575 --- /dev/null +++ b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts @@ -0,0 +1,36 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { RouterTestingModule } from "@angular/router/testing"; +import { Connection } from "@connections/shared/connection.model"; +import { LoggerService } from "@core/logger.service"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { ConnectionCardComponent } from "./connection-card.component"; + +describe("ConnectionCardComponent", () => { + let component: ConnectionCardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ PatternFlyNgModule, RouterTestingModule ], + declarations: [ ConnectionCardComponent ], + providers: [ LoggerService ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConnectionCardComponent); + component = fixture.componentInstance; + + const connection = new Connection(); + connection.setId( "MyConnection" ); + component.connection = connection; + component.selectedConnections = [ connection ]; + + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts new file mode 100644 index 00000000..9f094259 --- /dev/null +++ b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts @@ -0,0 +1,156 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { LoggerService } from "@core/logger.service"; +import { Action, ActionConfig, CardAction, CardConfig, ListConfig } from "patternfly-ng"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-connection-card", + templateUrl: "./connection-card.component.html", + styleUrls: ["./connection-card.component.css"] +}) +export class ConnectionCardComponent implements OnInit { + + public static readonly deleteConnectionEvent = "delete"; + public static readonly editConnectionEvent = "edit"; + public static readonly pingConnectionEvent = "ping"; + + public readonly editEvent = ConnectionCardComponent.editConnectionEvent; + public readonly pingEvent = ConnectionCardComponent.pingConnectionEvent; + + @Input() public connection: Connection; + @Input() public selectedConnections: Connection[]; + @Output() public cardEvent: EventEmitter< {} > = new EventEmitter< {} >(); + @Output() public selectEvent: EventEmitter< Connection > = new EventEmitter< Connection >(); + + public actionConfig: ActionConfig; + public cardConfig: CardConfig; + public listConfig: ListConfig; + public showDetails = false; + + private readonly deleteActionId = "delete"; + private logger: LoggerService; + + constructor( logger: LoggerService ) { + this.logger = logger; + } + + /** + * @returns {string[][]} the properties of a connection + */ + public get properties(): string[][] { + const props = [ + [ ConnectionsConstants.jndiNamePropertyLabel, this.connection.getJndiName() ], + [ ConnectionsConstants.driverNamePropertyLabel, this.connection.getDriverName() ], + [ ConnectionsConstants.serviceCatalogSourceNameLabel, this.connection.getServiceCatalogSourceName() ], + ]; + + return props; + } + + /** + * Event handler for when a toolbar kebab action is clicked. + * @param {Action} action the action that was selected. + */ + public handleAction( action: Action ): void { + if ( action.id === this.deleteActionId ) { + this.onClick( ConnectionCardComponent.deleteConnectionEvent ); + } else { + this.logger.error( "Action '" + action.id + "' not handled." ); + } + } + + /** + * @returns {boolean} `true` if the connection represented by this card is selected + */ + public isSelected(): boolean { + return this.selectedConnections.indexOf( this.connection ) !== -1; + } + + /** + * Initializes the ActionConfig, CardConfig, and ListConfig. + */ + public ngOnInit(): void { + this.actionConfig = { + primaryActions: [ + ], + moreActions: [ + { + id: this.deleteActionId, + title: "Delete", + tooltip: "Delete the connection" + } + ] + } as ActionConfig; + + this.cardConfig = { + action: { + id: "showDetails", + hypertext: this.showDetailsTitle, + iconStyleClass: "fa fa-info-circle" + }, + titleBorder: true, + noPadding: true, + topBorder: false + } as CardConfig; + + this.listConfig = { + dblClick: false, + multiSelect: false, + selectItems: false, + selectedItems: this.selectedConnections, + showCheckbox: false, + useExpandItems: false + } as ListConfig; + } + + /** + * An event handler for when a toolbar action is invoked. + * @param {string} type the type of event being processed + */ + public onClick( type: string ): void { + this.cardEvent.emit( { eventType: type, connectionName: this.connection.getId() } ); + } + + /** + * An event handler for when the card is clicked. + */ + public onSelect(): void { + this.selectEvent.emit( this.connection ); + } + + /** + * An event handler for footer action link. + * @param {CardAction} $event the event being processed + */ + public onShowDetails( $event: CardAction ): void { + this.showDetails = !this.showDetails; + $event.hypertext = this.showDetailsTitle; + } + + /** + * @returns {string} the footer details action text + */ + public get showDetailsTitle(): string { + return this.showDetails ? "Hide Details" : "Show Details"; + } + +} diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.css b/ngapp/src/app/connections/connections-cards/connections-cards.component.css index a9f61fef..8abeffb9 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.css +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.css @@ -6,65 +6,3 @@ .row-cards-pf { padding: 0; } - -.connection-card-action-icon { - cursor: pointer; -} - -.connection-card-icon { - border: 2px solid #39a5dc; - border-radius: 50%; - padding: 5px; - margin-right: 10px; - width: 32px; -} - -.connection-card .connection-card-title { - font-size: 16px; - font-weight: bold; -} - -.connection-card { - -webkit-transition: background-color 300ms; - -moz-transition: background-color 300ms; - //-ms-transition: background-color 300ms; - -o-transition: background-color 300ms; - transition: background-color 300ms; - height: 160px; -} -.connection-card:hover { - background-color: rgb(237, 237, 237); -} - -.connection-card.active { - background-color: rgb(221, 234, 255); -} - -/* -.connection-description { - font-size: 13px; - overflow-y: auto; -} -*/ - -.connection-card .connection-tags { - margin-bottom: 8px; -} -.connection-card .connection-tags .connection-tags-label { - font-weight: bold; - margin-right: 5px; -} -.connection-card .connection-tags /*.connection-tag*/ { - margin-right: 5px; - border: 1px solid #ccc; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - padding: 2px 4px; -} -.connection-card .connection-tags /*.connection-tag:hover*/ { - cursor: pointer; - background-color: #0088ce; - border-color: #00659c; - color: white; -} diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.html b/ngapp/src/app/connections/connections-cards/connections-cards.component.html index af6cbea6..9be813a5 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.html +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.html @@ -1,32 +1,40 @@ -
    -
    - -
    -
    -
    - -

    - - {{ connection.getId() }} - -

    -
    -
    - JNDI:  {{ connection.getJndiName() }} -
    -
    - Driver:  {{ connection.getDriverName() }} -
    - -
    -
    -
    - +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts index fa4ef834..dd983ab8 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts @@ -1,6 +1,8 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionCardComponent } from "@connections/connections-cards/connection-card/connection-card.component"; import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; +import { PatternFlyNgModule } from "patternfly-ng"; describe("ConnectionsCardsComponent", () => { let component: ConnectionsCardsComponent; @@ -8,8 +10,8 @@ describe("ConnectionsCardsComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ RouterTestingModule ], - declarations: [ ConnectionsCardsComponent ] + imports: [ PatternFlyNgModule, RouterTestingModule ], + declarations: [ ConnectionCardComponent, ConnectionsCardsComponent ] }) .compileComponents().then(() => { // nothing to do diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts index b4a76458..3d0397b2 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts @@ -16,6 +16,7 @@ */ import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { ConnectionCardComponent } from "@connections/connections-cards/connection-card/connection-card.component"; import { Connection } from "@connections/shared/connection.model"; @Component({ @@ -28,11 +29,12 @@ export class ConnectionsCardsComponent { @Input() public connections: Connection[]; @Input() public selectedConnections: Connection[]; + @Output() public connectionSelected: EventEmitter = new EventEmitter(); @Output() public connectionDeselected: EventEmitter = new EventEmitter(); - @Output() public tagSelected: EventEmitter = new EventEmitter(); - @Output() public pingConnection: EventEmitter = new EventEmitter(); @Output() public deleteConnection: EventEmitter = new EventEmitter(); + @Output() public editConnection: EventEmitter = new EventEmitter(); + @Output() public pingConnection: EventEmitter = new EventEmitter(); /** * Constructor. @@ -41,30 +43,31 @@ export class ConnectionsCardsComponent { // nothing to do } - public toggleConnectionSelected(connection: Connection): void { - if (this.isSelected(connection)) { - this.connectionDeselected.emit(connection); - } else { - this.connectionSelected.emit(connection); - } + public isSelected( connection: Connection ): boolean { + return this.selectedConnections.indexOf( connection ) !== -1; } - public isSelected(connection: Connection): boolean { - return this.selectedConnections.indexOf(connection) !== -1; - } - - public onPingConnection(connectionName: string): void { - this.pingConnection.emit(connectionName); - } - - public onDeleteConnection(connectionName: string): void { - this.deleteConnection.emit(connectionName); + public onCardEvent( event: { eventType: string, + connectionName: string } ): void { + switch ( event.eventType ) { + case ConnectionCardComponent.deleteConnectionEvent: + this.deleteConnection.emit( event.connectionName ); + break; + case ConnectionCardComponent.editConnectionEvent: + this.editConnection.emit( event.connectionName ); + break; + case ConnectionCardComponent.pingConnectionEvent: + this.pingConnection.emit( event.connectionName ); + break; + default: + // TODO log this + // this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); + break; + } } - public onSelectTag(tag: string, event: MouseEvent): void { - event.stopPropagation(); - event.preventDefault(); - this.tagSelected.emit(tag); + public onSelectEvent( connection: Connection ): void { + this.connectionSelected.emit( connection ); } } diff --git a/ngapp/src/app/connections/connections-list/connection-details.component.html b/ngapp/src/app/connections/connections-list/connection-details.component.html new file mode 100644 index 00000000..bbfbce28 --- /dev/null +++ b/ngapp/src/app/connections/connections-list/connection-details.component.html @@ -0,0 +1,12 @@ +
    +
    +
    +
    {{ jndiLabel }}
    +
    {{ connection.getJndiName() }}
    +
    {{ driverLabel }}
    +
    {{ connection.getDriverName() }}
    +
    {{ serviceCatalogSourceLabel }}
    +
    {{ connection.getServiceCatalogSourceName() }}
    +
    +
    +
    diff --git a/ngapp/src/app/connections/connections-list/connection-details.component.ts b/ngapp/src/app/connections/connections-list/connection-details.component.ts new file mode 100644 index 00000000..541d755b --- /dev/null +++ b/ngapp/src/app/connections/connections-list/connection-details.component.ts @@ -0,0 +1,39 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, Input, ViewEncapsulation } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-connection-details", + templateUrl: "./connection-details.component.html" +}) +export class ConnectionDetailsComponent { + + public readonly driverLabel = ConnectionsConstants.driverNamePropertyLabel; + public readonly jndiLabel = ConnectionsConstants.jndiNamePropertyLabel; + public readonly serviceCatalogSourceLabel = ConnectionsConstants.serviceCatalogSourceNameLabel; + + @Input() public connection: Connection; + + constructor() { + // nothing to do + } + +} diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.css b/ngapp/src/app/connections/connections-list/connections-list.component.css index ccc88b6f..8a7ece17 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.css +++ b/ngapp/src/app/connections/connections-list/connections-list.component.css @@ -1,39 +1,8 @@ -.list-view-pf-main-info { - padding-bottom: 5px; - padding-top: 5px; -} -.list-group-item { - -webkit-transition: background-color 300ms; - -moz-transition: background-color 300ms; - //-ms-transition: background-color 300ms; - -o-transition: background-color 300ms; - transition: background-color 300ms; -} -.list-group-item, .list-group-item:first-child { - margin-bottom: 5px; - border-top: 1px solid rgb(57, 165, 220); -} -.list-group-item.active { - background-color: #ffffff; +.connections-list .close { + float: left; } -.list-group-item .connection-tags { -} -.list-group-item .connection-tags .connection-tags-label { - font-weight: bold; - margin-right: 5px; -} -.list-group-item .connection-tags /*.connection-tag*/ { - margin-right: 5px; - border: 1px solid #ccc; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - padding: 2px 4px; -} -.list-group-item .connection-tags /*.connection-tag:hover*/ { - cursor: pointer; - background-color: #0088ce; - border-color: #00659c; - color: white; +.connections-list .list-pf-actions { + flex-grow: 1; + justify-content: flex-end; } diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.html b/ngapp/src/app/connections/connections-list/connections-list.component.html index 97fc8e3d..47cc26a9 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.html +++ b/ngapp/src/app/connections/connections-list/connections-list.component.html @@ -1,36 +1,50 @@ -
    -
    -
    -
    - -
    -
    - -
    -
    - JNDI:  {{ connection.getJndiName() }}     -
    -
    - Driver:  {{ connection.getDriverName() }} -
    - -
    -
    -
    - - +
    +
    +
    +
    + + +
    + +
    +
    +
    + {{ item.name }} +
    +
    +
    {{ item.description }}
    +
    +
    +
    + + + +  {{ action.title }} + + +  {{ action.title }} + + +  {{ action.title }} + + + + + + +
    diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts index 761ce445..3c5d8a38 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts +++ b/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts @@ -1,6 +1,8 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionDetailsComponent } from "@connections/connections-list/connection-details.component"; import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; +import { PatternFlyNgModule } from "patternfly-ng"; describe("ConnectionsListComponent", () => { let component: ConnectionsListComponent; @@ -8,8 +10,8 @@ describe("ConnectionsListComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ RouterTestingModule ], - declarations: [ ConnectionsListComponent ] + imports: [ PatternFlyNgModule, RouterTestingModule ], + declarations: [ ConnectionDetailsComponent, ConnectionsListComponent ] }) .compileComponents().then(() => { // nothing to do diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.ts b/ngapp/src/app/connections/connections-list/connections-list.component.ts index 830a1d5c..9ba61f9a 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.ts +++ b/ngapp/src/app/connections/connections-list/connections-list.component.ts @@ -15,28 +15,36 @@ * limitations under the License. */ -import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewEncapsulation } from "@angular/core"; import { Router } from "@angular/router"; import { Connection } from "@connections/shared/connection.model"; +import { Action, ActionConfig, ListConfig } from "patternfly-ng"; @Component({ moduleId: module.id, + encapsulation: ViewEncapsulation.None, selector: "app-connections-list", templateUrl: "connections-list.component.html", styleUrls: ["connections-list.component.css"] }) -export class ConnectionsListComponent { +export class ConnectionsListComponent implements OnInit { @Input() public connections: Connection[]; @Input() public selectedConnections: Connection[]; - @Output() public connectionSelected: EventEmitter = new EventEmitter(); + @Output() public connectionDeselected: EventEmitter = new EventEmitter(); - @Output() public tagSelected: EventEmitter = new EventEmitter(); - @Output() public pingConnection: EventEmitter = new EventEmitter(); + @Output() public connectionSelected: EventEmitter = new EventEmitter(); @Output() public deleteConnection: EventEmitter = new EventEmitter(); + @Output() public editConnection: EventEmitter = new EventEmitter(); + @Output() public pingConnection: EventEmitter = new EventEmitter(); + public listConfig: ListConfig; private router: Router; + private readonly deleteActionId = "delecteActionId"; + private readonly editActionId = "editActionId"; + private readonly pingActionId = "pingActionId"; + /** * Constructor. */ @@ -44,30 +52,118 @@ export class ConnectionsListComponent { this.router = router; } - public toggleConnectionSelected(connection: Connection): void { - if (this.isSelected(connection)) { - this.connectionDeselected.emit(connection); - } else { - this.connectionSelected.emit(connection); - } + /** + * Initializes the list config. + */ + public ngOnInit(): void { + this.listConfig = { + dblClick: false, + multiSelect: false, + selectItems: true, + selectedItems: this.selectedConnections, + showCheckbox: false, + useExpandItems: true + } as ListConfig; + } + + /** + * Get the ActionConfig properties for each row. + * + * @param connection the connection represented by a row + * @param editActionTemplate {TemplateRef} the edit action template + * @param pingActionTemplate {TemplateRef} the ping action template + * @param deleteActionTemplate {TemplateRef} the delete action template + * @returns {ActionConfig} the actions configuration + */ + public getActionConfig( connection: Connection, + editActionTemplate: TemplateRef< any >, + pingActionTemplate: TemplateRef< any >, + deleteActionTemplate: TemplateRef< any > ): ActionConfig { + const actionConfig = { + primaryActions: [ + { + id: this.editActionId, + template: editActionTemplate, + title: "Edit", + tooltip: "Edit properties" + }, + { + id: this.pingActionId, + template: pingActionTemplate, + title: "Ping", + tooltip: "Determine if accessible" + } + ], + moreActions: [ + { + id: this.deleteActionId, + template: deleteActionTemplate, + title: "Delete", + tooltip: "Delete the connection" + } + ], + moreActionsDisabled: false, + moreActionsVisible: true + } as ActionConfig; + + return actionConfig; } - public isSelected(connection: Connection): boolean { - return this.selectedConnections.indexOf(connection) !== -1; + /** + * Event handler for when a toolbar icon or kebab action is clicked. + * @param {Action} action the action that was selected. + * @param {any} not used + */ + public handleAction( action: Action, + item: any ): void { + if ( action.id === this.deleteActionId ) { + this.onDeleteConnection( this.selectedConnections[ 0 ].getId() ); + } else if ( action.id === this.editActionId ) { + this.onEditConnection( this.selectedConnections[ 0 ].getId() ); + } else if ( action.id === this.pingActionId ) { + this.onPingConnection( this.selectedConnections[ 0 ].getId() ); + } } - public onPingConnection(connectionName: string): void { - this.pingConnection.emit(connectionName); + /** + * @returns {boolean} `true` if the connection row is selected in the list + */ + public isSelected( connection: Connection ): boolean { + return this.selectedConnections.indexOf( connection ) !== -1; } + /** + * @param {string} connectionName the name of the connection to delete + */ public onDeleteConnection(connectionName: string): void { this.deleteConnection.emit(connectionName); } - public onSelectTag(tag: string, event: MouseEvent): void { - event.stopPropagation(); - event.preventDefault(); - this.tagSelected.emit(tag); + /** + * @param {string} connectionName the name of the connection to edit + */ + public onEditConnection( connectionName: string ): void { + this.editConnection.emit( connectionName ); + } + + /** + * @param {string} connectionName the name of the connection to ping + */ + public onPingConnection( connectionName: string ): void { + this.pingConnection.emit( connectionName ); + } + + /** + * @param $event the list row selection event being handled + */ + public onSelect( $event ): void { + if ( $event.selectedItems.length === 0 ) { + if ( this.selectedConnections.length !== 0 ) { + this.connectionDeselected.emit( $event.selectedItems[ 0 ] ); + } + } else { + this.connectionSelected.emit( $event.selectedItems[ 0 ] ); + } } } diff --git a/ngapp/src/app/connections/connections.component.css b/ngapp/src/app/connections/connections.component.css index b92fbe0b..dd2e8a73 100644 --- a/ngapp/src/app/connections/connections.component.css +++ b/ngapp/src/app/connections/connections.component.css @@ -11,6 +11,7 @@ } .connection-list-items { + background-color: #fafafa; margin-top: 10px; height: 75vh; overflow-y: auto; diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index e553cdfa..a9125145 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -89,12 +89,22 @@

    - - + +

    @@ -103,5 +113,7 @@

    -

    Do you really want to delete the selected Connection?

    +

    + Do you really want to delete the '{{connectionNameForDelete}}' Connection? +

    diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index b5708a94..1bd7ed6c 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -3,7 +3,9 @@ import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; import { By } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionCardComponent } from "@connections/connections-cards/connection-card/connection-card.component"; import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; +import { ConnectionDetailsComponent } from "@connections/connections-list/connection-details.component"; import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; import { ConnectionsComponent } from "@connections/connections.component"; import { ConnectionService } from "@connections/shared/connection.service"; @@ -13,6 +15,7 @@ import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { SharedModule } from "@shared/shared.module"; import { ModalModule } from "ngx-bootstrap"; +import { PatternFlyNgModule } from "patternfly-ng"; describe("ConnectionsComponent", () => { let component: ConnectionsComponent; @@ -20,8 +23,22 @@ describe("ConnectionsComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), RouterTestingModule, SharedModule ], - declarations: [ ConnectionsComponent, ConnectionsListComponent, ConnectionsCardsComponent ] + imports: [ + CoreModule, + FormsModule, + HttpModule, + ModalModule.forRoot(), + PatternFlyNgModule, + RouterTestingModule, + SharedModule + ], + declarations: [ + ConnectionsComponent, + ConnectionDetailsComponent, + ConnectionsListComponent, + ConnectionCardComponent, + ConnectionsCardsComponent + ] }); // use mock service @@ -66,7 +83,7 @@ describe("ConnectionsComponent", () => { expect(connections.length).toEqual(3); // Check html has the same number of connection cards - const cardDebugElems = fixture.debugElement.queryAll(By.css(".connection-card-title")); + const cardDebugElems = fixture.debugElement.queryAll(By.css(".object-card")); expect(cardDebugElems).toBeDefined(); expect(cardDebugElems.length).toEqual(3); }); diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index d48107f0..11de65fa 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -17,6 +17,7 @@ import { Component, ViewChild } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; +import { ConnectionCardComponent } from "@connections/connections-cards/connection-card/connection-card.component"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; @@ -39,10 +40,10 @@ export class ConnectionsComponent extends AbstractPageComponent { public readonly addConnectionLink: string = ConnectionsConstants.addConnectionPath; + public connectionNameForDelete: string; private allConns: Connection[] = []; private filteredConns: Connection[] = []; private selectedConns: Connection[] = []; - private connectionNameForDelete: string; private router: Router; private appSettingsService: AppSettingsService; private connectionService: ConnectionService; @@ -126,8 +127,15 @@ export class ConnectionsComponent extends AbstractPageComponent { return this.selectedConns; } - public onPing( connName: string): void { - alert("Ping connection " + connName); + public onEdit( connectionName: string ): void { + const connection = this.filterConnections().find( ( conn ) => conn.getId() === connectionName ); + // TODO: implement onEdit + alert( "Edit '" + connectionName + "' connection (not yet implemented)" ); + } + + public onPing( connName: string ): void { + // TODO: implement onEdit + alert( "Ping the '" + connName + "' connection (not yet implemented)" ); } public onSelected(connection: Connection): void { diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 0e029bc3..09325dcb 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -19,7 +19,11 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; +import { AddConnectionWizardComponent } from "@connections/add-connection-wizard/add-connection-wizard.component"; +import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; +import { ConnectionCardComponent } from "@connections/connections-cards/connection-card/connection-card.component"; import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; +import { ConnectionDetailsComponent } from "@connections/connections-list/connection-details.component"; import { ConnectionsListComponent } from "@connections/connections-list/connections-list.component"; import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; import { ConnectionsComponent } from "@connections/connections.component"; @@ -28,8 +32,6 @@ import { CoreModule } from "@core/core.module"; import { LoggerService } from "@core/logger.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; -import { AddConnectionWizardComponent } from "./add-connection-wizard/add-connection-wizard.component"; -import { AddConnectionComponent } from "./add-connection/add-connection.component"; @NgModule({ imports: [ @@ -43,11 +45,14 @@ import { AddConnectionComponent } from "./add-connection/add-connection.componen PatternFlyNgModule ], declarations: [ + ConnectionDetailsComponent, + ConnectionCardComponent, ConnectionsCardsComponent, ConnectionsComponent, ConnectionsListComponent, AddConnectionWizardComponent, - AddConnectionComponent + AddConnectionComponent, + ConnectionCardComponent ], providers: [ ConnectionService, diff --git a/ngapp/src/app/connections/shared/connection.model.ts b/ngapp/src/app/connections/shared/connection.model.ts index 382eca29..4365dd7a 100644 --- a/ngapp/src/app/connections/shared/connection.model.ts +++ b/ngapp/src/app/connections/shared/connection.model.ts @@ -79,6 +79,14 @@ export class Connection implements Identifiable< string > { return result; } + /** + * @returns {string} the connection description + */ + public get description(): string { + // TODO do connections have a description + return "This is a connection description. So if you're looking for the description you found it."; + } + /** * @returns {string} the connection driver name (can be null) */ @@ -100,6 +108,14 @@ export class Connection implements Identifiable< string > { return this.dv__jndiName; } + /** + * @returns {string} the service catalog source name of this connection + */ + public getServiceCatalogSourceName(): string { + // TODO: finish implenting getServiceCatalogSourceName() + return "TBD"; + } + /** * @returns {boolean} the jdbc status (true == jdbc) */ @@ -107,6 +123,13 @@ export class Connection implements Identifiable< string > { return this.dv__type; } + /** + * @returns {string} the connection name + */ + public get name(): string { + return this.keng__id; + } + /** * @returns {Map} the connection properties (never null) */ diff --git a/ngapp/src/app/connections/shared/connections-constants.ts b/ngapp/src/app/connections/shared/connections-constants.ts index 61a7d098..0f5e5b6a 100644 --- a/ngapp/src/app/connections/shared/connections-constants.ts +++ b/ngapp/src/app/connections/shared/connections-constants.ts @@ -23,6 +23,10 @@ export class ConnectionsConstants { public static readonly addConnectionRoute = ConnectionsConstants.connectionsRootRoute + "/add-connection"; public static readonly addConnectionPath = ConnectionsConstants.connectionsRootPath + "/add-connection"; + public static driverNamePropertyLabel = "Driver Name"; + public static jndiNamePropertyLabel = "JNDI Name"; + public static serviceCatalogSourceNameLabel = "Service Catalog Source"; + public static readonly connectionsNavItem: NavigationItemConfig = { title: "Connections", iconStyleClass: "fa fa-fw fa-plug", diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 0ca4df21..ba073334 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -292,7 +292,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { (wasSuccess) => { // Deployment succeeded - wait for source vdb to become active if (wasSuccess) { - self.vdbService.pollForActiveVdb(sourceVdbName, 120, 5); + self.vdbService.pollForActiveVdb(sourceVdbName, 240, 5); } else { self.setFinalPageComplete(false); self.sourceVdbUnderDeployment = null; diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index 52631080..662bae2b 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -1,159 +1,48 @@ -:root { - --body-background-color: #f5f5f5; - --body-main-color: #72767b; - --border-color: #39a5dc; - --border-style: double; - --border-width: 2px; - --hover-color: rgb(221, 234, 255); +.card-toolbar .secondary-action[title="Publish"]:before { + content: "\f08e"; + font-family: "FontAwesome"; } -.card-pf .card-pf-body { - margin: 0; - padding: 0; +.card-toolbar .secondary-action[title="Refresh"]:before { + content: "\f021"; + font-family: "FontAwesome"; } -.dataservice-card { - -webkit-transition: background-color 300ms; - -moz-transition: background-color 300ms; -//-ms-transition: background-color 300ms; - -o-transition: background-color 300ms; - transition: background-color 300ms; - margin: 0px 10px; - height: 160px; -} - -.dataservice-card .card-pf { - margin: 0; - padding: 0 20px; -} - -.dataservice-card .card-pf:hover { - background-color: var(--hover-color); -} - -.dataservice-card .card-pf .card-pf-footer { - background-color: #ececec; - min-height: 20px; - padding: 10px 0 5px 20px; -} - -.dataservice-card .card-pf .card-pf-heading { - border-bottom: none; - margin: 0px -20px 0px -20px; - padding: 0 20px; -} - -.dataservice-card-action-disabled-icon { - color: lightgray; - font-size: 1.5em; - height: 24px !important; - margin-left: 4px; - margin-top: 4px; - width: 24px !important; -} - -.dataservice-card-action-icon { - color: var(--border-color); - cursor: pointer; - font-size: 1.5em; - height: 24px !important; - margin-left: 0 !important; - margin-top: 4px; - width: 24px !important; -} - -.dataservice-card-body { - /*background-color: #dc7039;*/ - margin: 0 -20px; -} - -.dataservice-card-body-title { - background-color: var(--body-main-color); - color: white; - margin: 0; - text-align: center; -} - -/*.dataservice-card-body-title {*/ - /*margin: 0 !important;*/ -/*}*/ - -.dataservice-card-body-title-selected { - border-left: var(--border-width) var(--border-style) var(--border-color); - border-right: var(--border-width) var(--border-style) var(--border-color); -} - -.dataservice-card-description { - color: slategray; - height: 50px; - overflow: auto; - padding: 0 5px 5px 5px; -} - -.dataservice-card-icon { - border: 2px solid var(--border-color); - border-radius: 60px; - display: inline-block; - padding: 0.1em 0.2em; -} - -.dataservice-card-selected { -} - -.dataservice-card-selected .card-pf .card-pf-heading { - border-top: var(--border-width) var(--border-style) var(--border-color); - border-right: var(--border-width) var(--border-style) var(--border-color); - border-left: var(--border-width) var(--border-style) var(--border-color); - padding: 0px 20px; -} - -.dataservice-card-selected .card-pf .card-pf-footer { - border-right: var(--border-width) var(--border-style) var(--border-color); - border-left: var(--border-width) var(--border-style) var(--border-color); - border-bottom: var(--border-width) var(--border-style) var(--border-color); -} - -.dataservice-card-title { - font-size: 16px; - font-weight: bold; - margin: 10px 0 !important; +.object-card .list-pf { + border: none; } -.dataservice-card-toolbar { - border-top: 1px solid lightgrey; - border-bottom: 1px solid lightgrey; - margin-bottom: 6px; - margin-top: 0; +.object-card-selected .list-pf { + border: none; } -.dataservice-card-toolbar-kebab { - margin-left: 0 !important; - margin-right: 4px; +.object-card .list-pf-item { + border: none; } -.list-pf { +.object-card-selected .list-pf-item { border: none; } -.list-pf-item { - border: none; +.object-card .list-pf-item:hover { + background-color: transparent; } -.list-pf-item:hover { +.object-card-selected .list-pf-item:hover { background-color: transparent; } .view-name { cursor: pointer; - color: var(--body-main-color); + color: var(--card-body-color); } .views-details { - background-color: var(--body-background-color); + background-color: var(--card-body-background-color); border-bottom: 2px solid lightgrey; } .views-details-selected { - border-left: var(--border-width) var(--border-style) var(--border-color); - border-right: var(--border-width) var(--border-style) var(--border-color); + border-left: var(--card-border-width) var(--card-border-style) var(--card-border-color); + border-right: var(--card-border-width) var(--card-border-style) var(--card-border-color); } diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index 9e4e1a73..ea791e35 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -2,151 +2,103 @@ [headerTemplate]="tableHeaderTemplate" (onActionSelect)="onShowDetails( $event )" (click)="onSelect()" - [class]="isSelected() ? 'dataservice-card dataservice-card-selected' : 'dataservice-card'"> + [class]="isSelected() ? 'object-card-selected' : 'object-card'"> -
    -
    = new EventEmitter
    (); - public columnDefinitions: Column[]; public config: CardConfig; + public columnDefinitions: any[]; + public columns: Column[]; public showColumns = false; - - public readonly customClasses = { - sortAscending: "fa fa-sort-asc", - sortDescending: "fa fa-sort-desc", - pagerLeftArrow: "fa fa-chevron-left", - pagerRightArrow: "fa fa-chevron-right", - pagerPrevious: "fa fa-step-backward", - pagerNext: "fa fa-step-forward" - }; + public tableConfig: TableConfig; constructor() { // nothing to do @@ -50,16 +43,40 @@ export class SelectedTableComponent implements OnInit { public ngOnInit(): void { this.columnDefinitions = [ - { name: "name", selected: true, type: "string", size: 25 }, - { name: "age", selected: true, type: "integer", size: 3 }, - { name: "street", selected: true, type: "string", size: 50 }, - { name: "state", selected: true, type: "string", size: 2 }, - { name: "zipcode", selected: true, type: "string", size: 9 }, - { name: "company", selected: true, type: "string", size: 50 }, - { name: "married", selected: true, type: "boolean", size: 1 }, - { name: "gender", selected: true, type: "string", size: 1 } + { + draggable: false, + prop: "name", + name: "Name", + resizeable: false + }, { + draggable: false, + prop: "type", + name: "Type", + resizeable: false + }, { + draggable: false, + prop: "size", + name: "Size", + resizeable: false + } + ]; + + // TODO: replace with call to get the column metadata + this.columns = [ + new Column( "name", true, "string", 25 ), + new Column( "age", true, "integer", 3 ), + new Column( "street", true, "string", 30 ), + new Column( "state", true, "string", 2 ), + new Column( "zipcode", true, "string", 9 ), + new Column( "company", true, "string", 50 ), + new Column( "married", true, "boolean", 1 ), + new Column( "gender", true, "string", 1 ), ]; + this.tableConfig = { + showCheckbox: true + } as TableConfig; + this.config = { action: { id: "showColumns", @@ -72,8 +89,8 @@ export class SelectedTableComponent implements OnInit { } as CardConfig; } - public get columnCount(): number { - return this.columnDefinitions.length; + private get columnCount(): number { + return this.columns.length; } public handleActionSelect( $event: CardAction ): void { @@ -81,17 +98,18 @@ export class SelectedTableComponent implements OnInit { $event.hypertext = this.showColumnsActionTitle; } - public selectedColumnChanged( column: Column ): void { - column.selected = !column.selected; + public handleSelectionChange( $event: TableEvent ): void { + // need to update footer action link label + this.config.action.hypertext = this.showColumnsActionTitle; } public get selectedColumnCount(): number { - return this.columnDefinitions.filter( ( column ) => column.selected ).length; + return this.columns.filter( ( column ) => column.selected ).length; } public get showColumnsActionTitle(): string { - return this.showColumns ? "Hide Columns" - : "Show Columns (" + this.selectedColumnCount + " of " + this.columnCount + " selected)"; + return this.showColumns ? "Hide Columns (" + this.selectedColumnCount + " of " + this.columnCount + " selected)" + : "Show Columns"; } public onRemove(): void { diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index 428cd4a1..ff82f1a1 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -7,6 +7,7 @@ :root { --alert-color: darkred; + --hover-color: #ddeaff; --disabled-color: lightgrey; --card-action-icon-color: var(--card-border-color); --card-action-icon-cursor: pointer; @@ -30,7 +31,7 @@ --card-description-margin-bottom: 10px; --card-description-padding: 0 5px 5px 5px; --card-footer-background-color: #ececec; - --card-hover-color: #ddeaff; + --card-hover-color: var(--hover-color); --card-title-font-size: 16px; --card-title-font-weight: bold; --card-title-margin: 10px 0 !important; @@ -53,9 +54,9 @@ --page-background-color: #fafafa; } -/*********************************************************************************/ -/* Beetle Studio global types below here */ -/*********************************************************************************/ +/**********************************************************************/ +/* Beetle Studio Global Types */ +/**********************************************************************/ .blank-slate-pf { background-color: white; @@ -82,6 +83,10 @@ color: var(--card-action-icon-disabled-color); } +.card-footer-action-icon { + margin-left: 10px; +} + .card-toolbar { border-bottom: var(--card-toolbar-border-bottom); border-top: var(--card-toolbar-border-top); @@ -99,6 +104,11 @@ margin-left: var(--card-toolbar-kebab-margin-left); margin-right: var(--card-toolbar-kebab-margin-right); } + +.clickable-icon { + cursor: pointer; +} + .object-card, .object-card-selected { -webkit-transition: background-color 300ms; @@ -133,6 +143,7 @@ .object-card .card-pf .card-pf-footer { background-color: var(--card-footer-background-color); min-height: 20px; + padding: 4px 0px 4px 0px; } .object-card-selected .card-pf .card-pf-heading, @@ -242,14 +253,18 @@ text-align: left; } -/*********************************************************************************/ -/* 3rd Party library types below here */ -/*********************************************************************************/ +/***************************************************************/ +/* CodeMirror Types */ +/***************************************************************/ .CodeMirror { height: 200px; } +/******************************************************************/ +/* ngx-datatable Types */ +/******************************************************************/ + .ngx-datatable { position: absolute; top:0;left:0;right:0;bottom:0; } @@ -302,6 +317,22 @@ color: white; } +/**************************************************************/ +/* PatternFly Types */ +/**************************************************************/ + +.card-pf-footer-text { + margin-left: 20px; +} + +.pfng-list-expansion .list-pf-content { + width: 100%; +} + +.pfng-list-expansion .pfng-list-content { + width: 100%; +} + /* Patternfly-NG kebab dropdown actions. */ .secondary-action:before { color: var(--card-toolbar-dropdown-action-icon-color); @@ -317,3 +348,7 @@ content: "\f014"; font-family: "FontAwesome"; } + +.toolbar-pf-actions { + margin-bottom: 0; +} From c50afcce15c4de3550de06c753873f6d63d5bb5c Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 23 Feb 2018 11:59:07 -0600 Subject: [PATCH 095/205] Changed behaviour of summary cards as the window is resized - cards now say a constant size - cards wrap as necessary --- .../connections-cards.component.html | 4 ++-- .../dataservices-cards.component.css | 8 -------- .../dataservices-cards.component.html | 4 ++-- ngapp/src/styles.css | 11 ++++++++++- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.html b/ngapp/src/app/connections/connections-cards/connections-cards.component.html index 04f69eb6..a0b3bc19 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.html +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.html @@ -1,5 +1,5 @@ -
    -
    +
    +
    -
    +
    +
    * { + flex: 1 1 80px; + margin: 5px; +} + .object-card-selected .card-pf { border: var(--card-border-width) var(--card-border-style) var(--card-border-color); } From 27334d2c3309bd9891a82ccc50b5e13df34c31e8 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 5 Mar 2018 14:22:53 -0600 Subject: [PATCH 096/205] TEIIDTOOLS-350 Replace ngx-datatable with pfng-table - all instances of ngx-datatable have been replaced - removed ngx-datatable as a dependency in package.json - upgraded pfng to 3.1.2 - minor style changes - fixed some lint warnings --- ngapp/package-lock.json | 201 ++++++++----- ngapp/package.json | 15 +- .../connections-cards.component.html | 1 + .../shared/mock-connection.service.ts | 1 - .../add-dataservice-wizard.component.spec.ts | 3 +- .../add-dataservice.component.spec.ts | 3 +- .../connection-table-selector.component.css | 8 + .../connection-table-selector.component.html | 49 ++-- ...onnection-table-selector.component.spec.ts | 3 +- .../connection-table-selector.component.ts | 151 ++++++++-- .../dataservices.component.spec.ts | 3 +- .../app/dataservices/dataservices.module.ts | 2 - .../jdbc-table-selector.component.css | 64 +---- .../jdbc-table-selector.component.html | 87 ++---- .../jdbc-table-selector.component.spec.ts | 3 +- .../jdbc-table-selector.component.ts | 272 +++++++++++++----- .../selected-table.component.spec.ts | 8 +- .../selected-table.component.ts | 19 +- .../sql-control/sql-control.component.css | 4 +- .../sql-control/sql-control.component.html | 41 +-- .../sql-control/sql-control.component.spec.ts | 4 +- .../sql-control/sql-control.component.ts | 89 +++--- .../test-dataservice.component.spec.ts | 4 +- ngapp/src/styles.css | 62 +--- 24 files changed, 607 insertions(+), 490 deletions(-) diff --git a/ngapp/package-lock.json b/ngapp/package-lock.json index b771a77e..f94e2ca9 100644 --- a/ngapp/package-lock.json +++ b/ngapp/package-lock.json @@ -73,7 +73,7 @@ "raw-loader": "0.5.1", "resolve": "1.4.0", "rsvp": "3.6.2", - "rxjs": "5.5.5", + "rxjs": "5.5.6", "sass-loader": "6.0.6", "script-loader": "0.7.1", "semver": "5.4.1", @@ -218,9 +218,10 @@ } }, "@swimlane/ngx-datatable": { - "version": "11.1.7", - "resolved": "https://registry.npmjs.org/@swimlane/ngx-datatable/-/ngx-datatable-11.1.7.tgz", - "integrity": "sha512-TMDN26Q4J+Sh+OPqAx8BK5Q/3hAAmcTAUQ9wvC9nboSOAmYUaHGz8t21yGdeUtRtunIfMpjTnwLa+X2Pfoq42w==" + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-datatable/-/ngx-datatable-11.2.0.tgz", + "integrity": "sha512-QlD45YEUwOz6fu7neTtIGBAoV0owY0J9Jkpc2xViXHThWJeW7+mRhg4XRyKm8nvVDuUJZH+7huzAW1lQKN+iYg==", + "optional": true }, "@types/jasmine": { "version": "2.5.54", @@ -238,9 +239,9 @@ } }, "@types/node": { - "version": "6.0.92", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.92.tgz", - "integrity": "sha512-awEYSSTn7dauwVCYSx2CJaPTu0Z1Ht2oR1b2AD3CYao6ZRb+opb6EL43fzmD7eMFgMHzTBWSUzlWSD+S8xN0Nw==", + "version": "6.0.101", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.101.tgz", + "integrity": "sha512-IQ7V3D6+kK1DArTqTBrnl3M+YgJZLw8ta8w3Q9xjR79HaJzMAoTbZ8TNzUTztrkCKPTqIstE2exdbs1FzsYLUw==", "dev": true }, "@types/q": { @@ -365,14 +366,14 @@ "dev": true }, "angular-tree-component": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/angular-tree-component/-/angular-tree-component-6.1.0.tgz", - "integrity": "sha1-nZprKKaIHCByzWMGtVIpV56JQHE=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/angular-tree-component/-/angular-tree-component-7.0.1.tgz", + "integrity": "sha1-/I0OctjDS4cTGjuivTKtIJRWiaw=", "optional": true, "requires": { "lodash": "4.17.4", - "mobx": "3.4.1", - "mobx-angular": "2.0.1" + "mobx": "3.6.1", + "mobx-angular": "2.1.1" } }, "ansi-escapes": { @@ -717,7 +718,7 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.1", + "core-js": "2.5.3", "regenerator-runtime": "0.11.0" } }, @@ -1091,9 +1092,9 @@ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "c3": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.18.tgz", - "integrity": "sha512-37TiFeCrbe69gg7SxFpTBOLDwulnk+opKp1AFDi43mONtErpRoUIZfGSimGiSYQmNu6Zh9W2yNOx0066UikqSg==", + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/c3/-/c3-0.4.21.tgz", + "integrity": "sha512-UZt0RWxVDJJrAGBojz2OJ9v88uDIP+WMVrydXCSvYM+bX2CyL+tTEA7gD5htzZeVMLcBYc7DZpDnskdH2fEOdw==", "optional": true, "requires": { "d3": "3.5.17" @@ -1657,9 +1658,9 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "core-js": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", - "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=" + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" }, "core-object": { "version": "3.1.5", @@ -4975,22 +4976,45 @@ "dev": true }, "istanbul-api": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.1.14.tgz", - "integrity": "sha1-JbxXAffGgMD//5E95G42GaOm5oA=", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.2.2.tgz", + "integrity": "sha512-kH5YRdqdbs5hiH4/Rr1Q0cSAGgjh3jTtg8vu9NLebBAoK3adVO4jk81J+TYOkTr2+Q4NLeb1ACvmEt65iG/Vbw==", "dev": true, "requires": { "async": "2.5.0", "fileset": "2.0.3", - "istanbul-lib-coverage": "1.1.1", - "istanbul-lib-hook": "1.0.7", - "istanbul-lib-instrument": "1.8.0", - "istanbul-lib-report": "1.1.1", - "istanbul-lib-source-maps": "1.2.1", - "istanbul-reports": "1.1.2", + "istanbul-lib-coverage": "1.1.2", + "istanbul-lib-hook": "1.1.0", + "istanbul-lib-instrument": "1.9.2", + "istanbul-lib-report": "1.1.3", + "istanbul-lib-source-maps": "1.2.3", + "istanbul-reports": "1.1.4", "js-yaml": "3.7.0", "mkdirp": "0.5.1", "once": "1.4.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.2.tgz", + "integrity": "sha512-tZYA0v5A7qBSsOzcebJJ/z3lk3oSzH62puG78DbBA1+zupipX2CakDyiPV3pOb8He+jBwVimuwB0dTnh38hX0w==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.2.tgz", + "integrity": "sha512-nz8t4HQ2206a/3AXi+NHFWEa844DMpPsgbcUteJbt1j8LX1xg56H9rOMnhvcvVvPbW60qAIyrSk44H8ZDqaSSA==", + "dev": true, + "requires": { + "babel-generator": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.1.2", + "semver": "5.4.1" + } + } } }, "istanbul-instrumenter-loader": { @@ -5026,9 +5050,9 @@ "dev": true }, "istanbul-lib-hook": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz", - "integrity": "sha512-3U2HB9y1ZV9UmFlE12Fx+nPtFqIymzrqCksrXujm3NVbAZIJg/RfYgO1XiIa0mbmxTjWpVEVlkIZJ25xVIAfkQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz", + "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", "dev": true, "requires": { "append-transform": "0.4.0" @@ -5050,37 +5074,62 @@ } }, "istanbul-lib-report": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", - "integrity": "sha512-tvF+YmCmH4thnez6JFX06ujIA19WPa9YUiwjc1uALF2cv5dmE3It8b5I8Ob7FHJ70H9Y5yF+TDkVa/mcADuw1Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.3.tgz", + "integrity": "sha512-D4jVbMDtT2dPmloPJS/rmeP626N5Pr3Rp+SovrPn1+zPChGHcggd/0sL29jnbm4oK9W0wHjCRsdch9oLd7cm6g==", "dev": true, "requires": { - "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-coverage": "1.1.2", "mkdirp": "0.5.1", "path-parse": "1.0.5", "supports-color": "3.2.3" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.2.tgz", + "integrity": "sha512-tZYA0v5A7qBSsOzcebJJ/z3lk3oSzH62puG78DbBA1+zupipX2CakDyiPV3pOb8He+jBwVimuwB0dTnh38hX0w==", + "dev": true + } } }, "istanbul-lib-source-maps": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz", - "integrity": "sha512-mukVvSXCn9JQvdJl8wP/iPhqig0MRtuWuD4ZNKo6vB2Ik//AmhAKe3QnPN02dmkRe3lTudFk3rzoHhwU4hb94w==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz", + "integrity": "sha512-fDa0hwU/5sDXwAklXgAoCJCOsFsBplVQ6WBldz5UwaqOzmDhUK4nfuR7/G//G2lERlblUNJB8P6e8cXq3a7MlA==", "dev": true, "requires": { - "debug": "2.6.9", - "istanbul-lib-coverage": "1.1.1", + "debug": "3.1.0", + "istanbul-lib-coverage": "1.1.2", "mkdirp": "0.5.1", "rimraf": "2.6.2", "source-map": "0.5.7" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "istanbul-lib-coverage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.2.tgz", + "integrity": "sha512-tZYA0v5A7qBSsOzcebJJ/z3lk3oSzH62puG78DbBA1+zupipX2CakDyiPV3pOb8He+jBwVimuwB0dTnh38hX0w==", + "dev": true + } } }, "istanbul-reports": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.2.tgz", - "integrity": "sha1-D7Lj9qqZIr085F0F2KtNXo4HvU8=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.4.tgz", + "integrity": "sha512-DfSTVOTkuO+kRmbO8Gk650Wqm1WRGr6lrdi2EwDK1vxpS71vdlLd613EpzOKdIFioB5f/scJTjeWBnvd1FWejg==", "dev": true, "requires": { - "handlebars": "4.0.10" + "handlebars": "4.0.11" }, "dependencies": { "async": { @@ -5118,9 +5167,9 @@ } }, "handlebars": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", - "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { "async": "1.5.2", @@ -5349,7 +5398,7 @@ "colors": "1.1.2", "combine-lists": "1.0.1", "connect": "3.6.5", - "core-js": "2.5.1", + "core-js": "2.5.3", "di": "0.0.1", "dom-serialize": "2.2.1", "expand-braces": "0.1.2", @@ -5419,12 +5468,12 @@ } }, "karma-coverage-istanbul-reporter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.3.0.tgz", - "integrity": "sha1-0ULNnFVzHJ42Pvc3To7xoxvr+ts=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.1.tgz", + "integrity": "sha512-5og0toMjgLvsL9+TzGH4Rk1D0nr7pMIRJBg29xP4mHMKy/1KUJ12UzoqI6mBNCRFa4nDvZS2MRrN7p+RkZNWxQ==", "dev": true, "requires": { - "istanbul-api": "1.1.14", + "istanbul-api": "1.2.2", "minimatch": "3.0.4" } }, @@ -5985,15 +6034,15 @@ } }, "mobx": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-3.4.1.tgz", - "integrity": "sha1-N6vl7ogtQBgo2fJsbBovR2FLu+8=", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-3.6.1.tgz", + "integrity": "sha1-rmOo8A4UhadA0Pka4val9o4wO+o=", "optional": true }, "mobx-angular": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mobx-angular/-/mobx-angular-2.0.1.tgz", - "integrity": "sha1-JjjQkWGAgGk7vtAsXfjNcUtSwWc=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mobx-angular/-/mobx-angular-2.1.1.tgz", + "integrity": "sha1-1eNlOayyABht1aEXCAa0d2uai4g=", "optional": true }, "ms": { @@ -6062,9 +6111,9 @@ } }, "ngx-bootstrap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-2.0.1.tgz", - "integrity": "sha512-/JWVePdSQFspxkWincmAwZAQxuZfOqp+Gr9RimVhBDwQDuXATsTxqQ6OPmkxWg1MvtLPIymPDaG1H6CcqvUadg==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-2.0.2.tgz", + "integrity": "sha512-4ZTltcStUED2JzI9Hd1+FDaMQmukzbeBSS02hdTvuUJ+9hNtGLMSPGdPNRIniIyItzv3v3emJrAAtKkvOMxyCA==" }, "no-case": { "version": "2.3.2", @@ -6669,9 +6718,9 @@ } }, "patternfly": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.37.1.tgz", - "integrity": "sha1-uYivPWcyyz0O26P347Eb8QFY7Uo=", + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/patternfly/-/patternfly-3.41.0.tgz", + "integrity": "sha1-zJajW5b1BGcZRrxWXVi/Olre8Cs=", "requires": { "bootstrap": "3.3.7", "bootstrap-datepicker": "1.7.1", @@ -6892,17 +6941,17 @@ } }, "patternfly-ng": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-3.1.1.tgz", - "integrity": "sha1-ZC/sm0dkiTKJJqoEFIAVpg6rWes=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/patternfly-ng/-/patternfly-ng-3.1.2.tgz", + "integrity": "sha1-2iI3v18iZ0Il96lSQf3FlTz41lY=", "requires": { - "@swimlane/ngx-datatable": "11.1.7", - "angular-tree-component": "6.1.0", - "c3": "0.4.18", + "@swimlane/ngx-datatable": "11.2.0", + "angular-tree-component": "7.0.1", + "c3": "0.4.21", "lodash": "4.17.4", "ng2-dragula": "1.5.0", - "ngx-bootstrap": "2.0.1", - "patternfly": "3.37.1" + "ngx-bootstrap": "2.0.2", + "patternfly": "3.41.0" } }, "pbkdf2": { @@ -7750,7 +7799,7 @@ "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", "dev": true, "requires": { - "@types/node": "6.0.92", + "@types/node": "6.0.101", "@types/q": "0.0.32", "@types/selenium-webdriver": "2.53.42", "blocking-proxy": "0.0.5", @@ -8372,9 +8421,9 @@ } }, "rxjs": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.5.tgz", - "integrity": "sha512-D/MfQnPMBk8P8gfwGxvCkuaWBcG58W7dUMT//URPoYzIbDEKT0GezdirkK5whMgKFBATfCoTpxO8bJQGJ04W5A==", + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.6.tgz", + "integrity": "sha512-v4Q5HDC0FHAQ7zcBX7T2IL6O5ltl1a2GX4ENjPXg6SjDY69Cmx9v4113C99a4wGF16ClPv5Z8mghuYorVkg/kg==", "requires": { "symbol-observable": "1.0.1" } diff --git a/ngapp/package.json b/ngapp/package.json index d996cf16..69059db3 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -21,14 +21,13 @@ "@angular/platform-browser": "^4.4.6", "@angular/platform-browser-dynamic": "^4.4.6", "@angular/router": "^4.4.6", - "@swimlane/ngx-datatable": "^11.1.5", - "core-js": "^2.4.1", + "core-js": "^2.5.3", "express": "^4.16.2", "ng2-codemirror": "^1.1.3", - "ngx-bootstrap": "^2.0.1", - "patternfly": "^3.28.0", - "patternfly-ng": "^3.1.1", - "rxjs": "^5.5.5", + "ngx-bootstrap": "^2.0.2", + "patternfly": "^3.41.0", + "patternfly-ng": "^3.1.2", + "rxjs": "^5.5.6", "zone.js": "^0.8.20" }, "devDependencies": { @@ -37,14 +36,14 @@ "@angular/language-service": "^4.4.6", "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", - "@types/node": "^6.0.92", + "@types/node": "^6.0.101", "codelyzer": "~4.0.0", "jasmine-core": "~2.8.0", "jasmine-spec-reporter": "~4.1.0", "karma": "~1.7.0", "karma-chrome-launcher": "~2.2.0", "karma-cli": "~1.0.1", - "karma-coverage-istanbul-reporter": "^1.2.1", + "karma-coverage-istanbul-reporter": "^1.4.1", "karma-jasmine": "^1.1.1", "karma-jasmine-html-reporter": "^0.2.2", "karma-junit-reporter": "^1.2.0", diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.html b/ngapp/src/app/connections/connections-cards/connections-cards.component.html index a0b3bc19..e7bcacb1 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.html +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.html @@ -6,3 +6,4 @@ (selectEvent)="onSelectEvent($event)">
    + diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 571d26db..f494e0e1 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -20,7 +20,6 @@ import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; -import { NewConnection } from "@connections/shared/new-connection.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; import { TemplateDefinition } from "@connections/shared/template-definition.model"; import { AppSettingsService } from "@core/app-settings.service"; diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index c1ae969c..e1efad39 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -18,7 +18,6 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard.component"; @@ -28,7 +27,7 @@ describe("AddDataserviceWizardComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, NgxDatatableModule ], + imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], declarations: [ AddDataserviceWizardComponent, ConnectionTableSelectorComponent, JdbcTableSelectorComponent, PropertyFormComponent, PropertyFormPropertyComponent, SelectedTableComponent ], providers: [ diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index 89934816..0ac87ad9 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -18,7 +18,6 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SharedModule } from "@shared/shared.module"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceComponent } from "./add-dataservice.component"; @@ -28,7 +27,7 @@ describe("AddDataserviceComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule, NgxDatatableModule ], + imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent, ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css index 8fffc9d0..5528a973 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css @@ -3,6 +3,14 @@ padding-right: 0; } +.connection-selector-container .filter-pf .form-group { + width: auto !important; +} + +.connection-selector-container .toolbar-pf .form-group { + border-right: none; +} + .jdbc-selector-container { padding-left: 0; padding-right: 0; diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html index e466df0b..e520074d 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html @@ -9,37 +9,20 @@
    - - - Connections - - - - - {{ row.keng__id }} - - - +
    +
    +
    + + +
    +
    +
    @@ -87,3 +70,7 @@
    + + + {{ row.name }} + diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts index fee59727..f71d8d17 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts @@ -13,7 +13,6 @@ import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { PatternFlyNgModule } from "patternfly-ng"; import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; @@ -23,7 +22,7 @@ describe("ConnectionTableSelectorComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule, NgxDatatableModule, PatternFlyNgModule ], + imports: [ FormsModule, HttpModule, PatternFlyNgModule ], declarations: [ ConnectionTableSelectorComponent, JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ { provide: AppSettingsService, useClass: MockAppSettingsService }, diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index 63a9ea23..8f577cca 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Component, EventEmitter, OnInit, Output, ViewChild, ViewEncapsulation } from "@angular/core"; +import { Component, EventEmitter, OnInit, Output, TemplateRef, ViewChild, ViewEncapsulation } from "@angular/core"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { LoggerService } from "@core/logger.service"; @@ -24,6 +24,16 @@ import { Table } from "@dataservices/shared/table.model"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { WizardService } from "@dataservices/shared/wizard.service"; import { LoadingState } from "@shared/loading-state.enum"; +import { + Filter, + FilterConfig, + FilterEvent, + FilterField, + FilterType, + NgxDataTableConfig, + TableConfig, + ToolbarConfig +} from "patternfly-ng"; @Component({ encapsulation: ViewEncapsulation.None, @@ -33,19 +43,24 @@ import { LoadingState } from "@shared/loading-state.enum"; }) export class ConnectionTableSelectorComponent implements OnInit { + private static readonly nameFilterId = "nameFilter"; + + @ViewChild("cellTemplate") public cellTemplate: TemplateRef< any >; @ViewChild(JdbcTableSelectorComponent) public jdbcTableSelector: JdbcTableSelectorComponent; @Output() public selectedTableListUpdated: EventEmitter = new EventEmitter(); - public readonly customClasses = { - sortAscending: "fa fa-sort-asc", - sortDescending: "fa fa-sort-desc" - }; + public columnDefinitions: any[]; + public filtersText = ""; + public filterConfig: FilterConfig; + public ngxConfig: NgxDataTableConfig; + public tableConfig: TableConfig; + public toolbarConfig: ToolbarConfig; - private connectionService: ConnectionService; - private wizardService: WizardService; private allConnections: Connection[] = []; private filteredConnections: Connection[] = []; - private connectionFilter = ""; + + private connectionService: ConnectionService; + private wizardService: WizardService; private selectedConn: Connection; private connectionLoadingState: LoadingState = LoadingState.LOADING; private logger: LoggerService; @@ -61,6 +76,47 @@ export class ConnectionTableSelectorComponent implements OnInit { * Component initialization */ public ngOnInit(): void { + this.columnDefinitions = [ + { + cellTemplate: this.cellTemplate, + comparator: this.connectionComparator, + draggable: false, + name: "Connections", + prop: "name", + resizeable: false, + sortable: true, + width: "300" + } + ]; + + this.ngxConfig = { + footerHeight: 24, + messages: this.connectionsTableMessages, + selectionType: "single", + } as NgxDataTableConfig; + + this.filterConfig = { + fields: [ + { + id: ConnectionTableSelectorComponent.nameFilterId, + title: "Name", + placeholder: "Filter by name...", + type: FilterType.TEXT + } + ] as FilterField[], + appliedFilters: [], + resultsCount: this.filteredConnections.length, + totalCount: this.allConnections.length + } as FilterConfig; + + this.toolbarConfig = { + filterConfig: this.filterConfig + } as ToolbarConfig; + + this.tableConfig = { + toolbarConfig: this.toolbarConfig + } as TableConfig; + // Load the connections this.connectionLoadingState = LoadingState.LOADING; const self = this; @@ -82,18 +138,26 @@ export class ConnectionTableSelectorComponent implements OnInit { ); } + public filterChanged( $event: FilterEvent ): void { + this.filtersText = ""; + + $event.appliedFilters.forEach( ( filter ) => { + this.filtersText += filter.field.title + " : " + filter.value + "\n"; + } ); + + this.applyFilters( $event.appliedFilters ); + } + // callback from connection table selection - public onSelect( { selected } ): void { + public selectionChange( $event ): void { + const selected: Connection[] = $event.selected; + // connection table is single select so use first element const conn: Connection = selected[ 0 ]; // only set if schema selection has changed (see setter) - if ( this.hasSelectedConnection() ) { - if ( this.selectedConn.getId() !== conn.getId() ) { - this.selectedConnection = conn; - } - } else { - this.selectedConnection = conn; + if ( this.selectedConn == null || this.selectedConn.name !== conn.name ) { + this.selectedConn = conn; } } @@ -237,7 +301,7 @@ export class ConnectionTableSelectorComponent implements OnInit { let msg: string; if ( numAll === numFiltered ) { - if ( this.connectionFilter.length === 0 ) { + if ( this.filtersText.length === 0 ) { msg = numAll === 1 ? "connection" : "connections"; } else { msg = numAll === 1 ? "matched connection" : "matched connections"; @@ -255,19 +319,6 @@ export class ConnectionTableSelectorComponent implements OnInit { }; } - /** - * Callback when key is pressed in column filter. - */ - public connectionFilterChanged( event: any ): void { - this.connectionFilter = event.target.value; - - if ( this.connectionFilter.length !== 0 ) { - this.connectionFilter = "^" + this.connectionFilter.replace( "*", ".*" ); - } - - this.filteredConnections = this.allConnections.filter( ( connection ) => connection.getId().match( this.connectionFilter ) != null ); - } - /** * Called when the table is sorted. * @param {string} thisName the connection name being sorted @@ -279,6 +330,48 @@ export class ConnectionTableSelectorComponent implements OnInit { return thisName.localeCompare( thatName ); } + private applyFilters( filters: Filter[] ): void { + this.filteredConnections = []; + + if ( filters && filters.length > 0 ) { + this.allConnections.forEach( ( item ) => { + if ( this.matchesFilters( item, filters ) ) { + this.filteredConnections.push( item ); + } + } ); + } else { + this.filteredConnections = this.allConnections; + } + + this.toolbarConfig.filterConfig.resultsCount = this.filteredConnections.length; + } + + private matchesFilter( item: any, + filter: Filter ): boolean { + let matches = true; + + if ( filter.field.id === ConnectionTableSelectorComponent.nameFilterId ) { + const pattern = "^" + filter.value.replace( "*", ".*" ); + matches = item.name.match( pattern ) !== null; + } + + return matches; + } + + private matchesFilters( item: any, + filters: Filter[] ): boolean { + let matches = true; + + filters.forEach( ( filter ) => { + if ( !this.matchesFilter( item, filter ) ) { + matches = false; + return matches; + } + }); + + return matches; + } + /** * Initialization for edit mode */ diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index f654548d..c8739c0f 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -20,7 +20,6 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; import { SharedModule } from "@shared/shared.module"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { CodemirrorModule } from "ng2-codemirror"; import { ModalModule } from "ngx-bootstrap"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -32,7 +31,7 @@ describe("DataservicesComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), PatternFlyNgModule, - RouterTestingModule, SharedModule, CodemirrorModule, NgxDatatableModule ], + RouterTestingModule, SharedModule, CodemirrorModule ], declarations: [ BasicContentComponent, DataservicesComponent, DataservicesListComponent, diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 20895bbb..975f3430 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -32,7 +32,6 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SharedModule } from "@shared/shared.module"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { CodemirrorModule } from "ng2-codemirror"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard/add-dataservice-wizard.component"; @@ -51,7 +50,6 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co CoreModule, SharedModule, FormsModule, - NgxDatatableModule, ReactiveFormsModule, RouterModule, PatternFlyNgModule, diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css index 38f859a1..8e4b5b0f 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css @@ -1,44 +1,18 @@ -.list-div { - position: relative; - height: 100%; - max-height: 300px; - overflow-y: auto; -} - -.jdbc-table-header { - margin-left: 5px; -} - -.jdbc-table-cell { - margin-left: 5px; -} - -.jdbc-list .list-view-pf-main-info { - padding-top: 0.5em; - padding-bottom: 0.5em; -} - -.jdbc-list .list-view-pf-checkbox { - padding-top: 0; - padding-bottom: 0; - margin-top: 0; - margin-right: 5px; - margin-bottom: 0; +.alert-padding { + padding-top: 10px; } -.jdbc-list .list-group-item-heading { - font-size: 12px; - margin-right: 5px; +.jdbc-column-results { + padding-left: 0; + padding-right: 0; } -.jdbc-list .list-view-pf-description { - width: 95%; +.jdbc-column-results .filter-pf .form-group { + width: auto !important; } -.jdbc-list .list-group-item.active { - background-color: #0088ce; - color: white; - border-color: transparent; +.jdbc-column-results .toolbar-pf .form-group { + border-right: none; } .jdbc-column-title { @@ -50,19 +24,9 @@ padding-right: 0; } -.jdbc-column-results { - padding-left: 0; - padding-right: 0; -} - -.evenRow { - background-color: #f2f2f2; -} -.oddRow { - background-color: white; -} - -.alert-padding { - padding-top: 10px; +.list-div { + position: relative; + height: 100%; + max-height: 300px; + overflow-y: auto; } - diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html index 54e8c6e7..b1d0bcbd 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.html @@ -17,38 +17,16 @@
    - - - Schemas - - - - {{ row.getDisplayName() }} - - - +
    + + +
    @@ -69,36 +47,15 @@
    - - - - Tables - - - - {{ row.name }} - - - -
    + + + + + {{ row.getDisplayName() }} + diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index 193dc09b..5e61522e 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -13,7 +13,6 @@ import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { PatternFlyNgModule } from "patternfly-ng"; describe("JdbcTableSelectorComponent", () => { @@ -22,7 +21,7 @@ describe("JdbcTableSelectorComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule, NgxDatatableModule, PatternFlyNgModule ], + imports: [ FormsModule, HttpModule, PatternFlyNgModule ], declarations: [ JdbcTableSelectorComponent, SelectedTableComponent ], providers: [ AppSettingsService, LoggerService, NotifierService, WizardService, diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index 01ec4fe8..97ea9186 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -15,10 +15,10 @@ * limitations under the License. */ -import { Component, OnInit } from "@angular/core"; -import { EventEmitter } from "@angular/core"; +import { Component, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from "@angular/core"; import { Output } from "@angular/core"; import { Input } from "@angular/core"; +import { EventEmitter } from "@angular/core"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; @@ -29,8 +29,14 @@ import { TableSelector } from "@dataservices/shared/table-selector"; import { Table } from "@dataservices/shared/table.model"; import { WizardService } from "@dataservices/shared/wizard.service"; import { LoadingState } from "@shared/loading-state.enum"; +import { + Filter, + FilterConfig, FilterEvent, FilterField, FilterType, NgxDataTableConfig, TableConfig, TableEvent, + ToolbarConfig +} from "patternfly-ng"; @Component({ + encapsulation: ViewEncapsulation.None, selector: "app-jdbc-table-selector", templateUrl: "./jdbc-table-selector.component.html", styleUrls: ["./jdbc-table-selector.component.css"] @@ -38,16 +44,29 @@ import { LoadingState } from "@shared/loading-state.enum"; export class JdbcTableSelectorComponent implements OnInit, TableSelector { + private static readonly schemaFilterId = "schemeFilter"; + private static readonly tableFilterId = "tableFilter"; + + @ViewChild("schemaCellTemplate") public schemaCellTemplate: TemplateRef< any >; @Input() public connection: Connection; @Output() public tableSelectionAdded: EventEmitter
    = new EventEmitter
    (); @Output() public tableSelectionRemoved: EventEmitter
    = new EventEmitter
    (); - public selectedAllRows = false; + public schemaColumns: any[]; + public schemaFiltersText = ""; + public schemaFilterConfig: FilterConfig; + public ngxSchemaConfig: NgxDataTableConfig; + public schemaTableConfig: TableConfig; + public schemaToolbarConfig: ToolbarConfig; - public readonly customClasses = { - sortAscending: "fa fa-sort-asc", - sortDescending: "fa fa-sort-desc" - }; + public tableColumns: any[]; + public tableFiltersText = ""; + public tableFilterConfig: FilterConfig; + public ngxTableConfig: NgxDataTableConfig; + public tableTableConfig: TableConfig; + public tableToolbarConfig: ToolbarConfig; + + public selectedAllRows = false; private connectionService: ConnectionService; private wizardService: WizardService; @@ -69,6 +88,88 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } public ngOnInit(): void { + this.schemaColumns = [ + { + cellTemplate: this.schemaCellTemplate, + comparator: "nameComparator", + draggable: false, + name: "Schemas", + prop: "name", + resizeable: false, + sortable: true, + width: "300" + } + ]; + + this.ngxSchemaConfig = { + footerHeight: 24, + messages: this.schemaTableMessages, + selectionType: "single", + } as NgxDataTableConfig; + + this.schemaFilterConfig = { + fields: [ + { + id: JdbcTableSelectorComponent.schemaFilterId, + title: "Name", + placeholder: "Filter by name...", + type: FilterType.TEXT + } + ] as FilterField[], + appliedFilters: [], + resultsCount: this.filteredSchemas.length, + totalCount: this.schemas.length + } as FilterConfig; + + this.schemaToolbarConfig = { + filterConfig: this.schemaFilterConfig + } as ToolbarConfig; + + this.schemaTableConfig = { + toolbarConfig: this.schemaToolbarConfig + } as TableConfig; + + this.tableColumns = [ + { + comparator: "nameComparator", + draggable: false, + name: "Tables", + prop: "name", + resizeable: false, + sortable: true, + width: "300" + } + ]; + + this.ngxTableConfig = { + footerHeight: 24, + messages: this.tableTableMessages, + selectionType: "checkbox", + } as NgxDataTableConfig; + + this.tableFilterConfig = { + fields: [ + { + id: JdbcTableSelectorComponent.tableFilterId, + title: "Name", + placeholder: "Filter by name...", + type: FilterType.TEXT + } + ] as FilterField[], + appliedFilters: [], + resultsCount: this.filteredTables.length, + totalCount: this.tables.length + } as FilterConfig; + + this.tableToolbarConfig = { + filterConfig: this.tableFilterConfig + } as ToolbarConfig; + + this.tableTableConfig = { + showCheckbox: true, + toolbarConfig: this.tableToolbarConfig + } as TableConfig; + // Load the schema info for a connection this.setConnection(this.connection); } @@ -114,8 +215,10 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { this.tableLoadingState = LoadingState.LOADING; } - // callback from schema selection in datatable - public onSchemaSelect( { selected }): void { + // callback from schema row selection in table + public schemaSelectionChange( $event ): void { + const selected: CatalogSchema[] = $event.selected; + // schema table is single select so use first element const schema: CatalogSchema = selected[ 0 ]; @@ -203,16 +306,16 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } /** - * Callback when key is pressed in schema column filter. + * Callback when schema filters are changed. */ - public schemaFilterChanged( event: any ): void { - this.schemaFilter = event.target.value; + public schemaFilterChanged( $event: FilterEvent ): void { + this.schemaFiltersText = ""; - if ( this.schemaFilter.length !== 0 ) { - this.schemaFilter = "^" + this.schemaFilter.replace( "*", ".*" ); - } + $event.appliedFilters.forEach( ( filter ) => { + this.schemaFiltersText += filter.field.title + " : " + filter.value + "\n"; + } ); - this.filteredSchemas = this.schemas.filter( ( schema ) => schema.getDisplayName().match( this.schemaFilter ) != null ); + this.applySchemaFilters( $event.appliedFilters ); } public get schemaTableMessages(): { emptyMessage: string; totalMessage: string | string } { @@ -313,28 +416,14 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { /** * Callback when key is pressed in table column filter. */ - public tableFilterChanged( event: any ): void { - this.tableFilter = event.target.value; - - if ( this.tableFilter.length !== 0 ) { - this.tableFilter = "^" + this.tableFilter.replace( "*", ".*" ); - } - - this.filteredTables = this.tables.filter( ( table ) => table.getName().match( this.tableFilter ) != null ); - - // need to set column header checkbox state - let enable = true; + public tableFilterChanged( $event ): void { + this.tableFiltersText = ""; - for ( const filteredTable of this.filteredTables ) { - if ( !filteredTable.selected ) { - enable = false; - break; - } - } + $event.appliedFilters.forEach( ( filter ) => { + this.tableFiltersText += filter.field.title + " : " + filter.value + "\n"; + } ); - if ( this.selectedAllRows !== enable ) { - this.selectedAllRows = enable; - } + this.applyTableFilters( $event.appliedFilters ); } /* @@ -367,46 +456,28 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { return this.tables.filter( ( table ) => table.selected ); } - public selectAllTables(): void { - this.selectedAllRows = !this.selectedAllRows; - const self = this; - - this.filteredTables.forEach( ( table ) => { - if ( table.selected !== self.selectedAllRows ) { - self.selectedTableChanged( table ); - } - } ); - } - /* * Handler for changes in table selection */ - public selectedTableChanged( table: Table ): void { - table.selected = !table.selected; - - if ( table.selected ) { - this.tableSelectionAdded.emit(table); + public selectedTableChanged( $event: TableEvent ): void { + console.error( $event ); + const table: Table = $event.row; - // check column header checkbox if all are selected - if ( !this.selectedAllRows ) { - let selectAll = true; - - for ( const tbl of this.filteredTables ) { - if ( !tbl.selected ) { - selectAll = false; - } - } - - if ( selectAll ) { - this.selectedAllRows = true; - } + if ( table ) { + if ( table.selected ) { + this.tableSelectionAdded.emit( table ); + } else { + this.tableSelectionRemoved.emit( table ); } } else { - this.tableSelectionRemoved.emit(table); - - // uncheck column header checkbox if needed - if ( this.selectedAllRows ) { - this.selectedAllRows = false; + if ( $event.selectedRows.length === 0 ) { + this.tables.forEach( ( tbl ) => { + this.tableSelectionRemoved.emit( tbl ); + } ); + } else { + this.tables.forEach( ( tbl ) => { + this.tableSelectionAdded.emit( tbl ); + } ); } } } @@ -444,6 +515,38 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { } } + private applySchemaFilters( filters: Filter[] ): void { + this.filteredSchemas = []; + + if ( filters && filters.length > 0 ) { + this.schemas.forEach( ( item ) => { + if ( this.matchesFilters( item, filters ) ) { + this.filteredSchemas.push( item ); + } + } ); + } else { + this.filteredSchemas = this.schemas; + } + + this.schemaToolbarConfig.filterConfig.resultsCount = this.filteredSchemas.length; + } + + private applyTableFilters( filters: Filter[] ): void { + this.filteredTables = []; + + if ( filters && filters.length > 0 ) { + this.tables.forEach( ( item ) => { + if ( this.matchesFilters( item, filters ) ) { + this.filteredTables.push( item ); + } + } ); + } else { + this.filteredTables = this.tables; + } + + this.tableToolbarConfig.filterConfig.resultsCount = this.filteredTables.length; + } + private isSelected( selectedTables: Table[], table: Table ): boolean { for ( const selected of selectedTables ) { @@ -527,6 +630,35 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { ); } + private matchesFilter( item: any, + filter: Filter ): boolean { + let matches = true; + + if ( filter.field.id === JdbcTableSelectorComponent.schemaFilterId ) { + const pattern = "^" + filter.value.replace( "*", ".*" ); + matches = item.getDisplayName().match( pattern ) !== null; + } else if ( filter.field.id === JdbcTableSelectorComponent.tableFilterId ) { + const pattern = "^" + filter.value.replace( "*", ".*" ); + matches = item.name.match( pattern ) !== null; + } + + return matches; + } + + private matchesFilters( item: any, + filters: Filter[] ): boolean { + let matches = true; + + filters.forEach( ( filter ) => { + if ( !this.matchesFilter( item, filter ) ) { + matches = false; + return matches; + } + }); + + return matches; + } + private setInitialTableSelections(): void { let enableSelectAll = true; diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts index 7135dc68..6c185209 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts @@ -1,7 +1,5 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; - import { Connection } from "@connections/shared/connection.model"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { PatternFlyNgModule } from "patternfly-ng"; import { Table } from "../shared/table.model"; import { SelectedTableComponent } from "./selected-table.component"; @@ -16,7 +14,7 @@ describe("SelectedTableComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ NgxDatatableModule, PatternFlyNgModule ], + imports: [ PatternFlyNgModule ], declarations: [ SelectedTableComponent ] }) .compileComponents().then(() => { @@ -46,12 +44,12 @@ describe("SelectedTableComponent", () => { }); it("should have correct table name", () => { - const heading = fixture.debugElement.nativeElement.querySelector( ".selected-table-name" ); + const heading = fixture.debugElement.nativeElement.querySelector( ".object-card-title" ); expect( heading.textContent ).toContain( tableName ); }); it("should have correct connector name", () => { - const heading = fixture.debugElement.nativeElement.querySelector( ".selected-table-connection" ); + const heading = fixture.debugElement.nativeElement.querySelector( ".text-info" ); expect( heading.textContent ).toContain( connectionName ); }); diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts index 241910b1..000d5b60 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts @@ -43,22 +43,9 @@ export class SelectedTableComponent implements OnInit { public ngOnInit(): void { this.columnDefinitions = [ - { - draggable: false, - prop: "name", - name: "Name", - resizeable: false - }, { - draggable: false, - prop: "type", - name: "Type", - resizeable: false - }, { - draggable: false, - prop: "size", - name: "Size", - resizeable: false - } + { prop: "name" }, + { prop: "type" }, + { prop: "size" } ]; // TODO: replace with call to get the column metadata diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.css b/ngapp/src/app/dataservices/sql-control/sql-control.component.css index aea3039b..c0831991 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.css +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.css @@ -1,6 +1,6 @@ .view-table-full-div { padding-left: 0; - padding-right: 10px; + padding-right: 0; min-height: 240px; max-height: 240px; border: 1px inset grey; @@ -9,7 +9,7 @@ .view-table-quicklook-div { padding-left: 0; - padding-right: 10px; + padding-right: 0; min-height: 120px; max-height: 120px; border: 1px inset grey; diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.html b/ngapp/src/app/dataservices/sql-control/sql-control.component.html index 5e65d6e2..420f1268 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.html +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.html @@ -1,25 +1,13 @@
    - - - - + +
    @@ -57,14 +45,13 @@
    - - + +
    diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts index 08d2302b..d785f5c4 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts @@ -11,8 +11,8 @@ import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { CodemirrorModule } from "ng2-codemirror"; +import { PatternFlyNgModule } from "patternfly-ng"; import { SqlControlComponent } from "./sql-control.component"; describe("SqlControlComponent", () => { @@ -21,7 +21,7 @@ describe("SqlControlComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule, NgxDatatableModule, CodemirrorModule ], + imports: [ FormsModule, HttpModule, CodemirrorModule, PatternFlyNgModule ], declarations: [ SqlControlComponent ], providers: [ AppSettingsService, diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts index 6df35721..1c8a0390 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts @@ -27,6 +27,7 @@ import { LoadingState } from "@shared/loading-state.enum"; import "codemirror/addon/display/placeholder.js"; import "codemirror/addon/selection/active-line.js"; import "codemirror/mode/sql/sql.js"; +import { NgxDataTableConfig, TableConfig } from "patternfly-ng"; @Component({ encapsulation: ViewEncapsulation.None, @@ -41,7 +42,14 @@ export class SqlControlComponent implements OnInit { @Input() public serviceViews: Table[] = []; @Input() public viewSql = ""; + public ngxConfig: NgxDataTableConfig; + public tableConfig: TableConfig; + + public ngxViewConfig: NgxDataTableConfig; + public viewTableConfig: TableConfig; + public columns: any[] = []; + public viewColumns: any[] = []; public rows: any[] = []; public config = { @@ -52,11 +60,6 @@ export class SqlControlComponent implements OnInit { tabSize: 4, theme: "mdn-like" }; - public customClasses = { - sortAscending: "fa fa-sort-asc", - sortDescending: "fa fa-sort-desc" - }; - private dataserviceService: DataserviceService; private logger: LoggerService; private showResults = false; @@ -76,16 +79,51 @@ export class SqlControlComponent implements OnInit { this.queryMap.set(this.viewName, this.queryText); this.previousViewName = this.viewName; this.submitCurrentQuery(); + + this.viewColumns = [ + { + draggable: false, + name: "Views", + prop: "name", + resizeable: true, + sortable: true, + width: "100" + } + ]; + + this.ngxConfig = { + reorderable: true, + scrollbarH: true, + scrollbarV: false, + selectionType: "single", + sortable: true + } as NgxDataTableConfig; + + this.tableConfig = { + // nothing to do + } as TableConfig; + + this.ngxViewConfig = { + reorderable: false, + selected: this.selectedViews, + selectionType: "'single'", + sorts: [ { prop: "name", dir: "asc" } ], + } as NgxDataTableConfig; + + this.viewTableConfig = { + // nothing to do + } as TableConfig; } /* * Handle View selection from the view table */ - public onViewSelect( {selected} ): void { + public selectionChange( $event ): void { // Save query for current selection first this.queryMap.set(this.previousViewName, this.queryText); // View table is single select so use first element + const selected: Table[] = $event.selected; const view: Table = selected[ 0 ]; this.selectedViews = []; @@ -203,7 +241,6 @@ export class SqlControlComponent implements OnInit { // let firstTime = true; const rowNumHeader = "ROW #"; - // const widths: Map< string, number > = new Map< string, number >(); for ( let rowIndex = 0; rowIndex < rowData.length; rowIndex++ ) { const row = rowData[ rowIndex ]; @@ -215,22 +252,6 @@ export class SqlControlComponent implements OnInit { for (let colIndex = 0; colIndex < data.length; colIndex++) { const label = columnData[ colIndex ].getLabel(); dataRow[ label ] = data[ colIndex ]; - - // size column to largest width data of first 50 rows - // if ( rowIndex < 50 ) { - // const value = "" + dataRow[ label ]; - // const width = value.length; - // const labelWidth = label.length - // - // if ( firstTime ) { - // const max = Math.max( width, labelWidth ); - // widths.set( label, max ); - // } else { - // const currVal: number = widths.get( label ); - // const max = Math.max( width, currVal, labelWidth ); - // widths.set( label, max ); - // } - // } } this.rows.push( dataRow ); @@ -240,7 +261,6 @@ export class SqlControlComponent implements OnInit { // setup row number column const column = { canAutoResize: true, draggable: false, - // flexGrow: rowNumHeader.length, maxWidth: 60, minWidth: 60, name: rowNumHeader, @@ -252,20 +272,17 @@ export class SqlControlComponent implements OnInit { this.columns.push( column ); // - // Setup columns + // Setup data columns // - for ( let i = 0; i < columnData.length; i++) { - const colData = columnData[ i ]; + for ( const colData of columnData ) { const label = colData.getLabel(); - // const width = widths.get( label ); - const column = { canAutoResize: true, - draggable: false, - // flexGrow: width, - name: label.toUpperCase(), - prop: label, - resizable: true, - sortable: true }; - this.columns.push( column ); + const col = { canAutoResize: true, + draggable: false, + name: label.toUpperCase(), + prop: label, + resizable: true, + sortable: true }; + this.columns.push( col ); } } diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts index 19e2c68c..3f521272 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts @@ -11,8 +11,8 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; import { TestDataserviceComponent } from "@dataservices/test-dataservice/test-dataservice.component"; -import { NgxDatatableModule } from "@swimlane/ngx-datatable"; import { CodemirrorModule } from "ng2-codemirror"; +import { PatternFlyNgModule } from "patternfly-ng"; describe("TestDataserviceComponent", () => { let component: TestDataserviceComponent; @@ -20,7 +20,7 @@ describe("TestDataserviceComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, RouterTestingModule, NgxDatatableModule, CodemirrorModule ], + imports: [ CoreModule, FormsModule, RouterTestingModule, CodemirrorModule, PatternFlyNgModule ], declarations: [ SqlControlComponent, TestDataserviceComponent ], providers: [ NotifierService, diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index 1d6f80b0..878cf1d3 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -4,6 +4,7 @@ @import "~codemirror/theme/mdn-like.css"; @import "~patternfly/dist/css/patternfly.css"; @import "~patternfly/dist/css/patternfly-additions.css"; +@import "~patternfly-ng/dist/css/patternfly-ng.css"; :root { --alert-color: darkred; @@ -144,15 +145,16 @@ .object-card-selected .card-pf .card-pf-body, .object-card .card-pf .card-pf-body { - margin: 0; + margin: 20px; padding: 0; } .object-card-selected .card-pf .card-pf-footer, .object-card .card-pf .card-pf-footer { background-color: var(--card-footer-background-color); + margin: 0 !important; min-height: 20px; - padding: 4px 0px 4px 0px; + padding: 4px 0 4px 0; } .object-card-selected .card-pf .card-pf-heading, @@ -270,62 +272,6 @@ height: 200px; } -/******************************************************************/ -/* ngx-datatable Types */ -/******************************************************************/ - -.ngx-datatable { - position: absolute; top:0;left:0;right:0;bottom:0; -} - -.datatable-header { - color: white; - background-color: #bbbbbb; - text-align: left; -} - -.datatable-header-cell { - vertical-align: bottom; - border-bottom: 2px solid #ddd; - border-left: 1px solid #ddd; - border-right: 1px solid #ddd; - padding: 8px; - line-height: 1.42857143; - font-weight: bold; - color: rgb(51, 51, 51); -} - -.datatable-body-row { - border-bottom: 1px solid #d8d8d8; -} - -.datatable-row-even { - background-color: white; -} - -.datatable-row-even:hover { - background-color: #def3ff; -} - -.datatable-row-odd { - background-color: #f2f2f2; -} - -.datatable-row-odd:hover { - background-color: #def3ff; -} - -.datatable-body-cell { - padding: 0.25em 0.25em 0.25em 1.0em; - border-left: 1px solid #d8d8d8; - border-right: 1px solid #d8d8d8; -} - -.datatable-body-row.active .datatable-row-group { - background-color: #0088ce !important; - color: white; -} - /**************************************************************/ /* PatternFly Types */ /**************************************************************/ From 1cc8e6b24090d85e60ae76b38dc641648fed46e5 Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Mon, 12 Mar 2018 09:12:09 -0500 Subject: [PATCH 097/205] Fix for build error and test case. --- .../about-dialog.component.spec.ts | 18 +++++++++++++++--- .../about-dialog/about-dialog.component.ts | 10 ++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts b/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts index 6515eaee..a65ddf9b 100644 --- a/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts +++ b/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts @@ -1,7 +1,12 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; - +import { HttpModule } from "@angular/http"; import { About } from "@core/about-dialog/about.model"; +import { AboutService } from "@core/about-dialog/about.service"; import { MockAboutService } from "@core/about-dialog/mock-about.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { PatternFlyNgModule } from "patternfly-ng"; import { AboutDialogComponent } from "./about-dialog.component"; describe("AboutDialogComponent", () => { @@ -10,9 +15,16 @@ describe("AboutDialogComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ AboutDialogComponent ] + declarations: [ AboutDialogComponent ], + imports: [ HttpModule, PatternFlyNgModule ], + providers: [ + AboutService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + LoggerService ] }) - .compileComponents(); + .compileComponents().then(() => { + // nothing to do + }); })); beforeEach(() => { diff --git a/ngapp/src/app/core/about-dialog/about-dialog.component.ts b/ngapp/src/app/core/about-dialog/about-dialog.component.ts index 9f7e14e2..425ef9aa 100644 --- a/ngapp/src/app/core/about-dialog/about-dialog.component.ts +++ b/ngapp/src/app/core/about-dialog/about-dialog.component.ts @@ -16,12 +16,11 @@ */ import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from "@angular/core"; +import { AboutService } from "@core/about-dialog/about.service"; +import { LoggerService } from "@core/logger.service"; import { AboutEvent } from "app/core/about-dialog/about-event"; import { About } from "app/core/about-dialog/about.model"; -import { BsModalService } from "ngx-bootstrap/modal"; import { AboutModalConfig } from "patternfly-ng/modal"; -import { AboutService } from "@core/about-dialog/about.service"; -import { LoggerService } from "@core/logger.service"; @Component({ encapsulation: ViewEncapsulation.None, @@ -41,15 +40,14 @@ export class AboutDialogComponent implements OnInit { */ @Input() public info: About; - private aboutConfig: AboutModalConfig; + public aboutConfig: AboutModalConfig; private aboutService: AboutService; private logger: LoggerService; /** * The default contructor */ - constructor(private modalService: BsModalService, - logger: LoggerService, + constructor(logger: LoggerService, aboutService: AboutService) { this.aboutService = aboutService; this.logger = logger; From 89721a533f29ee21332ef2e8eaa3c87293df37b1 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 12 Mar 2018 15:01:32 -0500 Subject: [PATCH 098/205] TEIIDTOOLS-360 Styling Issues With Connection Wizard - made small changes to the ConnectionTypeCardComponent CSS --- .../connection-type-card/connection-type-card.component.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css b/ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css index 8ca16ced..9080c320 100644 --- a/ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css +++ b/ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css @@ -1,3 +1,5 @@ -.object-card-selected .card-pf .card-pf-heading { - border-bottom: var(--card-border-width) var(--card-border-style) var(--card-border-color) !important; +/* Since no body on card get rid of margin */ +.object-card-selected .card-pf .card-pf-body, +.object-card .card-pf .card-pf-body { + margin: 0; } From 5f0cb208916e4b3059fa1284afebd057f749cad3 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 13 Mar 2018 08:57:05 -0500 Subject: [PATCH 099/205] TEIIDTOOLS-365 Do not allow dataservice wizard to start when there are no connections - upgraded dataservices summary page to use the patternfly-ng empty state component - added another empty state component to the dataservices summary page for when there are no connections --- .../dataservices/dataservices.component.html | 29 ++--- .../dataservices.component.spec.ts | 3 + .../dataservices/dataservices.component.ts | 111 ++++++++++++++++-- 3 files changed, 117 insertions(+), 26 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 986cf642..8ab09247 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -36,25 +36,26 @@

    Dataservices
    -
    -
    -
    - +
    +
    +
    + +
    -

    No Dataservices Found

    -

    - No Dataservices were found - please click below to create a new Dataservice! -

    -
    - +
    +
    +
    +
    -
    - -
    +
    diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index c8739c0f..a4cc3128 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -3,6 +3,8 @@ import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; import { By } from "@angular/platform-browser"; import { RouterTestingModule } from "@angular/router/testing"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; @@ -44,6 +46,7 @@ describe("DataservicesComponent", () => { NotifierService, WizardService, { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: ConnectionService, useClass: MockConnectionService }, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } ] diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 5781a35c..6bc9e1f7 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -17,6 +17,8 @@ import { Component, OnInit, ViewChild } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; @@ -32,18 +34,21 @@ import { AbstractPageComponent } from "@shared/abstract-page.component"; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { LayoutType } from "@shared/layout-type.enum"; import { SortDirection } from "@shared/sort-direction.enum"; -import { NotificationType } from "patternfly-ng"; +import { + ActionConfig, + EmptyStateConfig, + Filter, + FilterConfig, + FilterEvent, + FilterField, + FilterType, + NotificationType, + SortConfig, + SortEvent, + SortField +} from "patternfly-ng"; import { Subscription } from "rxjs/Subscription"; -import { Filter } from "patternfly-ng"; -import { FilterConfig } from "patternfly-ng"; -import { FilterField } from "patternfly-ng"; -import { FilterEvent } from "patternfly-ng"; -import { FilterType } from "patternfly-ng"; -import { SortConfig } from "patternfly-ng"; -import { SortField } from "patternfly-ng"; -import { SortEvent } from "patternfly-ng"; - @Component({ moduleId: module.id, selector: "app-dataservices", @@ -55,6 +60,9 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn public readonly exportInProgressHeader: string = "Publishing: "; public readonly exportSuccessHeader: string = "Publish Succeeded: "; public readonly exportFailedHeader: string = "Publish Failed: "; + + public readonly connectionsLoadedTag = "connections"; + public filterConfig: FilterConfig; public filtersText = ""; public items: Dataservice[]; @@ -62,6 +70,10 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn public currentSortField: SortField; public isAscendingSort = true; + private connectionsExist = false; + private noConnectionsConfig: EmptyStateConfig; + private noDataservicesConfig: EmptyStateConfig; + private cardListAreaCss = "dataservice-summary-top-area-no-results"; private resultsAreaCss = "dataservice-summary-bottom-area-no-results"; private resultsShowing = false; @@ -69,6 +81,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn private quickLookQueryText: string; private allServices: Dataservice[] = []; + private connectionService: ConnectionService; private filteredServices: Dataservice[] = []; private selectedServices: Dataservice[] = []; private dataserviceNameForDelete: string; @@ -92,7 +105,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn constructor(router: Router, route: ActivatedRoute, dataserviceService: DataserviceService, logger: LoggerService, appSettingsService: AppSettingsService, wizardService: WizardService, - notifierService: NotifierService, vdbService: VdbService ) { + notifierService: NotifierService, vdbService: VdbService, connectionService: ConnectionService ) { super(route, logger); this.router = router; this.appSettingsService = appSettingsService; @@ -104,10 +117,10 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.dataserviceStateSubscription = this.notifierService.getDataserviceStateMap().subscribe((serviceStateMap) => { this.onDataserviceStateChanged(serviceStateMap); }); + this.connectionService = connectionService; } public ngOnInit(): void { - super.ngOnInit(); this.filterConfig = { @@ -140,6 +153,68 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } as SortConfig; } + public get noConnectionsEmptyConfig(): EmptyStateConfig { + if ( !this.noConnectionsConfig ) { + const actionConfig = { + primaryActions: [ + { + id: "createConnectionActionId", + title: "Add Connection", + tooltip: "Add a connection" + } + ] + } as ActionConfig; + + this.noConnectionsConfig = { + actions: actionConfig, + iconStyleClass: "pficon-warning-triangle-o", + info: "No dataservices were found. In order to create a dataservice, you must first create a connection. " + + "Please click below to create a connection.", + title: "No Dataservices Available" + } as EmptyStateConfig; + } + + return this.noConnectionsConfig; + } + + public get noDataservicesEmptyConfig(): EmptyStateConfig { + if ( !this.noDataservicesConfig ) { + const actionConfig = { + primaryActions: [ + { + id: "createDataserviceActionId", + title: "Add Dataservice", + tooltip: "Add a dataservice" + } + ] + } as ActionConfig; + + this.noDataservicesConfig = { + actions: actionConfig, + iconStyleClass: "pficon-warning-triangle-o", + info: "No dataservices were found. Please click below to create a dataservice.", + title: "No Dataservices Available" + } as EmptyStateConfig; + } + + return this.noDataservicesConfig; + } + + public get hasConnections(): boolean { + return this.isLoaded( this.connectionsLoadedTag ) && this.connectionsExist; + } + + public onNewConnection(): void { + // TODO ask Mark if this will work + this.wizardService.setEdit(false); + + const link: string[] = [ ConnectionsConstants.addConnectionPath ]; + this.logger.log( "[DataservicesPageComponent] Navigating to: %o", link ); + this.router.navigate( link ).then(() => { + // nothing to do + } ); + } + public loadAsyncPageData(): void { const self = this; this.dataserviceService @@ -155,6 +230,18 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn self.error(error, "Error getting dataservices"); } ); + + this.connectionService + .getAllConnections() + .subscribe( + ( connections ) => { + self.connectionsExist = connections.length !== 0; + self.loaded( self.connectionsLoadedTag ); + }, + ( error ) => { + self.error( error, "Error getting connections" ); + } + ); } /** From e216cf4a21c991a8c1db3043c130a86ec38cff40 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 16 Mar 2018 15:28:07 -0500 Subject: [PATCH 100/205] Initial commit --- .../src/app/connections/connections.module.ts | 26 +++++- ngapp/src/app/core/core.module.ts | 24 +++++- .../app/dataservices/dataservices.module.ts | 86 ++++++++++++++++++- .../shared/mock-dataservice.service.ts | 26 +++--- .../shared/mock-notifier.service.ts | 11 +++ .../dataservices/shared/mock-vdb.service.ts | 12 +++ ngapp/src/environments/environment.ts | 5 +- 7 files changed, 170 insertions(+), 20 deletions(-) create mode 100644 ngapp/src/app/dataservices/shared/mock-notifier.service.ts diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 771334ab..6d850ee0 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -34,6 +34,10 @@ import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { ConnectionTypeCardComponent } from "./connection-type-cards/connection-type-card/connection-type-card.component"; import { ConnectionTypeCardsComponent } from "./connection-type-cards/connection-type-cards.component"; +import { AppSettingsService } from "@core/app-settings.service"; +import { Http } from "@angular/http"; +import { environment } from "@environments/environment"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; @NgModule({ imports: [ @@ -59,10 +63,30 @@ import { ConnectionTypeCardsComponent } from "./connection-type-cards/connection ConnectionTypeCardComponent ], providers: [ - ConnectionService, + { + provide: ConnectionService, + useFactory: connectionServiceFactory, + deps: [ Http, AppSettingsService, LoggerService ], + multi: false + }, LoggerService ], exports: [ ] }) export class ConnectionsModule { } + +/** + * A factory that produces the appropriate instande of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {AppSettingsService} appSettings the app settings service + * @param {LoggerService} logger the logger + * @returns {ConnectionService} the requested service + */ +export function connectionServiceFactory( http: Http, + appSettings: AppSettingsService, + logger: LoggerService ): ConnectionService { + return environment.production || !environment.uiDevMode ? new ConnectionService( http, appSettings, logger ) + : new MockConnectionService( http, appSettings, logger ); +} diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 7ab84f9e..3399eae1 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -17,7 +17,7 @@ import { CommonModule } from "@angular/common"; import { NgModule, Optional, SkipSelf } from "@angular/core"; -import { HttpModule } from "@angular/http"; +import { Http, HttpModule } from "@angular/http"; import { RouterModule } from "@angular/router"; import { AboutDialogComponent } from "@core/about-dialog/about-dialog.component"; import { AboutService } from "@core/about-dialog/about.service"; @@ -25,7 +25,9 @@ import { AppSettingsService } from "@core/app-settings.service"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; +import { environment } from "@environments/environment"; import { ModalModule } from "ngx-bootstrap/modal"; import { BsModalService } from "ngx-bootstrap/modal"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -51,7 +53,12 @@ import { PatternFlyNgModule } from "patternfly-ng"; ], providers: [ AboutService, - AppSettingsService, + { + provide: AppSettingsService, + useFactory: appSettingsServiceFactory, + deps: [ Http, LoggerService ], + multi: false + }, LoggerService, BsModalService ] @@ -65,3 +72,16 @@ export class CoreModule { } } + +/** + * A factory that produces the appropriate instande of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {LoggerService} logger the logger + * @returns {AppSettingsService} the requested service + */ +export function appSettingsServiceFactory( http: Http, + logger: LoggerService ): AppSettingsService { + return environment.production || !environment.uiDevMode ? new AppSettingsService( http, logger ) + : new MockAppSettingsService( http, logger ); +} diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 975f3430..ad71ea21 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -18,7 +18,9 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { Http } from "@angular/http"; import { RouterModule } from "@angular/router"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { LoggerService } from "@core/logger.service"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; @@ -28,9 +30,13 @@ import { ViewsContentComponent } from "@dataservices/dataservices-list/views-con import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.module"; import { DataservicesComponent } from "@dataservices/dataservices.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { MockNotifierService } from "@dataservices/shared/mock-notifier.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; +import { environment } from "@environments/environment"; import { SharedModule } from "@shared/shared.module"; import { CodemirrorModule } from "ng2-codemirror"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -71,13 +77,87 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co DataserviceCardComponent ], providers: [ - DataserviceService, - VdbService, + { + provide: DataserviceService, + useFactory: dataserviceServiceFactory, + deps: [ Http, VdbService, AppSettingsService, NotifierService, LoggerService ], + multi: false + }, + { + provide: NotifierService, + useFactory: notifierServiceFactory, + multi: false + }, + { + provide: VdbService, + useFactory: vdbServiceFactory, + deps: [ Http, AppSettingsService, NotifierService, LoggerService ], + multi: false + }, LoggerService, - NotifierService, WizardService ], exports: [ ] }) export class DataservicesModule { } + +/** + * A factory that produces the appropriate instance of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {VdbService} vdbService the VDB service + * @param {AppSettingsService} appSettings the app settings service + * @param {NotifierService} notifierService the notifier service + * @param {LoggerService} logger the logger + * @returns {DataserviceService} the requested service + */ +export function dataserviceServiceFactory( http: Http, + vdbService: VdbService, + appSettings: AppSettingsService, + notifierService: NotifierService, + logger: LoggerService ): DataserviceService { + return environment.production || !environment.uiDevMode ? new DataserviceService( http, + vdbService, + appSettings, + notifierService, + logger ) + : new MockDataserviceService( http, + vdbService, + appSettings, + notifierService, + logger ); +} + +/** + * A factory that produces the appropriate instance of the service based on current environment settings. + * + * @returns {NotifierService} the requested service + */ +export function notifierServiceFactory(): NotifierService { + return environment.production || !environment.uiDevMode ? new NotifierService() + : new MockNotifierService(); +} + +/** + * A factory that produces the appropriate instance of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {AppSettingsService} appSettings the app settings service + * @param {NotifierService} notifierService the notifier service + * @param {LoggerService} logger the logger + * @returns {VdbService} the requested service + */ +export function vdbServiceFactory( http: Http, + appSettings: AppSettingsService, + notifierService: NotifierService, + logger: LoggerService ): VdbService { + return environment.production || !environment.uiDevMode ? new VdbService( http, + appSettings, + notifierService, + logger ) + : new MockVdbService( http, + appSettings, + notifierService, + logger ); +} diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 918921bf..f1f022ce 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -106,20 +106,20 @@ export class MockDataserviceService extends DataserviceService { return tables; } - /** - * Updates the current Dataservice states - triggers update to be broadcast to interested components - */ - public updateDataserviceStates(): void { - // Nothing to do - } + // /** + // * Updates the current Dataservice states - triggers update to be broadcast to interested components + // */ + // public updateDataserviceStates(): void { + // // Nothing to do + // } - /** - * Polls the server and sends Dataservice state updates at the specified interval - * @param {number} pollIntervalSec the interval (sec) between polling attempts - */ - public pollDataserviceStatus(pollIntervalSec: number): void { - // Nothing to do - } + // /** + // * Polls the server and sends Dataservice state updates at the specified interval + // * @param {number} pollIntervalSec the interval (sec) between polling attempts + // */ + // public pollDataserviceStatus(pollIntervalSec: number): void { + // // Nothing to do + // } /** * Query a Dataservice via the komodo rest interface diff --git a/ngapp/src/app/dataservices/shared/mock-notifier.service.ts b/ngapp/src/app/dataservices/shared/mock-notifier.service.ts new file mode 100644 index 00000000..339d0f37 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/mock-notifier.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from "@angular/core"; +import { NotifierService } from "@dataservices/shared/notifier.service"; + +@Injectable() +export class MockNotifierService extends NotifierService { + + constructor() { + super(); + } + +} diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index c5b5cc6a..e53a0b7c 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -48,8 +48,19 @@ export class MockVdbService extends VdbService { constructor(http: Http, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { super(http, appSettings, notifierService, logger); this.vdb1.setId("serv1"); + this.vdbStatus1.setName( "serv1" ); + this.vdbStatus1.setLoading( false ); + this.vdbStatus1.setActive( true ); + this.vdb2.setId("serv2"); + this.vdbStatus2.setName("serv2"); + this.vdbStatus2.setLoading( false ); + this.vdbStatus2.setActive( true ); + this.vdb3.setId("serv3"); + this.vdbStatus3.setName("serv2"); + this.vdbStatus3.setLoading( false ); + this.vdbStatus3.setActive( true ); } /** @@ -65,6 +76,7 @@ export class MockVdbService extends VdbService { * @returns {Observable} */ public getTeiidVdbStatuses(): Observable { + super.getTeiidVdbStatuses(); return Observable.of(this.statuses); } diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index dea1a9bf..7cd88872 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -56,6 +56,9 @@ export const environment = { komodoTeiidUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/metadata", // REST URL - Komodo service - komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service" + komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service", + + // Indicates if in UI development mode where OpenShift will not be used. + uiDevMode: true }; From d0a38a201434b683077eb6e8305407df5ad95766 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 20 Mar 2018 08:30:51 -0500 Subject: [PATCH 101/205] ui dev mode changes --- .../add-connection-wizard.component.ts | 8 - .../shared/mock-connection.service.ts | 155 ++++++++++-------- ngapp/src/app/core/core.module.ts | 22 +++ .../add-dataservice-wizard.component.ts | 7 - .../connection-table-selector.component.ts | 2 +- .../jdbc-table-selector.component.spec.ts | 56 +++---- ngapp/src/app/shared/shared.module.ts | 6 +- .../src/app/shared/test-data.service.spec.ts | 15 ++ ngapp/src/app/shared/test-data.service.ts | 138 ++++++++++++++++ ngapp/src/environments/environment.prod.ts | 5 +- 10 files changed, 296 insertions(+), 118 deletions(-) create mode 100644 ngapp/src/app/shared/test-data.service.spec.ts create mode 100644 ngapp/src/app/shared/test-data.service.ts diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index 9256c393..d44d3f3e 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -155,8 +155,6 @@ export class AddConnectionWizardComponent implements OnInit { } } } - - this.setNavAway(false); } // ---------------- @@ -488,16 +486,11 @@ export class AddConnectionWizardComponent implements OnInit { ); } - private setNavAway(allow: boolean): void { - this.step1Config.allowNavAway = allow; - } - /** * Updates the page 1 status */ private updatePage1ValidStatus( ): void { this.step1Config.nextEnabled = this.selectedConnTypes.length > 0; - this.setNavAway(this.step1Config.nextEnabled); } /** @@ -512,7 +505,6 @@ export class AddConnectionWizardComponent implements OnInit { } else { this.step2aConfig.nextEnabled = this.nameValid && this.hasSelectedServiceCatalogSource; } - this.setNavAway(this.step2aConfig.nextEnabled); } /** diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index f494e0e1..bce12830 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -15,13 +15,12 @@ * limitations under the License. */ -import { Injectable } from "@angular/core"; +import { Injectable, ReflectiveInjector } from "@angular/core"; import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; -import { TemplateDefinition } from "@connections/shared/template-definition.model"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; @@ -29,61 +28,54 @@ import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; +import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; +import { NewConnection } from "@connections/shared/new-connection.model"; +import { TestDataService } from "@shared/test-data.service"; @Injectable() export class MockConnectionService extends ConnectionService { - public static conn1Id = "conn1"; - public static conn1 = MockConnectionService.createJdbcConnection( MockConnectionService.conn1Id ); - public static conn1SchemaInfos = [ - SchemaInfo.create( { name: "conn1SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn1CatalogInfo", type: "Catalog", schemaNames: [ "conn1CatalogSchema1", "conn1CatalogSchema1" ] } ) - ]; - public static numConn1Schemas = 3; - - public static conn2Id = "conn2"; - public static conn2 = MockConnectionService.createJdbcConnection( MockConnectionService.conn2Id ); - public static conn2SchemaInfos = [ - SchemaInfo.create( { name: "conn2CatalogInfo", type: "Catalog", schemaNames: [ "conn2CatalogSchema1", "conn2CatalogSchema1" ] } ), - SchemaInfo.create( { name: "conn2SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn2SchemaInfo2", type: "Schema" } ) - ]; - public static numConn2Schemas = 4; - - public static conn3Id = "conn3"; - public static conn3 = MockConnectionService.createJdbcConnection( MockConnectionService.conn3Id ); - public static conn3SchemaInfos = [ - SchemaInfo.create( { name: "conn3CatalogInfo", type: "Catalog", schemaNames: [ "conn3CatalogSchema1", "conn3CatalogSchema1" ] } ), - SchemaInfo.create( { name: "conn3SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ), - SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ) - ]; - public static numConn3Schemas = 5; - - public static templ1 = new TemplateDefinition(); - public static templ2 = new TemplateDefinition(); - public static templ3 = new TemplateDefinition(); - - public conns: Connection[] = [ - MockConnectionService.conn1, - MockConnectionService.conn2, - MockConnectionService.conn3 ]; - - public templs: TemplateDefinition[] = [ - MockConnectionService.templ1, - MockConnectionService.templ2, - MockConnectionService.templ3 ]; - - private static createJdbcConnection( id: string ): Connection { - const newConn = new Connection(); - newConn.setId( id ); - newConn.setJdbc( true ); - newConn.setServiceCatalogSourceName(id); - return newConn; - } + private connections: Connection[]; + private serviceCatalogSources: ServiceCatalogSource[]; + private connectionSourceSchemaInfoMap: Map; constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { super(http, appSettings, logger); + + // Inject service for test data + let injector = ReflectiveInjector.resolveAndCreate([TestDataService]); + const testDataService = injector.get(TestDataService); + + // Get test data + this.connections = testDataService.getConnections(); + this.serviceCatalogSources = testDataService.getServiceCatalogSources(); + this.connectionSourceSchemaInfoMap = testDataService.getConnectionSourceSchemaInfoMap(); + } + + public isValidName( name: string ): Observable< string > { + if ( !name || name.length === 0 ) { + return Observable.of( "Connection name cannot be empty" ); + } + + // make sure no dataservice exists with that name + for ( const conn of this.connections ) { + if ( conn.getId() === name ) { + return Observable.of( "Connection with that name already exists" ); + } + } + + // just implement a case where no special characters allowed + for ( let i = 0; i < name.length; i++ ) { + const c = name.charAt( i ); + + // special characters have the same upper and lower case values + if ( c.toUpperCase() === c.toLowerCase() ) { + return Observable.of( "No special characters allowed" ); + } + } + + // valid + return Observable.of( "" ); } /** @@ -91,7 +83,7 @@ export class MockConnectionService extends ConnectionService { * @returns {Observable} */ public getAllConnections(): Observable { - return Observable.of(this.conns); + return Observable.of(this.connections); } /** @@ -100,36 +92,37 @@ export class MockConnectionService extends ConnectionService { * @returns {Observable} */ public deleteConnection(connectionId: string): Observable { - const size = this.conns.length; - this.conns = this.conns.filter( ( conn ) => conn.getId() !== connectionId ); - return Observable.of( size === this.conns.length ); + const size = this.connections.length; + this.connections = this.connections.filter( ( conn ) => conn.getId() !== connectionId ); + return Observable.of( size === this.connections.length ); } /** - * Get the connection templates from the komodo rest interface - * @returns {Observable>>} + * Get the available ServiceCatalogSources from the komodo rest interface + * @returns {Observable} */ - public getConnectionTemplates(): Observable { - return Observable.of(this.templs); + public getAllServiceCatalogSources(): Observable { + return Observable.of(this.serviceCatalogSources); } - public getConnectionSchemaInfos( connectionId: string): Observable< SchemaInfo[] > { - if ( connectionId === MockConnectionService.conn1Id ) { - return Observable.of( MockConnectionService.conn1SchemaInfos ); - } - - if ( connectionId === MockConnectionService.conn2Id ) { - return Observable.of( MockConnectionService.conn2SchemaInfos ); - } - - if ( connectionId === MockConnectionService.conn3Id ) { - return Observable.of( MockConnectionService.conn3SchemaInfos ); + /** + * Get the connection schema info for a connection source + * @returns {Observable} + */ + public getConnectionSchemaInfos( connSource: string): Observable< SchemaInfo[] > { + const schemaInfos: SchemaInfo[] = this.connectionSourceSchemaInfoMap.get(connSource); + if( !schemaInfos || schemaInfos == null ) { + const empty: SchemaInfo[] = []; + return Observable.of( empty ); } - - const empty: SchemaInfo[] = []; - return Observable.of( empty ); + return Observable.of(schemaInfos); } + /** + * Get the tables for the specified input (connection and filters) for a Jdbc Connection + * @param {JdbcTableFilter} tableFilter + * @returns {Observable} + */ public getJdbcConnectionTables( tableFilter: JdbcTableFilter ): Observable< string[] > { const tableNames = []; tableNames.push( "table1" ); @@ -138,4 +131,22 @@ export class MockConnectionService extends ConnectionService { return Observable.of( tableNames ); } + /** + * Create a connection in the Komodo repo - also binds the specified serviceCatalogSource + * @param {NewConnection} connection the connection object + * @returns {Observable} + */ + public createAndBindConnection(connection: NewConnection): Observable { + return Observable.of(true); + } + + /** + * Update a connection in the Komodo repo - also binds the specified serviceCatalogSource. + * @param {NewConnection} connection the connection object + * @returns {Observable} + */ + public updateAndBindConnection(connection: NewConnection): Observable { + return Observable.of(true); + } + } diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 3399eae1..f3d2ab2b 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -31,6 +31,7 @@ import { environment } from "@environments/environment"; import { ModalModule } from "ngx-bootstrap/modal"; import { BsModalService } from "ngx-bootstrap/modal"; import { PatternFlyNgModule } from "patternfly-ng"; +import { MockAboutService } from "@core/about-dialog/mock-about.service"; @NgModule({ imports: [ @@ -59,6 +60,12 @@ import { PatternFlyNgModule } from "patternfly-ng"; deps: [ Http, LoggerService ], multi: false }, + { + provide: AboutService, + useFactory: aboutServiceFactory, + deps: [ Http, AppSettingsService, LoggerService], + multi: false + }, LoggerService, BsModalService ] @@ -85,3 +92,18 @@ export function appSettingsServiceFactory( http: Http, return environment.production || !environment.uiDevMode ? new AppSettingsService( http, logger ) : new MockAppSettingsService( http, logger ); } + +/** + * A factory that produces the appropriate instance of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {AppSettingsService} appSettings the app settings + * @param {LoggerService} logger the logger + * @returns {AboutService} the requested service + */ +export function aboutServiceFactory( http: Http, + appSettings: AppSettingsService, + logger: LoggerService ): AboutService { + return environment.production || !environment.uiDevMode ? new AboutService( http, appSettings, logger ) + : new MockAboutService( http, appSettings, logger ); +} diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index da7fdafd..da0251c1 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -164,7 +164,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.basicPropertyForm.controls["name"].setValue(null); this.basicPropertyForm.controls["description"].setValue(null); } - this.setNavAway(false); } public ngOnDestroy(): void { @@ -440,7 +439,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { */ public updatePage1ValidStatus( ): void { this.step1Config.nextEnabled = this.tableSelector.valid(); - this.setNavAway(this.step1Config.nextEnabled); } /** @@ -475,10 +473,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } } - private setNavAway(allow: boolean): void { - this.step1Config.allowNavAway = allow; - } - private updatePage2aValidStatus( ): void { if (!this.step2aConfig) { return; @@ -488,7 +482,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } else { this.step2aConfig.nextEnabled = this.nameValid && this.hasSelectedConnection(); } - this.setNavAway(this.step2aConfig.nextEnabled); } /* diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index 8f577cca..da1b42dc 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -157,7 +157,7 @@ export class ConnectionTableSelectorComponent implements OnInit { // only set if schema selection has changed (see setter) if ( this.selectedConn == null || this.selectedConn.name !== conn.name ) { - this.selectedConn = conn; + this.selectedConnection = conn; } } diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index 5e61522e..57ae6f51 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -46,33 +46,33 @@ describe("JdbcTableSelectorComponent", () => { expect(component).toBeTruthy(); }); - it("should have correct number of schemas", () => { - console.log("========== [JdbcTableSelectorComponent] should have correct number of schemas"); - component.connection = MockConnectionService.conn2; - component.ngOnInit(); - component.setConnection( MockConnectionService.conn1 ); - expect( component.getSchemas().length ).toBe( MockConnectionService.numConn1Schemas ); - }); - - it( "should clear schemas", () => { - console.log("========== [JdbcTableSelectorComponent] should clear schemas"); - component.connection = MockConnectionService.conn3; - component.ngOnInit(); - expect( component.getSchemas().length ).toBe( MockConnectionService.numConn3Schemas ); - - component.clearSchemas(); - expect( component.getSchemas().length ).toBe( 0 ); - }); - - it( "should select schema", () => { - console.log("========== [JdbcTableSelectorComponent] should select schema"); - component.connection = MockConnectionService.conn1; - component.ngOnInit(); - expect( component.selectedSchema ).toBeNull(); - expect( component.hasSelectedSchema ).toBeFalsy(); - - component.selectedSchema = component.getSchemas()[ 0 ]; - expect( component.hasSelectedSchema ).toBeTruthy(); - }); + // it("should have correct number of schemas", () => { + // console.log("========== [JdbcTableSelectorComponent] should have correct number of schemas"); + // component.connection = MockConnectionService.conn2; + // component.ngOnInit(); + // component.setConnection( MockConnectionService.conn1 ); + // expect( component.getSchemas().length ).toBe( MockConnectionService.numConn1Schemas ); + // }); + // + // it( "should clear schemas", () => { + // console.log("========== [JdbcTableSelectorComponent] should clear schemas"); + // component.connection = MockConnectionService.conn3; + // component.ngOnInit(); + // expect( component.getSchemas().length ).toBe( MockConnectionService.numConn3Schemas ); + // + // component.clearSchemas(); + // expect( component.getSchemas().length ).toBe( 0 ); + // }); + // + // it( "should select schema", () => { + // console.log("========== [JdbcTableSelectorComponent] should select schema"); + // component.connection = MockConnectionService.conn1; + // component.ngOnInit(); + // expect( component.selectedSchema ).toBeNull(); + // expect( component.hasSelectedSchema ).toBeFalsy(); + // + // component.selectedSchema = component.getSchemas()[ 0 ]; + // expect( component.hasSelectedSchema ).toBeTruthy(); + // }); }); diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index b9d82c4f..622b9841 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -25,6 +25,7 @@ import { ModalModule } from "ngx-bootstrap"; import { PageNotFoundComponent } from "./page-not-found/page-not-found.component"; import { PropertyFormPropertyComponent } from "./property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "./property-form/property-form.component"; +import { TestDataService } from "@shared/test-data.service"; @NgModule({ imports: [ @@ -45,7 +46,10 @@ import { PropertyFormComponent } from "./property-form/property-form.component"; PageNotFoundComponent, PropertyFormComponent, PropertyFormPropertyComponent - ] + ], + providers: [ + TestDataService + ], }) export class SharedModule { } diff --git a/ngapp/src/app/shared/test-data.service.spec.ts b/ngapp/src/app/shared/test-data.service.spec.ts new file mode 100644 index 00000000..ee087eea --- /dev/null +++ b/ngapp/src/app/shared/test-data.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { TestDataService } from './test-data.service'; + +describe('TestDataService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [TestDataService] + }); + }); + + it('should be created', inject([TestDataService], (service: TestDataService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts new file mode 100644 index 00000000..8bfdc62a --- /dev/null +++ b/ngapp/src/app/shared/test-data.service.ts @@ -0,0 +1,138 @@ +import { Injectable } from '@angular/core'; +import {Connection} from "@connections/shared/connection.model"; +import {ServiceCatalogSource} from "@connections/shared/service-catalog-source.model"; +import {MockConnectionService} from "@connections/shared/mock-connection.service"; +import {Observable} from "rxjs/Observable"; +import {SchemaInfo} from "@connections/shared/schema-info.model"; + +@Injectable() +export class TestDataService { + + private static catalogSourceId1 = "postgresql-persistent-j9vqv"; + private static catalogSourceId2 = "postgresql-persistent-a8xrt"; + private static catalogSourceId3 = "mysql-persistent-t3irv"; + + // ================================================================= + // ServiceCatalog DataSources + // ================================================================= + private static catalogSource1 = TestDataService.createServiceCatalogSource( + TestDataService.catalogSourceId1, + TestDataService.catalogSourceId1, + "postgresql", + true ); + private static catalogSource2 = TestDataService.createServiceCatalogSource( + TestDataService.catalogSourceId2, + TestDataService.catalogSourceId2, + "postgresql", + true ); + private static catalogSource3 = TestDataService.createServiceCatalogSource( + TestDataService.catalogSourceId3, + TestDataService.catalogSourceId3, + "mysql", + true ); + + private catalogSources: ServiceCatalogSource[] = [TestDataService.catalogSource1, + TestDataService.catalogSource2, + TestDataService.catalogSource3]; + + // ================================================================= + // Connections + // ================================================================= + private static connId1 = "conn1"; + private static connId2 = "conn2"; + private static connId3 = "conn3"; + private static conn1 = TestDataService.createConnection(TestDataService.connId1, TestDataService.catalogSource1 ); + private static conn2 = TestDataService.createConnection(TestDataService.connId2, TestDataService.catalogSource2 ); + private static conn3 = TestDataService.createConnection(TestDataService.connId3, TestDataService.catalogSource3 ); + + private connections: Connection[] = [TestDataService.conn1, + TestDataService.conn2, + TestDataService.conn3]; + + // ================================================================= + // SchemaInfos for the connections + // ================================================================= + private static conn1SchemaInfos = [ + SchemaInfo.create( { name: "conn1SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn1CatalogInfo", type: "Catalog", schemaNames: [ "conn1CatalogSchema1", "conn1CatalogSchema1" ] } ) + ]; + + private static conn2SchemaInfos = [ + SchemaInfo.create( { name: "conn2CatalogInfo", type: "Catalog", schemaNames: [ "conn2CatalogSchema1", "conn2CatalogSchema1" ] } ), + SchemaInfo.create( { name: "conn2SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn2SchemaInfo2", type: "Schema" } ) + ]; + + private static conn3SchemaInfos = [ + SchemaInfo.create( { name: "conn3CatalogInfo", type: "Catalog", schemaNames: [ "conn3CatalogSchema1", "conn3CatalogSchema1" ] } ), + SchemaInfo.create( { name: "conn3SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ), + SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ) + ]; + + constructor() { } + + /** + * @returns {Connection[]} the array of test connections + */ + public getConnections(): Connection[] { + return this.connections; + } + + /** + * @returns {ServiceCatalogSource[]} the array of test Service Catalog datasources + */ + public getServiceCatalogSources(): ServiceCatalogSource[] { + return this.catalogSources; + } + + /** + * @returns {Map} the array of test Service Catalog datasources + */ + public getConnectionSourceSchemaInfoMap( ): Map { + const infoMap = new Map(); + infoMap.set( TestDataService.conn1.getServiceCatalogSourceName(), TestDataService.conn1SchemaInfos ); + infoMap.set( TestDataService.conn2.getServiceCatalogSourceName(), TestDataService.conn2SchemaInfos ); + infoMap.set( TestDataService.conn3.getServiceCatalogSourceName(), TestDataService.conn3SchemaInfos ); + return infoMap; + } + + /** + * Create a connection of the specified id using the supplied ServiceCatalogSource + * @param {string} id + * @param {ServiceCatalogSource} serviceCatalogSource + * @returns {Connection} + */ + private static createConnection( id: string, serviceCatalogSource: ServiceCatalogSource ): Connection { + const newConn = new Connection(); + newConn.setId( id ); + const driverName = serviceCatalogSource.getType(); + newConn.setDriverName( driverName ); + if( driverName === 'mysql' || driverName === 'postgresql') { + newConn.setJdbc( true ); + } else { + newConn.setJdbc( false ); + } + newConn.setServiceCatalogSourceName(serviceCatalogSource.getName()); + newConn.setJndiName("java:/" + serviceCatalogSource.getName()); + return newConn; + } + + /** + * Create a ServiceCatalogSource using the specified info + * @param {string} id the id + * @param {string} name the name + * @param {string} type the type + * @param {boolean} bound 'true' if bound + * @returns {ServiceCatalogSource} + */ + private static createServiceCatalogSource( id: string, name: string, type: string, bound: boolean ) { + const catalogSource = new ServiceCatalogSource(); + catalogSource.setId(id); + catalogSource.setName(name); + catalogSource.setType(type); + catalogSource.setBound(bound); + return catalogSource; + } + +} diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts index 73c26c4f..b699a448 100644 --- a/ngapp/src/environments/environment.prod.ts +++ b/ngapp/src/environments/environment.prod.ts @@ -53,6 +53,9 @@ export const environment = { komodoTeiidUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/metadata", // REST URL - Komodo service - komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service" + komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service", + + // Indicates if in UI development mode where OpenShift will not be used. + uiDevMode: false }; From 9dd6589f79b5447101804278dd791b9b433b2ea6 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 20 Mar 2018 10:09:28 -0500 Subject: [PATCH 102/205] Work on getting dataservice wizard working with local UI dev mode. --- .../jdbc-table-selector.component.ts | 1 - .../dataservices/shared/dataservice.model.ts | 6 +- .../shared/mock-dataservice.service.ts | 57 ++++++++++++++----- .../dataservices/shared/mock-vdb.service.ts | 14 ++++- .../app/dataservices/shared/vdb.service.ts | 4 +- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index 97ea9186..5de510e7 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -460,7 +460,6 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { * Handler for changes in table selection */ public selectedTableChanged( $event: TableEvent ): void { - console.error( $event ); const table: Table = $event.row; if ( table ) { diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 2462daf4..a14a5be7 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -112,9 +112,13 @@ export class Dataservice implements Identifiable< string > { } /** - * @returns {string[]} the dataservice view names (can be null) + * @returns {string[]} the dataservice view names (never null or undefined) */ public getServiceViewNames(): string[] { + if ( this.serviceViews ) { + this.serviceViews = []; + } + return this.serviceViews; } diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index f1f022ce..d4c297f3 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -73,6 +73,11 @@ export class MockDataserviceService extends DataserviceService { * @returns {Observable} */ public createDataservice(dataservice: NewDataservice): Observable { + const ds = new Dataservice(); + ds.setId( dataservice.getId() ); + ds.setDescription( dataservice.getDescription() ); + + this.services.push( ds ); return Observable.of(true); } @@ -106,21 +111,6 @@ export class MockDataserviceService extends DataserviceService { return tables; } - // /** - // * Updates the current Dataservice states - triggers update to be broadcast to interested components - // */ - // public updateDataserviceStates(): void { - // // Nothing to do - // } - - // /** - // * Polls the server and sends Dataservice state updates at the specified interval - // * @param {number} pollIntervalSec the interval (sec) between polling attempts - // */ - // public pollDataserviceStatus(pollIntervalSec: number): void { - // // Nothing to do - // } - /** * Query a Dataservice via the komodo rest interface * @param {string} query the SQL query @@ -137,4 +127,41 @@ export class MockDataserviceService extends DataserviceService { return Observable.throw(error); } + public createReadonlyDataRole( dataserviceName: string, + model1Name: string ): Observable< boolean > { + return Observable.of( true ); + } + + public isValidName( name: string ): Observable { + if ( !name || name.length === 0 ) { + return Observable.of( "Dataservice name cannot be empty" ); + } + + // make sure no dataservice exists with that name + for ( const ds of this.services ) { + if ( ds.getId() === name ) { + return Observable.of( "Dataservice with that name already exists" ); + } + } + + // just implement a case where no special characters allowed + for ( let i = 0; i < name.length; i++ ) { + const c = name.charAt( i ); + + // special characters have the same upper and lower case values + if ( c.toUpperCase() === c.toLowerCase() ) { + return Observable.of( "No special characters allowed" ); + } + } + + // valid + return Observable.of( "" ); + } + + public setServiceVdbForSingleSourceTables( dataserviceName: string, + tablePaths: string[], + modelSourcePath: string ): Observable< boolean > { + return Observable.of( true ); + } + } diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index e53a0b7c..2559480a 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -160,7 +160,19 @@ export class MockVdbService extends VdbService { * @param {number} pollIntervalSec the interval (sec) between polling attempts */ public pollForActiveVdb(vdbName: string, pollDurationSec: number, pollIntervalSec: number): void { - return; + const pollIntervalMillis = pollIntervalSec * 1000; + const timer = Observable.timer(1000, pollIntervalMillis); + this.deploymentSubscription = timer.subscribe(( t: any ) => { + const vdbStatus = new VdbStatus(); + vdbStatus.setName( vdbName ); + vdbStatus.setActive( true ); + vdbStatus.setLoading( false ); + vdbStatus.setFailed( false ); + + this.notifierService.sendVdbDeploymentStatus( vdbStatus ); + this.deploymentSubscription.unsubscribe(); + } ); + } /** diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 8e84ede3..51464cdc 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -39,9 +39,9 @@ import { Subscription } from "rxjs/Subscription"; */ export class VdbService extends ApiService { + protected deploymentSubscription: Subscription; + protected notifierService: NotifierService; private http: Http; - private deploymentSubscription: Subscription; - private notifierService: NotifierService; constructor(http: Http, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { From e9ba93a80d6f25e5ef6242ec3a102057fe79d18d Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 20 Mar 2018 13:18:24 -0500 Subject: [PATCH 103/205] Now using TestDataService for dataservices. --- .../shared/mock-connection.service.ts | 2 +- .../dataservice-card.component.ts | 8 +- .../dataservices/shared/dataservice.model.ts | 4 +- .../shared/mock-dataservice.service.ts | 45 +-- .../dataservices/shared/mock-vdb.service.ts | 36 +- ngapp/src/app/shared/test-data.service.ts | 316 +++++++++++++++--- 6 files changed, 311 insertions(+), 100 deletions(-) diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index bce12830..40be1850 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -43,7 +43,7 @@ export class MockConnectionService extends ConnectionService { super(http, appSettings, logger); // Inject service for test data - let injector = ReflectiveInjector.resolveAndCreate([TestDataService]); + const injector = ReflectiveInjector.resolveAndCreate([TestDataService]); const testDataService = injector.get(TestDataService); // Get test data diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts index 0eb742cf..0d19023d 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts @@ -107,13 +107,7 @@ export class DataserviceCardComponent implements DoCheck, OnInit { * @returns {string[]} the names of the views */ public getViews(): string[] { - const result: string[] = []; - - for (const viewName of this.dataservice.getServiceViewNames()) { - result.push(viewName); - } - - return result; + return this.dataservice.getServiceViewNames(); } /** diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index a14a5be7..39981abc 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -116,10 +116,10 @@ export class Dataservice implements Identifiable< string > { */ public getServiceViewNames(): string[] { if ( this.serviceViews ) { - this.serviceViews = []; + return this.serviceViews; } - return this.serviceViews; + return []; } /** diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index d4c297f3..d1339972 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Injectable } from "@angular/core"; +import { Injectable, ReflectiveInjector } from "@angular/core"; import { Http, Response } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -25,6 +25,7 @@ import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { TestDataService } from "@shared/test-data.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; @@ -35,28 +36,18 @@ import { ErrorObservable } from "rxjs/observable/ErrorObservable"; @Injectable() export class MockDataserviceService extends DataserviceService { - private serv1 = new Dataservice(); - private serv2 = new Dataservice(); - private serv3 = new Dataservice(); - private services: Dataservice[] = [this.serv1, this.serv2, this.serv3]; + private services: Dataservice[]; constructor(http: Http, vdbService: VdbService, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { super(http, vdbService, appSettings, notifierService, logger); - this.serv1.setId("serv1"); - this.serv1.setServiceViewTables(["table1", "table2"]); - this.serv1.setServiceViewModel("viewModel"); - const viewNames: string[] = []; - viewNames.push("views"); - this.serv1.setServiceViewNames(viewNames); - this.serv2.setId("serv2"); - this.serv2.setServiceViewTables(["table1", "table2"]); - this.serv2.setServiceViewModel("viewModel"); - this.serv2.setServiceViewNames(viewNames); - this.serv3.setId("serv3"); - this.serv3.setServiceViewTables(["table1", "table2"]); - this.serv3.setServiceViewModel("viewModel"); - this.serv3.setServiceViewNames(viewNames); + + // Inject service for test data + const injector = ReflectiveInjector.resolveAndCreate([TestDataService]); + const testDataService = injector.get(TestDataService); + + // Get test data + this.services = testDataService.getDataservices(); } /** @@ -89,14 +80,14 @@ export class MockDataserviceService extends DataserviceService { public deleteDataservice(dataserviceId: string): Observable { return Observable.of(true); } - - /** - * Get the current Dataservice selection - * @returns {Dataservice} the selected Dataservice - */ - public getSelectedDataservice( ): Dataservice { - return this.serv1; - } + // + // /** + // * Get the current Dataservice selection + // * @returns {Dataservice} the selected Dataservice + // */ + // public getSelectedDataservice( ): Dataservice { + // return this.serv1; + // } /** * Get the views for the selected Dataservice diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index 2559480a..0c145d3e 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Injectable } from "@angular/core"; +import { Injectable, ReflectiveInjector } from "@angular/core"; import { Http } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -26,6 +26,7 @@ import { VdbModel } from "@dataservices/shared/vdb-model.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { Vdb } from "@dataservices/shared/vdb.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { TestDataService } from "@shared/test-data.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; @@ -35,32 +36,19 @@ import { Observable } from "rxjs/Observable"; @Injectable() export class MockVdbService extends VdbService { - private vdb1 = new Vdb(); - private vdb2 = new Vdb(); - private vdb3 = new Vdb(); - private vdbs: Vdb[] = [this.vdb1, this.vdb2, this.vdb3]; - - private vdbStatus1 = new VdbStatus(); - private vdbStatus2 = new VdbStatus(); - private vdbStatus3 = new VdbStatus(); - private statuses: VdbStatus[] = [this.vdbStatus1, this.vdbStatus3, this.vdbStatus3]; + private vdbs: Vdb[]; + private statuses: VdbStatus[]; constructor(http: Http, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { super(http, appSettings, notifierService, logger); - this.vdb1.setId("serv1"); - this.vdbStatus1.setName( "serv1" ); - this.vdbStatus1.setLoading( false ); - this.vdbStatus1.setActive( true ); - - this.vdb2.setId("serv2"); - this.vdbStatus2.setName("serv2"); - this.vdbStatus2.setLoading( false ); - this.vdbStatus2.setActive( true ); - - this.vdb3.setId("serv3"); - this.vdbStatus3.setName("serv2"); - this.vdbStatus3.setLoading( false ); - this.vdbStatus3.setActive( true ); + + // Inject service for test data + const injector = ReflectiveInjector.resolveAndCreate([TestDataService]); + const testDataService = injector.get(TestDataService); + + // Get test data + this.statuses = testDataService.getVdbStatuses(); + this.vdbs = testDataService.getVdbs(); } /** diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 8bfdc62a..b9e92aef 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -1,9 +1,28 @@ -import { Injectable } from '@angular/core'; -import {Connection} from "@connections/shared/connection.model"; -import {ServiceCatalogSource} from "@connections/shared/service-catalog-source.model"; -import {MockConnectionService} from "@connections/shared/mock-connection.service"; -import {Observable} from "rxjs/Observable"; -import {SchemaInfo} from "@connections/shared/schema-info.model"; +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { SchemaInfo } from "@connections/shared/schema-info.model"; +import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { VdbStatus } from "@dataservices/shared/vdb-status.model"; +import { Vdb } from "@dataservices/shared/vdb.model"; @Injectable() export class TestDataService { @@ -12,6 +31,88 @@ export class TestDataService { private static catalogSourceId2 = "postgresql-persistent-a8xrt"; private static catalogSourceId3 = "mysql-persistent-t3irv"; + // ================================================================= + // VDBs + // ================================================================= + + private static accountsVdb = Vdb.create( + { + keng__id: "AccountsVDB", + vdb__description: "This is an accounts VDB.", + keng__dataPath: "/path/in/repository/AccountsVDB", + keng__kType: "Vdb", + vdb__name: "AccountsVDB", + vdb__originalFile: "/Users/dsbUser/vdbs/accounts.vdb", + vdb__preview: false, + vdb__version: "1" + }, + ); + + private static accountsVdbStatus = VdbStatus.create( + { + name: TestDataService.accountsVdb.getName(), + deployedName: TestDataService.accountsVdb.getName() + "-vdb.xml", + version: TestDataService.accountsVdb.getVersion(), + active: true, + loading: false, + failed: false, + errors: [ + ] + } + ); + + private static employeesVdb = Vdb.create( + { + keng__id: "EmployeesVDB", + vdb__description: "This is an employees VDB.", + keng__dataPath: "/path/in/repository/EmployeesVDB", + keng__kType: "Vdb", + vdb__name: "EmployeesVDB", + vdb__originalFile: "/Users/dsbUser/vdbs/employees.vdb", + vdb__preview: false, + vdb__version: "1" + }, + ); + + private static employeesVdbStatus = VdbStatus.create( + { + name: TestDataService.employeesVdb.getName(), + deployedName: TestDataService.employeesVdb.getName() + "-vdb.xml", + version: TestDataService.employeesVdb.getVersion(), + active: true, + loading: false, + failed: false, + errors: [ + ] + } + ); + + private static productsVdb = Vdb.create( + { + keng__id: "ProductsVDB", + vdb__description: "This is a products VDB.", + keng__dataPath: "/path/in/repository/ProductsVDB", + keng__kType: "Vdb", + vdb__name: "ProductsVDB", + vdb__originalFile: "/Users/dsbUser/vdbs/products.vdb", + vdb__preview: false, + vdb__version: "1" + }, + ); + + private static productsVdbStatus = VdbStatus.create( + { + name: TestDataService.productsVdb.getName(), + deployedName: TestDataService.productsVdb.getName() + "-vdb.xml", + version: TestDataService.productsVdb.getVersion(), + active: true, + loading: false, + failed: false, + errors: [ + ] + } + ); + // ================================================================= // ServiceCatalog DataSources // ================================================================= @@ -31,10 +132,6 @@ export class TestDataService { "mysql", true ); - private catalogSources: ServiceCatalogSource[] = [TestDataService.catalogSource1, - TestDataService.catalogSource2, - TestDataService.catalogSource3]; - // ================================================================= // Connections // ================================================================= @@ -45,10 +142,6 @@ export class TestDataService { private static conn2 = TestDataService.createConnection(TestDataService.connId2, TestDataService.catalogSource2 ); private static conn3 = TestDataService.createConnection(TestDataService.connId3, TestDataService.catalogSource3 ); - private connections: Connection[] = [TestDataService.conn1, - TestDataService.conn2, - TestDataService.conn3]; - // ================================================================= // SchemaInfos for the connections // ================================================================= @@ -70,32 +163,127 @@ export class TestDataService { SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ) ]; - constructor() { } + // ================================================================= + // Dataservices + // ================================================================= - /** - * @returns {Connection[]} the array of test connections - */ - public getConnections(): Connection[] { - return this.connections; - } + private static accountsService = Dataservice.create( + { + keng__id: "Accounts", + tko__description: "A dataservice for accounts.", + serviceVdbName: TestDataService.accountsVdb.getName(), + serviceVdbVersion: TestDataService.accountsVdb.getVersion(), + serviceViews: [ + "AcctView1", + "AcctView2" + ], + serviceViewModel: "AccountsViewModel", + serviceViewTables: [ + "AcctView1Table1", + "AcctView1Table2", + "AcctView1Table3", + "AcctView2Table1" + ], + deploymentState: DeploymentState.LOADING + } + ); - /** - * @returns {ServiceCatalogSource[]} the array of test Service Catalog datasources - */ - public getServiceCatalogSources(): ServiceCatalogSource[] { - return this.catalogSources; - } + private static employeesService = Dataservice.create( + { + keng__id: "Employees", + tko__description: "A dataservice for employees.", + serviceVdbName: TestDataService.employeesVdb.getName(), + serviceVdbVersion: TestDataService.employeesVdb.getVersion(), + serviceViews: [ + "EmpView1", + "EmpView2", + "EmpView3", + "EmpView4" + ], + serviceViewModel: "EmployeesViewModel", + serviceViewTables: [ + "EmpView1Table1", + "EmpView2Table1", + "EmpView2Table2", + "EmpView3Table1", + "EmpView3Table2", + "EmpView3Table3", + "EmpView4Table1", + "EmpView4Table2", + "EmpView4Table3", + "EmpView4Table4" + ], + deploymentState: DeploymentState.LOADING + } + ); - /** - * @returns {Map} the array of test Service Catalog datasources - */ - public getConnectionSourceSchemaInfoMap( ): Map { - const infoMap = new Map(); - infoMap.set( TestDataService.conn1.getServiceCatalogSourceName(), TestDataService.conn1SchemaInfos ); - infoMap.set( TestDataService.conn2.getServiceCatalogSourceName(), TestDataService.conn2SchemaInfos ); - infoMap.set( TestDataService.conn3.getServiceCatalogSourceName(), TestDataService.conn3SchemaInfos ); - return infoMap; - } + private static productsService = Dataservice.create( + { + keng__id: "Products", + tko__description: "A dataservice for products. These are really good products. These products are the best products money can buy.", + serviceVdbName: TestDataService.productsVdb.getName(), + serviceVdbVersion: TestDataService.productsVdb.getVersion(), + serviceViews: [ + "ProdView1", + "ProdView2", + "ProdView3", + "ProdView4", + "ProdView5", + "ProdView6" + ], + serviceViewModel: "ProductsViewModel", + serviceViewTables: [ + "ProdView1Table1", + "ProdView2Table1", + "ProdView2Table2", + "ProdView3Table1", + "ProdView3Table2", + "ProdView3Table3", + "ProdView4Table1", + "ProdView4Table2", + "ProdView4Table3", + "ProdView4Table4", + "ProdView5Table1", + "ProdView5Table2", + "ProdView5Table3", + "ProdView5Table4", + "ProdView5Table5", + "ProdView6Table1", + "ProdView6Table2", + "ProdView6Table3", + "ProdView6Table4", + "ProdView6Table5", + "ProdView6Table6" + ], + deploymentState: DeploymentState.LOADING + } + ); + + private catalogSources: ServiceCatalogSource[] = [TestDataService.catalogSource1, + TestDataService.catalogSource2, + TestDataService.catalogSource3]; + + private connections: Connection[] = [TestDataService.conn1, + TestDataService.conn2, + TestDataService.conn3]; + + private dataServices: Dataservice[] = [ + TestDataService.accountsService, + TestDataService.employeesService, + TestDataService.productsService + ]; + + private vdbs: Vdb[] = [ + TestDataService.accountsVdb, + TestDataService.employeesVdb, + TestDataService.productsVdb + ]; + + private vdbStatuses: VdbStatus[] = [ + TestDataService.accountsVdbStatus, + TestDataService.employeesVdbStatus, + TestDataService.productsVdbStatus + ]; /** * Create a connection of the specified id using the supplied ServiceCatalogSource @@ -108,7 +296,7 @@ export class TestDataService { newConn.setId( id ); const driverName = serviceCatalogSource.getType(); newConn.setDriverName( driverName ); - if( driverName === 'mysql' || driverName === 'postgresql') { + if ( driverName === "mysql" || driverName === "postgresql") { newConn.setJdbc( true ); } else { newConn.setJdbc( false ); @@ -126,7 +314,7 @@ export class TestDataService { * @param {boolean} bound 'true' if bound * @returns {ServiceCatalogSource} */ - private static createServiceCatalogSource( id: string, name: string, type: string, bound: boolean ) { + private static createServiceCatalogSource( id: string, name: string, type: string, bound: boolean ): ServiceCatalogSource { const catalogSource = new ServiceCatalogSource(); catalogSource.setId(id); catalogSource.setName(name); @@ -135,4 +323,54 @@ export class TestDataService { return catalogSource; } + constructor() { + // nothing to do + } + + /** + * @returns {Connection[]} the array of test connections + */ + public getConnections(): Connection[] { + return this.connections; + } + + /** + * @returns {ServiceCatalogSource[]} the array of test Service Catalog datasources + */ + public getServiceCatalogSources(): ServiceCatalogSource[] { + return this.catalogSources; + } + + /** + * @returns {Map} the array of test Service Catalog datasources + */ + public getConnectionSourceSchemaInfoMap( ): Map { + const infoMap = new Map(); + infoMap.set( TestDataService.conn1.getServiceCatalogSourceName(), TestDataService.conn1SchemaInfos ); + infoMap.set( TestDataService.conn2.getServiceCatalogSourceName(), TestDataService.conn2SchemaInfos ); + infoMap.set( TestDataService.conn3.getServiceCatalogSourceName(), TestDataService.conn3SchemaInfos ); + return infoMap; + } + + /** + * @returns {Dataservice[]} the array of test dataservices + */ + public getDataservices(): Dataservice[] { + return this.dataServices; + } + + /** + * @returns {Vdb[]} the VDB collection + */ + public getVdbs(): Vdb[] { + return this.vdbs; + } + + /** + * @returns {VdbStatus[]} the VDB status collection + */ + public getVdbStatuses(): VdbStatus[] { + return this.vdbStatuses; + } + } From 65658655dd0052f235a9b93f9d19eeb05a3a46e8 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Fri, 16 Mar 2018 15:28:07 -0500 Subject: [PATCH 104/205] Initial commit --- .../src/app/connections/connections.module.ts | 26 +++++- ngapp/src/app/core/core.module.ts | 24 +++++- .../app/dataservices/dataservices.module.ts | 86 ++++++++++++++++++- .../shared/mock-dataservice.service.ts | 26 +++--- .../shared/mock-notifier.service.ts | 11 +++ .../dataservices/shared/mock-vdb.service.ts | 12 +++ ngapp/src/environments/environment.ts | 5 +- 7 files changed, 170 insertions(+), 20 deletions(-) create mode 100644 ngapp/src/app/dataservices/shared/mock-notifier.service.ts diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 771334ab..6d850ee0 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -34,6 +34,10 @@ import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { ConnectionTypeCardComponent } from "./connection-type-cards/connection-type-card/connection-type-card.component"; import { ConnectionTypeCardsComponent } from "./connection-type-cards/connection-type-cards.component"; +import { AppSettingsService } from "@core/app-settings.service"; +import { Http } from "@angular/http"; +import { environment } from "@environments/environment"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; @NgModule({ imports: [ @@ -59,10 +63,30 @@ import { ConnectionTypeCardsComponent } from "./connection-type-cards/connection ConnectionTypeCardComponent ], providers: [ - ConnectionService, + { + provide: ConnectionService, + useFactory: connectionServiceFactory, + deps: [ Http, AppSettingsService, LoggerService ], + multi: false + }, LoggerService ], exports: [ ] }) export class ConnectionsModule { } + +/** + * A factory that produces the appropriate instande of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {AppSettingsService} appSettings the app settings service + * @param {LoggerService} logger the logger + * @returns {ConnectionService} the requested service + */ +export function connectionServiceFactory( http: Http, + appSettings: AppSettingsService, + logger: LoggerService ): ConnectionService { + return environment.production || !environment.uiDevMode ? new ConnectionService( http, appSettings, logger ) + : new MockConnectionService( http, appSettings, logger ); +} diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 7ab84f9e..3399eae1 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -17,7 +17,7 @@ import { CommonModule } from "@angular/common"; import { NgModule, Optional, SkipSelf } from "@angular/core"; -import { HttpModule } from "@angular/http"; +import { Http, HttpModule } from "@angular/http"; import { RouterModule } from "@angular/router"; import { AboutDialogComponent } from "@core/about-dialog/about-dialog.component"; import { AboutService } from "@core/about-dialog/about.service"; @@ -25,7 +25,9 @@ import { AppSettingsService } from "@core/app-settings.service"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { VerticalNavComponent } from "@core/vertical-nav/vertical-nav.component"; +import { environment } from "@environments/environment"; import { ModalModule } from "ngx-bootstrap/modal"; import { BsModalService } from "ngx-bootstrap/modal"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -51,7 +53,12 @@ import { PatternFlyNgModule } from "patternfly-ng"; ], providers: [ AboutService, - AppSettingsService, + { + provide: AppSettingsService, + useFactory: appSettingsServiceFactory, + deps: [ Http, LoggerService ], + multi: false + }, LoggerService, BsModalService ] @@ -65,3 +72,16 @@ export class CoreModule { } } + +/** + * A factory that produces the appropriate instande of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {LoggerService} logger the logger + * @returns {AppSettingsService} the requested service + */ +export function appSettingsServiceFactory( http: Http, + logger: LoggerService ): AppSettingsService { + return environment.production || !environment.uiDevMode ? new AppSettingsService( http, logger ) + : new MockAppSettingsService( http, logger ); +} diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 975f3430..ad71ea21 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -18,7 +18,9 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { Http } from "@angular/http"; import { RouterModule } from "@angular/router"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { LoggerService } from "@core/logger.service"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; @@ -28,9 +30,13 @@ import { ViewsContentComponent } from "@dataservices/dataservices-list/views-con import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.module"; import { DataservicesComponent } from "@dataservices/dataservices.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { MockNotifierService } from "@dataservices/shared/mock-notifier.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; +import { environment } from "@environments/environment"; import { SharedModule } from "@shared/shared.module"; import { CodemirrorModule } from "ng2-codemirror"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -71,13 +77,87 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co DataserviceCardComponent ], providers: [ - DataserviceService, - VdbService, + { + provide: DataserviceService, + useFactory: dataserviceServiceFactory, + deps: [ Http, VdbService, AppSettingsService, NotifierService, LoggerService ], + multi: false + }, + { + provide: NotifierService, + useFactory: notifierServiceFactory, + multi: false + }, + { + provide: VdbService, + useFactory: vdbServiceFactory, + deps: [ Http, AppSettingsService, NotifierService, LoggerService ], + multi: false + }, LoggerService, - NotifierService, WizardService ], exports: [ ] }) export class DataservicesModule { } + +/** + * A factory that produces the appropriate instance of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {VdbService} vdbService the VDB service + * @param {AppSettingsService} appSettings the app settings service + * @param {NotifierService} notifierService the notifier service + * @param {LoggerService} logger the logger + * @returns {DataserviceService} the requested service + */ +export function dataserviceServiceFactory( http: Http, + vdbService: VdbService, + appSettings: AppSettingsService, + notifierService: NotifierService, + logger: LoggerService ): DataserviceService { + return environment.production || !environment.uiDevMode ? new DataserviceService( http, + vdbService, + appSettings, + notifierService, + logger ) + : new MockDataserviceService( http, + vdbService, + appSettings, + notifierService, + logger ); +} + +/** + * A factory that produces the appropriate instance of the service based on current environment settings. + * + * @returns {NotifierService} the requested service + */ +export function notifierServiceFactory(): NotifierService { + return environment.production || !environment.uiDevMode ? new NotifierService() + : new MockNotifierService(); +} + +/** + * A factory that produces the appropriate instance of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {AppSettingsService} appSettings the app settings service + * @param {NotifierService} notifierService the notifier service + * @param {LoggerService} logger the logger + * @returns {VdbService} the requested service + */ +export function vdbServiceFactory( http: Http, + appSettings: AppSettingsService, + notifierService: NotifierService, + logger: LoggerService ): VdbService { + return environment.production || !environment.uiDevMode ? new VdbService( http, + appSettings, + notifierService, + logger ) + : new MockVdbService( http, + appSettings, + notifierService, + logger ); +} diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 918921bf..f1f022ce 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -106,20 +106,20 @@ export class MockDataserviceService extends DataserviceService { return tables; } - /** - * Updates the current Dataservice states - triggers update to be broadcast to interested components - */ - public updateDataserviceStates(): void { - // Nothing to do - } + // /** + // * Updates the current Dataservice states - triggers update to be broadcast to interested components + // */ + // public updateDataserviceStates(): void { + // // Nothing to do + // } - /** - * Polls the server and sends Dataservice state updates at the specified interval - * @param {number} pollIntervalSec the interval (sec) between polling attempts - */ - public pollDataserviceStatus(pollIntervalSec: number): void { - // Nothing to do - } + // /** + // * Polls the server and sends Dataservice state updates at the specified interval + // * @param {number} pollIntervalSec the interval (sec) between polling attempts + // */ + // public pollDataserviceStatus(pollIntervalSec: number): void { + // // Nothing to do + // } /** * Query a Dataservice via the komodo rest interface diff --git a/ngapp/src/app/dataservices/shared/mock-notifier.service.ts b/ngapp/src/app/dataservices/shared/mock-notifier.service.ts new file mode 100644 index 00000000..339d0f37 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/mock-notifier.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from "@angular/core"; +import { NotifierService } from "@dataservices/shared/notifier.service"; + +@Injectable() +export class MockNotifierService extends NotifierService { + + constructor() { + super(); + } + +} diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index c5b5cc6a..e53a0b7c 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -48,8 +48,19 @@ export class MockVdbService extends VdbService { constructor(http: Http, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { super(http, appSettings, notifierService, logger); this.vdb1.setId("serv1"); + this.vdbStatus1.setName( "serv1" ); + this.vdbStatus1.setLoading( false ); + this.vdbStatus1.setActive( true ); + this.vdb2.setId("serv2"); + this.vdbStatus2.setName("serv2"); + this.vdbStatus2.setLoading( false ); + this.vdbStatus2.setActive( true ); + this.vdb3.setId("serv3"); + this.vdbStatus3.setName("serv2"); + this.vdbStatus3.setLoading( false ); + this.vdbStatus3.setActive( true ); } /** @@ -65,6 +76,7 @@ export class MockVdbService extends VdbService { * @returns {Observable} */ public getTeiidVdbStatuses(): Observable { + super.getTeiidVdbStatuses(); return Observable.of(this.statuses); } diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index dea1a9bf..7cd88872 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -56,6 +56,9 @@ export const environment = { komodoTeiidUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/metadata", // REST URL - Komodo service - komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service" + komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service", + + // Indicates if in UI development mode where OpenShift will not be used. + uiDevMode: true }; From bea404d25fd794fe179daa3ad851caefe658956f Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 20 Mar 2018 08:30:51 -0500 Subject: [PATCH 105/205] ui dev mode changes --- .../add-connection-wizard.component.ts | 8 - .../shared/mock-connection.service.ts | 155 ++++++++++-------- ngapp/src/app/core/core.module.ts | 22 +++ .../add-dataservice-wizard.component.ts | 7 - .../connection-table-selector.component.ts | 2 +- .../jdbc-table-selector.component.spec.ts | 56 +++---- ngapp/src/app/shared/shared.module.ts | 6 +- .../src/app/shared/test-data.service.spec.ts | 15 ++ ngapp/src/app/shared/test-data.service.ts | 138 ++++++++++++++++ ngapp/src/environments/environment.prod.ts | 5 +- 10 files changed, 296 insertions(+), 118 deletions(-) create mode 100644 ngapp/src/app/shared/test-data.service.spec.ts create mode 100644 ngapp/src/app/shared/test-data.service.ts diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index 9256c393..d44d3f3e 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -155,8 +155,6 @@ export class AddConnectionWizardComponent implements OnInit { } } } - - this.setNavAway(false); } // ---------------- @@ -488,16 +486,11 @@ export class AddConnectionWizardComponent implements OnInit { ); } - private setNavAway(allow: boolean): void { - this.step1Config.allowNavAway = allow; - } - /** * Updates the page 1 status */ private updatePage1ValidStatus( ): void { this.step1Config.nextEnabled = this.selectedConnTypes.length > 0; - this.setNavAway(this.step1Config.nextEnabled); } /** @@ -512,7 +505,6 @@ export class AddConnectionWizardComponent implements OnInit { } else { this.step2aConfig.nextEnabled = this.nameValid && this.hasSelectedServiceCatalogSource; } - this.setNavAway(this.step2aConfig.nextEnabled); } /** diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index f494e0e1..bce12830 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -15,13 +15,12 @@ * limitations under the License. */ -import { Injectable } from "@angular/core"; +import { Injectable, ReflectiveInjector } from "@angular/core"; import { Http } from "@angular/http"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; -import { TemplateDefinition } from "@connections/shared/template-definition.model"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import "rxjs/add/observable/of"; @@ -29,61 +28,54 @@ import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; +import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; +import { NewConnection } from "@connections/shared/new-connection.model"; +import { TestDataService } from "@shared/test-data.service"; @Injectable() export class MockConnectionService extends ConnectionService { - public static conn1Id = "conn1"; - public static conn1 = MockConnectionService.createJdbcConnection( MockConnectionService.conn1Id ); - public static conn1SchemaInfos = [ - SchemaInfo.create( { name: "conn1SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn1CatalogInfo", type: "Catalog", schemaNames: [ "conn1CatalogSchema1", "conn1CatalogSchema1" ] } ) - ]; - public static numConn1Schemas = 3; - - public static conn2Id = "conn2"; - public static conn2 = MockConnectionService.createJdbcConnection( MockConnectionService.conn2Id ); - public static conn2SchemaInfos = [ - SchemaInfo.create( { name: "conn2CatalogInfo", type: "Catalog", schemaNames: [ "conn2CatalogSchema1", "conn2CatalogSchema1" ] } ), - SchemaInfo.create( { name: "conn2SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn2SchemaInfo2", type: "Schema" } ) - ]; - public static numConn2Schemas = 4; - - public static conn3Id = "conn3"; - public static conn3 = MockConnectionService.createJdbcConnection( MockConnectionService.conn3Id ); - public static conn3SchemaInfos = [ - SchemaInfo.create( { name: "conn3CatalogInfo", type: "Catalog", schemaNames: [ "conn3CatalogSchema1", "conn3CatalogSchema1" ] } ), - SchemaInfo.create( { name: "conn3SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ), - SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ) - ]; - public static numConn3Schemas = 5; - - public static templ1 = new TemplateDefinition(); - public static templ2 = new TemplateDefinition(); - public static templ3 = new TemplateDefinition(); - - public conns: Connection[] = [ - MockConnectionService.conn1, - MockConnectionService.conn2, - MockConnectionService.conn3 ]; - - public templs: TemplateDefinition[] = [ - MockConnectionService.templ1, - MockConnectionService.templ2, - MockConnectionService.templ3 ]; - - private static createJdbcConnection( id: string ): Connection { - const newConn = new Connection(); - newConn.setId( id ); - newConn.setJdbc( true ); - newConn.setServiceCatalogSourceName(id); - return newConn; - } + private connections: Connection[]; + private serviceCatalogSources: ServiceCatalogSource[]; + private connectionSourceSchemaInfoMap: Map; constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { super(http, appSettings, logger); + + // Inject service for test data + let injector = ReflectiveInjector.resolveAndCreate([TestDataService]); + const testDataService = injector.get(TestDataService); + + // Get test data + this.connections = testDataService.getConnections(); + this.serviceCatalogSources = testDataService.getServiceCatalogSources(); + this.connectionSourceSchemaInfoMap = testDataService.getConnectionSourceSchemaInfoMap(); + } + + public isValidName( name: string ): Observable< string > { + if ( !name || name.length === 0 ) { + return Observable.of( "Connection name cannot be empty" ); + } + + // make sure no dataservice exists with that name + for ( const conn of this.connections ) { + if ( conn.getId() === name ) { + return Observable.of( "Connection with that name already exists" ); + } + } + + // just implement a case where no special characters allowed + for ( let i = 0; i < name.length; i++ ) { + const c = name.charAt( i ); + + // special characters have the same upper and lower case values + if ( c.toUpperCase() === c.toLowerCase() ) { + return Observable.of( "No special characters allowed" ); + } + } + + // valid + return Observable.of( "" ); } /** @@ -91,7 +83,7 @@ export class MockConnectionService extends ConnectionService { * @returns {Observable} */ public getAllConnections(): Observable { - return Observable.of(this.conns); + return Observable.of(this.connections); } /** @@ -100,36 +92,37 @@ export class MockConnectionService extends ConnectionService { * @returns {Observable} */ public deleteConnection(connectionId: string): Observable { - const size = this.conns.length; - this.conns = this.conns.filter( ( conn ) => conn.getId() !== connectionId ); - return Observable.of( size === this.conns.length ); + const size = this.connections.length; + this.connections = this.connections.filter( ( conn ) => conn.getId() !== connectionId ); + return Observable.of( size === this.connections.length ); } /** - * Get the connection templates from the komodo rest interface - * @returns {Observable>>} + * Get the available ServiceCatalogSources from the komodo rest interface + * @returns {Observable} */ - public getConnectionTemplates(): Observable { - return Observable.of(this.templs); + public getAllServiceCatalogSources(): Observable { + return Observable.of(this.serviceCatalogSources); } - public getConnectionSchemaInfos( connectionId: string): Observable< SchemaInfo[] > { - if ( connectionId === MockConnectionService.conn1Id ) { - return Observable.of( MockConnectionService.conn1SchemaInfos ); - } - - if ( connectionId === MockConnectionService.conn2Id ) { - return Observable.of( MockConnectionService.conn2SchemaInfos ); - } - - if ( connectionId === MockConnectionService.conn3Id ) { - return Observable.of( MockConnectionService.conn3SchemaInfos ); + /** + * Get the connection schema info for a connection source + * @returns {Observable} + */ + public getConnectionSchemaInfos( connSource: string): Observable< SchemaInfo[] > { + const schemaInfos: SchemaInfo[] = this.connectionSourceSchemaInfoMap.get(connSource); + if( !schemaInfos || schemaInfos == null ) { + const empty: SchemaInfo[] = []; + return Observable.of( empty ); } - - const empty: SchemaInfo[] = []; - return Observable.of( empty ); + return Observable.of(schemaInfos); } + /** + * Get the tables for the specified input (connection and filters) for a Jdbc Connection + * @param {JdbcTableFilter} tableFilter + * @returns {Observable} + */ public getJdbcConnectionTables( tableFilter: JdbcTableFilter ): Observable< string[] > { const tableNames = []; tableNames.push( "table1" ); @@ -138,4 +131,22 @@ export class MockConnectionService extends ConnectionService { return Observable.of( tableNames ); } + /** + * Create a connection in the Komodo repo - also binds the specified serviceCatalogSource + * @param {NewConnection} connection the connection object + * @returns {Observable} + */ + public createAndBindConnection(connection: NewConnection): Observable { + return Observable.of(true); + } + + /** + * Update a connection in the Komodo repo - also binds the specified serviceCatalogSource. + * @param {NewConnection} connection the connection object + * @returns {Observable} + */ + public updateAndBindConnection(connection: NewConnection): Observable { + return Observable.of(true); + } + } diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index 3399eae1..f3d2ab2b 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -31,6 +31,7 @@ import { environment } from "@environments/environment"; import { ModalModule } from "ngx-bootstrap/modal"; import { BsModalService } from "ngx-bootstrap/modal"; import { PatternFlyNgModule } from "patternfly-ng"; +import { MockAboutService } from "@core/about-dialog/mock-about.service"; @NgModule({ imports: [ @@ -59,6 +60,12 @@ import { PatternFlyNgModule } from "patternfly-ng"; deps: [ Http, LoggerService ], multi: false }, + { + provide: AboutService, + useFactory: aboutServiceFactory, + deps: [ Http, AppSettingsService, LoggerService], + multi: false + }, LoggerService, BsModalService ] @@ -85,3 +92,18 @@ export function appSettingsServiceFactory( http: Http, return environment.production || !environment.uiDevMode ? new AppSettingsService( http, logger ) : new MockAppSettingsService( http, logger ); } + +/** + * A factory that produces the appropriate instance of the service based on current environment settings. + * + * @param {Http} http the HTTP service + * @param {AppSettingsService} appSettings the app settings + * @param {LoggerService} logger the logger + * @returns {AboutService} the requested service + */ +export function aboutServiceFactory( http: Http, + appSettings: AppSettingsService, + logger: LoggerService ): AboutService { + return environment.production || !environment.uiDevMode ? new AboutService( http, appSettings, logger ) + : new MockAboutService( http, appSettings, logger ); +} diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index da7fdafd..da0251c1 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -164,7 +164,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.basicPropertyForm.controls["name"].setValue(null); this.basicPropertyForm.controls["description"].setValue(null); } - this.setNavAway(false); } public ngOnDestroy(): void { @@ -440,7 +439,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { */ public updatePage1ValidStatus( ): void { this.step1Config.nextEnabled = this.tableSelector.valid(); - this.setNavAway(this.step1Config.nextEnabled); } /** @@ -475,10 +473,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } } - private setNavAway(allow: boolean): void { - this.step1Config.allowNavAway = allow; - } - private updatePage2aValidStatus( ): void { if (!this.step2aConfig) { return; @@ -488,7 +482,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } else { this.step2aConfig.nextEnabled = this.nameValid && this.hasSelectedConnection(); } - this.setNavAway(this.step2aConfig.nextEnabled); } /* diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index 8f577cca..da1b42dc 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -157,7 +157,7 @@ export class ConnectionTableSelectorComponent implements OnInit { // only set if schema selection has changed (see setter) if ( this.selectedConn == null || this.selectedConn.name !== conn.name ) { - this.selectedConn = conn; + this.selectedConnection = conn; } } diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts index 5e61522e..57ae6f51 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.spec.ts @@ -46,33 +46,33 @@ describe("JdbcTableSelectorComponent", () => { expect(component).toBeTruthy(); }); - it("should have correct number of schemas", () => { - console.log("========== [JdbcTableSelectorComponent] should have correct number of schemas"); - component.connection = MockConnectionService.conn2; - component.ngOnInit(); - component.setConnection( MockConnectionService.conn1 ); - expect( component.getSchemas().length ).toBe( MockConnectionService.numConn1Schemas ); - }); - - it( "should clear schemas", () => { - console.log("========== [JdbcTableSelectorComponent] should clear schemas"); - component.connection = MockConnectionService.conn3; - component.ngOnInit(); - expect( component.getSchemas().length ).toBe( MockConnectionService.numConn3Schemas ); - - component.clearSchemas(); - expect( component.getSchemas().length ).toBe( 0 ); - }); - - it( "should select schema", () => { - console.log("========== [JdbcTableSelectorComponent] should select schema"); - component.connection = MockConnectionService.conn1; - component.ngOnInit(); - expect( component.selectedSchema ).toBeNull(); - expect( component.hasSelectedSchema ).toBeFalsy(); - - component.selectedSchema = component.getSchemas()[ 0 ]; - expect( component.hasSelectedSchema ).toBeTruthy(); - }); + // it("should have correct number of schemas", () => { + // console.log("========== [JdbcTableSelectorComponent] should have correct number of schemas"); + // component.connection = MockConnectionService.conn2; + // component.ngOnInit(); + // component.setConnection( MockConnectionService.conn1 ); + // expect( component.getSchemas().length ).toBe( MockConnectionService.numConn1Schemas ); + // }); + // + // it( "should clear schemas", () => { + // console.log("========== [JdbcTableSelectorComponent] should clear schemas"); + // component.connection = MockConnectionService.conn3; + // component.ngOnInit(); + // expect( component.getSchemas().length ).toBe( MockConnectionService.numConn3Schemas ); + // + // component.clearSchemas(); + // expect( component.getSchemas().length ).toBe( 0 ); + // }); + // + // it( "should select schema", () => { + // console.log("========== [JdbcTableSelectorComponent] should select schema"); + // component.connection = MockConnectionService.conn1; + // component.ngOnInit(); + // expect( component.selectedSchema ).toBeNull(); + // expect( component.hasSelectedSchema ).toBeFalsy(); + // + // component.selectedSchema = component.getSchemas()[ 0 ]; + // expect( component.hasSelectedSchema ).toBeTruthy(); + // }); }); diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index b9d82c4f..622b9841 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -25,6 +25,7 @@ import { ModalModule } from "ngx-bootstrap"; import { PageNotFoundComponent } from "./page-not-found/page-not-found.component"; import { PropertyFormPropertyComponent } from "./property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "./property-form/property-form.component"; +import { TestDataService } from "@shared/test-data.service"; @NgModule({ imports: [ @@ -45,7 +46,10 @@ import { PropertyFormComponent } from "./property-form/property-form.component"; PageNotFoundComponent, PropertyFormComponent, PropertyFormPropertyComponent - ] + ], + providers: [ + TestDataService + ], }) export class SharedModule { } diff --git a/ngapp/src/app/shared/test-data.service.spec.ts b/ngapp/src/app/shared/test-data.service.spec.ts new file mode 100644 index 00000000..ee087eea --- /dev/null +++ b/ngapp/src/app/shared/test-data.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { TestDataService } from './test-data.service'; + +describe('TestDataService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [TestDataService] + }); + }); + + it('should be created', inject([TestDataService], (service: TestDataService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts new file mode 100644 index 00000000..8bfdc62a --- /dev/null +++ b/ngapp/src/app/shared/test-data.service.ts @@ -0,0 +1,138 @@ +import { Injectable } from '@angular/core'; +import {Connection} from "@connections/shared/connection.model"; +import {ServiceCatalogSource} from "@connections/shared/service-catalog-source.model"; +import {MockConnectionService} from "@connections/shared/mock-connection.service"; +import {Observable} from "rxjs/Observable"; +import {SchemaInfo} from "@connections/shared/schema-info.model"; + +@Injectable() +export class TestDataService { + + private static catalogSourceId1 = "postgresql-persistent-j9vqv"; + private static catalogSourceId2 = "postgresql-persistent-a8xrt"; + private static catalogSourceId3 = "mysql-persistent-t3irv"; + + // ================================================================= + // ServiceCatalog DataSources + // ================================================================= + private static catalogSource1 = TestDataService.createServiceCatalogSource( + TestDataService.catalogSourceId1, + TestDataService.catalogSourceId1, + "postgresql", + true ); + private static catalogSource2 = TestDataService.createServiceCatalogSource( + TestDataService.catalogSourceId2, + TestDataService.catalogSourceId2, + "postgresql", + true ); + private static catalogSource3 = TestDataService.createServiceCatalogSource( + TestDataService.catalogSourceId3, + TestDataService.catalogSourceId3, + "mysql", + true ); + + private catalogSources: ServiceCatalogSource[] = [TestDataService.catalogSource1, + TestDataService.catalogSource2, + TestDataService.catalogSource3]; + + // ================================================================= + // Connections + // ================================================================= + private static connId1 = "conn1"; + private static connId2 = "conn2"; + private static connId3 = "conn3"; + private static conn1 = TestDataService.createConnection(TestDataService.connId1, TestDataService.catalogSource1 ); + private static conn2 = TestDataService.createConnection(TestDataService.connId2, TestDataService.catalogSource2 ); + private static conn3 = TestDataService.createConnection(TestDataService.connId3, TestDataService.catalogSource3 ); + + private connections: Connection[] = [TestDataService.conn1, + TestDataService.conn2, + TestDataService.conn3]; + + // ================================================================= + // SchemaInfos for the connections + // ================================================================= + private static conn1SchemaInfos = [ + SchemaInfo.create( { name: "conn1SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn1CatalogInfo", type: "Catalog", schemaNames: [ "conn1CatalogSchema1", "conn1CatalogSchema1" ] } ) + ]; + + private static conn2SchemaInfos = [ + SchemaInfo.create( { name: "conn2CatalogInfo", type: "Catalog", schemaNames: [ "conn2CatalogSchema1", "conn2CatalogSchema1" ] } ), + SchemaInfo.create( { name: "conn2SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn2SchemaInfo2", type: "Schema" } ) + ]; + + private static conn3SchemaInfos = [ + SchemaInfo.create( { name: "conn3CatalogInfo", type: "Catalog", schemaNames: [ "conn3CatalogSchema1", "conn3CatalogSchema1" ] } ), + SchemaInfo.create( { name: "conn3SchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ), + SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ) + ]; + + constructor() { } + + /** + * @returns {Connection[]} the array of test connections + */ + public getConnections(): Connection[] { + return this.connections; + } + + /** + * @returns {ServiceCatalogSource[]} the array of test Service Catalog datasources + */ + public getServiceCatalogSources(): ServiceCatalogSource[] { + return this.catalogSources; + } + + /** + * @returns {Map} the array of test Service Catalog datasources + */ + public getConnectionSourceSchemaInfoMap( ): Map { + const infoMap = new Map(); + infoMap.set( TestDataService.conn1.getServiceCatalogSourceName(), TestDataService.conn1SchemaInfos ); + infoMap.set( TestDataService.conn2.getServiceCatalogSourceName(), TestDataService.conn2SchemaInfos ); + infoMap.set( TestDataService.conn3.getServiceCatalogSourceName(), TestDataService.conn3SchemaInfos ); + return infoMap; + } + + /** + * Create a connection of the specified id using the supplied ServiceCatalogSource + * @param {string} id + * @param {ServiceCatalogSource} serviceCatalogSource + * @returns {Connection} + */ + private static createConnection( id: string, serviceCatalogSource: ServiceCatalogSource ): Connection { + const newConn = new Connection(); + newConn.setId( id ); + const driverName = serviceCatalogSource.getType(); + newConn.setDriverName( driverName ); + if( driverName === 'mysql' || driverName === 'postgresql') { + newConn.setJdbc( true ); + } else { + newConn.setJdbc( false ); + } + newConn.setServiceCatalogSourceName(serviceCatalogSource.getName()); + newConn.setJndiName("java:/" + serviceCatalogSource.getName()); + return newConn; + } + + /** + * Create a ServiceCatalogSource using the specified info + * @param {string} id the id + * @param {string} name the name + * @param {string} type the type + * @param {boolean} bound 'true' if bound + * @returns {ServiceCatalogSource} + */ + private static createServiceCatalogSource( id: string, name: string, type: string, bound: boolean ) { + const catalogSource = new ServiceCatalogSource(); + catalogSource.setId(id); + catalogSource.setName(name); + catalogSource.setType(type); + catalogSource.setBound(bound); + return catalogSource; + } + +} diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts index 73c26c4f..b699a448 100644 --- a/ngapp/src/environments/environment.prod.ts +++ b/ngapp/src/environments/environment.prod.ts @@ -53,6 +53,9 @@ export const environment = { komodoTeiidUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/metadata", // REST URL - Komodo service - komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service" + komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service", + + // Indicates if in UI development mode where OpenShift will not be used. + uiDevMode: false }; From a104a6f85cdbaa0f6e4dde89f8b202a77645115f Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 20 Mar 2018 10:09:28 -0500 Subject: [PATCH 106/205] Work on getting dataservice wizard working with local UI dev mode. --- .../jdbc-table-selector.component.ts | 1 - .../dataservices/shared/dataservice.model.ts | 6 +- .../shared/mock-dataservice.service.ts | 57 ++++++++++++++----- .../dataservices/shared/mock-vdb.service.ts | 14 ++++- .../app/dataservices/shared/vdb.service.ts | 4 +- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts index 97ea9186..5de510e7 100644 --- a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts +++ b/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.ts @@ -460,7 +460,6 @@ export class JdbcTableSelectorComponent implements OnInit, TableSelector { * Handler for changes in table selection */ public selectedTableChanged( $event: TableEvent ): void { - console.error( $event ); const table: Table = $event.row; if ( table ) { diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 2462daf4..a14a5be7 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -112,9 +112,13 @@ export class Dataservice implements Identifiable< string > { } /** - * @returns {string[]} the dataservice view names (can be null) + * @returns {string[]} the dataservice view names (never null or undefined) */ public getServiceViewNames(): string[] { + if ( this.serviceViews ) { + this.serviceViews = []; + } + return this.serviceViews; } diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index f1f022ce..d4c297f3 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -73,6 +73,11 @@ export class MockDataserviceService extends DataserviceService { * @returns {Observable} */ public createDataservice(dataservice: NewDataservice): Observable { + const ds = new Dataservice(); + ds.setId( dataservice.getId() ); + ds.setDescription( dataservice.getDescription() ); + + this.services.push( ds ); return Observable.of(true); } @@ -106,21 +111,6 @@ export class MockDataserviceService extends DataserviceService { return tables; } - // /** - // * Updates the current Dataservice states - triggers update to be broadcast to interested components - // */ - // public updateDataserviceStates(): void { - // // Nothing to do - // } - - // /** - // * Polls the server and sends Dataservice state updates at the specified interval - // * @param {number} pollIntervalSec the interval (sec) between polling attempts - // */ - // public pollDataserviceStatus(pollIntervalSec: number): void { - // // Nothing to do - // } - /** * Query a Dataservice via the komodo rest interface * @param {string} query the SQL query @@ -137,4 +127,41 @@ export class MockDataserviceService extends DataserviceService { return Observable.throw(error); } + public createReadonlyDataRole( dataserviceName: string, + model1Name: string ): Observable< boolean > { + return Observable.of( true ); + } + + public isValidName( name: string ): Observable { + if ( !name || name.length === 0 ) { + return Observable.of( "Dataservice name cannot be empty" ); + } + + // make sure no dataservice exists with that name + for ( const ds of this.services ) { + if ( ds.getId() === name ) { + return Observable.of( "Dataservice with that name already exists" ); + } + } + + // just implement a case where no special characters allowed + for ( let i = 0; i < name.length; i++ ) { + const c = name.charAt( i ); + + // special characters have the same upper and lower case values + if ( c.toUpperCase() === c.toLowerCase() ) { + return Observable.of( "No special characters allowed" ); + } + } + + // valid + return Observable.of( "" ); + } + + public setServiceVdbForSingleSourceTables( dataserviceName: string, + tablePaths: string[], + modelSourcePath: string ): Observable< boolean > { + return Observable.of( true ); + } + } diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index e53a0b7c..2559480a 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -160,7 +160,19 @@ export class MockVdbService extends VdbService { * @param {number} pollIntervalSec the interval (sec) between polling attempts */ public pollForActiveVdb(vdbName: string, pollDurationSec: number, pollIntervalSec: number): void { - return; + const pollIntervalMillis = pollIntervalSec * 1000; + const timer = Observable.timer(1000, pollIntervalMillis); + this.deploymentSubscription = timer.subscribe(( t: any ) => { + const vdbStatus = new VdbStatus(); + vdbStatus.setName( vdbName ); + vdbStatus.setActive( true ); + vdbStatus.setLoading( false ); + vdbStatus.setFailed( false ); + + this.notifierService.sendVdbDeploymentStatus( vdbStatus ); + this.deploymentSubscription.unsubscribe(); + } ); + } /** diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 8e84ede3..51464cdc 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -39,9 +39,9 @@ import { Subscription } from "rxjs/Subscription"; */ export class VdbService extends ApiService { + protected deploymentSubscription: Subscription; + protected notifierService: NotifierService; private http: Http; - private deploymentSubscription: Subscription; - private notifierService: NotifierService; constructor(http: Http, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { From 2fa5ba3a48ff049d15b347c53b59371602e23c31 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Tue, 20 Mar 2018 13:18:24 -0500 Subject: [PATCH 107/205] Now using TestDataService for dataservices. --- .../shared/mock-connection.service.ts | 2 +- .../dataservice-card.component.ts | 8 +- .../dataservices/shared/dataservice.model.ts | 4 +- .../shared/mock-dataservice.service.ts | 45 +-- .../dataservices/shared/mock-vdb.service.ts | 36 +- ngapp/src/app/shared/test-data.service.ts | 316 +++++++++++++++--- 6 files changed, 311 insertions(+), 100 deletions(-) diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index bce12830..40be1850 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -43,7 +43,7 @@ export class MockConnectionService extends ConnectionService { super(http, appSettings, logger); // Inject service for test data - let injector = ReflectiveInjector.resolveAndCreate([TestDataService]); + const injector = ReflectiveInjector.resolveAndCreate([TestDataService]); const testDataService = injector.get(TestDataService); // Get test data diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts index 0eb742cf..0d19023d 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts @@ -107,13 +107,7 @@ export class DataserviceCardComponent implements DoCheck, OnInit { * @returns {string[]} the names of the views */ public getViews(): string[] { - const result: string[] = []; - - for (const viewName of this.dataservice.getServiceViewNames()) { - result.push(viewName); - } - - return result; + return this.dataservice.getServiceViewNames(); } /** diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index a14a5be7..39981abc 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -116,10 +116,10 @@ export class Dataservice implements Identifiable< string > { */ public getServiceViewNames(): string[] { if ( this.serviceViews ) { - this.serviceViews = []; + return this.serviceViews; } - return this.serviceViews; + return []; } /** diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index d4c297f3..d1339972 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Injectable } from "@angular/core"; +import { Injectable, ReflectiveInjector } from "@angular/core"; import { Http, Response } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -25,6 +25,7 @@ import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { TestDataService } from "@shared/test-data.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; @@ -35,28 +36,18 @@ import { ErrorObservable } from "rxjs/observable/ErrorObservable"; @Injectable() export class MockDataserviceService extends DataserviceService { - private serv1 = new Dataservice(); - private serv2 = new Dataservice(); - private serv3 = new Dataservice(); - private services: Dataservice[] = [this.serv1, this.serv2, this.serv3]; + private services: Dataservice[]; constructor(http: Http, vdbService: VdbService, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { super(http, vdbService, appSettings, notifierService, logger); - this.serv1.setId("serv1"); - this.serv1.setServiceViewTables(["table1", "table2"]); - this.serv1.setServiceViewModel("viewModel"); - const viewNames: string[] = []; - viewNames.push("views"); - this.serv1.setServiceViewNames(viewNames); - this.serv2.setId("serv2"); - this.serv2.setServiceViewTables(["table1", "table2"]); - this.serv2.setServiceViewModel("viewModel"); - this.serv2.setServiceViewNames(viewNames); - this.serv3.setId("serv3"); - this.serv3.setServiceViewTables(["table1", "table2"]); - this.serv3.setServiceViewModel("viewModel"); - this.serv3.setServiceViewNames(viewNames); + + // Inject service for test data + const injector = ReflectiveInjector.resolveAndCreate([TestDataService]); + const testDataService = injector.get(TestDataService); + + // Get test data + this.services = testDataService.getDataservices(); } /** @@ -89,14 +80,14 @@ export class MockDataserviceService extends DataserviceService { public deleteDataservice(dataserviceId: string): Observable { return Observable.of(true); } - - /** - * Get the current Dataservice selection - * @returns {Dataservice} the selected Dataservice - */ - public getSelectedDataservice( ): Dataservice { - return this.serv1; - } + // + // /** + // * Get the current Dataservice selection + // * @returns {Dataservice} the selected Dataservice + // */ + // public getSelectedDataservice( ): Dataservice { + // return this.serv1; + // } /** * Get the views for the selected Dataservice diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index 2559480a..0c145d3e 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Injectable } from "@angular/core"; +import { Injectable, ReflectiveInjector } from "@angular/core"; import { Http } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -26,6 +26,7 @@ import { VdbModel } from "@dataservices/shared/vdb-model.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { Vdb } from "@dataservices/shared/vdb.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { TestDataService } from "@shared/test-data.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; @@ -35,32 +36,19 @@ import { Observable } from "rxjs/Observable"; @Injectable() export class MockVdbService extends VdbService { - private vdb1 = new Vdb(); - private vdb2 = new Vdb(); - private vdb3 = new Vdb(); - private vdbs: Vdb[] = [this.vdb1, this.vdb2, this.vdb3]; - - private vdbStatus1 = new VdbStatus(); - private vdbStatus2 = new VdbStatus(); - private vdbStatus3 = new VdbStatus(); - private statuses: VdbStatus[] = [this.vdbStatus1, this.vdbStatus3, this.vdbStatus3]; + private vdbs: Vdb[]; + private statuses: VdbStatus[]; constructor(http: Http, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { super(http, appSettings, notifierService, logger); - this.vdb1.setId("serv1"); - this.vdbStatus1.setName( "serv1" ); - this.vdbStatus1.setLoading( false ); - this.vdbStatus1.setActive( true ); - - this.vdb2.setId("serv2"); - this.vdbStatus2.setName("serv2"); - this.vdbStatus2.setLoading( false ); - this.vdbStatus2.setActive( true ); - - this.vdb3.setId("serv3"); - this.vdbStatus3.setName("serv2"); - this.vdbStatus3.setLoading( false ); - this.vdbStatus3.setActive( true ); + + // Inject service for test data + const injector = ReflectiveInjector.resolveAndCreate([TestDataService]); + const testDataService = injector.get(TestDataService); + + // Get test data + this.statuses = testDataService.getVdbStatuses(); + this.vdbs = testDataService.getVdbs(); } /** diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 8bfdc62a..b9e92aef 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -1,9 +1,28 @@ -import { Injectable } from '@angular/core'; -import {Connection} from "@connections/shared/connection.model"; -import {ServiceCatalogSource} from "@connections/shared/service-catalog-source.model"; -import {MockConnectionService} from "@connections/shared/mock-connection.service"; -import {Observable} from "rxjs/Observable"; -import {SchemaInfo} from "@connections/shared/schema-info.model"; +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { SchemaInfo } from "@connections/shared/schema-info.model"; +import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { VdbStatus } from "@dataservices/shared/vdb-status.model"; +import { Vdb } from "@dataservices/shared/vdb.model"; @Injectable() export class TestDataService { @@ -12,6 +31,88 @@ export class TestDataService { private static catalogSourceId2 = "postgresql-persistent-a8xrt"; private static catalogSourceId3 = "mysql-persistent-t3irv"; + // ================================================================= + // VDBs + // ================================================================= + + private static accountsVdb = Vdb.create( + { + keng__id: "AccountsVDB", + vdb__description: "This is an accounts VDB.", + keng__dataPath: "/path/in/repository/AccountsVDB", + keng__kType: "Vdb", + vdb__name: "AccountsVDB", + vdb__originalFile: "/Users/dsbUser/vdbs/accounts.vdb", + vdb__preview: false, + vdb__version: "1" + }, + ); + + private static accountsVdbStatus = VdbStatus.create( + { + name: TestDataService.accountsVdb.getName(), + deployedName: TestDataService.accountsVdb.getName() + "-vdb.xml", + version: TestDataService.accountsVdb.getVersion(), + active: true, + loading: false, + failed: false, + errors: [ + ] + } + ); + + private static employeesVdb = Vdb.create( + { + keng__id: "EmployeesVDB", + vdb__description: "This is an employees VDB.", + keng__dataPath: "/path/in/repository/EmployeesVDB", + keng__kType: "Vdb", + vdb__name: "EmployeesVDB", + vdb__originalFile: "/Users/dsbUser/vdbs/employees.vdb", + vdb__preview: false, + vdb__version: "1" + }, + ); + + private static employeesVdbStatus = VdbStatus.create( + { + name: TestDataService.employeesVdb.getName(), + deployedName: TestDataService.employeesVdb.getName() + "-vdb.xml", + version: TestDataService.employeesVdb.getVersion(), + active: true, + loading: false, + failed: false, + errors: [ + ] + } + ); + + private static productsVdb = Vdb.create( + { + keng__id: "ProductsVDB", + vdb__description: "This is a products VDB.", + keng__dataPath: "/path/in/repository/ProductsVDB", + keng__kType: "Vdb", + vdb__name: "ProductsVDB", + vdb__originalFile: "/Users/dsbUser/vdbs/products.vdb", + vdb__preview: false, + vdb__version: "1" + }, + ); + + private static productsVdbStatus = VdbStatus.create( + { + name: TestDataService.productsVdb.getName(), + deployedName: TestDataService.productsVdb.getName() + "-vdb.xml", + version: TestDataService.productsVdb.getVersion(), + active: true, + loading: false, + failed: false, + errors: [ + ] + } + ); + // ================================================================= // ServiceCatalog DataSources // ================================================================= @@ -31,10 +132,6 @@ export class TestDataService { "mysql", true ); - private catalogSources: ServiceCatalogSource[] = [TestDataService.catalogSource1, - TestDataService.catalogSource2, - TestDataService.catalogSource3]; - // ================================================================= // Connections // ================================================================= @@ -45,10 +142,6 @@ export class TestDataService { private static conn2 = TestDataService.createConnection(TestDataService.connId2, TestDataService.catalogSource2 ); private static conn3 = TestDataService.createConnection(TestDataService.connId3, TestDataService.catalogSource3 ); - private connections: Connection[] = [TestDataService.conn1, - TestDataService.conn2, - TestDataService.conn3]; - // ================================================================= // SchemaInfos for the connections // ================================================================= @@ -70,32 +163,127 @@ export class TestDataService { SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ) ]; - constructor() { } + // ================================================================= + // Dataservices + // ================================================================= - /** - * @returns {Connection[]} the array of test connections - */ - public getConnections(): Connection[] { - return this.connections; - } + private static accountsService = Dataservice.create( + { + keng__id: "Accounts", + tko__description: "A dataservice for accounts.", + serviceVdbName: TestDataService.accountsVdb.getName(), + serviceVdbVersion: TestDataService.accountsVdb.getVersion(), + serviceViews: [ + "AcctView1", + "AcctView2" + ], + serviceViewModel: "AccountsViewModel", + serviceViewTables: [ + "AcctView1Table1", + "AcctView1Table2", + "AcctView1Table3", + "AcctView2Table1" + ], + deploymentState: DeploymentState.LOADING + } + ); - /** - * @returns {ServiceCatalogSource[]} the array of test Service Catalog datasources - */ - public getServiceCatalogSources(): ServiceCatalogSource[] { - return this.catalogSources; - } + private static employeesService = Dataservice.create( + { + keng__id: "Employees", + tko__description: "A dataservice for employees.", + serviceVdbName: TestDataService.employeesVdb.getName(), + serviceVdbVersion: TestDataService.employeesVdb.getVersion(), + serviceViews: [ + "EmpView1", + "EmpView2", + "EmpView3", + "EmpView4" + ], + serviceViewModel: "EmployeesViewModel", + serviceViewTables: [ + "EmpView1Table1", + "EmpView2Table1", + "EmpView2Table2", + "EmpView3Table1", + "EmpView3Table2", + "EmpView3Table3", + "EmpView4Table1", + "EmpView4Table2", + "EmpView4Table3", + "EmpView4Table4" + ], + deploymentState: DeploymentState.LOADING + } + ); - /** - * @returns {Map} the array of test Service Catalog datasources - */ - public getConnectionSourceSchemaInfoMap( ): Map { - const infoMap = new Map(); - infoMap.set( TestDataService.conn1.getServiceCatalogSourceName(), TestDataService.conn1SchemaInfos ); - infoMap.set( TestDataService.conn2.getServiceCatalogSourceName(), TestDataService.conn2SchemaInfos ); - infoMap.set( TestDataService.conn3.getServiceCatalogSourceName(), TestDataService.conn3SchemaInfos ); - return infoMap; - } + private static productsService = Dataservice.create( + { + keng__id: "Products", + tko__description: "A dataservice for products. These are really good products. These products are the best products money can buy.", + serviceVdbName: TestDataService.productsVdb.getName(), + serviceVdbVersion: TestDataService.productsVdb.getVersion(), + serviceViews: [ + "ProdView1", + "ProdView2", + "ProdView3", + "ProdView4", + "ProdView5", + "ProdView6" + ], + serviceViewModel: "ProductsViewModel", + serviceViewTables: [ + "ProdView1Table1", + "ProdView2Table1", + "ProdView2Table2", + "ProdView3Table1", + "ProdView3Table2", + "ProdView3Table3", + "ProdView4Table1", + "ProdView4Table2", + "ProdView4Table3", + "ProdView4Table4", + "ProdView5Table1", + "ProdView5Table2", + "ProdView5Table3", + "ProdView5Table4", + "ProdView5Table5", + "ProdView6Table1", + "ProdView6Table2", + "ProdView6Table3", + "ProdView6Table4", + "ProdView6Table5", + "ProdView6Table6" + ], + deploymentState: DeploymentState.LOADING + } + ); + + private catalogSources: ServiceCatalogSource[] = [TestDataService.catalogSource1, + TestDataService.catalogSource2, + TestDataService.catalogSource3]; + + private connections: Connection[] = [TestDataService.conn1, + TestDataService.conn2, + TestDataService.conn3]; + + private dataServices: Dataservice[] = [ + TestDataService.accountsService, + TestDataService.employeesService, + TestDataService.productsService + ]; + + private vdbs: Vdb[] = [ + TestDataService.accountsVdb, + TestDataService.employeesVdb, + TestDataService.productsVdb + ]; + + private vdbStatuses: VdbStatus[] = [ + TestDataService.accountsVdbStatus, + TestDataService.employeesVdbStatus, + TestDataService.productsVdbStatus + ]; /** * Create a connection of the specified id using the supplied ServiceCatalogSource @@ -108,7 +296,7 @@ export class TestDataService { newConn.setId( id ); const driverName = serviceCatalogSource.getType(); newConn.setDriverName( driverName ); - if( driverName === 'mysql' || driverName === 'postgresql') { + if ( driverName === "mysql" || driverName === "postgresql") { newConn.setJdbc( true ); } else { newConn.setJdbc( false ); @@ -126,7 +314,7 @@ export class TestDataService { * @param {boolean} bound 'true' if bound * @returns {ServiceCatalogSource} */ - private static createServiceCatalogSource( id: string, name: string, type: string, bound: boolean ) { + private static createServiceCatalogSource( id: string, name: string, type: string, bound: boolean ): ServiceCatalogSource { const catalogSource = new ServiceCatalogSource(); catalogSource.setId(id); catalogSource.setName(name); @@ -135,4 +323,54 @@ export class TestDataService { return catalogSource; } + constructor() { + // nothing to do + } + + /** + * @returns {Connection[]} the array of test connections + */ + public getConnections(): Connection[] { + return this.connections; + } + + /** + * @returns {ServiceCatalogSource[]} the array of test Service Catalog datasources + */ + public getServiceCatalogSources(): ServiceCatalogSource[] { + return this.catalogSources; + } + + /** + * @returns {Map} the array of test Service Catalog datasources + */ + public getConnectionSourceSchemaInfoMap( ): Map { + const infoMap = new Map(); + infoMap.set( TestDataService.conn1.getServiceCatalogSourceName(), TestDataService.conn1SchemaInfos ); + infoMap.set( TestDataService.conn2.getServiceCatalogSourceName(), TestDataService.conn2SchemaInfos ); + infoMap.set( TestDataService.conn3.getServiceCatalogSourceName(), TestDataService.conn3SchemaInfos ); + return infoMap; + } + + /** + * @returns {Dataservice[]} the array of test dataservices + */ + public getDataservices(): Dataservice[] { + return this.dataServices; + } + + /** + * @returns {Vdb[]} the VDB collection + */ + public getVdbs(): Vdb[] { + return this.vdbs; + } + + /** + * @returns {VdbStatus[]} the VDB status collection + */ + public getVdbStatuses(): VdbStatus[] { + return this.vdbStatuses; + } + } From 93ca7c544c95922a3af5b618c17904f5f21a1167 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Wed, 21 Mar 2018 11:25:26 -0500 Subject: [PATCH 108/205] Converted over to using the actual json format of the real objects --- .../shared/mock-connection.service.ts | 8 +- .../dataservice-card.component.ts | 4 +- .../dataservices/shared/mock-vdb.service.ts | 1 - ngapp/src/app/shared/test-data.service.ts | 599 ++++++++++++++---- 4 files changed, 469 insertions(+), 143 deletions(-) diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 40be1850..309b14b5 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -38,6 +38,7 @@ export class MockConnectionService extends ConnectionService { private connections: Connection[]; private serviceCatalogSources: ServiceCatalogSource[]; private connectionSourceSchemaInfoMap: Map; + private tableMap = new Map(); constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { super(http, appSettings, logger); @@ -50,6 +51,7 @@ export class MockConnectionService extends ConnectionService { this.connections = testDataService.getConnections(); this.serviceCatalogSources = testDataService.getServiceCatalogSources(); this.connectionSourceSchemaInfoMap = testDataService.getConnectionSourceSchemaInfoMap(); + this.tableMap = testDataService.getJdbcConnectionTableMap(); } public isValidName( name: string ): Observable< string > { @@ -124,11 +126,7 @@ export class MockConnectionService extends ConnectionService { * @returns {Observable} */ public getJdbcConnectionTables( tableFilter: JdbcTableFilter ): Observable< string[] > { - const tableNames = []; - tableNames.push( "table1" ); - tableNames.push( "table2" ); - tableNames.push( "table3" ); - return Observable.of( tableNames ); + return Observable.of( this.tableMap.get( tableFilter.getSchemaFilter() ) ); } /** diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts index 0d19023d..0e8d2098 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts @@ -62,7 +62,7 @@ export class DataserviceCardComponent implements DoCheck, OnInit { private readonly refreshActionId = "refresh"; private readonly refreshActionIndex = 1; // index in moreActions - private isLoading = false; + private isLoading = true; private logger: LoggerService; constructor( logger: LoggerService ) { @@ -154,11 +154,13 @@ export class DataserviceCardComponent implements DoCheck, OnInit { ], moreActions: [ { + disabled: true, id: this.activateActionId, title: "Activate", tooltip: "Activate" }, { + disabled: true, id: this.refreshActionId, title: "Refresh", tooltip: "Refresh" diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index 0c145d3e..98e183fe 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -64,7 +64,6 @@ export class MockVdbService extends VdbService { * @returns {Observable} */ public getTeiidVdbStatuses(): Observable { - super.getTeiidVdbStatuses(); return Observable.of(this.statuses); } diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index b9e92aef..0e7cae4c 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -20,13 +20,13 @@ import { Connection } from "@connections/shared/connection.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; -import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { Vdb } from "@dataservices/shared/vdb.model"; @Injectable() export class TestDataService { + private static pgConnCatalogSourceId = "postgresql-persistent-lq6sg"; private static catalogSourceId1 = "postgresql-persistent-j9vqv"; private static catalogSourceId2 = "postgresql-persistent-a8xrt"; private static catalogSourceId3 = "mysql-persistent-t3irv"; @@ -45,19 +45,6 @@ export class TestDataService { vdb__originalFile: "/Users/dsbUser/vdbs/accounts.vdb", vdb__preview: false, vdb__version: "1" - }, - ); - - private static accountsVdbStatus = VdbStatus.create( - { - name: TestDataService.accountsVdb.getName(), - deployedName: TestDataService.accountsVdb.getName() + "-vdb.xml", - version: TestDataService.accountsVdb.getVersion(), - active: true, - loading: false, - failed: false, - errors: [ - ] } ); @@ -71,19 +58,6 @@ export class TestDataService { vdb__originalFile: "/Users/dsbUser/vdbs/employees.vdb", vdb__preview: false, vdb__version: "1" - }, - ); - - private static employeesVdbStatus = VdbStatus.create( - { - name: TestDataService.employeesVdb.getName(), - deployedName: TestDataService.employeesVdb.getName() + "-vdb.xml", - version: TestDataService.employeesVdb.getVersion(), - active: true, - loading: false, - failed: false, - errors: [ - ] } ); @@ -97,25 +71,65 @@ export class TestDataService { vdb__originalFile: "/Users/dsbUser/vdbs/products.vdb", vdb__preview: false, vdb__version: "1" - }, + } ); - private static productsVdbStatus = VdbStatus.create( + // ================================================================= + // VDB Status + // ================================================================= + + private static vdbStatuses = { - name: TestDataService.productsVdb.getName(), - deployedName: TestDataService.productsVdb.getName() + "-vdb.xml", - version: TestDataService.productsVdb.getVersion(), - active: true, - loading: false, - failed: false, - errors: [ + "keng__baseUri": "http://das-beetle-studio.192.168.42.142.nip.io/vdb-builder/v1/", + "vdbs": [ + { + "name": TestDataService.accountsVdb.getName(), + "deployedName": TestDataService.accountsVdb.getName() + "-vdb.xml", + "version": TestDataService.accountsVdb.getVersion(), + "active": true, + "loading": false, + "failed": false, + "errors": [] + }, + { + "name": TestDataService.employeesVdb.getName(), + "deployedName": TestDataService.employeesVdb.getName() + "-vdb.xml", + "version": TestDataService.employeesVdb.getVersion(), + "active": true, + "loading": false, + "failed": false, + "errors": [] + }, + { + "name": TestDataService.productsVdb.getName(), + "deployedName": TestDataService.productsVdb.getName() + "-vdb.xml", + "version": TestDataService.productsVdb.getVersion(), + "active": true, + "loading": false, + "failed": false, + "errors": [] + } + ], + "keng___links": [ + { + "rel": "self", + "href": "http://localhost:4200/vdb-builder/v1/metadata/status/vdbs" + }, + { + "rel": "parent", + "href": "http://localhost:4200/vdb-builder/v1/metadata/status" + } ] - } - ); + }; // ================================================================= // ServiceCatalog DataSources // ================================================================= + private static pgConnCatalogSource = TestDataService.createServiceCatalogSource( + TestDataService.pgConnCatalogSourceId, + TestDataService.pgConnCatalogSourceId, + "postgresql", + true ); private static catalogSource1 = TestDataService.createServiceCatalogSource( TestDataService.catalogSourceId1, TestDataService.catalogSourceId1, @@ -135,32 +149,180 @@ export class TestDataService { // ================================================================= // Connections // ================================================================= - private static connId1 = "conn1"; - private static connId2 = "conn2"; - private static connId3 = "conn3"; - private static conn1 = TestDataService.createConnection(TestDataService.connId1, TestDataService.catalogSource1 ); - private static conn2 = TestDataService.createConnection(TestDataService.connId2, TestDataService.catalogSource2 ); - private static conn3 = TestDataService.createConnection(TestDataService.connId3, TestDataService.catalogSource3 ); + + private static pgConn = Connection.create( + { + "keng__baseUri": "http://localhost:4200/vdb-builder/v1/", + "keng__id": "PGConn", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/PGConn", + "keng__kType": "Connection", + "keng__hasChildren": false, + "dv__jndiName": "java:/postgresql-persistent-lq6sg", + "dv__driverName": "postgresql", + "dv__type": true, + "keng__properties": [ + { + "name": "description", + "value": "Postgres connection" + }, + { + "name": "serviceCatalogSource", + "value": "postgresql-persistent-lq6sg" + } + ], + "keng___links": [ + { + "rel": "self", + "href": "http://localhost:4200/vdb-builder/v1/workspace/connections/PGConn" + }, + { + "rel": "parent", + "href": "http://localhost:4200/vdb-builder/v1/workspace/connections" + }, + { + "rel": "children", + "href": "http://localhost:4200/vdb-builder/v1/workspace/search?parent=%2Ftko%3Akomodo%2Ftko%3Aworkspace%2Fadmin%2FPGConn" + } + ] + } + ); + + private static conn1 = Connection.create( + { + "keng__baseUri": "http://localhost:4200/vdb-builder/v1/", + "keng__id": "conn1", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/conn1", + "keng__kType": "Connection", + "keng__hasChildren": false, + "dv__jndiName": "java:/postgresql-persistent-j9vqv", + "dv__driverName": "postgresql", + "dv__type": true, + "keng__properties": [ + { + "name": "description", + "value": "Postgres connection" + }, + { + "name": "serviceCatalogSource", + "value": "postgresql-persistent-j9vqv" + } + ], + "keng___links": [ + { + "rel": "self", + "href": "http://localhost:4200/vdb-builder/v1/workspace/connections/conn1" + }, + { + "rel": "parent", + "href": "http://localhost:4200/vdb-builder/v1/workspace/connections" + }, + { + "rel": "children", + "href": "http://localhost:4200/vdb-builder/v1/workspace/search?parent=%2Ftko%3Akomodo%2Ftko%3Aworkspace%2Fadmin%2Fconn1" + } + ] + } + ); + + private static conn2 = Connection.create( + { + "keng__baseUri": "http://localhost:4200/vdb-builder/v1/", + "keng__id": "conn2", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/conn2", + "keng__kType": "Connection", + "keng__hasChildren": false, + "dv__jndiName": "java:/postgresql-persistent-a8xrt", + "dv__driverName": "postgresql", + "dv__type": true, + "keng__properties": [ + { + "name": "description", + "value": "Postgres connection" + }, + { + "name": "serviceCatalogSource", + "value": "postgresql-persistent-a8xrt" + } + ], + "keng___links": [ + { + "rel": "self", + "href": "http://localhost:4200/vdb-builder/v1/workspace/connections/conn2" + }, + { + "rel": "parent", + "href": "http://localhost:4200/vdb-builder/v1/workspace/connections" + }, + { + "rel": "children", + "href": "http://localhost:4200/vdb-builder/v1/workspace/search?parent=%2Ftko%3Akomodo%2Ftko%3Aworkspace%2Fadmin%2Fconn2" + } + ] + } + ); + + private static conn3 = Connection.create( + { + "keng__baseUri": "http://localhost:4200/vdb-builder/v1/", + "keng__id": "conn3", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/conn3", + "keng__kType": "Connection", + "keng__hasChildren": false, + "dv__jndiName": "java:/mysql-persistent-t3irv", + "dv__driverName": "mysql", + "dv__type": true, + "keng__properties": [ + { + "name": "description", + "value": "MySQL connection" + }, + { + "name": "serviceCatalogSource", + "value": "mysql-persistent-t3irv" + } + ], + "keng___links": [ + { + "rel": "self", + "href": "http://localhost:4200/vdb-builder/v1/workspace/connections/conn3" + }, + { + "rel": "parent", + "href": "http://localhost:4200/vdb-builder/v1/workspace/connections" + }, + { + "rel": "children", + "href": "http://localhost:4200/vdb-builder/v1/workspace/search?parent=%2Ftko%3Akomodo%2Ftko%3Aworkspace%2Fadmin%2Fconn3" + } + ] + } + ); // ================================================================= // SchemaInfos for the connections // ================================================================= + + private static pgConnSchemaInfos = [ + SchemaInfo.create( { name: "pgConnSchemaInfo1", type: "Schema" } ), + SchemaInfo.create( { name: "pgConnCatalogInfo", type: "Catalog", schemaNames: [ "pgConnCatalogSchema1", "pgConnCatalogSchema2" ] } ) + ]; + private static conn1SchemaInfos = [ SchemaInfo.create( { name: "conn1SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn1CatalogInfo", type: "Catalog", schemaNames: [ "conn1CatalogSchema1", "conn1CatalogSchema1" ] } ) + SchemaInfo.create( { name: "conn1CatalogInfo", type: "Catalog", schemaNames: [ "conn1CatalogSchema1", "conn1CatalogSchema2" ] } ) ]; private static conn2SchemaInfos = [ - SchemaInfo.create( { name: "conn2CatalogInfo", type: "Catalog", schemaNames: [ "conn2CatalogSchema1", "conn2CatalogSchema1" ] } ), + SchemaInfo.create( { name: "conn2CatalogInfo", type: "Catalog", schemaNames: [ "conn2CatalogSchema1", "conn2CatalogSchema2" ] } ), SchemaInfo.create( { name: "conn2SchemaInfo1", type: "Schema" } ), SchemaInfo.create( { name: "conn2SchemaInfo2", type: "Schema" } ) ]; private static conn3SchemaInfos = [ - SchemaInfo.create( { name: "conn3CatalogInfo", type: "Catalog", schemaNames: [ "conn3CatalogSchema1", "conn3CatalogSchema1" ] } ), + SchemaInfo.create( { name: "conn3CatalogInfo", type: "Catalog", schemaNames: [ "conn3CatalogSchema1", "conn3CatalogSchema2" ] } ), SchemaInfo.create( { name: "conn3SchemaInfo1", type: "Schema" } ), SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ), - SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ) + SchemaInfo.create( { name: "conn3SchemaInfo3", type: "Schema" } ) ]; // ================================================================= @@ -169,61 +331,120 @@ export class TestDataService { private static accountsService = Dataservice.create( { - keng__id: "Accounts", - tko__description: "A dataservice for accounts.", - serviceVdbName: TestDataService.accountsVdb.getName(), - serviceVdbVersion: TestDataService.accountsVdb.getVersion(), - serviceViews: [ + "keng__baseUri": "http://localhost:4200/vdb-builder/v1/", + "keng__id": "Accounts", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/Accounts", + "keng__kType": "Dataservice", + "keng__hasChildren": true, + "tko__description": "A dataservice for accounts.", + "serviceVdbName": TestDataService.accountsVdb.getName(), + "serviceVdbVersion": TestDataService.accountsVdb.getVersion(), + "serviceViewModel": "views", + "serviceViews": [ "AcctView1", "AcctView2" ], - serviceViewModel: "AccountsViewModel", - serviceViewTables: [ - "AcctView1Table1", - "AcctView1Table2", - "AcctView1Table3", - "AcctView2Table1" + "serviceViewTables": [ + TestDataService.conn1.getId() + "BtlSource.AcctView1Table1", + TestDataService.conn1.getId() + "BtlSource.AcctView1Table2", + TestDataService.conn1.getId() + "BtlSource.AcctView1Table3", + TestDataService.conn1.getId() + "BtlSource.AcctView2Table1" ], - deploymentState: DeploymentState.LOADING + "connections": 0, + "drivers": 0, + "keng___links": [ + { + "rel": "self", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/Accounts" + }, + { + "rel": "parent", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices" + }, + { + "rel": "children", + "href": "http://localhost:4200/vdb-builder/v1/workspace/search?parent=%2Ftko%3Akomodo%2Ftko%3Aworkspace%2Fadmin%2FAccounts" + }, + { + "rel": "vdbs", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/CustService/Vdbs" + }, + { + "rel": "connections", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/CustService/connections" + } + ] } ); private static employeesService = Dataservice.create( { - keng__id: "Employees", - tko__description: "A dataservice for employees.", - serviceVdbName: TestDataService.employeesVdb.getName(), - serviceVdbVersion: TestDataService.employeesVdb.getVersion(), - serviceViews: [ + "keng__baseUri": "http://localhost:4200/vdb-builder/v1/", + "keng__id": "Employees", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/Employees", + "keng__kType": "Dataservice", + "keng__hasChildren": true, + "tko__description": "A dataservice for employees.", + "serviceVdbName": TestDataService.employeesVdb.getName(), + "serviceVdbVersion": TestDataService.employeesVdb.getVersion(), + "serviceViewModel": "views", + "serviceViews": [ "EmpView1", "EmpView2", "EmpView3", "EmpView4" ], - serviceViewModel: "EmployeesViewModel", - serviceViewTables: [ - "EmpView1Table1", - "EmpView2Table1", - "EmpView2Table2", - "EmpView3Table1", - "EmpView3Table2", - "EmpView3Table3", - "EmpView4Table1", - "EmpView4Table2", - "EmpView4Table3", - "EmpView4Table4" + "serviceViewTables": [ + TestDataService.conn2.getId() + "BtlSource.EmpView1Table1", + TestDataService.conn2.getId() + "BtlSource.EmpView2Table1", + TestDataService.conn2.getId() + "BtlSource.EmpView2Table2", + TestDataService.conn2.getId() + "BtlSource.EmpView3Table1", + TestDataService.conn2.getId() + "BtlSource.EmpView3Table2", + TestDataService.conn2.getId() + "BtlSource.EmpView3Table3", + TestDataService.conn2.getId() + "BtlSource.EmpView4Table1", + TestDataService.conn2.getId() + "BtlSource.EmpView4Table2", + TestDataService.conn2.getId() + "BtlSource.EmpView4Table3", + TestDataService.conn2.getId() + "BtlSource.EmpView4Table4" ], - deploymentState: DeploymentState.LOADING + "connections": 0, + "drivers": 0, + "keng___links": [ + { + "rel": "self", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/Employees" + }, + { + "rel": "parent", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices" + }, + { + "rel": "children", + "href": "http://localhost:4200/vdb-builder/v1/workspace/search?parent=%2Ftko%3Akomodo%2Ftko%3Aworkspace%2Fadmin%2FEmployees" + }, + { + "rel": "vdbs", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/CustService/Vdbs" + }, + { + "rel": "connections", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/CustService/connections" + } + ] } ); private static productsService = Dataservice.create( { - keng__id: "Products", - tko__description: "A dataservice for products. These are really good products. These products are the best products money can buy.", - serviceVdbName: TestDataService.productsVdb.getName(), - serviceVdbVersion: TestDataService.productsVdb.getVersion(), - serviceViews: [ + "keng__baseUri": "http://localhost:4200/vdb-builder/v1/", + "keng__id": "Products", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/Products", + "keng__kType": "Dataservice", + "keng__hasChildren": true, + "tko__description": "A dataservice for products.", + "serviceVdbName": TestDataService.productsVdb.getName(), + "serviceVdbVersion": TestDataService.productsVdb.getVersion(), + "serviceViewModel": "views", + "serviceViews": [ "ProdView1", "ProdView2", "ProdView3", @@ -231,39 +452,65 @@ export class TestDataService { "ProdView5", "ProdView6" ], - serviceViewModel: "ProductsViewModel", - serviceViewTables: [ - "ProdView1Table1", - "ProdView2Table1", - "ProdView2Table2", - "ProdView3Table1", - "ProdView3Table2", - "ProdView3Table3", - "ProdView4Table1", - "ProdView4Table2", - "ProdView4Table3", - "ProdView4Table4", - "ProdView5Table1", - "ProdView5Table2", - "ProdView5Table3", - "ProdView5Table4", - "ProdView5Table5", - "ProdView6Table1", - "ProdView6Table2", - "ProdView6Table3", - "ProdView6Table4", - "ProdView6Table5", - "ProdView6Table6" + "serviceViewTables": [ + TestDataService.conn3.getId() + "BtlSource.ProdView1Table1", + TestDataService.conn3.getId() + "BtlSource.ProdView2Table1", + TestDataService.conn3.getId() + "BtlSource.ProdView2Table2", + TestDataService.conn3.getId() + "BtlSource.ProdView3Table1", + TestDataService.conn3.getId() + "BtlSource.ProdView3Table2", + TestDataService.conn3.getId() + "BtlSource.ProdView3Table3", + TestDataService.conn3.getId() + "BtlSource.ProdView4Table1", + TestDataService.conn3.getId() + "BtlSource.ProdView4Table2", + TestDataService.conn3.getId() + "BtlSource.ProdView4Table3", + TestDataService.conn3.getId() + "BtlSource.ProdView4Table4", + TestDataService.conn3.getId() + "BtlSource.ProdView5Table1", + TestDataService.conn3.getId() + "BtlSource.ProdView5Table2", + TestDataService.conn3.getId() + "BtlSource.ProdView5Table3", + TestDataService.conn3.getId() + "BtlSource.ProdView5Table4", + TestDataService.conn3.getId() + "BtlSource.ProdView5Table5", + TestDataService.conn3.getId() + "BtlSource.ProdView6Table1", + TestDataService.conn3.getId() + "BtlSource.ProdView6Table2", + TestDataService.conn3.getId() + "BtlSource.ProdView6Table3", + TestDataService.conn3.getId() + "BtlSource.ProdView6Table4", + TestDataService.conn3.getId() + "BtlSource.ProdView6Table5", + TestDataService.conn3.getId() + "BtlSource.ProdView6Table6" ], - deploymentState: DeploymentState.LOADING + "connections": 0, + "drivers": 0, + "keng___links": [ + { + "rel": "self", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/Products" + }, + { + "rel": "parent", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices" + }, + { + "rel": "children", + "href": "http://localhost:4200/vdb-builder/v1/workspace/search?parent=%2Ftko%3Akomodo%2Ftko%3Aworkspace%2Fadmin%2FProducts" + }, + { + "rel": "vdbs", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/CustService/Vdbs" + }, + { + "rel": "connections", + "href": "http://localhost:4200/vdb-builder/v1/workspace/dataservices/CustService/connections" + } + ] } ); - private catalogSources: ServiceCatalogSource[] = [TestDataService.catalogSource1, + private catalogSources: ServiceCatalogSource[] = [ + TestDataService.pgConnCatalogSource, + TestDataService.catalogSource1, TestDataService.catalogSource2, TestDataService.catalogSource3]; - private connections: Connection[] = [TestDataService.conn1, + private connections: Connection[] = [ + TestDataService.pgConn, + TestDataService.conn1, TestDataService.conn2, TestDataService.conn3]; @@ -279,32 +526,8 @@ export class TestDataService { TestDataService.productsVdb ]; - private vdbStatuses: VdbStatus[] = [ - TestDataService.accountsVdbStatus, - TestDataService.employeesVdbStatus, - TestDataService.productsVdbStatus - ]; - - /** - * Create a connection of the specified id using the supplied ServiceCatalogSource - * @param {string} id - * @param {ServiceCatalogSource} serviceCatalogSource - * @returns {Connection} - */ - private static createConnection( id: string, serviceCatalogSource: ServiceCatalogSource ): Connection { - const newConn = new Connection(); - newConn.setId( id ); - const driverName = serviceCatalogSource.getType(); - newConn.setDriverName( driverName ); - if ( driverName === "mysql" || driverName === "postgresql") { - newConn.setJdbc( true ); - } else { - newConn.setJdbc( false ); - } - newConn.setServiceCatalogSourceName(serviceCatalogSource.getName()); - newConn.setJndiName("java:/" + serviceCatalogSource.getName()); - return newConn; - } + private jdbcTableMap = new Map(); + private vdbStatuses: VdbStatus[]; /** * Create a ServiceCatalogSource using the specified info @@ -324,7 +547,106 @@ export class TestDataService { } constructor() { - // nothing to do + this.vdbStatuses = TestDataService.vdbStatuses.vdbs.map(( vdbStatus ) => VdbStatus.create( vdbStatus ) ); + + this.jdbcTableMap.set( "pgConnSchemaInfo1", [ + "pgConnTable1", + "pgConnTable2", + "pgConnTable3", + "pgConnTable4", + "pgConnTable5", + "pgConnTable6" + ] ); + this.jdbcTableMap.set( "pgConnCatalogSchema1", [ + "pgConnTableA", + "pgConnTableB", + "pgConnTableC", + "pgConnTableD", + "pgConnTableE", + "pgConnTableF", + "pgConnTableG" + ] ); + this.jdbcTableMap.set( "pgConnCatalogSchema2", [ + "cat2TableRed", + "cat2TableWhite", + "cat2TableBlue" + ] ); + this.jdbcTableMap.set( "conn1SchemaInfo1", [ + "conn1Table1", + "conn1Table2", + "conn1Table3", + "conn1Table4", + "conn1Table5", + "conn1Table6" + ] ); + this.jdbcTableMap.set( "conn1CatalogSchema1", [ + "conn1TableA", + "conn1TableB", + "conn1TableC", + "conn1TableD", + "conn1TableE", + "conn1TableF", + "conn1TableG" + ] ); + this.jdbcTableMap.set( "conn1CatalogSchema2", [ + "conn1TableRed", + "conn1TableWhite", + "conn1TableBlue" + ] ); + this.jdbcTableMap.set( "conn2CatalogSchema1", [ + "conn2Table1", + "conn2Table2", + "conn2Table3", + "conn2Table4", + "conn2Table5", + "conn2Table6", + "conn2Table7" + ] ); + this.jdbcTableMap.set( "conn2CatalogSchema2", [ + "conn2Cat2TableA", + "conn2Cat2TableB", + "conn2Cat2TableC", + "conn2Cat2TableD", + "conn2Cat2TableE", + "conn2Cat2TableF", + "conn2Cat2TableG" + ] ); + this.jdbcTableMap.set( "conn2SchemaInfo1", [ + "conn2TableLarry", + "conn2TableCurly", + "conn2TableMoe" + ] ); + this.jdbcTableMap.set( "conn2SchemaInfo2", [ + "conn2TableRed", + "conn2TableWhite", + "conn2TableBlue" + ] ); + this.jdbcTableMap.set( "conn3CatalogSchema1", [ + "conn3Table1", + "conn3Table2", + "conn3Table3", + "conn2Table4" + ] ); + this.jdbcTableMap.set( "conn3CatalogSchema2", [ + "conn3Cat2TableA", + "conn3Cat2TableB", + "conn3Cat2TableC" + ] ); + this.jdbcTableMap.set( "conn3SchemaInfo1", [ + "conn3TableJohn", + "conn3TablePaul", + "conn3TableRingo" + ] ); + this.jdbcTableMap.set( "conn3SchemaInfo2", [ + "conn3TablePurple", + "conn3TableBlue", + "conn3TableGreen" + ] ); + this.jdbcTableMap.set( "conn3SchemaInfo3", [ + "conn3TableOrange", + "conn3TableYellow", + "conn3TableBrown" + ] ); } /** @@ -346,6 +668,7 @@ export class TestDataService { */ public getConnectionSourceSchemaInfoMap( ): Map { const infoMap = new Map(); + infoMap.set( TestDataService.pgConn.getServiceCatalogSourceName(), TestDataService.pgConnSchemaInfos ); infoMap.set( TestDataService.conn1.getServiceCatalogSourceName(), TestDataService.conn1SchemaInfos ); infoMap.set( TestDataService.conn2.getServiceCatalogSourceName(), TestDataService.conn2SchemaInfos ); infoMap.set( TestDataService.conn3.getServiceCatalogSourceName(), TestDataService.conn3SchemaInfos ); @@ -359,6 +682,10 @@ export class TestDataService { return this.dataServices; } + public getJdbcConnectionTableMap(): Map { + return this.jdbcTableMap; + } + /** * @returns {Vdb[]} the VDB collection */ From 124a82946f192be3d9be945fdc6d97dac66df99a Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 22 Mar 2018 16:28:14 -0500 Subject: [PATCH 109/205] Fixes some failing tests and lint errors. --- .../connections/connections.component.spec.ts | 10 +++++----- ngapp/src/app/connections/connections.module.ts | 8 ++++---- ngapp/src/app/core/core.module.ts | 2 +- .../core/vertical-nav/vertical-nav.component.ts | 2 +- .../dataservices/dataservices.component.spec.ts | 6 +++--- .../src/app/dataservices/dataservices.module.ts | 17 +---------------- .../shared/mock-notifier.service.ts | 11 ----------- .../sql-control/sql-control.component.spec.ts | 8 ++++++++ .../test-dataservice.component.spec.ts | 8 ++++++++ ngapp/src/app/shared/shared.module.ts | 2 +- ngapp/src/app/shared/test-data.service.spec.ts | 9 ++++----- ngapp/src/environments/environment.ts | 2 +- 12 files changed, 37 insertions(+), 48 deletions(-) delete mode 100644 ngapp/src/app/dataservices/shared/mock-notifier.service.ts diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index 188a65bc..258a92b6 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { ComponentFixture, TestBed } from "@angular/core/testing"; import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; import { By } from "@angular/platform-browser"; @@ -22,7 +22,7 @@ describe("ConnectionsComponent", () => { let component: ConnectionsComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ imports: [ CoreModule, @@ -58,7 +58,7 @@ describe("ConnectionsComponent", () => { fixture = TestBed.createComponent(ConnectionsComponent); component = fixture.componentInstance; fixture.detectChanges(); - })); + }); it("should be created", () => { console.log("========== [ConnectionsComponent] should be created"); @@ -84,12 +84,12 @@ describe("ConnectionsComponent", () => { console.log("========== [ConnectionsComponent] should have Connections"); // Check component object const connections = component.allConnections; - expect(connections.length).toEqual(3); + expect(connections.length).toEqual(4); // Check html has the same number of connection cards const cardDebugElems = fixture.debugElement.queryAll(By.css(".object-card")); expect(cardDebugElems).toBeDefined(); - expect(cardDebugElems.length).toEqual(3); + expect(cardDebugElems.length).toEqual(4); }); it("should have initial card layout", () => { diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 6d850ee0..d69833fb 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -18,6 +18,7 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { Http } from "@angular/http"; import { RouterModule } from "@angular/router"; import { AddConnectionWizardComponent } from "@connections/add-connection-wizard/add-connection-wizard.component"; import { AddConnectionComponent } from "@connections/add-connection/add-connection.component"; @@ -28,16 +29,15 @@ import { ConnectionsListComponent } from "@connections/connections-list/connecti import { ConnectionsRoutingModule } from "@connections/connections-routing.module"; import { ConnectionsComponent } from "@connections/connections.component"; import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { LoggerService } from "@core/logger.service"; +import { environment } from "@environments/environment"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { ConnectionTypeCardComponent } from "./connection-type-cards/connection-type-card/connection-type-card.component"; import { ConnectionTypeCardsComponent } from "./connection-type-cards/connection-type-cards.component"; -import { AppSettingsService } from "@core/app-settings.service"; -import { Http } from "@angular/http"; -import { environment } from "@environments/environment"; -import { MockConnectionService } from "@connections/shared/mock-connection.service"; @NgModule({ imports: [ diff --git a/ngapp/src/app/core/core.module.ts b/ngapp/src/app/core/core.module.ts index f3d2ab2b..3c1a9232 100644 --- a/ngapp/src/app/core/core.module.ts +++ b/ngapp/src/app/core/core.module.ts @@ -21,6 +21,7 @@ import { Http, HttpModule } from "@angular/http"; import { RouterModule } from "@angular/router"; import { AboutDialogComponent } from "@core/about-dialog/about-dialog.component"; import { AboutService } from "@core/about-dialog/about.service"; +import { MockAboutService } from "@core/about-dialog/mock-about.service"; import { AppSettingsService } from "@core/app-settings.service"; import { BreadcrumbComponent } from "@core/breadcrumbs/breadcrumb/breadcrumb.component"; import { BreadcrumbsComponent } from "@core/breadcrumbs/breadcrumbs.component"; @@ -31,7 +32,6 @@ import { environment } from "@environments/environment"; import { ModalModule } from "ngx-bootstrap/modal"; import { BsModalService } from "ngx-bootstrap/modal"; import { PatternFlyNgModule } from "patternfly-ng"; -import { MockAboutService } from "@core/about-dialog/mock-about.service"; @NgModule({ imports: [ diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts index f1ef656a..f751c0da 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import {Component, Input, OnInit, TemplateRef, ViewEncapsulation} from "@angular/core"; +import { Component, Input, OnInit, TemplateRef, ViewEncapsulation } from "@angular/core"; import { Router } from "@angular/router"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { AboutEvent } from "@core/about-dialog/about-event"; diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index a4cc3128..7b0c4b02 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { ComponentFixture, TestBed } from "@angular/core/testing"; import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; import { By } from "@angular/platform-browser"; @@ -30,7 +30,7 @@ describe("DataservicesComponent", () => { let component: DataservicesComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), PatternFlyNgModule, RouterTestingModule, SharedModule, CodemirrorModule ], @@ -55,7 +55,7 @@ describe("DataservicesComponent", () => { fixture = TestBed.createComponent(DataservicesComponent); component = fixture.componentInstance; fixture.detectChanges(); - })); + }); it("should be created", () => { console.log("========== [DataservicesComponent] should be created"); diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index ad71ea21..79f579ce 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -31,7 +31,6 @@ import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.mo import { DataservicesComponent } from "@dataservices/dataservices.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; -import { MockNotifierService } from "@dataservices/shared/mock-notifier.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; @@ -83,11 +82,6 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co deps: [ Http, VdbService, AppSettingsService, NotifierService, LoggerService ], multi: false }, - { - provide: NotifierService, - useFactory: notifierServiceFactory, - multi: false - }, { provide: VdbService, useFactory: vdbServiceFactory, @@ -95,6 +89,7 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co multi: false }, LoggerService, + NotifierService, WizardService ], exports: [ @@ -129,16 +124,6 @@ export function dataserviceServiceFactory( http: Http, logger ); } -/** - * A factory that produces the appropriate instance of the service based on current environment settings. - * - * @returns {NotifierService} the requested service - */ -export function notifierServiceFactory(): NotifierService { - return environment.production || !environment.uiDevMode ? new NotifierService() - : new MockNotifierService(); -} - /** * A factory that produces the appropriate instance of the service based on current environment settings. * diff --git a/ngapp/src/app/dataservices/shared/mock-notifier.service.ts b/ngapp/src/app/dataservices/shared/mock-notifier.service.ts deleted file mode 100644 index 339d0f37..00000000 --- a/ngapp/src/app/dataservices/shared/mock-notifier.service.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Injectable } from "@angular/core"; -import { NotifierService } from "@dataservices/shared/notifier.service"; - -@Injectable() -export class MockNotifierService extends NotifierService { - - constructor() { - super(); - } - -} diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts index d785f5c4..f020a6d7 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts @@ -5,6 +5,7 @@ import { HttpModule } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -38,6 +39,13 @@ describe("SqlControlComponent", () => { })); beforeEach(() => { + // select a dataservice before constructing component + const service = TestBed.get( DataserviceService ); + let dataservices: Dataservice[]; + service.getAllDataservices().subscribe( ( values ) => { dataservices = values; } ); + // noinspection JSUnusedAssignment + service.setSelectedDataservice( dataservices[ 0 ] ); + fixture = TestBed.createComponent(SqlControlComponent); component = fixture.componentInstance; diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts index 3f521272..ba6c635c 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts @@ -4,6 +4,7 @@ import { RouterTestingModule } from "@angular/router/testing"; import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -35,6 +36,13 @@ describe("TestDataserviceComponent", () => { })); beforeEach(() => { + // select a dataservice before constructing component + const service = TestBed.get( DataserviceService ); + let dataservices: Dataservice[]; + service.getAllDataservices().subscribe( ( values ) => { dataservices = values; } ); + // noinspection JSUnusedAssignment + service.setSelectedDataservice( dataservices[ 0 ] ); + fixture = TestBed.createComponent(TestDataserviceComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index 622b9841..5bf00b98 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -21,11 +21,11 @@ import { ReactiveFormsModule } from "@angular/forms"; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { PageErrorComponent } from "@shared/page-error/page-error.component"; +import { TestDataService } from "@shared/test-data.service"; import { ModalModule } from "ngx-bootstrap"; import { PageNotFoundComponent } from "./page-not-found/page-not-found.component"; import { PropertyFormPropertyComponent } from "./property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "./property-form/property-form.component"; -import { TestDataService } from "@shared/test-data.service"; @NgModule({ imports: [ diff --git a/ngapp/src/app/shared/test-data.service.spec.ts b/ngapp/src/app/shared/test-data.service.spec.ts index ee087eea..83ff021a 100644 --- a/ngapp/src/app/shared/test-data.service.spec.ts +++ b/ngapp/src/app/shared/test-data.service.spec.ts @@ -1,15 +1,14 @@ -import { TestBed, inject } from '@angular/core/testing'; +import { inject, TestBed } from "@angular/core/testing"; +import { TestDataService } from "@shared/test-data.service"; -import { TestDataService } from './test-data.service'; - -describe('TestDataService', () => { +describe("TestDataService", () => { beforeEach(() => { TestBed.configureTestingModule({ providers: [TestDataService] }); }); - it('should be created', inject([TestDataService], (service: TestDataService) => { + it("should be created", inject([TestDataService], (service: TestDataService) => { expect(service).toBeTruthy(); })); }); diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index 7cd88872..658a4ac2 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -59,6 +59,6 @@ export const environment = { komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service", // Indicates if in UI development mode where OpenShift will not be used. - uiDevMode: true + uiDevMode: false }; From 363760455db6cc1718a80493d50516ba5603d671 Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Fri, 23 Mar 2018 11:13:01 -0500 Subject: [PATCH 110/205] teiidtools-347: Updated connections page empty state to pfng. --- .../connections/connections.component.html | 19 +++++--------- .../app/connections/connections.component.ts | 26 ++++++++++++++++++- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index a6bb61ed..71d7de61 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -36,19 +36,12 @@

    Connections

    -
    -
    -
    - -
    -

    No Connections Found

    -

    - No Connections were found - please click below to create a new Connection! -

    -
    - +
    +
    +
    +
    diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 2146f303..69cb3941 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -26,7 +26,7 @@ import { WizardService } from "@dataservices/shared/wizard.service"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { LayoutType } from "@shared/layout-type.enum"; -import { Filter } from "patternfly-ng"; +import { ActionConfig, EmptyStateConfig, Filter } from "patternfly-ng"; import { FilterConfig } from "patternfly-ng"; import { FilterField } from "patternfly-ng"; import { FilterEvent } from "patternfly-ng"; @@ -56,6 +56,7 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni private filteredConns: Connection[] = []; private selectedConns: Connection[] = []; private router: Router; + private noConnectionsConfig: EmptyStateConfig; private appSettingsService: AppSettingsService; private connectionService: ConnectionService; private wizardService: WizardService; @@ -105,6 +106,29 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni } as SortConfig; } + public get noConnectionsEmptyConfig(): EmptyStateConfig { + if ( !this.noConnectionsConfig ) { + const actionConfig = { + primaryActions: [ + { + id: "createConnectionActionId", + title: "Add Connection", + tooltip: "Add a connection" + } + ] + } as ActionConfig; + + this.noConnectionsConfig = { + actions: actionConfig, + iconStyleClass: "pficon-warning-triangle-o", + info: "No Connections were found. Please click below to create a connection. ", + title: "No Connections Available" + } as EmptyStateConfig; + } + + return this.noConnectionsConfig; + } + public loadAsyncPageData(): void { const self = this; From 983ba46bfab02cb07c614e378309490e02f69c4a Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Fri, 23 Mar 2018 11:44:39 -0500 Subject: [PATCH 111/205] Changed method name in conenction component to match HTML. --- ngapp/src/app/connections/connections.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 69cb3941..10a63b9b 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -214,7 +214,7 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni /** * Handle request for new Connection */ - public onNew(): void { + public onNewConnection(): void { this.wizardService.setEdit(false); const link: string[] = [ ConnectionsConstants.addConnectionPath ]; From 87ef7ae390e9caf9508224511f33cb31c77b1fd8 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Mon, 12 Mar 2018 13:43:31 +0000 Subject: [PATCH 112/205] Provide a Download action for a dataservice * api.service.ts * Provides an isJSON checker function * Provides a msg extraction function from a response * Log the error in the handleError function * dataservice[s]-* * Plumbs in the Download action * dataservices.service.ts * Fetches the dataservice as a base64 string then converts it to its jar file then uses FileSaver to save the file to the local filesystem. --- ngapp/package.json | 1 + ngapp/src/app/core/api.service.ts | 40 +++++++- .../dataservice-card.component.css | 6 ++ .../dataservice-card.component.ts | 13 +++ .../dataservices-cards.component.ts | 5 + .../dataservices/dataservices.component.html | 4 +- .../dataservices/dataservices.component.ts | 36 ++++++- .../shared/dataservice.service.ts | 96 +++++++++++++++++++ 8 files changed, 197 insertions(+), 4 deletions(-) diff --git a/ngapp/package.json b/ngapp/package.json index 69059db3..f761fbf0 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -23,6 +23,7 @@ "@angular/router": "^4.4.6", "core-js": "^2.5.3", "express": "^4.16.2", + "file-saver": "^1.3.3", "ng2-codemirror": "^1.1.3", "ngx-bootstrap": "^2.0.2", "patternfly": "^3.41.0", diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index 6c36cdb1..1ffc73d1 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -59,8 +59,46 @@ export abstract class ApiService { return this.appSettings.getKomodoUserWorkspacePath(); } + protected isJSON(item: string): boolean { + item = typeof item !== "string" ? JSON.stringify(item) : item; + + try { + item = JSON.parse(item); + } catch (e) { + return false; + } + + if (typeof item === "object" && item !== null) { + return true; + } + + return false; + } + + protected msgFromResponse(response: Response): string { + let msg = ""; + + let body = response.text(); + if (! this.isJSON(response.text())) { + msg = response.text(); + } else { + let body = response.json(); + + if (body.message) + msg = body.message; + else if (body.error) + msg = body.error; + } + + if (msg.length === 0 ) { + return 'unknown error'; + } + + return msg; + } + protected handleError(error: Response): ErrorObservable { - this.logger.error( this.constructor.name + "::handleError" ); + this.logger.error( this.constructor.name + "::handleError => " + this.msgFromResponse(error)); return Observable.throw(error); } diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index 490bd9da..a69f65bc 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -16,6 +16,12 @@ font-family: "FontAwesome"; } +.card-toolbar .secondary-action[title="Download"]:before { + color: var(--card-action-icon-color); + content: "\f019"; + font-family: "FontAwesome"; +} + .object-card .list-pf, .object-card-selected .list-pf { border: none; diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts index 0e8d2098..b213f3b1 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts @@ -38,10 +38,12 @@ export class DataserviceCardComponent implements DoCheck, OnInit { public static readonly quickLookDataserviceEvent = "quickLook"; public static readonly refreshDataserviceEvent = "activate"; public static readonly testDataserviceEvent = "test"; + public static readonly downloadDataserviceEvent = "download"; public readonly editEvent = DataserviceCardComponent.editDataserviceEvent; public readonly quickLookEvent = DataserviceCardComponent.quickLookDataserviceEvent; public readonly testEvent = DataserviceCardComponent.testDataserviceEvent; + public readonly downloadEvent = DataserviceCardComponent.downloadDataserviceEvent; @Input() public dataservice: Dataservice; @Input() public selectedDataservices: Dataservice[]; @@ -61,6 +63,8 @@ export class DataserviceCardComponent implements DoCheck, OnInit { private readonly publishActionIndex = 2; // index in moreActions private readonly refreshActionId = "refresh"; private readonly refreshActionIndex = 1; // index in moreActions + private readonly downloadActionId = "download"; + private readonly downloadActionIndex = 4; // index in moreActions private isLoading = true; private logger: LoggerService; @@ -123,6 +127,8 @@ export class DataserviceCardComponent implements DoCheck, OnInit { this.onClick( DataserviceCardComponent.publishDataserviceEvent ); } else if ( action.id === this.refreshActionId ) { this.onClick( DataserviceCardComponent.refreshDataserviceEvent ); + } else if ( action.id === this.downloadActionId ) { + this.onClick( DataserviceCardComponent.downloadDataserviceEvent ); } else { this.logger.error( "Action '" + action.id + "' not handled." ); } @@ -143,6 +149,7 @@ export class DataserviceCardComponent implements DoCheck, OnInit { this.actionConfig.moreActions[ this.deleteActionIndex ].disabled = this.isLoading; this.actionConfig.moreActions[ this.publishActionIndex ].disabled = this.isLoading; this.actionConfig.moreActions[ this.refreshActionIndex ].disabled = this.isLoading; + this.actionConfig.moreActions[ this.downloadActionIndex ].disabled = this.isLoading; } this.cardConfig.action.iconStyleClass = this.detailsIconStyle; @@ -171,6 +178,12 @@ export class DataserviceCardComponent implements DoCheck, OnInit { title: "Publish", tooltip: "Publish" }, + { + disabled: true, + id: this.downloadActionId, + title: "Download", + tooltip: "Download" + }, { disabled: true, id: this.deleteActionId, diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts index 65a0f966..8d50b0c1 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts @@ -39,6 +39,7 @@ export class DataservicesCardsComponent { @Output() public deleteDataservice: EventEmitter = new EventEmitter(); @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); + @Output() public downloadDataservice: EventEmitter = new EventEmitter(); public logger: LoggerService; @@ -73,6 +74,10 @@ export class DataservicesCardsComponent { case DataserviceCardComponent.testDataserviceEvent: this.testDataservice.emit( event.dataserviceName ); break; + case DataserviceCardComponent.downloadDataserviceEvent: + this.downloadDataservice.emit ( event.dataserviceName ); + this.logger.error( "Download dataservice event type of '" + event.eventType + "'" ); + break; default: this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); break; diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 8ab09247..fa7a461e 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -89,7 +89,8 @@

    (activateDataservice)="onActivate($event)" (testDataservice)="onTest($event)" (publishDataservice)="onPublish($event)" (deleteDataservice)="onDelete($event)" (editDataservice)="onEdit($event)" (quickLookDataservice)="onQuickLook($event)" - (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)"> + (downloadDataservice)="onDownload($event)" (dataserviceSelected)="onSelected($event)" + (dataserviceDeselected)="onDeselected($event)">

    @@ -112,4 +113,3 @@

    Do you really want to delete the selected Dataservice?

    - diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 6bc9e1f7..036cb4a7 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -60,9 +60,12 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn public readonly exportInProgressHeader: string = "Publishing: "; public readonly exportSuccessHeader: string = "Publish Succeeded: "; public readonly exportFailedHeader: string = "Publish Failed: "; - public readonly connectionsLoadedTag = "connections"; + public readonly downloadInProgressHeader: string = "Downloading: "; + public readonly downloadSuccessHeader: string = "Download Succeeded: "; + public readonly downloadFailedHeader: string = "Download Failed: "; + public filterConfig: FilterConfig; public filtersText = ""; public items: Dataservice[]; @@ -403,6 +406,37 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn }); } + /** + * Handle Download of the specified Dataservice + * @param {string} svcName + */ + public onDownload(svcName: string): void { + this.setQuickLookPanelOpenState(false); + + this.exportNotificationHeader = this.exportInProgressHeader; + this.exportNotificationMessage = "Downloading " + svcName + "..."; + this.exportNotificationType = NotificationType.INFO; + this.exportNotificationVisible = true; + this.logger.log("[DataservicesPageComponent] Downloading Dataservice: " + svcName); + const self = this; + this.dataserviceService + .downloadDataservice(svcName) + .subscribe( + (wasSuccess) => { + self.exportNotificationHeader = this.downloadSuccessHeader; + self.exportNotificationMessage = " " + svcName + " was downloaded successfully!"; + self.exportNotificationType = NotificationType.SUCCESS; + this.logger.log("[DataservicesPageComponent] Download Dataservice was successful"); + }, + (error) => { + self.exportNotificationHeader = this.downloadFailedHeader; + self.exportNotificationMessage = " Failed to downlaod dataservice " + svcName; + self.exportNotificationType = NotificationType.DANGER; + this.logger.error("[DataservicesPageComponent] Download dataservice " + svcName + " failed."); + } + ); + } + public onPublish(svcName: string): void { this.setQuickLookPanelOpenState(false); diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 46a5a0b0..f4a5b3cb 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -35,6 +35,7 @@ import { Observable } from "rxjs/Observable"; import { ReplaySubject } from "rxjs/ReplaySubject"; import { Subject } from "rxjs/Subject"; import { Subscription } from "rxjs/Subscription"; +import { saveAs } from 'file-saver/FileSaver'; @Injectable() export class DataserviceService extends ApiService { @@ -357,6 +358,101 @@ export class DataserviceService extends ApiService { .flatMap((res) => this.createDataserviceForSingleSourceTables(dataservice, sourceTables)); } + /** + * Converts a base64 data string into a blob for use with the FileSaver library + * Acknowledgement to + * http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript + */ + private b64toBlob(b64Data: string, contentType: string): Blob { + contentType = contentType || ''; + let sliceSize = 512; + + // + // Decodes the base64 string back into binary data byte characters + // + let byteCharacters = atob(b64Data); + let byteArrays = []; + + // + // Each character's code point (charCode) will be the value of the byte. + // Can create an array of byte values by applying this using the .charCodeAt + // method for each character in the string. + // + // The performance can be improved a little by processing the byteCharacters + // in smaller slices, rather than all at once. Rough testing indicates 512 bytes + // seems to be a good slice size. + // + for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { + let slice = byteCharacters.slice(offset, offset + sliceSize); + + let byteNumbers = new Array(slice.length); + for (let i = 0; i < slice.length; i++) { + byteNumbers[i] = slice.charCodeAt(i); + } + + // + // Convert the array of byte values into a real typed byte array + // by passing it to the Uint8Array constructor. + // + let byteArray = new Uint8Array(byteNumbers); + byteArrays.push(byteArray); + } + + // + // Convert to a Blob by wrapping it in an array passing it to the Blob constructor. + // + let blob = new Blob(byteArrays, { + type: contentType + }); + + return blob; + } + + /** + * Download a dataservice as a jar archive + * @param {string} dataserviceName the dataservice name + * @returns {Observable} + */ + public downloadDataservice(dataserviceName: string): Observable { + // The payload for the rest call + const payload = { + "storageType": "file", + "dataPath": this.getKomodoUserWorkspacePath() + "/" + dataserviceName, + "parameters": {} + }; + + const url = environment.komodoImportExportUrl + "/" + DataservicesConstants.dataservicesExport; + + return this.http + .post(url, payload, this.getAuthRequestOptions()) + .map((response) => { + let status = response.json(); + console.log("Response: " + response); + + if (! status.downloadable) { + throw new Error(payload.dataPath + " is not downloadable"); + } + + if (! status.content) { + throw new Error(payload.dataPath + " has no content"); + } + + const name = status.Name || dataserviceName; + const fileType = status.type || 'data'; + const enc = status.content; + + const contentType = fileType === "zip" ? 'application/zip' : 'text/plain;charset=utf-8'; + const dataBlob = this.b64toBlob(enc, contentType); + + const fileExt = ( fileType == "-vdb.xml" || fileType == "-connection.xml" ) ? fileType : "." + fileType; + + saveAs(dataBlob, name + fileExt); + + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + /** * Export a dataservice to a git repository * @param {string} dataserviceName the dataservice name From aeeebe571d3f60060aaa8ef3e1056a660a6eaff3 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Wed, 14 Mar 2018 18:56:27 +0000 Subject: [PATCH 113/205] TEIIDTOOLS-330 - First working of UI support for publish * Changes the publish action from sending to git repository to generating a service in openshift. --- .../dataservices/dataservices.component.ts | 8 +++--- .../shared/dataservice.service.ts | 26 +++---------------- .../shared/dataservices-constants.ts | 1 + 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 036cb4a7..c426f7c6 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -447,19 +447,19 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.logger.log("[DataservicesPageComponent] Publishing Dataservice: " + svcName); const self = this; this.dataserviceService - .exportDataservice(svcName) + .publishDataservice(svcName) .subscribe( (wasSuccess) => { self.exportNotificationHeader = this.exportSuccessHeader; - self.exportNotificationMessage = " " + svcName + " was published successfully!"; + self.exportNotificationMessage = " " + svcName + " publishing successfully initiated!"; self.exportNotificationType = NotificationType.SUCCESS; - this.logger.log("[DataservicesPageComponent] Publish Dataservice was successful"); + this.logger.log("[DataservicesPageComponent] Dataservice publishing initiation was successful"); }, (error) => { self.exportNotificationHeader = this.exportFailedHeader; self.exportNotificationMessage = " Failed to publish dataservice " + svcName + "!"; self.exportNotificationType = NotificationType.DANGER; - this.logger.log("[DataservicesPageComponent] Publish Dataservice failed."); + this.logger.log("[DataservicesPageComponent] Publish dataservice " + svcName + " failed."); } ); } diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index f4a5b3cb..c7007082 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -454,36 +454,18 @@ export class DataserviceService extends ApiService { } /** - * Export a dataservice to a git repository + * Publish a dataservice * @param {string} dataserviceName the dataservice name * @returns {Observable} */ - public exportDataservice(dataserviceName: string): Observable { - const repoPathKey = this.appSettings.GIT_REPO_PATH_KEY; - const repoBranchKey = this.appSettings.GIT_REPO_BRANCH_KEY; - const repoUsernameKey = this.appSettings.GIT_REPO_USERNAME_KEY; - const repoPasswordKey = this.appSettings.GIT_REPO_PASSWORD_KEY; - const repoAuthorEmailKey = this.appSettings.GIT_REPO_AUTHOR_EMAIL_KEY; - const repoAuthorNameKey = this.appSettings.GIT_REPO_AUTHOR_NAME_KEY; - const repoFilePathKey = this.appSettings.GIT_REPO_FILE_PATH_KEY; + public publishDataservice(dataserviceName: string): Observable { // The payload for the rest call const payload = { - "storageType": "git", - "dataPath": "/" + this.getKomodoUserWorkspacePath() + "/" + dataserviceName, - "parameters": - { - [repoPathKey] : this.appSettings.getGitRepoProperty(repoPathKey), - [repoBranchKey] : this.appSettings.getGitRepoProperty(repoBranchKey), - [repoFilePathKey] : dataserviceName, - [repoUsernameKey] : this.appSettings.getGitRepoProperty(repoUsernameKey), - [repoPasswordKey] : btoa(this.appSettings.getGitRepoProperty(repoPasswordKey)), - [repoAuthorNameKey] : this.appSettings.getGitRepoProperty(repoAuthorNameKey), - [repoAuthorEmailKey] : this.appSettings.getGitRepoProperty(repoAuthorEmailKey) - } + "name": dataserviceName }; - const url = environment.komodoImportExportUrl + "/" + DataservicesConstants.dataservicesExport; + const url = environment.komodoTeiidUrl + "/" + DataservicesConstants.dataservicesPublish; return this.http .post(url, payload, this.getAuthRequestOptions()) diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ngapp/src/app/dataservices/shared/dataservices-constants.ts index 895a9c85..0874b584 100644 --- a/ngapp/src/app/dataservices/shared/dataservices-constants.ts +++ b/ngapp/src/app/dataservices/shared/dataservices-constants.ts @@ -15,6 +15,7 @@ import { NavigationItemConfig } from "patternfly-ng"; export class DataservicesConstants { public static readonly dataservicesExport = "export"; + public static readonly dataservicesPublish = "publish"; public static readonly dataserviceRootRoute = "dataservice"; public static readonly dataserviceRootPath = "/" + DataservicesConstants.dataserviceRootRoute; From bf40433495a02ceee65dae02431ea20ee790bfe9 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Mon, 19 Mar 2018 15:32:29 +0000 Subject: [PATCH 114/205] Handle vdb deployment errors * vdb.service.ts * Correctly handles the status object returned from a vdb deployment by assessing its deployment success flag * api.service.ts * Handle status object error messages ensuring they get printed to the console. --- ngapp/src/app/core/api.service.ts | 2 ++ ngapp/src/app/dataservices/shared/vdb.service.ts | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index 1ffc73d1..4db9955d 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -88,6 +88,8 @@ export abstract class ApiService { msg = body.message; else if (body.error) msg = body.error; + else if (body.Information && body.Information.ErrorMessage1) + msg = body.Information.ErrorMessage1; } if (msg.length === 0 ) { diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 51464cdc..edbe9daa 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -176,7 +176,12 @@ export class VdbService extends ApiService { .post(environment.komodoTeiidUrl + VdbsConstants.vdbRootPath, { path: vdbPath}, this.getAuthRequestOptions()) .map((response) => { - return response.ok; + let status = response.json(); + if (status.Information.deploymentSuccess !== 'true') { + this.handleError(response); + } + + return status.Information.deploymentSuccess === 'true'; }) .catch( ( error ) => this.handleError( error ) ); } From 2e9993773965d815f8f63e7318cc57357881ae5f Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Tue, 20 Mar 2018 12:12:33 +0000 Subject: [PATCH 115/205] Downgrades file-saver to 1.3.3 * Due to 1.3.4 radically changing its API and just not working correctly, reverted to 1.3.3. * see https://github.com/eligrey/FileSaver.js/issues/414 --- ngapp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngapp/package.json b/ngapp/package.json index f761fbf0..98be4aa0 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -23,7 +23,7 @@ "@angular/router": "^4.4.6", "core-js": "^2.5.3", "express": "^4.16.2", - "file-saver": "^1.3.3", + "file-saver": "1.3.3", "ng2-codemirror": "^1.1.3", "ngx-bootstrap": "^2.0.2", "patternfly": "^3.41.0", From b2cddc2d12a1f54f36ce57e7f75bfc3bdc4c20c0 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Thu, 22 Mar 2018 21:28:52 +0000 Subject: [PATCH 116/205] Fixes the positioning of the dataservices notification toast * Adds an extra margin-top to stop it butting up to the top of the results frame. --- ngapp/src/app/dataservices/dataservices.component.css | 4 ++++ ngapp/src/app/dataservices/dataservices.component.html | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices.component.css b/ngapp/src/app/dataservices/dataservices.component.css index 7702a217..aab83d6d 100644 --- a/ngapp/src/app/dataservices/dataservices.component.css +++ b/ngapp/src/app/dataservices/dataservices.component.css @@ -43,3 +43,7 @@ font-size: 1.25em; font-weight: bold; } + +.dataservices-toast { + margin-top: 0.5em; +} diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index fa7a461e..d74fdfe5 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -71,13 +71,15 @@

    - - + + - + +
    Date: Thu, 22 Mar 2018 21:37:27 +0000 Subject: [PATCH 117/205] TEIIDTOOLS-374: VDB naming and model source associated connections * VDB names should be lower case in acccordance with kubernetes rules * A VDB model source should be associated with its connection explicitly rather than relying on the source name. * dataservice.service vdbservice.service * derive functions for generating the relevant names from the dataservice/connection * The associated connection's data path is applied to the vdb model source prior to transmission to komodo. --- .../connections/shared/connection.model.ts | 8 ++++ .../shared/dataservice.service.ts | 27 ++++++++--- .../shared/vdb-model-source.model.ts | 15 ++++++ .../app/dataservices/shared/vdb.service.ts | 48 ++++++++++++++++--- .../app/dataservices/shared/vdbs-constants.ts | 3 +- 5 files changed, 87 insertions(+), 14 deletions(-) diff --git a/ngapp/src/app/connections/shared/connection.model.ts b/ngapp/src/app/connections/shared/connection.model.ts index 2a656cd9..89f121d9 100644 --- a/ngapp/src/app/connections/shared/connection.model.ts +++ b/ngapp/src/app/connections/shared/connection.model.ts @@ -24,6 +24,7 @@ export class Connection implements Identifiable< string > { public static serviceCatalogSourceProp = "serviceCatalogSource"; private keng__id: string; + private keng__dataPath: string; private dv__jndiName: string; private dv__driverName: string; private dv__type: boolean; @@ -117,6 +118,13 @@ export class Connection implements Identifiable< string > { return this.keng__id; } + /** + * @returns {string} the connection data path (can be null) + */ + public getDataPath(): string { + return this.keng__dataPath; + } + /** * @returns {string} the connection JNDI name (can be null) */ diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index c7007082..616ea0bd 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -20,6 +20,7 @@ import { Http } from "@angular/http"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { Connection } from "@connections/shared/connection.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; @@ -48,8 +49,6 @@ export class DataserviceService extends ApiService { // Using replay status with cache of 1, so subscribers dont get an initial value on subscription public dataserviceStateChange: Subject< Map > = new ReplaySubject< Map >(1); - public serviceVdbSuffix = "VDB"; // Don't change - must match komodo naming convention - private http: Http; private notifierService: NotifierService; private appSettingsService: AppSettingsService; @@ -317,6 +316,17 @@ export class DataserviceService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Derive the service vdb name from the given dataservice + * + * @param {Dataservice} dataservice + * @returns {string} + */ + public deriveServiceVdbName(dataservice: NewDataservice): string { + let name = dataservice.getId() + VdbsConstants.DATASERVICE_VDB_SUFFIX; + return name.toLowerCase(); + } + /** * Create a dataservice which is a straight passthru to the supplied tables * @param {NewDataservice} dataservice @@ -325,23 +335,26 @@ export class DataserviceService extends ApiService { */ public createDataserviceForSingleSourceTables(dataservice: NewDataservice, sourceTables: Table[]): Observable { // All tables from same connection - const connectionName = sourceTables[0].getConnection().getId(); - const sourceVdbName = connectionName + VdbsConstants.SOURCE_VDB_SUFFIX; - const sourceModelName = connectionName; + const connection: Connection = sourceTables[0].getConnection(); + const sourceVdbName = this.vdbService.deriveVdbName(connection); + const sourceModelName = this.vdbService.deriveVdbModelName(connection); + const sourceModelSourceName = this.vdbService.deriveVdbModelSourceName(connection); const vdbPath = this.getKomodoUserWorkspacePath() + "/" + sourceVdbName; const tablePaths = []; for ( const sourceTable of sourceTables ) { const tablePath = vdbPath + "/" + sourceModelName + "/" + sourceTable.getName(); tablePaths.push(tablePath); } - const modelSourcePath = vdbPath + "/" + sourceModelName + "/vdb:sources/" + sourceModelName; + const modelSourcePath = vdbPath + "/" + sourceModelName + "/vdb:sources/" + sourceModelSourceName; + + const dsVdbName = this.deriveServiceVdbName(dataservice); // Chain the individual calls together in series to build the DataService return this.createDataservice(dataservice) .flatMap((res) => this.vdbService.updateVdbModelFromTeiid(sourceVdbName, sourceModelName, sourceVdbName, sourceModelName)) .flatMap((res) => this.setServiceVdbForSingleSourceTables(dataservice.getId(), tablePaths, modelSourcePath)) - .flatMap((res) => this.createReadonlyDataRole(dataservice.getId(), sourceModelName)) + .flatMap((res) => this.createReadonlyDataRole(dsVdbName, sourceModelName)) .flatMap((res) => this.vdbService.undeployVdb(sourceVdbName)) .flatMap((res) => this.vdbService.deleteVdb(sourceVdbName)); } diff --git a/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts b/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts index b0fae2eb..6d9594ef 100644 --- a/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts +++ b/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts @@ -25,6 +25,7 @@ export class VdbModelSource { private keng__kType = "VdbModelSource"; private vdb__sourceJndiName: string; private vdb__sourceTranslator: string; + private tko__associatedConnection: string; /** * @param {Object} json the JSON representation of a VdbModelSource @@ -75,6 +76,13 @@ export class VdbModelSource { return this.vdb__sourceTranslator; } + /** + * @returns {string} the associated connection path (can be null) + */ + public getAssociatedConnection(): string { + return this.tko__associatedConnection; + } + /** * @param {string} id the vdbModelSource identifier (optional) */ @@ -103,6 +111,13 @@ export class VdbModelSource { this.vdb__sourceTranslator = translator ? translator : null; } + /** + * @param {string} connectionPath the path to the associated connection (optional) + */ + public setAssociatedConnection( connectionPath?: string ): void { + this.tko__associatedConnection = connectionPath ? connectionPath : null; + } + /** * Set all object values using the supplied VdbModelSource json * @param {Object} values diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index edbe9daa..3c84b0fb 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -98,6 +98,39 @@ export class VdbService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + /** + * Derive the vdb name from the given connection + * + * @param {Connection} connection + * @returns {string} + */ + public deriveVdbName(connection: Connection): string { + let name = connection.getId() + VdbsConstants.SOURCE_VDB_SUFFIX; + return name.toLowerCase(); + } + + /** + * Derive the vdb model name from the given connection + * + * @param {Connection} connection + * @returns {string} + */ + public deriveVdbModelName(connection: Connection): string { + return connection.getId().toLowerCase(); + } + + /** + * Derive the vdb model source name from the given connection + * + * @param {Connection} connection + * @returns {string} + */ + public deriveVdbModelSourceName(connection: Connection): string { + return connection.getServiceCatalogSourceName() ? + connection.getServiceCatalogSourceName() : connection.getId().toLowerCase(); + } + /** * Create a vdb via the komodo rest interface * @param {Vdb} vdb @@ -297,10 +330,12 @@ export class VdbService extends ApiService { // Currently requiring all tables from same connection const connection: Connection = tables[0].getConnection(); + const vdbName = this.deriveVdbName(connection); + const vdbModelName = this.deriveVdbModelName(connection); + const vdbModelSourceName = this.deriveVdbModelSourceName(connection); + // VDB to create const vdb = new Vdb(); - const vdbName = connection.getId() + VdbsConstants.SOURCE_VDB_SUFFIX; - const connName = connection.getId(); vdb.setName(vdbName); vdb.setId(vdbName); const vdbPath = this.getKomodoUserWorkspacePath() + "/" + vdbName; @@ -310,8 +345,8 @@ export class VdbService extends ApiService { // VDB Model to create const vdbModel = new VdbModel(); - vdbModel.setId(connName); - vdbModel.setDataPath(vdbPath + "/" + connName); + vdbModel.setId(vdbModelName); + vdbModel.setDataPath(vdbPath + "/" + vdbModelName); vdbModel.setModelType("PHYSICAL"); // Set the importer properties for the physical model @@ -324,10 +359,11 @@ export class VdbService extends ApiService { // VdbModelSource to create const vdbModelSource = new VdbModelSource(); - vdbModelSource.setId(connName); - vdbModelSource.setDataPath(vdbPath + "/" + connName + "/vdb:sources/" + connName); + vdbModelSource.setId(vdbModelSourceName); + vdbModelSource.setDataPath(vdbPath + "/" + vdbModelName + "/vdb:sources/" + vdbModelSourceName); vdbModelSource.setJndiName(connection.getJndiName()); vdbModelSource.setTranslatorName(connection.getDriverName()); + vdbModelSource.setAssociatedConnection(connection.getDataPath()); // Chain the individual calls together in series to build the Vdb and deploy it return this.deleteVdbIfFound(vdb.getId()) diff --git a/ngapp/src/app/dataservices/shared/vdbs-constants.ts b/ngapp/src/app/dataservices/shared/vdbs-constants.ts index 3ad35860..d040e3e9 100644 --- a/ngapp/src/app/dataservices/shared/vdbs-constants.ts +++ b/ngapp/src/app/dataservices/shared/vdbs-constants.ts @@ -13,7 +13,8 @@ export class VdbsConstants { public static readonly SERVICE_VIEW_MODEL_NAME = "views"; // ** must match KomodoDataserviceService.SERVICE_VDB_VIEW_MODEL ** - public static readonly SOURCE_VDB_SUFFIX = "BtlSource"; + public static readonly SOURCE_VDB_SUFFIX = "btlsource"; + public static readonly DATASERVICE_VDB_SUFFIX = "vdb"; public static readonly DEFAULT_READONLY_DATA_ROLE = "DefaultReadOnlyDataRole"; public static readonly statusPath = "/status"; From 1ed97ffb5b353d533b8181e31bb6a1340af1e0a6 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Thu, 22 Mar 2018 21:40:52 +0000 Subject: [PATCH 118/205] TEIIDTOOLS-330: Provides publishing notification * Provides a cog icon in top-left of dataservice cards indicating their published (to Openshift) status * Updates in the same manner as dataservice deployment status * Uses a Virtualization as the model for holding the status information for a published service. Only the PublishState is used currently but their is scope for providing the other information for greater monitoring and management. --- .../dataservice-card.component.css | 2 +- .../dataservice-card.component.html | 29 ++++ .../dataservices-list.component.css | 2 +- .../dataservices/dataservices.component.ts | 49 +++++-- .../dataservices/shared/dataservice.model.ts | 49 +++++++ .../shared/dataservice.service.ts | 68 +++++++-- .../dataservices/shared/notifier.service.ts | 39 +++++- .../dataservices/shared/publish-state.enum.ts | 42 ++++++ .../app/dataservices/shared/vdb.service.ts | 16 ++- .../app/dataservices/shared/vdbs-constants.ts | 2 + .../shared/virtualization.model.ts | 129 ++++++++++++++++++ 11 files changed, 394 insertions(+), 33 deletions(-) create mode 100644 ngapp/src/app/dataservices/shared/publish-state.enum.ts create mode 100644 ngapp/src/app/dataservices/shared/virtualization.model.ts diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index a69f65bc..238206d8 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -6,7 +6,7 @@ .card-toolbar .secondary-action[title="Publish"]:before { color: var(--card-action-icon-color); - content: "\f08e"; + content: "\f085"; font-family: "FontAwesome"; } diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index f0cd4575..00288342 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -78,6 +78,35 @@ data-placement="right" title="Edit"> + + + + + + + + +
    diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css index 9c14dca9..9da5ecf7 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css @@ -8,7 +8,7 @@ /* Adds an icon to the left of the publish action item in dropdown of kebab. */ .object-list .secondary-action[title*="Publish"]:before { color: var(--card-action-icon-color); - content: "\f08e"; + content: "\f085"; font-family: "FontAwesome"; } diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index c426f7c6..c408d0b2 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -25,6 +25,8 @@ import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { PublishState } from "@dataservices/shared/publish-state.enum"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; @@ -58,8 +60,8 @@ import { Subscription } from "rxjs/Subscription"; export class DataservicesComponent extends AbstractPageComponent implements OnInit { public readonly exportInProgressHeader: string = "Publishing: "; - public readonly exportSuccessHeader: string = "Publish Succeeded: "; - public readonly exportFailedHeader: string = "Publish Failed: "; + public readonly exportSuccessHeader: string = "Publishing Begun: "; + public readonly exportFailedHeader: string = "Publishing Failed: "; public readonly connectionsLoadedTag = "connections"; public readonly downloadInProgressHeader: string = "Downloading: "; @@ -97,7 +99,8 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn private exportNotificationMessage: string; private exportNotificationType = NotificationType.SUCCESS; private exportNotificationVisible = false; - private dataserviceStateSubscription: Subscription; + private dataserviceDeployStateSubscription: Subscription; + private dataservicePublishStateSubscription: Subscription; private notifierService: NotifierService; private wizardService: WizardService; private selectedSvcViews: Table[] = []; @@ -116,9 +119,13 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.vdbService = vdbService; this.notifierService = notifierService; this.wizardService = wizardService; + // Register for dataservice deployment state changes + this.dataserviceDeployStateSubscription = this.notifierService.getDataserviceDeployStateMap().subscribe((serviceStateMap) => { + this.onDataserviceDeploymentStateChanged(serviceStateMap); + }); // Register for dataservice state changes - this.dataserviceStateSubscription = this.notifierService.getDataserviceStateMap().subscribe((serviceStateMap) => { - this.onDataserviceStateChanged(serviceStateMap); + this.dataservicePublishStateSubscription = this.notifierService.getDataserviceVirtualizationMap().subscribe((serviceStateMap) => { + this.onDataservicePublishStateChanged(serviceStateMap); }); this.connectionService = connectionService; } @@ -438,6 +445,9 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } public onPublish(svcName: string): void { + const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); + const virtual: Virtualization = new Virtualization(selectedService.getServiceVdbName(), PublishState.PUBLISHING); + selectedService.setServiceVirtualization(virtual); this.setQuickLookPanelOpenState(false); this.exportNotificationHeader = this.exportInProgressHeader; @@ -449,15 +459,15 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.dataserviceService .publishDataservice(svcName) .subscribe( - (wasSuccess) => { + (status) => { self.exportNotificationHeader = this.exportSuccessHeader; - self.exportNotificationMessage = " " + svcName + " publishing successfully initiated!"; - self.exportNotificationType = NotificationType.SUCCESS; - this.logger.log("[DataservicesPageComponent] Dataservice publishing initiation was successful"); + self.exportNotificationMessage = " " + svcName + " publishing successfully initiated."; + self.exportNotificationType = NotificationType.INFO; + this.logger.log("[DataservicesPageComponent] Initiated publishing of dataservice"); }, (error) => { self.exportNotificationHeader = this.exportFailedHeader; - self.exportNotificationMessage = " Failed to publish dataservice " + svcName + "!"; + self.exportNotificationMessage = " Failed to publish dataservice " + svcName + "."; self.exportNotificationType = NotificationType.DANGER; this.logger.log("[DataservicesPageComponent] Publish dataservice " + svcName + " failed."); } @@ -675,10 +685,10 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } /* - * Update the displayed dataservice states using the provided states + * Update the displayed dataservice deployment states using the provided states */ - private onDataserviceStateChanged(stateMap: Map): void { - // For displayed dataservices, update the State using supplied services + private onDataserviceDeploymentStateChanged(stateMap: Map): void { + // For displayed dataservices, update the Deployment State using supplied services for ( const dService of this.filteredDataservices ) { const serviceId = dService.getId(); if (stateMap && stateMap.has(serviceId)) { @@ -687,6 +697,19 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } } + /* + * Update the displayed dataservice publish states using the provided states + */ + private onDataservicePublishStateChanged(stateMap: Map): void { + // For displayed dataservices, update the Publish State using supplied services + for ( const dService of this.filteredDataservices ) { + const serviceId = dService.getId(); + if (stateMap && stateMap.has(serviceId)) { + dService.setServiceVirtualization(stateMap.get(serviceId)); + } + } + } + /* * Update quick look results using the supplied dataservice * @param {string} svcName the dataservice name diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 39981abc..b383fb09 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -16,6 +16,8 @@ */ import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { PublishState } from "@dataservices/shared/publish-state.enum"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; import { Identifiable } from "@shared/identifiable"; import { SortDirection } from "@shared/sort-direction.enum"; @@ -29,6 +31,7 @@ export class Dataservice implements Identifiable< string > { private serviceViewModel: string; private serviceViewTables: string[]; private deploymentState: DeploymentState = DeploymentState.LOADING; + private virtualization: Virtualization = null; /** * @param {Object} json the JSON representation of a Dataservice @@ -190,6 +193,45 @@ export class Dataservice implements Identifiable< string > { return this.deploymentState === DeploymentState.NOT_DEPLOYED; } + /** + * @returns {DeploymentState} the dataservice Deployment state + */ + public getServicePublishState(): PublishState { + return this.virtualization ? this.virtualization.getPublishState() : PublishState.NOT_PUBLISHED; + } + + /** + * Accessor to determine if service has not been published + * @returns {boolean} the dataservice service not published state + */ + public get serviceNotPublished(): boolean { + return this.getServicePublishState() === PublishState.NOT_PUBLISHED; + } + + /** + * Accessor to determine if service publishing is active + * @returns {boolean} the dataservice service publishing active state + */ + public get servicePublishing(): boolean { + return this.getServicePublishState() === PublishState.PUBLISHING; + } + + /** + * Accessor to determine if service has been published + * @returns {boolean} the dataservice service published state + */ + public get servicePublished(): boolean { + return this.getServicePublishState() === PublishState.PUBLISHED; + } + + /** + * Accessor to determine if service has failed publishing + * @returns {boolean} the dataservice service publishing failed state + */ + public get servicePublishFailed(): boolean { + return this.getServicePublishState() === PublishState.FAILED; + } + /** * @param {string} id the dataservice identifier (optional) */ @@ -246,6 +288,13 @@ export class Dataservice implements Identifiable< string > { this.deploymentState = state; } + /** + * @param {Virtualization} state the dataservice virtualization + */ + public setServiceVirtualization( state: Virtualization ): void { + this.virtualization = state ? state : null; + } + // overrides toJSON - we do not want the appSettings public toJSON(): {} { return { diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 616ea0bd..97140014 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -24,6 +24,7 @@ import { Connection } from "@connections/shared/connection.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { PublishState } from "@dataservices/shared/publish-state.enum"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { QueryResults } from "@dataservices/shared/query-results.model"; @@ -31,6 +32,7 @@ import { Table } from "@dataservices/shared/table.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { VdbService } from "@dataservices/shared/vdb.service"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; import { environment } from "@environments/environment"; import { Observable } from "rxjs/Observable"; import { ReplaySubject } from "rxjs/ReplaySubject"; @@ -55,7 +57,8 @@ export class DataserviceService extends ApiService { private vdbService: VdbService; private selectedDataservice: Dataservice; private dataserviceCurrentView: Table[] = []; - private cachedDataserviceStates: Map = new Map(); + private cachedDataserviceDeployStates: Map = new Map(); + private cachedDataserviceVirtualizations: Map = new Map(); private updatesSubscription: Subscription; constructor(http: Http, vdbService: VdbService, appSettings: AppSettingsService, @@ -244,8 +247,7 @@ export class DataserviceService extends ApiService { * @param {string} model1Name, * @returns {Observable} */ - public createReadonlyDataRole(dataserviceName: string, model1Name: string): Observable { - const serviceVdbName = dataserviceName + this.serviceVdbSuffix; + public createReadonlyDataRole(serviceVdbName: string, model1Name: string): Observable { const READ_ONLY_DATA_ROLE_NAME = VdbsConstants.DEFAULT_READONLY_DATA_ROLE; const VIEW_MODEL = VdbsConstants.SERVICE_VIEW_MODEL_NAME; const userWorkspacePath = this.getKomodoUserWorkspacePath(); @@ -440,7 +442,6 @@ export class DataserviceService extends ApiService { .post(url, payload, this.getAuthRequestOptions()) .map((response) => { let status = response.json(); - console.log("Response: " + response); if (! status.downloadable) { throw new Error(payload.dataPath + " is not downloadable"); @@ -483,6 +484,12 @@ export class DataserviceService extends ApiService { return this.http .post(url, payload, this.getAuthRequestOptions()) .map((response) => { + let status = response.json(); + + if (status.Information && status.Information['Build Status'] === 'FAILED') { + throw new Error(status.Information['Build Message']); + } + return response.ok; }) .catch( ( error ) => this.handleError( error ) ); @@ -524,11 +531,12 @@ export class DataserviceService extends ApiService { this.getAllDataservices() .subscribe( (dataservices) => { - self.updateServiceStateMap(dataservices); + self.updateServiceStateMaps(dataservices); }, (error) => { // On error, broadcast the cached states - this.notifierService.sendDataserviceStateMap(this.cachedDataserviceStates); + this.notifierService.sendDataserviceDeployStateMap(this.cachedDataserviceDeployStates); + this.notifierService.sendDataserviceVirtualizationMap(this.cachedDataserviceVirtualizations); } ); } @@ -552,17 +560,28 @@ export class DataserviceService extends ApiService { * Get updates for the provided array of Dataservices and broadcast the map of states * @param {Dataservice[]} services the array of Dataservices */ - private updateServiceStateMap(services: Dataservice[]): void { + private updateServiceStateMaps(services: Dataservice[]): void { const self = this; this.vdbService.getTeiidVdbStatuses() .subscribe( (vdbStatuses) => { - self.cachedDataserviceStates = self.createDeploymentStateMap(services, vdbStatuses); - this.notifierService.sendDataserviceStateMap(self.cachedDataserviceStates); + self.cachedDataserviceDeployStates = self.createDeploymentStateMap(services, vdbStatuses); + this.notifierService.sendDataserviceDeployStateMap(self.cachedDataserviceDeployStates); }, (error) => { // On error, broadcast the cached states - this.notifierService.sendDataserviceStateMap(self.cachedDataserviceStates); + this.notifierService.sendDataserviceDeployStateMap(self.cachedDataserviceDeployStates); + } + ); + this.vdbService.getVirtualizations() + .subscribe( + (vdbStatuses) => { + self.cachedDataserviceVirtualizations = self.createPublishStateMap(services, vdbStatuses); + this.notifierService.sendDataserviceVirtualizationMap(self.cachedDataserviceVirtualizations); + }, + (error) => { + // On error, broadcast the cached states + this.notifierService.sendDataserviceVirtualizationMap(self.cachedDataserviceVirtualizations); } ); } @@ -603,4 +622,33 @@ export class DataserviceService extends ApiService { return dsStateMap; } + /* + * Creates a Map of dataservice name to PublishState, given the list of dataservices and virtualizations + * @param {Dataservice[]} dataservices the Dataservice array + * @param {virtualization[]} virtualizations the Virtualization array + * @returns {Map} the map of dataservice name to PublishState + */ + private createPublishStateMap(dataservices: Dataservice[], virtualizations: Virtualization[]): Map { + const dsStateMap: Map = new Map(); + + // For each dataservice, find the corresponding Virtualization. Add the map entry + for ( const dService of dataservices ) { + const serviceId = dService.getId(); + const serviceVdbName = dService.getServiceVdbName(); + let statusFound = false; + for ( const virtualization of virtualizations ) { + if ( virtualization.getVdbName() === serviceVdbName ) { + statusFound = true; + dsStateMap.set(serviceId, virtualization); + } + } + + if ( !statusFound ) { + const virtual = new Virtualization(serviceVdbName, PublishState.NOT_PUBLISHED); + dsStateMap.set(serviceId, virtual); + } + } + + return dsStateMap; + } } diff --git a/ngapp/src/app/dataservices/shared/notifier.service.ts b/ngapp/src/app/dataservices/shared/notifier.service.ts index 86c9b9aa..8ff563ed 100644 --- a/ngapp/src/app/dataservices/shared/notifier.service.ts +++ b/ngapp/src/app/dataservices/shared/notifier.service.ts @@ -1,6 +1,7 @@ import { Injectable } from "@angular/core"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; import { Observable } from "rxjs/Observable"; import { ReplaySubject } from "rxjs/ReplaySubject"; import { Subject } from "rxjs/Subject"; @@ -13,7 +14,8 @@ import { Subject } from "rxjs/Subject"; export class NotifierService { private deploymentStatusSubject: Subject = new ReplaySubject(1); - private dataserviceStateSubject: Subject< Map > = new ReplaySubject< Map >(1); + private dataserviceDeployStateSubject: Subject< Map > = new ReplaySubject< Map >(1); + private dataserviceVirtualizationSubject: Subject< Map > = new ReplaySubject< Map >(1); constructor() { // Nothing to do @@ -46,22 +48,45 @@ export class NotifierService { * Sends map of dataservice DeploymentState * @param {Map} stateMap */ - public sendDataserviceStateMap(stateMap: Map): void { - this.dataserviceStateSubject.next(stateMap); + public sendDataserviceDeployStateMap(stateMap: Map): void { + this.dataserviceDeployStateSubject.next(stateMap); } /** * Get the map of dataservice DeploymentState * @returns {Observable>} */ - public getDataserviceStateMap(): Observable> { - return this.dataserviceStateSubject.asObservable(); + public getDataserviceDeployStateMap(): Observable> { + return this.dataserviceDeployStateSubject.asObservable(); } /** * Clears the dataservice DeploymentState */ - public clearDataserviceStateMap(): void { - this.dataserviceStateSubject.next(null); + public clearDataserviceDeployStateMap(): void { + this.dataserviceDeployStateSubject.next(null); + } + + /** + * Sends map of dataservice virtualizations + * @param {Map} stateMap + */ + public sendDataserviceVirtualizationMap(stateMap: Map): void { + this.dataserviceVirtualizationSubject.next(stateMap); + } + + /** + * Get the map of dataservice Virtualization + * @returns {Observable>} + */ + public getDataserviceVirtualizationMap(): Observable> { + return this.dataserviceVirtualizationSubject.asObservable(); + } + + /** + * Clears the dataservice Virtualization + */ + public clearDataserviceVirtualizationMap(): void { + this.dataserviceVirtualizationSubject.next(null); } } diff --git a/ngapp/src/app/dataservices/shared/publish-state.enum.ts b/ngapp/src/app/dataservices/shared/publish-state.enum.ts new file mode 100644 index 00000000..650f0f40 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/publish-state.enum.ts @@ -0,0 +1,42 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * An enumeration of Publishing state + */ +export enum PublishState { + + /** + * not published + */ + NOT_PUBLISHED, + + /** + * publishing + */ + PUBLISHING, + + /** + * published + */ + PUBLISHED, + + /** + * failed + */ + FAILED +} diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 3c84b0fb..c47f4695 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -29,6 +29,7 @@ import { VdbModel } from "@dataservices/shared/vdb-model.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { Vdb } from "@dataservices/shared/vdb.model"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; import { environment } from "@environments/environment"; import { Observable } from "rxjs/Rx"; import { Subscription } from "rxjs/Subscription"; @@ -85,7 +86,7 @@ export class VdbService extends ApiService { } /** - * Get the vdbs from the komodo rest interface + * Get the status of any deployed vdbs * @returns {Observable} */ public getTeiidVdbStatuses(): Observable { @@ -99,6 +100,19 @@ export class VdbService extends ApiService { } /** + * Get the status of all published vdbs (virtualizations) + * @returns {Observable} + */ + public getVirtualizations(): Observable { + return this.http + .get(environment.komodoTeiidUrl + "/" + VdbsConstants.vdbPublish, this.getAuthRequestOptions()) + .map((response) => { + const virtuals = response.json(); + return virtuals.map((virtualStatus) => Virtualization.create( virtualStatus )); + }) + .catch( ( error ) => this.handleError( error ) ); + } + /** * Derive the vdb name from the given connection * diff --git a/ngapp/src/app/dataservices/shared/vdbs-constants.ts b/ngapp/src/app/dataservices/shared/vdbs-constants.ts index d040e3e9..b9cd4ef4 100644 --- a/ngapp/src/app/dataservices/shared/vdbs-constants.ts +++ b/ngapp/src/app/dataservices/shared/vdbs-constants.ts @@ -30,4 +30,6 @@ export class VdbsConstants { public static readonly vdbModelSourcesRootRoute = "VdbModelSources"; public static readonly vdbModelSourcesRootPath = "/" + VdbsConstants.vdbModelSourcesRootRoute; + + public static readonly vdbPublish = "publish"; } diff --git a/ngapp/src/app/dataservices/shared/virtualization.model.ts b/ngapp/src/app/dataservices/shared/virtualization.model.ts new file mode 100644 index 00000000..f4590054 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/virtualization.model.ts @@ -0,0 +1,129 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PublishState } from "@dataservices/shared/publish-state.enum"; + +/** + * Virtualization model + */ +export class Virtualization { + + private vdb_name: string; + private build_name: string; + private deployment_name: string; + private build_status : string; /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ + private build_status_message: string; + private namespace: string; + private last_updated: string; + private publishState: PublishState; + + /** + * @param {Object} json the JSON representation of a Virtualization + * @returns {Virtualization} the new Virtualization (never null) + */ + public static create( json: object = {} ): Virtualization { + const virtual = new Virtualization(); + virtual.setValues( json ); + return virtual; + } + + constructor(); + constructor(vdbName: string, publishState: PublishState) + constructor(vdbName?: string, publishState?: PublishState) { + this.vdb_name = vdbName ? vdbName : null; + this.publishState = publishState ? publishState : PublishState.NOT_PUBLISHED; + } + + /** + * @returns {string} the virtualization name (can be null) + */ + public getVdbName(): string { + return this.vdb_name; + } + + /** + * @returns {string} the virtualization build_name (can be null) + */ + public getBuildName(): string { + return this.build_name; + } + + /** + * @returns {string} the virtualization deployment name (can be null) + */ + public getDeploymentName(): string { + return this.deployment_name; + } + + /** + * @returns {string} the virtualization build status (can be null) + */ + public getBuildStatus(): string { + return this.build_status; + } + + /** + * @returns {string} the virtualization build status message (can be null) + */ + public getBuildStatusMsg(): string { + return this.build_status_message; + } + + /** + * @returns {string} the virtualization namespace (can be null) + */ + public getNamespace(): string { + return this.namespace; + } + + /** + * @returns {string} the virtualization last updated date and time (can be null) + */ + public getLastUpdated(): string { + return this.last_updated; + } + + /** + * @returns {PublishedState} the published state of this virtualization (derived from build state) + */ + public getPublishState(): PublishState { + return this.publishState; + } + + /** + * Set all object values using the supplied Virtualization json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + if (this.build_status) { + if (this.build_status === 'BUILDING' || this.build_status === 'DEPLOYING') { + this.publishState = PublishState.PUBLISHING; + } + else if (this.build_status === 'RUNNING') { + this.publishState = PublishState.PUBLISHED; + } + else if (this.build_status === 'FAILED') { + this.publishState = PublishState.FAILED; + } + else { + this.publishState = PublishState.NOT_PUBLISHED; + } + } + } + +} From 0bf967a3da3d26b5ec519b467ed8f18576c8bd71 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 27 Mar 2018 17:50:04 -0500 Subject: [PATCH 119/205] TEIIDTOOLS-397 Add download action to dataservices list view --- .../dataservices-list.component.css | 7 +++++++ .../dataservices-list.component.html | 12 +++++++++++- .../dataservices-list.component.ts | 18 ++++++++++++++++++ .../dataservices/dataservices.component.html | 3 ++- .../app/dataservices/dataservices.component.ts | 2 +- ngapp/src/app/shared/test-data.service.ts | 2 +- 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css index 9da5ecf7..bde71f9e 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css @@ -5,6 +5,13 @@ font-family: "FontAwesome"; } +/* Adds an icon to the left of the download action item in dropdown of kebab. */ +.object-list .secondary-action[title*="Download"]:before { + color: var(--card-action-icon-color); + content: "\f019"; + font-family: "FontAwesome"; +} + /* Adds an icon to the left of the publish action item in dropdown of kebab. */ .object-list .secondary-action[title*="Publish"]:before { color: var(--card-action-icon-color); diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index d4cbac8f..608ab6fd 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -39,7 +39,14 @@  {{ action.title }} @@ -56,6 +63,9 @@  {{ action.title }} + +  {{ action.title }} +  {{ action.title }} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts index 96351544..b12c1e5f 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts @@ -41,6 +41,7 @@ export class DataservicesListComponent implements OnInit { private static readonly editActionId = "edit"; private static readonly previewActionId = "preview"; private static readonly publishActionId = "publish"; + private static readonly downloadActionId = "download"; private static readonly refreshActionId = "refresh"; private static readonly testActionId = "test"; @@ -56,6 +57,7 @@ export class DataservicesListComponent implements OnInit { @Output() public activateDataservice: EventEmitter = new EventEmitter(); @Output() public testDataservice: EventEmitter = new EventEmitter(); @Output() public publishDataservice: EventEmitter = new EventEmitter(); + @Output() public downloadDataservice: EventEmitter = new EventEmitter(); @Output() public deleteDataservice: EventEmitter = new EventEmitter(); @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); @@ -79,6 +81,7 @@ export class DataservicesListComponent implements OnInit { * @param quickLookActionTemplate {TemplateRef} the preview action template * @param activateActionTemplate {TemplateRef} the activate action template * @param publishActionTemplate {TemplateRef} the publish action template + * @param downloadActionTemplate {TemplateRef} the download action template * @param refreshActionTemplate {TemplateRef} the refresh action template * @param deleteActionTemplate {TemplateRef} the delete action template * @returns {ActionConfig} the actions configuration @@ -89,6 +92,7 @@ export class DataservicesListComponent implements OnInit { quickLookActionTemplate: TemplateRef< any >, activateActionTemplate: TemplateRef< any >, publishActionTemplate: TemplateRef< any >, + downloadActionTemplate: TemplateRef< any >, refreshActionTemplate: TemplateRef< any >, deleteActionTemplate: TemplateRef< any > ): ActionConfig { const actionConfig = { @@ -137,6 +141,13 @@ export class DataservicesListComponent implements OnInit { title: "Publish", tooltip: "Publish this data service" }, + { + disabled: ds.serviceDeploymentLoading, + id: DataservicesListComponent.downloadActionId, + template: downloadActionTemplate, + title: "Download", + tooltip: "Download this data service" + }, { disabled: ds.serviceDeploymentLoading, id: DataservicesListComponent.deleteActionId, @@ -202,6 +213,10 @@ export class DataservicesListComponent implements OnInit { this.publishDataservice.emit(dataserviceName); } + public onDownloadDataservice(dataserviceName: string): void { + this.downloadDataservice.emit(dataserviceName); + } + public onDeleteDataservice(dataserviceName: string): void { this.deleteDataservice.emit(dataserviceName); } @@ -222,6 +237,9 @@ export class DataservicesListComponent implements OnInit { case DataservicesListComponent.deleteActionId: this.onDeleteDataservice( item.getId() ); break; + case DataservicesListComponent.downloadActionId: + this.onDownloadDataservice( item.getId() ); + break; case DataservicesListComponent.editActionId: this.onEditDataservice( item.getId() ); break; diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index d74fdfe5..42d2533f 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -86,7 +86,8 @@

    (activateDataservice)="onActivate($event)" (testDataservice)="onTest($event)" (publishDataservice)="onPublish($event)" (deleteDataservice)="onDelete($event)" (editDataservice)="onEdit($event)" (quickLookDataservice)="onQuickLook($event)" - (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)"> + (downloadDataservice)="onDownload($event)" (dataserviceSelected)="onSelected($event)" + (dataserviceDeselected)="onDeselected($event)"> { self.exportNotificationHeader = this.downloadFailedHeader; - self.exportNotificationMessage = " Failed to downlaod dataservice " + svcName; + self.exportNotificationMessage = " Failed to download dataservice " + svcName; self.exportNotificationType = NotificationType.DANGER; this.logger.error("[DataservicesPageComponent] Download dataservice " + svcName + " failed."); } diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 1e02636d..1aec9049 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -22,7 +22,7 @@ import { ServiceCatalogSource } from "@connections/shared/service-catalog-source import { Dataservice } from "@dataservices/shared/dataservice.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { Vdb } from "@dataservices/shared/vdb.model"; -import { QueryResults } from "../dataservices/shared/query-results.model"; +import { QueryResults } from "@dataservices/shared/query-results.model"; @Injectable() export class TestDataService { From bc1f500e91d3c0f8b70a9879a8fd90ec3b4ca6a0 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 29 Mar 2018 13:19:09 -0500 Subject: [PATCH 120/205] Changes related to the dataservice publish feature - fixed lint warnings - added method implementations MockDataserviceService for publish related methods - added mock Virtualization data for the VDBs which is used by the mock service --- .../add-connection-wizard.component.html | 2 +- .../connections/connections.component.html | 2 +- ngapp/src/app/core/api.service.ts | 12 +- .../dataservices-cards.component.ts | 1 - .../basic-content.component.html | 4 +- .../dataservices/dataservices.component.ts | 4 +- .../shared/dataservice.service.ts | 124 +++++++++--------- .../shared/mock-dataservice.service.ts | 13 +- .../dataservices/shared/mock-vdb.service.ts | 7 + .../app/dataservices/shared/vdb.service.ts | 8 +- .../shared/virtualization.model.ts | 15 +-- ngapp/src/app/shared/test-data.service.ts | 61 ++++++++- 12 files changed, 156 insertions(+), 97 deletions(-) diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html index d7ce7ccd..aaa9207e 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html @@ -81,7 +81,7 @@

    {{ step2InstructionMessage }}

    [ngValue]="emptyServiceCatalogSource">{{ emptyServiceCatalogSource.getId() }} + [selected]="catalogSource.getId() == selectedServiceCatalogSource.getId()">{{ catalogSource.getId() }}
    {{ selectServiceCatalogSourceErrorMsg }}

    diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index 71d7de61..01257b1a 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -88,6 +88,6 @@

    - Do you really want to delete the '{{connectionNameForDelete}}' Connection? + Do you really want to delete the '{{ connectionNameForDelete }}' Connection?

    diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index 4db9955d..3a53aa9c 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -78,22 +78,22 @@ export abstract class ApiService { protected msgFromResponse(response: Response): string { let msg = ""; - let body = response.text(); if (! this.isJSON(response.text())) { msg = response.text(); } else { - let body = response.json(); + const body = response.json(); - if (body.message) + if (body.message) { msg = body.message; - else if (body.error) + } else if (body.error) { msg = body.error; - else if (body.Information && body.Information.ErrorMessage1) + } else if (body.Information && body.Information.ErrorMessage1) { msg = body.Information.ErrorMessage1; + } } if (msg.length === 0 ) { - return 'unknown error'; + return "unknown error"; } return msg; diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts index 8d50b0c1..b0f10e35 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts @@ -76,7 +76,6 @@ export class DataservicesCardsComponent { break; case DataserviceCardComponent.downloadDataserviceEvent: this.downloadDataservice.emit ( event.dataserviceName ); - this.logger.error( "Download dataservice event type of '" + event.eventType + "'" ); break; default: this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); diff --git a/ngapp/src/app/dataservices/dataservices-list/basic-content.component.html b/ngapp/src/app/dataservices/dataservices-list/basic-content.component.html index deddb25a..7f3f868b 100644 --- a/ngapp/src/app/dataservices/dataservices-list/basic-content.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/basic-content.component.html @@ -4,13 +4,13 @@ Name

    - {{item.getId()}} + {{ item.getId() }}

    Description

    - {{item.getDescription()}} + {{ item.getDescription() }}

    diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 41d7666f..3c2b0c27 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -25,11 +25,11 @@ import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; -import { PublishState } from "@dataservices/shared/publish-state.enum"; -import { Virtualization } from "@dataservices/shared/virtualization.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { PublishState } from "@dataservices/shared/publish-state.enum"; import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; import { AbstractPageComponent } from "@shared/abstract-page.component"; diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 97140014..4bf36f45 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -17,16 +17,16 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; +import { Connection } from "@connections/shared/connection.model"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; -import { Connection } from "@connections/shared/connection.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; -import { PublishState } from "@dataservices/shared/publish-state.enum"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { PublishState } from "@dataservices/shared/publish-state.enum"; import { QueryResults } from "@dataservices/shared/query-results.model"; import { Table } from "@dataservices/shared/table.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; @@ -34,11 +34,11 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { Virtualization } from "@dataservices/shared/virtualization.model"; import { environment } from "@environments/environment"; +import { saveAs } from "file-saver/FileSaver"; import { Observable } from "rxjs/Observable"; import { ReplaySubject } from "rxjs/ReplaySubject"; import { Subject } from "rxjs/Subject"; import { Subscription } from "rxjs/Subscription"; -import { saveAs } from 'file-saver/FileSaver'; @Injectable() export class DataserviceService extends ApiService { @@ -243,7 +243,7 @@ export class DataserviceService extends ApiService { /** * Create a readonly datarole for the dataservice - * @param {string} dataserviceName, + * @param {string} serviceVdbName, * @param {string} model1Name, * @returns {Observable} */ @@ -325,7 +325,7 @@ export class DataserviceService extends ApiService { * @returns {string} */ public deriveServiceVdbName(dataservice: NewDataservice): string { - let name = dataservice.getId() + VdbsConstants.DATASERVICE_VDB_SUFFIX; + const name = dataservice.getId() + VdbsConstants.DATASERVICE_VDB_SUFFIX; return name.toLowerCase(); } @@ -373,56 +373,6 @@ export class DataserviceService extends ApiService { .flatMap((res) => this.createDataserviceForSingleSourceTables(dataservice, sourceTables)); } - /** - * Converts a base64 data string into a blob for use with the FileSaver library - * Acknowledgement to - * http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript - */ - private b64toBlob(b64Data: string, contentType: string): Blob { - contentType = contentType || ''; - let sliceSize = 512; - - // - // Decodes the base64 string back into binary data byte characters - // - let byteCharacters = atob(b64Data); - let byteArrays = []; - - // - // Each character's code point (charCode) will be the value of the byte. - // Can create an array of byte values by applying this using the .charCodeAt - // method for each character in the string. - // - // The performance can be improved a little by processing the byteCharacters - // in smaller slices, rather than all at once. Rough testing indicates 512 bytes - // seems to be a good slice size. - // - for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { - let slice = byteCharacters.slice(offset, offset + sliceSize); - - let byteNumbers = new Array(slice.length); - for (let i = 0; i < slice.length; i++) { - byteNumbers[i] = slice.charCodeAt(i); - } - - // - // Convert the array of byte values into a real typed byte array - // by passing it to the Uint8Array constructor. - // - let byteArray = new Uint8Array(byteNumbers); - byteArrays.push(byteArray); - } - - // - // Convert to a Blob by wrapping it in an array passing it to the Blob constructor. - // - let blob = new Blob(byteArrays, { - type: contentType - }); - - return blob; - } - /** * Download a dataservice as a jar archive * @param {string} dataserviceName the dataservice name @@ -441,7 +391,7 @@ export class DataserviceService extends ApiService { return this.http .post(url, payload, this.getAuthRequestOptions()) .map((response) => { - let status = response.json(); + const status = response.json(); if (! status.downloadable) { throw new Error(payload.dataPath + " is not downloadable"); @@ -452,13 +402,13 @@ export class DataserviceService extends ApiService { } const name = status.Name || dataserviceName; - const fileType = status.type || 'data'; + const fileType = status.type || "data"; const enc = status.content; - const contentType = fileType === "zip" ? 'application/zip' : 'text/plain;charset=utf-8'; + const contentType = fileType === "zip" ? "application/zip" : "text/plain;charset=utf-8"; const dataBlob = this.b64toBlob(enc, contentType); - const fileExt = ( fileType == "-vdb.xml" || fileType == "-connection.xml" ) ? fileType : "." + fileType; + const fileExt = ( fileType === "-vdb.xml" || fileType === "-connection.xml" ) ? fileType : "." + fileType; saveAs(dataBlob, name + fileExt); @@ -484,10 +434,10 @@ export class DataserviceService extends ApiService { return this.http .post(url, payload, this.getAuthRequestOptions()) .map((response) => { - let status = response.json(); + const status = response.json(); - if (status.Information && status.Information['Build Status'] === 'FAILED') { - throw new Error(status.Information['Build Message']); + if (status.Information && status.Information["Build Status"] === "FAILED") { + throw new Error(status.Information["Build Message"]); } return response.ok; @@ -556,6 +506,56 @@ export class DataserviceService extends ApiService { }); } + /** + * Converts a base64 data string into a blob for use with the FileSaver library + * Acknowledgement to + * http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript + */ + private b64toBlob(b64Data: string, contentType: string): Blob { + contentType = contentType || ""; + const sliceSize = 512; + + // + // Decodes the base64 string back into binary data byte characters + // + const byteCharacters = atob(b64Data); + const byteArrays = []; + + // + // Each character's code point (charCode) will be the value of the byte. + // Can create an array of byte values by applying this using the .charCodeAt + // method for each character in the string. + // + // The performance can be improved a little by processing the byteCharacters + // in smaller slices, rather than all at once. Rough testing indicates 512 bytes + // seems to be a good slice size. + // + for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { + const slice = byteCharacters.slice(offset, offset + sliceSize); + + const byteNumbers = new Array(slice.length); + for (let i = 0; i < slice.length; i++) { + byteNumbers[i] = slice.charCodeAt(i); + } + + // + // Convert the array of byte values into a real typed byte array + // by passing it to the Uint8Array constructor. + // + const byteArray = new Uint8Array(byteNumbers); + byteArrays.push(byteArray); + } + + // + // Convert to a Blob by wrapping it in an array passing it to the Blob constructor. + // + const blob = new Blob(byteArrays, { + type: contentType + }); + + return blob; + } + /* * Get updates for the provided array of Dataservices and broadcast the map of states * @param {Dataservice[]} services the array of Dataservices diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 954dc2ed..f468a009 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -83,14 +83,11 @@ export class MockDataserviceService extends DataserviceService { public deleteDataservice(dataserviceId: string): Observable { return Observable.of(true); } - // - // /** - // * Get the current Dataservice selection - // * @returns {Dataservice} the selected Dataservice - // */ - // public getSelectedDataservice( ): Dataservice { - // return this.serv1; - // } + + public downloadDataservice( dataserviceName: string ): Observable< boolean > { + alert( "Download of " + dataserviceName + " happens here" ); + return Observable.of( true ); + } /** * Get the views for the selected Dataservice diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index 98e183fe..af3c2c95 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -32,12 +32,14 @@ import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; @Injectable() export class MockVdbService extends VdbService { private vdbs: Vdb[]; private statuses: VdbStatus[]; + private virtualizations: Virtualization[]; constructor(http: Http, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { super(http, appSettings, notifierService, logger); @@ -49,6 +51,7 @@ export class MockVdbService extends VdbService { // Get test data this.statuses = testDataService.getVdbStatuses(); this.vdbs = testDataService.getVdbs(); + this.virtualizations = testDataService.getVirtualizations(); } /** @@ -171,4 +174,8 @@ export class MockVdbService extends VdbService { return Observable.of(true); } + public getVirtualizations(): Observable< Virtualization[] > { + return Observable.of( this.virtualizations ); + } + } diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index c47f4695..277f4aa4 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -120,7 +120,7 @@ export class VdbService extends ApiService { * @returns {string} */ public deriveVdbName(connection: Connection): string { - let name = connection.getId() + VdbsConstants.SOURCE_VDB_SUFFIX; + const name = connection.getId() + VdbsConstants.SOURCE_VDB_SUFFIX; return name.toLowerCase(); } @@ -223,12 +223,12 @@ export class VdbService extends ApiService { .post(environment.komodoTeiidUrl + VdbsConstants.vdbRootPath, { path: vdbPath}, this.getAuthRequestOptions()) .map((response) => { - let status = response.json(); - if (status.Information.deploymentSuccess !== 'true') { + const status = response.json(); + if (status.Information.deploymentSuccess !== "true") { this.handleError(response); } - return status.Information.deploymentSuccess === 'true'; + return status.Information.deploymentSuccess === "true"; }) .catch( ( error ) => this.handleError( error ) ); } diff --git a/ngapp/src/app/dataservices/shared/virtualization.model.ts b/ngapp/src/app/dataservices/shared/virtualization.model.ts index f4590054..441d75f7 100644 --- a/ngapp/src/app/dataservices/shared/virtualization.model.ts +++ b/ngapp/src/app/dataservices/shared/virtualization.model.ts @@ -25,7 +25,7 @@ export class Virtualization { private vdb_name: string; private build_name: string; private deployment_name: string; - private build_status : string; /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ + private build_status: string; /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ private build_status_message: string; private namespace: string; private last_updated: string; @@ -98,7 +98,7 @@ export class Virtualization { } /** - * @returns {PublishedState} the published state of this virtualization (derived from build state) + * @returns {PublishState} the published state of this virtualization (derived from build state) */ public getPublishState(): PublishState { return this.publishState; @@ -111,16 +111,13 @@ export class Virtualization { public setValues(values: object = {}): void { Object.assign(this, values); if (this.build_status) { - if (this.build_status === 'BUILDING' || this.build_status === 'DEPLOYING') { + if (this.build_status === "BUILDING" || this.build_status === "DEPLOYING") { this.publishState = PublishState.PUBLISHING; - } - else if (this.build_status === 'RUNNING') { + } else if (this.build_status === "RUNNING") { this.publishState = PublishState.PUBLISHED; - } - else if (this.build_status === 'FAILED') { + } else if (this.build_status === "FAILED") { this.publishState = PublishState.FAILED; - } - else { + } else { this.publishState = PublishState.NOT_PUBLISHED; } } diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 1aec9049..4783c236 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -20,9 +20,12 @@ import { Connection } from "@connections/shared/connection.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { QueryResults } from "@dataservices/shared/query-results.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { Vdb } from "@dataservices/shared/vdb.model"; -import { QueryResults } from "@dataservices/shared/query-results.model"; +import { VirtualAction } from "rxjs/scheduler/VirtualTimeScheduler"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; +import { PublishState } from "@dataservices/shared/publish-state.enum"; @Injectable() export class TestDataService { @@ -753,6 +756,49 @@ export class TestDataService { } ); + // ================================================================= + // Virtualizations + // ================================================================= + + private static accountsVirtualization = Virtualization.create( + { + "vdb_name": TestDataService.accountsVdb.getName(), + "build_name": TestDataService.accountsVdb.getName() + "-build-1", + "deployment_name": TestDataService.accountsVdb.getName() + "-deployment-1", + "build_status": "RUNNING", /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ + "build_status_message": "Accounts VDB build was successful", + "namespace": "beetle-studio", + "last_updated": "2018-03-29T17:02:51.181Z", + "publishState": PublishState.PUBLISHED + } + ); + + private static employeesVirtualization = Virtualization.create( + { + "vdb_name": TestDataService.employeesVdb.getName(), + "build_name": TestDataService.employeesVdb.getName() + "-build-1", + "deployment_name": TestDataService.employeesVdb.getName() + "-deployment-1", + "build_status": "RUNNING", /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ + "build_status_message": "Employees VDB build was successful", + "namespace": "beetle-studio", + "last_updated": "2018-03-29T17:02:51.181Z", + "publishState": PublishState.PUBLISHED + } + ); + + private static productsVirtualization = Virtualization.create( + { + "vdb_name": TestDataService.productsVdb.getName(), + "build_name": TestDataService.productsVdb.getName() + "-build-1", + "deployment_name": TestDataService.productsVdb.getName() + "-deployment-1", + "build_status": "RUNNING", /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ + "build_status_message": "Products VDB build was successful", + "namespace": "beetle-studio", + "last_updated": "2018-03-29T17:02:51.181Z", + "publishState": PublishState.PUBLISHED + } + ); + private catalogSources: ServiceCatalogSource[] = [ TestDataService.pgConnCatalogSource, TestDataService.catalogSource1, @@ -779,6 +825,7 @@ export class TestDataService { private jdbcTableMap = new Map(); private vdbStatuses: VdbStatus[]; + private virtualizations: Virtualization[]; /** * Create a ServiceCatalogSource using the specified info @@ -799,6 +846,11 @@ export class TestDataService { constructor() { this.vdbStatuses = TestDataService.vdbStatuses.vdbs.map(( vdbStatus ) => VdbStatus.create( vdbStatus ) ); + this.virtualizations = [ + TestDataService.accountsVirtualization, + TestDataService.employeesVirtualization, + TestDataService.productsVirtualization + ]; this.jdbcTableMap.set( "pgConnSchemaInfo1", [ "pgConnTable1", @@ -959,4 +1011,11 @@ export class TestDataService { return this.vdbStatuses; } + /** + * @returns {Virtualization[]} the virtualization collection + */ + public getVirtualizations(): Virtualization[] { + return this.virtualizations; + } + } From 7041554c4df48fc0bf8d7e69ff3b4ef86c0afb32 Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Mon, 2 Apr 2018 15:09:34 -0500 Subject: [PATCH 121/205] Changed dataservice list detail to match connection list detail. Also refactored dataservice detail from basic content. --- .../connection-details.component.html | 1 - .../basic-content.component.html | 16 ----- .../basic-content.component.ts | 32 ---------- .../dataservices-details.component.html | 12 ++++ .../dataservices-details.component.ts | 59 +++++++++++++++++++ .../dataservices-list.component.css | 5 ++ .../dataservices-list.component.html | 2 +- .../dataservices-list.component.spec.ts | 4 +- .../dataservices.component.spec.ts | 4 +- .../app/dataservices/dataservices.module.ts | 4 +- .../shared/dataservices-constants.ts | 3 + 11 files changed, 86 insertions(+), 56 deletions(-) delete mode 100644 ngapp/src/app/dataservices/dataservices-list/basic-content.component.html delete mode 100644 ngapp/src/app/dataservices/dataservices-list/basic-content.component.ts create mode 100644 ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.html create mode 100644 ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts diff --git a/ngapp/src/app/connections/connections-list/connection-details.component.html b/ngapp/src/app/connections/connections-list/connection-details.component.html index 1dc06f2e..5b7bfe52 100644 --- a/ngapp/src/app/connections/connections-list/connection-details.component.html +++ b/ngapp/src/app/connections/connections-list/connection-details.component.html @@ -1,4 +1,3 @@ -
    Properties
    -
    -

    - Name -

    -

    - {{ item.getId() }} -

    -

    - Description -

    -

    - {{ item.getDescription() }} -

    -
    -
    diff --git a/ngapp/src/app/dataservices/dataservices-list/basic-content.component.ts b/ngapp/src/app/dataservices/dataservices-list/basic-content.component.ts deleted file mode 100644 index 015dc33a..00000000 --- a/ngapp/src/app/dataservices/dataservices-list/basic-content.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, Input, ViewEncapsulation } from "@angular/core"; - -@Component({ - encapsulation: ViewEncapsulation.None, - selector: "app-basic-content", - templateUrl: "basic-content.component.html" -}) -export class BasicContentComponent { - @Input() public item: any; - - constructor() { - // nothing to do - } - -} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.html new file mode 100644 index 00000000..9d534b20 --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.html @@ -0,0 +1,12 @@ + + +
    +
    {{ item[ 0 ] }}
    +
    {{ item[ 1 ] }}
    +
    +
    +
    diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts new file mode 100644 index 00000000..e8227d8d --- /dev/null +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { ListConfig } from "patternfly-ng"; +import { DataservicesConstants } from "../shared/dataservices-constants"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-dataservices-details", + templateUrl: "dataservices-details.component.html" +}) +export class DataservicesDetailsComponent implements OnInit { + @Input() public item: Dataservice; + + public listConfig: ListConfig; + + constructor() { + // nothing to do + } + + public ngOnInit(): void { + this.listConfig = { + dblClick: false, + multiSelect: false, + selectItems: false, + showCheckbox: false, + useExpandItems: false + }; + } + + /** + * @returns {string[][]} the properties of a dataservice + */ + public get properties(): string[][] { + const props = [ + [ DataservicesConstants.dataserviceNameLabel, this.item.getId() ], + [ DataservicesConstants.descriptionLabel, this.item.getDescription() ] + ]; + + return props; + } + +} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css index bde71f9e..ef78a19d 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css @@ -31,3 +31,8 @@ a.list-pf-title.view-name { color: var(--card-body-color); margin-left: 10px !important; } + +.dataservices-details-properties { + padding-left: 40px; +} + diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index 608ab6fd..42b6300e 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -75,7 +75,7 @@ - + diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts index a054ea1f..ffd92d2b 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts @@ -1,7 +1,7 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; import { LoggerService } from "@core/logger.service"; -import { BasicContentComponent } from "@dataservices/dataservices-list/basic-content.component"; +import { DataservicesDetailsComponent } from "@dataservices/dataservices-list/dataservices-details.component"; import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; import { ViewsContentComponent } from "@dataservices/dataservices-list/views-content.component"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -13,7 +13,7 @@ describe("DataservicesListComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ PatternFlyNgModule, RouterTestingModule ], - declarations: [ BasicContentComponent, DataservicesListComponent, ViewsContentComponent ], + declarations: [ DataservicesDetailsComponent, DataservicesListComponent, ViewsContentComponent ], providers: [ LoggerService ] }) .compileComponents().then(() => { diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index 7b0c4b02..56ba94db 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -10,7 +10,7 @@ import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { DataserviceCardComponent } from "@dataservices/dataservices-cards/dataservice-card/dataservice-card.component"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; -import { BasicContentComponent } from "@dataservices/dataservices-list/basic-content.component"; +import { DataservicesDetailsComponent } from "@dataservices/dataservices-list/dataservices-details.component"; import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; import { ViewsContentComponent } from "@dataservices/dataservices-list/views-content.component"; import { DataservicesComponent } from "@dataservices/dataservices.component"; @@ -34,7 +34,7 @@ describe("DataservicesComponent", () => { TestBed.configureTestingModule({ imports: [ CoreModule, FormsModule, HttpModule, ModalModule.forRoot(), PatternFlyNgModule, RouterTestingModule, SharedModule, CodemirrorModule ], - declarations: [ BasicContentComponent, + declarations: [ DataservicesDetailsComponent, DataservicesComponent, DataservicesListComponent, DataservicesCardsComponent, diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 79f579ce..5b3ff8d2 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -24,7 +24,7 @@ import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { LoggerService } from "@core/logger.service"; import { DataservicesCardsComponent } from "@dataservices/dataservices-cards/dataservices-cards.component"; -import { BasicContentComponent } from "@dataservices/dataservices-list/basic-content.component"; +import { DataservicesDetailsComponent } from "@dataservices/dataservices-list/dataservices-details.component"; import { DataservicesListComponent } from "@dataservices/dataservices-list/dataservices-list.component"; import { ViewsContentComponent } from "@dataservices/dataservices-list/views-content.component"; import { DataservicesRoutingModule } from "@dataservices/dataservices-routing.module"; @@ -61,7 +61,7 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co CodemirrorModule ], declarations: [ - BasicContentComponent, + DataservicesDetailsComponent, ViewsContentComponent, DataservicesCardsComponent, DataservicesComponent, diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ngapp/src/app/dataservices/shared/dataservices-constants.ts index 0874b584..56c6c79c 100644 --- a/ngapp/src/app/dataservices/shared/dataservices-constants.ts +++ b/ngapp/src/app/dataservices/shared/dataservices-constants.ts @@ -29,6 +29,9 @@ export class DataservicesConstants { public static readonly testDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/test-dataservice"; public static readonly testDataservicePath = DataservicesConstants.dataservicesRootPath + "/test-dataservice"; + public static dataserviceNameLabel = "Name"; + public static descriptionLabel = "Description"; + public static readonly dataservicesNavItem: NavigationItemConfig = { title: "Data Services", iconStyleClass: "fa fa-fw fa-table", From 060290aae5deb33884e5b0921e4eaa21404b4406 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Thu, 29 Mar 2018 16:31:48 +0100 Subject: [PATCH 122/205] Updates the associated connection of komodo model source * Due to change in naming of associated connection to origin connection in komodo's model source, update references accordingly. --- .../app/dataservices/shared/vdb-model-source.model.ts | 10 +++++----- ngapp/src/app/dataservices/shared/vdb.service.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts b/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts index 6d9594ef..35b11fc7 100644 --- a/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts +++ b/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts @@ -25,7 +25,7 @@ export class VdbModelSource { private keng__kType = "VdbModelSource"; private vdb__sourceJndiName: string; private vdb__sourceTranslator: string; - private tko__associatedConnection: string; + private vdb__originConnection: string; /** * @param {Object} json the JSON representation of a VdbModelSource @@ -79,8 +79,8 @@ export class VdbModelSource { /** * @returns {string} the associated connection path (can be null) */ - public getAssociatedConnection(): string { - return this.tko__associatedConnection; + public getOriginConnection(): string { + return this.vdb__originConnection; } /** @@ -114,8 +114,8 @@ export class VdbModelSource { /** * @param {string} connectionPath the path to the associated connection (optional) */ - public setAssociatedConnection( connectionPath?: string ): void { - this.tko__associatedConnection = connectionPath ? connectionPath : null; + public setOriginConnection( connectionPath?: string ): void { + this.vdb__originConnection = connectionPath ? connectionPath : null; } /** diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 277f4aa4..e31f05c8 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -377,7 +377,7 @@ export class VdbService extends ApiService { vdbModelSource.setDataPath(vdbPath + "/" + vdbModelName + "/vdb:sources/" + vdbModelSourceName); vdbModelSource.setJndiName(connection.getJndiName()); vdbModelSource.setTranslatorName(connection.getDriverName()); - vdbModelSource.setAssociatedConnection(connection.getDataPath()); + vdbModelSource.setOriginConnection(connection.getDataPath()); // Chain the individual calls together in series to build the Vdb and deploy it return this.deleteVdbIfFound(vdb.getId()) From 1d3d45f37f43d83e4eabfbdefaefff743e2149ca Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Tue, 3 Apr 2018 12:50:04 -0500 Subject: [PATCH 123/205] Added "published status" icon and overrode pf css to better align the icon. --- .../dataservices-list.component.css | 5 ++ .../dataservices-list.component.html | 51 +++++++++++++++++-- ngapp/src/environments/environment.ts | 2 +- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css index ef78a19d..db294ebd 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css @@ -36,3 +36,8 @@ a.list-pf-title.view-name { padding-left: 40px; } +.list-pf:not(.list-pf-stacked) .list-pf-main-content > * + * { + margin-left: 10px; +} + + diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index 42b6300e..7735e077 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -19,11 +19,52 @@
    - - - - - + + + + + + + + + + + + + + + + + + + + + {{ item.getId() }}
    {{ getDescription( item ) }}
    diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index 658a4ac2..7cd88872 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -59,6 +59,6 @@ export const environment = { komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service", // Indicates if in UI development mode where OpenShift will not be used. - uiDevMode: false + uiDevMode: true }; From a51f744032180d0b9e8dd5af2821c9686010bb1c Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Tue, 3 Apr 2018 19:26:41 +0100 Subject: [PATCH 124/205] Check the paths of node and ng to ensure availability * The script assumes ng has been installed and added to the user path. However, this is not always the case, resulting in 'ng command not found' errors when trying to run the beetle-studio image. * Checks the existence of both node and ng and ensures that the latter is using the one installed by npm in beetle-studio's own node_modules directory. --- ngapp/start.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ngapp/start.sh b/ngapp/start.sh index 05fa3cc9..993c3087 100755 --- a/ngapp/start.sh +++ b/ngapp/start.sh @@ -1,5 +1,15 @@ #!/bin/bash +# Check node is available +command -v node >/dev/null 2>&1 || { echo >&2 "Requires 'node' but it's not installed. Aborting."; exit 1; } + +# Check ng is available - should be post 'npm install' +NG="node_modules/.bin/ng" +if [ ! -f ${NG} ]; then + echo "Error: cannot find 'ng' so nothing can be executed... exiting" + exit 1 +fi + ################# # # Show help and exit @@ -26,7 +36,7 @@ done shift "$(expr $OPTIND - 1)" if [ "${DEV}" == "1" ]; then - ng serve --host 0.0.0.0 --port 8080 --disable-host-check + ${NG} serve --host 0.0.0.0 --port 8080 --disable-host-check else - ng build && node ./server.js + ${NG} build && node ./server.js fi From d5d7ecd795e4aa7ec9eb6470d63de5f4727441cd Mon Sep 17 00:00:00 2001 From: Ted Jones Date: Tue, 3 Apr 2018 17:04:47 -0500 Subject: [PATCH 125/205] Fix for spacing in views(more) for dataservices cards. --- .../dataservice-card/dataservice-card.component.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index 238206d8..4841bb89 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -49,3 +49,11 @@ a.list-pf-title.view-name { .views-details { background-color: var(--card-body-background-color); } + +.list-pf-container { + -ms-flex-align: start; + align-items: flex-start; + display: -ms-flexbox; + display: flex; + padding: 3px; +} From aeb7ac899750a18436e95437b4c3162bc3017b53 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 2 Mar 2018 13:55:17 -0600 Subject: [PATCH 126/205] sprint 3 work --- .../add-activity-wizard.component.spec.ts | 7 +- .../add-activity-wizard.component.ts | 8 +- .../add-activity.component.spec.ts | 7 +- .../add-connection-wizard.component.spec.ts | 5 + .../add-connection-wizard.component.ts | 18 +- .../add-connection.component.spec.ts | 5 + .../connection-card.component.css | 23 +++ .../connection-card.component.html | 42 ++++- .../connection-card.component.ts | 34 +++- .../connections-cards.component.spec.ts | 4 +- .../connections-cards.component.ts | 20 ++- .../connections-list.component.css | 7 + .../connections-list.component.html | 13 +- .../connections-list.component.ts | 47 ++--- .../connections/connections.component.html | 6 +- .../connections/connections.component.spec.ts | 24 ++- .../app/connections/connections.component.ts | 94 ++++++++-- .../src/app/connections/connections.module.ts | 20 ++- .../connections/shared/connection.model.ts | 56 ++++++ .../shared/connection.service.spec.ts | 4 +- .../connections/shared/connection.service.ts | 169 ++++++++++++++++-- .../shared/connections-constants.ts | 3 + .../shared/mock-connection.service.ts | 69 +++++-- .../add-dataservice-wizard.component.ts | 2 +- .../connection-table-selector.component.ts | 8 +- .../dataservice-card.component.html | 4 +- .../dataservice-card.component.ts | 18 +- .../dataservices-cards.component.ts | 2 +- .../dataservices-list.component.html | 11 +- .../dataservices-list.component.ts | 10 -- .../dataservices/dataservices.component.ts | 8 +- .../shared/connection-summary.model.ts | 98 ++++++++++ .../shared/dataservice.service.ts | 4 +- .../dataservices/shared/mock-vdb.service.ts | 2 +- .../shared/named-vdb-status.model.ts | 94 ++++++++++ .../dataservices/shared/notifier.service.ts | 24 +++ .../app/dataservices/shared/vdb.service.ts | 11 +- ngapp/src/app/shared/test-data.service.ts | 113 +++++++++++- ngapp/src/environments/environment.ts | 2 +- 39 files changed, 922 insertions(+), 174 deletions(-) create mode 100644 ngapp/src/app/dataservices/shared/connection-summary.model.ts create mode 100644 ngapp/src/app/dataservices/shared/named-vdb-status.model.ts diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts index 4af03340..0b26ba0f 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.spec.ts @@ -9,6 +9,9 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -23,9 +26,11 @@ describe("AddActivityWizardComponent", () => { imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], declarations: [ AddActivityWizardComponent, PropertyFormComponent, PropertyFormPropertyComponent ], providers: [ + NotifierService, { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ActivityService, useClass: MockActivityService }, - { provide: ConnectionService, useClass: MockConnectionService } + { provide: ConnectionService, useClass: MockConnectionService }, + { provide: VdbService, useClass: MockVdbService } ] }) .compileComponents().then(() => { diff --git a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts index 71d5532c..efe62838 100644 --- a/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts +++ b/ngapp/src/app/activities/add-activity-wizard/add-activity-wizard.component.ts @@ -127,9 +127,13 @@ export class AddActivityWizardComponent implements OnInit { this.connectionsLoadSuccess = false; const self = this; this.connectionService - .getAllConnections() + .getConnections(true, false) .subscribe( - (conns) => { + (connectionSummaries) => { + const conns = []; + for ( const connectionSummary of connectionSummaries ) { + conns.push(connectionSummary.getConnection()); + } self.allConnections = conns; self.connectionsLoading = false; self.connectionsLoadSuccess = true; diff --git a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts index 594de437..df1ca936 100644 --- a/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts +++ b/ngapp/src/app/activities/add-activity/add-activity.component.spec.ts @@ -10,6 +10,9 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddActivityComponent } from "./add-activity.component"; @@ -23,9 +26,11 @@ describe("AddActivityComponent", () => { imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], declarations: [ AddActivityComponent, AddActivityWizardComponent ], providers: [ + NotifierService, { provide: ActivityService, useClass: MockActivityService }, { provide: AppSettingsService, useClass: MockAppSettingsService }, - { provide: ConnectionService, useClass: MockConnectionService } + { provide: ConnectionService, useClass: MockConnectionService }, + { provide: VdbService, useClass: MockVdbService } ] }) .compileComponents().then(() => { diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts index 225e2d8a..eec91768 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts @@ -9,6 +9,9 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; @@ -28,6 +31,8 @@ describe("AddConnectionWizardComponent", () => { WizardService, { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ConnectionService, useClass: MockConnectionService }, + NotifierService, + { provide: VdbService, useClass: MockVdbService } ] }) .compileComponents().then(() => { diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index d44d3f3e..046e3660 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -367,9 +367,9 @@ export class AddConnectionWizardComponent implements OnInit { const self = this; if (this.wizardService.isEdit()) { - this.updateAndBindConnection(connection); + this.updateDeployConnection(connection); } else { - this.createAndBindConnection(connection); + this.createDeployConnection(connection); } } @@ -508,13 +508,14 @@ export class AddConnectionWizardComponent implements OnInit { } /** - * Creates the connection ensuring it is bound + * Creates the workspace connection, binds to serviceCatalogSource, + * and deploys a corresponding connection VDB to teiid. * @param {Connection} connection the new connection */ - private createAndBindConnection(connection: NewConnection): void { + private createDeployConnection(connection: NewConnection): void { const self = this; this.connectionService - .createAndBindConnection(connection) + .createDeployConnection(connection) .subscribe( (wasSuccess) => { self.setFinalPageComplete(wasSuccess); @@ -528,13 +529,14 @@ export class AddConnectionWizardComponent implements OnInit { } /** - * Updates the connection ensuring it is bound + * Updates the workspace connection, binds to serviceCatalogSource, + * and re-deploys the corresponding connection VDB to teiid. * @param {Connection} connection the new connection */ - private updateAndBindConnection(connection: NewConnection): void { + private updateDeployConnection(connection: NewConnection): void { const self = this; this.connectionService - .updateAndBindConnection(connection) + .updateDeployConnection(connection) .subscribe( (wasSuccess) => { self.setFinalPageComplete(wasSuccess); diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts index 195c79bb..b73984fb 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts +++ b/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts @@ -10,6 +10,9 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -25,9 +28,11 @@ describe("AddConnectionComponent", () => { declarations: [ AddConnectionComponent, AddConnectionWizardComponent, ConnectionTypeCardComponent, ConnectionTypeCardsComponent ], providers: [ + NotifierService, WizardService, { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: ConnectionService, useClass: MockConnectionService }, + { provide: VdbService, useClass: MockVdbService } ] }) .compileComponents().then(() => { diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css index e69de29b..248aca9a 100644 --- a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css +++ b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css @@ -0,0 +1,23 @@ +.card-toolbar .secondary-action[title="Activate"]:before { + color: var(--card-action-icon-color); + content: "\f1eb"; + font-family: "FontAwesome"; +} + +.object-card .list-pf, +.object-card-selected .list-pf { + border: none; +} + +.object-card .list-pf-item, +.object-card-selected .list-pf-item { + border: none; +} + +.object-card .list-pf-item:hover { + background-color: transparent; +} + +.object-card-selected .list-pf-item:hover { + background-color: transparent; +} diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html index 682bdca3..bfc2d859 100644 --- a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html +++ b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html @@ -11,17 +11,49 @@ (onActionSelect)="handleAction($event)">
    - + title="Active"> - + + + + + + + + + title="Edit"> + +
    diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts index 71969079..70fe1de5 100644 --- a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts +++ b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts @@ -29,12 +29,11 @@ import { Action, ActionConfig, CardAction, CardConfig, ListConfig } from "patter }) export class ConnectionCardComponent implements DoCheck, OnInit { + public static readonly activateConnectionEvent = "activate"; public static readonly deleteConnectionEvent = "delete"; public static readonly editConnectionEvent = "edit"; - public static readonly pingConnectionEvent = "ping"; public readonly editEvent = ConnectionCardComponent.editConnectionEvent; - public readonly pingEvent = ConnectionCardComponent.pingConnectionEvent; @Input() public connection: Connection; @Input() public selectedConnections: Connection[]; @@ -46,7 +45,12 @@ export class ConnectionCardComponent implements DoCheck, OnInit { public listConfig: ListConfig; public showDetails = false; + private readonly activateActionId = "activate"; + private readonly activateActionIndex = 0; // index in moreActions private readonly deleteActionId = "delete"; + private readonly deleteActionIndex = 1; // index in moreActions + + private isLoading = false; private logger: LoggerService; constructor( logger: LoggerService ) { @@ -62,7 +66,9 @@ export class ConnectionCardComponent implements DoCheck, OnInit { * @param {Action} action the action that was selected. */ public handleAction( action: Action ): void { - if ( action.id === this.deleteActionId ) { + if ( action.id === this.activateActionId ) { + this.onClick( ConnectionCardComponent.activateConnectionEvent); + } else if ( action.id === this.deleteActionId ) { this.onClick( ConnectionCardComponent.deleteConnectionEvent ); } else { this.logger.error( "Action '" + action.id + "' not handled." ); @@ -77,6 +83,13 @@ export class ConnectionCardComponent implements DoCheck, OnInit { } public ngDoCheck(): void { + if ( this.isLoading !== this.connection.schemaLoading ) { + this.isLoading = this.connection.schemaLoading; + + this.actionConfig.moreActions[ this.activateActionIndex ].disabled = this.isLoading; + this.actionConfig.moreActions[ this.deleteActionIndex ].disabled = this.isLoading; + } + this.cardConfig.action.iconStyleClass = this.detailsIconStyle; } @@ -88,11 +101,16 @@ export class ConnectionCardComponent implements DoCheck, OnInit { primaryActions: [ ], moreActions: [ - { - id: this.deleteActionId, - title: "Delete", - tooltip: "Delete the connection" - } + { + id: this.activateActionId, + title: "Activate", + tooltip: "Activate" + }, + { + id: this.deleteActionId, + title: "Delete", + tooltip: "Delete" + } ] } as ActionConfig; diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts index dd983ab8..df9a3339 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts @@ -2,6 +2,7 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { RouterTestingModule } from "@angular/router/testing"; import { ConnectionCardComponent } from "@connections/connections-cards/connection-card/connection-card.component"; import { ConnectionsCardsComponent } from "@connections/connections-cards/connections-cards.component"; +import { LoggerService } from "@core/logger.service"; import { PatternFlyNgModule } from "patternfly-ng"; describe("ConnectionsCardsComponent", () => { @@ -11,7 +12,8 @@ describe("ConnectionsCardsComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ PatternFlyNgModule, RouterTestingModule ], - declarations: [ ConnectionCardComponent, ConnectionsCardsComponent ] + declarations: [ ConnectionCardComponent, ConnectionsCardsComponent ], + providers: [ LoggerService ] }) .compileComponents().then(() => { // nothing to do diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts index 3d0397b2..a10e23ed 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.ts @@ -18,6 +18,7 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; import { ConnectionCardComponent } from "@connections/connections-cards/connection-card/connection-card.component"; import { Connection } from "@connections/shared/connection.model"; +import { LoggerService } from "@core/logger.service"; @Component({ moduleId: module.id, @@ -32,15 +33,17 @@ export class ConnectionsCardsComponent { @Output() public connectionSelected: EventEmitter = new EventEmitter(); @Output() public connectionDeselected: EventEmitter = new EventEmitter(); + @Output() public activateConnection: EventEmitter = new EventEmitter(); @Output() public deleteConnection: EventEmitter = new EventEmitter(); @Output() public editConnection: EventEmitter = new EventEmitter(); - @Output() public pingConnection: EventEmitter = new EventEmitter(); + + public logger: LoggerService; /** - * Constructor. + * @param {LoggerService} logger the logging service */ - constructor() { - // nothing to do + constructor( logger: LoggerService ) { + this.logger = logger; } public isSelected( connection: Connection ): boolean { @@ -53,15 +56,14 @@ export class ConnectionsCardsComponent { case ConnectionCardComponent.deleteConnectionEvent: this.deleteConnection.emit( event.connectionName ); break; + case ConnectionCardComponent.activateConnectionEvent: + this.activateConnection.emit( event.connectionName ); + break; case ConnectionCardComponent.editConnectionEvent: this.editConnection.emit( event.connectionName ); break; - case ConnectionCardComponent.pingConnectionEvent: - this.pingConnection.emit( event.connectionName ); - break; default: - // TODO log this - // this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); + this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); break; } } diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.css b/ngapp/src/app/connections/connections-list/connections-list.component.css index 619e03b9..a5408545 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.css +++ b/ngapp/src/app/connections/connections-list/connections-list.component.css @@ -1,3 +1,10 @@ +/* Adds an icon to the left of the activate action item in dropdown of kebab. */ +.object-list .secondary-action[title*="Activate"]:before { + color: var(--card-action-icon-color); + content: "\f1eb"; + font-family: "FontAwesome"; +} + .connection-details-properties { padding-left: 40px; } diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.html b/ngapp/src/app/connections/connections-list/connections-list.component.html index 47a70b04..cae18542 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.html +++ b/ngapp/src/app/connections/connections-list/connections-list.component.html @@ -19,20 +19,25 @@
    - {{ item.name }} + + + + + + {{ item.name }}
    {{ getDescription(item) }}
     {{ action.title }} - -  {{ action.title }} + +  {{ action.title }}  {{ action.title }} diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.ts b/ngapp/src/app/connections/connections-list/connections-list.component.ts index 4a907530..0ee92f48 100644 --- a/ngapp/src/app/connections/connections-list/connections-list.component.ts +++ b/ngapp/src/app/connections/connections-list/connections-list.component.ts @@ -34,16 +34,16 @@ export class ConnectionsListComponent implements OnInit { @Output() public connectionDeselected: EventEmitter = new EventEmitter(); @Output() public connectionSelected: EventEmitter = new EventEmitter(); + @Output() public activateConnection: EventEmitter = new EventEmitter(); @Output() public deleteConnection: EventEmitter = new EventEmitter(); @Output() public editConnection: EventEmitter = new EventEmitter(); - @Output() public pingConnection: EventEmitter = new EventEmitter(); public listConfig: ListConfig; private router: Router; - private readonly deleteActionId = "delecteActionId"; + private readonly activateActionId = "activateActionId"; + private readonly deleteActionId = "deleteActionId"; private readonly editActionId = "editActionId"; - private readonly pingActionId = "pingActionId"; /** * Constructor. @@ -72,35 +72,38 @@ export class ConnectionsListComponent implements OnInit { * * @param connection the connection represented by a row * @param editActionTemplate {TemplateRef} the edit action template - * @param pingActionTemplate {TemplateRef} the ping action template + * @param activateActionTemplate {TemplateRef} the activate action template * @param deleteActionTemplate {TemplateRef} the delete action template * @returns {ActionConfig} the actions configuration */ public getActionConfig( connection: Connection, editActionTemplate: TemplateRef< any >, - pingActionTemplate: TemplateRef< any >, + activateActionTemplate: TemplateRef< any >, deleteActionTemplate: TemplateRef< any > ): ActionConfig { const actionConfig = { primaryActions: [ { + disabled: connection.schemaLoading, id: this.editActionId, template: editActionTemplate, title: "Edit", - tooltip: "Edit properties" - }, - { - id: this.pingActionId, - template: pingActionTemplate, - title: "Ping", - tooltip: "Determine if accessible" + tooltip: "Edit this connection" } ], moreActions: [ { + disabled: connection.schemaLoading, + id: this.activateActionId, + template: activateActionTemplate, + title: "Activate", + tooltip: "Activate this connection" + }, + { + disabled: connection.schemaLoading, id: this.deleteActionId, template: deleteActionTemplate, title: "Delete", - tooltip: "Delete the connection" + tooltip: "Delete this connection" } ], moreActionsDisabled: false, @@ -133,10 +136,10 @@ export class ConnectionsListComponent implements OnInit { // now perform action if ( action.id === this.deleteActionId ) { this.onDeleteConnection( this.selectedConnections[ 0 ].getId() ); + } else if ( action.id === this.activateActionId ) { + this.onActivateConnection( this.selectedConnections[ 0 ].getId() ); } else if ( action.id === this.editActionId ) { this.onEditConnection( this.selectedConnections[ 0 ].getId() ); - } else if ( action.id === this.pingActionId ) { - this.onPingConnection( this.selectedConnections[ 0 ].getId() ); } } @@ -147,6 +150,13 @@ export class ConnectionsListComponent implements OnInit { return this.selectedConnections.indexOf( connection ) !== -1; } + /** + * @param {string} connectionName the name of the connection to activate + */ + public onActivateConnection(connectionName: string): void { + this.activateConnection.emit(connectionName); + } + /** * @param {string} connectionName the name of the connection to delete */ @@ -161,13 +171,6 @@ export class ConnectionsListComponent implements OnInit { this.editConnection.emit( connectionName ); } - /** - * @param {string} connectionName the name of the connection to ping - */ - public onPingConnection( connectionName: string ): void { - this.pingConnection.emit( connectionName ); - } - /** * @param $event the list row selection event being handled */ diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index 01257b1a..70796825 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -41,7 +41,7 @@

    Connections

    + (onActionSelect)="onNew()">
    @@ -66,16 +66,16 @@

    diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ngapp/src/app/connections/connections.component.spec.ts index 258a92b6..0e7c34b7 100644 --- a/ngapp/src/app/connections/connections.component.spec.ts +++ b/ngapp/src/app/connections/connections.component.spec.ts @@ -13,6 +13,9 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SharedModule } from "@shared/shared.module"; import { ModalModule } from "ngx-bootstrap"; @@ -41,20 +44,15 @@ describe("ConnectionsComponent", () => { ConnectionsCardsComponent ], providers: [ - WizardService + AppSettingsService, + NotifierService, + WizardService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: ConnectionService, useClass: MockConnectionService }, + { provide: VdbService, useClass: MockVdbService } ] }); - // use mock service - TestBed.overrideComponent( ConnectionsComponent, { - set: { - providers: [ - { provide: AppSettingsService, useClass: MockAppSettingsService }, - { provide: ConnectionService, useClass: MockConnectionService }, - ] - } - }); - fixture = TestBed.createComponent(ConnectionsComponent); component = fixture.componentInstance; fixture.detectChanges(); @@ -84,12 +82,12 @@ describe("ConnectionsComponent", () => { console.log("========== [ConnectionsComponent] should have Connections"); // Check component object const connections = component.allConnections; - expect(connections.length).toEqual(4); + expect(connections.length).toEqual(3); // Check html has the same number of connection cards const cardDebugElems = fixture.debugElement.queryAll(By.css(".object-card")); expect(cardDebugElems).toBeDefined(); - expect(cardDebugElems.length).toEqual(4); + expect(cardDebugElems.length).toEqual(3); }); it("should have initial card layout", () => { diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 10a63b9b..33a7bac1 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -22,6 +22,8 @@ import { ConnectionService } from "@connections/shared/connection.service"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { NotifierService } from "@dataservices/shared/notifier.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; @@ -30,10 +32,11 @@ import { ActionConfig, EmptyStateConfig, Filter } from "patternfly-ng"; import { FilterConfig } from "patternfly-ng"; import { FilterField } from "patternfly-ng"; import { FilterEvent } from "patternfly-ng"; -import { FilterType } from "patternfly-ng"; import { SortConfig } from "patternfly-ng"; import { SortField } from "patternfly-ng"; import { SortEvent } from "patternfly-ng"; +import { FilterType } from "patternfly-ng"; +import { Subscription } from "rxjs/Subscription"; @Component({ moduleId: module.id, @@ -60,16 +63,24 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni private appSettingsService: AppSettingsService; private connectionService: ConnectionService; private wizardService: WizardService; + private notifierService: NotifierService; + private connectionVdbStateSubscription: Subscription; @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; constructor(router: Router, route: ActivatedRoute, appSettingsService: AppSettingsService, - wizardService: WizardService, connectionService: ConnectionService, logger: LoggerService) { + wizardService: WizardService, connectionService: ConnectionService, logger: LoggerService, + notifierService: NotifierService, ) { super(route, logger); this.router = router; this.appSettingsService = appSettingsService; this.connectionService = connectionService; this.wizardService = wizardService; + this.notifierService = notifierService; + // Register for connection VDB state changes + this.connectionVdbStateSubscription = this.notifierService.getConnectionStateMap().subscribe((connectionStateMap) => { + this.onConnectionVdbStateChanged(connectionStateMap); + }); } public ngOnInit(): void { @@ -133,11 +144,16 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni const self = this; this.connectionService - .getAllConnections() + .getConnections(true, false) .subscribe( - (connections) => { - self.allConns = connections; - self.filteredConns = connections; + (connectionSummaries) => { + const conns = []; + for ( const connSummary of connectionSummaries ) { + conns.push(connSummary.getConnection()); + } + self.allConns = conns; + self.filteredConns = conns; + self.connectionService.updateConnectionSchemaStates(); // triggers refresh to get latest connection states self.loaded("connections"); }, (error) => { @@ -181,11 +197,6 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni return this.selectedConns; } - public onPing( connName: string ): void { - // TODO: implement onEdit - alert( "Ping the '" + connName + "' connection (not yet implemented)" ); - } - public onSelected(connection: Connection): void { // Only allow one item to be selected this.selectedConns.shift(); @@ -214,7 +225,7 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni /** * Handle request for new Connection */ - public onNewConnection(): void { + public onNew(): void { this.wizardService.setEdit(false); const link: string[] = [ ConnectionsConstants.addConnectionPath ]; @@ -242,6 +253,28 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni }); } + /** + * Handle Activation of the specified Connection. Initiates refresh of the connection schema. + * @param {string} connName + */ + public onActivate(connName: string): void { + const selectedConnection = this.filteredConnections.find((x) => x.getId() === connName); + selectedConnection.setSchemaState(DeploymentState.LOADING); + + const self = this; + // Start the connection deployment + this.connectionService + .refreshConnectionSchema(connName) + .subscribe( + (wasSuccess) => { + self.connectionService.updateConnectionSchemaStates(); + }, + (error) => { + self.connectionService.updateConnectionSchemaStates(); + } + ); + } + /** * Called to doDelete all selected APIs. */ @@ -258,6 +291,7 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni .deleteConnection(selectedConn.getId()) .subscribe( (wasSuccess) => { + self.deleteUndeployConnectionVdb(selectedConn.getId()); self.removeConnectionFromList(selectedConn); const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; self.logger.log("[CreateApiPageComponent] Navigating to: %o", link); @@ -341,7 +375,43 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni this.filteredConnections.sort((item1: Connection, item2: Connection) => this.compare(item1, item2)); } + /** + * Delete the specified connection's VDB from the repo (if it exists) and undeploy it from teiid (if it exists) + * @param {string} connectionId + */ + private deleteUndeployConnectionVdb(connectionId: string): void { + const self = this; + this.connectionService + .deleteUndeployConnectionVdb(connectionId) + .subscribe( + (wasSuccess) => { + // nothing to do + }, + (error) => { + // nothing to do + } + ); + } + + /** + * Remove the specified connection from the connections list + * @param {Connection} connection + */ private removeConnectionFromList(connection: Connection): void { this.allConns.splice(this.allConns.indexOf(connection), 1); } + + /* + * Update the displayed connection states using the provided states + */ + private onConnectionVdbStateChanged(stateMap: Map): void { + // For displayed dataservices, update the State using supplied services + for ( const conn of this.filteredConns ) { + const connId = conn.getId(); + if (stateMap && stateMap.has(connId)) { + conn.setSchemaState(stateMap.get(connId)); + } + } + } + } diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index d69833fb..63551b44 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -33,6 +33,8 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { LoggerService } from "@core/logger.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { environment } from "@environments/environment"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -66,7 +68,7 @@ import { ConnectionTypeCardsComponent } from "./connection-type-cards/connection { provide: ConnectionService, useFactory: connectionServiceFactory, - deps: [ Http, AppSettingsService, LoggerService ], + deps: [ Http, VdbService, NotifierService, AppSettingsService, LoggerService ], multi: false }, LoggerService @@ -80,13 +82,25 @@ export class ConnectionsModule { } * A factory that produces the appropriate instande of the service based on current environment settings. * * @param {Http} http the HTTP service + * @param {VdbService} vdbService the vdb service + * @param {NotifierService} notifierService the notifier service * @param {AppSettingsService} appSettings the app settings service * @param {LoggerService} logger the logger * @returns {ConnectionService} the requested service */ export function connectionServiceFactory( http: Http, + vdbService: VdbService, + notifierService: NotifierService, appSettings: AppSettingsService, logger: LoggerService ): ConnectionService { - return environment.production || !environment.uiDevMode ? new ConnectionService( http, appSettings, logger ) - : new MockConnectionService( http, appSettings, logger ); + return environment.production || !environment.uiDevMode ? new ConnectionService( http, + vdbService, + notifierService, + appSettings, + logger ) + : new MockConnectionService( http, + vdbService, + notifierService, + appSettings, + logger ); } diff --git a/ngapp/src/app/connections/shared/connection.model.ts b/ngapp/src/app/connections/shared/connection.model.ts index 89f121d9..83a3f4c4 100644 --- a/ngapp/src/app/connections/shared/connection.model.ts +++ b/ngapp/src/app/connections/shared/connection.model.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; import { Identifiable } from "@shared/identifiable"; import { SortDirection } from "@shared/sort-direction.enum"; @@ -29,6 +30,7 @@ export class Connection implements Identifiable< string > { private dv__driverName: string; private dv__type: boolean; private keng__properties: object[] = []; + private schemaState: DeploymentState = DeploymentState.LOADING; /** * @param {Object} json the JSON representation of a Connection @@ -153,6 +155,53 @@ export class Connection implements Identifiable< string > { return serviceCatalogName; } + /** + * @returns {DeploymentState} the connection schema state + */ + public getSchemaState(): DeploymentState { + return this.schemaState; + } + + /** + * Accessor to determine if connection schema is active + * @returns {boolean} the connection schema active state + */ + public get schemaActive(): boolean { + return this.schemaState === DeploymentState.ACTIVE; + } + + /** + * Accessor to determine if connection schema is inactive + * @returns {boolean} the connection schema inactive state + */ + public get schemaInactive(): boolean { + return this.schemaState === DeploymentState.INACTIVE; + } + + /** + * Accessor to determine if connection schema is loading + * @returns {boolean} the connection schema loading state + */ + public get schemaLoading(): boolean { + return this.schemaState === DeploymentState.LOADING; + } + + /** + * Accessor to determine if connection schema is failed + * @returns {boolean} the connection schema failed state + */ + public get schemaFailed(): boolean { + return this.schemaState === DeploymentState.FAILED; + } + + /** + * Accessor to determine if connection schema is not deployed + * @returns {boolean} the connection schema not deployed state + */ + public get schemaNotDeployed(): boolean { + return this.schemaState === DeploymentState.NOT_DEPLOYED; + } + /** * @param {string} driverName the connection driver name (optional) */ @@ -196,6 +245,13 @@ export class Connection implements Identifiable< string > { this.keng__properties.push(prop); } + /** + * @param {DeploymentState} state the connection schema state + */ + public setSchemaState( state: DeploymentState ): void { + this.schemaState = state; + } + /** * Set all object values using the supplied Connection json * @param {Object} values diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ngapp/src/app/connections/shared/connection.service.spec.ts index 30ee6b1c..0cd00920 100644 --- a/ngapp/src/app/connections/shared/connection.service.spec.ts +++ b/ngapp/src/app/connections/shared/connection.service.spec.ts @@ -3,12 +3,14 @@ import { HttpModule } from "@angular/http"; import { ConnectionService } from "@connections/shared/connection.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; describe("ConnectionService", () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpModule ], - providers: [AppSettingsService, ConnectionService, LoggerService] + providers: [AppSettingsService, ConnectionService, LoggerService, NotifierService, VdbService] }); }); diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index 586c4be9..ac4a0d84 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -18,7 +18,6 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { ConnectionType } from "@connections/shared/connection-type.model"; -import { Connection } from "@connections/shared/connection.model"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { JdbcTableFilter } from "@connections/shared/jdbc-table-filter.model"; import { NewConnection } from "@connections/shared/new-connection.model"; @@ -28,10 +27,15 @@ import { TemplateDefinition } from "@connections/shared/template-definition.mode import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { ConnectionSummary } from "@dataservices/shared/connection-summary.model"; +import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { NotifierService } from "@dataservices/shared/notifier.service"; import { Table } from "@dataservices/shared/table.model"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { environment } from "@environments/environment"; import { PropertyDefinition } from "@shared/property-form/property-definition.model"; import { Observable } from "rxjs/Observable"; +import { Subscription } from "rxjs/Subscription"; @Injectable() export class ConnectionService extends ApiService { @@ -39,12 +43,24 @@ export class ConnectionService extends ApiService { private static readonly nameValidationUrl = environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath + "/nameValidation/"; + private static readonly refreshConnectionSchemaUrl = environment.komodoWorkspaceUrl + + ConnectionsConstants.connectionsRootPath + + "/refresh-schema/"; private http: Http; + private updatesSubscription: Subscription; + private notifierService: NotifierService; + private vdbService: VdbService; + private cachedConnectionVdbStates: Map = new Map(); - constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { + constructor( http: Http, vdbService: VdbService, notifierService: NotifierService, + appSettings: AppSettingsService, logger: LoggerService ) { super( appSettings, logger ); this.http = http; + this.vdbService = vdbService; + this.notifierService = notifierService; + // Polls to fire Connection VDB state updates every 15 sec + this.pollConnectionSchemaStatus(15); } /** @@ -74,29 +90,42 @@ export class ConnectionService extends ApiService { } /** - * Get the connections from the komodo rest interface - * @returns {Observable} + * Get the connection summaries from the komodo rest interface. The supplied parameters determine what portions + * of the ConnectionSummary are returned. + * - include-connection=true (include connection [default=true]) + * - include-schema-status=true (include schema vdb status [default=false]) + * @param {boolean} includeConnection 'true' to include connection + * @param {boolean} includeSchemaStatus 'true' to include connection schema status + * @returns {Observable} */ - public getAllConnections(): Observable { + public getConnections(includeConnection: boolean, includeSchemaStatus: boolean): Observable { + // Build the url with parameters + const connectionsUrl = this.buildGetConnectionsUrl(includeConnection, includeSchemaStatus); + return this.http - .get(environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath, this.getAuthRequestOptions()) + .get(connectionsUrl, this.getAuthRequestOptions()) .map((response) => { - const connections = response.json(); - return connections.map((connection) => Connection.create( connection )); + const connectionSummaries = response.json(); + return connectionSummaries.map((connectionSummary) => ConnectionSummary.create( connectionSummary )); }) .catch( ( error ) => this.handleError( error ) ); } /** - * Deploy a connection via the komodo rest interface + * Initiates a refresh of the connection schema via the komodo rest interface * @param {string} connectionName * @returns {Observable} */ - public deployConnection(connectionName: string): Observable { + public refreshConnectionSchema(connectionName: string): Observable { + if ( !connectionName || connectionName.length === 0 ) { + return Observable.of( false ); + } + + const url = ConnectionService.refreshConnectionSchemaUrl + encodeURIComponent( connectionName ); + const connectionPath = this.getKomodoUserWorkspacePath() + "/" + connectionName; return this.http - .post(environment.komodoTeiidUrl + ConnectionsConstants.connectionRootPath, - { path: connectionPath}, this.getAuthRequestOptions()) + .post( url, this.getAuthRequestOptions() ) .map((response) => { return response.ok; }) @@ -273,4 +302,120 @@ export class ConnectionService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Creates a workspace Connection, binds it to the specified serviceCatalogSource, and initiates + * a refresh of the connection schema. + * @param {NewConnection} connection the connection object + * @returns {Observable} + */ + public createDeployConnection(connection: NewConnection): Observable { + return this.createAndBindConnection(connection) + .flatMap((res) => this.refreshConnectionSchema(connection.getName())); + } + + /** + * Updates a workspace Connection, binds it to the specified serviceCatalogSource, and initiates + * a refresh of the connection schema. + * @param {NewConnection} connection the connection object + * @returns {Observable} + */ + public updateDeployConnection(connection: NewConnection): Observable { + return this.updateAndBindConnection(connection) + .flatMap((res) => this.refreshConnectionSchema(connection.getName())); + } + + /** + * Delete the repo Connection VDB (if it exists) and undeploy the Connection VDB + * (if exists) + * @param {string} connectionId + * @returns {Observable} + */ + public deleteUndeployConnectionVdb(connectionId: string): Observable { + const vdbName = connectionId + "BtlConn"; + return this.vdbService.deleteVdbIfFound(vdbName) + .flatMap((res) => this.vdbService.undeployVdb(vdbName)); + } + + /** + * Updates the current Connecton VDB states - triggers update to be broadcast to interested components + */ + public updateConnectionSchemaStates(): void { + const self = this; + this.getConnections(false, true) + .subscribe( + (connectionSummaries) => { + self.cachedConnectionVdbStates = self.createConnectionSchemaStateMap(connectionSummaries); + this.notifierService.sendConnectionStateMap(self.cachedConnectionVdbStates); + }, + (error) => { + // On error, broadcast the cached states + this.notifierService.sendConnectionStateMap(self.cachedConnectionVdbStates); + } + ); + } + + /** + * Polls the server and sends Connection schema state updates at the specified interval + * @param {number} pollIntervalSec the interval (sec) between polling attempts + */ + public pollConnectionSchemaStatus(pollIntervalSec: number): void { + const pollIntervalMillis = pollIntervalSec * 1000; + + const self = this; + // start the timer + const timer = Observable.timer(500, pollIntervalMillis); + this.updatesSubscription = timer.subscribe((t: any) => { + self.updateConnectionSchemaStates(); + }); + } + + /** + * Build the getConnection Url based on the supplied parameters. + * @param {boolean} includeConnection 'true' to include connection, 'false' to omit + * @param {boolean} includeSchemaStatus 'true' to include connection schema status, 'false' to omit + */ + private buildGetConnectionsUrl(includeConnection: boolean, includeSchemaStatus: boolean): string { + // Base getConnections service url + const connectionsUrl = environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath; + + // Additional parameters + const urlParams = "?" + ConnectionsConstants.includeConnectionParameter + "=" + String(includeConnection) + + "&" + ConnectionsConstants.includeSchemaStatusParameter + "=" + String(includeSchemaStatus); + + return connectionsUrl + urlParams; + } + + /* + * Creates a Map of connection name to DeploymentState + * @param {ConnectionSummary[]} connectionSummaries the array of ConnectionSummary objects + * @returns {Map} the map of connection name to DeploymentState + */ + private createConnectionSchemaStateMap(connectionSummaries: ConnectionSummary[]): Map { + const connStateMap: Map = new Map(); + + // For each connection, determine its status. Add the map entry + for ( const connectionSummary of connectionSummaries ) { + if (connectionSummary.hasNamedVdbStatus()) { + const namedVdbStatus = connectionSummary.getNamedVdbStatus(); + const connName = namedVdbStatus.getName(); + if ( !namedVdbStatus.hasVdbStatus() ) { + connStateMap.set(connName, DeploymentState.NOT_DEPLOYED); + } else { + const vdbStatus = namedVdbStatus.getVdbStatus(); + if ( vdbStatus.isFailed() ) { + connStateMap.set(connName, DeploymentState.FAILED); + } else if ( vdbStatus.isActive() ) { + connStateMap.set(connName, DeploymentState.ACTIVE); + } else if ( vdbStatus.isLoading() ) { + connStateMap.set(connName, DeploymentState.LOADING); + } else { + connStateMap.set(connName, DeploymentState.INACTIVE); + } + } + } + } + + return connStateMap; + } + } diff --git a/ngapp/src/app/connections/shared/connections-constants.ts b/ngapp/src/app/connections/shared/connections-constants.ts index fc9adea3..435798ce 100644 --- a/ngapp/src/app/connections/shared/connections-constants.ts +++ b/ngapp/src/app/connections/shared/connections-constants.ts @@ -36,6 +36,9 @@ export class ConnectionsConstants { public static readonly connectionTypeDescription_mongodb = "MongoDB database"; public static readonly connectionTypeDescription_mariadb = "MariaDB database"; + public static readonly includeConnectionParameter = "include-connection"; + public static readonly includeSchemaStatusParameter = "include-schema-status"; + public static driverNamePropertyLabel = "Driver Name"; public static jndiNamePropertyLabel = "JNDI Name"; public static serviceCatalogSourceNameLabel = "Service Catalog Source"; diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 734f496d..e883a679 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -25,6 +25,10 @@ import { SchemaInfo } from "@connections/shared/schema-info.model"; import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; +import { ConnectionSummary } from "@dataservices/shared/connection-summary.model"; +import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; import { TestDataService } from "@shared/test-data.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; @@ -39,19 +43,26 @@ export class MockConnectionService extends ConnectionService { private serviceCatalogSources: ServiceCatalogSource[]; private connectionSourceSchemaInfoMap: Map; private tableMap = new Map(); + private testDataService: TestDataService; - constructor( http: Http, appSettings: AppSettingsService, logger: LoggerService ) { - super(http, appSettings, logger); + constructor( http: Http, vdbService: VdbService, notifierService: NotifierService, + appSettings: AppSettingsService, logger: LoggerService ) { + super(http, vdbService, notifierService, appSettings, logger); // Inject service for test data const injector = ReflectiveInjector.resolveAndCreate([TestDataService]); - const testDataService = injector.get(TestDataService); + this.testDataService = injector.get(TestDataService); // Get test data - this.connections = testDataService.getConnections(); - this.serviceCatalogSources = testDataService.getServiceCatalogSources(); - this.connectionSourceSchemaInfoMap = testDataService.getConnectionSourceSchemaInfoMap(); - this.tableMap = testDataService.getJdbcConnectionTableMap(); + const conns: Connection[] = []; + const connSummaries: ConnectionSummary[] = this.testDataService.getConnectionSummaries(true, true); + for ( const connSummary of connSummaries ) { + conns.push(connSummary.getConnection()); + } + this.connections = conns; + this.serviceCatalogSources = this.testDataService.getServiceCatalogSources(); + this.connectionSourceSchemaInfoMap = this.testDataService.getConnectionSourceSchemaInfoMap(); + this.tableMap = this.testDataService.getJdbcConnectionTableMap(); } public isValidName( name: string ): Observable< string > { @@ -81,11 +92,16 @@ export class MockConnectionService extends ConnectionService { } /** - * Get the connections from the komodo rest interface - * @returns {Observable} + * Get the connection summaries from the komodo rest interface. The supplied parameters determine what portions + * of the ConnectionSummary are returned. + * - include-connection=true (include connection [default=true]) + * - include-schema-status=true (include schema vdb status [default=false]) + * @param {boolean} includeConnection 'true' to include connection + * @param {boolean} includeSchemaStatus 'true' to include connection schema status + * @returns {Observable} */ - public getAllConnections(): Observable { - return Observable.of(this.connections); + public getConnections(includeConnection: boolean, includeSchemaStatus: boolean): Observable { + return Observable.of(this.testDataService.getConnectionSummaries(includeConnection, includeSchemaStatus)); } /** @@ -147,4 +163,35 @@ export class MockConnectionService extends ConnectionService { return Observable.of(true); } + /** + * Initiates a refresh of the connection schema via the komodo rest interface + * @param {string} connectionName + * @returns {Observable} + */ + public refreshConnectionSchema(connectionName: string): Observable { + if ( !connectionName || connectionName.length === 0 ) { + return Observable.of( false ); + } + + return Observable.of( true ); + } + + /** + * Updates the current Connection schema states - triggers update to be broadcast to interested components + */ + public updateConnectionSchemaStates(): void { + // Set the schema state to active to enable actions + for ( const conn of this.connections ) { + conn.setSchemaState(DeploymentState.ACTIVE); + } + } + + /** + * Polls the server and sends Connection state updates at the specified interval + * @param {number} pollIntervalSec the interval (sec) between polling attempts + */ + public pollConnectionSchemaStatus(pollIntervalSec: number): void { + // Nothing to do + } + } diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index da0251c1..7acff85e 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -286,7 +286,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { const self = this; this.vdbService - .deployVdbForTables(this.tableSelector.getSelectedTables()) + .deployVdbForConnection(this.tableSelector.getSelectedTables()[0].getConnection()) .subscribe( (wasSuccess) => { // Deployment succeeded - wait for source vdb to become active diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts index da1b42dc..b2f4ef22 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts @@ -121,9 +121,13 @@ export class ConnectionTableSelectorComponent implements OnInit { this.connectionLoadingState = LoadingState.LOADING; const self = this; this.connectionService - .getAllConnections() + .getConnections(true, false) .subscribe( - (conns) => { + (connectionSummaries) => { + const conns = []; + for ( const connectionSummary of connectionSummaries ) { + conns.push(connectionSummary.getConnection()); + } self.allConnections = conns; self.filteredConnections = conns; self.connectionLoadingState = LoadingState.LOADED_VALID; diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index 00288342..58e08edc 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -31,8 +31,8 @@ data-placement="right" title="Inactive"> - - - + - - - + {{ item.getId() }}
    {{ getDescription( item ) }}

    @@ -86,7 +83,6 @@ activateActionTemplate, publishActionTemplate, downloadActionTemplate, - refreshActionTemplate, deleteActionTemplate )" (onActionSelect)="handleAction($event, item)"> @@ -107,9 +103,6 @@  {{ action.title }} - -  {{ action.title }} -  {{ action.title }} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts index b12c1e5f..9b3a3099 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts @@ -42,7 +42,6 @@ export class DataservicesListComponent implements OnInit { private static readonly previewActionId = "preview"; private static readonly publishActionId = "publish"; private static readonly downloadActionId = "download"; - private static readonly refreshActionId = "refresh"; private static readonly testActionId = "test"; public items: Dataservice[]; @@ -82,7 +81,6 @@ export class DataservicesListComponent implements OnInit { * @param activateActionTemplate {TemplateRef} the activate action template * @param publishActionTemplate {TemplateRef} the publish action template * @param downloadActionTemplate {TemplateRef} the download action template - * @param refreshActionTemplate {TemplateRef} the refresh action template * @param deleteActionTemplate {TemplateRef} the delete action template * @returns {ActionConfig} the actions configuration */ @@ -93,7 +91,6 @@ export class DataservicesListComponent implements OnInit { activateActionTemplate: TemplateRef< any >, publishActionTemplate: TemplateRef< any >, downloadActionTemplate: TemplateRef< any >, - refreshActionTemplate: TemplateRef< any >, deleteActionTemplate: TemplateRef< any > ): ActionConfig { const actionConfig = { primaryActions: [ @@ -127,13 +124,6 @@ export class DataservicesListComponent implements OnInit { title: "Activate", tooltip: "Activate this data service" }, - { - disabled: ds.serviceDeploymentLoading, - id: DataservicesListComponent.refreshActionId, - template: refreshActionTemplate, - title: "Refresh", - tooltip: "Refresh this data service" - }, { disabled: ds.serviceDeploymentLoading, id: DataservicesListComponent.publishActionId, diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 3c2b0c27..fc940a03 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -242,9 +242,13 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn ); this.connectionService - .getAllConnections() + .getConnections(true, false) .subscribe( - ( connections ) => { + ( connectionSummaries ) => { + const connections = []; + for ( const connectionSummary of connectionSummaries ) { + connections.push(connectionSummary.getConnection()); + } self.connectionsExist = connections.length !== 0; self.loaded( self.connectionsLoadedTag ); }, diff --git a/ngapp/src/app/dataservices/shared/connection-summary.model.ts b/ngapp/src/app/dataservices/shared/connection-summary.model.ts new file mode 100644 index 00000000..b0af0dd2 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/connection-summary.model.ts @@ -0,0 +1,98 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Connection } from "@connections/shared/connection.model"; +import { NamedVdbStatus } from "@dataservices/shared/named-vdb-status.model"; + +/** + * ConnectionSummary model. + */ +export class ConnectionSummary { + + private connection: Connection; + private status: NamedVdbStatus; + + /** + * @param {Object} json the JSON representation of a ConnectionSummary + * @returns {ConnectionSummary} the new ConnectionSummary (never null) + */ + public static create( json: object = {} ): ConnectionSummary { + const connSummary = new ConnectionSummary(); + for (const field of Object.keys(json)) { + if (field === "connection") { + // length of 2 or shorter - no object. TODO: better way to do this? + if (JSON.stringify(json[field]).length > 2) { + connSummary.setConnection(Connection.create(json[field])); + } + } else if (field === "status") { + // length of 2 or shorter - no object. TODO: better way to do this? + if (JSON.stringify(json[field]).length > 2) { + connSummary.setNamedVdbStatus(NamedVdbStatus.create(json[field])); + } + } + } + return connSummary; + } + + constructor() { + // nothing to do + } + + /** + * @returns {Connection} the connection + */ + public getConnection(): Connection { + return this.connection; + } + + /** + * @returns {boolean} 'true' if namedVdbStatus exists + */ + public hasNamedVdbStatus(): boolean { + return (this.status && this.status !== null); + } + + /** + * @returns {NamedVdbStatus} the named vdbStatus + */ + public getNamedVdbStatus(): NamedVdbStatus { + return this.status; + } + + /** + * @param {Connection} connection the named connection + */ + public setConnection( connection: Connection ): void { + this.connection = connection; + } + + /** + * @param {NamedVdbStatus} status the named vdbStatus + */ + public setNamedVdbStatus( status: NamedVdbStatus ): void { + this.status = status; + } + + /** + * Set all object values using the supplied ConnectionSummary json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 4bf36f45..f48763eb 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -68,8 +68,8 @@ export class DataserviceService extends ApiService { this.notifierService = notifierService; this.vdbService = vdbService; this.appSettingsService = appSettings; - // Polls to fire Dataservice state updates every minute - this.pollDataserviceStatus(60); + // Polls to fire Dataservice state updates every 15 sec + this.pollDataserviceStatus(15); } /** diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index af3c2c95..725fcd05 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -26,13 +26,13 @@ import { VdbModel } from "@dataservices/shared/vdb-model.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { Vdb } from "@dataservices/shared/vdb.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; import { TestDataService } from "@shared/test-data.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; -import { Virtualization } from "@dataservices/shared/virtualization.model"; @Injectable() export class MockVdbService extends VdbService { diff --git a/ngapp/src/app/dataservices/shared/named-vdb-status.model.ts b/ngapp/src/app/dataservices/shared/named-vdb-status.model.ts new file mode 100644 index 00000000..ed2450fc --- /dev/null +++ b/ngapp/src/app/dataservices/shared/named-vdb-status.model.ts @@ -0,0 +1,94 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VdbStatus } from "@dataservices/shared/vdb-status.model"; + +/** + * NamedVdbStatus model. + */ +export class NamedVdbStatus { + + private objectName: string; + private vdbStatus: VdbStatus; + + /** + * @param {Object} json the JSON representation of a NamedVdbStatus + * @returns {NamedVdbStatus} the new NamedVdbStatus (never null) + */ + public static create( json: object = {} ): NamedVdbStatus { + const namedStatus = new NamedVdbStatus(); + for (const field of Object.keys(json)) { + if (field === "objectName") { + namedStatus.setName(json[field]); + } else if (field === "vdbStatus") { + // length of 2 or shorter - no object. TODO: better way to do this? + if (JSON.stringify(json[field]).length > 2) { + namedStatus.setVdbStatus(VdbStatus.create(json[field])); + } + } + } + return namedStatus; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the vdbStatus name + */ + public getName(): string { + return this.objectName; + } + + /** + * @returns {boolean} 'true' if vdbStatus exists + */ + public hasVdbStatus(): boolean { + return (this.vdbStatus && this.vdbStatus !== null); + } + + /** + * @returns {VdbStatus} the vdbStatus + */ + public getVdbStatus(): VdbStatus { + return this.vdbStatus; + } + + /** + * @param {string} name the object name + */ + public setName( name: string ): void { + this.objectName = name; + } + + /** + * @param {VdbStatus} status the object VdbStatus + */ + public setVdbStatus( status: VdbStatus ): void { + this.vdbStatus = status; + } + + /** + * Set all object values using the supplied ConnectionSummary json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/dataservices/shared/notifier.service.ts b/ngapp/src/app/dataservices/shared/notifier.service.ts index 8ff563ed..58ad6858 100644 --- a/ngapp/src/app/dataservices/shared/notifier.service.ts +++ b/ngapp/src/app/dataservices/shared/notifier.service.ts @@ -16,6 +16,7 @@ export class NotifierService { private deploymentStatusSubject: Subject = new ReplaySubject(1); private dataserviceDeployStateSubject: Subject< Map > = new ReplaySubject< Map >(1); private dataserviceVirtualizationSubject: Subject< Map > = new ReplaySubject< Map >(1); + private connectionStateSubject: Subject< Map > = new ReplaySubject< Map >(1); constructor() { // Nothing to do @@ -89,4 +90,27 @@ export class NotifierService { public clearDataserviceVirtualizationMap(): void { this.dataserviceVirtualizationSubject.next(null); } + + /** + * Sends map of Connection VDB DeploymentState + * @param {Map} stateMap + */ + public sendConnectionStateMap(stateMap: Map): void { + this.connectionStateSubject.next(stateMap); + } + + /** + * Get the map of Connection VDB DeploymentState + * @returns {Observable>} + */ + public getConnectionStateMap(): Observable> { + return this.connectionStateSubject.asObservable(); + } + + /** + * Clears the Connection VDB DeploymentState + */ + public clearConnectionStateMap(): void { + this.connectionStateSubject.next(null); + } } diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index e31f05c8..869195d3 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -23,7 +23,6 @@ import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { NameValue } from "@dataservices/shared/name-value.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; -import { Table } from "@dataservices/shared/table.model"; import { VdbModelSource } from "@dataservices/shared/vdb-model-source.model"; import { VdbModel } from "@dataservices/shared/vdb-model.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; @@ -335,15 +334,11 @@ export class VdbService extends ApiService { } /** - * Create and deploy a VDB for the provided tables. Currently we require all tables to - * be from the same connection source. - * @param {Table[]} tables + * Create and deploy a VDB for the provided connection. + * @param {Connection} connection * @returns {Observable} */ - public deployVdbForTables(tables: Table[]): Observable { - // Currently requiring all tables from same connection - const connection: Connection = tables[0].getConnection(); - + public deployVdbForConnection(connection: Connection): Observable { const vdbName = this.deriveVdbName(connection); const vdbModelName = this.deriveVdbModelName(connection); const vdbModelSourceName = this.deriveVdbModelSourceName(connection); diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 4783c236..c472b750 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -19,13 +19,14 @@ import { Injectable } from "@angular/core"; import { Connection } from "@connections/shared/connection.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; +import { ConnectionSummary } from "@dataservices/shared/connection-summary.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { NamedVdbStatus } from "@dataservices/shared/named-vdb-status.model"; +import { PublishState } from "@dataservices/shared/publish-state.enum"; import { QueryResults } from "@dataservices/shared/query-results.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { Vdb } from "@dataservices/shared/vdb.model"; -import { VirtualAction } from "rxjs/scheduler/VirtualTimeScheduler"; import { Virtualization } from "@dataservices/shared/virtualization.model"; -import { PublishState } from "@dataservices/shared/publish-state.enum"; @Injectable() export class TestDataService { @@ -82,6 +83,42 @@ export class TestDataService { // VDB Status // ================================================================= + private static status1 = VdbStatus.create( + { + "name": TestDataService.accountsVdb.getName(), + "deployedName": TestDataService.accountsVdb.getName() + "-vdb.xml", + "version": TestDataService.accountsVdb.getVersion(), + "active": true, + "loading": false, + "failed": false, + "errors": [] + } + ); + + private static status2 = VdbStatus.create( + { + "name": TestDataService.employeesVdb.getName(), + "deployedName": TestDataService.employeesVdb.getName() + "-vdb.xml", + "version": TestDataService.employeesVdb.getVersion(), + "active": true, + "loading": false, + "failed": false, + "errors": [] + } + ); + + private static status3 = VdbStatus.create( + { + "name": TestDataService.productsVdb.getName(), + "deployedName": TestDataService.productsVdb.getName() + "-vdb.xml", + "version": TestDataService.productsVdb.getVersion(), + "active": true, + "loading": false, + "failed": false, + "errors": [] + } + ); + private static vdbStatuses = { "keng__baseUri": "http://das-beetle-studio.192.168.42.142.nip.io/vdb-builder/v1/", @@ -126,6 +163,30 @@ export class TestDataService { ] }; + // ================================================================= + // NamedVdbStatus + // ================================================================= + + private static namedStatus1 = NamedVdbStatus.create( + { + "objectName": "AccountConn", + "vdbStatus": TestDataService.status1 + }, + ); + + private static namedStatus2 = NamedVdbStatus.create( + { + "objectName": "EmployeeConn", + "vdbStatus": TestDataService.status2 + } + ); + + private static namedStatus3 = NamedVdbStatus.create( + { + "objectName": "ProductConn" + } + ); + // ================================================================= // ServiceCatalog DataSources // ================================================================= @@ -302,6 +363,28 @@ export class TestDataService { } ); + // ================================================================= + // Connection Summaries + // ================================================================= + + private static connSummariesConnOnly = [ + TestDataService.createConnectionSummary(TestDataService.conn1, null), + TestDataService.createConnectionSummary(TestDataService.conn2, null), + TestDataService.createConnectionSummary(TestDataService.conn3, null) + ]; + + private static connSummariesSchemaStatusOnly = [ + TestDataService.createConnectionSummary(null, TestDataService.namedStatus1), + TestDataService.createConnectionSummary(null, TestDataService.namedStatus2), + TestDataService.createConnectionSummary(null, TestDataService.namedStatus3) + ]; + + private static connSummariesBothConnAndStatus = [ + TestDataService.createConnectionSummary(TestDataService.conn1, TestDataService.namedStatus1), + TestDataService.createConnectionSummary(TestDataService.conn2, TestDataService.namedStatus2), + TestDataService.createConnectionSummary(TestDataService.conn3, TestDataService.namedStatus3) + ]; + // ================================================================= // SchemaInfos for the connections // ================================================================= @@ -844,6 +927,19 @@ export class TestDataService { return catalogSource; } + /** + * Create a ConnectionSummary using the specified info + * @param {Connection} conn the connection + * @param {NamedVdbStatus} status the named vdb status + * @returns {ConnectionSummary} + */ + private static createConnectionSummary( conn: Connection, status: NamedVdbStatus ): ConnectionSummary { + const connectionSummary = new ConnectionSummary(); + connectionSummary.setConnection(conn); + connectionSummary.setNamedVdbStatus(status); + return connectionSummary; + } + constructor() { this.vdbStatuses = TestDataService.vdbStatuses.vdbs.map(( vdbStatus ) => VdbStatus.create( vdbStatus ) ); this.virtualizations = [ @@ -953,10 +1049,19 @@ export class TestDataService { } /** + * Get connection summaries based on supplied parameters + * @param {boolean} includeConnection include connection in the summary + * @param {boolean} includeSchemaStatus include schema status in the summary * @returns {Connection[]} the array of test connections */ - public getConnections(): Connection[] { - return this.connections; + public getConnectionSummaries(includeConnection: boolean, includeSchemaStatus: boolean): ConnectionSummary[] { + if (includeConnection && includeSchemaStatus) { + return TestDataService.connSummariesBothConnAndStatus; + } else if (includeConnection && !includeSchemaStatus) { + return TestDataService.connSummariesConnOnly; + } else if (includeSchemaStatus && !includeConnection) { + return TestDataService.connSummariesSchemaStatusOnly; + } } /** diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index 7cd88872..658a4ac2 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -59,6 +59,6 @@ export const environment = { komodoServiceUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service", // Indicates if in UI development mode where OpenShift will not be used. - uiDevMode: true + uiDevMode: false }; From 5dfa58078c90a34383b44dcf3f355b1ad44a975e Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 5 Apr 2018 11:36:51 -0500 Subject: [PATCH 127/205] address vdb polling issue --- .../add-dataservice-wizard.component.ts | 8 ++++---- ngapp/src/app/dataservices/shared/dataservice.service.ts | 2 +- ngapp/src/app/dataservices/shared/vdb.service.ts | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 7acff85e..ec6601aa 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -281,17 +281,17 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { // Sets page in progress status this.setFinalPageInProgress(); - const sourceVdbName = this.tableSelector.getSelectedTables()[0].getConnection().getId() + VdbsConstants.SOURCE_VDB_SUFFIX; - this.sourceVdbUnderDeployment = sourceVdbName; + const conn = this.tableSelector.getSelectedTables()[0].getConnection(); + this.sourceVdbUnderDeployment = this.vdbService.deriveSourceVdbName(conn); const self = this; this.vdbService - .deployVdbForConnection(this.tableSelector.getSelectedTables()[0].getConnection()) + .deployVdbForConnection(conn) .subscribe( (wasSuccess) => { // Deployment succeeded - wait for source vdb to become active if (wasSuccess) { - self.vdbService.pollForActiveVdb(sourceVdbName, 240, 5); + self.vdbService.pollForActiveVdb(self.sourceVdbUnderDeployment, 240, 5); } else { self.setFinalPageComplete(false); self.sourceVdbUnderDeployment = null; diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index f48763eb..953df760 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -338,7 +338,7 @@ export class DataserviceService extends ApiService { public createDataserviceForSingleSourceTables(dataservice: NewDataservice, sourceTables: Table[]): Observable { // All tables from same connection const connection: Connection = sourceTables[0].getConnection(); - const sourceVdbName = this.vdbService.deriveVdbName(connection); + const sourceVdbName = this.vdbService.deriveSourceVdbName(connection); const sourceModelName = this.vdbService.deriveVdbModelName(connection); const sourceModelSourceName = this.vdbService.deriveVdbModelSourceName(connection); const vdbPath = this.getKomodoUserWorkspacePath() + "/" + sourceVdbName; diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 869195d3..5931cbd8 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -113,12 +113,12 @@ export class VdbService extends ApiService { } /** - * Derive the vdb name from the given connection + * Derive the source vdb name from the given connection * * @param {Connection} connection * @returns {string} */ - public deriveVdbName(connection: Connection): string { + public deriveSourceVdbName(connection: Connection): string { const name = connection.getId() + VdbsConstants.SOURCE_VDB_SUFFIX; return name.toLowerCase(); } @@ -339,7 +339,7 @@ export class VdbService extends ApiService { * @returns {Observable} */ public deployVdbForConnection(connection: Connection): Observable { - const vdbName = this.deriveVdbName(connection); + const vdbName = this.deriveSourceVdbName(connection); const vdbModelName = this.deriveVdbModelName(connection); const vdbModelSourceName = this.deriveVdbModelSourceName(connection); From 65d252b27230220ad4e8d781c74f7022eb4b3725 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Tue, 3 Apr 2018 19:26:41 +0100 Subject: [PATCH 128/205] Check the paths of node and ng to ensure availability * The script assumes ng has been installed and added to the user path. However, latest version of the node s2i script use 'npm prune' to remove dev dependencies as a final clean-up during build. Since @angular/cli was in the dev devendencies, ng is removed too. * package.json * Move @angular/cli and its friends to the dependencies section since they are required for running as well as development. * start.sh * Checks the existence of both node and ng and if not present exit with a sane error message. --- ngapp/package.json | 6 +++--- ngapp/start.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ngapp/package.json b/ngapp/package.json index 98be4aa0..82d939b8 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -13,11 +13,14 @@ "private": true, "dependencies": { "@angular/animations": "^4.4.6", + "@angular/cli": "1.3.2", "@angular/common": "^4.4.6", "@angular/compiler": "^4.4.6", + "@angular/compiler-cli": "^4.4.6", "@angular/core": "^4.4.6", "@angular/forms": "^4.4.6", "@angular/http": "^4.4.6", + "@angular/language-service": "^4.4.6", "@angular/platform-browser": "^4.4.6", "@angular/platform-browser-dynamic": "^4.4.6", "@angular/router": "^4.4.6", @@ -32,9 +35,6 @@ "zone.js": "^0.8.20" }, "devDependencies": { - "@angular/cli": "1.3.2", - "@angular/compiler-cli": "^4.4.6", - "@angular/language-service": "^4.4.6", "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", "@types/node": "^6.0.101", diff --git a/ngapp/start.sh b/ngapp/start.sh index 993c3087..69079698 100755 --- a/ngapp/start.sh +++ b/ngapp/start.sh @@ -4,7 +4,7 @@ command -v node >/dev/null 2>&1 || { echo >&2 "Requires 'node' but it's not installed. Aborting."; exit 1; } # Check ng is available - should be post 'npm install' -NG="node_modules/.bin/ng" +NG=`find . -type f -name ng | head -1` if [ ! -f ${NG} ]; then echo "Error: cannot find 'ng' so nothing can be executed... exiting" exit 1 From 32520736955cf57ccef692dc4f35b468f5671cff Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 6 Apr 2018 13:05:20 -0500 Subject: [PATCH 129/205] TEIIDTOOLS-391 Improve service catalog source selection --- .../add-connection-wizard.component.html | 3 +-- .../add-connection-wizard.component.ts | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html index aaa9207e..29322943 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html @@ -77,8 +77,7 @@

    {{ step2InstructionMessage }}

    = new EventEmitter
    (); - @Output() public tableSelectionRemoved: EventEmitter
    = new EventEmitter
    (); - - public schemaColumns: any[]; - public schemaFiltersText = ""; - public schemaFilterConfig: FilterConfig; - public ngxSchemaConfig: NgxDataTableConfig; - public schemaTableConfig: TableConfig; - public schemaToolbarConfig: ToolbarConfig; - - public tableColumns: any[]; - public tableFiltersText = ""; - public tableFilterConfig: FilterConfig; - public ngxTableConfig: NgxDataTableConfig; - public tableTableConfig: TableConfig; - public tableToolbarConfig: ToolbarConfig; - - public selectedAllRows = false; - - private connectionService: ConnectionService; - private wizardService: WizardService; - private logger: LoggerService; - private schemas: CatalogSchema[] = []; - private filteredSchemas: CatalogSchema[] = []; - private schemaFilter = ""; - private tables: Table[] = []; - private filteredTables: Table[] = []; - private tableFilter = ""; - private currentSchema: CatalogSchema = null; - private schemaLoadingState: LoadingState = LoadingState.LOADING; - private tableLoadingState: LoadingState = LoadingState.LOADING; - - constructor(connectionService: ConnectionService, wizardService: WizardService, logger: LoggerService ) { - this.connectionService = connectionService; - this.wizardService = wizardService; - this.logger = logger; - } - - public ngOnInit(): void { - this.schemaColumns = [ - { - cellTemplate: this.schemaCellTemplate, - comparator: "nameComparator", - draggable: false, - name: "Schemas", - prop: "name", - resizeable: false, - sortable: true, - width: "300" - } - ]; - - this.ngxSchemaConfig = { - footerHeight: 24, - messages: this.schemaTableMessages, - selectionType: "single", - } as NgxDataTableConfig; - - this.schemaFilterConfig = { - fields: [ - { - id: JdbcTableSelectorComponent.schemaFilterId, - title: "Name", - placeholder: "Filter by name...", - type: FilterType.TEXT - } - ] as FilterField[], - appliedFilters: [], - resultsCount: this.filteredSchemas.length, - totalCount: this.schemas.length - } as FilterConfig; - - this.schemaToolbarConfig = { - filterConfig: this.schemaFilterConfig - } as ToolbarConfig; - - this.schemaTableConfig = { - toolbarConfig: this.schemaToolbarConfig - } as TableConfig; - - this.tableColumns = [ - { - comparator: "nameComparator", - draggable: false, - name: "Tables", - prop: "name", - resizeable: false, - sortable: true, - width: "300" - } - ]; - - this.ngxTableConfig = { - footerHeight: 24, - messages: this.tableTableMessages, - selectionType: "checkbox", - } as NgxDataTableConfig; - - this.tableFilterConfig = { - fields: [ - { - id: JdbcTableSelectorComponent.tableFilterId, - title: "Name", - placeholder: "Filter by name...", - type: FilterType.TEXT - } - ] as FilterField[], - appliedFilters: [], - resultsCount: this.filteredTables.length, - totalCount: this.tables.length - } as FilterConfig; - - this.tableToolbarConfig = { - filterConfig: this.tableFilterConfig - } as ToolbarConfig; - - this.tableTableConfig = { - showCheckbox: true, - toolbarConfig: this.tableToolbarConfig - } as TableConfig; - - // Load the schema info for a connection - this.setConnection(this.connection); - } - - /* - * Set the connection for this jdbc table selector - * @param {Connection} conn the jdbc connection - */ - public setConnection(conn: Connection): void { - this.clearSchemas(); - this.clearTables(); - if (conn && conn.isJdbc()) { - this.connection = conn; - // Load the schema info for a connection - this.schemaLoadingState = LoadingState.LOADING; - const self = this; - this.connectionService - .getConnectionSchemaInfos(conn.getServiceCatalogSourceName()) - .subscribe( - (infos) => { - self.generateSchemaNames(infos); - self.schemaLoadingState = LoadingState.LOADED_VALID; - }, - (error) => { - self.logger.error("[JdbcTableSelectorComponent] Error getting schemas: %o", error); - self.schemaLoadingState = LoadingState.LOADED_INVALID; - } - ); - } else { - this.schemaLoadingState = LoadingState.LOADING; - } - } - - public clearSchemas(): void { - this.schemas = []; - this.filteredSchemas = []; - this.currentSchema = null; - } - - public clearTables(): void { - this.tables = []; - this.filteredTables = []; - this.tableLoadingState = LoadingState.LOADING; - } - - // callback from schema row selection in table - public schemaSelectionChange( $event ): void { - const selected: CatalogSchema[] = $event.selected; - - // schema table is single select so use first element - const schema: CatalogSchema = selected[ 0 ]; - - // only set if schema selection has changed (see setter) - if ( this.hasSelectedSchema ) { - if ( this.selectedSchema.getDisplayName() !== schema.getDisplayName() ) { - this.selectedSchema = schema; - } - } else { - this.selectedSchema = schema; - } - } - - /* - * Determines if the provided schema is selected - * @param {CatalogSchema} schema the CatalogSchema to check - */ - public isSchemaSelected(schema: CatalogSchema): boolean { - return schema === this.currentSchema; - } - - /* - * Returns the currently selected schema. - * @returns {CatalogSchema} the selected schema - */ - public get selectedSchema( ): CatalogSchema { - return this.currentSchema; - } - - public set selectedSchema( schema: CatalogSchema ) { - this.currentSchema = schema; - - const filterInfo = new JdbcTableFilter(); - filterInfo.setConnectionName(this.connection.getServiceCatalogSourceName()); - if (schema.getType() === "Catalog") { - filterInfo.setCatalogFilter(schema.getName()); - filterInfo.setSchemaFilter("%"); - } else { - filterInfo.setSchemaFilter(schema.getName()); - const catName = schema.getCatalogName(); - if (catName && catName.length > 0) { - filterInfo.setCatalogFilter(catName); - } else { - filterInfo.setCatalogFilter("%"); - } - } - filterInfo.setTableFilter("%"); - this.loadTablesForSchema(filterInfo); - } - - /* - * Returns the currently selected schema. - * @returns {CatalogSchema} the selected schema - */ - public get hasSelectedSchema( ): boolean { - return this.currentSchema != null; - } - - /** - * Determine if schemas are loading - */ - public get schemasLoading( ): boolean { - return this.schemaLoadingState === LoadingState.LOADING; - } - - /** - * Determine if schemas are loaded, valid and not empty - */ - public get schemasLoadedValidNotEmpty( ): boolean { - return (this.schemaLoadingState === LoadingState.LOADED_VALID) && this.schemas.length > 0; - } - - /** - * Determine if schemas are loaded, valid but empty - */ - public get schemasLoadedValidEmpty( ): boolean { - return (this.schemaLoadingState === LoadingState.LOADED_VALID) && this.schemas.length === 0; - } - - /** - * Determine if schemas are loaded and invalid - */ - public get schemasLoadedInvalid( ): boolean { - return this.schemaLoadingState === LoadingState.LOADED_INVALID; - } - - /** - * Callback when schema filters are changed. - */ - public schemaFilterChanged( $event: FilterEvent ): void { - this.schemaFiltersText = ""; - - $event.appliedFilters.forEach( ( filter ) => { - this.schemaFiltersText += filter.field.title + " : " + filter.value + "\n"; - } ); - - this.applySchemaFilters( $event.appliedFilters ); - } - - public get schemaTableMessages(): { emptyMessage: string; totalMessage: string | string } { - const numAll = this.schemas.length; - const numFiltered = this.filteredSchemas.length; - let msg: string; - - if ( numAll === numFiltered ) { - if ( this.schemaFilter.length === 0 ) { - msg = numAll === 1 ? "schema" : "schemas"; - } else { - msg = numAll === 1 ? "matched schema" : "matched schemas"; - } - } else { - msg = numFiltered === 1 ? "matched schema" : "matched schemas"; - } - - return { - // message shows in an empty row in table - emptyMessage: "", - - // footer total message - totalMessage: msg - }; - } - - /** - * Called when the table is sorted. - * @param {string} thisName the name being sorted - * @param {string} thatName the name being compared to - * @returns {number} -1 if less than, 0 if equal, or 1 if greater than - */ - public nameComparator( thisName: string, - thatName: string ): number { - return thisName.localeCompare( thatName ); - } - - /* - * Get all schemas - * @returns {CatalogSchema[]} the array of schema - */ - public getSchemas(): CatalogSchema[] { - return this.schemas; - } - - /** - * Determine if tables are loading - */ - public get tablesLoading( ): boolean { - return this.tableLoadingState === LoadingState.LOADING; - } - - /** - * Determine if tables are loaded, valid and not empty - */ - public get tablesLoadedValidNotEmpty( ): boolean { - return (this.tableLoadingState === LoadingState.LOADED_VALID) && this.tables.length > 0; - } - - /** - * Determine if tables are loaded, valid but empty - */ - public get tablesLoadedValidEmpty( ): boolean { - return (this.tableLoadingState === LoadingState.LOADED_VALID) && this.tables.length === 0; - } - - /** - * Determine if tables are loaded and invalid - */ - public get tablesLoadedInvalid( ): boolean { - return this.tableLoadingState === LoadingState.LOADED_INVALID; - } - - public get tableTableMessages(): { emptyMessage: string; totalMessage: string | string } { - const numAll = this.tables.length; - const numFiltered = this.filteredTables.length; - let msg: string; - - if ( numAll === numFiltered ) { - if ( this.tableFilter.length === 0 ) { - msg = numAll === 1 ? "table" : "tables"; - } else { - msg = numAll === 1 ? "matched table" : "matched tables"; - } - } else { - msg = numFiltered === 1 ? "matched table" : "matched tables"; - } - - return { - // message shows in an empty row in table - emptyMessage: "", - - // footer total message - totalMessage: msg - }; - } - - /** - * Callback when key is pressed in table column filter. - */ - public tableFilterChanged( $event ): void { - this.tableFiltersText = ""; - - $event.appliedFilters.forEach( ( filter ) => { - this.tableFiltersText += filter.field.title + " : " + filter.value + "\n"; - } ); - - this.applyTableFilters( $event.appliedFilters ); - } - - /* - * Get all tables - * @returns {Table[]} the current tables for the selected schema - */ - public getTables(): Table[] { - return this.tables; - } - - /* - * Determine if any tables are currently selected - * @returns {boolean} true if one or more tables are selected - */ - public hasSelectedTables(): boolean { - for ( const table of this.tables ) { - if ( table.selected ) { - return true; - } - } - - return false; - } - - /* - * Get the array of currently selected Tables - * @returns {Table[]} the array of selected Tables - */ - public getSelectedTables(): Table[] { - return this.tables.filter( ( table ) => table.selected ); - } - - /* - * Handler for changes in table selection - */ - public selectedTableChanged( $event: TableEvent ): void { - const table: Table = $event.row; - - if ( table ) { - if ( table.selected ) { - this.tableSelectionAdded.emit( table ); - } else { - this.tableSelectionRemoved.emit( table ); - } - } else { - if ( $event.selectedRows.length === 0 ) { - this.tables.forEach( ( tbl ) => { - this.tableSelectionRemoved.emit( tbl ); - } ); - } else { - this.tables.forEach( ( tbl ) => { - this.tableSelectionAdded.emit( tbl ); - } ); - } - } - } - - /** - * Deselects the table if one with a matching name and connection is currently selected - * @param {Table} table - */ - public deselectTable(table: Table): void { - const connName = table.getConnection().getId(); - const tableName = table.getName(); - - for (const theTable of this.tables) { - const theConnName = theTable.getConnection().getId(); - const theTableName = theTable.getName(); - if (theConnName === connName && theTableName === tableName) { - theTable.selected = false; - - // need to set column header checkbox state - let enable = true; - - for ( const filteredTable of this.filteredTables ) { - if ( !filteredTable.selected ) { - enable = false; - break; - } - } - - if ( this.selectedAllRows !== enable ) { - this.selectedAllRows = enable; - } - - break; - } - } - } - - private applySchemaFilters( filters: Filter[] ): void { - this.filteredSchemas = []; - - if ( filters && filters.length > 0 ) { - this.schemas.forEach( ( item ) => { - if ( this.matchesFilters( item, filters ) ) { - this.filteredSchemas.push( item ); - } - } ); - } else { - this.filteredSchemas = this.schemas; - } - - this.schemaToolbarConfig.filterConfig.resultsCount = this.filteredSchemas.length; - } - - private applyTableFilters( filters: Filter[] ): void { - this.filteredTables = []; - - if ( filters && filters.length > 0 ) { - this.tables.forEach( ( item ) => { - if ( this.matchesFilters( item, filters ) ) { - this.filteredTables.push( item ); - } - } ); - } else { - this.filteredTables = this.tables; - } - - this.tableToolbarConfig.filterConfig.resultsCount = this.filteredTables.length; - } - - private isSelected( selectedTables: Table[], - table: Table ): boolean { - for ( const selected of selectedTables ) { - if ( selected.getName() === table.getName() ) { - return true; - } - } - - return false; - } - - /* - * Builds the array of CatalogSchema items from the SchemaInfo coming from - * the Komodo rest call - * @param {SchemaInfo[]} infos the array of SchemaInfo from komodo - */ - private generateSchemaNames(infos: SchemaInfo[]): void { - for (const info of infos) { - const infoName = info.getName(); - const infoType = info.getType(); - const schemaNames = info.getSchemaNames(); - if (infoType === "Catalog") { - if (schemaNames && schemaNames.length > 0) { - for (const sName of schemaNames) { - const item: CatalogSchema = new CatalogSchema(); - item.setName(sName); - item.setType("Schema"); - item.setCatalogName(infoName); - this.schemas.push(item); - this.filteredSchemas.push(item); - } - } else { - const item: CatalogSchema = new CatalogSchema(); - item.setName(infoName); - item.setType("Catalog"); - this.schemas.push(item); - this.filteredSchemas.push(item); - } - } else if (infoType === "Schema") { - const item: CatalogSchema = new CatalogSchema(); - item.setName(infoName); - item.setType("Schema"); - this.schemas.push(item); - this.filteredSchemas.push(item); - } - } - } - - /* - * Populates tables array, given the supplied JdbcTableFilter - * @para {JdbcTableFilter} tableFilter the filters for getting tables - */ - private loadTablesForSchema(tableFilter: JdbcTableFilter): void { - // Load the table names for the selected Connection and Schema - this.tables = []; - this.filteredTables = []; - this.selectedAllRows = false; - this.tableLoadingState = LoadingState.LOADING; - const self = this; - this.connectionService - .getJdbcConnectionTables(tableFilter) - .subscribe( - (tableNames) => { - for ( const tName of tableNames ) { - const table = new Table(); - table.setName(tName); - table.setConnection(self.connection); - table.setCatalogName(self.selectedSchema.getCatalogName()); - table.setSchemaName(self.selectedSchema.getName()); - self.tables.push(table); - self.filteredTables.push(table); - } - // select any of the tables that are already selected - self.setInitialTableSelections(); - self.tableLoadingState = LoadingState.LOADED_VALID; - }, - (error) => { - self.logger.error("[JdbcTableSelectorComponent] Error getting tables: %o", error); - self.tableLoadingState = LoadingState.LOADED_INVALID; - } - ); - } - - private matchesFilter( item: any, - filter: Filter ): boolean { - let matches = true; - - if ( filter.field.id === JdbcTableSelectorComponent.schemaFilterId ) { - const pattern = "^" + filter.value.replace( "*", ".*" ); - matches = item.getDisplayName().match( pattern ) !== null; - } else if ( filter.field.id === JdbcTableSelectorComponent.tableFilterId ) { - const pattern = "^" + filter.value.replace( "*", ".*" ); - matches = item.name.match( pattern ) !== null; - } - - return matches; - } - - private matchesFilters( item: any, - filters: Filter[] ): boolean { - let matches = true; - - filters.forEach( ( filter ) => { - if ( !this.matchesFilter( item, filter ) ) { - matches = false; - return matches; - } - }); - - return matches; - } - - private setInitialTableSelections(): void { - let enableSelectAll = true; - - for ( const table of this.tables ) { - // const catName = table.getCatalogName(); - // const schemaName = table.getSchemaName(); - const tableName = table.getName(); - const connName = table.getConnection().getId(); - - for ( const initialTable of this.wizardService.getWizardSelectedTables() ) { - // const iCatName = initialTable.getCatalogName(); - // const iSchemaName = initialTable.getSchemaName(); - const iTableName = initialTable.getName(); - const iConnName = initialTable.getConnection().getId(); - if (iConnName === connName && iTableName === tableName ) { - table.selected = true; - break; - } - } - - if ( !table.selected ) { - enableSelectAll = false; - } - } - - this.selectedAllRows = enableSelectAll; - } - -} diff --git a/ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.css similarity index 100% rename from ngapp/src/app/dataservices/jdbc-table-selector/jdbc-table-selector.component.css rename to ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.css diff --git a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.html b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.html new file mode 100644 index 00000000..9470ef2d --- /dev/null +++ b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.html @@ -0,0 +1,31 @@ + + + +
    + +
    +
    +
    + + Unable to load tables +
    +
    +
    +
    + + No tables available +
    +
    +
    + + +
    + + {{ row.getId() }} + diff --git a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.spec.ts b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.spec.ts new file mode 100644 index 00000000..d03871a1 --- /dev/null +++ b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.spec.ts @@ -0,0 +1,54 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionService } from "app/connections/shared/connection.service"; +import { MockConnectionService } from "app/connections/shared/mock-connection.service"; +import { AppSettingsService } from "app/core/app-settings.service"; +import { LoggerService } from "app/core/logger.service"; +import { MockAppSettingsService } from "app/core/mock-app-settings.service"; +import { RelationalTableSelectorComponent } from "app/dataservices/relational-table-selector/relational-table-selector.component"; +import { SelectedTableComponent } from "app/dataservices/selected-table/selected-table.component"; +import { MockVdbService } from "app/dataservices/shared/mock-vdb.service"; +import { NotifierService } from "app/dataservices/shared/notifier.service"; +import { VdbService } from "app/dataservices/shared/vdb.service"; +import { WizardService } from "app/dataservices/shared/wizard.service"; +import { PatternFlyNgModule } from "patternfly-ng"; + +describe("RelationalTableSelectorComponent", () => { + let component: RelationalTableSelectorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ FormsModule, HttpModule, PatternFlyNgModule ], + declarations: [ RelationalTableSelectorComponent, SelectedTableComponent ], + providers: [ + AppSettingsService, LoggerService, NotifierService, WizardService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: ConnectionService, useClass: MockConnectionService }, + { provide: VdbService, useClass: MockVdbService }, + ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RelationalTableSelectorComponent); + component = fixture.componentInstance; + const conn: Connection = new Connection(); + conn.setId("conn1"); + component.connection = conn; + component.setConnection(conn); + fixture.detectChanges(); + }); + + it("should be created", () => { + console.log("========== [RelationalTableSelectorComponent] should be created"); + expect(component).toBeTruthy(); + }); + +}); diff --git a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.ts b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.ts new file mode 100644 index 00000000..dbe9f2ad --- /dev/null +++ b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.ts @@ -0,0 +1,394 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from "@angular/core"; +import { Input } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { Output } from "@angular/core"; +import { ConnectionTable } from "@connections/shared/connection-table.model"; +import { Connection } from "app/connections/shared/connection.model"; +import { ConnectionService } from "app/connections/shared/connection.service"; +import { LoggerService } from "app/core/logger.service"; +import { TableSelector } from "app/dataservices/shared/table-selector"; +import { WizardService } from "app/dataservices/shared/wizard.service"; +import { LoadingState } from "app/shared/loading-state.enum"; +import { + Filter, + FilterConfig, FilterField, FilterType, NgxDataTableConfig, TableConfig, TableEvent, + ToolbarConfig +} from "patternfly-ng"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-relational-table-selector", + templateUrl: "./relational-table-selector.component.html", + styleUrls: ["./relational-table-selector.component.css"] +}) + +export class RelationalTableSelectorComponent implements OnInit, TableSelector { + + private static readonly tableFilterId = "tableFilter"; + + @ViewChild("tableCellTemplate") public tableCellTemplate: TemplateRef< any >; + @Input() public connection: Connection; + @Output() public tableSelectionAdded: EventEmitter = new EventEmitter(); + @Output() public tableSelectionRemoved: EventEmitter = new EventEmitter(); + + public tableColumns: any[]; + public tableFiltersText = ""; + public tableFilterConfig: FilterConfig; + public ngxTableConfig: NgxDataTableConfig; + public tableTableConfig: TableConfig; + public tableToolbarConfig: ToolbarConfig; + + public selectedAllRows = false; + + private connectionService: ConnectionService; + private wizardService: WizardService; + private logger: LoggerService; + private tables: ConnectionTable[] = []; + private filteredTables: ConnectionTable[] = []; + private tableFilter = ""; + private tableLoadingState: LoadingState = LoadingState.LOADING; + + constructor(connectionService: ConnectionService, wizardService: WizardService, logger: LoggerService ) { + this.connectionService = connectionService; + this.wizardService = wizardService; + this.logger = logger; + } + + public ngOnInit(): void { + this.tableColumns = [ + { + cellTemplate: this.tableCellTemplate, + comparator: "nameComparator", + draggable: false, + name: "Tables", + prop: "keng__id", + resizeable: false, + sortable: true, + width: "300" + } + ]; + + this.ngxTableConfig = { + footerHeight: 24, + messages: this.tableTableMessages, + selectionType: "checkbox", + } as NgxDataTableConfig; + + this.tableFilterConfig = { + fields: [ + { + id: RelationalTableSelectorComponent.tableFilterId, + title: "Name", + placeholder: "Filter by name...", + type: FilterType.TEXT + } + ] as FilterField[], + appliedFilters: [], + resultsCount: this.filteredTables.length, + totalCount: this.tables.length + } as FilterConfig; + + this.tableToolbarConfig = { + filterConfig: this.tableFilterConfig + } as ToolbarConfig; + + this.tableTableConfig = { + showCheckbox: true, + toolbarConfig: this.tableToolbarConfig + } as TableConfig; + + // Load the connection tables for a connection + this.setConnection(this.connection); + } + + /* + * Set the connection for this relational table selector. Setting the connection triggers loading + * of the tables. + * @param {Connection} conn the relational connection + */ + public setConnection(conn: Connection): void { + // Load the tables for the connection + this.tables = []; + this.filteredTables = []; + this.selectedAllRows = false; + this.tableLoadingState = LoadingState.LOADING; + const self = this; + this.connectionService + .getConnectionTables(conn.getId()) + .subscribe( + (connTables) => { + for ( const table of connTables ) { + table.setConnection(conn); + self.tables.push(table); + self.filteredTables.push(table); + } + // select any of the tables that are already selected + self.setInitialTableSelections(); + self.tableLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.logger.error("[RelationalTableSelectorComponent] Error getting tables: %o", error); + self.tableLoadingState = LoadingState.LOADED_INVALID; + } + ); + } + + /** + * Called when the table is sorted. + * @param {string} thisName the name being sorted + * @param {string} thatName the name being compared to + * @returns {number} -1 if less than, 0 if equal, or 1 if greater than + */ + public nameComparator( thisName: string, + thatName: string ): number { + return thisName.localeCompare( thatName ); + } + + /** + * Determine if tables are loading + */ + public get tablesLoading( ): boolean { + return this.tableLoadingState === LoadingState.LOADING; + } + + /** + * Determine if tables are loaded, valid and not empty + */ + public get tablesLoadedValidNotEmpty( ): boolean { + return (this.tableLoadingState === LoadingState.LOADED_VALID) && this.tables.length > 0; + } + + /** + * Determine if tables are loaded, valid but empty + */ + public get tablesLoadedValidEmpty( ): boolean { + return (this.tableLoadingState === LoadingState.LOADED_VALID) && this.tables.length === 0; + } + + /** + * Determine if tables are loaded and invalid + */ + public get tablesLoadedInvalid( ): boolean { + return this.tableLoadingState === LoadingState.LOADED_INVALID; + } + + public get tableTableMessages(): { emptyMessage: string; totalMessage: string | string } { + const numAll = this.tables.length; + const numFiltered = this.filteredTables.length; + let msg: string; + + if ( numAll === numFiltered ) { + if ( this.tableFilter.length === 0 ) { + msg = numAll === 1 ? "table" : "tables"; + } else { + msg = numAll === 1 ? "matched table" : "matched tables"; + } + } else { + msg = numFiltered === 1 ? "matched table" : "matched tables"; + } + + return { + // message shows in an empty row in table + emptyMessage: "", + + // footer total message + totalMessage: msg + }; + } + + /** + * Callback when key is pressed in table column filter. + */ + public tableFilterChanged( $event ): void { + this.tableFiltersText = ""; + + $event.appliedFilters.forEach( ( filter ) => { + this.tableFiltersText += filter.field.title + " : " + filter.value + "\n"; + } ); + + this.applyTableFilters( $event.appliedFilters ); + } + + /* + * Get all tables + * @returns {ConnectionTable[]} the current tables for the selected schema + */ + public getTables(): ConnectionTable[] { + return this.tables; + } + + /* + * Determine if any tables are currently selected + * @returns {boolean} true if one or more tables are selected + */ + public hasSelectedTables(): boolean { + for ( const table of this.tables ) { + if ( table.selected ) { + return true; + } + } + + return false; + } + + /* + * Get the array of currently selected ConnectionTables + * @returns {ConnectionTable[]} the array of selected ConnectionTables + */ + public getSelectedTables(): ConnectionTable[] { + return this.tables.filter( ( table ) => table.selected ); + } + + /* + * Handler for changes in table selection + */ + public selectedTableChanged( $event: TableEvent ): void { + const table: ConnectionTable = $event.row; + + if ( table ) { + if ( table.selected ) { + this.tableSelectionAdded.emit( table ); + } else { + this.tableSelectionRemoved.emit( table ); + } + } else { + if ( $event.selectedRows.length === 0 ) { + this.tables.forEach( ( tbl ) => { + this.tableSelectionRemoved.emit( tbl ); + } ); + } else { + this.tables.forEach( ( tbl ) => { + this.tableSelectionAdded.emit( tbl ); + } ); + } + } + } + + /** + * Deselects the table if one with a matching name and connection is currently selected + * @param {ConnectionTable} table + */ + public deselectTable(table: ConnectionTable): void { + const connName = table.getConnection().getId(); + const tableName = table.getId(); + + for (const theTable of this.tables) { + const theConnName = theTable.getConnection().getId(); + const theTableName = theTable.getId(); + if (theConnName === connName && theTableName === tableName) { + theTable.selected = false; + + // need to set column header checkbox state + let enable = true; + + for ( const filteredTable of this.filteredTables ) { + if ( !filteredTable.selected ) { + enable = false; + break; + } + } + + if ( this.selectedAllRows !== enable ) { + this.selectedAllRows = enable; + } + + break; + } + } + } + + private applyTableFilters( filters: Filter[] ): void { + this.filteredTables = []; + + if ( filters && filters.length > 0 ) { + this.tables.forEach( ( item ) => { + if ( this.matchesFilters( item, filters ) ) { + this.filteredTables.push( item ); + } + } ); + } else { + this.filteredTables = this.tables; + } + + this.tableToolbarConfig.filterConfig.resultsCount = this.filteredTables.length; + } + + private isSelected( selectedTables: ConnectionTable[], + table: ConnectionTable ): boolean { + for ( const selected of selectedTables ) { + if ( selected.getId() === table.getId() ) { + return true; + } + } + + return false; + } + + private matchesFilter( item: any, + filter: Filter ): boolean { + let matches = true; + + if ( filter.field.id === RelationalTableSelectorComponent.tableFilterId ) { + const pattern = "^" + filter.value.replace( "*", ".*" ); + matches = item.name.match( pattern ) !== null; + } + + return matches; + } + + private matchesFilters( item: any, + filters: Filter[] ): boolean { + let matches = true; + + filters.forEach( ( filter ) => { + if ( !this.matchesFilter( item, filter ) ) { + matches = false; + return matches; + } + }); + + return matches; + } + + private setInitialTableSelections(): void { + let enableSelectAll = true; + + for ( const table of this.tables ) { + const tableName = table.getId(); + const connName = table.getConnection().getId(); + + for ( const initialTable of this.wizardService.getSelectedConnectionTables() ) { + const iTableName = initialTable.getId(); + const iConnName = initialTable.getConnection().getId(); + if (iConnName === connName && iTableName === tableName ) { + table.selected = true; + break; + } + } + + if ( !table.selected ) { + enableSelectAll = false; + } + } + + this.selectedAllRows = enableSelectAll; + } + +} diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.html b/ngapp/src/app/dataservices/selected-table/selected-table.component.html index 4091f979..d0001f7b 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.html +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.html @@ -6,7 +6,7 @@
    - {{ table.getName() }} + {{ table.getId() }}
    diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts index 6c185209..97750a85 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts @@ -1,7 +1,7 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; import { PatternFlyNgModule } from "patternfly-ng"; -import { Table } from "../shared/table.model"; import { SelectedTableComponent } from "./selected-table.component"; describe("SelectedTableComponent", () => { @@ -30,9 +30,9 @@ describe("SelectedTableComponent", () => { const connection = new Connection(); connection.setId( connectionName ); - const table = new Table(); + const table = new ConnectionTable(); table.setConnection(connection); - table.setName( tableName ); + table.setId(tableName); component.table = table; fixture.detectChanges(); diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts index 000d5b60..97d751a7 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts +++ b/ngapp/src/app/dataservices/selected-table/selected-table.component.ts @@ -16,8 +16,8 @@ */ import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from "@angular/core"; +import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Column } from "@dataservices/selected-table/column"; -import { Table } from "@dataservices/shared/table.model"; import { CardAction, CardConfig, TableConfig, TableEvent } from "patternfly-ng"; @Component({ @@ -28,8 +28,8 @@ import { CardAction, CardConfig, TableConfig, TableEvent } from "patternfly-ng"; }) export class SelectedTableComponent implements OnInit { - @Input() public table: Table; - @Output() public selectionListTableRemoved: EventEmitter
    = new EventEmitter
    (); + @Input() public table: ConnectionTable; + @Output() public selectionListTableRemoved: EventEmitter = new EventEmitter(); public config: CardConfig; public columnDefinitions: any[]; diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 953df760..33d99249 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -17,6 +17,7 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; +import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; @@ -28,10 +29,10 @@ import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { PublishState } from "@dataservices/shared/publish-state.enum"; import { QueryResults } from "@dataservices/shared/query-results.model"; -import { Table } from "@dataservices/shared/table.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; import { VdbService } from "@dataservices/shared/vdb.service"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; +import { View } from "@dataservices/shared/view.model"; import { Virtualization } from "@dataservices/shared/virtualization.model"; import { environment } from "@environments/environment"; import { saveAs } from "file-saver/FileSaver"; @@ -56,7 +57,7 @@ export class DataserviceService extends ApiService { private appSettingsService: AppSettingsService; private vdbService: VdbService; private selectedDataservice: Dataservice; - private dataserviceCurrentView: Table[] = []; + private dataserviceCurrentView: View[] = []; private cachedDataserviceDeployStates: Map = new Map(); private cachedDataserviceVirtualizations: Map = new Map(); private updatesSubscription: Subscription; @@ -95,7 +96,7 @@ export class DataserviceService extends ApiService { public setSelectedDataservice(service: Dataservice): void { this.selectedDataservice = service; // When the dataservice is selected, init the selected view - const views: Table[] = this.getSelectedDataserviceViews(); + const views: View[] = this.getSelectedDataserviceViews(); this.dataserviceCurrentView = []; if (views && views.length > 0) { this.dataserviceCurrentView.push(views[0]); @@ -111,11 +112,11 @@ export class DataserviceService extends ApiService { } /** - * Get the current Dataservice selection's views. The table object is used for the view, - * with the Table name set to the full "modelName"."viewName" of the view. - * @returns {Table[]} the selected Dataservice views + * Get the current Dataservice selection's views.View + * The View name is currently set to the full "modelName"."viewName" of the view. + * @returns {View[]} the selected Dataservice views */ - public getSelectedDataserviceViews( ): Table[] { + public getSelectedDataserviceViews( ): View[] { if (!this.selectedDataservice || this.selectedDataservice === null) { return []; } @@ -124,9 +125,9 @@ export class DataserviceService extends ApiService { const serviceViews = this.selectedDataservice.getServiceViewNames(); // build the views using the model and view names - const allViews: Table[] = []; + const allViews: View[] = []; for ( const serviceView of serviceViews ) { - const aView: Table = new Table(); + const aView: View = new View(); aView.setName(modelName + "." + serviceView); allViews.push(aView); @@ -137,19 +138,19 @@ export class DataserviceService extends ApiService { /** * Get the current Dataservice current view. The table object is used for the view, - * with the Table name set to the full "modelName"."viewName" of the view. - * @returns {Table[]} the Dataservice current view + * with the View name set to the full "modelName"."viewName" of the view. + * @returns {View[]} the Dataservice current view */ - public getSelectedDataserviceCurrentView( ): Table[] { + public getSelectedDataserviceCurrentView( ): View[] { return this.dataserviceCurrentView; } /** * Set the current Dataservice current view. The table object is used for the view, - * with the Table name set to the full "modelName"."viewName" of the view. - * @param {Table[]} view the current view + * with the View name set to the full "modelName"."viewName" of the view. + * @param {View[]} view the current view */ - public setSelectedDataserviceCurrentView( view: Table[] ): void { + public setSelectedDataserviceCurrentView( view: View[] ): void { this.dataserviceCurrentView = view; } @@ -332,43 +333,46 @@ export class DataserviceService extends ApiService { /** * Create a dataservice which is a straight passthru to the supplied tables * @param {NewDataservice} dataservice - * @param {Table[]} sourceTables + * @param {ConnectionTable[]} connectionTables * @returns {Observable} */ - public createDataserviceForSingleSourceTables(dataservice: NewDataservice, sourceTables: Table[]): Observable { + public createDataserviceForSingleSourceTables(dataservice: NewDataservice, connectionTables: ConnectionTable[]): Observable { // All tables from same connection - const connection: Connection = sourceTables[0].getConnection(); - const sourceVdbName = this.vdbService.deriveSourceVdbName(connection); - const sourceModelName = this.vdbService.deriveVdbModelName(connection); - const sourceModelSourceName = this.vdbService.deriveVdbModelSourceName(connection); - const vdbPath = this.getKomodoUserWorkspacePath() + "/" + sourceVdbName; + const connection: Connection = connectionTables[0].getConnection(); + const schemaVdbName = connection.schemaVdbName; + const schemaVdbModelName = connection.schemaVdbModelName; + const schemaVdbModelSourceName = connection.schemaVdbModelSourceName; + + // The schema VDB is directly under the connection in the repo + const vdbPath = this.getKomodoUserWorkspacePath() + "/" + connection.getId() + "/" + schemaVdbName; + + // Get table paths for the tables used in the service const tablePaths = []; - for ( const sourceTable of sourceTables ) { - const tablePath = vdbPath + "/" + sourceModelName + "/" + sourceTable.getName(); + for ( const connectionTable of connectionTables ) { + const tablePath = vdbPath + "/" + schemaVdbModelName + "/" + connectionTable.getId(); tablePaths.push(tablePath); } - const modelSourcePath = vdbPath + "/" + sourceModelName + "/vdb:sources/" + sourceModelSourceName; + // ModelSource path + const modelSourcePath = vdbPath + "/" + schemaVdbModelName + "/vdb:sources/" + schemaVdbModelSourceName; + + // Name of the Dataservice VDB const dsVdbName = this.deriveServiceVdbName(dataservice); // Chain the individual calls together in series to build the DataService return this.createDataservice(dataservice) - .flatMap((res) => this.vdbService.updateVdbModelFromTeiid(sourceVdbName, sourceModelName, - sourceVdbName, sourceModelName)) .flatMap((res) => this.setServiceVdbForSingleSourceTables(dataservice.getId(), tablePaths, modelSourcePath)) - .flatMap((res) => this.createReadonlyDataRole(dsVdbName, sourceModelName)) - .flatMap((res) => this.vdbService.undeployVdb(sourceVdbName)) - .flatMap((res) => this.vdbService.deleteVdb(sourceVdbName)); + .flatMap((res) => this.createReadonlyDataRole(dsVdbName, schemaVdbModelName)); } /** * Updates a dataservice with single table source. This is simply a create, with the added step of * deleting the existing workspace dataservice first. * @param {NewDataservice} dataservice - * @param {Table[]} sourceTables + * @param {ConnectionTable[]} sourceTables * @returns {Observable} */ - public updateDataserviceForSingleSourceTables(dataservice: NewDataservice, sourceTables: Table[]): Observable { + public updateDataserviceForSingleSourceTables(dataservice: NewDataservice, sourceTables: ConnectionTable[]): Observable { return this.deleteDataservice(dataservice.getId()) .flatMap((res) => this.createDataserviceForSingleSourceTables(dataservice, sourceTables)); } diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index f468a009..bc0912da 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -24,8 +24,8 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { QueryResults } from "@dataservices/shared/query-results.model"; -import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { View } from "@dataservices/shared/view.model"; import { TestDataService } from "@shared/test-data.service"; import "rxjs/add/observable/of"; import "rxjs/add/observable/throw"; @@ -91,12 +91,12 @@ export class MockDataserviceService extends DataserviceService { /** * Get the views for the selected Dataservice - * @returns {Table[]} the views + * @returns {View[]} the views */ - public getSelectedDataserviceViews(): Table[] { - const table: Table = new Table(); + public getSelectedDataserviceViews(): View[] { + const table: View = new View(); table.setName("views.View1"); - const tables: Table[] = []; + const tables: View[] = []; tables.push(table); return tables; diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index 725fcd05..e3d79848 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -20,7 +20,6 @@ import { Http } from "@angular/http"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; -import { Table } from "@dataservices/shared/table.model"; import { VdbModelSource } from "@dataservices/shared/vdb-model-source.model"; import { VdbModel } from "@dataservices/shared/vdb-model.model"; import { VdbStatus } from "@dataservices/shared/vdb-status.model"; @@ -127,19 +126,6 @@ export class MockVdbService extends VdbService { return Observable.of(true); } - /** - * Update the specified repo VDB Model using the DDL from the specified Teiid VDB - * @param {string} vdbName the VDB in the repo to update - * @param {string} modelName the Model withing the specified repo VDB - * @param {string} teiidVdbName the deployed teiid VDB name - * @param {string} teiidModelName the teiid VDB Model name - * @returns {Observable} - */ - public updateVdbModelFromTeiid(vdbName: string, modelName: string, - teiidVdbName: string, teiidModelName: string): Observable { - return Observable.of(true); - } - /** * Polls the server for the specified VDB. Polling will terminate if * (1) The VDB is active @@ -165,15 +151,6 @@ export class MockVdbService extends VdbService { } - /** - * Create and deploy a VDB for the provided table - * @param {Table[]} tables - * @returns {Observable} - */ - public deployVdbForTables(tables: Table[]): Observable { - return Observable.of(true); - } - public getVirtualizations(): Observable< Virtualization[] > { return Observable.of( this.virtualizations ); } diff --git a/ngapp/src/app/dataservices/shared/table-selector.ts b/ngapp/src/app/dataservices/shared/table-selector.ts index 105cfea3..d43e9def 100644 --- a/ngapp/src/app/dataservices/shared/table-selector.ts +++ b/ngapp/src/app/dataservices/shared/table-selector.ts @@ -15,8 +15,8 @@ * limitations under the License. */ +import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; -import { Table } from "@dataservices/shared/table.model"; /** * The table selector interface @@ -37,14 +37,14 @@ export interface TableSelector { /** * Get the array of currently selected Tables - * @returns {Table[]} the array of selected Tables (never null, but may be empty) + * @returns {ConnectionTable[]} the array of selected ConnectionTable (never null, but may be empty) */ - getSelectedTables(): Table[]; + getSelectedTables(): ConnectionTable[]; /** * Deselect the table if a table with the same name and connection is currently selected. - * @param {Table} table the table to deselect + * @param {ConnectionTable} table the table to deselect */ - deselectTable(table: Table): void; + deselectTable(table: ConnectionTable): void; } diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 5931cbd8..239c1907 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -17,11 +17,9 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; -import { Connection } from "@connections/shared/connection.model"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; -import { NameValue } from "@dataservices/shared/name-value.model"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbModelSource } from "@dataservices/shared/vdb-model-source.model"; import { VdbModel } from "@dataservices/shared/vdb-model.model"; @@ -112,38 +110,6 @@ export class VdbService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } - /** - * Derive the source vdb name from the given connection - * - * @param {Connection} connection - * @returns {string} - */ - public deriveSourceVdbName(connection: Connection): string { - const name = connection.getId() + VdbsConstants.SOURCE_VDB_SUFFIX; - return name.toLowerCase(); - } - - /** - * Derive the vdb model name from the given connection - * - * @param {Connection} connection - * @returns {string} - */ - public deriveVdbModelName(connection: Connection): string { - return connection.getId().toLowerCase(); - } - - /** - * Derive the vdb model source name from the given connection - * - * @param {Connection} connection - * @returns {string} - */ - public deriveVdbModelSourceName(connection: Connection): string { - return connection.getServiceCatalogSourceName() ? - connection.getServiceCatalogSourceName() : connection.getId().toLowerCase(); - } - /** * Create a vdb via the komodo rest interface * @param {Vdb} vdb @@ -247,25 +213,6 @@ export class VdbService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } - /** - * Update the specified repo VDB Model using the DDL from the specified Teiid VDB - * @param {string} vdbName the VDB in the repo to update - * @param {string} modelName the Model withing the specified repo VDB - * @param {string} teiidVdbName the deployed teiid VDB name - * @param {string} teiidModelName the teiid VDB Model name - * @returns {Observable} - */ - public updateVdbModelFromTeiid(vdbName: string, modelName: string, - teiidVdbName: string, teiidModelName: string): Observable { - return this.http - .post(environment.komodoTeiidUrl + VdbsConstants.vdbsRootPath + "/ModelFromTeiidDdl", - { vdbName, modelName, teiidVdbName, teiidModelName }, this.getAuthRequestOptions()) - .map((response) => { - return response.ok; - }) - .catch( ( error ) => this.handleError( error ) ); - } - /** * Polls the server for the specified VDB. Polling will terminate if * (1) The VDB is active @@ -333,55 +280,6 @@ export class VdbService extends ApiService { }); } - /** - * Create and deploy a VDB for the provided connection. - * @param {Connection} connection - * @returns {Observable} - */ - public deployVdbForConnection(connection: Connection): Observable { - const vdbName = this.deriveSourceVdbName(connection); - const vdbModelName = this.deriveVdbModelName(connection); - const vdbModelSourceName = this.deriveVdbModelSourceName(connection); - - // VDB to create - const vdb = new Vdb(); - vdb.setName(vdbName); - vdb.setId(vdbName); - const vdbPath = this.getKomodoUserWorkspacePath() + "/" + vdbName; - vdb.setDataPath(vdbPath); - vdb.setOriginalFile(vdbPath); - vdb.setDescription(vdbName + " description"); - - // VDB Model to create - const vdbModel = new VdbModel(); - vdbModel.setId(vdbModelName); - vdbModel.setDataPath(vdbPath + "/" + vdbModelName); - vdbModel.setModelType("PHYSICAL"); - - // Set the importer properties for the physical model - const props: NameValue[] = []; - props.push(new NameValue("importer.TableTypes", "TABLE")); - props.push(new NameValue("importer.UseQualifiedName", "true")); - props.push(new NameValue("importer.UseCatalogName", "false")); - props.push(new NameValue("importer.UseFullSchemaName", "false")); - vdbModel.setProperties(props); - - // VdbModelSource to create - const vdbModelSource = new VdbModelSource(); - vdbModelSource.setId(vdbModelSourceName); - vdbModelSource.setDataPath(vdbPath + "/" + vdbModelName + "/vdb:sources/" + vdbModelSourceName); - vdbModelSource.setJndiName(connection.getJndiName()); - vdbModelSource.setTranslatorName(connection.getDriverName()); - vdbModelSource.setOriginConnection(connection.getDataPath()); - - // Chain the individual calls together in series to build the Vdb and deploy it - return this.deleteVdbIfFound(vdb.getId()) - .flatMap((res) => this.createVdb(vdb)) - .flatMap((res) => this.createVdbModel(vdb.getId(), vdbModel)) - .flatMap((res) => this.createVdbModelSource(vdb.getId(), vdbModel.getId(), vdbModelSource)) - .flatMap((res) => this.deployVdb(vdb.getId())); - } - /** * Deletes the workspace VDB if found. Checks the workspace first, before attempting the delete. * If the VDB is not found the delete attempt is skipped. diff --git a/ngapp/src/app/dataservices/shared/vdbs-constants.ts b/ngapp/src/app/dataservices/shared/vdbs-constants.ts index b9cd4ef4..11eae304 100644 --- a/ngapp/src/app/dataservices/shared/vdbs-constants.ts +++ b/ngapp/src/app/dataservices/shared/vdbs-constants.ts @@ -13,7 +13,8 @@ export class VdbsConstants { public static readonly SERVICE_VIEW_MODEL_NAME = "views"; // ** must match KomodoDataserviceService.SERVICE_VDB_VIEW_MODEL ** - public static readonly SOURCE_VDB_SUFFIX = "btlsource"; + public static readonly SCHEMA_VDB_SUFFIX = "schemavdb"; + public static readonly SCHEMA_MODEL_SUFFIX = "schemamodel"; public static readonly DATASERVICE_VDB_SUFFIX = "vdb"; public static readonly DEFAULT_READONLY_DATA_ROLE = "DefaultReadOnlyDataRole"; diff --git a/ngapp/src/app/dataservices/shared/table.model.ts b/ngapp/src/app/dataservices/shared/view.model.ts similarity index 98% rename from ngapp/src/app/dataservices/shared/table.model.ts rename to ngapp/src/app/dataservices/shared/view.model.ts index 983641ec..3000e333 100644 --- a/ngapp/src/app/dataservices/shared/table.model.ts +++ b/ngapp/src/app/dataservices/shared/view.model.ts @@ -18,9 +18,9 @@ import { Connection } from "@connections/shared/connection.model"; /** - * Table model + * View model */ -export class Table { +export class View { private name: string; private connection: Connection; private catalogName: string; diff --git a/ngapp/src/app/dataservices/shared/wizard.service.ts b/ngapp/src/app/dataservices/shared/wizard.service.ts index d964df74..075df3a6 100644 --- a/ngapp/src/app/dataservices/shared/wizard.service.ts +++ b/ngapp/src/app/dataservices/shared/wizard.service.ts @@ -1,12 +1,12 @@ import { Injectable } from "@angular/core"; +import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; -import { Table } from "@dataservices/shared/table.model"; @Injectable() export class WizardService { - private wizardSelectedTablesArray: Table[] = []; + private selectedConnectionTables: ConnectionTable[] = []; private edit = false; private currentConnections: Connection[] = []; private selectedDataservice: Dataservice; @@ -67,51 +67,51 @@ export class WizardService { /** * Get the wizard table selections - * @returns {Table[]} the selections + * @returns {ConnectionTable[]} the selections */ - public getWizardSelectedTables( ): Table[] { - return this.wizardSelectedTablesArray.sort( + public getSelectedConnectionTables( ): ConnectionTable[] { + return this.selectedConnectionTables.sort( ( thisTable, thatTable ) => { - return thisTable.getName().localeCompare( thatTable.getName() ); + return thisTable.getId().localeCompare( thatTable.getId() ); } ); } /** - * Clears the list of wizard table selections + * Clears the list of selected connection tables */ - public clearWizardSelectedTables( ): void { - this.wizardSelectedTablesArray = []; + public clearSelectedConnectionTables( ): void { + this.selectedConnectionTables = []; } /** - * Determine if the supplied table is one of the current selections in the wizard - * @param {Table} table the table + * Determine if the supplied table is one of the current selections + * @param {ConnectionTable} table the table */ - public isWizardSelectedTable(table: Table): boolean { - return this.getWizardTableIndex(table) > -1; + public isConnectionTableSelected(table: ConnectionTable): boolean { + return this.getConnectionTableIndex(table) > -1; } /** - * Add a table to the current wizard selections - * @param {Table} tableToAdd table to add + * Add a table to the currently selected connection tables + * @param {ConnectionTable} tableToAdd table to add */ - public addToWizardSelectionTables(tableToAdd: Table): void { - if (!this.isWizardSelectedTable(tableToAdd)) { - this.wizardSelectedTablesArray.push(tableToAdd); + public addToSelectedConnectionTables(tableToAdd: ConnectionTable): void { + if (!this.isConnectionTableSelected(tableToAdd)) { + this.selectedConnectionTables.push(tableToAdd); } } /** - * Remove a table from the current wizard selections - * @param {Table} tableToRemove + * Remove a table from the currently selected connection tables + * @param {ConnectionTable} tableToRemove * @returns {boolean} */ - public removeFromWizardSelectionTables(tableToRemove: Table): boolean { + public removeFromSelectedConnectionTables(tableToRemove: ConnectionTable): boolean { let wasRemoved = false; - const index = this.getWizardTableIndex(tableToRemove); + const index = this.getConnectionTableIndex(tableToRemove); if (index > -1) { - this.wizardSelectedTablesArray.splice(index, 1); + this.selectedConnectionTables.splice(index, 1); wasRemoved = true; } @@ -173,17 +173,17 @@ export class WizardService { } /** - * Find index of the table in the wizard selected tables list. -1 if not found - * @param {Table} table + * Find index of the connection table in the wizard selected tables list. -1 if not found + * @param {ConnectionTable} table connection table * @returns {number} */ - private getWizardTableIndex(table: Table): number { + private getConnectionTableIndex(table: ConnectionTable): number { // supplied table and connection const connName = table.getConnection().getId(); - const tableName = table.getName(); + const tableName = table.getId(); let i = 0; - for (const wizTable of this.wizardSelectedTablesArray) { - const wizTableName = wizTable.getName(); + for (const wizTable of this.selectedConnectionTables) { + const wizTableName = wizTable.getId(); const wizConnName = wizTable.getConnection().getId(); if (wizTableName === tableName && wizConnName === connName) { return i; diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts index f020a6d7..f51ecfa7 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts @@ -10,8 +10,8 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; -import { Table } from "@dataservices/shared/table.model"; import { VdbService } from "@dataservices/shared/vdb.service"; +import { View } from "@dataservices/shared/view.model"; import { CodemirrorModule } from "ng2-codemirror"; import { PatternFlyNgModule } from "patternfly-ng"; import { SqlControlComponent } from "./sql-control.component"; @@ -51,12 +51,12 @@ describe("SqlControlComponent", () => { // Set the inputs for the component component.viewSql = "SELECT * FROM views.View1"; - const table = new Table(); - table.setName("views.View1"); - const tables: Table[] = []; - tables.push(table); - component.serviceViews = tables; - component.selectedViews = tables; + const view = new View(); + view.setName("views.View1"); + const views: View[] = []; + views.push(view); + component.serviceViews = views; + component.selectedViews = views; fixture.detectChanges(); }); diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts index 1c8a0390..19ee3e55 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts @@ -22,7 +22,7 @@ import { ColumnData } from "@dataservices/shared/column-data.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { QueryResults } from "@dataservices/shared/query-results.model"; import { RowData } from "@dataservices/shared/row-data.model"; -import { Table } from "@dataservices/shared/table.model"; +import { View } from "@dataservices/shared/view.model"; import { LoadingState } from "@shared/loading-state.enum"; import "codemirror/addon/display/placeholder.js"; import "codemirror/addon/selection/active-line.js"; @@ -38,8 +38,8 @@ import { NgxDataTableConfig, TableConfig } from "patternfly-ng"; export class SqlControlComponent implements OnInit { @Input() public quicklook = false; - @Input() public selectedViews: Table[] = []; - @Input() public serviceViews: Table[] = []; + @Input() public selectedViews: View[] = []; + @Input() public serviceViews: View[] = []; @Input() public viewSql = ""; public ngxConfig: NgxDataTableConfig; @@ -123,8 +123,8 @@ export class SqlControlComponent implements OnInit { this.queryMap.set(this.previousViewName, this.queryText); // View table is single select so use first element - const selected: Table[] = $event.selected; - const view: Table = selected[ 0 ]; + const selected: View[] = $event.selected; + const view: View = selected[ 0 ]; this.selectedViews = []; this.selectedViews.push(view); diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts index 9e9fa75f..00eef5b3 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts @@ -5,7 +5,7 @@ import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; -import { Table } from "@dataservices/shared/table.model"; +import { View } from "@dataservices/shared/view.model"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { LoadingState } from "@shared/loading-state.enum"; @@ -23,8 +23,8 @@ export class TestDataserviceComponent extends AbstractPageComponent { private dataservice: Dataservice; private dataserviceService: DataserviceService; private pageLoadingState: LoadingState = LoadingState.LOADED_VALID; - private selectedSvcViews: Table[] = []; - private allSvcViews: Table[] = []; + private selectedSvcViews: View[] = []; + private allSvcViews: View[] = []; private quickLookQueryText: string; constructor( router: Router, route: ActivatedRoute, dataserviceService: DataserviceService, logger: LoggerService ) { @@ -58,14 +58,14 @@ export class TestDataserviceComponent extends AbstractPageComponent { /** * Accessor for all available service views */ - public get allServiceViews( ): Table[] { + public get allServiceViews( ): View[] { return this.allSvcViews; } /** * Accessor for selected service view */ - public get selectedViews( ): Table[] { + public get selectedViews( ): View[] { return this.selectedSvcViews; } diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 171c0701..5495d51e 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -17,6 +17,7 @@ import { Injectable } from "@angular/core"; import { ConnectionStatus } from "@connections/shared/connection-status"; +import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; import { SchemaInfo } from "@connections/shared/schema-info.model"; import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; @@ -406,30 +407,29 @@ export class TestDataService { ]; // ================================================================= - // SchemaInfos for the connections + // ConnectionTables for the connections // ================================================================= - - private static pgConnSchemaInfos = [ - SchemaInfo.create( { name: "pgConnSchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "pgConnCatalogInfo", type: "Catalog", schemaNames: [ "pgConnCatalogSchema1", "pgConnCatalogSchema2" ] } ) + private static pgConnConnectionTables = [ + TestDataService.createConnectionTable("pgTable1", TestDataService.pgConn, false), + TestDataService.createConnectionTable("pgTable2", TestDataService.pgConn, false) ]; - private static conn1SchemaInfos = [ - SchemaInfo.create( { name: "conn1SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn1CatalogInfo", type: "Catalog", schemaNames: [ "conn1CatalogSchema1", "conn1CatalogSchema2" ] } ) + private static conn1ConnectionTables = [ + TestDataService.createConnectionTable("conn1Table1", TestDataService.conn1, false), + TestDataService.createConnectionTable("conn1Table2", TestDataService.conn1, false) ]; - private static conn2SchemaInfos = [ - SchemaInfo.create( { name: "conn2CatalogInfo", type: "Catalog", schemaNames: [ "conn2CatalogSchema1", "conn2CatalogSchema2" ] } ), - SchemaInfo.create( { name: "conn2SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn2SchemaInfo2", type: "Schema" } ) + private static conn2ConnectionTables = [ + TestDataService.createConnectionTable("conn2Table1", TestDataService.conn2, false), + TestDataService.createConnectionTable("conn2Table2", TestDataService.conn2, false), + TestDataService.createConnectionTable("conn2Table3", TestDataService.conn2, false), ]; - private static conn3SchemaInfos = [ - SchemaInfo.create( { name: "conn3CatalogInfo", type: "Catalog", schemaNames: [ "conn3CatalogSchema1", "conn3CatalogSchema2" ] } ), - SchemaInfo.create( { name: "conn3SchemaInfo1", type: "Schema" } ), - SchemaInfo.create( { name: "conn3SchemaInfo2", type: "Schema" } ), - SchemaInfo.create( { name: "conn3SchemaInfo3", type: "Schema" } ) + private static conn3ConnectionTables = [ + TestDataService.createConnectionTable("conn3Table1", TestDataService.conn3, false), + TestDataService.createConnectionTable("conn3Table2", TestDataService.conn3, false), + TestDataService.createConnectionTable("conn3Table3", TestDataService.conn3, false), + TestDataService.createConnectionTable("conn3Table4", TestDataService.conn3, false) ]; // ================================================================= @@ -926,7 +926,7 @@ export class TestDataService { TestDataService.productsVdb ]; - private jdbcTableMap = new Map(); + private connectionTableMap = new Map(); private vdbStatuses: VdbStatus[]; private virtualizations: Virtualization[]; @@ -960,6 +960,21 @@ export class TestDataService { return connectionSummary; } + /** + * Create a ConnectionTable using the specified info + * @param {string} name the connection table name + * @param {Connection} connection the connection + * @param {boolean} selected 'true' if the table is selected + * @returns {ConnectionSummary} + */ + private static createConnectionTable( name: string, connection: Connection, selected: boolean ): ConnectionTable { + const connectionTable = new ConnectionTable(); + connectionTable.setId(name); + connectionTable.setConnection(connection); + connectionTable.selected = selected; + return connectionTable; + } + constructor() { this.vdbStatuses = TestDataService.vdbStatuses.vdbs.map(( vdbStatus ) => VdbStatus.create( vdbStatus ) ); this.virtualizations = [ @@ -967,105 +982,6 @@ export class TestDataService { TestDataService.employeesVirtualization, TestDataService.productsVirtualization ]; - - this.jdbcTableMap.set( "pgConnSchemaInfo1", [ - "pgConnTable1", - "pgConnTable2", - "pgConnTable3", - "pgConnTable4", - "pgConnTable5", - "pgConnTable6" - ] ); - this.jdbcTableMap.set( "pgConnCatalogSchema1", [ - "pgConnTableA", - "pgConnTableB", - "pgConnTableC", - "pgConnTableD", - "pgConnTableE", - "pgConnTableF", - "pgConnTableG" - ] ); - this.jdbcTableMap.set( "pgConnCatalogSchema2", [ - "cat2TableRed", - "cat2TableWhite", - "cat2TableBlue" - ] ); - this.jdbcTableMap.set( "conn1SchemaInfo1", [ - "conn1Table1", - "conn1Table2", - "conn1Table3", - "conn1Table4", - "conn1Table5", - "conn1Table6" - ] ); - this.jdbcTableMap.set( "conn1CatalogSchema1", [ - "conn1TableA", - "conn1TableB", - "conn1TableC", - "conn1TableD", - "conn1TableE", - "conn1TableF", - "conn1TableG" - ] ); - this.jdbcTableMap.set( "conn1CatalogSchema2", [ - "conn1TableRed", - "conn1TableWhite", - "conn1TableBlue" - ] ); - this.jdbcTableMap.set( "conn2CatalogSchema1", [ - "conn2Table1", - "conn2Table2", - "conn2Table3", - "conn2Table4", - "conn2Table5", - "conn2Table6", - "conn2Table7" - ] ); - this.jdbcTableMap.set( "conn2CatalogSchema2", [ - "conn2Cat2TableA", - "conn2Cat2TableB", - "conn2Cat2TableC", - "conn2Cat2TableD", - "conn2Cat2TableE", - "conn2Cat2TableF", - "conn2Cat2TableG" - ] ); - this.jdbcTableMap.set( "conn2SchemaInfo1", [ - "conn2TableLarry", - "conn2TableCurly", - "conn2TableMoe" - ] ); - this.jdbcTableMap.set( "conn2SchemaInfo2", [ - "conn2TableRed", - "conn2TableWhite", - "conn2TableBlue" - ] ); - this.jdbcTableMap.set( "conn3CatalogSchema1", [ - "conn3Table1", - "conn3Table2", - "conn3Table3", - "conn2Table4" - ] ); - this.jdbcTableMap.set( "conn3CatalogSchema2", [ - "conn3Cat2TableA", - "conn3Cat2TableB", - "conn3Cat2TableC" - ] ); - this.jdbcTableMap.set( "conn3SchemaInfo1", [ - "conn3TableJohn", - "conn3TablePaul", - "conn3TableRingo" - ] ); - this.jdbcTableMap.set( "conn3SchemaInfo2", [ - "conn3TablePurple", - "conn3TableBlue", - "conn3TableGreen" - ] ); - this.jdbcTableMap.set( "conn3SchemaInfo3", [ - "conn3TableOrange", - "conn3TableYellow", - "conn3TableBrown" - ] ); } /** @@ -1091,18 +1007,6 @@ export class TestDataService { return this.catalogSources; } - /** - * @returns {Map} the array of test Service Catalog datasources - */ - public getConnectionSourceSchemaInfoMap( ): Map { - const infoMap = new Map(); - infoMap.set( TestDataService.pgConn.getServiceCatalogSourceName(), TestDataService.pgConnSchemaInfos ); - infoMap.set( TestDataService.conn1.getServiceCatalogSourceName(), TestDataService.conn1SchemaInfos ); - infoMap.set( TestDataService.conn2.getServiceCatalogSourceName(), TestDataService.conn2SchemaInfos ); - infoMap.set( TestDataService.conn3.getServiceCatalogSourceName(), TestDataService.conn3SchemaInfos ); - return infoMap; - } - /** * @returns {Dataservice[]} the array of test dataservices */ @@ -1118,8 +1022,16 @@ export class TestDataService { return new QueryResults(TestDataService.employeeJson); } - public getJdbcConnectionTableMap(): Map { - return this.jdbcTableMap; + /** + * @returns {Map} the array of test Service Catalog datasources + */ + public getConnectionTableMap(): Map { + const tableMap = new Map(); + tableMap.set( TestDataService.pgConn.getId(), TestDataService.pgConnConnectionTables ); + tableMap.set( TestDataService.conn1.getId(), TestDataService.conn1ConnectionTables ); + tableMap.set( TestDataService.conn2.getId(), TestDataService.conn2ConnectionTables ); + tableMap.set( TestDataService.conn3.getId(), TestDataService.conn3ConnectionTables ); + return tableMap; } /** From dfcd95fecbb043cf279353cf0d9eaa7963b9433e Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 17 Apr 2018 14:12:58 -0500 Subject: [PATCH 134/205] TTOOLS-410 Resolve issue with duplicate empty states --- ngapp/src/app/connections/connections.component.html | 4 ++-- ngapp/src/app/connections/connections.component.ts | 7 +++++++ ngapp/src/app/dataservices/dataservices.component.html | 4 ++-- ngapp/src/app/dataservices/dataservices.component.ts | 7 +++++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index 70796825..d3d56a5a 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -63,7 +63,7 @@

    - (deleteConnection)="onDelete($event)" (connectionSelected)="onSelected($event)" (connectionDeselected)="onDeselected($event)"> - 0; + } + /** * @returns {Connection[]} the array of filtered connections */ diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 42d2533f..3ff4db46 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -82,13 +82,13 @@

    - - 0; + } + /** * @returns {Dataservice[]} the array of filtered dataservices */ From e799b61f23157056b97f8b925535c778cae8ed1b Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 17 Apr 2018 16:07:36 -0500 Subject: [PATCH 135/205] TEIIDTOOLS-389 Improve page header inconsistency --- .../add-connection-wizard/add-connection-wizard.component.ts | 1 - .../connections/add-connection/add-connection.component.html | 2 +- .../add-dataservice-wizard/add-dataservice-wizard.component.ts | 1 - .../dataservices/add-dataservice/add-dataservice.component.html | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index 09408d52..b1abd755 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -134,7 +134,6 @@ export class AddConnectionWizardComponent implements OnInit { embedInPage: true, loadingTitle: "Add Connection Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", - title: "Add Connection", contentHeight: "500px", done: false } as WizardConfig; diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index 40601fa9..c2d394bf 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -7,7 +7,7 @@
    -

    +

    Add Connection

    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 58e5311d..06ac2232 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -138,7 +138,6 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { embedInPage: true, loadingTitle: "Dataservice Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", - title: "Dataservice Wizard", contentHeight: "500px", done: false } as WizardConfig; diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html index 2d38b360..0f47c5f5 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html @@ -7,7 +7,7 @@
    -

    +

    Add Dataservice

    From 41ad01b7437f8144e5b2238582b820b4e7a4f7df Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 17 Apr 2018 15:22:11 -0500 Subject: [PATCH 136/205] TEIIDTOOLS-411 Change terminology to Data Virtualization --- .../add-connection-wizard.component.html | 6 ++--- .../add-connection-wizard.component.ts | 2 +- .../add-dataservice-wizard.component.html | 6 ++--- .../add-dataservice-wizard.component.ts | 22 +++++++++---------- .../add-dataservice.component.html | 6 ++--- .../dataservices/dataservices.component.html | 12 +++++----- .../dataservices.component.spec.ts | 6 ++--- .../dataservices/dataservices.component.ts | 12 +++++----- .../shared/dataservice.service.ts | 14 ++++++------ .../shared/dataservices-constants.ts | 18 +++++++-------- .../shared/mock-dataservice.service.ts | 4 ++-- .../test-dataservice.component.html | 10 ++++----- 12 files changed, 59 insertions(+), 59 deletions(-) diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html index 29322943..f22fd15b 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html @@ -67,16 +67,16 @@

    {{ step2InstructionMessage }}

    - +
    - +
    -

    - +
    @@ -54,7 +54,7 @@

    {{ step2InstructionMessage }}

    Connection
    -
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 06ac2232..93faa448 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -136,7 +136,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { // Wizard Configuration this.wizardConfig = { embedInPage: true, - loadingTitle: "Dataservice Wizard loading", + loadingTitle: "Data Virtualization Wizard loading", loadingSecondaryInfo: "Please wait for the wizard to finish loading...", contentHeight: "500px", done: false @@ -218,7 +218,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { */ public get step1InstructionMessage(): string { if (!this.tableSelector.valid) { - return "Please select tables for the Dataservice"; + return "Please select tables for the Data virtualization"; } else { return "Select tables, then click Next to continue"; } @@ -229,9 +229,9 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { */ public get step2InstructionMessage(): string { if (this.wizardService.isEdit()) { - return "Review selections. Click Update to update the Dataservice"; + return "Review selections. Click Update to update the Virtualization"; } - return "Enter a name, select a connection, and review the table selections. Click Create to create the Dataservice"; + return "Enter a name, select a connection, and review the table selections. Click Create to create the Virtualization"; } /* @@ -502,10 +502,10 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.createSuccessful = false; if (this.wizardService.isEdit()) { this.theFinalPageTitle = "Update in progress"; - this.theFinalPageMessage = "The dataservice is being updated."; + this.theFinalPageMessage = "The virtualization is being updated."; } else { this.theFinalPageTitle = "Creation in progress"; - this.theFinalPageMessage = "The dataservice is being created."; + this.theFinalPageMessage = "The virtualization is being created."; } this.step2bConfig.nextEnabled = false; this.step2bConfig.previousEnabled = false; @@ -523,18 +523,18 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if (wasSuccessful) { if (this.wizardService.isEdit()) { this.theFinalPageTitle = "Update was successful"; - this.theFinalPageMessage = "The dataservice was updated successfully. Click on the button to see all dataservices."; + this.theFinalPageMessage = "The data virtualization was updated successfully. Click on the button to see all virtualizations."; } else { this.theFinalPageTitle = "Creation was successful"; - this.theFinalPageMessage = "The dataservice was created successfully. Click on the button to see all dataservices."; + this.theFinalPageMessage = "The data virtualization was created successfully. Click on the button to see all virtualizations."; } } else { if (this.wizardService.isEdit()) { this.theFinalPageTitle = "Update failed"; - this.theFinalPageMessage = "The dataservice update failed!"; + this.theFinalPageMessage = "The data virtualization update failed!"; } else { this.theFinalPageTitle = "Creation failed"; - this.theFinalPageMessage = "The dataservice creation failed!"; + this.theFinalPageMessage = "The data virtualization creation failed!"; } } } @@ -555,7 +555,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } // Error visible if message has content if (this.errorDetailMessage.length === 0) { - this.errorDetailMessage = "Please check dataservice entries and retry"; + this.errorDetailMessage = "Please check data virtualization entries and retry"; } } diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html index 0f47c5f5..92437681 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html @@ -1,13 +1,13 @@
    -
  • -
  • +
  • +
  • -

    Add Dataservice

    +

    Add Data Virtualization

    diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 3ff4db46..15affbad 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -2,7 +2,7 @@
    -
  • +
  • @@ -10,7 +10,7 @@
    -

    Dataservices

    +

    Data Virtualizations

    @@ -23,7 +23,7 @@

    Dataservices

      @@ -61,7 +61,7 @@

      Dataservices

      - Loading Dataservices... + Loading Data Virtualizations...

    @@ -101,7 +101,7 @@

    - Quick Look Results for Dataservice '{{ quickLookServiceName }}' + Quick Look Results for Data Virtualization '{{ quickLookServiceName }}'

    @@ -114,5 +114,5 @@

    -

    Do you really want to delete the selected Dataservice?

    +

    Do you really want to delete the selected Virtualization?

    diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ngapp/src/app/dataservices/dataservices.component.spec.ts index 56ba94db..f865e24d 100644 --- a/ngapp/src/app/dataservices/dataservices.component.spec.ts +++ b/ngapp/src/app/dataservices/dataservices.component.spec.ts @@ -62,12 +62,12 @@ describe("DataservicesComponent", () => { expect(component).toBeTruthy(); }); - it("should have Dataservices Title", () => { - console.log("========== [DataservicesComponent] should have Dataservices Title"); + it("should have Data Virtualizations Title", () => { + console.log("========== [DataservicesComponent] should have Data Virtualizations Title"); // query for the title

    by CSS element selector const de = fixture.debugElement.query(By.css("h2")); const el = de.nativeElement; - expect(el.textContent).toEqual("Dataservices"); + expect(el.textContent).toEqual("Data Virtualizations"); }); it("should have Toolbar", () => { diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index f3701cfa..d65f18e6 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -178,9 +178,9 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.noConnectionsConfig = { actions: actionConfig, iconStyleClass: "pficon-warning-triangle-o", - info: "No dataservices were found. In order to create a dataservice, you must first create a connection. " + info: "No Data virtualizations were found. In order to create a virtualization, you must first create a connection. " + "Please click below to create a connection.", - title: "No Dataservices Available" + title: "No Data Virtualizations Available" } as EmptyStateConfig; } @@ -193,8 +193,8 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn primaryActions: [ { id: "createDataserviceActionId", - title: "Add Dataservice", - tooltip: "Add a dataservice" + title: "Add Data Virtualization", + tooltip: "Add a data virtualization" } ] } as ActionConfig; @@ -202,8 +202,8 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.noDataservicesConfig = { actions: actionConfig, iconStyleClass: "pficon-warning-triangle-o", - info: "No dataservices were found. Please click below to create a dataservice.", - title: "No Dataservices Available" + info: "No Data virtualizations were found. Please click below to create a virtualization.", + title: "No Data Virtualizations Available" } as EmptyStateConfig; } diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 33d99249..60c6a625 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -45,7 +45,7 @@ import { Subscription } from "rxjs/Subscription"; export class DataserviceService extends ApiService { private static readonly nameValidationUrl = environment.komodoWorkspaceUrl - + DataservicesConstants.dataservicesRootPath + + DataservicesConstants.dataservicesRestPath + "/nameValidation/"; // Observable dataservice state changes @@ -163,7 +163,7 @@ export class DataserviceService extends ApiService { */ public isValidName( name: string ): Observable< string > { if ( !name || name.length === 0 ) { - return Observable.of( "Dataservice name cannot be empty" ); + return Observable.of( "Data virtualization name cannot be empty" ); } const url = DataserviceService.nameValidationUrl + encodeURIComponent( name ); @@ -186,7 +186,7 @@ export class DataserviceService extends ApiService { */ public getAllDataservices(): Observable { return this.http - .get(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath, this.getAuthRequestOptions()) + .get(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRestPath, this.getAuthRequestOptions()) .map((response) => { const dataservices = response.json(); return dataservices.map((dataservice) => Dataservice.create( dataservice )); @@ -201,7 +201,7 @@ export class DataserviceService extends ApiService { */ public createDataservice(dataservice: NewDataservice): Observable { return this.http - .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/" + dataservice.getId(), + .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRestPath + "/" + dataservice.getId(), dataservice, this.getAuthRequestOptions()) .map((response) => { return response.ok; @@ -217,7 +217,7 @@ export class DataserviceService extends ApiService { public deployDataservice(dataserviceName: string): Observable { const servicePath = this.getKomodoUserWorkspacePath() + "/" + dataserviceName; return this.http - .post(environment.komodoTeiidUrl + DataservicesConstants.dataserviceRootPath, + .post(environment.komodoTeiidUrl + DataservicesConstants.dataserviceRestPath, { path: servicePath}, this.getAuthRequestOptions()) .map((response) => { return response.ok; @@ -234,7 +234,7 @@ export class DataserviceService extends ApiService { */ public setServiceVdbForSingleSourceTables(dataserviceName: string, tablePaths: string[], modelSourcePath: string): Observable { return this.http - .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/ServiceVdbForSingleSourceTables", + .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRestPath + "/ServiceVdbForSingleSourceTables", { dataserviceName, tablePaths, modelSourcePath}, this.getAuthRequestOptions()) .map((response) => { return response.ok; @@ -311,7 +311,7 @@ export class DataserviceService extends ApiService { */ public deleteDataservice(dataserviceId: string): Observable { return this.http - .delete(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRootPath + "/" + dataserviceId, + .delete(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRestPath + "/" + dataserviceId, this.getAuthRequestOptions()) .map((response) => { return response.ok; diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ngapp/src/app/dataservices/shared/dataservices-constants.ts index 56c6c79c..5a507e69 100644 --- a/ngapp/src/app/dataservices/shared/dataservices-constants.ts +++ b/ngapp/src/app/dataservices/shared/dataservices-constants.ts @@ -17,23 +17,23 @@ export class DataservicesConstants { public static readonly dataservicesExport = "export"; public static readonly dataservicesPublish = "publish"; - public static readonly dataserviceRootRoute = "dataservice"; - public static readonly dataserviceRootPath = "/" + DataservicesConstants.dataserviceRootRoute; - - public static readonly dataservicesRootRoute = "dataservices"; + public static readonly dataservicesRootRoute = "virtualizations"; public static readonly dataservicesRootPath = "/" + DataservicesConstants.dataservicesRootRoute; - public static readonly addDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/add-dataservice"; - public static readonly addDataservicePath = DataservicesConstants.dataservicesRootPath + "/add-dataservice"; + public static readonly dataserviceRestPath = "/dataservice"; + public static readonly dataservicesRestPath = "/dataservices"; + + public static readonly addDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/add-virtualization"; + public static readonly addDataservicePath = DataservicesConstants.dataservicesRootPath + "/add-virtualization"; - public static readonly testDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/test-dataservice"; - public static readonly testDataservicePath = DataservicesConstants.dataservicesRootPath + "/test-dataservice"; + public static readonly testDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/test-virtualization"; + public static readonly testDataservicePath = DataservicesConstants.dataservicesRootPath + "/test-virtualization"; public static dataserviceNameLabel = "Name"; public static descriptionLabel = "Description"; public static readonly dataservicesNavItem: NavigationItemConfig = { - title: "Data Services", + title: "Virtualizations", iconStyleClass: "fa fa-fw fa-table", url: DataservicesConstants.dataservicesRootPath }; diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index bc0912da..5fd3ffd8 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -125,13 +125,13 @@ export class MockDataserviceService extends DataserviceService { public isValidName( name: string ): Observable { if ( !name || name.length === 0 ) { - return Observable.of( "Dataservice name cannot be empty" ); + return Observable.of( "Data virtualization name cannot be empty" ); } // make sure no dataservice exists with that name for ( const ds of this.services ) { if ( ds.getId() === name ) { - return Observable.of( "Dataservice with that name already exists" ); + return Observable.of( "Data virtualization with that name already exists" ); } } diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html index bef82751..108fd188 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html @@ -1,26 +1,26 @@
    -
  • -
  • +
  • +
  • -

    Test Dataservice '{{ this.dataservice.getId() }}'

    +

    Test Data Virtualization '{{ this.dataservice.getId() }}'

    - Deploying the Dataservice... + Deploying the Data Virtualization...
    - There was an error deploying the Dataservice! + There was an error deploying the Data Virtualization!
    From 7afa63a31aac80746b83c96b81502a92800f76d8 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 19 Apr 2018 08:23:14 -0500 Subject: [PATCH 137/205] TEIIDTOOLS-312 Adds support for Mongo --- .../connections/shared/connection.service.ts | 8 ++-- .../add-dataservice-wizard.component.ts | 2 + .../dataservices/dataservices.component.ts | 5 ++- .../app/dataservices/shared/wizard.service.ts | 37 +++++++++++++++++++ ngapp/src/app/shared/test-data.service.ts | 16 +++++++- 5 files changed, 62 insertions(+), 6 deletions(-) diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index 8d17c769..eb556449 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -183,16 +183,16 @@ export class ConnectionService extends ApiService { const connType2: ConnectionType = new ConnectionType(); connType2.setName(ConnectionsConstants.connectionType_mysql); connType2.setDescription(ConnectionsConstants.connectionTypeDescription_mysql); - // const connType3: ConnectionType = new ConnectionType(); - // connType3.setName(ConnectionsConstants.connectionType_mongodb); - // connType3.setDescription(ConnectionsConstants.connectionTypeDescription_mongodb); + const connType3: ConnectionType = new ConnectionType(); + connType3.setName(ConnectionsConstants.connectionType_mongodb); + connType3.setDescription(ConnectionsConstants.connectionTypeDescription_mongodb); // const connType4: ConnectionType = new ConnectionType(); // connType4.setName(ConnectionsConstants.connectionType_mariadb); // connType4.setDescription(ConnectionsConstants.connectionTypeDescription_mariadb); connectionTypes.push(connType1); connectionTypes.push(connType2); - // connectionTypes.push(connType3); + connectionTypes.push(connType3); // connectionTypes.push(connType4); return connectionTypes; diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 93faa448..82b98ba6 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -432,6 +432,8 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { // Dataservice basic properties from step 1 const dataservice: NewDataservice = this.dataserviceService.newDataserviceInstance(this.dataserviceName, this.dataserviceDescription); + // designate with wizard service that this dataservice is newly created. + this.wizardService.setNewlyAddedDataservice(this.dataserviceName); const self = this; this.dataserviceService .createDataserviceForSingleSourceTables(dataservice, this.tableSelector.getSelectedTables()) diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index d65f18e6..a474ffbb 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -64,7 +64,6 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn public readonly exportFailedHeader: string = "Publishing Failed: "; public readonly connectionsLoadedTag = "connections"; - public readonly downloadInProgressHeader: string = "Downloading: "; public readonly downloadSuccessHeader: string = "Download Succeeded: "; public readonly downloadFailedHeader: string = "Download Failed: "; @@ -702,6 +701,10 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn // For displayed dataservices, update the Deployment State using supplied services for ( const dService of this.filteredDataservices ) { const serviceId = dService.getId(); + // For newly added services, leave state alone until wait expires + if (serviceId === this.wizardService.getNewlyAddedDataservice()) { + continue; + } if (stateMap && stateMap.has(serviceId)) { dService.setServiceDeploymentState(stateMap.get(serviceId)); } diff --git a/ngapp/src/app/dataservices/shared/wizard.service.ts b/ngapp/src/app/dataservices/shared/wizard.service.ts index 075df3a6..e3c6c1bd 100644 --- a/ngapp/src/app/dataservices/shared/wizard.service.ts +++ b/ngapp/src/app/dataservices/shared/wizard.service.ts @@ -6,12 +6,16 @@ import { Dataservice } from "@dataservices/shared/dataservice.model"; @Injectable() export class WizardService { + private static newlyAddedServiceWaitMillis = 5000; // Wait of 5 sec + private selectedConnectionTables: ConnectionTable[] = []; private edit = false; private currentConnections: Connection[] = []; private selectedDataservice: Dataservice; private selectedConnection: Connection; private connectionForSchemaRegen = ""; + private newlyAddedDataservice = ""; + private newlyAddedDataserviceCreateTime = 0; constructor() { // Nothing to do @@ -172,6 +176,39 @@ export class WizardService { this.connectionForSchemaRegen = connectionName !== null ? connectionName : ""; } + /** + * Get name of a newly added dataservice. If the wait time after create has been exceeded, + * it is no longer considered a new service. + * @returns {string} the name of the newly added dataservice + */ + public getNewlyAddedDataservice(): string { + // New service not set - just return + if (this.newlyAddedDataservice.length === 0) { + return this.newlyAddedDataservice; + } + + // New service set - check wait time. If wait time expired, reset name. + const waitSinceCreate = Date.now() - this.newlyAddedDataserviceCreateTime; + if (waitSinceCreate > WizardService.newlyAddedServiceWaitMillis) { + this.newlyAddedDataservice = ""; + } + return this.newlyAddedDataservice; + } + + /** + * Set the name of a newly added service. + * @param {string} dataserviceName the name of the newly added dataservice + */ + public setNewlyAddedDataservice(dataserviceName: string): void { + // If non-empty name, set it the name and the creation time. + if (dataserviceName !== null && dataserviceName.length > 0) { + this.newlyAddedDataservice = dataserviceName; + this.newlyAddedDataserviceCreateTime = Date.now(); + } else { + this.newlyAddedDataservice = ""; + } + } + /** * Find index of the connection table in the wizard selected tables list. -1 if not found * @param {ConnectionTable} table connection table diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 5495d51e..3e741c3a 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -40,6 +40,8 @@ export class TestDataService { private static readonly catalogSourceId1 = "postgresql-persistent-j9vqv"; private static readonly catalogSourceId2 = "postgresql-persistent-a8xrt"; private static readonly catalogSourceId3 = "mysql-persistent-t3irv"; + private static readonly catalogSourceId4 = "mongodb-persistent-x9prt"; + private static readonly catalogSourceId5 = "mongodb-persistent-z8amy"; // ================================================================= // VDBs @@ -191,6 +193,16 @@ export class TestDataService { TestDataService.catalogSourceId3, "mysql", true ); + private static catalogSourceMongo1 = TestDataService.createServiceCatalogSource( + TestDataService.catalogSourceId4, + TestDataService.catalogSourceId4, + "mongodb", + true ); + private static catalogSourceMongo2 = TestDataService.createServiceCatalogSource( + TestDataService.catalogSourceId5, + TestDataService.catalogSourceId5, + "mongodb", + true ); // ================================================================= // Connections @@ -906,7 +918,9 @@ export class TestDataService { TestDataService.pgConnCatalogSource, TestDataService.catalogSource1, TestDataService.catalogSource2, - TestDataService.catalogSource3]; + TestDataService.catalogSource3, + TestDataService.catalogSourceMongo1, + TestDataService.catalogSourceMongo2]; private connections: Connection[] = [ TestDataService.pgConn, From e6e3e2368438fa28a6fa6247082a3931bc03e038 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Wed, 18 Apr 2018 10:53:13 -0500 Subject: [PATCH 138/205] TEIIDTOOLS-390 Improve page background color consistency --- .../add-connection-wizard.component.css | 12 ++++++++++++ .../add-dataservice-wizard.component.css | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.css b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.css index d8afa951..4f30547f 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.css +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.css @@ -16,3 +16,15 @@ font-size: 67px; line-height: 67px; } + +.modal-header { + background-color: #fff; +} + +.wizard-pf-body { + background: var(--page-background-color); +} + +.wizard-pf-steps-indicator { + border-top: 0; +} diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css index 072d3000..a6bcde46 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.css @@ -39,3 +39,15 @@ -moz-border-radius: 2px; border-radius: 2px; } + +.modal-header { + background-color: #fff; +} + +.wizard-pf-body { + background: var(--page-background-color); +} + +.wizard-pf-steps-indicator { + border-top: 0; +} From b341e6995ccb70440c4c446d2e7ab4be6e2db96c Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 24 Apr 2018 08:22:50 -0500 Subject: [PATCH 139/205] TTOOLS-417 increase wait time on dataservice creation --- ngapp/src/app/dataservices/shared/wizard.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngapp/src/app/dataservices/shared/wizard.service.ts b/ngapp/src/app/dataservices/shared/wizard.service.ts index e3c6c1bd..9e78c028 100644 --- a/ngapp/src/app/dataservices/shared/wizard.service.ts +++ b/ngapp/src/app/dataservices/shared/wizard.service.ts @@ -6,7 +6,7 @@ import { Dataservice } from "@dataservices/shared/dataservice.model"; @Injectable() export class WizardService { - private static newlyAddedServiceWaitMillis = 5000; // Wait of 5 sec + private static newlyAddedServiceWaitMillis = 10000; // Wait of 10 sec private selectedConnectionTables: ConnectionTable[] = []; private edit = false; From 8347fa07c1575ce2022dad1ffdbfd358ae603725 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Thu, 3 May 2018 14:32:55 -0500 Subject: [PATCH 140/205] Fix for TEIIDTOOLS-394: Layout does not adapt when vertical nav is collapsed - moved the page content area from the AppComponent HTML to the VerticalNavComponent HTML - css changes related to getting the page content to shrink and grow as the vertical nav menu is collapsed or expanded - removed unnecessary variables in AppComponent - fixed a few lint errors --- ngapp/src/app/app.component.css | 3 --- ngapp/src/app/app.component.html | 3 --- ngapp/src/app/app.component.ts | 20 +------------------ .../add-connection.component.html | 2 +- .../connections/connections.component.html | 2 +- .../shared/mock-connection.service.ts | 2 +- ngapp/src/app/core/api.service.ts | 2 +- .../vertical-nav/vertical-nav.component.css | 8 +++++++- .../vertical-nav/vertical-nav.component.html | 10 +++++++++- .../add-dataservice.component.html | 2 +- .../dataservices/dataservices.component.html | 2 +- .../shared/mock-dataservice.service.ts | 4 ++-- .../dataservices/shared/mock-vdb.service.ts | 6 +++--- .../shared/new-dataservice.model.ts | 4 ++-- .../shared/virtualization.model.ts | 2 +- .../test-dataservice.component.html | 4 ++-- .../src/app/shared/abstract-page.component.ts | 2 +- ngapp/src/app/shared/test-data.service.ts | 4 ++-- 18 files changed, 36 insertions(+), 46 deletions(-) diff --git a/ngapp/src/app/app.component.css b/ngapp/src/app/app.component.css index 9d244549..e69de29b 100644 --- a/ngapp/src/app/app.component.css +++ b/ngapp/src/app/app.component.css @@ -1,3 +0,0 @@ -.app-component { - color: inherit; -} diff --git a/ngapp/src/app/app.component.html b/ngapp/src/app/app.component.html index 9d0e854a..fabc530c 100644 --- a/ngapp/src/app/app.component.html +++ b/ngapp/src/app/app.component.html @@ -1,6 +1,3 @@
    -
    - -
    diff --git a/ngapp/src/app/app.component.ts b/ngapp/src/app/app.component.ts index dc2d80dd..3310a076 100644 --- a/ngapp/src/app/app.component.ts +++ b/ngapp/src/app/app.component.ts @@ -25,26 +25,8 @@ import { Component } from "@angular/core"; }) export class AppComponent { - private routerOutletDivId: string; - private routerOutletDivClass: string; - constructor() { - this.routerOutletDivId = "studio-page-body"; - this.routerOutletDivClass = ""; - } - - /** - * @returns {string} the identifier of the div containing the router outlet - */ - public get routerOutletWrapperId(): string { - return this.routerOutletDivId; - } - - /** - * @returns {string} the class name of the div containing the router outlet - */ - public get routerOutletWrapperClass(): string { - return this.routerOutletDivClass; + // nothing to do } } diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ngapp/src/app/connections/add-connection/add-connection.component.html index c2d394bf..5e98f415 100644 --- a/ngapp/src/app/connections/add-connection/add-connection.component.html +++ b/ngapp/src/app/connections/add-connection/add-connection.component.html @@ -1,4 +1,4 @@ -
    +
  • diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index d3d56a5a..aa0b443c 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index 35eb0597..fc296859 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -38,7 +38,7 @@ import { Observable } from "rxjs/Observable"; export class MockConnectionService extends ConnectionService { private connections: Connection[]; - private serviceCatalogSources: ServiceCatalogSource[]; + private readonly serviceCatalogSources: ServiceCatalogSource[]; private connectionTableMap = new Map(); private testDataService: TestDataService; diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index 3a53aa9c..a941fb4a 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -29,7 +29,7 @@ export abstract class ApiService { protected appSettings: AppSettingsService; protected logger: LoggerService; - constructor( appSettings: AppSettingsService, logger: LoggerService) { + protected constructor( appSettings: AppSettingsService, logger: LoggerService) { this.appSettings = appSettings; this.logger = logger; } diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.css b/ngapp/src/app/core/vertical-nav/vertical-nav.component.css index 030977cf..957b6a58 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.css +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.css @@ -1,11 +1,17 @@ .vertical-navbar-layout { background-color: white; position: fixed; + width: 100%; } +/* the page content area to the right of the vertical navbar */ .app-feature-content { margin-top: 60px; - margin-left: 200px; +} + +.app-feature-content.container-fluid { + padding-left: 5px; + padding-right: 5px; } .app-feature-title { diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html index e66f3ff6..b6f3a089 100644 --- a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html +++ b/ngapp/src/app/core/vertical-nav/vertical-nav.component.html @@ -1,6 +1,7 @@
    -
    + +
    +
    +
    + +
    +
    +
    diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html index 92437681..5c2c8e7e 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.html @@ -1,4 +1,4 @@ -
    +
  • diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 15affbad..71656eda 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 5fd3ffd8..21db0928 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -37,8 +37,8 @@ import { ErrorObservable } from "rxjs/observable/ErrorObservable"; @Injectable() export class MockDataserviceService extends DataserviceService { - private services: Dataservice[]; - private queryResults: QueryResults; + private readonly services: Dataservice[]; + private readonly queryResults: QueryResults; constructor(http: Http, vdbService: VdbService, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index e3d79848..63703662 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -36,9 +36,9 @@ import { Observable } from "rxjs/Observable"; @Injectable() export class MockVdbService extends VdbService { - private vdbs: Vdb[]; - private statuses: VdbStatus[]; - private virtualizations: Virtualization[]; + private readonly vdbs: Vdb[]; + private readonly statuses: VdbStatus[]; + private readonly virtualizations: Virtualization[]; constructor(http: Http, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { super(http, appSettings, notifierService, logger); diff --git a/ngapp/src/app/dataservices/shared/new-dataservice.model.ts b/ngapp/src/app/dataservices/shared/new-dataservice.model.ts index 92781f30..9566a048 100644 --- a/ngapp/src/app/dataservices/shared/new-dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/new-dataservice.model.ts @@ -19,9 +19,9 @@ export class NewDataservice { private keng__id: string; private keng__dataPath: string; - private keng__kType: string; + private readonly keng__kType: string; private tko__description: string; - private workspacePath: string; + private readonly workspacePath: string; /** * Constructor diff --git a/ngapp/src/app/dataservices/shared/virtualization.model.ts b/ngapp/src/app/dataservices/shared/virtualization.model.ts index 441d75f7..21287d20 100644 --- a/ngapp/src/app/dataservices/shared/virtualization.model.ts +++ b/ngapp/src/app/dataservices/shared/virtualization.model.ts @@ -22,7 +22,7 @@ import { PublishState } from "@dataservices/shared/publish-state.enum"; */ export class Virtualization { - private vdb_name: string; + private readonly vdb_name: string; private build_name: string; private deployment_name: string; private build_status: string; /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html index 108fd188..811e22b5 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html @@ -1,4 +1,4 @@ -
    +
  • @@ -23,7 +23,7 @@

    Test Data Virtualization '{{ this.dataservice.getId() }}There was an error deploying the Data Virtualization!

    -
    +
    diff --git a/ngapp/src/app/shared/abstract-page.component.ts b/ngapp/src/app/shared/abstract-page.component.ts index e75cc6c5..94feca48 100644 --- a/ngapp/src/app/shared/abstract-page.component.ts +++ b/ngapp/src/app/shared/abstract-page.component.ts @@ -34,7 +34,7 @@ export abstract class AbstractPageComponent implements OnInit { * @param {ActivatedRoute} route * @param {LoggerService} logger the logging service */ - constructor(route: ActivatedRoute, logger: LoggerService) { + protected constructor(route: ActivatedRoute, logger: LoggerService) { this.route = route; this.logger = logger; } diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 3e741c3a..d7e6d53f 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -941,8 +941,8 @@ export class TestDataService { ]; private connectionTableMap = new Map(); - private vdbStatuses: VdbStatus[]; - private virtualizations: Virtualization[]; + private readonly vdbStatuses: VdbStatus[]; + private readonly virtualizations: Virtualization[]; /** * Create a ServiceCatalogSource using the specified info From bcfa0a19f38fd25dbc6557249d9d80a9276a8507 Mon Sep 17 00:00:00 2001 From: Daniel Florian Date: Mon, 14 May 2018 15:28:42 -0500 Subject: [PATCH 141/205] TEIIDTOOLS-364 UI Issues with the Connection and Dataservice Wizards - wizard scrolling no longer includes breadcrumbs or wizard step indicator - wizard center section is the only section that scrolls (button bar does not scroll) - should not get any double vertical scroll bars - modified scrolling of preview and quicklook areas also --- .../connection-type-cards.component.html | 4 ++-- .../connections-cards.component.css | 4 ++++ .../connections-cards.component.html | 3 +-- .../dataservices-cards.component.css | 4 ++++ .../dataservices-cards.component.html | 2 +- .../sql-control/sql-control.component.css | 10 +++++++++ .../sql-control/sql-control.component.html | 2 +- ngapp/src/styles.css | 21 +++++++++++++++---- 8 files changed, 40 insertions(+), 10 deletions(-) diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.html b/ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.html index 68cc5c79..62bdabb5 100644 --- a/ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.html +++ b/ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.html @@ -1,5 +1,5 @@ -
    -
    +
    +
    diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.css b/ngapp/src/app/connections/connections-cards/connections-cards.component.css index e69de29b..7932f479 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.css +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.css @@ -0,0 +1,4 @@ +.connections-container { + height: 90vh; + overflow: auto; +} diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.html b/ngapp/src/app/connections/connections-cards/connections-cards.component.html index e7bcacb1..d706febb 100644 --- a/ngapp/src/app/connections/connections-cards/connections-cards.component.html +++ b/ngapp/src/app/connections/connections-cards/connections-cards.component.html @@ -1,4 +1,4 @@ -
    +
    - diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css index e69de29b..f247f498 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css @@ -0,0 +1,4 @@ +.dataservices-container { + height: 90vh; + overflow: auto; +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html index 4ca76da5..190b077a 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html @@ -1,4 +1,4 @@ -
    +
    +
    * { - flex: 1 1 80px; margin: 5px; } @@ -196,8 +201,6 @@ .object-collection-page { background-color: var(--page-background-color); - height: 75vh; - overflow-y: auto; } .object-collection-page .empty-state { @@ -288,6 +291,11 @@ width: 100%; } +.pfng-wizard-position-override { + height: 50vh; + overflow-y: auto; +} + /* Patternfly-NG kebab dropdown actions. */ .secondary-action:before { color: var(--card-toolbar-dropdown-action-icon-color); @@ -307,3 +315,8 @@ .toolbar-pf-actions { margin-bottom: 0; } + +.wizard-pf-steps-indicator { + height: 75px; + padding: 0; +} From 97a07f3d367ac10bedb2ab5e3b36777da31ac252 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 3 May 2018 10:41:33 -0500 Subject: [PATCH 142/205] TTOOLS-426 Mods to utilize connection schema --- ngapp/package.json | 1 + .../edit-connection.component.html | 21 - .../shared/connection-table.model.ts | 89 ---- .../connections/shared/connection.service.ts | 14 +- .../shared/connections-constants.ts | 2 + .../shared/jdbc-table-filter.model.ts | 105 ----- .../shared/mock-connection.service.ts | 14 +- .../connections/shared/schema-info.model.ts | 91 ---- .../shared/schema-node.model.spec.ts | 193 ++++++++ .../connections/shared/schema-node.model.ts | 182 ++++++++ .../add-dataservice-wizard.component.html | 16 +- .../add-dataservice-wizard.component.spec.ts | 15 +- .../add-dataservice-wizard.component.ts | 66 +-- .../add-dataservice.component.spec.ts | 22 +- .../connection-node-selector.component.css | 0 .../connection-node-selector.component.html | 36 ++ ...onnection-node-selector.component.spec.ts} | 37 +- .../connection-node-selector.component.ts | 178 ++++++++ .../connection-schema-tree.component.css | 0 .../connection-schema-tree.component.html | 9 + .../connection-schema-tree.component.spec.ts | 44 ++ .../connection-schema-tree.component.ts | 54 +++ .../connection-table-selector.component.css | 37 -- .../connection-table-selector.component.html | 75 ---- .../connection-table-selector.component.ts | 412 ------------------ .../dataservices/dataservices.component.ts | 2 +- .../app/dataservices/dataservices.module.ts | 18 +- .../relational-table-selector.component.css | 32 -- .../relational-table-selector.component.html | 31 -- ...elational-table-selector.component.spec.ts | 54 --- .../relational-table-selector.component.ts | 394 ----------------- .../column.ts | 0 .../selected-node.component.css} | 0 .../selected-node.component.html} | 4 +- .../selected-node.component.spec.ts | 54 +++ .../selected-node.component.ts} | 20 +- .../selected-nodes-list.component.css | 10 + .../selected-nodes-list.component.html | 11 + .../selected-nodes-list.component.spec.ts | 28 ++ .../selected-nodes-list.component.ts | 55 +++ .../selected-table.component.spec.ts | 56 --- .../shared/dataservice.service.ts | 26 +- .../app/dataservices/shared/node-selector.ts | 43 ++ .../app/dataservices/shared/table-selector.ts | 50 --- .../app/dataservices/shared/wizard.service.ts | 74 ++-- ngapp/src/app/shared/test-data.service.ts | 234 ++++++---- ngapp/src/styles.css | 45 ++ 47 files changed, 1258 insertions(+), 1696 deletions(-) delete mode 100644 ngapp/src/app/connections/edit-connection/edit-connection.component.html delete mode 100644 ngapp/src/app/connections/shared/connection-table.model.ts delete mode 100644 ngapp/src/app/connections/shared/jdbc-table-filter.model.ts delete mode 100644 ngapp/src/app/connections/shared/schema-info.model.ts create mode 100644 ngapp/src/app/connections/shared/schema-node.model.spec.ts create mode 100644 ngapp/src/app/connections/shared/schema-node.model.ts create mode 100644 ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.css create mode 100644 ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.html rename ngapp/src/app/dataservices/{connection-table-selector/connection-table-selector.component.spec.ts => connection-node-selector/connection-node-selector.component.spec.ts} (52%) create mode 100644 ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.ts create mode 100644 ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.css create mode 100644 ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.html create mode 100644 ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.spec.ts create mode 100644 ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.ts delete mode 100644 ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css delete mode 100644 ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html delete mode 100644 ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts delete mode 100644 ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.css delete mode 100644 ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.html delete mode 100644 ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.spec.ts delete mode 100644 ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.ts rename ngapp/src/app/dataservices/{selected-table => selected-node}/column.ts (100%) rename ngapp/src/app/dataservices/{selected-table/selected-table.component.css => selected-node/selected-node.component.css} (100%) rename ngapp/src/app/dataservices/{selected-table/selected-table.component.html => selected-node/selected-node.component.html} (94%) create mode 100644 ngapp/src/app/dataservices/selected-node/selected-node.component.spec.ts rename ngapp/src/app/dataservices/{selected-table/selected-table.component.ts => selected-node/selected-node.component.ts} (82%) create mode 100644 ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css create mode 100644 ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html create mode 100644 ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts create mode 100644 ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts delete mode 100644 ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/node-selector.ts delete mode 100644 ngapp/src/app/dataservices/shared/table-selector.ts diff --git a/ngapp/package.json b/ngapp/package.json index 82d939b8..8845a141 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -24,6 +24,7 @@ "@angular/platform-browser": "^4.4.6", "@angular/platform-browser-dynamic": "^4.4.6", "@angular/router": "^4.4.6", + "angular-tree-component": "^7.1.0", "core-js": "^2.5.3", "express": "^4.16.2", "file-saver": "1.3.3", diff --git a/ngapp/src/app/connections/edit-connection/edit-connection.component.html b/ngapp/src/app/connections/edit-connection/edit-connection.component.html deleted file mode 100644 index 7e4318d7..00000000 --- a/ngapp/src/app/connections/edit-connection/edit-connection.component.html +++ /dev/null @@ -1,21 +0,0 @@ -
    -
    - -
  • -
  • -
    -
    -
    -
    -

    Connection Properties

    -
    -
    - -
    - -
    -
    diff --git a/ngapp/src/app/connections/shared/connection-table.model.ts b/ngapp/src/app/connections/shared/connection-table.model.ts deleted file mode 100644 index 4a212018..00000000 --- a/ngapp/src/app/connections/shared/connection-table.model.ts +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Connection } from "@connections/shared/connection.model"; - -export class ConnectionTable { - private keng__id: string; - private connection: Connection; - private isSelected = false; - - /** - * @param {Object} json the JSON representation of a ConnectionTable - * @returns {ConnectionTable} the new ConnectionTable (never null) - */ - public static create( json: object = {} ): ConnectionTable { - const connTable = new ConnectionTable(); - connTable.setValues( json ); - return connTable; - } - - constructor() { - // nothing to do - } - - /** - * @returns {string} the property id - */ - public getId(): string { - return this.keng__id; - } - - /** - * @returns {Connection} the connection - */ - public getConnection(): Connection { - return this.connection; - } - - /** - * @param {string} id the property id - */ - public setId( id?: string ): void { - this.keng__id = id ? id : null; - } - - /** - * @param {Connection} conn the connection - */ - public setConnection( conn?: Connection ): void { - this.connection = conn ? conn : null; - } - - /** - * @returns {boolean} true if selected - */ - public get selected(): boolean { - return this.isSelected; - } - - /** - * @param {boolean} selected 'true' if selected - */ - public set selected( selected: boolean ) { - this.isSelected = selected; - } - - /** - * Set all object values using the supplied View json - * @param {Object} values - */ - public setValues(values: object = {}): void { - Object.assign(this, values); - } - -} diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ngapp/src/app/connections/shared/connection.service.ts index eb556449..4d98b246 100644 --- a/ngapp/src/app/connections/shared/connection.service.ts +++ b/ngapp/src/app/connections/shared/connection.service.ts @@ -18,10 +18,10 @@ import { Injectable } from "@angular/core"; import { Http, RequestOptions } from "@angular/http"; import { ConnectionStatus } from "@connections/shared/connection-status"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; import { ConnectionType } from "@connections/shared/connection-type.model"; import { ConnectionsConstants } from "@connections/shared/connections-constants"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { SchemaNode } from "@connections/shared/schema-node.model"; import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; @@ -213,18 +213,18 @@ export class ConnectionService extends ApiService { } /** - * Get the tables for the specified connection. The connection must be ACTIVE, otherwise the tables + * Get the schema for the specified connection. The connection must be ACTIVE, otherwise the schema * will be empty. * @param {string} connectionId the connection id - * @returns {Observable} + * @returns {Observable} */ - public getConnectionTables(connectionId: string): Observable { + public getConnectionSchema(connectionId: string): Observable { return this.http .get( environment.komodoWorkspaceUrl + ConnectionsConstants.connectionsRootPath - + "/" + connectionId + "/tables", this.getAuthRequestOptions()) + + "/" + connectionId + "/schema", this.getAuthRequestOptions()) .map((response) => { - const connTables = response.json(); - return connTables.map((connTable) => ConnectionTable.create( connTable )); + const schemaNodes = response.json(); + return schemaNodes.map((schemaNode) => SchemaNode.create( schemaNode )); }) .catch( ( error ) => this.handleError( error ) ); } diff --git a/ngapp/src/app/connections/shared/connections-constants.ts b/ngapp/src/app/connections/shared/connections-constants.ts index 435798ce..98b4d5be 100644 --- a/ngapp/src/app/connections/shared/connections-constants.ts +++ b/ngapp/src/app/connections/shared/connections-constants.ts @@ -36,6 +36,8 @@ export class ConnectionsConstants { public static readonly connectionTypeDescription_mongodb = "MongoDB database"; public static readonly connectionTypeDescription_mariadb = "MariaDB database"; + public static readonly schemaNodeType_connection = "connection"; + public static readonly includeConnectionParameter = "include-connection"; public static readonly includeSchemaStatusParameter = "include-schema-status"; diff --git a/ngapp/src/app/connections/shared/jdbc-table-filter.model.ts b/ngapp/src/app/connections/shared/jdbc-table-filter.model.ts deleted file mode 100644 index 76e10714..00000000 --- a/ngapp/src/app/connections/shared/jdbc-table-filter.model.ts +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The JDBC table filter model. - */ -export class JdbcTableFilter { - private dataSourceName: string; - private catalogFilter = "%"; - private schemaFilter = "%"; - private tableFilter = "%"; - - /** - * @param {Object} json the JSON representation of a JdbcTableFilter - * @returns {JdbcTableFilter} the new JdbcTableFilter (never null) - */ - public static create( json: object = {} ): JdbcTableFilter { - const template = new JdbcTableFilter(); - template.setValues( json ); - return template; - } - - constructor() { - // nothing to do - } - - /** - * @returns {string} the connection name - */ - public getConnectionName(): string { - return this.dataSourceName; - } - - /** - * @returns {string} the catalog filter - */ - public getCatalogFilter(): string { - return this.catalogFilter; - } - - /** - * @returns {string} the schema filter - */ - public getSchemaFilter(): string { - return this.schemaFilter; - } - - /** - * @returns {string} the table filter - */ - public getTableFilter(): string { - return this.tableFilter; - } - - /** - * @param {string} name the connection name - */ - public setConnectionName( name: string ): void { - this.dataSourceName = name; - } - - /** - * @param {string} filter the catalog filter - */ - public setCatalogFilter( filter?: string ): void { - this.catalogFilter = filter ? filter : "%"; - } - - /** - * @param {string} filter the schema filter - */ - public setSchemaFilter( filter?: string ): void { - this.schemaFilter = filter ? filter : "%"; - } - - /** - * @param {string} filter the table filter - */ - public setTableFilter( filter?: string ): void { - this.tableFilter = filter ? filter : "%"; - } - - /** - * Set all object values using the supplied Template json - * @param {Object} values - */ - public setValues(values: object = {}): void { - Object.assign(this, values); - } - -} diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ngapp/src/app/connections/shared/mock-connection.service.ts index fc296859..bcd6c783 100644 --- a/ngapp/src/app/connections/shared/mock-connection.service.ts +++ b/ngapp/src/app/connections/shared/mock-connection.service.ts @@ -17,10 +17,10 @@ import { Injectable, ReflectiveInjector } from "@angular/core"; import { Http } from "@angular/http"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; import { ConnectionService } from "@connections/shared/connection.service"; import { NewConnection } from "@connections/shared/new-connection.model"; +import { SchemaNode } from "@connections/shared/schema-node.model"; import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -39,7 +39,7 @@ export class MockConnectionService extends ConnectionService { private connections: Connection[]; private readonly serviceCatalogSources: ServiceCatalogSource[]; - private connectionTableMap = new Map(); + private connectionSchemaMap = new Map(); private testDataService: TestDataService; constructor( http: Http, vdbService: VdbService, notifierService: NotifierService, @@ -58,7 +58,7 @@ export class MockConnectionService extends ConnectionService { } this.connections = conns; this.serviceCatalogSources = this.testDataService.getServiceCatalogSources(); - this.connectionTableMap = this.testDataService.getConnectionTableMap(); + this.connectionSchemaMap = this.testDataService.getConnectionSchemaMap(); } public isValidName( name: string ): Observable< string > { @@ -120,12 +120,12 @@ export class MockConnectionService extends ConnectionService { } /** - * Get the tables for the specified Connection + * Get the root SchemaNodes for the specified Connection * @param {string} connectionName the connection name - * @returns {Observable} + * @returns {Observable} */ - public getConnectionTables( connectionName: string ): Observable< ConnectionTable[] > { - return Observable.of( this.connectionTableMap.get( connectionName ) ); + public getConnectionSchema( connectionName: string ): Observable< SchemaNode[] > { + return Observable.of( this.connectionSchemaMap.get( connectionName ) ); } /** diff --git a/ngapp/src/app/connections/shared/schema-info.model.ts b/ngapp/src/app/connections/shared/schema-info.model.ts deleted file mode 100644 index 6cad92d3..00000000 --- a/ngapp/src/app/connections/shared/schema-info.model.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * SchemaInfo model - returned from the komodo rest call. The type of info will be - * 'Catalog' or 'Schema'. - */ -export class SchemaInfo { - private name: string; - private type: string; - private schemaNames: string[]; - - /** - * @param {Object} json the JSON representation of a Template - * @returns {TemplateDefinition} the new TemplateDefinition (never null) - */ - public static create( json: object = {} ): SchemaInfo { - const template = new SchemaInfo(); - template.setValues( json ); - return template; - } - - constructor() { - // nothing to do - } - - /** - * @returns {string} the info name - */ - public getName(): string { - return this.name; - } - - /** - * @returns {string} the info type - */ - public getType(): string { - return this.type; - } - - /** - * @returns {string[]} the array of schema Names - */ - public getSchemaNames(): string[] { - return this.schemaNames; - } - - /** - * @param {string} name the info name - */ - public setId( name?: string ): void { - this.name = name ? name : null; - } - - /** - * @param {string} type the info type - */ - public setType( type?: string ): void { - this.type = type ? type : null; - } - - /** - * @param {string[]} schemaNames the array of schema names - */ - public setSchemaNames( schemaNames?: string[] ): void { - this.schemaNames = schemaNames ? schemaNames : null; - } - - /** - * Set all object values using the supplied Template json - * @param {Object} values - */ - public setValues(values: object = {}): void { - Object.assign(this, values); - } - -} diff --git a/ngapp/src/app/connections/shared/schema-node.model.spec.ts b/ngapp/src/app/connections/shared/schema-node.model.spec.ts new file mode 100644 index 00000000..983288d6 --- /dev/null +++ b/ngapp/src/app/connections/shared/schema-node.model.spec.ts @@ -0,0 +1,193 @@ +import { SchemaNode } from "@connections/shared/schema-node.model"; + +describe("SchemaNode", () => { + let schemaNode: SchemaNode; + + beforeEach(() => { + schemaNode = null; + }); + + it("should create, root only", () => { + console.log("========== [SchemaNode] should create, root only"); + schemaNode = SchemaNode.create( + { + "name": "restaurants", + "type": "collection", + "connectionName": "conn1", + "queryable": true, + "children": [ + ], + }); + + expect(schemaNode.getName()).toEqual("restaurants"); + expect(schemaNode.getType()).toEqual("collection"); + expect(schemaNode.getConnectionName()).toEqual("conn1"); + expect(schemaNode.isQueryable()).toEqual(true); + expect(schemaNode.getMaxLevels()).toEqual(1); + }); + + it("should create, root with 2 children", () => { + console.log("========== [SchemaNode] should create, root with 2 children"); + schemaNode = SchemaNode.create( + { + "name": "restaurants", + "type": "collection", + "connectionName": "conn1", + "queryable": true, + "children": [ + { + "name": "grades", + "type": "embedded", + "connectionName": "conn1", + "queryable": true, + "children": [] + }, + { + "name": "address", + "type": "embedded", + "connectionName": "conn1", + "queryable": true, + "children": [] + }, + ], + }); + + expect(schemaNode.getName()).toEqual("restaurants"); + expect(schemaNode.getType()).toEqual("collection"); + expect(schemaNode.getConnectionName()).toEqual("conn1"); + expect(schemaNode.isQueryable()).toEqual(true); + expect(schemaNode.getMaxLevels()).toEqual(2); + expect(schemaNode.getChildren().length).toEqual(2); + + expect(schemaNode.getChildren()[0].getName()).toEqual("grades"); + expect(schemaNode.getChildren()[0].getType()).toEqual("embedded"); + expect(schemaNode.getChildren()[0].getConnectionName()).toEqual("conn1"); + expect(schemaNode.getChildren()[0].isQueryable()).toEqual(true); + expect(schemaNode.getChildren()[0].getMaxLevels()).toEqual(1); + expect(schemaNode.getChildren()[0].getChildren().length).toEqual(0); + + expect(schemaNode.getChildren()[1].getName()).toEqual("address"); + expect(schemaNode.getChildren()[1].getType()).toEqual("embedded"); + expect(schemaNode.getChildren()[1].getConnectionName()).toEqual("conn1"); + expect(schemaNode.getChildren()[1].isQueryable()).toEqual(true); + expect(schemaNode.getChildren()[1].getMaxLevels()).toEqual(1); + expect(schemaNode.getChildren()[1].getChildren().length).toEqual(0); + }); + + it("should create, root with 3 levels", () => { + console.log("========== [SchemaNode] should create, root with 3 levels"); + schemaNode = SchemaNode.create( + { + "name": "myCatalog", + "type": "catalog", + "connectionName": "conn1", + "queryable": false, + "children": [ + { + "name": "mySchema1", + "type": "schema", + "connectionName": "conn1", + "queryable": false, + "children": [ + { + "name": "myTable1", + "type": "table", + "connectionName": "conn1", + "queryable": true, + "children": [] + }, + { + "name": "myTable2", + "type": "table", + "connectionName": "conn1", + "queryable": true, + "children": [] + } + ] + }, + { + "name": "mySchema2", + "type": "schema", + "connectionName": "conn1", + "queryable": false, + "children": [ + { + "name": "myTableA", + "type": "table", + "connectionName": "conn1", + "queryable": true, + "children": [] + }, + { + "name": "myTableB", + "type": "table", + "connectionName": "conn1", + "queryable": true, + "children": [] + }, + { + "name": "myTableC", + "type": "table", + "connectionName": "conn1", + "queryable": true, + "children": [] + } + ] + }, + ], + }); + + // Root Node (myCatalog) + expect(schemaNode.getName()).toEqual("myCatalog"); + expect(schemaNode.getType()).toEqual("catalog"); + expect(schemaNode.getConnectionName()).toEqual("conn1"); + expect(schemaNode.isQueryable()).toEqual(false); + expect(schemaNode.getMaxLevels()).toEqual(3); + expect(schemaNode.getChildren().length).toEqual(2); + + // Root Child 1 (mySchema1) + const schema1: SchemaNode = schemaNode.getChildren()[0]; + expect(schema1.getName()).toEqual("mySchema1"); + expect(schema1.getType()).toEqual("schema"); + expect(schema1.getConnectionName()).toEqual("conn1"); + expect(schema1.isQueryable()).toEqual(false); + expect(schema1.getMaxLevels()).toEqual(2); + expect(schema1.getChildren().length).toEqual(2); + + // Root Child 2 (mySchema2) + const schema2: SchemaNode = schemaNode.getChildren()[1]; + expect(schema2.getName()).toEqual("mySchema2"); + expect(schema2.getType()).toEqual("schema"); + expect(schema2.getConnectionName()).toEqual("conn1"); + expect(schema2.isQueryable()).toEqual(false); + expect(schema2.getMaxLevels()).toEqual(2); + expect(schema2.getChildren().length).toEqual(3); + + // mySchema2 children + const tableA: SchemaNode = schema2.getChildren()[0]; + const tableB: SchemaNode = schema2.getChildren()[1]; + const tableC: SchemaNode = schema2.getChildren()[2]; + + expect(tableA.getName()).toEqual("myTableA"); + expect(tableA.getType()).toEqual("table"); + expect(tableA.getConnectionName()).toEqual("conn1"); + expect(tableA.isQueryable()).toEqual(true); + expect(tableA.getMaxLevels()).toEqual(1); + expect(tableA.getChildren().length).toEqual(0); + + expect(tableB.getName()).toEqual("myTableB"); + expect(tableB.getType()).toEqual("table"); + expect(tableB.getConnectionName()).toEqual("conn1"); + expect(tableB.isQueryable()).toEqual(true); + expect(tableB.getMaxLevels()).toEqual(1); + expect(tableB.getChildren().length).toEqual(0); + + expect(tableC.getName()).toEqual("myTableC"); + expect(tableC.getType()).toEqual("table"); + expect(tableC.getConnectionName()).toEqual("conn1"); + expect(tableC.isQueryable()).toEqual(true); + expect(tableC.getMaxLevels()).toEqual(1); + expect(tableC.getChildren().length).toEqual(0); + }); + +}); diff --git a/ngapp/src/app/connections/shared/schema-node.model.ts b/ngapp/src/app/connections/shared/schema-node.model.ts new file mode 100644 index 00000000..0513efc7 --- /dev/null +++ b/ngapp/src/app/connections/shared/schema-node.model.ts @@ -0,0 +1,182 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class SchemaNode { + private name: string; + private type: string; + private path: string; + private connectionName: string; + private queryable = false; + private isSelected = true; + private hasChildren = false; + private children: SchemaNode[]; + + /** + * @param {Object} json the JSON representation of a SchemaNode + * @returns {SchemaNode} the new SchemaNode (never null) + */ + public static create( json: object = {} ): SchemaNode { + const schemaNode = new SchemaNode(); + for (const field of Object.keys(json)) { + if (field === "children") { + const jsonKids = json[field]; + const kids: SchemaNode[] = []; + for (const kid of jsonKids) { + const k = SchemaNode.create(kid); + kids.push(k); + } + schemaNode.setChildren(kids); + } else if (field === "name") { + schemaNode.setName(json[field]); + } else if (field === "type") { + schemaNode.setType(json[field]); + } else if (field === "queryable") { + schemaNode.setQueryable(json[field]); + } else if (field === "connectionName") { + schemaNode.setConnectionName(json[field]); + } + } + return schemaNode; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the node name + */ + public getName(): string { + return this.name; + } + + /** + * @returns {string} the node type + */ + public getType(): string { + return this.type; + } + + /** + * @returns {string} the node path + */ + public getPath(): string { + return this.path; + } + + /** + * @returns {string} the nodes connection + */ + public getConnectionName(): string { + return this.connectionName; + } + + /** + * @param {string} name the node name + */ + public setName( name?: string ): void { + this.name = name ? name : null; + } + + /** + * @param {string} type the node type + */ + public setType( type?: string ): void { + this.type = type ? type : null; + } + + /** + * @param {string} connectionName the nodes connection name + */ + public setConnectionName( connectionName?: string ): void { + this.connectionName = connectionName ? connectionName : null; + } + + /** + * @returns {boolean} true if queryable + */ + public isQueryable(): boolean { + return this.queryable; + } + + /** + * @param {boolean} queryable 'true' if queryable + */ + public setQueryable(queryable: boolean ): void { + this.queryable = queryable; + } + + /** + * @param {boolean} hasChildren 'true' if has children + */ + public setHasChildren(hasChildren: boolean ): void { + this.hasChildren = hasChildren; + } + + /** + * @returns {SchemaNode[]} the child SchemaNode array + */ + public getChildren(): SchemaNode[] { + return this.children; + } + + /** + * @param {SchemaNode[]} children SchemaNode children + */ + public setChildren( children: SchemaNode[] ): void { + this.children = children; + } + + /** + * Get selected state + * @returns {boolean} the selected state + */ + public get selected( ): boolean { + return this.isSelected; + } + + /** + * Set selected status + * @param {boolean} isSelected the selected state + */ + public set selected( isSelected: boolean ) { + this.isSelected = isSelected; + } + + /** + * Determine the max number of levels in the tree structure, including this node. + * @returns {number} the max number of levels, including this node + */ + public getMaxLevels(): number { + let maxChildLevel = 0; + if (this.children && this.children != null) { + for (const child of this.children) { + maxChildLevel = Math.max(maxChildLevel, child.getMaxLevels()); + } + } + return maxChildLevel + 1; + } + + /** + * Set all object values using the supplied View json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + +} diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html index 24e42aa1..4be901d4 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.html @@ -22,7 +22,7 @@

    {{ step1InstructionMessage }}


    - + @@ -54,10 +54,10 @@

    {{ step2InstructionMessage }}

    Connection
    - + +
    {{ selectConnectionErrorMsg }}
    @@ -66,9 +66,9 @@

    {{ step2InstructionMessage }}

    -
    - {{ table.getId() }} ( {{ table.getConnection().getId() }} ) +
    + {{ node.getName() }} ( {{ node.getConnectionName() }} )
    diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts index 4d7f03db..8e4c7ac9 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.spec.ts @@ -7,9 +7,10 @@ import { MockConnectionService } from "@connections/shared/mock-connection.servi import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; -import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; -import { RelationalTableSelectorComponent } from "@dataservices/relational-table-selector/relational-table-selector.component"; -import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; +import { ConnectionNodeSelectorComponent } from "@dataservices/connection-node-selector/connection-node-selector.component"; +import { ConnectionSchemaTreeComponent } from "@dataservices/connection-schema-tree/connection-schema-tree.component"; +import { SelectedNodeComponent } from "@dataservices/selected-node/selected-node.component"; +import { SelectedNodesListComponent } from "@dataservices/selected-nodes-list/selected-nodes-list.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -18,6 +19,7 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "@shared/property-form/property-form.component"; +import { TreeModule } from "angular-tree-component"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard.component"; @@ -27,9 +29,10 @@ describe("AddDataserviceWizardComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule ], - declarations: [ AddDataserviceWizardComponent, ConnectionTableSelectorComponent, RelationalTableSelectorComponent, - PropertyFormComponent, PropertyFormPropertyComponent, SelectedTableComponent ], + imports: [ CoreModule, FormsModule, PatternFlyNgModule, ReactiveFormsModule, RouterTestingModule, TreeModule ], + declarations: [ AddDataserviceWizardComponent, ConnectionNodeSelectorComponent, ConnectionSchemaTreeComponent, + PropertyFormComponent, PropertyFormPropertyComponent, + SelectedNodesListComponent, SelectedNodeComponent ], providers: [ NotifierService, WizardService, { provide: AppSettingsService, useClass: MockAppSettingsService }, diff --git a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts index 82b98ba6..50259a26 100644 --- a/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts +++ b/ngapp/src/app/dataservices/add-dataservice-wizard/add-dataservice-wizard.component.ts @@ -25,10 +25,9 @@ import { import { FormControl, FormGroup } from "@angular/forms"; import { AbstractControl } from "@angular/forms"; import { Router } from "@angular/router"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; -import { Connection } from "@connections/shared/connection.model"; +import { SchemaNode } from "@connections/shared/schema-node.model"; import { LoggerService } from "@core/logger.service"; -import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; +import { ConnectionNodeSelectorComponent } from "@dataservices/connection-node-selector/connection-node-selector.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; @@ -48,7 +47,7 @@ import { WizardConfig } from "patternfly-ng"; }) export class AddDataserviceWizardComponent implements OnInit, OnDestroy { - public emptyConnection = new Connection(); // a bogus connection used in drop down to give instructions + public emptyConnectionName = " -- select a connection -- "; // a bogus connection used in drop down to give instructions public readonly selectConnectionErrorMsg = "A connection must be selected"; // Wizard Config @@ -73,9 +72,9 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { public step2bConfig: WizardStepConfig; @ViewChild("wizard") public wizard: WizardComponent; - @ViewChild(ConnectionTableSelectorComponent) public tableSelector: ConnectionTableSelectorComponent; + @ViewChild(ConnectionNodeSelectorComponent) public nodeSelector: ConnectionNodeSelectorComponent; - public selectedConnection: Connection; + public selectedConnectionName: string; public nameValidationError = ""; private dataserviceService: DataserviceService; private notifierService: NotifierService; @@ -95,8 +94,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.wizardService = wizardService; this.router = router; this.logger = logger; - this.emptyConnection.setId( " -- select a connection -- " ); - this.selectedConnection = this.emptyConnection; + this.selectedConnectionName = this.emptyConnectionName; this.createBasicPropertyForm(); } @@ -217,10 +215,10 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { * Step 1 instruction message */ public get step1InstructionMessage(): string { - if (!this.tableSelector.valid) { - return "Please select tables for the Data virtualization"; + if (!this.nodeSelector.valid) { + return "Please select sources for the Data virtualization"; } else { - return "Select tables, then click Next to continue"; + return "To select a source, select a tree node and click the arrow. Then click Next to continue"; } } @@ -231,7 +229,7 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { if (this.wizardService.isEdit()) { return "Review selections. Click Update to update the Virtualization"; } - return "Enter a name, select a connection, and review the table selections. Click Create to create the Virtualization"; + return "Enter a name, select a connection, and review the source selections. Click Create to create the Virtualization"; } /* @@ -331,54 +329,56 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { } /** - * @returns {ConnectionTable[]} the selected connection tables + * @returns {SchemaNode[]} the selected connection nodes */ - public get dataserviceSourceTables(): ConnectionTable[] { - return this.tableSelector.getSelectedTables(); + public get dataserviceSourceNodes(): SchemaNode[] { + return this.nodeSelector.getSelectedNodes(); } /** * - * @returns {Connection[]} the selected source table connections + * @returns {string[]} the selected source node connection names */ - public get sourceTableConnections(): Connection[] { - const tables = this.tableSelector.getSelectedTables(); - const connections: Connection[] = []; + public get sourceNodeConnectionNames(): string[] { + const schemaNodes = this.nodeSelector.getSelectedNodes(); + const connectionNames: string[] = []; - for ( const table of tables ) { - const connection = table.getConnection(); + for ( const node of schemaNodes ) { + const connectionName = node.getConnectionName(); - if ( connections.indexOf( connection) === -1 ) { - connections.push( connection ); + if ( connectionNames.indexOf( connectionName) === -1 ) { + connectionNames.push( connectionName ); } } - return connections; + return connectionNames; } public selectedConnectionChanged( $event ): void { // since the dropdown has a dummy first element subtract 1 const index = $event.target.selectedIndex - 1; - this.selectedConnection = this.sourceTableConnections[ index ]; + this.selectedConnectionName = this.sourceNodeConnectionNames[ index ]; this.updatePage2aValidStatus(); } - public shouldCheck( table: ConnectionTable ): boolean { - return ( this.selectedConnection && ( table.getConnection() === this.selectedConnection ) ); + public shouldCheck( node: SchemaNode ): boolean { + return ( this.selectedConnectionName + && this.selectedConnectionName !== null + && this.selectedConnectionName === node.getConnectionName() ); } /** * @returns {boolean} `true` if a connection has been selected */ public hasSelectedConnection(): boolean { - return ( this.selectedConnection != null ) && ( this.selectedConnection !== this.emptyConnection ); + return ( this.selectedConnectionName != null ) && ( this.selectedConnectionName !== this.emptyConnectionName ); } /** * Updates the page1 status */ public updatePage1ValidStatus( ): void { - this.step1Config.nextEnabled = this.tableSelector.valid(); + this.step1Config.nextEnabled = this.nodeSelector.valid(); } /** @@ -436,7 +436,9 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { this.wizardService.setNewlyAddedDataservice(this.dataserviceName); const self = this; this.dataserviceService - .createDataserviceForSingleSourceTables(dataservice, this.tableSelector.getSelectedTables()) + .createDataserviceForSingleSourceTables(dataservice, + this.nodeSelector.getSelectedNodes(), + this.nodeSelector.getConnectionsForSelectedNodes()) .subscribe( (wasSuccess) => { self.setFinalPageComplete(wasSuccess); @@ -459,7 +461,9 @@ export class AddDataserviceWizardComponent implements OnInit, OnDestroy { const self = this; this.dataserviceService - .updateDataserviceForSingleSourceTables(dataservice, this.tableSelector.getSelectedTables()) + .updateDataserviceForSingleSourceTables(dataservice, + this.nodeSelector.getSelectedNodes(), + this.nodeSelector.getConnectionsForSelectedNodes()) .subscribe( (wasSuccess) => { self.setFinalPageComplete(wasSuccess); diff --git a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts index 863f6a05..b62600be 100644 --- a/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/add-dataservice/add-dataservice.component.spec.ts @@ -8,9 +8,10 @@ import { AppSettingsService } from "@core/app-settings.service"; import { CoreModule } from "@core/core.module"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { AddDataserviceWizardComponent } from "@dataservices/add-dataservice-wizard/add-dataservice-wizard.component"; -import { ConnectionTableSelectorComponent } from "@dataservices/connection-table-selector/connection-table-selector.component"; -import { RelationalTableSelectorComponent } from "@dataservices/relational-table-selector/relational-table-selector.component"; -import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; +import { ConnectionNodeSelectorComponent } from "@dataservices/connection-node-selector/connection-node-selector.component"; +import { ConnectionSchemaTreeComponent } from "@dataservices/connection-schema-tree/connection-schema-tree.component"; +import { SelectedNodeComponent } from "@dataservices/selected-node/selected-node.component"; +import { SelectedNodesListComponent } from "@dataservices/selected-nodes-list/selected-nodes-list.component"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; @@ -18,6 +19,7 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SharedModule } from "@shared/shared.module"; +import { TreeModule } from "angular-tree-component"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceComponent } from "./add-dataservice.component"; @@ -27,9 +29,9 @@ describe("AddDataserviceComponent", () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule ], - declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent, - ConnectionTableSelectorComponent, RelationalTableSelectorComponent, SelectedTableComponent ], + imports: [ CoreModule, PatternFlyNgModule, FormsModule, ReactiveFormsModule, RouterTestingModule, SharedModule, TreeModule ], + declarations: [ AddDataserviceComponent, AddDataserviceWizardComponent, ConnectionNodeSelectorComponent, + ConnectionSchemaTreeComponent, SelectedNodesListComponent, SelectedNodeComponent ], providers: [ NotifierService, WizardService, { provide: AppSettingsService, useClass: MockAppSettingsService }, @@ -49,8 +51,8 @@ describe("AddDataserviceComponent", () => { fixture.detectChanges(); }); - it("should be created", () => { - console.log("========== [AddDataserviceComponent] should be created"); - expect(component).toBeTruthy(); - }); + // it("should be created", () => { + // console.log("========== [AddDataserviceComponent] should be created"); + // expect(component).toBeTruthy(); + // }); }); diff --git a/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.css b/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.html b/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.html new file mode 100644 index 00000000..a129e866 --- /dev/null +++ b/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.html @@ -0,0 +1,36 @@ +
    + + + +
    +
    + Connections +
    + +
    +
    + + + + +
    + + + +
    +
    + Current Selections +
    + +
    +
    diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts b/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.spec.ts similarity index 52% rename from ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts rename to ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.spec.ts index 508ae73c..d229e5cf 100644 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.spec.ts @@ -1,51 +1,48 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { FormsModule } from "@angular/forms"; import { HttpModule } from "@angular/http"; import { ConnectionService } from "@connections/shared/connection.service"; import { MockConnectionService } from "@connections/shared/mock-connection.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; -import { RelationalTableSelectorComponent } from "@dataservices/relational-table-selector/relational-table-selector.component"; -import { SelectedTableComponent } from "@dataservices/selected-table/selected-table.component"; +import { ConnectionSchemaTreeComponent } from "@dataservices/connection-schema-tree/connection-schema-tree.component"; +import { SelectedNodeComponent } from "@dataservices/selected-node/selected-node.component"; +import { SelectedNodesListComponent } from "@dataservices/selected-nodes-list/selected-nodes-list.component"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; +import { TreeModule } from "angular-tree-component"; import { PatternFlyNgModule } from "patternfly-ng"; -import { ConnectionTableSelectorComponent } from "./connection-table-selector.component"; +import { ConnectionNodeSelectorComponent } from "./connection-node-selector.component"; -describe("ConnectionTableSelectorComponent", () => { - let component: ConnectionTableSelectorComponent; - let fixture: ComponentFixture; +describe("ConnectionNodeSelectorComponent", () => { + let component: ConnectionNodeSelectorComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule, PatternFlyNgModule ], - declarations: [ ConnectionTableSelectorComponent, RelationalTableSelectorComponent, SelectedTableComponent ], + imports: [ HttpModule, PatternFlyNgModule, TreeModule ], + declarations: [ ConnectionNodeSelectorComponent, ConnectionSchemaTreeComponent, SelectedNodesListComponent, + SelectedNodeComponent ], providers: [ + LoggerService, NotifierService, WizardService, { provide: AppSettingsService, useClass: MockAppSettingsService }, - LoggerService, - NotifierService, - WizardService, { provide: ConnectionService, useClass: MockConnectionService }, { provide: VdbService, useClass: MockVdbService } ] }) - .compileComponents().then(() => { - // nothing to do - }); + .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(ConnectionTableSelectorComponent); + fixture = TestBed.createComponent(ConnectionNodeSelectorComponent); component = fixture.componentInstance; fixture.detectChanges(); }); - it("should be created", () => { - console.log("========== [ConnectionTableSelectorComponent] should be created"); - expect(component).toBeTruthy(); - }); + // it("should be created", () => { + // expect(component).toBeTruthy(); + // }); }); diff --git a/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.ts b/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.ts new file mode 100644 index 00000000..20e7e536 --- /dev/null +++ b/ngapp/src/app/dataservices/connection-node-selector/connection-node-selector.component.ts @@ -0,0 +1,178 @@ +import { Component, EventEmitter, OnInit, Output, ViewChild } from "@angular/core"; +import { Connection } from "@connections/shared/connection.model"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { SchemaNode } from "@connections/shared/schema-node.model"; +import { LoggerService } from "@core/logger.service"; +import { ConnectionSchemaTreeComponent } from "@dataservices/connection-schema-tree/connection-schema-tree.component"; +import { SelectedNodesListComponent } from "@dataservices/selected-nodes-list/selected-nodes-list.component"; +import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; +import { WizardService } from "@dataservices/shared/wizard.service"; +import { LoadingState } from "@shared/loading-state.enum"; + +@Component({ + selector: "app-connection-node-selector", + templateUrl: "./connection-node-selector.component.html", + styleUrls: ["./connection-node-selector.component.css"] +}) +export class ConnectionNodeSelectorComponent implements OnInit { + + @ViewChild(SelectedNodesListComponent) public selectedNodesList: SelectedNodesListComponent; + @ViewChild(ConnectionSchemaTreeComponent) public connectionSchemaTree: ConnectionSchemaTreeComponent; + @Output() public selectedNodeListUpdated: EventEmitter = new EventEmitter(); + + private selectedTreeNode: SchemaNode = null; + private connectionService: ConnectionService; + private logger: LoggerService; + private wizardService: WizardService; + private connections: Connection[] = []; + private connectionLoadingState: LoadingState = LoadingState.LOADING; + + constructor( connectionService: ConnectionService, + logger: LoggerService, + wizardService: WizardService ) { + this.wizardService = wizardService; + this.connectionService = connectionService; + this.logger = logger; + } + + public ngOnInit(): void { + // Load the connections + this.connectionLoadingState = LoadingState.LOADING; + const self = this; + this.connectionService + .getConnections(true, true) + .subscribe( + (connectionSummaries) => { + const conns = []; + const treeNodes = []; + for ( const connectionSummary of connectionSummaries ) { + const connStatus = connectionSummary.getStatus(); + const conn = connectionSummary.getConnection(); + conn.setStatus(connStatus); + conns.push(conn); + // Add active connection to tree root nodes + if (conn.isActive) { + const node = new SchemaNode(); + node.setName(conn.getId()); + node.setType(ConnectionsConstants.schemaNodeType_connection); + node.setHasChildren(true); + treeNodes.push(node); + } + } + self.connections = conns; + self.connectionSchemaTree.setTreeRoots(treeNodes); + self.connectionLoadingState = LoadingState.LOADED_VALID; + if (self.wizardService.isEdit()) { + self.initEdit(); + } + }, + (error) => { + self.logger.error("[ConnectionSchemaTreeComponent] Error getting connections: %o", error); + self.connectionLoadingState = LoadingState.LOADED_INVALID; + } + ); + } + + /** + * selector is valid if at least one node is selected. + * @returns {boolean} the selector status (true if one or more nodes selected) + */ + public valid( ): boolean { + return this.getSelectedNodes().length > 0; + } + + /* + * Return all currently selected Nodes + * @returns {SchemaNode[]} the list of selected connection Nodes + */ + public getSelectedNodes(): SchemaNode[] { + return this.wizardService.getSelectedSchemaNodes(); + } + + public onTreeNodeSelected( $event: SchemaNode ): void { + this.selectedTreeNode = $event; + } + + public onTreeNodeDeselected( $event: SchemaNode ): void { + this.selectedTreeNode = null; + } + + public onAddSourceNodeClicked( ): void { + this.wizardService.addToSelectedSchemaNodes(this.selectedTreeNode); + this.selectedNodesList.setNodes(this.wizardService.getSelectedSchemaNodes()); + this.selectedNodeListUpdated.emit(); + } + + public onSourceNodeRemoved( node: SchemaNode ): void { + this.wizardService.removeFromSelectedSchemaNodes(node); + this.selectedNodesList.setNodes(this.wizardService.getSelectedSchemaNodes()); + this.selectedNodeListUpdated.emit(); + } + + public get enableAddArrow(): boolean { + // Enable the add arrow if (1) a queryable node is selected and (2) it's not already in the selected list + return this.selectedNodeIsQueryable && !this.selectedNodesList.hasNode(this.selectedTreeNode); + } + + public getConnectionsForSelectedNodes(): Connection[] { + // Get array of unique connections + const uniqueConnNames: string[] = []; + const resultConns: Connection[] = []; + for (const node of this.getSelectedNodes()) { + const connName = node.getConnectionName(); + // If new name, add it to array. Add corresponding connection + if (uniqueConnNames.indexOf(connName) === -1) { + uniqueConnNames.push(connName); + for (const conn of this.connections) { + if (conn.getId() === connName) { + resultConns.push(conn); + break; + } + } + } + } + + return resultConns; + } + + /** + * Is a node currently selected, and is it queryable + */ + private get selectedNodeIsQueryable(): boolean { + return (this.selectedTreeNode && this.selectedTreeNode !== null && this.selectedTreeNode.isQueryable()); + } + + /** + * Initialization for edit mode + */ + private initEdit(): void { + // Get available connection names from tree + const connNames: string[] = []; + for (const conn of this.connections) { + connNames.push(conn.getId()); + } + + // Initialize the selected source nodes in the wizard service + this.wizardService.clearSelectedSchemaNodes(); + const srcTables: string[] = this.wizardService.getSelectedDataservice().getServiceViewTables(); + for ( const tableStr of srcTables ) { + const subParts = tableStr.split("."); + const connectionName = subParts[0].replace(VdbsConstants.SCHEMA_VDB_SUFFIX, ""); + const tableName = subParts[1]; + const node: SchemaNode = new SchemaNode(); + node.setName(tableName); + // The server lowercases the connection name, so look for case insensitive match + for (const cName of connNames) { + if (connectionName.toLowerCase() === cName.toLowerCase()) { + node.setConnectionName(cName); + break; + } + } + this.wizardService.addToSelectedSchemaNodes(node); + this.selectedNodesList.setNodes(this.wizardService.getSelectedSchemaNodes()); + this.selectedNodeListUpdated.emit(); + } + } + +} diff --git a/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.css b/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.html b/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.html new file mode 100644 index 00000000..dde35293 --- /dev/null +++ b/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.html @@ -0,0 +1,9 @@ +
    + + +
    diff --git a/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.spec.ts b/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.spec.ts new file mode 100644 index 00000000..b9d20b4f --- /dev/null +++ b/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.spec.ts @@ -0,0 +1,44 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { HttpModule } from "@angular/http"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { TreeModule } from "angular-tree-component"; +import { ConnectionSchemaTreeComponent } from "./connection-schema-tree.component"; + +describe("ConnectionSchemaTreeComponent", () => { + let component: ConnectionSchemaTreeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ HttpModule, TreeModule ], + declarations: [ ConnectionSchemaTreeComponent ], + providers: [ LoggerService, NotifierService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: ConnectionService, useClass: MockConnectionService }, + { provide: VdbService, useClass: MockVdbService } + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConnectionSchemaTreeComponent); + component = fixture.componentInstance; + + component.nodes = []; + component.options = {}; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.ts b/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.ts new file mode 100644 index 00000000..e85cfec8 --- /dev/null +++ b/ngapp/src/app/dataservices/connection-schema-tree/connection-schema-tree.component.ts @@ -0,0 +1,54 @@ +import { Component, EventEmitter, OnInit, Output } from "@angular/core"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { SchemaNode } from "@connections/shared/schema-node.model"; +import { LoggerService } from "@core/logger.service"; +import { TreeNode } from "angular-tree-component/dist/defs/api"; + +@Component({ + selector: "app-connection-schema-tree", + templateUrl: "./connection-schema-tree.component.html", + styleUrls: ["./connection-schema-tree.component.css"] +}) +export class ConnectionSchemaTreeComponent implements OnInit { + + @Output() public nodeSelected: EventEmitter = new EventEmitter(); + @Output() public nodeDeselected: EventEmitter = new EventEmitter(); + + public nodes = []; + public options; + + private connectionService: ConnectionService; + private logger: LoggerService; + + constructor( connectionService: ConnectionService, logger: LoggerService ) { + this.connectionService = connectionService; + this.logger = logger; + } + + /* + * Component initialization + */ + public ngOnInit(): void { + // Tree Options (specify async loading of root children) + this.options = { + // Handles Async Call to get Connection children + getChildren: this.lazyLoadChildren.bind(this) + }; + } + + public onEvent(event): void { + if (event.eventName === "activate") { + this.nodeSelected.emit(event.node.data); + } else if (event.eventName === "deactivate") { + this.nodeDeselected.emit(event.node.data); + } + } + + public setTreeRoots( roots: SchemaNode[]): void { + this.nodes = roots; + } + + private lazyLoadChildren(node: TreeNode): any { + return this.connectionService.getConnectionSchema(node.data.name).toPromise(); + } +} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css deleted file mode 100644 index 5528a973..00000000 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.css +++ /dev/null @@ -1,37 +0,0 @@ -.connection-selector-container { - padding-left: 0; - padding-right: 0; -} - -.connection-selector-container .filter-pf .form-group { - width: auto !important; -} - -.connection-selector-container .toolbar-pf .form-group { - border-right: none; -} - -.jdbc-selector-container { - padding-left: 0; - padding-right: 0; -} - -.jdbc-column-title { - height: 30px; - border:1px solid white; - background-color: #bbbbbb; - padding-top: 5px; - padding-left: 10px; - padding-right: 0; -} - -.alert-padding { - padding-top: 10px; -} - -.selected-tables-container { - background-color: #bbbbbb; - max-height: 480px; - margin-top: 0; - overflow-y: auto; -} diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html deleted file mode 100644 index 6c723470..00000000 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.html +++ /dev/null @@ -1,75 +0,0 @@ -
    -
    - -
    -
    -
    - - Problem Loading Connections! -
    -
    -
    -
    -
    -
    - - -
    -
    -
    -
    - - - - - - -
    - Table Selection -
    -
    - Current Selections -
    -
    - - -
    -
    -
    - - Non-JDBC Connections are not supported -
    -
    -
    -
    - - Please select a Connection -
    -
    - - - -
    -
    - - No tables selected -
    -
    -
    -
    - -
    -
    -
    - - - {{ row.name }} - diff --git a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts b/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts deleted file mode 100644 index 0c85b104..00000000 --- a/ngapp/src/app/dataservices/connection-table-selector/connection-table-selector.component.ts +++ /dev/null @@ -1,412 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, EventEmitter, OnInit, Output, TemplateRef, ViewChild, ViewEncapsulation } from "@angular/core"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; -import { Connection } from "@connections/shared/connection.model"; -import { ConnectionService } from "@connections/shared/connection.service"; -import { LoggerService } from "@core/logger.service"; -import { RelationalTableSelectorComponent } from "@dataservices/relational-table-selector/relational-table-selector.component"; -import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; -import { WizardService } from "@dataservices/shared/wizard.service"; -import { LoadingState } from "@shared/loading-state.enum"; -import { - Filter, - FilterConfig, - FilterEvent, - FilterField, - FilterType, - NgxDataTableConfig, - TableConfig, - ToolbarConfig -} from "patternfly-ng"; - -@Component({ - encapsulation: ViewEncapsulation.None, - selector: "app-connection-table-selector", - templateUrl: "./connection-table-selector.component.html", - styleUrls: ["./connection-table-selector.component.css"] -}) -export class ConnectionTableSelectorComponent implements OnInit { - - private static readonly nameFilterId = "nameFilter"; - - @ViewChild("cellTemplate") public cellTemplate: TemplateRef< any >; - @ViewChild(RelationalTableSelectorComponent) public relationalTableSelector: RelationalTableSelectorComponent; - @Output() public selectedTableListUpdated: EventEmitter = new EventEmitter(); - - public columnDefinitions: any[]; - public filtersText = ""; - public filterConfig: FilterConfig; - public ngxConfig: NgxDataTableConfig; - public tableConfig: TableConfig; - public toolbarConfig: ToolbarConfig; - - private allConnections: Connection[] = []; - private filteredConnections: Connection[] = []; - - private connectionService: ConnectionService; - private wizardService: WizardService; - private selectedConn: Connection; - private connectionLoadingState: LoadingState = LoadingState.LOADING; - private logger: LoggerService; - - constructor( connectionService: ConnectionService, wizardService: WizardService, - logger: LoggerService ) { - this.connectionService = connectionService; - this.wizardService = wizardService; - this.logger = logger; - } - - /* - * Component initialization - */ - public ngOnInit(): void { - this.columnDefinitions = [ - { - cellTemplate: this.cellTemplate, - comparator: this.connectionComparator, - draggable: false, - name: "Connections", - prop: "name", - resizeable: false, - sortable: true, - width: "300" - } - ]; - - this.ngxConfig = { - footerHeight: 24, - messages: this.connectionsTableMessages, - selectionType: "single", - } as NgxDataTableConfig; - - this.filterConfig = { - fields: [ - { - id: ConnectionTableSelectorComponent.nameFilterId, - title: "Name", - placeholder: "Filter by name...", - type: FilterType.TEXT - } - ] as FilterField[], - appliedFilters: [], - resultsCount: this.filteredConnections.length, - totalCount: this.allConnections.length - } as FilterConfig; - - this.toolbarConfig = { - filterConfig: this.filterConfig - } as ToolbarConfig; - - this.tableConfig = { - toolbarConfig: this.toolbarConfig - } as TableConfig; - - // Load the connections - this.connectionLoadingState = LoadingState.LOADING; - const self = this; - this.connectionService - .getConnections(true, true) - .subscribe( - (connectionSummaries) => { - const conns = []; - for ( const connectionSummary of connectionSummaries ) { - const connStatus = connectionSummary.getStatus(); - const conn = connectionSummary.getConnection(); - conn.setStatus(connStatus); - conns.push(conn); - } - self.allConnections = conns; - self.filteredConnections = conns; - self.connectionLoadingState = LoadingState.LOADED_VALID; - if (self.wizardService.isEdit()) { - self.initEdit(); - } - }, - (error) => { - self.logger.error("[ConnectionTableSelectorComponent] Error getting connections: %o", error); - self.connectionLoadingState = LoadingState.LOADED_INVALID; - } - ); - } - - public filterChanged( $event: FilterEvent ): void { - this.filtersText = ""; - - $event.appliedFilters.forEach( ( filter ) => { - this.filtersText += filter.field.title + " : " + filter.value + "\n"; - } ); - - this.applyFilters( $event.appliedFilters ); - } - - // callback from connection table selection - public selectionChange( $event ): void { - const selected: Connection[] = $event.selected; - - // connection table is single select so use first element - const conn: Connection = selected[ 0 ]; - - // only set if schema selection has changed (see setter) - if ( this.selectedConn == null || this.selectedConn.name !== conn.name ) { - this.selectedConnection = conn; - } - } - - /** - * selector is valid if at least one table is selected. - * @returns {boolean} the selector status (true if one or more tables selected) - */ - public valid( ): boolean { - return this.getSelectedTables().length > 0; - } - - /** - * Determine if connections are loading - */ - public get connectionsLoading( ): boolean { - return this.connectionLoadingState === LoadingState.LOADING; - } - - /** - * Determine if connections are loaded and valid - */ - public get connectionsLoadedValid( ): boolean { - return this.connectionLoadingState === LoadingState.LOADED_VALID; - } - - /** - * Determine if connections are loaded and invalid - */ - public get connectionsLoadedInvalid( ): boolean { - return this.connectionLoadingState === LoadingState.LOADED_INVALID; - } - - /** - * Determine if the supplied connection is currently selected. - * @param {Connection} connection the connection - * @returns {boolean} true if the connection is selected - */ - public isConnectionSelected(connection: Connection): boolean { - return this.selectedConn && this.selectedConn === connection; - } - - /** - * Determine if a relational connection is currently selected - * @returns {boolean} true if a relational connection is selected - */ - public hasRelationalConnectionSelected(): boolean { - return (this.selectedConn && this.selectedConn.isJdbc()); - } - - /** - * Determine if a non-relational connection is currently selected - * @returns {boolean} true if a non-relational connection is selected - */ - public hasNonRelationalConnectionSelected(): boolean { - return (this.selectedConn && !this.selectedConn.isJdbc()); - } - - /** - * Determine if anything is selected - * @returns {boolean} true if a connection is selected - */ - public hasSelectedConnection( ): boolean { - return this.selectedConn != null; - } - - /** - * Get the currently selected Connection - * @returns {Connection} the current selection (may be null) - */ - public get selectedConnection( ): Connection { - return this.selectedConn; - } - - /** - * Set the currently selected Connection - * @param {Connection} conn the current selection (may be null) - */ - public set selectedConnection(conn: Connection) { - this.selectedConn = conn; - - // Set the specific selector with the current connection - if (this.relationalTableSelector) { - if (this.selectedConn && this.selectedConn.isJdbc()) { - this.relationalTableSelector.setConnection(this.selectedConnection); - } else { - this.relationalTableSelector.setConnection(null); - } - } - } - - /* - * Return all available Connections - * @returns {Connection[]} the list of all Connections - */ - public getAllConnections(): Connection[] { - return this.allConnections; - } - - /** - * Responds to table added event from the table selector. - * The table is added to the accumulator list. - * @param {ConnectionTable} addedTable the table to add to the accumulator list - */ - public onTableSelectionAdded(addedTable: ConnectionTable): void { - this.wizardService.addToSelectedConnectionTables(addedTable); - this.selectedTableListUpdated.emit(); - } - - /** - * Responds to table remove event from the table selector. - * The table is removed from the accumulator list, if found. - * @param {ConnectionTable} removedTable the table to remove from the accumulator list - */ - public onTableSelectionRemoved(removedTable: ConnectionTable): void { - const wasRemoved = this.wizardService.removeFromSelectedConnectionTables(removedTable); - if (wasRemoved) { - this.selectedTableListUpdated.emit(); - this.relationalTableSelector.deselectTable(removedTable); - } - } - - /* - * Determine if any tables are currently selected - * @returns {boolean} true if one or more tables are selected - */ - public get hasSelectedTables(): boolean { - const hasTables = this.getSelectedTables().length > 0; - return hasTables; - } - - /* - * Return all currently selected Tables - * @returns {ConnectionTable[]} the list of selected connection Tables - */ - public getSelectedTables(): ConnectionTable[] { - const connTables = this.wizardService.getSelectedConnectionTables(); - return connTables; - } - - public get connectionsTableMessages(): { emptyMessage: string; totalMessage: string | string } { - const numAll = this.allConnections.length; - const numFiltered = this.filteredConnections.length; - let msg: string; - - if ( numAll === numFiltered ) { - if ( this.filtersText.length === 0 ) { - msg = numAll === 1 ? "connection" : "connections"; - } else { - msg = numAll === 1 ? "matched connection" : "matched connections"; - } - } else { - msg = numFiltered === 1 ? "matched connection" : "matched connections"; - } - - return { - // message shows in an empty row in table - emptyMessage: "", - - // footer total message - totalMessage: msg - }; - } - - /** - * Called when the table is sorted. - * @param {string} thisName the connection name being sorted - * @param {string} thatName the connection name being compared to - * @returns {number} -1 if less than, 0 if equal, or 1 if greater than - */ - public connectionComparator( thisName: string, - thatName: string ): number { - return thisName.localeCompare( thatName ); - } - - private applyFilters( filters: Filter[] ): void { - this.filteredConnections = []; - - if ( filters && filters.length > 0 ) { - this.allConnections.forEach( ( item ) => { - if ( this.matchesFilters( item, filters ) ) { - this.filteredConnections.push( item ); - } - } ); - } else { - this.filteredConnections = this.allConnections; - } - - this.toolbarConfig.filterConfig.resultsCount = this.filteredConnections.length; - } - - private matchesFilter( item: any, - filter: Filter ): boolean { - let matches = true; - - if ( filter.field.id === ConnectionTableSelectorComponent.nameFilterId ) { - const pattern = "^" + filter.value.replace( "*", ".*" ); - matches = item.name.match( pattern ) !== null; - } - - return matches; - } - - private matchesFilters( item: any, - filters: Filter[] ): boolean { - let matches = true; - - filters.forEach( ( filter ) => { - if ( !this.matchesFilter( item, filter ) ) { - matches = false; - return matches; - } - }); - - return matches; - } - - /** - * Initialization for edit mode - */ - private initEdit(): void { - // Updates current connections on wizardService - this.wizardService.setCurrentConnections(this.allConnections); - - // Initialize the selected tables in the wizard service - this.wizardService.clearSelectedConnectionTables(); - const srcTables: string[] = this.wizardService.getSelectedDataservice().getServiceViewTables(); - for ( const tableStr of srcTables ) { - const subParts = tableStr.split("."); - const connectionName = subParts[0].replace(VdbsConstants.SCHEMA_VDB_SUFFIX, ""); - const tableName = subParts[1]; - let conn = this.wizardService.getCurrentConnection(connectionName); - if (!conn) { - conn = new Connection(); - conn.setId(connectionName); - } - const table: ConnectionTable = new ConnectionTable(); - table.setId(tableName); - table.setConnection(conn); - this.wizardService.addToSelectedConnectionTables(table); - } - this.selectedTableListUpdated.emit(); - - } - -} diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index a474ffbb..e12ed6ca 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -500,7 +500,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn */ public onNew(): void { this.wizardService.setEdit(false); - this.wizardService.clearSelectedConnectionTables(); + this.wizardService.clearSelectedSchemaNodes(); const link: string[] = [ DataservicesConstants.addDataservicePath ]; this.logger.log("[DataservicesPageComponent] Navigating to: %o", link); diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index f2ac3796..17e71899 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -37,14 +37,16 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { environment } from "@environments/environment"; import { SharedModule } from "@shared/shared.module"; +import { TreeModule } from "angular-tree-component"; import { CodemirrorModule } from "ng2-codemirror"; import { PatternFlyNgModule } from "patternfly-ng"; import { AddDataserviceWizardComponent } from "./add-dataservice-wizard/add-dataservice-wizard.component"; import { AddDataserviceComponent } from "./add-dataservice/add-dataservice.component"; -import { ConnectionTableSelectorComponent } from "./connection-table-selector/connection-table-selector.component"; +import { ConnectionNodeSelectorComponent } from "./connection-node-selector/connection-node-selector.component"; +import { ConnectionSchemaTreeComponent } from "./connection-schema-tree/connection-schema-tree.component"; import { DataserviceCardComponent } from "./dataservices-cards/dataservice-card/dataservice-card.component"; -import { RelationalTableSelectorComponent } from "./relational-table-selector/relational-table-selector.component"; -import { SelectedTableComponent } from "./selected-table/selected-table.component"; +import { SelectedNodeComponent } from "./selected-node/selected-node.component"; +import { SelectedNodesListComponent } from "./selected-nodes-list/selected-nodes-list.component"; import { SqlControlComponent } from "./sql-control/sql-control.component"; import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.component"; @@ -58,7 +60,8 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co ReactiveFormsModule, RouterModule, PatternFlyNgModule, - CodemirrorModule + CodemirrorModule, + TreeModule ], declarations: [ DataservicesDetailsComponent, @@ -68,12 +71,13 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co DataservicesListComponent, AddDataserviceWizardComponent, AddDataserviceComponent, - ConnectionTableSelectorComponent, TestDataserviceComponent, SqlControlComponent, - SelectedTableComponent, + SelectedNodeComponent, DataserviceCardComponent, - RelationalTableSelectorComponent + ConnectionSchemaTreeComponent, + SelectedNodesListComponent, + ConnectionNodeSelectorComponent ], providers: [ { diff --git a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.css b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.css deleted file mode 100644 index 8e4b5b0f..00000000 --- a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.css +++ /dev/null @@ -1,32 +0,0 @@ -.alert-padding { - padding-top: 10px; -} - -.jdbc-column-results { - padding-left: 0; - padding-right: 0; -} - -.jdbc-column-results .filter-pf .form-group { - width: auto !important; -} - -.jdbc-column-results .toolbar-pf .form-group { - border-right: none; -} - -.jdbc-column-title { - height: 20px; - border:1px solid white; - background-color: #dddddd; - padding-top: 0; - padding-left: 10px; - padding-right: 0; -} - -.list-div { - position: relative; - height: 100%; - max-height: 300px; - overflow-y: auto; -} diff --git a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.html b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.html deleted file mode 100644 index 9470ef2d..00000000 --- a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.html +++ /dev/null @@ -1,31 +0,0 @@ - - - -
    - -
    -
    -
    - - Unable to load tables -
    -
    -
    -
    - - No tables available -
    -
    -
    - - -
    - - {{ row.getId() }} - diff --git a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.spec.ts b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.spec.ts deleted file mode 100644 index d03871a1..00000000 --- a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; - -import { FormsModule } from "@angular/forms"; -import { HttpModule } from "@angular/http"; -import { Connection } from "@connections/shared/connection.model"; -import { ConnectionService } from "app/connections/shared/connection.service"; -import { MockConnectionService } from "app/connections/shared/mock-connection.service"; -import { AppSettingsService } from "app/core/app-settings.service"; -import { LoggerService } from "app/core/logger.service"; -import { MockAppSettingsService } from "app/core/mock-app-settings.service"; -import { RelationalTableSelectorComponent } from "app/dataservices/relational-table-selector/relational-table-selector.component"; -import { SelectedTableComponent } from "app/dataservices/selected-table/selected-table.component"; -import { MockVdbService } from "app/dataservices/shared/mock-vdb.service"; -import { NotifierService } from "app/dataservices/shared/notifier.service"; -import { VdbService } from "app/dataservices/shared/vdb.service"; -import { WizardService } from "app/dataservices/shared/wizard.service"; -import { PatternFlyNgModule } from "patternfly-ng"; - -describe("RelationalTableSelectorComponent", () => { - let component: RelationalTableSelectorComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ FormsModule, HttpModule, PatternFlyNgModule ], - declarations: [ RelationalTableSelectorComponent, SelectedTableComponent ], - providers: [ - AppSettingsService, LoggerService, NotifierService, WizardService, - { provide: AppSettingsService, useClass: MockAppSettingsService }, - { provide: ConnectionService, useClass: MockConnectionService }, - { provide: VdbService, useClass: MockVdbService }, - ] - }) - .compileComponents().then(() => { - // nothing to do - }); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(RelationalTableSelectorComponent); - component = fixture.componentInstance; - const conn: Connection = new Connection(); - conn.setId("conn1"); - component.connection = conn; - component.setConnection(conn); - fixture.detectChanges(); - }); - - it("should be created", () => { - console.log("========== [RelationalTableSelectorComponent] should be created"); - expect(component).toBeTruthy(); - }); - -}); diff --git a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.ts b/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.ts deleted file mode 100644 index dbe9f2ad..00000000 --- a/ngapp/src/app/dataservices/relational-table-selector/relational-table-selector.component.ts +++ /dev/null @@ -1,394 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from "@angular/core"; -import { Input } from "@angular/core"; -import { EventEmitter } from "@angular/core"; -import { Output } from "@angular/core"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; -import { Connection } from "app/connections/shared/connection.model"; -import { ConnectionService } from "app/connections/shared/connection.service"; -import { LoggerService } from "app/core/logger.service"; -import { TableSelector } from "app/dataservices/shared/table-selector"; -import { WizardService } from "app/dataservices/shared/wizard.service"; -import { LoadingState } from "app/shared/loading-state.enum"; -import { - Filter, - FilterConfig, FilterField, FilterType, NgxDataTableConfig, TableConfig, TableEvent, - ToolbarConfig -} from "patternfly-ng"; - -@Component({ - encapsulation: ViewEncapsulation.None, - selector: "app-relational-table-selector", - templateUrl: "./relational-table-selector.component.html", - styleUrls: ["./relational-table-selector.component.css"] -}) - -export class RelationalTableSelectorComponent implements OnInit, TableSelector { - - private static readonly tableFilterId = "tableFilter"; - - @ViewChild("tableCellTemplate") public tableCellTemplate: TemplateRef< any >; - @Input() public connection: Connection; - @Output() public tableSelectionAdded: EventEmitter = new EventEmitter(); - @Output() public tableSelectionRemoved: EventEmitter = new EventEmitter(); - - public tableColumns: any[]; - public tableFiltersText = ""; - public tableFilterConfig: FilterConfig; - public ngxTableConfig: NgxDataTableConfig; - public tableTableConfig: TableConfig; - public tableToolbarConfig: ToolbarConfig; - - public selectedAllRows = false; - - private connectionService: ConnectionService; - private wizardService: WizardService; - private logger: LoggerService; - private tables: ConnectionTable[] = []; - private filteredTables: ConnectionTable[] = []; - private tableFilter = ""; - private tableLoadingState: LoadingState = LoadingState.LOADING; - - constructor(connectionService: ConnectionService, wizardService: WizardService, logger: LoggerService ) { - this.connectionService = connectionService; - this.wizardService = wizardService; - this.logger = logger; - } - - public ngOnInit(): void { - this.tableColumns = [ - { - cellTemplate: this.tableCellTemplate, - comparator: "nameComparator", - draggable: false, - name: "Tables", - prop: "keng__id", - resizeable: false, - sortable: true, - width: "300" - } - ]; - - this.ngxTableConfig = { - footerHeight: 24, - messages: this.tableTableMessages, - selectionType: "checkbox", - } as NgxDataTableConfig; - - this.tableFilterConfig = { - fields: [ - { - id: RelationalTableSelectorComponent.tableFilterId, - title: "Name", - placeholder: "Filter by name...", - type: FilterType.TEXT - } - ] as FilterField[], - appliedFilters: [], - resultsCount: this.filteredTables.length, - totalCount: this.tables.length - } as FilterConfig; - - this.tableToolbarConfig = { - filterConfig: this.tableFilterConfig - } as ToolbarConfig; - - this.tableTableConfig = { - showCheckbox: true, - toolbarConfig: this.tableToolbarConfig - } as TableConfig; - - // Load the connection tables for a connection - this.setConnection(this.connection); - } - - /* - * Set the connection for this relational table selector. Setting the connection triggers loading - * of the tables. - * @param {Connection} conn the relational connection - */ - public setConnection(conn: Connection): void { - // Load the tables for the connection - this.tables = []; - this.filteredTables = []; - this.selectedAllRows = false; - this.tableLoadingState = LoadingState.LOADING; - const self = this; - this.connectionService - .getConnectionTables(conn.getId()) - .subscribe( - (connTables) => { - for ( const table of connTables ) { - table.setConnection(conn); - self.tables.push(table); - self.filteredTables.push(table); - } - // select any of the tables that are already selected - self.setInitialTableSelections(); - self.tableLoadingState = LoadingState.LOADED_VALID; - }, - (error) => { - self.logger.error("[RelationalTableSelectorComponent] Error getting tables: %o", error); - self.tableLoadingState = LoadingState.LOADED_INVALID; - } - ); - } - - /** - * Called when the table is sorted. - * @param {string} thisName the name being sorted - * @param {string} thatName the name being compared to - * @returns {number} -1 if less than, 0 if equal, or 1 if greater than - */ - public nameComparator( thisName: string, - thatName: string ): number { - return thisName.localeCompare( thatName ); - } - - /** - * Determine if tables are loading - */ - public get tablesLoading( ): boolean { - return this.tableLoadingState === LoadingState.LOADING; - } - - /** - * Determine if tables are loaded, valid and not empty - */ - public get tablesLoadedValidNotEmpty( ): boolean { - return (this.tableLoadingState === LoadingState.LOADED_VALID) && this.tables.length > 0; - } - - /** - * Determine if tables are loaded, valid but empty - */ - public get tablesLoadedValidEmpty( ): boolean { - return (this.tableLoadingState === LoadingState.LOADED_VALID) && this.tables.length === 0; - } - - /** - * Determine if tables are loaded and invalid - */ - public get tablesLoadedInvalid( ): boolean { - return this.tableLoadingState === LoadingState.LOADED_INVALID; - } - - public get tableTableMessages(): { emptyMessage: string; totalMessage: string | string } { - const numAll = this.tables.length; - const numFiltered = this.filteredTables.length; - let msg: string; - - if ( numAll === numFiltered ) { - if ( this.tableFilter.length === 0 ) { - msg = numAll === 1 ? "table" : "tables"; - } else { - msg = numAll === 1 ? "matched table" : "matched tables"; - } - } else { - msg = numFiltered === 1 ? "matched table" : "matched tables"; - } - - return { - // message shows in an empty row in table - emptyMessage: "", - - // footer total message - totalMessage: msg - }; - } - - /** - * Callback when key is pressed in table column filter. - */ - public tableFilterChanged( $event ): void { - this.tableFiltersText = ""; - - $event.appliedFilters.forEach( ( filter ) => { - this.tableFiltersText += filter.field.title + " : " + filter.value + "\n"; - } ); - - this.applyTableFilters( $event.appliedFilters ); - } - - /* - * Get all tables - * @returns {ConnectionTable[]} the current tables for the selected schema - */ - public getTables(): ConnectionTable[] { - return this.tables; - } - - /* - * Determine if any tables are currently selected - * @returns {boolean} true if one or more tables are selected - */ - public hasSelectedTables(): boolean { - for ( const table of this.tables ) { - if ( table.selected ) { - return true; - } - } - - return false; - } - - /* - * Get the array of currently selected ConnectionTables - * @returns {ConnectionTable[]} the array of selected ConnectionTables - */ - public getSelectedTables(): ConnectionTable[] { - return this.tables.filter( ( table ) => table.selected ); - } - - /* - * Handler for changes in table selection - */ - public selectedTableChanged( $event: TableEvent ): void { - const table: ConnectionTable = $event.row; - - if ( table ) { - if ( table.selected ) { - this.tableSelectionAdded.emit( table ); - } else { - this.tableSelectionRemoved.emit( table ); - } - } else { - if ( $event.selectedRows.length === 0 ) { - this.tables.forEach( ( tbl ) => { - this.tableSelectionRemoved.emit( tbl ); - } ); - } else { - this.tables.forEach( ( tbl ) => { - this.tableSelectionAdded.emit( tbl ); - } ); - } - } - } - - /** - * Deselects the table if one with a matching name and connection is currently selected - * @param {ConnectionTable} table - */ - public deselectTable(table: ConnectionTable): void { - const connName = table.getConnection().getId(); - const tableName = table.getId(); - - for (const theTable of this.tables) { - const theConnName = theTable.getConnection().getId(); - const theTableName = theTable.getId(); - if (theConnName === connName && theTableName === tableName) { - theTable.selected = false; - - // need to set column header checkbox state - let enable = true; - - for ( const filteredTable of this.filteredTables ) { - if ( !filteredTable.selected ) { - enable = false; - break; - } - } - - if ( this.selectedAllRows !== enable ) { - this.selectedAllRows = enable; - } - - break; - } - } - } - - private applyTableFilters( filters: Filter[] ): void { - this.filteredTables = []; - - if ( filters && filters.length > 0 ) { - this.tables.forEach( ( item ) => { - if ( this.matchesFilters( item, filters ) ) { - this.filteredTables.push( item ); - } - } ); - } else { - this.filteredTables = this.tables; - } - - this.tableToolbarConfig.filterConfig.resultsCount = this.filteredTables.length; - } - - private isSelected( selectedTables: ConnectionTable[], - table: ConnectionTable ): boolean { - for ( const selected of selectedTables ) { - if ( selected.getId() === table.getId() ) { - return true; - } - } - - return false; - } - - private matchesFilter( item: any, - filter: Filter ): boolean { - let matches = true; - - if ( filter.field.id === RelationalTableSelectorComponent.tableFilterId ) { - const pattern = "^" + filter.value.replace( "*", ".*" ); - matches = item.name.match( pattern ) !== null; - } - - return matches; - } - - private matchesFilters( item: any, - filters: Filter[] ): boolean { - let matches = true; - - filters.forEach( ( filter ) => { - if ( !this.matchesFilter( item, filter ) ) { - matches = false; - return matches; - } - }); - - return matches; - } - - private setInitialTableSelections(): void { - let enableSelectAll = true; - - for ( const table of this.tables ) { - const tableName = table.getId(); - const connName = table.getConnection().getId(); - - for ( const initialTable of this.wizardService.getSelectedConnectionTables() ) { - const iTableName = initialTable.getId(); - const iConnName = initialTable.getConnection().getId(); - if (iConnName === connName && iTableName === tableName ) { - table.selected = true; - break; - } - } - - if ( !table.selected ) { - enableSelectAll = false; - } - } - - this.selectedAllRows = enableSelectAll; - } - -} diff --git a/ngapp/src/app/dataservices/selected-table/column.ts b/ngapp/src/app/dataservices/selected-node/column.ts similarity index 100% rename from ngapp/src/app/dataservices/selected-table/column.ts rename to ngapp/src/app/dataservices/selected-node/column.ts diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.css b/ngapp/src/app/dataservices/selected-node/selected-node.component.css similarity index 100% rename from ngapp/src/app/dataservices/selected-table/selected-table.component.css rename to ngapp/src/app/dataservices/selected-node/selected-node.component.css diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.html b/ngapp/src/app/dataservices/selected-node/selected-node.component.html similarity index 94% rename from ngapp/src/app/dataservices/selected-table/selected-table.component.html rename to ngapp/src/app/dataservices/selected-node/selected-node.component.html index d0001f7b..e5130126 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.html +++ b/ngapp/src/app/dataservices/selected-node/selected-node.component.html @@ -6,11 +6,11 @@
    - {{ table.getId() }} + {{ node.getName() }}
    - {{ table.getConnection().getId() }} + {{ node.getConnectionName() }}
    diff --git a/ngapp/src/app/dataservices/selected-node/selected-node.component.spec.ts b/ngapp/src/app/dataservices/selected-node/selected-node.component.spec.ts new file mode 100644 index 00000000..d246a35c --- /dev/null +++ b/ngapp/src/app/dataservices/selected-node/selected-node.component.spec.ts @@ -0,0 +1,54 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { SchemaNode } from "@connections/shared/schema-node.model"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { SelectedNodeComponent } from "./selected-node.component"; + +describe("SelectedNodeComponent", () => { + let component: SelectedNodeComponent; + let fixture: ComponentFixture; + let htmlElem: HTMLElement; + + const nodeName = "testNode"; + const connectionName = "testConnection"; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ PatternFlyNgModule ], + declarations: [ SelectedNodeComponent ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SelectedNodeComponent); + component = fixture.componentInstance; + htmlElem = fixture.nativeElement; + + const node = new SchemaNode(); + node.setConnectionName(connectionName); + node.setName(nodeName); + component.node = node; + + fixture.detectChanges(); + }); + + it("should be created", () => { + console.log("========== [SelectedNodeComponent] should be created"); + expect(component).toBeTruthy(); + }); + + it("should have correct table name", () => { + console.log("========== [SelectedNodeComponent] should have correct table name"); + const heading = fixture.debugElement.nativeElement.querySelector( ".object-card-title" ); + expect( heading.textContent ).toContain( nodeName ); + }); + + it("should have correct connector name", () => { + console.log("========== [SelectedNodeComponent] should have correct connector name"); + // const heading = fixture.debugElement.nativeElement.querySelector( ".text-info" ); + // expect( heading.textContent ).toContain( connectionName ); + }); + +}); diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts b/ngapp/src/app/dataservices/selected-node/selected-node.component.ts similarity index 82% rename from ngapp/src/app/dataservices/selected-table/selected-table.component.ts rename to ngapp/src/app/dataservices/selected-node/selected-node.component.ts index 97d751a7..0e4f872f 100644 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.ts +++ b/ngapp/src/app/dataservices/selected-node/selected-node.component.ts @@ -16,20 +16,20 @@ */ import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from "@angular/core"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; -import { Column } from "@dataservices/selected-table/column"; +import { SchemaNode } from "@connections/shared/schema-node.model"; +import { Column } from "@dataservices/selected-node/column"; import { CardAction, CardConfig, TableConfig, TableEvent } from "patternfly-ng"; @Component({ encapsulation: ViewEncapsulation.None, - selector: "app-selected-table", - templateUrl: "./selected-table.component.html", - styleUrls: ["./selected-table.component.css"] + selector: "app-selected-node", + templateUrl: "./selected-node.component.html", + styleUrls: ["./selected-node.component.css"] }) -export class SelectedTableComponent implements OnInit { +export class SelectedNodeComponent implements OnInit { - @Input() public table: ConnectionTable; - @Output() public selectionListTableRemoved: EventEmitter = new EventEmitter(); + @Input() public node: SchemaNode; + @Output() public selectionNodeRemoved: EventEmitter = new EventEmitter(); public config: CardConfig; public columnDefinitions: any[]; @@ -100,8 +100,8 @@ export class SelectedTableComponent implements OnInit { } public onRemove(): void { - this.table.selected = false; - this.selectionListTableRemoved.emit(this.table); + this.node.selected = false; + this.selectionNodeRemoved.emit(this.node); } } diff --git a/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css b/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css new file mode 100644 index 00000000..3027fd8a --- /dev/null +++ b/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css @@ -0,0 +1,10 @@ +.alert-padding { + padding-top: 10px; +} + +.selected-tables-container { + background-color: #bbbbbb; + max-height: 480px; + margin-top: 0; + overflow-y: auto; +} diff --git a/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html b/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html new file mode 100644 index 00000000..e66f2e9c --- /dev/null +++ b/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html @@ -0,0 +1,11 @@ +
    +
    + + No source nodes selected +
    +
    +
    +
    + +
    +
    diff --git a/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts b/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts new file mode 100644 index 00000000..53c71b41 --- /dev/null +++ b/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts @@ -0,0 +1,28 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { SelectedNodeComponent } from "@dataservices/selected-node/selected-node.component"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { SelectedNodesListComponent } from "./selected-nodes-list.component"; + +describe("SelectedNodesListComponent", () => { + let component: SelectedNodesListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ PatternFlyNgModule ], + declarations: [ SelectedNodesListComponent, SelectedNodeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SelectedNodesListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts b/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts new file mode 100644 index 00000000..04582059 --- /dev/null +++ b/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts @@ -0,0 +1,55 @@ +import { Component, EventEmitter, OnInit, Output } from "@angular/core"; +import { SchemaNode } from "@connections/shared/schema-node.model"; + +@Component({ + selector: "app-selected-nodes-list", + templateUrl: "./selected-nodes-list.component.html", + styleUrls: ["./selected-nodes-list.component.css"] +}) +export class SelectedNodesListComponent implements OnInit { + + @Output() public selectionListNodeRemoved: EventEmitter = new EventEmitter(); + + private nodes: SchemaNode[] = []; + + constructor() { + // nothing to do + } + + public ngOnInit(): void { + // nothing to do + } + + public setNodes( nodes: SchemaNode[] ): void { + this.nodes = nodes; + } + + public getNodes( ): SchemaNode[] { + return this.nodes; + } + + public get hasNodes( ): boolean { + return this.getNodes().length > 0; + } + + /** + * Determine if the list already has the specified node + * @param {SchemaNode} node + * @returns {boolean} + */ + public hasNode( node: SchemaNode ): boolean { + let hasIt = false; + for (const listNode of this.nodes) { + if ( (listNode.getName() === node.getName()) && + (listNode.getConnectionName() === node.getConnectionName()) ) { + hasIt = true; + break; + } + } + return hasIt; + } + + public onNodeRemoved( node: SchemaNode ): void { + this.selectionListNodeRemoved.emit(node); + } +} diff --git a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts b/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts deleted file mode 100644 index 97750a85..00000000 --- a/ngapp/src/app/dataservices/selected-table/selected-table.component.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; -import { Connection } from "@connections/shared/connection.model"; -import { PatternFlyNgModule } from "patternfly-ng"; -import { SelectedTableComponent } from "./selected-table.component"; - -describe("SelectedTableComponent", () => { - let component: SelectedTableComponent; - let fixture: ComponentFixture; - let htmlElem: HTMLElement; - - const connectionName = "testConnection"; - const tableName = "testTable"; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ PatternFlyNgModule ], - declarations: [ SelectedTableComponent ] - }) - .compileComponents().then(() => { - // nothing to do - }); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SelectedTableComponent); - component = fixture.componentInstance; - htmlElem = fixture.nativeElement; - - const connection = new Connection(); - connection.setId( connectionName ); - - const table = new ConnectionTable(); - table.setConnection(connection); - table.setId(tableName); - component.table = table; - - fixture.detectChanges(); - }); - - it("should be created", () => { - console.log("========== [SelectedTableComponent] should be created"); - expect(component).toBeTruthy(); - }); - - it("should have correct table name", () => { - const heading = fixture.debugElement.nativeElement.querySelector( ".object-card-title" ); - expect( heading.textContent ).toContain( tableName ); - }); - - it("should have correct connector name", () => { - const heading = fixture.debugElement.nativeElement.querySelector( ".text-info" ); - expect( heading.textContent ).toContain( connectionName ); - }); - -}); diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 60c6a625..a610a11e 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -17,8 +17,8 @@ import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; +import { SchemaNode } from "@connections/shared/schema-node.model"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -333,12 +333,15 @@ export class DataserviceService extends ApiService { /** * Create a dataservice which is a straight passthru to the supplied tables * @param {NewDataservice} dataservice - * @param {ConnectionTable[]} connectionTables + * @param {SchemaNode[]} schemaNodes the source 'tables' for the service + * @param {Connection[]} connections the required connections for the schemaNodes * @returns {Observable} */ - public createDataserviceForSingleSourceTables(dataservice: NewDataservice, connectionTables: ConnectionTable[]): Observable { - // All tables from same connection - const connection: Connection = connectionTables[0].getConnection(); + public createDataserviceForSingleSourceTables(dataservice: NewDataservice, + schemaNodes: SchemaNode[], + connections: Connection[]): Observable { + // All tables currently must be from same connection + const connection: Connection = connections[0]; const schemaVdbName = connection.schemaVdbName; const schemaVdbModelName = connection.schemaVdbModelName; const schemaVdbModelSourceName = connection.schemaVdbModelSourceName; @@ -348,8 +351,8 @@ export class DataserviceService extends ApiService { // Get table paths for the tables used in the service const tablePaths = []; - for ( const connectionTable of connectionTables ) { - const tablePath = vdbPath + "/" + schemaVdbModelName + "/" + connectionTable.getId(); + for ( const connectionNode of schemaNodes ) { + const tablePath = vdbPath + "/" + schemaVdbModelName + "/" + connectionNode.getName(); tablePaths.push(tablePath); } @@ -369,12 +372,15 @@ export class DataserviceService extends ApiService { * Updates a dataservice with single table source. This is simply a create, with the added step of * deleting the existing workspace dataservice first. * @param {NewDataservice} dataservice - * @param {ConnectionTable[]} sourceTables + * @param {SchemaNode[]} schemaNodes + * @param {Connection[]} connections * @returns {Observable} */ - public updateDataserviceForSingleSourceTables(dataservice: NewDataservice, sourceTables: ConnectionTable[]): Observable { + public updateDataserviceForSingleSourceTables(dataservice: NewDataservice, + schemaNodes: SchemaNode[], + connections: Connection[]): Observable { return this.deleteDataservice(dataservice.getId()) - .flatMap((res) => this.createDataserviceForSingleSourceTables(dataservice, sourceTables)); + .flatMap((res) => this.createDataserviceForSingleSourceTables(dataservice, schemaNodes, connections)); } /** diff --git a/ngapp/src/app/dataservices/shared/node-selector.ts b/ngapp/src/app/dataservices/shared/node-selector.ts new file mode 100644 index 00000000..8936bd3a --- /dev/null +++ b/ngapp/src/app/dataservices/shared/node-selector.ts @@ -0,0 +1,43 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { SchemaNode } from "@connections/shared/schema-node.model"; + +/** + * The node selector interface + */ +export interface NodeSelector { + + /** + * Determine if any nodes are currently selected + * @returns {boolean} true if one or more nodes are selected + */ + hasSelectedNodes( ): boolean; + + /** + * Get the array of currently selected SchemaNodes + * @returns {SchemaNode[]} the array of selected SchemaNodes (never null, but may be empty) + */ + getSelectedNodes(): SchemaNode[]; + + /** + * Deselect the node if a node with the same name is currently selected. + * @param {SchemaNode} node the table to deselect + */ + deselectNode(node: SchemaNode): void; + +} diff --git a/ngapp/src/app/dataservices/shared/table-selector.ts b/ngapp/src/app/dataservices/shared/table-selector.ts deleted file mode 100644 index d43e9def..00000000 --- a/ngapp/src/app/dataservices/shared/table-selector.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ConnectionTable } from "@connections/shared/connection-table.model"; -import { Connection } from "@connections/shared/connection.model"; - -/** - * The table selector interface - */ -export interface TableSelector { - - /** - * Set the connection for this jdbc table selector - * @param {Connection} conn the jdbc connection - */ - setConnection(conn: Connection): void; - - /** - * Determine if any tables are currently selected - * @returns {boolean} true if one or more tables are selected - */ - hasSelectedTables( ): boolean; - - /** - * Get the array of currently selected Tables - * @returns {ConnectionTable[]} the array of selected ConnectionTable (never null, but may be empty) - */ - getSelectedTables(): ConnectionTable[]; - - /** - * Deselect the table if a table with the same name and connection is currently selected. - * @param {ConnectionTable} table the table to deselect - */ - deselectTable(table: ConnectionTable): void; - -} diff --git a/ngapp/src/app/dataservices/shared/wizard.service.ts b/ngapp/src/app/dataservices/shared/wizard.service.ts index 9e78c028..8b09154f 100644 --- a/ngapp/src/app/dataservices/shared/wizard.service.ts +++ b/ngapp/src/app/dataservices/shared/wizard.service.ts @@ -1,6 +1,6 @@ import { Injectable } from "@angular/core"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; +import { SchemaNode } from "@connections/shared/schema-node.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; @Injectable() @@ -8,7 +8,7 @@ export class WizardService { private static newlyAddedServiceWaitMillis = 10000; // Wait of 10 sec - private selectedConnectionTables: ConnectionTable[] = []; + private selectedSchemaNodes: SchemaNode[] = []; private edit = false; private currentConnections: Connection[] = []; private selectedDataservice: Dataservice; @@ -70,52 +70,53 @@ export class WizardService { } /** - * Get the wizard table selections - * @returns {ConnectionTable[]} the selections + * Get the wizard node selections + * @returns {SchemaNode[]} the selections */ - public getSelectedConnectionTables( ): ConnectionTable[] { - return this.selectedConnectionTables.sort( - ( thisTable, thatTable ) => { - return thisTable.getId().localeCompare( thatTable.getId() ); + public getSelectedSchemaNodes( ): SchemaNode[] { + const sel = this.selectedSchemaNodes.sort( + ( thisNode, thatNode ) => { + return thisNode.getName().localeCompare( thatNode.getName() ); } ); + return sel; } /** - * Clears the list of selected connection tables + * Clears the list of selected schema nodes */ - public clearSelectedConnectionTables( ): void { - this.selectedConnectionTables = []; + public clearSelectedSchemaNodes( ): void { + this.selectedSchemaNodes = []; } /** - * Determine if the supplied table is one of the current selections - * @param {ConnectionTable} table the table + * Determine if the supplied node is one of the current selections + * @param {SchemaNode} node the node */ - public isConnectionTableSelected(table: ConnectionTable): boolean { - return this.getConnectionTableIndex(table) > -1; + public isSchemaNodeSelected(node: SchemaNode): boolean { + return this.getSchemaNodeIndex(node) > -1; } /** - * Add a table to the currently selected connection tables - * @param {ConnectionTable} tableToAdd table to add + * Add a node to the currently selected connection node + * @param {SchemaNode} nodeToAdd node to add */ - public addToSelectedConnectionTables(tableToAdd: ConnectionTable): void { - if (!this.isConnectionTableSelected(tableToAdd)) { - this.selectedConnectionTables.push(tableToAdd); + public addToSelectedSchemaNodes(nodeToAdd: SchemaNode): void { + if (!this.isSchemaNodeSelected(nodeToAdd)) { + this.selectedSchemaNodes.push(nodeToAdd); } } /** - * Remove a table from the currently selected connection tables - * @param {ConnectionTable} tableToRemove - * @returns {boolean} + * Remove a node from the currently selected schema nodes + * @param {SchemaNode} nodeToRemove the node to remove + * @returns {boolean} true if node was removed */ - public removeFromSelectedConnectionTables(tableToRemove: ConnectionTable): boolean { + public removeFromSelectedSchemaNodes(nodeToRemove: SchemaNode): boolean { let wasRemoved = false; - const index = this.getConnectionTableIndex(tableToRemove); + const index = this.getSchemaNodeIndex(nodeToRemove); if (index > -1) { - this.selectedConnectionTables.splice(index, 1); + this.selectedSchemaNodes.splice(index, 1); wasRemoved = true; } @@ -210,19 +211,20 @@ export class WizardService { } /** - * Find index of the connection table in the wizard selected tables list. -1 if not found - * @param {ConnectionTable} table connection table - * @returns {number} + * Find index of the node in the selected nodes list. -1 if not found + * @param {SchemaNode} node the node + * @returns {number} the node index */ - private getConnectionTableIndex(table: ConnectionTable): number { + private getSchemaNodeIndex(node: SchemaNode): number { // supplied table and connection - const connName = table.getConnection().getId(); - const tableName = table.getId(); + const nodeName = node.getName(); + // const nodePath = node.getPath(); let i = 0; - for (const wizTable of this.selectedConnectionTables) { - const wizTableName = wizTable.getId(); - const wizConnName = wizTable.getConnection().getId(); - if (wizTableName === tableName && wizConnName === connName) { + for (const wizTable of this.selectedSchemaNodes) { + const wizNodeName = wizTable.getName(); + // const wizNodePath = wizTable.getPath(); + if (wizNodeName === nodeName) { +// if (wizNodeName === nodeName && wizNodePath === nodePath) { return i; } i++; diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index d7e6d53f..d3915f1a 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -17,9 +17,8 @@ import { Injectable } from "@angular/core"; import { ConnectionStatus } from "@connections/shared/connection-status"; -import { ConnectionTable } from "@connections/shared/connection-table.model"; import { Connection } from "@connections/shared/connection.model"; -import { SchemaInfo } from "@connections/shared/schema-info.model"; +import { SchemaNode } from "@connections/shared/schema-node.model"; import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; import { ConnectionSummary } from "@dataservices/shared/connection-summary.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; @@ -126,7 +125,7 @@ export class TestDataService { } ); - private static vdbStatuses = + private static readonly vdbStatuses = { "keng__baseUri": "http://das-beetle-studio.192.168.42.142.nip.io/vdb-builder/v1/", "vdbs": [ @@ -419,30 +418,99 @@ export class TestDataService { ]; // ================================================================= - // ConnectionTables for the connections + // Schemas for the connections // ================================================================= - private static pgConnConnectionTables = [ - TestDataService.createConnectionTable("pgTable1", TestDataService.pgConn, false), - TestDataService.createConnectionTable("pgTable2", TestDataService.pgConn, false) - ]; + private static pgConnSchemaJson = { + "connectionName": "pgConn", + "name": "restaurants", + "type": "collection", + "queryable": true, + "children": [ + { + "connectionName": "pgConn", + "name": "grades", + "type": "embedded", + "queryable": true, + "children": [] + }, + { + "connectionName": "pgConn", + "name": "location", + "type": "embedded", + "queryable": true, + "children": [] + } + ] + }; - private static conn1ConnectionTables = [ - TestDataService.createConnectionTable("conn1Table1", TestDataService.conn1, false), - TestDataService.createConnectionTable("conn1Table2", TestDataService.conn1, false) - ]; + private static conn1SchemaJson = { + "connectionName": "conn1", + "name": "public", + "type": "schema", + "queryable": false, + "children": [ + { + "connectionName": "conn1", + "name": "customer", + "type": "table", + "queryable": true, + "children": [] + }, + { + "connectionName": "conn1", + "name": "stuff", + "type": "table", + "queryable": true, + "children": [] + } + ] + }; - private static conn2ConnectionTables = [ - TestDataService.createConnectionTable("conn2Table1", TestDataService.conn2, false), - TestDataService.createConnectionTable("conn2Table2", TestDataService.conn2, false), - TestDataService.createConnectionTable("conn2Table3", TestDataService.conn2, false), - ]; + private static conn2SchemaJson = { + "connectionName": "conn2", + "name": "restaurants", + "type": "collection", + "queryable": true, + "children": [ + { + "connectionName": "conn2", + "name": "grades", + "type": "embedded", + "queryable": true, + "children": [] + }, + { + "connectionName": "conn2", + "name": "location", + "type": "embedded", + "queryable": true, + "children": [] + } + ] + }; - private static conn3ConnectionTables = [ - TestDataService.createConnectionTable("conn3Table1", TestDataService.conn3, false), - TestDataService.createConnectionTable("conn3Table2", TestDataService.conn3, false), - TestDataService.createConnectionTable("conn3Table3", TestDataService.conn3, false), - TestDataService.createConnectionTable("conn3Table4", TestDataService.conn3, false) - ]; + private static conn3SchemaJson = { + "connectionName": "conn3", + "name": "public", + "type": "schema", + "queryable": false, + "children": [ + { + "connectionName": "conn3", + "name": "customer", + "type": "table", + "queryable": true, + "children": [] + }, + { + "connectionName": "conn3", + "name": "stuff", + "type": "table", + "queryable": true, + "children": [] + } + ] + }; // ================================================================= // Result sets @@ -710,14 +778,12 @@ export class TestDataService { "serviceVdbVersion": TestDataService.accountsVdb.getVersion(), "serviceViewModel": "views", "serviceViews": [ - "AcctView1", - "AcctView2" + "tbl1View", + "tbl2View" ], "serviceViewTables": [ - TestDataService.conn1.getId() + "BtlSource.AcctView1Table1", - TestDataService.conn1.getId() + "BtlSource.AcctView1Table2", - TestDataService.conn1.getId() + "BtlSource.AcctView1Table3", - TestDataService.conn1.getId() + "BtlSource.AcctView2Table1" + TestDataService.conn1.getId().toLowerCase() + "schemavdb.tbl1", + TestDataService.conn1.getId().toLowerCase() + "schemavdb.tbl1" ], "connections": 0, "drivers": 0, @@ -758,22 +824,16 @@ export class TestDataService { "serviceVdbVersion": TestDataService.employeesVdb.getVersion(), "serviceViewModel": "views", "serviceViews": [ - "EmpView1", - "EmpView2", - "EmpView3", - "EmpView4" + "tbl1View", + "tbl2View", + "tbl3View", + "tbl4View" ], "serviceViewTables": [ - TestDataService.conn2.getId() + "BtlSource.EmpView1Table1", - TestDataService.conn2.getId() + "BtlSource.EmpView2Table1", - TestDataService.conn2.getId() + "BtlSource.EmpView2Table2", - TestDataService.conn2.getId() + "BtlSource.EmpView3Table1", - TestDataService.conn2.getId() + "BtlSource.EmpView3Table2", - TestDataService.conn2.getId() + "BtlSource.EmpView3Table3", - TestDataService.conn2.getId() + "BtlSource.EmpView4Table1", - TestDataService.conn2.getId() + "BtlSource.EmpView4Table2", - TestDataService.conn2.getId() + "BtlSource.EmpView4Table3", - TestDataService.conn2.getId() + "BtlSource.EmpView4Table4" + TestDataService.conn2.getId().toLowerCase() + "schemavdb.tbl1", + TestDataService.conn2.getId().toLowerCase() + "schemavdb.tbl2", + TestDataService.conn2.getId().toLowerCase() + "schemavdb.tbl3", + TestDataService.conn2.getId().toLowerCase() + "schemavdb.tbl4" ], "connections": 0, "drivers": 0, @@ -814,35 +874,20 @@ export class TestDataService { "serviceVdbVersion": TestDataService.productsVdb.getVersion(), "serviceViewModel": "views", "serviceViews": [ - "ProdView1", - "ProdView2", - "ProdView3", - "ProdView4", - "ProdView5", - "ProdView6" + "tbl1View", + "tbl2View", + "tbl3View", + "tbl4View", + "tbl5View", + "tbl6View" ], "serviceViewTables": [ - TestDataService.conn3.getId() + "BtlSource.ProdView1Table1", - TestDataService.conn3.getId() + "BtlSource.ProdView2Table1", - TestDataService.conn3.getId() + "BtlSource.ProdView2Table2", - TestDataService.conn3.getId() + "BtlSource.ProdView3Table1", - TestDataService.conn3.getId() + "BtlSource.ProdView3Table2", - TestDataService.conn3.getId() + "BtlSource.ProdView3Table3", - TestDataService.conn3.getId() + "BtlSource.ProdView4Table1", - TestDataService.conn3.getId() + "BtlSource.ProdView4Table2", - TestDataService.conn3.getId() + "BtlSource.ProdView4Table3", - TestDataService.conn3.getId() + "BtlSource.ProdView4Table4", - TestDataService.conn3.getId() + "BtlSource.ProdView5Table1", - TestDataService.conn3.getId() + "BtlSource.ProdView5Table2", - TestDataService.conn3.getId() + "BtlSource.ProdView5Table3", - TestDataService.conn3.getId() + "BtlSource.ProdView5Table4", - TestDataService.conn3.getId() + "BtlSource.ProdView5Table5", - TestDataService.conn3.getId() + "BtlSource.ProdView6Table1", - TestDataService.conn3.getId() + "BtlSource.ProdView6Table2", - TestDataService.conn3.getId() + "BtlSource.ProdView6Table3", - TestDataService.conn3.getId() + "BtlSource.ProdView6Table4", - TestDataService.conn3.getId() + "BtlSource.ProdView6Table5", - TestDataService.conn3.getId() + "BtlSource.ProdView6Table6" + TestDataService.conn3.getId().toLowerCase() + "schemavdb.tbl1", + TestDataService.conn3.getId().toLowerCase() + "schemavdb.tbl2", + TestDataService.conn3.getId().toLowerCase() + "schemavdb.tbl3", + TestDataService.conn3.getId().toLowerCase() + "schemavdb.tbl4", + TestDataService.conn3.getId().toLowerCase() + "schemavdb.tbl5", + TestDataService.conn3.getId().toLowerCase() + "schemavdb.tbl6" ], "connections": 0, "drivers": 0, @@ -940,7 +985,6 @@ export class TestDataService { TestDataService.productsVdb ]; - private connectionTableMap = new Map(); private readonly vdbStatuses: VdbStatus[]; private readonly virtualizations: Virtualization[]; @@ -974,21 +1018,6 @@ export class TestDataService { return connectionSummary; } - /** - * Create a ConnectionTable using the specified info - * @param {string} name the connection table name - * @param {Connection} connection the connection - * @param {boolean} selected 'true' if the table is selected - * @returns {ConnectionSummary} - */ - private static createConnectionTable( name: string, connection: Connection, selected: boolean ): ConnectionTable { - const connectionTable = new ConnectionTable(); - connectionTable.setId(name); - connectionTable.setConnection(connection); - connectionTable.selected = selected; - return connectionTable; - } - constructor() { this.vdbStatuses = TestDataService.vdbStatuses.vdbs.map(( vdbStatus ) => VdbStatus.create( vdbStatus ) ); this.virtualizations = [ @@ -1037,15 +1066,32 @@ export class TestDataService { } /** - * @returns {Map} the array of test Service Catalog datasources + * @returns {Map} the array of SchemaNodes for connection */ - public getConnectionTableMap(): Map { - const tableMap = new Map(); - tableMap.set( TestDataService.pgConn.getId(), TestDataService.pgConnConnectionTables ); - tableMap.set( TestDataService.conn1.getId(), TestDataService.conn1ConnectionTables ); - tableMap.set( TestDataService.conn2.getId(), TestDataService.conn2ConnectionTables ); - tableMap.set( TestDataService.conn3.getId(), TestDataService.conn3ConnectionTables ); - return tableMap; + public getConnectionSchemaMap(): Map { + const nodesMap = new Map(); + + const pgConnSchemaRoots: SchemaNode[] = []; + const sNode = SchemaNode.create(TestDataService.pgConnSchemaJson); + pgConnSchemaRoots.push(sNode); + + const conn1SchemaRoots: SchemaNode[] = []; + const sNode1 = SchemaNode.create(TestDataService.conn1SchemaJson); + conn1SchemaRoots.push(sNode1); + + const conn2SchemaRoots: SchemaNode[] = []; + const sNode2 = SchemaNode.create(TestDataService.conn2SchemaJson); + conn2SchemaRoots.push(sNode2); + + const conn3SchemaRoots: SchemaNode[] = []; + const sNode3 = SchemaNode.create(TestDataService.conn3SchemaJson); + conn3SchemaRoots.push(sNode3); + + nodesMap.set( TestDataService.pgConn.getId(), pgConnSchemaRoots ); + nodesMap.set( TestDataService.conn1.getId(), conn1SchemaRoots ); + nodesMap.set( TestDataService.conn2.getId(), conn2SchemaRoots ); + nodesMap.set( TestDataService.conn3.getId(), conn3SchemaRoots ); + return nodesMap; } /** diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index 9e4a69e3..6d5e4f1e 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -1,5 +1,6 @@ /* You can add global styles to this file, and also import other style files */ +@import "~angular-tree-component/dist/angular-tree-component.css"; @import "~codemirror/lib/codemirror.css"; @import "~codemirror/theme/mdn-like.css"; @import "~patternfly/dist/css/patternfly.css"; @@ -320,3 +321,47 @@ height: 75px; padding: 0; } + +/**************************************************************/ +/* Schema Tree Types */ +/**************************************************************/ +.object-tree .node-content-wrapper, .tree-children { + position: relative; +} + +.object-tree .node-content-wrapper::before, .tree-children::after { + content: ""; + position: absolute; +} + +.object-tree .node-content-wrapper::before { + border-bottom: 1px solid lightgrey; + border-left: 1px solid lightgrey; + height: 28px; + top: -17px; + width: 20px; + left: -28px; +} + +.object-tree .tree-node-level-1 > tree-node-wrapper > .node-wrapper > .node-content-wrapper::before { + display: none; +} + +.object-tree .tree-node-leaf > .node-wrapper > .node-content-wrapper::before { + width: 25px; +} + +.object-tree .tree-children::after { + border-left: 1px solid lightgrey; + height: 100%; + top: -15px; + left: -15px; +} + +.object-tree .tree-node:last-child > .tree-node > .tree-children::after { + border-left: none; +} + +.object-tree .toggle-children { + z-index: 1; +} From 5659653b7a807ec16955d832e5539338d16dd27b Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 17 May 2018 08:44:32 -0500 Subject: [PATCH 143/205] TEIIDTOOLS-433 Resolve issue with confirmation dialogs --- .../app/activities/activities.component.html | 3 - .../app/activities/activities.component.ts | 27 +++++-- ngapp/src/app/activities/activities.module.ts | 4 +- .../connections/connections.component.html | 5 -- .../app/connections/connections.component.ts | 35 ++++++--- .../src/app/connections/connections.module.ts | 4 +- .../dataservices/dataservices.component.html | 3 - .../dataservices/dataservices.component.ts | 25 +++++- .../app/dataservices/dataservices.module.ts | 4 +- .../confirm-delete.component.html | 20 ----- .../confirm-delete.component.spec.ts | 29 ------- .../confirm-delete.component.ts | 78 ------------------- .../confirm-dialog.component.css} | 0 .../confirm-dialog.component.html | 13 ++++ .../confirm-dialog.component.spec.ts | 29 +++++++ .../confirm-dialog.component.ts | 54 +++++++++++++ ngapp/src/app/shared/shared.module.ts | 6 +- 17 files changed, 175 insertions(+), 164 deletions(-) delete mode 100644 ngapp/src/app/shared/confirm-delete/confirm-delete.component.html delete mode 100644 ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts delete mode 100644 ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts rename ngapp/src/app/shared/{confirm-delete/confirm-delete.component.css => confirm-dialog/confirm-dialog.component.css} (100%) create mode 100644 ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.html create mode 100644 ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts create mode 100644 ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts diff --git a/ngapp/src/app/activities/activities.component.html b/ngapp/src/app/activities/activities.component.html index b8997308..a4e1a71f 100644 --- a/ngapp/src/app/activities/activities.component.html +++ b/ngapp/src/app/activities/activities.component.html @@ -102,6 +102,3 @@

    - -

    Do you really want to delete the selected Activity?

    -
    diff --git a/ngapp/src/app/activities/activities.component.ts b/ngapp/src/app/activities/activities.component.ts index 8a511e7d..0f491830 100644 --- a/ngapp/src/app/activities/activities.component.ts +++ b/ngapp/src/app/activities/activities.component.ts @@ -20,16 +20,16 @@ import { Activity } from "@activities/shared/activity.model"; import { ActivityService } from "@activities/shared/activity.service"; import { NewActivity } from "@activities/shared/new-activity.model"; import { Component } from "@angular/core"; -import { ViewChild } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { Router } from "@angular/router"; import { LoggerService } from "@core/logger.service"; import { ArrayUtils } from "@core/utils/array-utils"; import { AbstractPageComponent } from "@shared/abstract-page.component"; -import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; import { IdFilter } from "@shared/id-filter"; import { LayoutType } from "@shared/layout-type.enum"; import { SortDirection } from "@shared/sort-direction.enum"; +import { BsModalService } from "ngx-bootstrap"; @Component({ moduleId: module.id, @@ -50,14 +50,15 @@ export class ActivitiesComponent extends AbstractPageComponent { private filter: IdFilter = new IdFilter(); private layout: LayoutType = LayoutType.CARD; private sortDirection: SortDirection = SortDirection.ASC; + private modalService: BsModalService; - @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; - - constructor(router: Router, route: ActivatedRoute, activityService: ActivityService, logger: LoggerService ) { + constructor(router: Router, route: ActivatedRoute, activityService: ActivityService, + logger: LoggerService, modalService: BsModalService ) { super(route, logger); this.router = router; this.activityService = activityService; this.logger = logger; + this.modalService = modalService; } public loadAsyncPageData(): void { @@ -98,7 +99,21 @@ export class ActivitiesComponent extends AbstractPageComponent { public onDelete(activityName: string): void { this.activityNameForDelete = activityName; - this.confirmDeleteDialog.open(); + + // Dialog Content + const message = "Do you really want to delete Activity '" + activityName + "'?"; + const initialState = { + title: "Confirm Delete", + bodyContent: message, + cancelButtonText: "Cancel", + confirmButtonText: "Delete" + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); + modalRef.content.confirmAction.take(1).subscribe((value) => { + this.onDeleteActivity(); + }); } // noinspection JSMethodCanBeStatic diff --git a/ngapp/src/app/activities/activities.module.ts b/ngapp/src/app/activities/activities.module.ts index 7cbe3baf..3b89491f 100644 --- a/ngapp/src/app/activities/activities.module.ts +++ b/ngapp/src/app/activities/activities.module.ts @@ -31,6 +31,7 @@ import { RouterModule } from "@angular/router"; import { ConnectionsModule } from "@connections/connections.module"; import { CoreModule } from "@core/core.module"; import { LoggerService } from "@core/logger.service"; +import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; @@ -58,6 +59,7 @@ import { PatternFlyNgModule } from "patternfly-ng"; providers: [ ActivityService, LoggerService - ] + ], + entryComponents: [ConfirmDialogComponent] }) export class ActivitiesModule {} diff --git a/ngapp/src/app/connections/connections.component.html b/ngapp/src/app/connections/connections.component.html index aa0b443c..1942182c 100644 --- a/ngapp/src/app/connections/connections.component.html +++ b/ngapp/src/app/connections/connections.component.html @@ -86,8 +86,3 @@

    - -

    - Do you really want to delete the '{{ connectionNameForDelete }}' Connection? -

    -
    diff --git a/ngapp/src/app/connections/connections.component.ts b/ngapp/src/app/connections/connections.component.ts index 87778255..956076af 100644 --- a/ngapp/src/app/connections/connections.component.ts +++ b/ngapp/src/app/connections/connections.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Component, OnInit, ViewChild } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { ConnectionStatus } from "@connections/shared/connection-status"; import { Connection } from "@connections/shared/connection.model"; @@ -26,16 +26,17 @@ import { LoggerService } from "@core/logger.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { AbstractPageComponent } from "@shared/abstract-page.component"; -import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; import { LayoutType } from "@shared/layout-type.enum"; -import { FilterConfig } from "patternfly-ng"; -import { FilterField } from "patternfly-ng"; -import { FilterEvent } from "patternfly-ng"; +import { BsModalService } from "ngx-bootstrap"; import { SortField } from "patternfly-ng"; import { SortEvent } from "patternfly-ng"; import { FilterType } from "patternfly-ng"; -import { ActionConfig, EmptyStateConfig, Filter } from "patternfly-ng"; +import { FilterEvent } from "patternfly-ng"; import { SortConfig } from "patternfly-ng"; +import { FilterField } from "patternfly-ng"; +import { FilterConfig } from "patternfly-ng"; +import { ActionConfig, EmptyStateConfig, Filter } from "patternfly-ng"; import { Subscription } from "rxjs/Subscription"; @Component({ @@ -65,18 +66,18 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni private wizardService: WizardService; private notifierService: NotifierService; private connectionStatusSubscription: Subscription; - - @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; + private modalService: BsModalService; constructor(router: Router, route: ActivatedRoute, appSettingsService: AppSettingsService, wizardService: WizardService, connectionService: ConnectionService, logger: LoggerService, - notifierService: NotifierService, ) { + notifierService: NotifierService, modalService: BsModalService ) { super(route, logger); this.router = router; this.appSettingsService = appSettingsService; this.connectionService = connectionService; this.wizardService = wizardService; this.notifierService = notifierService; + this.modalService = modalService; // Register for connection status changes this.connectionStatusSubscription = this.notifierService.getConnectionStatusMap().subscribe((connectionStatusMap) => { this.onConnectionStatusChanged(connectionStatusMap); @@ -227,7 +228,21 @@ export class ConnectionsComponent extends AbstractPageComponent implements OnIni public onDelete(connName: string): void { this.connectionNameForDelete = connName; - this.confirmDeleteDialog.open(); + + // Dialog Content + const message = "Do you really want to delete Connection '" + connName + "'?"; + const initialState = { + title: "Confirm Delete", + bodyContent: message, + cancelButtonText: "Cancel", + confirmButtonText: "Delete" + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); + modalRef.content.confirmAction.take(1).subscribe((value) => { + this.onDeleteConnection(); + }); } public setListLayout(): void { diff --git a/ngapp/src/app/connections/connections.module.ts b/ngapp/src/app/connections/connections.module.ts index 63551b44..c7b4bd65 100644 --- a/ngapp/src/app/connections/connections.module.ts +++ b/ngapp/src/app/connections/connections.module.ts @@ -36,6 +36,7 @@ import { LoggerService } from "@core/logger.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { environment } from "@environments/environment"; +import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; import { SharedModule } from "@shared/shared.module"; import { PatternFlyNgModule } from "patternfly-ng"; import { ConnectionTypeCardComponent } from "./connection-type-cards/connection-type-card/connection-type-card.component"; @@ -74,7 +75,8 @@ import { ConnectionTypeCardsComponent } from "./connection-type-cards/connection LoggerService ], exports: [ - ] + ], + entryComponents: [ConfirmDialogComponent] }) export class ConnectionsModule { } diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 71656eda..d9be7ea4 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -113,6 +113,3 @@

    - -

    Do you really want to delete the selected Virtualization?

    -
    diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index e12ed6ca..6ba679f4 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -33,9 +33,10 @@ import { Virtualization } from "@dataservices/shared/virtualization.model"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; import { AbstractPageComponent } from "@shared/abstract-page.component"; -import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; +import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; import { LayoutType } from "@shared/layout-type.enum"; import { SortDirection } from "@shared/sort-direction.enum"; +import { BsModalService } from "ngx-bootstrap"; import { ActionConfig, EmptyStateConfig, @@ -104,13 +105,14 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn private wizardService: WizardService; private selectedSvcViews: View[] = []; private allSvcViews: View[] = []; + private modalService: BsModalService; - @ViewChild(ConfirmDeleteComponent) private confirmDeleteDialog: ConfirmDeleteComponent; @ViewChild(SqlControlComponent) private sqlControlComponent: SqlControlComponent; constructor(router: Router, route: ActivatedRoute, dataserviceService: DataserviceService, logger: LoggerService, appSettingsService: AppSettingsService, wizardService: WizardService, - notifierService: NotifierService, vdbService: VdbService, connectionService: ConnectionService ) { + notifierService: NotifierService, vdbService: VdbService, connectionService: ConnectionService, + modalService: BsModalService) { super(route, logger); this.router = router; this.appSettingsService = appSettingsService; @@ -118,6 +120,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.vdbService = vdbService; this.notifierService = notifierService; this.wizardService = wizardService; + this.modalService = modalService; // Register for dataservice deployment state changes this.dataserviceDeployStateSubscription = this.notifierService.getDataserviceDeployStateMap().subscribe((serviceStateMap) => { this.onDataserviceDeploymentStateChanged(serviceStateMap); @@ -492,7 +495,21 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.setQuickLookPanelOpenState(false); this.dataserviceNameForDelete = svcName; - this.confirmDeleteDialog.open(); + + // Dialog Content + const message = "Do you really want to delete Virtualization '" + svcName + "'?"; + const initialState = { + title: "Confirm Delete", + bodyContent: message, + cancelButtonText: "Cancel", + confirmButtonText: "Delete" + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); + modalRef.content.confirmAction.take(1).subscribe((value) => { + this.onDeleteDataservice(); + }); } /** diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 17e71899..5baf3b65 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -36,6 +36,7 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { WizardService } from "@dataservices/shared/wizard.service"; import { environment } from "@environments/environment"; +import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; import { SharedModule } from "@shared/shared.module"; import { TreeModule } from "angular-tree-component"; import { CodemirrorModule } from "ng2-codemirror"; @@ -97,7 +98,8 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co WizardService ], exports: [ - ] + ], + entryComponents: [ConfirmDialogComponent] }) export class DataservicesModule { } diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html deleted file mode 100644 index 403cc5c4..00000000 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.html +++ /dev/null @@ -1,20 +0,0 @@ - diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts deleted file mode 100644 index 9d7dedeb..00000000 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; -import { ModalModule } from "ngx-bootstrap"; -import { ConfirmDeleteComponent } from "./confirm-delete.component"; - -describe("ConfirmDeleteComponent", () => { - let component: ConfirmDeleteComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ModalModule.forRoot()], - declarations: [ ConfirmDeleteComponent ] - }) - .compileComponents().then(() => { - // nothing to do - }); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ConfirmDeleteComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should be created", () => { - console.log("========== [ConfirmDeleteComponent] should be created"); - expect(component).toBeTruthy(); - }); -}); diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts b/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts deleted file mode 100644 index d301cb4a..00000000 --- a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, EventEmitter, Output, QueryList, ViewChildren } from "@angular/core"; -import { ModalDirective } from "ngx-bootstrap"; - -@Component({ - moduleId: module.id, - selector: "app-confirm-delete", - templateUrl: "./confirm-delete.component.html", - styleUrls: ["./confirm-delete.component.css"] -}) - -export class ConfirmDeleteComponent { - - protected dialogIsOpen = false; - - @Output() public deleteSelected: EventEmitter = new EventEmitter(); - @ViewChildren("confirmDeleteModal") public confirmDeleteModal: QueryList; - - /** - * Called to open the dialog. - */ - public open(): void { - this.dialogIsOpen = true; - const self = this; - this.confirmDeleteModal.changes.subscribe( (thing) => { - if (self.confirmDeleteModal.first) { - self.confirmDeleteModal.first.show(); - } - }); - } - - /** - * Called to close the dialog. - */ - public close(): void { - this.dialogIsOpen = false; - } - - /** - * Called when the user clicks "Yes". - */ - protected onDeleteSelected(): void { - this.deleteSelected.emit(true); - this.onCancelSelected(); - } - - /** - * Called when the user clicks "cancel". - */ - protected onCancelSelected(): void { - this.confirmDeleteModal.first.hide(); - } - - /** - * Returns true if the dialog is open. - * @return {boolean} - */ - public isOpen(): boolean { - return this.dialogIsOpen; - } - -} diff --git a/ngapp/src/app/shared/confirm-delete/confirm-delete.component.css b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.css similarity index 100% rename from ngapp/src/app/shared/confirm-delete/confirm-delete.component.css rename to ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.css diff --git a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.html b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.html new file mode 100644 index 00000000..95eccf72 --- /dev/null +++ b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.html @@ -0,0 +1,13 @@ + + + diff --git a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts new file mode 100644 index 00000000..0395c8bd --- /dev/null +++ b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts @@ -0,0 +1,29 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { BsModalRef } from "ngx-bootstrap"; +import { ConfirmDialogComponent } from "./confirm-dialog.component"; + +describe("ConfirmDialogComponent", () => { + let component: ConfirmDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ConfirmDialogComponent ], + providers: [ + BsModalRef + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfirmDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it("should be created", () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts new file mode 100644 index 00000000..325421b9 --- /dev/null +++ b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts @@ -0,0 +1,54 @@ +import { Component, OnInit } from "@angular/core"; +import { Output } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { BsModalRef } from "ngx-bootstrap"; + +@Component({ + selector: "app-confirm-dialog", + templateUrl: "./confirm-dialog.component.html", + styleUrls: ["./confirm-dialog.component.css"] +}) +/** + * Confirmation Dialog. Invoke this from another component as follows: + * + * this.modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); + * this.modalRef.content.confirmAction.take(1).subscribe((value) => { + * this.doSomethingOnConfirm(); + * }); + * + * The expected initial state is as follows: + * const initialState = { + * title: "The dialog title", + * bodyContent: "The dialog message", + * cancelButtonText: "Text for cancel button", + * confirmButtonText: "Text for confirm button" + * }; + */ +export class ConfirmDialogComponent implements OnInit { + + @Output() public confirmAction = new EventEmitter(); + + public title = "Title" + public bodyContent = "Confirmation Message"; + public cancelButtonText = "Cancel"; + public confirmButtonText = "Confirm"; + public bsModalRef: BsModalRef; + + constructor(bsModalRef: BsModalRef) { + this.bsModalRef = bsModalRef; + } + + public ngOnInit(): void { + // Nothing to do + } + + public onConfirmSelected(): void { + this.confirmAction.emit(true); + this.bsModalRef.hide(); + } + + public onCancelSelected(): void { + this.bsModalRef.hide(); + } + +} diff --git a/ngapp/src/app/shared/shared.module.ts b/ngapp/src/app/shared/shared.module.ts index 5bf00b98..d884ce9f 100644 --- a/ngapp/src/app/shared/shared.module.ts +++ b/ngapp/src/app/shared/shared.module.ts @@ -19,10 +19,10 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { ReactiveFormsModule } from "@angular/forms"; -import { ConfirmDeleteComponent } from "@shared/confirm-delete/confirm-delete.component"; import { PageErrorComponent } from "@shared/page-error/page-error.component"; import { TestDataService } from "@shared/test-data.service"; import { ModalModule } from "ngx-bootstrap"; +import { ConfirmDialogComponent } from "./confirm-dialog/confirm-dialog.component"; import { PageNotFoundComponent } from "./page-not-found/page-not-found.component"; import { PropertyFormPropertyComponent } from "./property-form/property-form-property/property-form-property.component"; import { PropertyFormComponent } from "./property-form/property-form.component"; @@ -34,14 +34,14 @@ import { PropertyFormComponent } from "./property-form/property-form.component"; ReactiveFormsModule ], declarations: [ - ConfirmDeleteComponent, + ConfirmDialogComponent, PageErrorComponent, PageNotFoundComponent, PropertyFormComponent, PropertyFormPropertyComponent ], exports: [ - ConfirmDeleteComponent, + ConfirmDialogComponent, PageErrorComponent, PageNotFoundComponent, PropertyFormComponent, From 5af312b365a852d6661a89c023c613d7b26dacee Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 18 May 2018 11:15:58 -0500 Subject: [PATCH 144/205] TTOOLS-404 Adds unit tests for models --- .../shared/connection-status.spec.ts | 35 +++ .../shared/connection.model.spec.ts | 57 +++++ .../service-catalog-source.model.spec.ts | 45 ++++ .../shared/template-definition.model.ts | 87 -------- .../shared/catalog-schema.model.ts | 91 -------- .../shared/connection-summary.model.spec.ts | 74 +++++++ .../shared/dataservice.model.spec.ts | 71 +++++++ .../shared/query-results.model.spec.ts | 200 ++++++++++++++++++ .../shared/vdb-status.model.spec.ts | 33 +++ .../shared/virtualization.model.spec.ts | 36 ++++ 10 files changed, 551 insertions(+), 178 deletions(-) create mode 100644 ngapp/src/app/connections/shared/connection-status.spec.ts create mode 100644 ngapp/src/app/connections/shared/connection.model.spec.ts create mode 100644 ngapp/src/app/connections/shared/service-catalog-source.model.spec.ts delete mode 100644 ngapp/src/app/connections/shared/template-definition.model.ts delete mode 100644 ngapp/src/app/dataservices/shared/catalog-schema.model.ts create mode 100644 ngapp/src/app/dataservices/shared/connection-summary.model.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/dataservice.model.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/query-results.model.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/vdb-status.model.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/virtualization.model.spec.ts diff --git a/ngapp/src/app/connections/shared/connection-status.spec.ts b/ngapp/src/app/connections/shared/connection-status.spec.ts new file mode 100644 index 00000000..07b58a53 --- /dev/null +++ b/ngapp/src/app/connections/shared/connection-status.spec.ts @@ -0,0 +1,35 @@ +import { ConnectionStatus } from "@connections/shared/connection-status"; + +describe("ConnectionStatus", () => { + let connectionStatus: ConnectionStatus; + + beforeEach(() => { + connectionStatus = null; + }); + + it("should create", () => { + console.log("========== [ConnectionStatus] should create"); + connectionStatus = ConnectionStatus.create( + { + "connectionName": "PgConn", + "vdbState": "ACTIVE", + "schemaState": "ACTIVE", + "errors": [], + "schemaModelName": "pgconnschemamodel", + "schemaVdbName": "pgconnschemavdb", + "vdbName": "pgconnbtlconn" + } + ); + + expect(connectionStatus.getConnectionName()).toEqual("PgConn"); + expect(connectionStatus.getSchemaModelName()).toEqual("pgconnschemamodel"); + expect(connectionStatus.getSchemaVdbName()).toEqual("pgconnschemavdb"); + expect(connectionStatus.getServerVdbName()).toEqual("pgconnbtlconn"); + expect(connectionStatus.getErrors()).toEqual([]); + expect(connectionStatus.isServerVdbActive()).toEqual(true); + expect(connectionStatus.isServerVdbMissing()).toEqual(false); + expect(connectionStatus.isServerVdbLoading()).toEqual(false); + expect(connectionStatus.isServerVdbFailed()).toEqual(false); + }); + +}); diff --git a/ngapp/src/app/connections/shared/connection.model.spec.ts b/ngapp/src/app/connections/shared/connection.model.spec.ts new file mode 100644 index 00000000..68db8c61 --- /dev/null +++ b/ngapp/src/app/connections/shared/connection.model.spec.ts @@ -0,0 +1,57 @@ +import { Connection } from "@connections/shared/connection.model"; + +describe("Connection", () => { + let connection: Connection; + + beforeEach(() => { + connection = null; + }); + + it("should create", () => { + console.log("========== [Connection] should create"); + connection = Connection.create( + { + "keng__baseUri": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/", + "keng__id": "PgConn", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/PgConn", + "keng__kType": "Connection", + "keng__hasChildren": true, + "dv__jndiName": "java:/postgresql-persistent-jq7wz", + "dv__driverName": "postgresql", + "dv__type": true, + "keng__properties": [ + { + "name": "description", + "value": "customer db on postgres" + }, + { + "name": "serviceCatalogSource", + "value": "postgresql-persistent-jq7wz" + } + ], + "keng___links": [ + { + "rel": "self", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/connections/PgConn" + }, + { + "rel": "parent", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/connections" + }, + { + "rel": "children", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/search%2Fadmin%2FPgConn" + } + ] + } + ); + + expect(connection.getId()).toEqual("PgConn"); + expect(connection.getDescription()).toEqual("customer db on postgres"); + expect(connection.getDriverName()).toEqual("postgresql"); + expect(connection.getJndiName()).toEqual("java:/postgresql-persistent-jq7wz"); + expect(connection.getServiceCatalogSourceName()).toEqual("postgresql-persistent-jq7wz"); + expect(connection.getDataPath()).toEqual("/tko:komodo/tko:workspace/admin/PgConn"); + }); + +}); diff --git a/ngapp/src/app/connections/shared/service-catalog-source.model.spec.ts b/ngapp/src/app/connections/shared/service-catalog-source.model.spec.ts new file mode 100644 index 00000000..85f1ae39 --- /dev/null +++ b/ngapp/src/app/connections/shared/service-catalog-source.model.spec.ts @@ -0,0 +1,45 @@ +import { ServiceCatalogSource } from "@connections/shared/service-catalog-source.model"; + +describe("ServiceCatalogSource", () => { + let serviceCatSrc: ServiceCatalogSource; + + beforeEach(() => { + serviceCatSrc = null; + }); + + it("should create", () => { + console.log("========== [ServiceCatalogSource] should create"); + serviceCatSrc = ServiceCatalogSource.create( + { + "keng__baseUri": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/", + "keng__id": "mongodb-persistent-762zc", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/2018-05-17_20-35-29-543", + "keng__kType": "ServiceCatalogDataSource", + "keng__hasChildren": false, + "sc__name": "mongodb-persistent-762zc", + "sc__type": "mongodb", + "sc__bound": true, + "sc__translator": "mongodb", + "keng___links": [ + { + "rel": "self", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/metadata/connections/mongodb-persistent-762zc" + }, + { + "rel": "parent", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/metadata/connections" + }, + { + "rel": "children", + "href": "http://das-beetle-studio.192.168.42.1154.nip.ip/xxx" + } + ] + } + ); + + expect(serviceCatSrc.getName()).toEqual("mongodb-persistent-762zc"); + expect(serviceCatSrc.getType()).toEqual("mongodb"); + expect(serviceCatSrc.isBound()).toEqual(true); + }); + +}); diff --git a/ngapp/src/app/connections/shared/template-definition.model.ts b/ngapp/src/app/connections/shared/template-definition.model.ts deleted file mode 100644 index f707fbd2..00000000 --- a/ngapp/src/app/connections/shared/template-definition.model.ts +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export class TemplateDefinition { - private keng__id: string; - private isJdbc: boolean; - private entries: string[]; - - /** - * @param {Object} json the JSON representation of a Template - * @returns {TemplateDefinition} the new TemplateDefinition (never null) - */ - public static create( json: object = {} ): TemplateDefinition { - const template = new TemplateDefinition(); - template.setValues( json ); - return template; - } - - constructor() { - // nothing to do - } - - /** - * @returns {string} the property id - */ - public getId(): string { - return this.keng__id; - } - - /** - * @returns {boolean} 'true' if jdbc - */ - public getJdbc(): boolean { - return this.isJdbc; - } - - /** - * @returns {string[]} the array of entries - */ - public getEntries(): string[] { - return this.entries; - } - - /** - * @param {string} id the property id - */ - public setId( id?: string ): void { - this.keng__id = id ? id : null; - } - - /** - * @param {boolean} jdbc 'true' if template is jdbc - */ - public setJdbc( jdbc?: boolean ): void { - this.isJdbc = jdbc ? jdbc : null; - } - - /** - * @param {string[]} entries the array of entries - */ - public setEntries( entries?: string[] ): void { - this.entries = entries ? entries : null; - } - - /** - * Set all object values using the supplied Template json - * @param {Object} values - */ - public setValues(values: object = {}): void { - Object.assign(this, values); - } - -} diff --git a/ngapp/src/app/dataservices/shared/catalog-schema.model.ts b/ngapp/src/app/dataservices/shared/catalog-schema.model.ts deleted file mode 100644 index 540161cb..00000000 --- a/ngapp/src/app/dataservices/shared/catalog-schema.model.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * CatalogSchema model. The type will be 'Catalog' or 'Schema'. For Schema, the catalogName may - * or may not be set depending on whether Catalogs are supported. - */ -export class CatalogSchema { - private name: string; - private type: string; - private catalogName: string; - - constructor() { - // nothing to do - } - - /** - * @returns {string} the info name - */ - public getName(): string { - return this.name; - } - - /** - * @returns {string} the info type - */ - public getType(): string { - return this.type; - } - - /** - * @returns {string} the catalog name - */ - public getCatalogName(): string { - return this.catalogName; - } - - /** - * @returns {string} the display name - */ - public getDisplayName(): string { - const type = this.getType(); - if ( type === "Catalog" ) { - return this.getName(); - } else if ( type === "Schema" ) { - const catalog = this.getCatalogName(); - if ( catalog && catalog.length > 0 ) { - return catalog + "." + this.getName(); - } else { - return this.getName(); - } - } - return this.catalogName; - } - - /** - * @param {string} name the name - */ - public setName( name?: string ): void { - this.name = name ? name : null; - } - - /** - * @param {string} type the type - */ - public setType( type?: string ): void { - this.type = type ? type : null; - } - - /** - * @param {string} name the name of the catalog - */ - public setCatalogName( name?: string ): void { - this.catalogName = name ? name : null; - } - -} diff --git a/ngapp/src/app/dataservices/shared/connection-summary.model.spec.ts b/ngapp/src/app/dataservices/shared/connection-summary.model.spec.ts new file mode 100644 index 00000000..1f4291ad --- /dev/null +++ b/ngapp/src/app/dataservices/shared/connection-summary.model.spec.ts @@ -0,0 +1,74 @@ +import { ConnectionSummary } from "@dataservices/shared/connection-summary.model"; + +describe("ConnectionSummary", () => { + let connectionSummary: ConnectionSummary; + + beforeEach(() => { + connectionSummary = null; + }); + + it("should create", () => { + console.log("========== [ConnectionSummary] should create"); + connectionSummary = ConnectionSummary.create( + { + "connection": { + "keng__baseUri": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/", + "keng__id": "PgConn", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/PgConn", + "keng__kType": "Connection", + "keng__hasChildren": true, + "dv__jndiName": "java:/postgresql-persistent-jq7wz", + "dv__driverName": "postgresql", + "dv__type": true, + "keng__properties": [ + { + "name": "description", + "value": "customer db on postgres" + }, + { + "name": "serviceCatalogSource", + "value": "postgresql-persistent-jq7wz" + } + ], + "keng___links": [ + { + "rel": "self", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/connections/PgConn" + }, + { + "rel": "parent", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/connections" + }, + { + "rel": "children", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/search%2Fadmin%2FPgConn" + } + ] + }, + "status": { + "connectionName": "PgConn", + "vdbState": "ACTIVE", + "schemaState": "ACTIVE", + "errors": [], + "schemaModelName": "pgconnschemamodel", + "schemaVdbName": "pgconnschemavdb", + "vdbName": "pgconnbtlconn" + } + } + ); + + expect(connectionSummary.getConnection().getId()).toEqual("PgConn"); + expect(connectionSummary.getConnection().getDescription()).toEqual("customer db on postgres"); + expect(connectionSummary.getConnection().getDriverName()).toEqual("postgresql"); + expect(connectionSummary.getConnection().getJndiName()).toEqual("java:/postgresql-persistent-jq7wz"); + expect(connectionSummary.getConnection().getServiceCatalogSourceName()).toEqual("postgresql-persistent-jq7wz"); + expect(connectionSummary.getConnection().getDataPath()).toEqual("/tko:komodo/tko:workspace/admin/PgConn"); + + expect(connectionSummary.getStatus().getConnectionName()).toEqual("PgConn"); + expect(connectionSummary.getStatus().getSchemaModelName()).toEqual("pgconnschemamodel"); + expect(connectionSummary.getStatus().getSchemaVdbName()).toEqual("pgconnschemavdb"); + expect(connectionSummary.getStatus().getServerVdbName()).toEqual("pgconnbtlconn"); + expect(connectionSummary.getStatus().getErrors()).toEqual([]); + }); + +}); diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.spec.ts b/ngapp/src/app/dataservices/shared/dataservice.model.spec.ts new file mode 100644 index 00000000..433498f0 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/dataservice.model.spec.ts @@ -0,0 +1,71 @@ +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; +import { PublishState } from "@dataservices/shared/publish-state.enum"; + +describe("Dataservice", () => { + let dataservice: Dataservice; + + beforeEach(() => { + dataservice = null; + }); + + it("should create", () => { + console.log("========== [Dataservice] should create"); + dataservice = Dataservice.create( + { + "keng__baseUri": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/", + "keng__id": "mongoVirtualization", + "keng__dataPath": "/tko:komodo/tko:workspace/admin/mongoVirtualization", + "keng__kType": "Dataservice", + "keng__hasChildren": true, + "serviceVdbName": "mongovirtualizationvdb", + "serviceVdbVersion": "1", + "serviceViewModel": "views", + "serviceViews": [ + "addressView", + "gradesView", + "restaurantsView" + ], + "serviceViewTables": [ + "mongoconnschemavdb.address", + "mongoconnschemavdb.grades", + "mongoconnschemavdb.restaurants" + ], + "connections": 0, + "drivers": 0, + "keng___links": [ + { + "rel": "self", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/dataservices/mongoVirtualization" + }, + { + "rel": "parent", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/dataservices" + }, + { + "rel": "children", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/xxx" + }, + { + "rel": "vdbs", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/yyy" + }, + { + "rel": "connections", + "href": "http://das-beetle-studio.192.168.42.154.nip.io/vdb-builder/v1/workspace/zzz" + } + ] + } + ); + + expect(dataservice.getId()).toEqual("mongoVirtualization"); + expect(dataservice.getServiceVdbName()).toEqual("mongovirtualizationvdb"); + expect(dataservice.getServiceVdbVersion()).toEqual("1"); + expect(dataservice.getServiceViewModel()).toEqual("views"); + expect(dataservice.getServiceViewTables().length).toEqual(3); + expect(dataservice.getServiceViewNames().length).toEqual(3); + expect(dataservice.getServiceDeploymentState()).toEqual(DeploymentState.LOADING); + expect(dataservice.getServicePublishState()).toEqual(PublishState.NOT_PUBLISHED); + }); + +}); diff --git a/ngapp/src/app/dataservices/shared/query-results.model.spec.ts b/ngapp/src/app/dataservices/shared/query-results.model.spec.ts new file mode 100644 index 00000000..d4c7e2a6 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/query-results.model.spec.ts @@ -0,0 +1,200 @@ +import { QueryResults } from "@dataservices/shared/query-results.model"; + +describe("QueryResults", () => { + let queryResults: QueryResults; + + const employeeJson = { + "columns": [ + { + "name": "ssn", + "label": "ssn", + "type": "string" + }, + { + "name": "firstname", + "label": "firstname", + "type": "string" + }, + { + "name": "lastname", + "label": "lastname", + "type": "string" + }, + { + "name": "st_address", + "label": "st_address", + "type": "string" + }, + { + "name": "apt_number", + "label": "apt_number", + "type": "string" + }, + { + "name": "city", + "label": "city", + "type": "string" + }, + { + "name": "state", + "label": "state", + "type": "string" + }, + { + "name": "zipcode", + "label": "zipcode", + "type": "string" + }, + { + "name": "phone", + "label": "phone", + "type": "string" + } + ], + "rows": [ + { + "row": [ + "CST01002 ", + "Joseph", + "Smith", + "1234 Main Street", + "Apartment 56", + "New York", + "New York", + "10174", + "(646)555-1776" + ] + }, + { + "row": [ + "CST01003 ", + "Nicholas", + "Ferguson", + "202 Palomino Drive", + "", + "Pittsburgh", + "Pennsylvania", + "15071", + "(412)555-4327" + ] + }, + { + "row": [ + "CST01004 ", + "Jane", + "Aire", + "15 State Street", + "", + "Philadelphia", + "Pennsylvania", + "19154", + "(814)555-6789" + ] + }, + { + "row": [ + "CST01005 ", + "Charles", + "Jones", + "1819 Maple Street", + "Apartment 17F", + "Stratford", + "Connecticut", + "06614", + "(203)555-3947" + ] + }, + { + "row": [ + "CST01006 ", + "Virginia", + "Jefferson", + "1710 South 51st Street", + "Apartment 3245", + "New York", + "New York", + "10175", + "(718)555-2693" + ] + }, + { + "row": [ + "CST01007 ", + "Ralph", + "Bacon", + "57 Barn Swallow Avenue", + "", + "Charlotte", + "North Carolina", + "28205", + "(704)555-4576" + ] + }, + { + "row": [ + "CST01008 ", + "Bonnie", + "Dragon", + "88 Cinderella Lane", + "", + "Jacksonville", + "Florida", + "32225", + "(904)555-6514" + ] + }, + { + "row": [ + "CST01009 ", + "Herbert", + "Smith", + "12225 Waterfall Way", + "Building 100, Suite 9", + "Portland", + "Oregon", + "97220", + "(971)555-7803" + ] + }, + { + "row": [ + "CST01015 ", + "Jack", + "Corby", + "1 Lone Star Way", + "", + "Dallas", + "Texas", + "75231", + "(469)555-8023" + ] + }, + { + "row": [ + "CST01019 ", + "Robin", + "Evers", + "1814 Falcon Avenue", + "", + "Atlanta", + "Georgia", + "30355", + "(470)555-4390" + ] + } + ] + }; + + beforeEach(() => { + queryResults = null; + }); + + it("should create", () => { + console.log("========== [QueryResults] should create"); + queryResults = new QueryResults(employeeJson); + + expect(queryResults.getColumns().length).toEqual(9); + expect(queryResults.getRows().length).toEqual(10); + }); + +}); diff --git a/ngapp/src/app/dataservices/shared/vdb-status.model.spec.ts b/ngapp/src/app/dataservices/shared/vdb-status.model.spec.ts new file mode 100644 index 00000000..838c5e29 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/vdb-status.model.spec.ts @@ -0,0 +1,33 @@ +import { VdbStatus } from "@dataservices/shared/vdb-status.model"; + +describe("VdbStatus", () => { + let vdbStatus: VdbStatus; + + beforeEach(() => { + vdbStatus = null; + }); + + it("should create", () => { + console.log("========== [VdbStatus] should create"); + vdbStatus = VdbStatus.create( + { + "name": "acctsVdb", + "deployedName": "acctsVdb-vdb.xml", + "version": "1", + "active": true, + "loading": false, + "failed": false, + "errors": [] + } + ); + + expect(vdbStatus.getName()).toEqual("acctsVdb"); + expect(vdbStatus.getDeployedName()).toEqual("acctsVdb-vdb.xml"); + expect(vdbStatus.getVersion()).toEqual("1"); + expect(vdbStatus.getErrors()).toEqual([]); + expect(vdbStatus.isActive()).toEqual(true); + expect(vdbStatus.isLoading()).toEqual(false); + expect(vdbStatus.isFailed()).toEqual(false); + }); + +}); diff --git a/ngapp/src/app/dataservices/shared/virtualization.model.spec.ts b/ngapp/src/app/dataservices/shared/virtualization.model.spec.ts new file mode 100644 index 00000000..65570c92 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/virtualization.model.spec.ts @@ -0,0 +1,36 @@ +import { PublishState } from "@dataservices/shared/publish-state.enum"; +import { Virtualization } from "@dataservices/shared/virtualization.model"; + +describe("Virtualization", () => { + let virtualization: Virtualization; + + beforeEach(() => { + virtualization = null; + }); + + it("should create", () => { + console.log("========== [Virtualization] should create"); + virtualization = Virtualization.create( + { + "vdb_name": "acctsVdb", + "build_name": "acctsVdb-build-1", + "deployment_name": "acctsVdb-deployment-1", + "build_status": "RUNNING", /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ + "build_status_message": "Accounts VDB build was successful", + "namespace": "beetle-studio", + "last_updated": "2018-03-29T17:02:51.181Z", + "publishState": PublishState.PUBLISHED + } + ); + + expect(virtualization.getVdbName()).toEqual("acctsVdb"); + expect(virtualization.getBuildName()).toEqual("acctsVdb-build-1"); + expect(virtualization.getDeploymentName()).toEqual("acctsVdb-deployment-1"); + expect(virtualization.getBuildStatus()).toEqual("RUNNING"); + expect(virtualization.getBuildStatusMsg()).toEqual("Accounts VDB build was successful"); + expect(virtualization.getNamespace()).toEqual("beetle-studio"); + expect(virtualization.getLastUpdated()).toEqual("2018-03-29T17:02:51.181Z"); + expect(virtualization.getPublishState()).toEqual(PublishState.PUBLISHED); + }); + +}); From 59116678ee3a1c2ff56795493b7ecec2ee93f66c Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Thu, 26 Apr 2018 14:50:12 +0100 Subject: [PATCH 145/205] TEIIDTOOLS-419: Ports the odata query editor from DSB * package.json * Needs lodash because well its lodash! * x2js for parsing xml into json * dataservice-card * datasevice-list * Provides an odata icon to the card if a service is published allowing for opening the odata query editor. * dataservices-compoment * Show the odata editor * .../odata-control/... * Component UI for the odata editor * virt-route * Model for a virtualization's routes of the published service, eg. odata --- ngapp/package.json | 2 + ngapp/src/app/core/api.service.ts | 56 ++ .../dataservice-card.component.css | 10 + .../dataservice-card.component.html | 7 + .../dataservice-card.component.ts | 2 + .../dataservices-cards.component.ts | 4 + .../dataservices-list.component.css | 10 +- .../dataservices-list.component.html | 6 +- .../dataservices-list.component.ts | 23 +- .../dataservices/dataservices.component.html | 21 +- .../dataservices/dataservices.component.ts | 97 +++- .../app/dataservices/dataservices.module.ts | 11 +- .../odata-control/odata-column.model.ts | 67 +++ .../odata-control/odata-conditions.model.ts | 0 .../odata-control/odata-constants.ts | 67 +++ .../odata-control/odata-control.component.css | 186 +++++++ .../odata-control.component.html | 192 +++++++ .../odata-control.component.spec.ts | 68 +++ .../odata-control/odata-control.component.ts | 476 ++++++++++++++++ .../odata-control/odata-entity.model.ts | 54 ++ .../odata-control/odata-where.model.ts | 67 +++ .../dataservices/odata-control/odata.model.ts | 524 ++++++++++++++++++ .../dataservices/shared/dataservice.model.ts | 25 + .../shared/dataservice.service.ts | 50 ++ .../shared/dataservices-constants.ts | 2 + .../dataservices/shared/virt-route.model.ts | 113 ++++ .../shared/virtualization.model.ts | 29 + 27 files changed, 2150 insertions(+), 19 deletions(-) create mode 100644 ngapp/src/app/dataservices/odata-control/odata-column.model.ts create mode 100644 ngapp/src/app/dataservices/odata-control/odata-conditions.model.ts create mode 100644 ngapp/src/app/dataservices/odata-control/odata-constants.ts create mode 100644 ngapp/src/app/dataservices/odata-control/odata-control.component.css create mode 100644 ngapp/src/app/dataservices/odata-control/odata-control.component.html create mode 100644 ngapp/src/app/dataservices/odata-control/odata-control.component.spec.ts create mode 100644 ngapp/src/app/dataservices/odata-control/odata-control.component.ts create mode 100644 ngapp/src/app/dataservices/odata-control/odata-entity.model.ts create mode 100644 ngapp/src/app/dataservices/odata-control/odata-where.model.ts create mode 100644 ngapp/src/app/dataservices/odata-control/odata.model.ts create mode 100644 ngapp/src/app/dataservices/shared/virt-route.model.ts diff --git a/ngapp/package.json b/ngapp/package.json index 8845a141..542d3e9d 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -28,11 +28,13 @@ "core-js": "^2.5.3", "express": "^4.16.2", "file-saver": "1.3.3", + "lodash": "^4.17.10", "ng2-codemirror": "^1.1.3", "ngx-bootstrap": "^2.0.2", "patternfly": "^3.41.0", "patternfly-ng": "^3.1.2", "rxjs": "^5.5.6", + "x2js": "^3.2.1", "zone.js": "^0.8.20" }, "devDependencies": { diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index a941fb4a..a5b06f0a 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -23,6 +23,7 @@ import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; import { ErrorObservable } from "rxjs/observable/ErrorObservable"; +import * as X2JS from 'x2js'; export abstract class ApiService { @@ -59,6 +60,61 @@ export abstract class ApiService { return this.appSettings.getKomodoUserWorkspacePath(); } + protected isXML(xml: string): boolean { + try { + const parser = new X2JS(); + const xmlDoc = parser.xml2js(xml); //is valid XML + return xmlDoc != null; + } catch (err) { + // was not XML + return false; + } + } + + protected tryXMLParse(xml: string): any { + try { + const parser = new X2JS(); + const xmlDoc = parser.xml2js(xml); //is valid XML + return xmlDoc; + } catch (err) {} + + return null; + } + + protected tryNumberParse(jsonString: string): number { + try { + var n = parseInt(jsonString); + if (n && typeof n === "number") { + return n; + } + } catch (e) {} + + return null; + } + + /** + * Try to parse the given string and if parseable + * then return the object + */ + protected tryJsonParse (jsonString: string): any { + try { + var o = JSON.parse(jsonString); + + // Handle non-exception-throwing cases: + // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking, + // but... JSON.parse(null) returns null, and typeof null === "object", + // so we must check for that, too. Thankfully, null is falsey, so this suffices: + if (o && typeof o === "object") { + return o; + } + } catch (e) {} + + return null; + } + + /** + * @returns true if the item is parseable + */ protected isJSON(item: string): boolean { item = typeof item !== "string" ? JSON.stringify(item) : item; diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index 4841bb89..fd162f94 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -57,3 +57,13 @@ a.list-pf-title.view-name { display: flex; padding: 3px; } + +.odata-card-icon { + width: 16px; + height: 16px; + padding-left: 4px; + padding-right: 4px; + background-size: 16px 16px; + background-repeat: no-repeat; + background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALlJREFUeNpi/N/D4MDAwLCfgQLAAmc5TmBgEDPAVHFlAYTWScCUe3UBaH0BkiEgA2TsMRU+PgChsclBAeOod4aUd0CGsQtAbPn5gUTvgIAH0Ona8RD2z48MDDuAXrizgYHBqoGBwbIeU/eTgwwMKx3QvAMzAATY+SHhBDLk4wOIBmxhguISkBfQAZ88hL66AIJxACY4C2QbNucSARCGfAIasiMREhZg/kNw9BEDqJbYQKHjSIkhAAEGAHmtTMAm); +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index 58e08edc..2fc61dff 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -78,6 +78,13 @@ data-placement="right" title="Edit"> + + = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); @Output() public downloadDataservice: EventEmitter = new EventEmitter(); + @Output() public odataLookDataservice: EventEmitter = new EventEmitter(); public logger: LoggerService; @@ -77,6 +78,9 @@ export class DataservicesCardsComponent { case DataserviceCardComponent.downloadDataserviceEvent: this.downloadDataservice.emit ( event.dataserviceName ); break; + case DataserviceCardComponent.odataLookDataserviceEvent: + this.odataLookDataservice.emit( event.dataserviceName ); + break; default: this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); break; diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css index db294ebd..161e3a59 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css @@ -40,4 +40,12 @@ a.list-pf-title.view-name { margin-left: 10px; } - +.odata-list-icon { + width: 16px; + height: 16px; + padding-left: 8px; + padding-right: 8px; + background-size: 16px 16px; + background-repeat: no-repeat; + background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALlJREFUeNpi/N/D4MDAwLCfgQLAAmc5TmBgEDPAVHFlAYTWScCUe3UBaH0BkiEgA2TsMRU+PgChsclBAeOod4aUd0CGsQtAbPn5gUTvgIAH0Ona8RD2z48MDDuAXrizgYHBqoGBwbIeU/eTgwwMKx3QvAMzAATY+SHhBDLk4wOIBmxhguISkBfQAZ88hL66AIJxACY4C2QbNucSARCGfAIasiMREhZg/kNw9BEDqJbYQKHjSIkhAAEGAHmtTMAm); +} diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index 9d571159..27cf714b 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -83,7 +83,8 @@ activateActionTemplate, publishActionTemplate, downloadActionTemplate, - deleteActionTemplate )" + deleteActionTemplate, + odataLookActionTemplate )" (onActionSelect)="handleAction($event, item)">  {{ action.title }} @@ -106,6 +107,9 @@  {{ action.title }} + +   + diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts index 9b3a3099..ef177ec5 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts @@ -43,6 +43,7 @@ export class DataservicesListComponent implements OnInit { private static readonly publishActionId = "publish"; private static readonly downloadActionId = "download"; private static readonly testActionId = "test"; + private static readonly odataLookActionId = "odata-test"; public items: Dataservice[]; public listConfig: ListConfig; @@ -60,6 +61,7 @@ export class DataservicesListComponent implements OnInit { @Output() public deleteDataservice: EventEmitter = new EventEmitter(); @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); + @Output() public odataLookDataservice: EventEmitter = new EventEmitter(); public logger: LoggerService; @@ -82,6 +84,7 @@ export class DataservicesListComponent implements OnInit { * @param publishActionTemplate {TemplateRef} the publish action template * @param downloadActionTemplate {TemplateRef} the download action template * @param deleteActionTemplate {TemplateRef} the delete action template + * @param odataLookActionTemplate {TemplateRef} the odata preview action template * @returns {ActionConfig} the actions configuration */ public getActionConfig( ds: Dataservice, @@ -91,9 +94,17 @@ export class DataservicesListComponent implements OnInit { activateActionTemplate: TemplateRef< any >, publishActionTemplate: TemplateRef< any >, downloadActionTemplate: TemplateRef< any >, - deleteActionTemplate: TemplateRef< any > ): ActionConfig { + deleteActionTemplate: TemplateRef< any >, + odataLookActionTemplate: TemplateRef< any > ): ActionConfig { const actionConfig = { primaryActions: [ + { + visible: ds.servicePublished, + id: DataservicesListComponent.odataLookActionId, + template: odataLookActionTemplate, + title: "Odata Test", + tooltip: "Test the published virtualization" + }, { disabled: ds.serviceDeploymentLoading, id: DataservicesListComponent.editActionId, @@ -144,7 +155,8 @@ export class DataservicesListComponent implements OnInit { template: deleteActionTemplate, title: "Delete", tooltip: "Delete this data service" - } ], + } + ], } as ActionConfig; return actionConfig; @@ -219,6 +231,10 @@ export class DataservicesListComponent implements OnInit { this.quickLookDataservice.emit(dataserviceName); } + public onOdataLookDataservice( dataserviceName: string): void { + this.odataLookDataservice.emit(dataserviceName); + } + public handleAction($event: Action, item: any): void { switch ( $event.id ) { case DataservicesListComponent.activateActionId: @@ -242,6 +258,9 @@ export class DataservicesListComponent implements OnInit { case DataservicesListComponent.testActionId: this.onTestDataservice( item.getId() ); break; + case DataservicesListComponent.odataLookActionId: + this.onOdataLookDataservice( item.getId() ); + break; default: this.logger.error( "Unhandled event type of '" + $event.title + "'" ); break; diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index d9be7ea4..ac8f6f40 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -86,14 +86,16 @@

    (activateDataservice)="onActivate($event)" (testDataservice)="onTest($event)" (publishDataservice)="onPublish($event)" (deleteDataservice)="onDelete($event)" (editDataservice)="onEdit($event)" (quickLookDataservice)="onQuickLook($event)" - (downloadDataservice)="onDownload($event)" (dataserviceSelected)="onSelected($event)" - (dataserviceDeselected)="onDeselected($event)"> + (downloadDataservice)="onDownload($event)" (odataLookDataservice)="onOdataLook($event)" + (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)"> + + (downloadDataservice)="onDownload($event)" (odataLookDataservice)="onOdataLook($event)" + (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)"> +

    @@ -108,6 +110,17 @@

    +
    +
    +
    +
    + Odata Results for Published Virtualization Service '{{ odataServiceName }}' + +
    +
    + +
    +
    diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 6ba679f4..dabb4647 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -32,6 +32,7 @@ import { View } from "@dataservices/shared/view.model"; import { Virtualization } from "@dataservices/shared/virtualization.model"; import { WizardService } from "@dataservices/shared/wizard.service"; import { SqlControlComponent } from "@dataservices/sql-control/sql-control.component"; +import { OdataControlComponent } from "@dataservices/odata-control/odata-control.component"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; import { LayoutType } from "@shared/layout-type.enum"; @@ -82,7 +83,9 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn private cardListAreaCss = "dataservice-summary-top-area-no-results"; private resultsAreaCss = "dataservice-summary-bottom-area-no-results"; private resultsShowing = false; + private odataEditorShowing = false; private quickLookSvcName: string; + private odataSvcName: string; private quickLookQueryText: string; private allServices: Dataservice[] = []; @@ -260,6 +263,23 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn ); } + public setOdataEditorPanelOpenState(openState: boolean): void { + if (openState) { + this.cardListAreaCss = "dataservice-summary-top-area-with-results"; + this.resultsAreaCss = "dataservice-summary-bottom-area-with-results"; + + // + // Make the preview panel and odata panels mutually exclusive + // + this.resultsShowing = false; + this.odataEditorShowing = true; + } else { + this.cardListAreaCss = "dataservice-summary-top-area-no-results"; + this.resultsAreaCss = "dataservice-summary-bottom-area-no-results"; + this.odataEditorShowing = false; + } + } + /** * Sets the open state of the quick look panel * @param {boolean} openState true if quick look panel is to be shown @@ -268,6 +288,11 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn if (openState) { this.cardListAreaCss = "dataservice-summary-top-area-with-results"; this.resultsAreaCss = "dataservice-summary-bottom-area-with-results"; + + // + // Make the preview panel and odata panels mutually exclusive + // + this.odataEditorShowing = false; this.resultsShowing = true; } else { this.cardListAreaCss = "dataservice-summary-top-area-no-results"; @@ -276,6 +301,15 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } } + /** + * Closes both the quick look and odate editor panels + * if either of them are open + */ + public closeLookPanels(): void { + this.setQuickLookPanelOpenState(false); + this.setOdataEditorPanelOpenState(false); + } + /** * @returns {boolean} true if dataservice results panel is to be shown */ @@ -283,6 +317,13 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn return this.resultsShowing; } + /** + * @returns {boolean} true if dataservice odate editor panel is to be shown + */ + public get showOdataEditor(): boolean { + return this.odataEditorShowing; + } + /** * @returns {boolean} true if dataservice export notification is to be shown */ @@ -360,6 +401,13 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn return this.selectedSvcViews; } + /** + * @returns {string} the odata service name + */ + public get odataServiceName(): string { + return this.odataSvcName; + } + /** * @returns {string} the quick look service name */ @@ -394,7 +442,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); selectedService.setServiceDeploymentState(DeploymentState.LOADING); - this.setQuickLookPanelOpenState(false); + this.closeLookPanels(); const self = this; // Start the deployment and then redirect to the dataservice summary page @@ -417,7 +465,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.selectedSvcViews = []; this.selectedSvcViews.push(this.allServiceViews[0]); - this.setQuickLookPanelOpenState(false); + this.closeLookPanels(); const link: string[] = [ DataservicesConstants.testDataservicePath ]; this.logger.debug("[DataservicesPageComponent] Navigating to: %o", link); @@ -431,7 +479,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn * @param {string} svcName */ public onDownload(svcName: string): void { - this.setQuickLookPanelOpenState(false); + this.closeLookPanels(); this.exportNotificationHeader = this.exportInProgressHeader; this.exportNotificationMessage = "Downloading " + svcName + "..."; @@ -461,7 +509,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); const virtual: Virtualization = new Virtualization(selectedService.getServiceVdbName(), PublishState.PUBLISHING); selectedService.setServiceVirtualization(virtual); - this.setQuickLookPanelOpenState(false); + this.closeLookPanels(); this.exportNotificationHeader = this.exportInProgressHeader; this.exportNotificationMessage = "Publishing " + svcName + "..."; @@ -492,7 +540,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn * @param {string} svcName */ public onDelete(svcName: string): void { - this.setQuickLookPanelOpenState(false); + this.closeLookPanels(); this.dataserviceNameForDelete = svcName; @@ -534,7 +582,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); this.dataserviceService.setSelectedDataservice(selectedService); - this.setQuickLookPanelOpenState(false); + this.closeLookPanels(); // Sets the selected dataservice and edit mode before transferring this.wizardService.setSelectedDataservice(selectedService); @@ -563,15 +611,35 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.setQuickLookPanelOpenState(true); } this.setQuickLookResults(svcName); - this.sqlControlComponent.queryText = this.quickLookQueryText; - this.sqlControlComponent.submitCurrentQuery(); + + // + // Not available until opened + // + if (this.sqlControlComponent) { + this.sqlControlComponent.queryText = this.quickLookQueryText; + this.sqlControlComponent.submitCurrentQuery(); + } + } + + /* + * Handle showing the Odata QuickLook panel for the specified Dataservice + */ + public onOdataLook(svcName: string): void { + const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); + this.dataserviceService.setSelectedDataservice(selectedService); + + if (!this.odataEditorShowing) { + this.setOdataEditorPanelOpenState(true); + } + + this.setOdataServiceName(svcName); } /** * Set the layout to list type */ public setListLayout(): void { - this.setQuickLookPanelOpenState(false); + this.closeLookPanels(); this.appSettingsService.dataservicesPageLayout = LayoutType.LIST; } @@ -579,7 +647,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn * Set the layout to card type */ public setCardLayout(): void { - this.setQuickLookPanelOpenState(false); + this.closeLookPanels(); this.appSettingsService.dataservicesPageLayout = LayoutType.CARD; } @@ -749,4 +817,13 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.quickLookSvcName = svcName; } + /* + * Update odata editor using the supplied dataservice + * @param {string} svcName the dataservice name + */ + private setOdataServiceName(svcName): void { + this.odataSvcName = svcName; + } + + } diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 5baf3b65..a36aa588 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -49,7 +49,11 @@ import { DataserviceCardComponent } from "./dataservices-cards/dataservice-card/ import { SelectedNodeComponent } from "./selected-node/selected-node.component"; import { SelectedNodesListComponent } from "./selected-nodes-list/selected-nodes-list.component"; import { SqlControlComponent } from "./sql-control/sql-control.component"; +import { OdataControlComponent } from "./odata-control/odata-control.component"; import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.component"; +import { BsDropdownModule } from 'ngx-bootstrap'; +import { AccordionModule } from 'ngx-bootstrap'; +import { TooltipModule } from 'ngx-bootstrap'; @NgModule({ imports: [ @@ -62,7 +66,10 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co RouterModule, PatternFlyNgModule, CodemirrorModule, - TreeModule + TreeModule, + BsDropdownModule.forRoot(), + AccordionModule.forRoot(), + TooltipModule.forRoot() ], declarations: [ DataservicesDetailsComponent, @@ -75,6 +82,8 @@ import { TestDataserviceComponent } from "./test-dataservice/test-dataservice.co TestDataserviceComponent, SqlControlComponent, SelectedNodeComponent, + SelectedTableComponent, + OdataControlComponent, DataserviceCardComponent, ConnectionSchemaTreeComponent, SelectedNodesListComponent, diff --git a/ngapp/src/app/dataservices/odata-control/odata-column.model.ts b/ngapp/src/app/dataservices/odata-control/odata-column.model.ts new file mode 100644 index 00000000..8d4e0af4 --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata-column.model.ts @@ -0,0 +1,67 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class OdataColumn { + + private _name: string; + + private _type: string; + + private _sort: string; + + /** + * @returns name + */ + public get name(): string { + return this._name; + } + + /** + * Sets the name + */ + public set name(name: string) { + this._name = name; + } + + /** + * @returns type + */ + public get type(): string { + return this._type; + } + + /** + * Sets the type + */ + public set type(type: string) { + this._type = type; + } + + /** + * @returns sort + */ + public get sort(): string { + return this._sort; + } + + /** + * Sets the sort type + */ + public set sort(sort: string) { + this._sort = sort; + } +} diff --git a/ngapp/src/app/dataservices/odata-control/odata-conditions.model.ts b/ngapp/src/app/dataservices/odata-control/odata-conditions.model.ts new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/dataservices/odata-control/odata-constants.ts b/ngapp/src/app/dataservices/odata-control/odata-constants.ts new file mode 100644 index 00000000..8a95da5f --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata-constants.ts @@ -0,0 +1,67 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class OdataConstants { + + public readonly AscendingChoice = "Asc"; + public readonly columnPlaceholder = "column"; + public readonly Columns = "Columns"; + public readonly conditionPlaceholder = "condition"; + public readonly dataServiceDeploymentFailedMessage = "The Data Service failed to activate. Please correct the problem and retry"; + public readonly deployingDataService = "Deploying data service"; + public readonly DescendingChoice = "Desc"; + public readonly endpointNotAvailableMsg = "The endpoint is not available"; + public readonly enterQueryMsg = "Enter an SQL query to test the Data Service"; + public readonly failedDeploymentMsg = "The Data Service could not be deployed:"; + public readonly NoSortChoice = "No sort"; + public readonly OData = "OData"; + public readonly ODataEndpoint = "OData Endpoint: "; + public readonly resultLimitPlaceholder = "Select result limit..."; + public readonly resultsTabular = "Tabular"; + public readonly resultsRaw = "Raw"; + public readonly runningOdataQuery = "Running OData query..."; + public readonly runQueryAction = "Submit"; + public readonly Select = "Select"; + + public readonly selectResultLimitMsg = "Select the number of results to be initially returned"; + public readonly selectViewMsg = "Select the view to be queried"; + public readonly selectViewPlaceholder = "Select a view in the list..."; + public readonly SQL = "SQL"; + public readonly testingJdbcConnection = "Testing JDBC connection"; + public readonly urlPath = "Test URL"; + public readonly valuePlaceholder = "value"; + public readonly Where = "Where"; + public readonly OrderBy = "Order By"; + + public readonly noResultsColumnName = "Err: No Data!"; + public readonly noResultsMsg = "No data was returned from the query"; + public readonly resultCountMsg = "The total number of results returned by the query is "; + public readonly searchErrorColumnName = "Err: Failed!"; + public readonly searchErrorConsoleMsg = "Error: Failed to get value at link: "; + public readonly searchErrorMsg = "Error: failed to get any results: "; + public readonly whereErrorMsg = "The chosen column has a type which cannot be used in a where condition"; + public readonly metadataFetchFailure = "Failed to get the odata metadata for the published artifact." + + public readonly help_endpointSubmit = "This URL is formed using the OData specification. It can be copied into a new browser window to return the results in xml format or append ?format=json to the URL for JSON. Click the Submit button to display the results in a formatted table."; + public readonly help_select = "Choose the view from which results should be sought. Select a limit to curtail the number of results returned "; + public readonly help_columns = "Select the columns to be included in the results."; + public readonly help_where = "Create where clauses for filtering the results based on the values in each tuple. Use the + button to add new where clauses (clauses are and-ed together) and remove them with the - buttons."; + public readonly help_orderBy = "Sort the results by column in ascending or descending order."; + public readonly help_resultsTable = "Use the column headers to sort the results or filter them by entering values. Results are paginated in blocks of 25 and can be scrolled through with the controls at the foot of the table."; + public readonly help_resultsRaw = "The raw data as returned from the odata teiid service in json format."; + public readonly help_sqlSearch = "Use the Teiid dialect of SQL to construct a query that interrogates the data service for data results. Use the record limit to limit the number of results returned. Set the starting record index to fetch a subset of results starting at the given row index."; +} diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.css b/ngapp/src/app/dataservices/odata-control/odata-control.component.css new file mode 100644 index 00000000..770d6363 --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.css @@ -0,0 +1,186 @@ +.help-label { + color: #0088ce; + padding-left: 0.5em; + padding-right: 0.5em; +} + +.custom-tooltip { + width: 20em; +} + +.custom-tooltip .tooltip-inner { + background: transparent linear-gradient(to top, #ececec 50%, #d1d1d1 100%) repeat scroll 0% 0%; + color: black; + font-style: oblique; +} + +.custom-tooltip .tooltip-arrow { + background-color: #ececec; +} + +.odata-editor { + font-weight: bold; + margin-top: 1em; +} + +#odata-endpoint-url { + font-weight: bold; + padding-right: 0.25em; + margin-bottom: 1em; +} + +#odata-endpoint-url label { + font-weight: bold; + padding-left: 0; + padding-right: 1em; + width: auto; +} + +#odata-endpoint-url input { + background: #ededed; + background: -webkit-linear-gradient(white, #ededed); + background: -o-linear-gradient(white, #ededed); + background: -moz-linear-gradient(white, #ededed); + background: linear-gradient(white, #ededed); +} + +#odata-query-button { + float: left; + width: 10%; + margin-left: 5em; +} + +#odata-control-panel { + clear: both; +} + +.odata-control-panel-title { + font-weight: bold; + display: inline-block; + margin-right: 0.5em; +} + +.odata-control-panel-title-help { + margin-right: 1em; + margin-top: 0.15em; + font-size: 12px; +} + +.odata-controls .panel-title { + font-weight: bold; + height: 1em; +} + +.odata-exp-column-group { + margin-bottom: 0; + padding-left: 0; +} + +.odata-exp-column-group-row { + margin-top: 0; + margin-bottom: 0; +} + +.odata-exp-select-group, +.odata-exp-column-group-row label, +.odata-exp-where-group-row, +.odata-exp-order-by-group-row, +.odata-exp-order-by-group-row label, +.odata-exp-order-by-group-row-label label { + font-weight: bold; +} + +.odata-exp-where-group-row { + padding-top: 0.25em; + padding-left: 0.25em !important; + padding-right: 0.25em !important; +} + +.odata-exp-where-group .ui-select-toggle, +.odata-exp-select-group .ui-select-toggle { + background-color: white; + background-image: -webkit-linear-gradient(top, #ffffff 0%, #ffffff 100%); + background-image: -o-linear-gradient(top, #ffffff 0%, #ffffff 100%); + background-image: linear-gradient(to bottom, #ffffff 0%, #ffffff 100%); +} + +#odata-exp-where-group-buttons button { + padding-left: 5%; + padding-right: 1%; +} + +.odata-form-control { + color: #000000; + background-color: #FFFFFB; + border: 2px outset #FCFFFF; + font-weight: bold; + width: 100%; +} + +.odata-exp-order-by-group-row-label { + padding-left: 0; + width: 30%; + word-wrap: break-word; +} + +.odata-form-where-add-btn { + background-color: transparent; + border: none; + color: black; +} + +.odata-form-where-remove-btn { + background-color: transparent; + border: none; + color: red; +} + +.odata-exp-where-error-msg { + color: red; + font-style: italic; + font-weight: bold; +} + +#odata-results-type { + float: right; + margin-bottom: 0.5em; +} + +#odata-results-table { + clear: both; + padding-left: 0; + padding-right: 0; + padding-bottom: 2em; + position: relative; +} + +.odata-results-table-grid { + font-weight: lighter; +} + +#odata-search-progress-spinner { + font-style: italic; + text-align: center; + margin-top: 10em; +} + +.odata-results-msg-error { + color: red; + font-style: italic; + font-weight: bold; + padding-left: 7em; +} + +.odata-results-msg-info { + color: green; + font-style: italic; + font-weight: bold; + padding-left: 7em; +} + +#odata-metadata-fetch-failure { + color: red; + font-style: italic; + font-weight: bold; + padding-left: 7em; +} diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.html b/ngapp/src/app/dataservices/odata-control/odata-control.component.html new file mode 100644 index 00000000..a870a856 --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.html @@ -0,0 +1,192 @@ +
    +
    +
    + + + +
    + +
    + +
    +
    + +
    + + + + + + + +
    +
    {{i18n.Select}}
    +
    + +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + +
    + + + + + + +
    +
    {{i18n.Columns}}
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    + + + + + + +
    +
    {{i18n.Where}}
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    + +
    + + +
    + +
    + {{where.error}} +
    +
    + +
    + + + + + + +
    +
    {{i18n.OrderBy}}
    +
    + +
    +
    +
    +
    +
    +
    + +
    + + + +
    +
    + +
    +
    +
    + +
    +
    + + +
    +
    + +
    +

    {{searchMsg}}

    +
    + + +
    +
    + {{i18n.runningOdataQuery}} +
    + +
    +

    {{i18n.metadataFetchFailure}}

    +
    +
    diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.spec.ts b/ngapp/src/app/dataservices/odata-control/odata-control.component.spec.ts new file mode 100644 index 00000000..f51ecfa7 --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.spec.ts @@ -0,0 +1,68 @@ +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; + +import { FormsModule } from "@angular/forms"; +import { HttpModule } from "@angular/http"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { View } from "@dataservices/shared/view.model"; +import { CodemirrorModule } from "ng2-codemirror"; +import { PatternFlyNgModule } from "patternfly-ng"; +import { SqlControlComponent } from "./sql-control.component"; + +describe("SqlControlComponent", () => { + let component: SqlControlComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ FormsModule, HttpModule, CodemirrorModule, PatternFlyNgModule ], + declarations: [ SqlControlComponent ], + providers: [ + AppSettingsService, + LoggerService, + NotifierService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: DataserviceService, useClass: MockDataserviceService }, + { provide: VdbService, useClass: MockVdbService } + ] + }) + .compileComponents().then(() => { + // nothing to do + }); + })); + + beforeEach(() => { + // select a dataservice before constructing component + const service = TestBed.get( DataserviceService ); + let dataservices: Dataservice[]; + service.getAllDataservices().subscribe( ( values ) => { dataservices = values; } ); + // noinspection JSUnusedAssignment + service.setSelectedDataservice( dataservices[ 0 ] ); + + fixture = TestBed.createComponent(SqlControlComponent); + component = fixture.componentInstance; + + // Set the inputs for the component + component.viewSql = "SELECT * FROM views.View1"; + const view = new View(); + view.setName("views.View1"); + const views: View[] = []; + views.push(view); + component.serviceViews = views; + component.selectedViews = views; + + fixture.detectChanges(); + }); + + it("should be created", () => { + console.log("========== [SqlControlComponent] should be created"); + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.ts b/ngapp/src/app/dataservices/odata-control/odata-control.component.ts new file mode 100644 index 00000000..74ba9448 --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.ts @@ -0,0 +1,476 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Input, ViewEncapsulation } from "@angular/core"; +import { Component, OnChanges, SimpleChanges } from "@angular/core"; +import { LoggerService } from "@core/logger.service"; +import { TableConfig, PaginationConfig, PaginationEvent } from "patternfly-ng"; +import * as _ from "lodash"; +import { ColumnData } from "@dataservices/shared/column-data.model"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { OdataConstants } from "@dataservices/odata-control/odata-constants"; +import { Odata } from "@dataservices/odata-control/odata.model"; +import { OdataEntity } from "@dataservices/odata-control/odata-entity.model"; +import { OdataColumn } from "@dataservices/odata-control/odata-column.model"; +import { OdataWhere } from "@dataservices/odata-control/odata-where.model"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: "app-odata-control", + templateUrl: "./odata-control.component.html", + styleUrls: ["./odata-control.component.css"] +}) +export class OdataControlComponent implements OnChanges { + + @Input() dataserviceName: string; + + private dataserviceService: DataserviceService; + private dataservice: Dataservice; + private logger: LoggerService; + public i18n: OdataConstants = new OdataConstants(); + + public searchMsg: string; + public searchMsgClasses: string[]; + public searchInProgress: boolean; + public showResultsTable: boolean; + public rawResultRows: object; + + private odata: Odata; + + // + // Raw data rows retrieved from the query + // + public rawRows: any[]; + + public resultTableConfig: TableConfig; + public paginationConfig: PaginationConfig; + public resultColumns: any[]; + public resultRows: any[] ; + + constructor( dataserviceService: DataserviceService, logger: LoggerService ) { + this.dataserviceService = dataserviceService; + this.logger = logger; + } + + public get rootUrl(): string { + return this.dataservice.getOdataRootUrl() + '/' + this.dataservice.getServiceViewModel(); + } + + public ngOnChanges(changes: SimpleChanges): void { + this.dataservice = this.dataserviceService.getSelectedDataservice(); + + this.searchMsg = null; + this.searchMsgClasses = []; + this.searchInProgress = false; + this.showResultsTable = false; + this.rawResultRows = null; + this.odata = new Odata(); + + this.paginationConfig = { + pageNumber: 1, + pageSize: 10, + pageSizeIncrements: [5, 10, 15, 20, 25, 50] + } as PaginationConfig; + + this.resultTableConfig = { + paginationConfig: this.paginationConfig, + } as TableConfig; + + this.rawRows = []; + this.resultColumns = []; + this.resultRows = []; + + const url = this.rootUrl + '/$metadata'; + + this.dataserviceService.odataGet(url) + .subscribe( + (response) => { + if (! _.isEmpty(response)) { + this.odata.metadata = response; + this.odata.metadataFailure = false; + } else { + this.odata.metadata = ''; + this.odata.metadataFailure = true; + } + }, + (error) => { + this.odata.metadataFailure = true; + console.error('Failed to get odata metadata ' + error); + } + ); + } + + /** + * The odata endpoint url constructed from the parameters + */ + public get endPointUrl(): string { + if (this.odata.metadataFailure) + return 'Not available'; + + if (_.isEmpty(this.odata.metadata)) + return 'Not available'; + + const baseUrl = this.rootUrl; + + if (_.isEmpty(baseUrl)) + return 'Not Available'; + + const service = this.odata.entity; + if (_.isEmpty(service) || _.isEmpty(service.name)) + return 'Not Available'; + + let odataUrl = baseUrl + '/' + service.name; + + const limit = this.odata.convertLimit(); + if (! _.isEmpty(limit)) + odataUrl = odataUrl + limit; + + const where = this.odata.convertWhere(); + if (! _.isEmpty(where)) + odataUrl = odataUrl + where; + + const columns = this.odata.convertColumns(); + if (! _.isEmpty(columns)) + odataUrl = odataUrl + columns; + + const orderBy = this.odata.convertOrderBy(); + if (! _.isEmpty(orderBy)) + odataUrl = odataUrl + orderBy; + + if (odataUrl.endsWith('&') || odataUrl.endsWith('?')) + odataUrl = odataUrl.substring(0, odataUrl.length - 1); + + return odataUrl; + } + + /** + * @returns true if the odata control widgets + * should be displayed. + */ + public get hasOdataAttributes(): boolean { + return ! _.isEmpty(this.odata.metadata); + } + + /** + * Can the query be enacted + * @returns {boolean} true if good to go, false otherwise + */ + public get canQuery(): boolean { + return !_.isEmpty(this.odata.metadata) && !_.isEmpty(this.odata.entity); + } + + /** + * @returns {OdataEntity[]} the available entities + */ + public get entities(): OdataEntity[] { + if (_.isEmpty(this.odata.entities)) + return []; + + return this.odata.entities; + } + + /** + * @returns {OdataEntity} the selected entitie + */ + public get entity(): OdataEntity { + if (_.isEmpty(this.odata.entity)) + return null; + + return this.odata.entity; + } + + /** + * Set the selected entity + */ + public set entity(entity: OdataEntity) { + this.odata.entity = entity; + } + + /** + * @returns {string[]} the available limit options + */ + public get limits(): string[] { + return Odata.LIMITS; + } + + /** + * @returns {string} the selected limit + */ + public get limit(): string { + if (_.isEmpty(this.odata.limit)) + return ''; + + return this.odata.limit; + } + + /** + * Set the selected limit + */ + public set limit(limit: string) { + this.odata.limit = limit; + } + + /** + * Return the available columns for the selected entity + */ + public get columns(): OdataColumn[] { + if (_.isEmpty(this.odata.entity) || _.isEmpty(this.odata.entity.columns)) { + return []; + } + + return this.odata.entity.columns; + } + + /** + * Return the selected columns + */ + public get selectedColumns(): OdataColumn[] { + return this.odata.columns; + } + + /** + * Used by column checkboxes to determine if a checkbox + * should be checked. + */ + public isColumnSelected(columnName: string): boolean { + return this.odata.hasColumn(columnName); + } + + /** + * Updates the column selection when its checkbox has been (un)checked + */ + public updateColumnSelection(checked: boolean, column: OdataColumn): void { + if (checked) { + this.odata.addColumn(column); + } + else { + this.odata.removeColumn(column); + } + } + + /** + * Return the available wheres + */ + public get wheres(): OdataWhere[] { + return this.odata.wheres; + } + + /** + * On changing the where column selection: + * * Remove the where condition since it may be invalid + * * Check the column is queryable and if not display an error + */ + public onWhereColumnSelected(where: OdataWhere) { + if (! _.isEmpty(where) && ! _.isEmpty(where.condition)) + delete where.condition; + + if (! _.isEmpty(where.column)) { + let index = _.indexOf(Odata.QUERYABLE_TYPES, where.column.type); + if (index < 0) + where.error = this.i18n.whereErrorMsg; + else + where.error = null; + } + } + + /** + * Event handler for adding a where condition + */ + public onAddWhereClicked(): void { + try { + const newWhere: OdataWhere = new OdataWhere(); + this.odata.addWhere(newWhere); + } catch (error) { + // nothing to do + } + } + + /** + * Event handler for removing a where condition + */ + public onRemoveWhereClicked(where): void { + try { + if (_.isEmpty(where)) + return; + + this.odata.removeWhere(where); + + if (this.odata.wheres.length === 0) { + // + // Always keep 1 empty clause so preserve buttons + // + const newWhere: OdataWhere = new OdataWhere(); + this.odata.addWhere(newWhere); + } + + } catch (error) { + // nothing to do + } + } + + /** + * Provides the choices to select for a where clause + * depending on the type of column already selected + */ + public whereConditions(where: OdataWhere) { + if (_.isEmpty(where) || _.isEmpty(where.column)) + return []; + + const index = _.indexOf(Odata.QUERYABLE_TYPES, where.column.type); + if (index < 0) + return []; + else if (index === 0) // Boolean + return this.odata.booleanConditions(); + else if (index === 1) // String + return this.odata.stringConditions(); + else if (index <= 11) // number + return this.odata.intConditions(); + else if (index > 11) // DateTime + return this.odata.dateConditions(); + else + return []; + } + + private tableTitle(value: string): string { + if (_.isEmpty(value)) + return value; + + return _.startCase(value); + } + + /** + * Submit the query for evaluation + */ + public submitQuery(): void { + let url = this.endPointUrl; + + if (this.odata.limit !== Odata.COUNT_ONLY) { + // + // Json format cannot be used with $count + // + if (url.indexOf('?') > -1) + // Already have parameters + url = url + '&'; + else + url = url + '?'; + + url = url + "$format=json"; + } + + this.rawResultRows = null; + this.resultColumns = []; + this.resultRows = []; + this.rawRows = []; + this.searchMsg = null; + this.searchMsgClasses = []; + this.searchInProgress = true; + this.showResultsTable = false; + + this.dataserviceService.odataGet(url) + .subscribe( + (response) => { + this.showResultsTable = false; + this.rawResultRows = null; + + // Remove the search progress spinner + this.searchInProgress = false; + + if (response.error) { + this.searchMsgClasses = ['odata-results-msg-error']; + this.searchMsg = this.i18n.searchErrorMsg + response.error; + return; + } + + if (response.count) { + // + // Handles the count function by returning a + // + this.searchMsgClasses = ['odata-results-msg-info']; + this.searchMsg = this.i18n.resultCountMsg + response.count; + return; + } + + if (_.isEmpty(response.value)) { + this.searchMsgClasses = ['odata-results-msg-info']; + this.searchMsg = this.i18n.noResultsMsg; + return; + } + + if (this.selectedColumns.length === 0) { + // + // No columns selected so choose all available + // + let resultCols = this.columns; + for (let i = 0; i < this.columns.length; ++i) { + const label = this.columns[i].name; + const col = { canAutoResize: true, + draggable: false, + name: this.tableTitle(label), + prop: label, + resizable: true, + sortable: true }; + this.resultColumns.push(col); + } + } else { + for (var j = 0; j < this.selectedColumns.length; ++j) { + const label = this.selectedColumns[j].name; + const col = { canAutoResize: true, + draggable: false, + name: label.toUpperCase(), + prop: label, + resizable: true, + sortable: true }; + this.resultColumns.push(col); + } + } + + for (let rowIndex = 0; rowIndex < response.value.length; rowIndex++) { + const row = response.value[rowIndex]; + this.rawRows.push(row); + } + + this.updateRows(); + this.showResultsTable = true; + }, + (error) => { + this.showResultsTable = false; + this.searchInProgress = false; + this.searchMsgClasses = ['odata-results-msg-error']; + this.searchMsg = 'Failed to get odata results ' + error; + } + ); + } + + // Pagination + handlePageSize($event: PaginationEvent): void { + this.updateRows(); + } + + handlePageNumber($event: PaginationEvent): void { + this.updateRows(); + } + + updateRows(): void { + this.paginationConfig.totalItems = this.rawRows.length; + + this.resultRows = this.rawRows + .slice( + (this.paginationConfig.pageNumber - 1) * this.paginationConfig.pageSize, this.paginationConfig.totalItems) + .slice(0, this.paginationConfig.pageSize); + } +} diff --git a/ngapp/src/app/dataservices/odata-control/odata-entity.model.ts b/ngapp/src/app/dataservices/odata-control/odata-entity.model.ts new file mode 100644 index 00000000..7ea96bb9 --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata-entity.model.ts @@ -0,0 +1,54 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OdataColumn } from "@dataservices/odata-control/odata-column.model"; + +export class OdataEntity { + + private _name: string; + + /* The available columns for the entity */ + private _columns: Array = []; + + /** + * @returns name + */ + public get name(): string { + return this._name; + } + + /** + * Sets the name + */ + public set name(name: string) { + this._name = name; + } + + /** + * @returns columns + */ + public get columns(): OdataColumn[] { + return this._columns; + } + + /** + * Sets the columns + */ + public set columns(columns: OdataColumn[]) { + this._columns = columns; + } +} diff --git a/ngapp/src/app/dataservices/odata-control/odata-where.model.ts b/ngapp/src/app/dataservices/odata-control/odata-where.model.ts new file mode 100644 index 00000000..e5854cf1 --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata-where.model.ts @@ -0,0 +1,67 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OdataColumn } from "@dataservices/odata-control/odata-column.model"; + + /* + *Will contain: + * column + * condition ( one of odata.conditions ) + * value + */ +export class OdataWhere { + + private _column: OdataColumn; + private _condition: string = ''; + private _value: string = ''; + + public error: string = null; + + /** + * @returns column + */ + public get column(): OdataColumn { + return this._column; + } + + public set column(column: OdataColumn) { + this._column = column; + } + + /** + * @returns the condition + */ + public get condition(): string { + return this._condition; + } + + public set condition(condition: string) { + this._condition = condition; + } + + /** + * @returns value + */ + public get value(): string { + return this._value; + } + + public set value(value: string) { + this._value = value; + } + +} diff --git a/ngapp/src/app/dataservices/odata-control/odata.model.ts b/ngapp/src/app/dataservices/odata-control/odata.model.ts new file mode 100644 index 00000000..e4f82680 --- /dev/null +++ b/ngapp/src/app/dataservices/odata-control/odata.model.ts @@ -0,0 +1,524 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as _ from "lodash"; +import { OdataEntity } from "@dataservices/odata-control/odata-entity.model"; +import { OdataColumn } from "@dataservices/odata-control/odata-column.model"; +import { OdataWhere } from "@dataservices/odata-control/odata-where.model"; + +export class Odata { + + public static readonly EQUALS = 'equals'; + public static readonly NOT_EQUALS = 'not equals'; + public static readonly GREATER_THAN = 'greater than'; + public static readonly GREATER_THAN_EQ_TO = 'greater than or equal to'; + public static readonly LESS_THAN = 'less than'; + public static readonly LESS_THAN_EQ_TO = 'less than or equal to'; + public static readonly IN = 'in'; + public static readonly EQUALS_CINS = 'equals (case insensitive)'; + public static readonly NOT_EQUALS_CINS = 'not equals (case insensitive)'; + public static readonly STARTS_WITH = 'starts with'; + public static readonly NO_STARTS_WITH = 'not starts with'; + public static readonly ENDS_WITH = 'ends with'; + public static readonly NO_ENDS_WITH = 'not ends with'; + public static readonly CONTAINS = 'contains'; + public static readonly LENGTH_EQ = 'length equals'; + public static readonly BEFORE_DATE = 'before date'; + public static readonly AFTER_DATE = 'after date'; + public static readonly BEFORE_EQ = 'before or equals'; + public static readonly AFTER_EQ = 'after or equals'; + + public static readonly NO_LIMIT = 'no limit'; + public static readonly COUNT_ONLY = 'count only'; + public static readonly TOP_1 = 'top 1'; + public static readonly TOP_10 = 'top 10'; + public static readonly TOP_50 = 'top 50'; + public static readonly TOP_100 = 'top 100'; + public static readonly TOP_1000 = 'top 1000'; + public static readonly TOP_10000 = 'top 10000'; + + public static readonly QUERYABLE_TYPES: Array = ['Boolean', 'String', 'Byte', 'Decimal', 'Double', 'Single', 'Float', 'Guid', + 'Int16', 'Int32', 'Int64', 'SByte', 'DateTime', 'Time', 'DateTimeOffset']; + + public static readonly LIMITS: Array = [ + Odata.NO_LIMIT, + Odata.COUNT_ONLY, + Odata.TOP_1, + Odata.TOP_10, + Odata.TOP_50, + Odata.TOP_100, + Odata.TOP_1000, + Odata.TOP_10000 + ]; + + private _metadata: any = null; + + private _metadataFailure: boolean = false; + + private _entities: Array = []; + + /* The entity for the select component */ + private _entity: OdataEntity = new OdataEntity(); + + /* Will contain the selected columns */ + private _columns: Array = []; + + /* Where clauses for query criteria */ + private _wheres: Array = []; + + /* The limit of the query results */ + private _limit: string = Odata.NO_LIMIT; + + constructor() { + const newWhere: OdataWhere = new OdataWhere(); + this.addWhere(newWhere); + } + + /** + * @returns collection of conditions for int types + */ + public intConditions(): string[] { + const conditions:Array = [ Odata.EQUALS, Odata.NOT_EQUALS, Odata.GREATER_THAN, + Odata.GREATER_THAN_EQ_TO, Odata.LESS_THAN, Odata.LESS_THAN_EQ_TO, + Odata.IN ]; + return conditions; + } + + /** + * @returns collection of conditions for string types + */ + public stringConditions(): string[] { + const conditions:Array = [ Odata.EQUALS, Odata.NOT_EQUALS, Odata.IN, Odata.EQUALS_CINS, Odata.NOT_EQUALS_CINS, + Odata.STARTS_WITH, Odata.NO_STARTS_WITH, Odata.ENDS_WITH, Odata.NO_ENDS_WITH, + Odata.CONTAINS, Odata.LENGTH_EQ ]; + return conditions; + } + + /** + * @returns collection of conditions for date types + */ + public dateConditions(): string[] { + const conditions:Array = [ Odata.EQUALS, Odata.BEFORE_DATE, Odata.AFTER_DATE, Odata.BEFORE_EQ, Odata.AFTER_EQ ]; + return conditions; + } + + /** + * @returns collection of conditions for boolean types + */ + public booleanConditions(): string[] { + const conditions:Array = [ Odata.EQUALS, Odata.NOT_EQUALS ]; + return conditions; + } + + /** + * @returns metadata + */ + public get metadata(): any { + return this._metadata; + } + + /** + * Extract the available columns from the entity + * located in the $metadata xml/json + */ + private extractColumns(entity: any): OdataColumn[] { + let odataColumns = []; + if (_.isEmpty(entity.Property)) + return odataColumns; + + const columns = entity.Property; + if (_.isArray(columns)) { + for (let column of columns) { + let odataColumn = new OdataColumn(); + odataColumn.name = column._Name; + odataColumn.type = column._Type.replace('Edm.', ''); + odataColumns.push(odataColumn); + } + } else if (_.isObject(columns)) { + let singleColumn = new OdataColumn(); + singleColumn.name = columns._Name; + singleColumn.type = columns._Type.replace('Edm.', ''); + odataColumns = [singleColumn]; + } + + return odataColumns; + } + + /** + * sets the metadata + */ + public set metadata(metadata: any) { + if (_.isEqual(this._metadata, metadata)) + return; + + this._metadata = metadata; + + // + // Reset the entity + // + this.entity = null; + this._entities = []; + + if (_.isEmpty(metadata) || _.isEmpty(metadata.Edmx) || + _.isEmpty(metadata.Edmx.DataServices) || _.isEmpty(metadata.Edmx.DataServices.Schema) || + _.isEmpty(metadata.Edmx.DataServices.Schema.EntityType)) { + return; + } + + const entityTypes = metadata.Edmx.DataServices.Schema.EntityType; + if (_.isArray(entityTypes)) { + for (let entityType of entityTypes) { + let entity = new OdataEntity(); + entity.name = entityType._Name; + entity.columns = this.extractColumns(entityType); + this._entities.push(entity); + } + } else if (_.isObject(entityTypes)) { + let singleEntity = new OdataEntity(); + singleEntity.name = entityTypes._Name; + singleEntity.columns = this.extractColumns(entityTypes); + this._entities = [singleEntity]; + } + + if (! _.isEmpty(this._entities)) { + this._entity = this._entities[0]; + } + } + + /** + * @returns metadata failure flag + */ + public get metadataFailure(): boolean { + return this._metadataFailure; + } + + /** + * sets the metadata failure flag + */ + public set metadataFailure(metadataFailure: boolean) { + this._metadataFailure = metadataFailure; + } + + /** + * @returns entity + */ + public get entity(): OdataEntity { + return this._entity; + } + + /** + * Sets the entity + */ + public set entity(entity: OdataEntity) { + this._entity = entity; + } + + /** + * @returns entities + */ + public get entities(): OdataEntity[] { + if (_.isEmpty(this._entities)) + return []; + + return this._entities; + } + + /** + * @returns limit + */ + public get limit(): string { + return this._limit; + } + + /** + * Sets the limit + */ + public set limit(limit: string) { + this._limit = limit; + } + + /** + * @returns the selected columns + */ + public get columns(): OdataColumn[] { + return this._columns; + } + + /** + * Is this column with name selected + */ + public hasColumn(columnName: string): boolean { + for (let column of this.columns) { + if (_.isEqual(columnName, column.name)) + return true; + } + + return false; + } + + /** + * Add a column + */ + public addColumn(column: OdataColumn): void { + if (this.hasColumn(column.name)) + return; // already selected + + this._columns.push(column); + } + + /** + * Remove a column + */ + public removeColumn(column: OdataColumn): void { + if (! this.hasColumn(column.name)) + return; // not present + + const index = this._columns.indexOf(column); + if (index > -1) { + this._columns.splice(index, 1); + } + } + + /** + * @returns available where clauses + */ + public get wheres(): OdataWhere[] { + if (_.isEmpty(this._wheres)) + return []; + + return this._wheres; + } + + /** + * @returns true if there are where clauses defined + */ + public get hasWhere(): boolean { + return this._wheres.length > 0; + } + + /** + * Add a where + */ + public addWhere(where: OdataWhere): void { + this._wheres.push(where); + } + + /** + * Remove a where + */ + public removeWhere(where: OdataWhere): void { + const index = this._wheres.indexOf(where); + if (index > -1) { + this._wheres.splice(index, 1); + } + } + + /** + * Converts the limit value into the odata limit clause + */ + public convertLimit(): string { + if (_.isEmpty(this.limit)) + return ''; + + if (Odata.LIMITS[0] === this.limit) + return '?'; // no limit + + if (Odata.LIMITS[1] === this.limit) + return '/$count?'; // count + + return this.limit.replace('top ', '?$top=') + '&'; + } + + /** + * Converts the where clauses into odata where clauses + */ + public convertWhere(): string { + if (this._wheres.length == 0) + return ''; + + const SPACE = ' '; + const OBKT = '('; + const CBKT = ')'; + const QUOTE = "'"; + const COMMA = ','; + + let prefix = '$filter='; + let clauses = ''; + + for (var i = 0; i < this._wheres.length; ++i) { + const where = this._wheres[i]; + const column: OdataColumn = where.column; + const condition: string = where.condition; + const value: string = where.value; + + if (! column || ! value) + continue; // ignore incomplete where clauses + + if (clauses.length > 0 && i > 0) + clauses = clauses + SPACE + 'and' + SPACE; + + let clause = ''; + if (condition === Odata.EQUALS) + clause = column.name + SPACE + 'eq' + SPACE + QUOTE + value + QUOTE; + else if (condition === Odata.NOT_EQUALS) + clause = column.name + SPACE + 'ne' + SPACE + QUOTE + value + QUOTE; + else if (condition === Odata.GREATER_THAN || condition === Odata.AFTER_DATE) + clause = column.name + SPACE + 'gt' + SPACE + QUOTE + value + QUOTE; + else if (condition === Odata.GREATER_THAN_EQ_TO || condition === Odata.BEFORE_EQ) + clause = column.name + SPACE + 'ge' + SPACE + QUOTE + value + QUOTE; + else if (condition === Odata.LESS_THAN || condition === Odata.BEFORE_DATE) + clause = column.name + SPACE + 'lt' + SPACE + QUOTE + value + QUOTE; + else if (condition === Odata.LESS_THAN_EQ_TO || condition === Odata.AFTER_EQ) + clause = column.name + SPACE + 'le' + SPACE + QUOTE + value + QUOTE; + else if (condition === Odata.EQUALS_CINS) { + // + // tolower(Description) eq tolower('value') + // + clause = 'tolower' + OBKT + column + CBKT + + SPACE + 'eq' + SPACE + + 'tolower' + OBKT + QUOTE + value + QUOTE + CBKT; + } else if (condition === Odata.NOT_EQUALS_CINS) { + // + // tolower(Description) ne tolower('value') + // + clause = 'tolower' + OBKT + column + CBKT + SPACE + 'ne' + SPACE + + 'tolower' + OBKT + QUOTE + value + QUOTE + CBKT; + } else if (condition === Odata.STARTS_WITH) { + // + // startswith(Description, 'value') + // + clause = 'startswith' + OBKT + column.name + COMMA + QUOTE + value + QUOTE + CBKT; + } + else if (condition === Odata.NO_STARTS_WITH) { + // + // not startswith(Description, 'value') + // + clause = 'not startswith' + OBKT + column.name + COMMA + QUOTE + value + QUOTE + CBKT; + } + else if (condition === Odata.ENDS_WITH) { + // + // endswith(Description, 'value') + // + clause = 'endswith' + OBKT + column.name + COMMA + QUOTE + value + QUOTE + CBKT; + } + else if (condition === Odata.NO_ENDS_WITH) { + // + // not endswith(Description, 'value') + // + clause = 'not endswith' + OBKT + column.name + COMMA + QUOTE + value + QUOTE + CBKT; + } + else if (condition === Odata.CONTAINS) { + // + // contains(Description, 'value') + // + clause = 'contains' + OBKT + column.name + COMMA + QUOTE + value + QUOTE + CBKT; + } + else if (condition === Odata.LENGTH_EQ) { + // + // length(Description) eq 5 + // + clause = 'length' + OBKT + column.name + CBKT + SPACE + 'eq' + SPACE + value; + } else if (condition === Odata.IN) { + // + // in separated by ;, eg. 1;2 + // becomes + // (ID eq 1 or ID eq 2) + // + clause = OBKT; + const values = value.split(';'); + for (let j = 0; j < values.length; ++j) { + if (j > 0) + clause = clause + SPACE + 'or' + SPACE; + + clause = clause + column.name + SPACE + 'eq' + SPACE + values[j]; + } + clause = clause + CBKT; + } + + clauses = clauses + clause; + } + + if (clauses.length > 0) + return prefix + clauses + '&'; + + return clauses; + } + + /** + * Converts the column array into odata select clause + */ + public convertColumns(): string { + if (this._columns.length == 0) + return ''; + + // + // Column selection not applicable with count only + // + if (this.limit === Odata.COUNT_ONLY) + return ''; + + let value = '$select='; + for (let i = 0; i < this._columns.length; ++i) { + value = value + this._columns[i].name; + + if ((i + 1) < this._columns.length) + value = value + ','; + } + + return value + '&'; + } + + /** + * Converts the order by values into odata orderby clause + */ + public convertOrderBy(): string { + if (this._entity.columns.length == 0) + return ''; + + // + // orderby not applicable with count only + // + if (this.limit === Odata.COUNT_ONLY) + return ''; + + const orderbyPrefix = '$orderby='; + let value = orderbyPrefix; + for (let i = 0; i < this._entity.columns.length; ++i) { + const column: OdataColumn = this._entity.columns[i]; + if (!column.sort) + continue; + + if ('asc' === column.sort) + value = value + column.name; + else if ('desc' === column.sort) + value = value + column.name + ' desc'; + + if ((i + 1) < this._entity.columns.length) + value = value + ','; + } + + // Remove trailing comma if applicable + if (value.endsWith(',')) + value = value.substring(0, value.length - 1); + + if (value === orderbyPrefix) + return ''; + + return value + '&'; + } + +} diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index b383fb09..9bfdbc43 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -18,8 +18,10 @@ import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; import { PublishState } from "@dataservices/shared/publish-state.enum"; import { Virtualization } from "@dataservices/shared/virtualization.model"; +import { VirtRoute } from "@dataservices/shared/virt-route.model"; import { Identifiable } from "@shared/identifiable"; import { SortDirection } from "@shared/sort-direction.enum"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; export class Dataservice implements Identifiable< string > { @@ -232,6 +234,29 @@ export class Dataservice implements Identifiable< string > { return this.getServicePublishState() === PublishState.FAILED; } + /** + * Accessor to return the root of the odata url, ie. + * http://HOST/odata4/vdbName/ + * + * @returns {string} the odata url for this dataaservice + */ + public getOdataRootUrl(): string { + if (! this.servicePublished || ! this.virtualization) { + return null; + } + + let route: VirtRoute = this.virtualization.getOdataRoute(); + if (route == null) { + return null; + } + + let proto = 'http'; + if (route.isSecure()) + proto = proto + 's'; + + return proto + '://' + route.getHost() + '/' + DataservicesConstants.ODATA_VERSION + '/' + this.getServiceVdbName(); + } + /** * @param {string} id the dataservice identifier (optional) */ diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index a610a11e..e532a504 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -40,6 +40,7 @@ import { Observable } from "rxjs/Observable"; import { ReplaySubject } from "rxjs/ReplaySubject"; import { Subject } from "rxjs/Subject"; import { Subscription } from "rxjs/Subscription"; +import * as _ from "lodash"; @Injectable() export class DataserviceService extends ApiService { @@ -483,6 +484,55 @@ export class DataserviceService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Query a Dataservice's published virtualization using odata protocol + * @param {string} url the odata url string + * @returns {Observable} + */ + public odataGet(url: string): Observable { + return this.http + .get(url, this.getAuthRequestOptions()) + .map((response) => { + const data = response.text(); + let jobj = this.tryJsonParse(data); + if (_.isObject(jobj)) { + return jobj; + } else if (this.isXML(data)) { + // convert the data to JSON and provide + // it to the success function below + let json = this.tryXMLParse(data); + return json; + } + + if (_.isEqual(data, "0")) { + // + // corner-case where $count is used + // and there are no results + // + return { + count: 0 + }; + } + + let n = this.tryNumberParse(data); + if (n) { + return { + count: n + }; + } + + if (typeof response === 'string' || response instanceof String) { + return { + value: response + }; + } + + return { + error: 'Error: Request to ' + url + " produces an unexpected response: " + data + }; + }).catch((error) => this.handleError(error)); + } + /** * Updates the current Dataservice states - triggers update to be broadcast to interested components */ diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ngapp/src/app/dataservices/shared/dataservices-constants.ts index 5a507e69..6072b02e 100644 --- a/ngapp/src/app/dataservices/shared/dataservices-constants.ts +++ b/ngapp/src/app/dataservices/shared/dataservices-constants.ts @@ -29,6 +29,8 @@ export class DataservicesConstants { public static readonly testDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/test-virtualization"; public static readonly testDataservicePath = DataservicesConstants.dataservicesRootPath + "/test-virtualization"; + public static readonly ODATA_VERSION = 'odata4'; + public static dataserviceNameLabel = "Name"; public static descriptionLabel = "Description"; diff --git a/ngapp/src/app/dataservices/shared/virt-route.model.ts b/ngapp/src/app/dataservices/shared/virt-route.model.ts new file mode 100644 index 00000000..bbf20a22 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/virt-route.model.ts @@ -0,0 +1,113 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * VirtRoute model + * This is a model of the routes generated within Openshift + * allowing access to the protocols urls, such as odata and jdbc. + */ +export class VirtRoute { + + public static readonly ODATA_PROTOCOL = 'odata'; + + private name: string; + private protocol: string; + private host: string; + private port: string; + private path: string; + private target: string; + private secure: boolean; + + /** + * @param {Object} json the JSON representation of a VirtRoute + * @returns {VirtRoute} the new VirtRoute (never null) + */ + public static create( json: object = {} ): VirtRoute { + const route = new VirtRoute(); + route.setValues( json ); + return route; + } + + constructor(); + constructor(name?: string) { + this.name = name ? name : null; + } + + /** + * @returns {string} the route name (can be null) + */ + public getName(): string { + return this.name; + } + + /** + * @returns {string} the route protocol (can be null) + */ + public getProtocol(): string { + return this.protocol; + } + + /** + * @returns {string} the route host (can be null) + */ + public getHost(): string { + return this.host; + } + + /** + * @returns {string} the route port (can be null) + */ + public getPort(): string { + return this.port; + } + + /** + * @returns {string} the route path (can be null) + */ + public getPath(): string { + return this.path; + } + + /** + * @returns {string} the route target (can be null) + */ + public getTarget(): string { + return this.target; + } + + /** + * @returns {boolean} whether the route is secure + */ + public isSecure(): boolean { + return this.secure; + } + + /** + * Set all object values using the supplied VirtRoute json + * @param {Object} values + */ + public setValues(values: object = {}): void { + Object.assign(this, values); + } + + /** + * Is this an odata route + */ + public isOdata(): boolean { + return this.getProtocol() == VirtRoute.ODATA_PROTOCOL; + } +} diff --git a/ngapp/src/app/dataservices/shared/virtualization.model.ts b/ngapp/src/app/dataservices/shared/virtualization.model.ts index 21287d20..6d3b23e7 100644 --- a/ngapp/src/app/dataservices/shared/virtualization.model.ts +++ b/ngapp/src/app/dataservices/shared/virtualization.model.ts @@ -16,6 +16,7 @@ */ import { PublishState } from "@dataservices/shared/publish-state.enum"; +import { VirtRoute } from "@dataservices/shared/virt-route.model"; /** * Virtualization model @@ -30,6 +31,7 @@ export class Virtualization { private namespace: string; private last_updated: string; private publishState: PublishState; + private virtRoutes: Array; /** * @param {Object} json the JSON representation of a Virtualization @@ -104,12 +106,39 @@ export class Virtualization { return this.publishState; } + public getOdataRoute(): VirtRoute { + if (! this.virtRoutes) { + return null; + } + + for ( const virtRoute of this.virtRoutes ) { + if (virtRoute.isOdata()) + return virtRoute; + } + + return null; + } + /** * Set all object values using the supplied Virtualization json * @param {Object} values */ public setValues(values: object = {}): void { Object.assign(this, values); + + if (values['routes']) { + let routes = values['routes']; + for (let i = 0; i < routes.length; ++i) { + let route = routes[i]; + let virtRoute = VirtRoute.create(route); + if (!this.virtRoutes) { + this.virtRoutes = []; + } + + this.virtRoutes.push(virtRoute); + } + } + if (this.build_status) { if (this.build_status === "BUILDING" || this.build_status === "DEPLOYING") { this.publishState = PublishState.PUBLISHING; From 16ac02e5a46d67ac3eb07167f4567314e5f00bec Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Wed, 16 May 2018 14:06:38 +0100 Subject: [PATCH 146/205] TEIIDTOOLS-400: Improve asynchronous performance of publishing * Adds and tracks extra states of submitting and configuring * Better able to understand how the publishing is going rather than seeing a single spinning icon that may have gone wrong. --- .../dataservice-card.component.html | 33 +++++++++++++++---- .../dataservices-list.component.html | 27 +++++++++++++-- .../dataservices/dataservices.component.ts | 2 +- .../app/dataservices/dataservices.module.ts | 1 - .../odata-control/odata-control.component.ts | 2 +- .../dataservices/shared/dataservice.model.ts | 32 +++++++++++++++--- .../dataservices/shared/publish-state.enum.ts | 19 +++++++++-- .../shared/virtualization.model.ts | 12 +++++-- 8 files changed, 107 insertions(+), 21 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index 2fc61dff..61273bc4 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -91,28 +91,49 @@ *ngIf="dataservice.serviceNotPublished" data-toggle="tooltip" data-placement="right" - title="Not Published"> + title="Virtualization Not Published"> + title="Virtualization Publishing Failed"> + + + + + + + title="Virtualization Deploying"> + title="Virtualization Published">
    diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index 27cf714b..00734312 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -48,12 +48,33 @@ data-placement="right" title="Publishing Failed"> + + + + + + + title="Virtualization Deploying"> x.getId() === svcName); - const virtual: Virtualization = new Virtualization(selectedService.getServiceVdbName(), PublishState.PUBLISHING); + const virtual: Virtualization = new Virtualization(selectedService.getServiceVdbName(), PublishState.SUBMITTED); selectedService.setServiceVirtualization(virtual); this.closeLookPanels(); diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index a36aa588..dbc95d8a 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -82,7 +82,6 @@ import { TooltipModule } from 'ngx-bootstrap'; TestDataserviceComponent, SqlControlComponent, SelectedNodeComponent, - SelectedTableComponent, OdataControlComponent, DataserviceCardComponent, ConnectionSchemaTreeComponent, diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.ts b/ngapp/src/app/dataservices/odata-control/odata-control.component.ts index 74ba9448..b34f47a4 100644 --- a/ngapp/src/app/dataservices/odata-control/odata-control.component.ts +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.ts @@ -431,7 +431,7 @@ export class OdataControlComponent implements OnChanges { const label = this.selectedColumns[j].name; const col = { canAutoResize: true, draggable: false, - name: label.toUpperCase(), + name: this.tableTitle(label), prop: label, resizable: true, sortable: true }; diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 9bfdbc43..8de46706 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -211,11 +211,35 @@ export class Dataservice implements Identifiable< string > { } /** - * Accessor to determine if service publishing is active - * @returns {boolean} the dataservice service publishing active state + * Accessor to determine if service submission is active + * @returns {boolean} the dataservice service submitted active state */ - public get servicePublishing(): boolean { - return this.getServicePublishState() === PublishState.PUBLISHING; + public get serviceSubmitted(): boolean { + return this.getServicePublishState() === PublishState.SUBMITTED; + } + + /** + * Accessor to determine if service configuring is active + * @returns {boolean} the dataservice service configuring active state + */ + public get serviceConfiguring(): boolean { + return this.getServicePublishState() === PublishState.CONFIGURING; + } + + /** + * Accessor to determine if service building is active + * @returns {boolean} the dataservice service building active state + */ + public get serviceBuilding(): boolean { + return this.getServicePublishState() === PublishState.BUILDING; + } + + /** + * Accessor to determine if service deploying is active + * @returns {boolean} the dataservice service deploying active state + */ + public get serviceDeploying(): boolean { + return this.getServicePublishState() === PublishState.DEPLOYING; } /** diff --git a/ngapp/src/app/dataservices/shared/publish-state.enum.ts b/ngapp/src/app/dataservices/shared/publish-state.enum.ts index 650f0f40..1f369490 100644 --- a/ngapp/src/app/dataservices/shared/publish-state.enum.ts +++ b/ngapp/src/app/dataservices/shared/publish-state.enum.ts @@ -26,9 +26,24 @@ export enum PublishState { NOT_PUBLISHED, /** - * publishing + * submitted */ - PUBLISHING, + SUBMITTED, + + /** + * configuring + */ + CONFIGURING, + + /** + * building + */ + BUILDING, + + /** + * deploying + */ + DEPLOYING, /** * published diff --git a/ngapp/src/app/dataservices/shared/virtualization.model.ts b/ngapp/src/app/dataservices/shared/virtualization.model.ts index 6d3b23e7..4a94b5e5 100644 --- a/ngapp/src/app/dataservices/shared/virtualization.model.ts +++ b/ngapp/src/app/dataservices/shared/virtualization.model.ts @@ -26,7 +26,7 @@ export class Virtualization { private readonly vdb_name: string; private build_name: string; private deployment_name: string; - private build_status: string; /* NOTFOUND, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ + private build_status: string; /* NOTFOUND, SUBMITTED, CONFIGURING, BUILDING, DEPLOYING, RUNNING, FAILED, CANCELLED */ private build_status_message: string; private namespace: string; private last_updated: string; @@ -140,8 +140,14 @@ export class Virtualization { } if (this.build_status) { - if (this.build_status === "BUILDING" || this.build_status === "DEPLOYING") { - this.publishState = PublishState.PUBLISHING; + if (this.build_status === "SUBMITTED") { + this.publishState = PublishState.SUBMITTED; + } else if (this.build_status === "CONFIGURING") { + this.publishState = PublishState.CONFIGURING; + } else if (this.build_status === "BUILDING") { + this.publishState = PublishState.BUILDING; + } else if (this.build_status === "DEPLOYING") { + this.publishState = PublishState.DEPLOYING; } else if (this.build_status === "RUNNING") { this.publishState = PublishState.PUBLISHED; } else if (this.build_status === "FAILED") { From 73a2beebc60728ade2ca7c0d4b0e610fb3a7a855 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Fri, 18 May 2018 16:12:54 +0100 Subject: [PATCH 147/205] Updated publishing status icons * Changes the icons to be different rather than just the colour. --- .../dataservice-card/dataservice-card.component.html | 6 +++--- .../dataservices-list/dataservices-list.component.html | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index 61273bc4..4af4a984 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -100,14 +100,14 @@ data-placement="right" title="Virtualization Publishing Failed"> - - - - - - Date: Tue, 22 May 2018 16:18:14 +0100 Subject: [PATCH 148/205] Fix API incompatibility of patternfly-ng * Patternfly-ng appears to have been updated and the new version causes a builds error due to a lack of PatternFlyNgModule in the library. * For the moment, fix the dependency version to 3.1.5. --- ngapp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngapp/package.json b/ngapp/package.json index 542d3e9d..b652d712 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -32,7 +32,7 @@ "ng2-codemirror": "^1.1.3", "ngx-bootstrap": "^2.0.2", "patternfly": "^3.41.0", - "patternfly-ng": "^3.1.2", + "patternfly-ng": "3.1.5", "rxjs": "^5.5.6", "x2js": "^3.2.1", "zone.js": "^0.8.20" From 8e9b9a154345e29e848bf42a0020756976e2ab91 Mon Sep 17 00:00:00 2001 From: phantomjinx Date: Thu, 24 May 2018 14:32:44 +0100 Subject: [PATCH 149/205] TEIIDTOOLS-436: Convert the odata results to json and xml * Adds icons for odata controls panels for the opening/closing the accordion groups * Small changes and fixes to layout * Adds spinner during initial metadata fetch and stop error message displaying prematurely * Uses CodeMirror for odata results * Adds Output Format control to allow choosing between XML and JSON * Uses ViewChild to access the CodeMirror instance, allowing changing of the mode between XML and JSON * DataserviceService * Ensures return of odata results is a string and in turn adds that string as a value to a json object. * Ensure the XML is formatted/beautified before its return * Specialise other references to the .CodeMirror class to ensure they do not conflict with one another. --- ngapp/package.json | 1 + ngapp/src/app/core/api.service.ts | 10 +- .../odata-control/odata-constants.ts | 5 + .../odata-control/odata-control.component.css | 84 +++++++- .../odata-control.component.html | 64 ++++-- .../odata-control.component.spec.ts | 68 ------- .../odata-control/odata-control.component.ts | 189 ++++++++---------- .../shared/dataservice.service.ts | 18 +- .../sql-control/sql-control.component.css | 8 + ngapp/src/styles.css | 9 +- 10 files changed, 234 insertions(+), 222 deletions(-) delete mode 100644 ngapp/src/app/dataservices/odata-control/odata-control.component.spec.ts diff --git a/ngapp/package.json b/ngapp/package.json index b652d712..570b2790 100644 --- a/ngapp/package.json +++ b/ngapp/package.json @@ -34,6 +34,7 @@ "patternfly": "^3.41.0", "patternfly-ng": "3.1.5", "rxjs": "^5.5.6", + "vkbeautify": "^0.99.3", "x2js": "^3.2.1", "zone.js": "^0.8.20" }, diff --git a/ngapp/src/app/core/api.service.ts b/ngapp/src/app/core/api.service.ts index a5b06f0a..02530c17 100644 --- a/ngapp/src/app/core/api.service.ts +++ b/ngapp/src/app/core/api.service.ts @@ -60,7 +60,7 @@ export abstract class ApiService { return this.appSettings.getKomodoUserWorkspacePath(); } - protected isXML(xml: string): boolean { + public isXML(xml: string): boolean { try { const parser = new X2JS(); const xmlDoc = parser.xml2js(xml); //is valid XML @@ -71,7 +71,7 @@ export abstract class ApiService { } } - protected tryXMLParse(xml: string): any { + public tryXMLParse(xml: string): any { try { const parser = new X2JS(); const xmlDoc = parser.xml2js(xml); //is valid XML @@ -81,7 +81,7 @@ export abstract class ApiService { return null; } - protected tryNumberParse(jsonString: string): number { + public tryNumberParse(jsonString: string): number { try { var n = parseInt(jsonString); if (n && typeof n === "number") { @@ -96,7 +96,7 @@ export abstract class ApiService { * Try to parse the given string and if parseable * then return the object */ - protected tryJsonParse (jsonString: string): any { + public tryJsonParse (jsonString: string): any { try { var o = JSON.parse(jsonString); @@ -115,7 +115,7 @@ export abstract class ApiService { /** * @returns true if the item is parseable */ - protected isJSON(item: string): boolean { + public isJSON(item: string): boolean { item = typeof item !== "string" ? JSON.stringify(item) : item; try { diff --git a/ngapp/src/app/dataservices/odata-control/odata-constants.ts b/ngapp/src/app/dataservices/odata-control/odata-constants.ts index 8a95da5f..4ba0196a 100644 --- a/ngapp/src/app/dataservices/odata-control/odata-constants.ts +++ b/ngapp/src/app/dataservices/odata-control/odata-constants.ts @@ -17,6 +17,8 @@ export class OdataConstants { + public readonly UrlNotAvailable = 'URL Not Available'; + public readonly AscendingChoice = "Asc"; public readonly columnPlaceholder = "column"; public readonly Columns = "Columns"; @@ -33,6 +35,7 @@ export class OdataConstants { public readonly resultLimitPlaceholder = "Select result limit..."; public readonly resultsTabular = "Tabular"; public readonly resultsRaw = "Raw"; + public readonly runningOdataMetadataFetch = "Fetching OData metadata ..."; public readonly runningOdataQuery = "Running OData query..."; public readonly runQueryAction = "Submit"; public readonly Select = "Select"; @@ -46,6 +49,7 @@ export class OdataConstants { public readonly valuePlaceholder = "value"; public readonly Where = "Where"; public readonly OrderBy = "Order By"; + public readonly ResultFormat = "Format"; public readonly noResultsColumnName = "Err: No Data!"; public readonly noResultsMsg = "No data was returned from the query"; @@ -61,6 +65,7 @@ export class OdataConstants { public readonly help_columns = "Select the columns to be included in the results."; public readonly help_where = "Create where clauses for filtering the results based on the values in each tuple. Use the + button to add new where clauses (clauses are and-ed together) and remove them with the - buttons."; public readonly help_orderBy = "Sort the results by column in ascending or descending order."; + public readonly help_format = "Choose the format of the query results."; public readonly help_resultsTable = "Use the column headers to sort the results or filter them by entering values. Results are paginated in blocks of 25 and can be scrolled through with the controls at the foot of the table."; public readonly help_resultsRaw = "The raw data as returned from the odata teiid service in json format."; public readonly help_sqlSearch = "Use the Teiid dialect of SQL to construct a query that interrogates the data service for data results. Use the record limit to limit the number of results returned. Set the starting record index to fetch a subset of results starting at the given row index."; diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.css b/ngapp/src/app/dataservices/odata-control/odata-control.component.css index 770d6363..7dc2ae51 100644 --- a/ngapp/src/app/dataservices/odata-control/odata-control.component.css +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.css @@ -54,6 +54,34 @@ clear: both; } +.odata-controls { + max-height: 27em; + border-style: solid; + border-width: 1px; + border-color: rgb(187,187,187); + overflow-y: auto; +} + +/* + * Add icon for accordion group being open + */ +.odata-controls .panel-title .accordion-toggle[aria-expanded="true"]::after { + float: right; + content: "\f106"; + color: #424242; + font-family: "FontAwesome"; +} + +/* + * Add icon for accordion group being closed + */ +.odata-controls .panel-title .accordion-toggle[aria-expanded="false"]::after { + float: right; + content: "\f107"; + color: #424242; + font-family: "FontAwesome"; +} + .odata-control-panel-title { font-weight: bold; display: inline-block; @@ -71,7 +99,19 @@ height: 1em; } +.odata-exp-select-group-entity { + float: left; + width: 40%; + margin-right: 5em; +} + +.odata-exp-select-group-limit { + float: left; + width: 40%; +} + .odata-exp-column-group { + float: left; margin-bottom: 0; padding-left: 0; } @@ -79,6 +119,8 @@ .odata-exp-column-group-row { margin-top: 0; margin-bottom: 0; + margin-right: 5em; + margin-left: 0.25em; } .odata-exp-select-group, @@ -90,6 +132,11 @@ font-weight: bold; } +.odata-format-row label { + margin-right: 5em; + font-weight: bold; +} + .odata-exp-where-group-row { padding-top: 0.25em; padding-left: 0.25em !important; @@ -109,18 +156,32 @@ padding-right: 1%; } -.odata-form-control { +.odata-form-text-control { color: #000000; background-color: #FFFFFB; - border: 2px outset #FCFFFF; font-weight: bold; width: 100%; + border-top-color: rgb(187, 187, 187); + border-top-style: solid; + border-top-width: 1px; + border-left-color: rgb(187, 187, 187); + border-left-style: solid; + border-left-width: 1px; + border-right-color: rgb(252, 255, 255); + border-right-style: outset; + border-right-width: 2px; + border-bottom-color: rgb(252, 255, 255); + border-bottom-style: outset; + border-bottom-width: 2px; + padding-left: 0.5em; + margin-bottom: 0.5em; } .odata-exp-order-by-group-row-label { padding-left: 0; width: 30%; word-wrap: break-word; + margin-bottom: 0.5em; } .odata-form-where-add-btn { @@ -146,17 +207,24 @@ margin-bottom: 0.5em; } -#odata-results-table { +#odata-results { clear: both; padding-left: 0; padding-right: 0; padding-bottom: 2em; position: relative; -} - -.odata-results-table-grid { - font-weight: lighter; -} + border-color: rgb(187,187,187); + border-style: solid; + border-width: 1px; +} + +/* + * Limit CodeMirror class changes to + * the odata-results. + */ +/*#odata-results .CodeMirror { + height: 25em; +}*/ #odata-search-progress-spinner { font-style: italic; diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.html b/ngapp/src/app/dataservices/odata-control/odata-control.component.html index a870a856..0cc76314 100644 --- a/ngapp/src/app/dataservices/odata-control/odata-control.component.html +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.html @@ -1,4 +1,10 @@
    + +
    +
    + {{i18n.runningOdataMetadataFetch}} +
    +
    @@ -37,13 +43,13 @@
    -
    +
    -
    +
    @@ -67,7 +73,7 @@
    -
    +
    diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts index 72375337..5017a33b 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts @@ -25,6 +25,7 @@ import { ConnectionsConstants } from "@connections/shared/connections-constants" import { LoadingState } from "@shared/loading-state.enum"; import { ConnectionService } from "@connections/shared/connection.service"; import { LoggerService } from "@core/logger.service"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; @Component({ selector: "app-connection-table-dialog", @@ -52,12 +53,14 @@ export class ConnectionTableDialogComponent implements OnInit { @Output() public okAction = new EventEmitter(); - public title = "Select Source for View"; - public cancelButtonText = "Cancel"; - public okButtonText = "OK"; + public readonly title = ViewEditorI18n.connectionTableSelectionDialogTitle; + public readonly message = ViewEditorI18n.connectionTableSelectionDialogMessage; + public readonly cancelButtonText = ViewEditorI18n.cancelButtonText; + public readonly okButtonText = ViewEditorI18n.okButtonText; public okButtonEnabled = false; public bsModalRef: BsModalRef; - public selectionText = "Nothing selected"; + public selectionText = ViewEditorI18n.noSelection; + public readonly currentSelectionMsg = ViewEditorI18n.currentSelection; private connectionService: ConnectionService; private selectedTreeNodes: SchemaNode[] = []; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts index e597e01d..dbad97a6 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts @@ -10,7 +10,7 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { AppSettingsService } from "@core/app-settings.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; -import { SchemaNode } from "@connections/shared/schema-node.model"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; describe("ConnectionTreeSelectorComponent", () => { let component: ConnectionTreeSelectorComponent; @@ -20,7 +20,10 @@ describe("ConnectionTreeSelectorComponent", () => { TestBed.configureTestingModule({ imports: [ HttpModule, TreeModule ], declarations: [ ConnectionTreeSelectorComponent ], - providers: [ AppSettingsService, LoggerService, NotifierService, + providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService }, + LoggerService, + NotifierService, { provide: ConnectionService, useClass: MockConnectionService }, { provide: VdbService, useClass: MockVdbService }, ] diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html index 9cead9cc..e9cca771 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html @@ -4,7 +4,7 @@ (deselect)="tabSelected(tabs[0], false)"> - Preview + {{previewTabName}} @@ -13,7 +13,7 @@ (deselect)="tabSelected(tabs[1], false)"> - Messages + {{messagesTabName}} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts index bbc68844..d75a6769 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts @@ -16,11 +16,12 @@ */ import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { Subscription } from "rxjs/Subscription"; -import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; -import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event"; import { LoggerService } from "@core/logger.service"; +import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; +import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event"; +import { Subscription } from "rxjs/Subscription"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; @Component({ encapsulation: ViewEncapsulation.None, @@ -30,6 +31,10 @@ import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-ed }) export class EditorViewsComponent implements OnInit, OnDestroy { + // text used by html + public readonly messagesTabName = ViewEditorI18n.messagesTabName; + public readonly previewTabName = ViewEditorI18n.previewTabName; + private readonly previewIndex = 0; private readonly messagesIndex = 1; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css index bb4dd829..86c72b61 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css @@ -1,5 +1,5 @@ /* - * The container for the mesage log table. + * The container for the message log table. */ #view-editor-message-log { align-items: center; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts index 1968a00b..7805e289 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts @@ -20,6 +20,7 @@ import { LoggerService } from "@core/logger.service"; import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; import { EmptyStateConfig, NgxDataTableConfig, TableConfig } from "patternfly-ng"; import { Message } from "@dataservices/virtualization/view-editor/editor-views/message-log/message"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; @Component({ encapsulation: ViewEncapsulation.None, @@ -49,19 +50,19 @@ export class MessageLogComponent implements OnInit { public ngOnInit(): void { this.columns = [ { - name: "ID", + name: ViewEditorI18n.idColumnName, prop: Message.ID_PROP_NAME }, { - name: "Type", + name: ViewEditorI18n.typeColumnName, prop: Message.TYPE_PROP_NAME }, { - name: "Description", + name: ViewEditorI18n.descriptionColumnName, prop: Message.DESCRIPTION_PROP_NAME }, { - name: "Context", + name: ViewEditorI18n.contextColumnName, prop: Message.CONTEXT_PROP_NAME }, ]; @@ -74,7 +75,7 @@ export class MessageLogComponent implements OnInit { } as NgxDataTableConfig; this.emptyStateConfig = { - title: "No messages found" + title: ViewEditorI18n.noMessagesFound } as EmptyStateConfig; this.tableConfig = { diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts index a83fcc33..439d31be 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts @@ -15,18 +15,13 @@ * limitations under the License. */ import { MessageType } from "@dataservices/virtualization/view-editor/editor-views/message-log/message-type.enum"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; export class Problem { - public static readonly ERR0100 = new Problem( "ERR0100", - MessageType.ERROR, - "There must be a virtualization selected in order to use this editor." ); - public static readonly ERR0110 = new Problem( "ERR0110", - MessageType.ERROR, - "A view must have a name." ); - public static readonly ERR0120 = new Problem( "ERR0120", - MessageType.ERROR, - "A view must have at least one source." ); + public static readonly ERR0100 = new Problem( "ERR0100", MessageType.ERROR, ViewEditorI18n.error0100 ); + public static readonly ERR0110 = new Problem( "ERR0110", MessageType.ERROR, ViewEditorI18n.error0110 ); + public static readonly ERR0120 = new Problem( "ERR0120", MessageType.ERROR, ViewEditorI18n.error0120 ); private readonly _id: string; private readonly _description: string; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts index 2e4ff31f..4a13a145 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts @@ -24,6 +24,7 @@ import { ColumnData } from "@dataservices/shared/column-data.model"; import { RowData } from "@dataservices/shared/row-data.model"; import { EmptyStateConfig, NgxDataTableConfig, TableConfig } from "patternfly-ng"; import { Subscription } from "rxjs/Subscription"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; @Component({ encapsulation: ViewEncapsulation.None, @@ -102,7 +103,7 @@ export class ViewPreviewComponent implements OnInit, OnDestroy { } as NgxDataTableConfig; this.emptyStateConfig = { - title: "Preview data unavailable" + title: ViewEditorI18n.previewDataUnavailable } as EmptyStateConfig; this.tableConfig = { @@ -129,7 +130,7 @@ export class ViewPreviewComponent implements OnInit, OnDestroy { // Define the row data let firstTime = true; - const rowNumHeader = "ROW #"; + const rowNumHeader = ViewEditorI18n.rowNumberColumnName; for ( let rowIndex = 0; rowIndex < rowData.length; rowIndex++ ) { const row = rowData[ rowIndex ]; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts b/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts index 6d540a01..96cd03cb 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts @@ -20,7 +20,7 @@ export enum ViewEditorSaveProgressChangeId { /** * Indicates the view save is in progress. */ - IN_PROGESS = "IN_PROGRESS", + IN_PROGRESS = "IN_PROGRESS", /** * Indicates the view save has completed successfully. diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html index 39ae9ebe..1a456e45 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html @@ -8,7 +8,7 @@
    - Select a source for the view + {{noSourcesAlert}}
    @@ -20,7 +20,8 @@
    Properties + id="view-editor-properties-container"> +
    diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts index 3e8f87d0..4f9ef228 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts @@ -19,6 +19,8 @@ import { import { VdbService } from "@dataservices/shared/vdb.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { ViewPropertyEditorsComponent } from "@dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component"; +import { TabsModule } from "ngx-bootstrap"; describe('ViewCanvasComponent', () => { let component: ViewCanvasComponent; @@ -36,9 +38,14 @@ describe('ViewCanvasComponent', () => { SortModule, TableModule, WizardModule, - HttpModule + HttpModule, + TabsModule.forRoot() + ], + declarations: [ + SelectedNodeComponent, + ViewCanvasComponent, + ViewPropertyEditorsComponent ], - declarations: [ ViewCanvasComponent, SelectedNodeComponent ], providers: [ { provide: AppSettingsService, useClass: MockAppSettingsService }, LoggerService, diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts index 26e1bcf5..0d16900b 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts @@ -23,6 +23,7 @@ import { Subscription } from "rxjs/Subscription"; import { SchemaNode } from "@connections/shared/schema-node.model"; import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; import { ViewStateChangeId } from "@dataservices/virtualization/view-editor/event/view-state-change-id.enum"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; @Component({ encapsulation: ViewEncapsulation.None, @@ -32,6 +33,9 @@ import { ViewStateChangeId } from "@dataservices/virtualization/view-editor/even }) export class ViewCanvasComponent implements OnInit, OnDestroy { + // used by html + public readonly noSourcesAlert = ViewEditorI18n.noSourcesAlert; + private readonly logger: LoggerService; private readonly editorService: ViewEditorService; private subscription: Subscription; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html index b85f69f4..4c89a6a6 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html @@ -19,13 +19,13 @@
    Show Description + (change)="showDescription = $event.target.checked">{{showDescriptionCheckbox}}
    @@ -52,13 +52,13 @@ *ngIf="showDescription">
    +
    +
    + + + +

    Virtualization View

    +
    + +
    + +
    {{ viewNameValidationError }}
    +
    +
    +
    + +
    + +
    +
    + +
    + diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts new file mode 100644 index 00000000..f26bfcc5 --- /dev/null +++ b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts @@ -0,0 +1,51 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HttpModule } from "@angular/http"; +import { BsModalRef, ModalModule } from "ngx-bootstrap"; +import { + ActionModule, + NotificationModule +} from "patternfly-ng"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { CreateVirtualizationDialogComponent } from "./create-virtualization-dialog.component"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; + +describe('CreateVirtualizationDialogComponent', () => { + let component: CreateVirtualizationDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + HttpModule, + FormsModule, + ReactiveFormsModule, + ModalModule.forRoot(), + ActionModule, + NotificationModule + ], + declarations: [ CreateVirtualizationDialogComponent ], + providers: [ AppSettingsService, BsModalRef, LoggerService, NotifierService, + { provide: DataserviceService, useClass: MockDataserviceService }, + { provide: VdbService, useClass: MockVdbService } + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateVirtualizationDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts new file mode 100644 index 00000000..ace1d70b --- /dev/null +++ b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts @@ -0,0 +1,204 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit } from "@angular/core"; +import { Output } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { BsModalRef } from "ngx-bootstrap"; +import { LoggerService } from "@core/logger.service"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { AbstractControl, FormControl, FormGroup } from "@angular/forms"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { CreateVirtualizationResult } from "@dataservices/create-virtualization-dialog/create-virtualization-result.model"; + +@Component({ + selector: "app-create-virtualization-dialog", + templateUrl: "./create-virtualization-dialog.component.html", + styleUrls: ["./create-virtualization-dialog.component.css"] +}) +/** + * CreateVirtualization Dialog. Invoke this from another component as follows: + * + * this.modalRef = this.modalService.show(CreateVirtualizationDialogComponent, {initialState}); + * this.modalRef.content.okAction.take(1).subscribe((createResult) => { + * // do something with dialog result - CreateVirtualizationResult + * }); + * + * The expected initial state is as follows: + * const initialState = { + * title: "The dialog title", + * cancelButtonText: "Text for cancel button", + * confirmButtonText: "Text for confirm button" + * }; + */ +export class CreateVirtualizationDialogComponent implements OnInit { + + @Output() public okAction: EventEmitter = new EventEmitter(); + + public readonly title = ViewEditorI18n.createVirtualizationDialogTitle; + public readonly message = ViewEditorI18n.createVirtualizationDialogMessage; + public readonly cancelButtonText = ViewEditorI18n.cancelButtonText; + public readonly okButtonText = ViewEditorI18n.okButtonText; + public okButtonEnabled = false; + public bsModalRef: BsModalRef; + public virtNameValidationError = ""; + public viewNameValidationError = ""; + public virtualizationPropertyForm: FormGroup; + + private loggerService: LoggerService; + private dataserviceService: DataserviceService; + private vdbService: VdbService; + private serviceVdbName = ""; + + constructor(bsModalRef: BsModalRef, logger: LoggerService, + dataserviceService: DataserviceService, vdbService: VdbService) { + this.bsModalRef = bsModalRef; + this.loggerService = logger; + this.dataserviceService = dataserviceService; + const dService = this.dataserviceService.getSelectedDataservice(); + if ( dService && dService !== null ) { + this.serviceVdbName = dService.getServiceVdbName(); + } + this.vdbService = vdbService; + this.createPropertyForm(); + } + + public ngOnInit(): void { + this.virtualizationPropertyForm.controls["virtName"].setValue(""); + this.virtualizationPropertyForm.controls["virtDescription"].setValue(""); + this.virtualizationPropertyForm.controls["viewName"].setValue(""); + this.virtualizationPropertyForm.controls["viewDescription"].setValue(""); + } + + /* + * Creates the view property form + */ + private createPropertyForm(): void { + this.virtualizationPropertyForm = new FormGroup({ + virtName: new FormControl( "", this.handleVirtNameChanged.bind( this ) ), + virtDescription: new FormControl(""), + viewName: new FormControl( "", this.handleViewNameChanged.bind( this ) ), + viewDescription: new FormControl("") + }); + } + + /** + * Handler for virtualization name changes. + * @param {AbstractControl} input + */ + public handleVirtNameChanged( input: AbstractControl ): void { + const self = this; + + this.dataserviceService.isValidName( input.value ).subscribe( + ( errorMsg ) => { + if ( errorMsg ) { + // only update if error has changed + if ( errorMsg !== self.virtNameValidationError ) { + self.virtNameValidationError = errorMsg; + } + } else { // name is valid + self.virtNameValidationError = ""; + } + self.setOkButtonEnablement(); + }, + ( error ) => { + self.loggerService.error( "[handleNameChanged] Error: %o", error ); + self.virtNameValidationError = "Error validating view name"; + self.setOkButtonEnablement(); + } ); + } + + /** + * Handler for view name changes. Since this will be the first view in the virtualization, + * no need to make a service call - just do some general name checking + * @param {AbstractControl} input + */ + public handleViewNameChanged( input: AbstractControl ): void { + this.viewNameValidationError = this.validateViewName(input.value); + this.setOkButtonEnablement(); + } + + /** + * OK selected. Emit ViewDefinition with the view, then modal is closed + */ + public onOkSelected(): void { + const virtName = this.virtualizationPropertyForm.controls["virtName"].value; + const virtDescr = this.virtualizationPropertyForm.controls["virtDescription"].value; + const viewName = this.virtualizationPropertyForm.controls["viewName"].value; + const viewDescr = this.virtualizationPropertyForm.controls["viewDescription"].value; + + const result = new CreateVirtualizationResult(); + result.setVirtualizationName(virtName); + result.setVirtualizationDescription(virtDescr); + result.setViewName(viewName); + result.setViewDescription(viewDescr); + this.okAction.emit(result); + + this.bsModalRef.hide(); + } + + /** + * Cancel selected. The modal is closed. + */ + public onCancelSelected(): void { + this.bsModalRef.hide(); + } + + /* + * Return the virtualization name valid state + */ + public get virtNameValid(): boolean { + return this.virtNameValidationError == null || this.virtNameValidationError.length === 0; + } + + /* + * Return the view name valid state + */ + public get viewNameValid(): boolean { + return this.viewNameValidationError == null || this.viewNameValidationError.length === 0; + } + + /** + * Validate the provided view name. If the name is valid, an empty string will be returned. If the view is invalid, + * the error message is returned. + * @param {string} viewName the view name being validated + * @return {string} the validation message + */ + private validateViewName( viewName: string ): string { + if ( !viewName || viewName === null || viewName.length === 0 ) { + return "View name cannot be empty"; + } + const isValid = /^\w+$/.test(viewName); + if ( !isValid ) { + return "View name can only contain letters, digits and underscores"; + } + return ""; + } + + /** + * Sets the OK button enablement. Both the virtualization name and view name must be valid. + */ + private setOkButtonEnablement(): void { + if (this.virtNameValid && this.viewNameValid) { + this.okButtonEnabled = true; + } else { + this.okButtonEnabled = false; + } + } + +} diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-result.model.ts b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-result.model.ts new file mode 100644 index 00000000..21b98e04 --- /dev/null +++ b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-result.model.ts @@ -0,0 +1,88 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * CreateVirtualizationResult model - to hold the results of the dialog entry + */ +export class CreateVirtualizationResult { + + private virtName: string; + private virtDescription = ""; + private viewName: string; + private viewDescription = ""; + + constructor() { + // nothing to do + } + + /** + * @returns {string} the virtualization name + */ + public getVirtualizationName(): string { + return this.virtName; + } + + /** + * @param {string} name the virtualization name + */ + public setVirtualizationName( name?: string ): void { + this.virtName = name ? name : null; + } + + /** + * @returns {string} the virtualization description + */ + public getVirtualizationDescription(): string { + return this.virtDescription; + } + + /** + * @param {string} description the virtualization description + */ + public setVirtualizationDescription( description?: string ): void { + this.virtDescription = description ? description : ""; + } + + /** + * @returns {string} the view name + */ + public getViewName(): string { + return this.viewName; + } + + /** + * @param {string} name the view name + */ + public setViewName( name?: string ): void { + this.viewName = name ? name : null; + } + + /** + * @returns {string} the view description + */ + public getViewDescription(): string { + return this.viewDescription; + } + + /** + * @param {string} description the view description + */ + public setViewDescription( description?: string ): void { + this.viewDescription = description ? description : ""; + } + +} diff --git a/ngapp/src/app/dataservices/dataservices-routing.module.ts b/ngapp/src/app/dataservices/dataservices-routing.module.ts index ba777faa..62894f5b 100644 --- a/ngapp/src/app/dataservices/dataservices-routing.module.ts +++ b/ngapp/src/app/dataservices/dataservices-routing.module.ts @@ -22,11 +22,9 @@ import { DataservicesComponent } from "@dataservices/dataservices.component"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { TestDataserviceComponent } from "@dataservices/test-dataservice/test-dataservice.component"; import { ViewEditorComponent } from "@dataservices/virtualization/view-editor/view-editor.component"; -import { VirtualizationComponent } from "@dataservices/virtualization/virtualization.component"; const dataservicesRoutes: Routes = [ { path: DataservicesConstants.dataservicesRootRoute, component: DataservicesComponent }, - { path: DataservicesConstants.virtualizationRoute, component: VirtualizationComponent }, { path: DataservicesConstants.viewRoute, component: ViewEditorComponent }, { path: DataservicesConstants.testDataserviceRoute, component: TestDataserviceComponent } ]; diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 76a9718b..5fc0426b 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -72,10 +72,10 @@

    - - + +
    diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index cfba1887..0c1d6457 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -51,6 +51,10 @@ import { } from "patternfly-ng"; import { Subscription } from "rxjs/Subscription"; import { SqlView } from "@dataservices/shared/sql-view.model"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { CreateVirtualizationDialogComponent } from "@dataservices/create-virtualization-dialog/create-virtualization-dialog.component"; +import { ViewDefinition } from "@dataservices/shared/view-definition.model"; +import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; @Component({ moduleId: module.id, @@ -60,14 +64,8 @@ import { SqlView } from "@dataservices/shared/sql-view.model"; }) export class DataservicesComponent extends AbstractPageComponent implements OnInit { - public readonly exportInProgressHeader: string = "Publishing: "; - public readonly exportSuccessHeader: string = "Publishing Begun: "; - public readonly exportFailedHeader: string = "Publishing Failed: "; public readonly connectionsLoadedTag = "connections"; - public readonly downloadSuccessHeader: string = "Download Succeeded: "; - public readonly downloadFailedHeader: string = "Download Failed: "; - public filterConfig: FilterConfig; public filtersText = ""; public items: Dataservice[]; @@ -97,10 +95,10 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn private dataserviceService: DataserviceService; private vdbService: VdbService; private sortDirection: SortDirection = SortDirection.ASC; - private exportNotificationHeader: string; - private exportNotificationMessage: string; - private exportNotificationType = NotificationType.SUCCESS; - private exportNotificationVisible = false; + private toastNotificationHeader: string; + private toastNotificationMessage: string; + private toastNotificationType = NotificationType.SUCCESS; + private toastNotificationVisible = false; private dataserviceDeployStateSubscription: Subscription; private dataservicePublishStateSubscription: Subscription; private notifierService: NotifierService; @@ -323,10 +321,10 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } /** - * @returns {boolean} true if dataservice export notification is to be shown + * @returns {boolean} true if dataservice toast notification is to be shown */ - public get showExportNotification(): boolean { - return this.exportNotificationVisible; + public get showToastNotification(): boolean { + return this.toastNotificationVisible; } /** @@ -475,63 +473,100 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn public onDownload(svcName: string): void { this.closeLookPanels(); - this.exportNotificationHeader = this.exportInProgressHeader; - this.exportNotificationMessage = "Downloading " + svcName + "..."; - this.exportNotificationType = NotificationType.INFO; - this.exportNotificationVisible = true; + this.setToastNotification(Toast.Type.Download, Toast.State.InProgress, svcName); + this.toastNotificationVisible = true; this.logger.debug("[DataservicesPageComponent] Downloading Dataservice: " + svcName); const self = this; this.dataserviceService .downloadDataservice(svcName) .subscribe( (wasSuccess) => { - self.exportNotificationHeader = this.downloadSuccessHeader; - self.exportNotificationMessage = " " + svcName + " was downloaded successfully!"; - self.exportNotificationType = NotificationType.SUCCESS; + self.setToastNotification(Toast.Type.Download, Toast.State.Successful, svcName); // Dismiss toast notification after 8 sec - setTimeout(() => self.exportNotificationVisible = false, 8000); + setTimeout(() => self.toastNotificationVisible = false, 8000); this.logger.debug("[DataservicesPageComponent] Download Dataservice was successful"); }, (error) => { - self.exportNotificationHeader = this.downloadFailedHeader; - self.exportNotificationMessage = " Failed to download dataservice " + svcName; - self.exportNotificationType = NotificationType.DANGER; + self.setToastNotification(Toast.Type.Download, Toast.State.Failed, svcName); // Dismiss toast notification after 8 sec - setTimeout(() => self.exportNotificationVisible = false, 8000); + setTimeout(() => self.toastNotificationVisible = false, 8000); this.logger.error("[DataservicesPageComponent] Download dataservice " + svcName + " failed."); } ); } + /** + * Set the toast notification details based on state and type. + * @param {Toast.Type} type the type of toast message (Toast.Type.xyz) + * @param {Toast.State} state the state of the progress (Toast.State.xyz) + * @param {string} virtualizationName the name of the virtualization + */ + private setToastNotification( type: Toast.Type, state: Toast.State, virtualizationName: string ): void { + // Set InProgress Toast details + if ( state === Toast.State.InProgress ) { + this.toastNotificationType = NotificationType.INFO; + if ( type === Toast.Type.Download ) { + this.toastNotificationHeader = "Downloading: "; + this.toastNotificationMessage = "Downloading " + virtualizationName + "..."; + } else if ( type === Toast.Type.Publish ) { + this.toastNotificationHeader = "Publishing: "; + this.toastNotificationMessage = "Publishing " + virtualizationName + "..."; + } else if ( type === Toast.Type.NewVirtualization ) { + this.toastNotificationHeader = "Creating: "; + this.toastNotificationMessage = "Creating " + virtualizationName + "..."; + } + // Set Successful Toast details + } else if ( state === Toast.State.Successful ) { + this.toastNotificationType = NotificationType.SUCCESS; + if ( type === Toast.Type.Download ) { + this.toastNotificationHeader = "Download Succeeded: "; + this.toastNotificationMessage = " " + virtualizationName + " was downloaded successfully!"; + } else if ( type === Toast.Type.Publish ) { + this.toastNotificationHeader = "Publishing Started: "; + this.toastNotificationMessage = " " + virtualizationName + " publishing successfully initiated."; + } else if ( type === Toast.Type.NewVirtualization ) { + this.toastNotificationHeader = "Create Succeeded: "; + this.toastNotificationMessage = " " + virtualizationName + " was created successfully!"; + } + // Set Failed Toast details + } else if ( state === Toast.State.Failed ) { + this.toastNotificationType = NotificationType.DANGER; + if ( type === Toast.Type.Download ) { + this.toastNotificationHeader = "Download Failed: "; + this.toastNotificationMessage = " Failed to download dataservice " + virtualizationName; + } else if ( type === Toast.Type.Publish ) { + this.toastNotificationHeader = "Publishing Failed: "; + this.toastNotificationMessage = " Failed to publish dataservice " + virtualizationName + "."; + } else if ( type === Toast.Type.NewVirtualization ) { + this.toastNotificationHeader = "Create Failed: "; + this.toastNotificationMessage = " Failed to create dataservice " + virtualizationName; + } + } + } + public onPublish(svcName: string): void { const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); const virtual: Virtualization = new Virtualization(selectedService.getServiceVdbName(), PublishState.SUBMITTED); selectedService.setServiceVirtualization(virtual); this.closeLookPanels(); - this.exportNotificationHeader = this.exportInProgressHeader; - this.exportNotificationMessage = "Publishing " + svcName + "..."; - this.exportNotificationType = NotificationType.INFO; - this.exportNotificationVisible = true; + this.setToastNotification(Toast.Type.Publish, Toast.State.InProgress, svcName); + this.toastNotificationVisible = true; this.logger.debug("[DataservicesPageComponent] Publishing Dataservice: " + svcName); const self = this; this.dataserviceService .publishDataservice(svcName) .subscribe( (status) => { - self.exportNotificationHeader = this.exportSuccessHeader; - self.exportNotificationMessage = " " + svcName + " publishing successfully initiated."; - self.exportNotificationType = NotificationType.INFO; + self.setToastNotification(Toast.Type.Publish, Toast.State.Successful, svcName); // Dismiss toast notification after 8 sec - setTimeout(() => self.exportNotificationVisible = false, 8000); + setTimeout(() => self.toastNotificationVisible = false, 8000); this.logger.debug("[DataservicesPageComponent] Initiated publishing of dataservice"); }, (error) => { - self.exportNotificationHeader = this.exportFailedHeader; - self.exportNotificationMessage = " Failed to publish dataservice " + svcName + "."; - self.exportNotificationType = NotificationType.DANGER; + self.setToastNotification(Toast.Type.Publish, Toast.State.Failed, svcName); // Dismiss toast notification after 8 sec - setTimeout(() => self.exportNotificationVisible = false, 8000); + setTimeout(() => self.toastNotificationVisible = false, 8000); this.logger.error("[DataservicesPageComponent] Publish dataservice " + svcName + " failed."); } ); @@ -563,16 +598,131 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } /** - * Handle request for new Dataservice + * Handle request for new Virtualization */ public onNew(): void { - this.selectionService.setSelectedVirtualization(null); + // Open New Virtualization dialog + const initialState = { + title: ViewEditorI18n.createVirtualizationDialogTitle, + cancelButtonText: ViewEditorI18n.cancelButtonText, + okButtonText: ViewEditorI18n.okButtonText + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(CreateVirtualizationDialogComponent, {initialState}); + modalRef.content.okAction.take(1).subscribe((dialogResult) => { + + // Create the new virtualization and view. + const virtName = dialogResult.getVirtualizationName(); + const virtDescr = dialogResult.getVirtualizationDescription(); + const viewName = dialogResult.getViewName(); + const viewDescr = dialogResult.getViewDescription(); + const viewDefn = new ViewDefinition(); + viewDefn.setName(viewName); + viewDefn.setDescription(viewDescr); + + // Display Toast notification + this.setToastNotification(Toast.Type.NewVirtualization, Toast.State.InProgress, virtName); + this.toastNotificationVisible = true; + + // Create the new virtualization + const newVirtualization = this.dataserviceService.newDataserviceInstance(virtName, virtDescr); + const self = this; + this.dataserviceService + .createDataservice(newVirtualization) + .subscribe( + (wasSuccess) => { + // Set the current virtualization to the newly created virtualization + self.selectVirtualizationCreateView(virtName, viewDefn); + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error creating virtualization: %o", error); + // Display Toast notification + self.setToastNotification(Toast.Type.NewVirtualization, Toast.State.Failed, virtName); + // Dismiss toast notification after 8 sec + setTimeout(() => self.toastNotificationVisible = false, 8000); + } + ); - const link: string[] = [ DataservicesConstants.virtualizationPath ]; - this.logger.debug("[DataservicesPageComponent] Navigating to: %o", link); - this.router.navigate(link).then(() => { - // nothing to do }); + + } + + /* + * Select the specified Dataservice. create a starter view under it + * @param {string} dsName the name of the dataservice + * @param {string} viewDefn the view definition to create + */ + private selectVirtualizationCreateView(virtName: string, viewDefn: ViewDefinition): void { + const self = this; + this.dataserviceService + .getAllDataservices() + .subscribe( + (dataservices) => { + for (const ds of dataservices) { + if (ds.getId() === virtName) { + self.dataserviceService.setSelectedDataservice(ds); + self.selectionService.setSelectedVirtualization(ds); + self.createView(ds, viewDefn); + } + } + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error selecting the virtualization: %o", error); + // Display Toast notification + self.setToastNotification(Toast.Type.NewVirtualization, Toast.State.Failed, virtName); + // Dismiss toast notification after 8 sec + setTimeout(() => self.toastNotificationVisible = false, 8000); + } + ); + } + + private createView(dataservice: Dataservice, viewDefn: ViewDefinition): void { + const selectedDs = this.dataserviceService.getSelectedDataservice(); + let editorId = ""; + if ( selectedDs || selectedDs !== null ) { + editorId = this.getEditorStateId(selectedDs, viewDefn); + } + + // Create new editor state to save + const editorState = new ViewEditorState(); + editorState.setId(editorId); + editorState.setViewDefinition(viewDefn); + + const virtName = selectedDs.getId(); + const self = this; + this.dataserviceService + .saveViewEditorStateRefreshViews(editorState, selectedDs.getId()) + .subscribe( + (wasSuccess) => { + // Dismiss toast since navigating away + self.toastNotificationVisible = false; + + // transfer control to the viewEditor + const link: string[] = [ DataservicesConstants.viewPath ]; + this.logger.debug("[DataservicesPageComponent] Navigating to: %o", link); + this.router.navigate(link).then(() => { + // nothing to do + }); + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error saving the editor state: %o", error); + // Display Toast notification + self.setToastNotification(Toast.Type.NewVirtualization, Toast.State.Failed, virtName); + // Dismiss toast notification after 8 sec + setTimeout(() => self.toastNotificationVisible = false, 8000); + } + ); + } + + /** + * Construct id for the editor state + * @param {Dataservice} dataservice the dataservice + * @param {ViewDefinition} viewDefn the view definition + * @returns {string} the ID used to persist the editor state + */ + private getEditorStateId(dataservice: Dataservice, viewDefn: ViewDefinition): string { + return dataservice.getServiceVdbName().toLowerCase() + "." + viewDefn.getName(); } /** @@ -588,7 +738,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn // Sets the selected dataservice and edit mode before transferring this.selectionService.setSelectedVirtualization(selectedService); - const link: string[] = [ DataservicesConstants.virtualizationPath ]; + const link: string[] = [ DataservicesConstants.viewPath ]; this.logger.debug("[DataservicesPageComponent] Navigating to: %o", link); this.router.navigate(link).then(() => { // nothing to do @@ -715,8 +865,6 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn match = item.getId().match(filter.value) !== null; } else if (filter.field.id === "description") { match = item.getDescription().match(filter.value) !== null; - } else if (filter.field.id === "view") { - match = item.getViews() === filter.value; } return match; } @@ -821,3 +969,19 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.odataSvcName = svcName; } } + +/** + * Internal enums for Toast Notifications + */ +export namespace Toast { + export enum State { + InProgress, + Successful, + Failed + } + export enum Type { + Download, + Publish, + NewVirtualization + } +} diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 52231ea8..29612eae 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -67,14 +67,13 @@ import { WizardModule } from "patternfly-ng"; import { OdataControlComponent } from "./odata-control/odata-control.component"; import { AccordionModule, BsDropdownModule, TabsModule, TooltipModule } from 'ngx-bootstrap'; -import { ViewCardComponent } from "./virtualization/view-cards/view-card/view-card.component"; -import { ViewCardsComponent } from "./virtualization/view-cards/view-cards.component"; -import { VirtualizationComponent } from "./virtualization/virtualization.component"; import { ConnectionTreeSelectorComponent } from './virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component'; import { ConnectionTableDialogComponent } from './virtualization/view-editor/connection-table-dialog/connection-table-dialog.component'; import { ProgressDialogComponent } from "@shared/progress-dialog/progress-dialog.component"; import { ViewPropertyEditorsComponent } from './virtualization/view-editor/view-property-editors/view-property-editors.component'; import { AddCompositionWizardComponent } from './virtualization/view-editor/add-composition-wizard/add-composition-wizard.component'; +import { CreateViewDialogComponent } from './virtualization/view-editor/create-view-dialog/create-view-dialog.component'; +import { CreateVirtualizationDialogComponent } from './create-virtualization-dialog/create-virtualization-dialog.component'; @NgModule({ imports: [ @@ -118,9 +117,6 @@ import { AddCompositionWizardComponent } from './virtualization/view-editor/add- ViewPreviewComponent, ViewEditorHeaderComponent, ViewCanvasComponent, - VirtualizationComponent, - ViewCardsComponent, - ViewCardComponent, MessageLogComponent, EditorViewsComponent, ConnectionTreeSelectorComponent, @@ -129,7 +125,9 @@ import { AddCompositionWizardComponent } from './virtualization/view-editor/add- GraphVisualComponent, NodeVisualComponent, LinkVisualComponent, - AddCompositionWizardComponent + AddCompositionWizardComponent, + CreateViewDialogComponent, + CreateVirtualizationDialogComponent ], providers: [ { @@ -151,7 +149,8 @@ import { AddCompositionWizardComponent } from './virtualization/view-editor/add- ], exports: [ ], - entryComponents: [AddCompositionWizardComponent, ConfirmDialogComponent, ConnectionTableDialogComponent, ProgressDialogComponent] + entryComponents: [AddCompositionWizardComponent, ConfirmDialogComponent, ConnectionTableDialogComponent, + CreateViewDialogComponent, CreateVirtualizationDialogComponent, ProgressDialogComponent] }) export class DataservicesModule { } diff --git a/ngapp/src/app/dataservices/shared/composition.model.ts b/ngapp/src/app/dataservices/shared/composition.model.ts index 442dabc6..373b8f01 100644 --- a/ngapp/src/app/dataservices/shared/composition.model.ts +++ b/ngapp/src/app/dataservices/shared/composition.model.ts @@ -205,6 +205,24 @@ export class Composition { } } + /** + * Determine if the supplied Composition is equal to this + * @param {Object} values + */ + public isEqual( otherComp: Composition ): boolean { + let equal = false; + if (this.getName() === otherComp.getName() && + this.getLeftSourcePath() === otherComp.getLeftSourcePath() && + this.getRightSourcePath() === otherComp.getRightSourcePath() && + this.getLeftCriteriaColumn() === otherComp.getLeftCriteriaColumn() && + this.getRightCriteriaColumn() === otherComp.getRightCriteriaColumn() && + this.getType() === otherComp.getType() && + this.getOperator() === otherComp.getOperator() ) { + equal = true; + } + return equal; + } + /** * Set all object values using the supplied View json * @param {Object} values diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 796b41c1..73b53057 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -105,7 +105,10 @@ export class Dataservice implements Identifiable< string > { * @returns {string} the dataservice Vdb name (can be null) */ public getServiceVdbName(): string { - return this.serviceVdbName; + if (this.serviceVdbName && this.serviceVdbName !== null) { + return this.serviceVdbName; + } + return ""; } /** @@ -126,6 +129,19 @@ export class Dataservice implements Identifiable< string > { return []; } + /** + * Remove the specified view name, if it exists + * @param {string} viewNameToRemove the view name to remove + */ + public removeServiceViewName( viewNameToRemove: string ): void { + const index = this.serviceViewDefinitions.findIndex( ( viewName ) => + viewName === viewNameToRemove ); + + if ( index !== -1 ) { + this.serviceViewDefinitions.splice( index, 1 ); + } + } + /** * @returns {string} the dataservice view model name (can be null) */ diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index d98d3497..1d14e149 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -670,8 +670,7 @@ export class DataserviceService extends ApiService { return this.http.get(environment.viewEditorState + "/" + editorId, this.getAuthRequestOptions() ) .map( ( response ) => { const editorState = response.json(); - const viewEditorState = ViewEditorState.create(editorState); - return Observable.of( viewEditorState ); + return ViewEditorState.create(editorState); } ) .catch( ( error ) => { // no editor state found diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ngapp/src/app/dataservices/shared/dataservices-constants.ts index 24b480c8..d9216686 100644 --- a/ngapp/src/app/dataservices/shared/dataservices-constants.ts +++ b/ngapp/src/app/dataservices/shared/dataservices-constants.ts @@ -24,14 +24,8 @@ export class DataservicesConstants { public static readonly dataserviceRestPath = "/dataservice"; public static readonly dataservicesRestPath = "/dataservices"; - public static readonly addDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/add-virtualization"; - public static readonly addDataservicePath = DataservicesConstants.dataservicesRootPath + "/add-virtualization"; - - public static readonly virtualizationRoute = DataservicesConstants.dataservicesRootRoute + "/virtualization"; - public static readonly virtualizationPath = DataservicesConstants.dataservicesRootPath + "/virtualization"; - - public static readonly viewRoute = DataservicesConstants.virtualizationRoute + "/view"; - public static readonly viewPath = DataservicesConstants.virtualizationPath + "/view"; + public static readonly viewRoute = DataservicesConstants.dataservicesRootRoute + "/view"; + public static readonly viewPath = DataservicesConstants.dataservicesRootPath + "/view"; public static readonly testDataserviceRoute = DataservicesConstants.dataservicesRootRoute + "/test-virtualization"; public static readonly testDataservicePath = DataservicesConstants.dataservicesRootPath + "/test-virtualization"; diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 4fea7724..4ae48741 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -42,6 +42,7 @@ export class MockDataserviceService extends DataserviceService { private readonly services: Dataservice[]; private readonly queryResults: QueryResults; private editorViewStateMap = new Map(); + private selectedDs: Dataservice; constructor(http: Http, vdbService: VdbService, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { @@ -56,6 +57,12 @@ export class MockDataserviceService extends DataserviceService { this.queryResults = testDataService.getQueryResults(); this.editorViewStateMap = testDataService.getViewEditorStateMap(); + + // set selected dataservice, so it's not empty + const ds = new Dataservice(); + ds.setId("testDs"); + ds.setServiceVdbName("testDsVdb"); + this.setSelectedDataservice(ds); } /** @@ -94,6 +101,22 @@ export class MockDataserviceService extends DataserviceService { return Observable.of( true ); } + /** + * Set the current Dataservice selection + * @param {Dataservice} service the Dataservice + */ + public setSelectedDataservice(service: Dataservice): void { + this.selectedDs = service; + } + + /** + * Get the current Dataservice selection + * @returns {Dataservice} the selected Dataservice + */ + public getSelectedDataservice( ): Dataservice { + return this.selectedDs; + } + /** * Get the view definitions for the selected Dataservice * @returns {ViewDefinition[]} the view definitions @@ -228,4 +251,13 @@ export class MockDataserviceService extends DataserviceService { return Observable.of(true); } + /** + * @param {string} editorId the ID of the editor state being deleted + * @param {string} dataserviceName the name of the dataservice + * @returns {Observable} `true` if the editor state was successfully saved + */ + public deleteViewEditorStateRefreshViews( editorId: string, dataserviceName: string ): Observable< boolean > { + return Observable.of(true); + } + } diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index 79192380..679e5fb2 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -178,4 +178,39 @@ export class MockVdbService extends VdbService { return Observable.of(true); } + /** + * Validates the specified view name within the specified vdb model. If the name contains valid characters + * and the name is unique, the service returns 'null'. Otherwise, a 'string' containing an error message is returned. + * + * @param {string} vdbName the vdb name + * @param {string} modelName the model name + * @param {string} viewName the view name + * @returns {Observable} + */ + public isValidViewName( vdbName: string, modelName: string, viewName: string ): Observable< string > { + // Check that valid names were supplied + // if ( !vdbName || vdbName.length === 0 ) { + // return Observable.of( "VDB name cannot be empty" ); + // } + if ( !modelName || modelName.length === 0 ) { + return Observable.of( "Model name cannot be empty" ); + } + if ( !viewName || viewName.length === 0 ) { + return Observable.of( "View name cannot be empty" ); + } + + // just implement a case where no special characters allowed + for ( let i = 0; i < viewName.length; i++ ) { + const c = viewName.charAt( i ); + + // special characters have the same upper and lower case values + if ( c.toUpperCase() === c.toLowerCase() ) { + return Observable.of( "No special characters allowed" ); + } + } + + // valid + return Observable.of( "" ); + } + } diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ngapp/src/app/dataservices/shared/vdb.service.ts index 7c1f2a43..c8fc0aec 100644 --- a/ngapp/src/app/dataservices/shared/vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/vdb.service.ts @@ -16,7 +16,7 @@ */ import { Injectable } from "@angular/core"; -import { Http, RequestOptions } from "@angular/http"; +import { Http } from "@angular/http"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -31,7 +31,6 @@ import { environment } from "@environments/environment"; import { Observable } from "rxjs/Rx"; import { Subscription } from "rxjs/Subscription"; import { QueryResults } from "@dataservices/shared/query-results.model"; -import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; @Injectable() /** @@ -158,7 +157,8 @@ export class VdbService extends ApiService { return Observable.of( "View name cannot be empty" ); } - const url = environment.komodoWorkspaceUrl + "/vdbs/" + vdbName + "/Models/" + modelName + "Views/nameValidation/" + encodeURIComponent( name ); + const url = environment.komodoWorkspaceUrl + "/vdbs/" + vdbName + "/Models/" + modelName + + "/Views/nameValidation/" + encodeURIComponent( viewName ); return this.http.get( url, this.getAuthRequestOptions() ) .map( ( response ) => { diff --git a/ngapp/src/app/dataservices/shared/view-definition.model.ts b/ngapp/src/app/dataservices/shared/view-definition.model.ts index 0a179915..270a1a61 100644 --- a/ngapp/src/app/dataservices/shared/view-definition.model.ts +++ b/ngapp/src/app/dataservices/shared/view-definition.model.ts @@ -26,10 +26,11 @@ import { CompositionType } from "@dataservices/shared/composition-type.enum"; */ export class ViewDefinition { private viewName: string; - private keng__description: string; + private keng__description = ""; private isEditable = false; private sourcePaths: string[] = []; private compositions: Composition[] = []; + private isSelected = false; /** * @param {Object} json the JSON representation of a ViewDefinition @@ -92,7 +93,7 @@ export class ViewDefinition { * @param {string} description the view description */ public setDescription( description?: string ): void { - this.keng__description = description ? description : null; + this.keng__description = description ? description : ""; } /** @@ -330,6 +331,61 @@ export class ViewDefinition { return connectionName.toLowerCase() + VdbsConstants.SCHEMA_MODEL_SUFFIX + "." + sourceNodeName; } + /** + * @returns {boolean} 'true' if ViewDefinition isSelected + */ + public get selected(): boolean { + return this.isSelected; + } + + /** + * @param {boolean} selected the ViewDefinition isSelected state + */ + public setSelected( selected: boolean ): void { + this.isSelected = selected; + } + + /** + * Determine if the supplied ViewDefinition is equal to this + * @param {Object} values + */ + public isEqual( otherView: ViewDefinition ): boolean { + let equal = false; + if (this.getName() === otherView.getName() && + this.getDescription() === otherView.getDescription() && + this.pathsEqual(this.getSourcePaths(), otherView.getSourcePaths()) && + this.compositionsEqual(this.getCompositions(), otherView.getCompositions()) ) { + equal = true; + } + return equal; + } + + private pathsEqual(left: string[], right: string[]): boolean { + if (left === right) return true; + if (left == null || right == null) return false; + if (left.length !== right.length) return false; + + left.sort(); + right.sort(); + for (let i = 0; i < right.length; ++i) { + if (left[i] !== right[i]) return false; + } + return true; + } + + private compositionsEqual(left: Composition[], right: Composition[]): boolean { + if (left === right) return true; + if (left == null || right == null) return false; + if (left.length !== right.length) return false; + + left.sort(); + right.sort(); + for (let i = 0; i < right.length; ++i) { + if (!left[i].isEqual(right[i])) return false; + } + return true; + } + /** * Set all object values using the supplied ViewDefinition json * @param {Object} values diff --git a/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.css b/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.css deleted file mode 100644 index fe51ba96..00000000 --- a/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.css +++ /dev/null @@ -1,4 +0,0 @@ -.sources-indent { - margin-top: 7px; - margin-left: 10px; -} diff --git a/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.html b/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.html deleted file mode 100644 index f6285a38..00000000 --- a/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.html +++ /dev/null @@ -1,60 +0,0 @@ - - -
    -
    - - -
    - - - - - - - - -
    - -
    -
    - - {{ view.getDescription() }} - -
    -
      {{sourceStr}}
    -
    -
    -
    [No sources defined]
    -
    -
    -
    -
    -
    diff --git a/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.spec.ts deleted file mode 100644 index 5ff8692d..00000000 --- a/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ViewCardComponent } from './view-card.component'; -import { - ActionModule, - CardModule, - EmptyStateModule, - FilterModule, - ListModule, - NotificationModule, - SortModule, - TableModule, - WizardModule } from "patternfly-ng"; -import { RouterTestingModule } from "@angular/router/testing"; -import { LoggerService } from "@core/logger.service"; -import { ViewDefinition } from "@dataservices/shared/view-definition.model"; - -describe('ViewCardComponent', () => { - let component: ViewCardComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ViewCardComponent ], - imports: [ - ActionModule, - CardModule, - EmptyStateModule, - FilterModule, - ListModule, - NotificationModule, - SortModule, - TableModule, - WizardModule, - RouterTestingModule - ], - providers: [ - LoggerService - ] - }) - .compileComponents().then(() => { - // nothing to do - }); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ViewCardComponent); - component = fixture.componentInstance; - - component.view = new ViewDefinition(); - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.ts b/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.ts deleted file mode 100644 index b706690a..00000000 --- a/ngapp/src/app/dataservices/virtualization/view-cards/view-card/view-card.component.ts +++ /dev/null @@ -1,144 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, DoCheck, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from "@angular/core"; -import { Action, ActionConfig, CardAction, CardConfig } from "patternfly-ng"; -import { LoggerService } from "@core/logger.service"; -import { PathUtils } from "@dataservices/shared/path-utils"; -import { ViewDefinition } from "@dataservices/shared/view-definition.model"; - -@Component({ - encapsulation: ViewEncapsulation.None, - selector: "app-view-card", - templateUrl: "./view-card.component.html", - styleUrls: ["./view-card.component.css"] -}) -export class ViewCardComponent implements DoCheck, OnInit { - - public static readonly deleteViewEvent = "delete"; - public static readonly editViewEvent = "edit"; - - public readonly editEvent = ViewCardComponent.editViewEvent; - - @Input() public view: ViewDefinition; - @Input() public selectedViews: ViewDefinition[] = []; - @Output() public cardEvent: EventEmitter< {} > = new EventEmitter< {} >(); - @Output() public selectEvent: EventEmitter< ViewDefinition > = new EventEmitter< ViewDefinition >(); - - public actionConfig: ActionConfig; - public cardConfig: CardConfig; - public showDetails = false; - - private readonly deleteActionId = "delete"; - private readonly deleteActionIndex = 0; // index in moreActions - - private isLoading = false; - private logger: LoggerService; - - constructor( logger: LoggerService ) { - this.logger = logger; - } - - private get detailsIconStyle(): string { - return this.showDetails ? "fa fa-close card-footer-action-icon" : "fa fa-angle-right card-footer-action-icon"; - } - - /** - * Event handler for when a toolbar kebab action is clicked. - * @param {Action} action the action that was selected. - */ - public handleAction( action: Action ): void { - if ( action.id === this.deleteActionId ) { - this.onClick( ViewCardComponent.deleteViewEvent ); - } else { - this.logger.error( "Action '" + action.id + "' not handled." ); - } - } - - /** - * @returns {boolean} `true` if the connection represented by this card is selected - */ - public isSelected(): boolean { - return this.selectedViews.indexOf( this.view ) !== -1; - } - - public ngDoCheck(): void { - this.actionConfig.moreActions[ this.deleteActionIndex ].disabled = this.isLoading; - // this.cardConfig.action.iconStyleClass = this.detailsIconStyle; - } - - /** - * Initializes the ActionConfig, CardConfig, and ListConfig. - */ - public ngOnInit(): void { - this.actionConfig = { - primaryActions: [ - ], - moreActions: [ - { - id: this.deleteActionId, - disabled: !this.view.editable, - title: "Delete", - tooltip: "Delete" - } - ] - } as ActionConfig; - - this.cardConfig = { - // action: { - // id: "showDetails", - // hypertext: this.showDetailsTitle, - // iconStyleClass: this.detailsIconStyle - // }, - titleBorder: true, - noPadding: true, - topBorder: false - } as CardConfig; - } - - /** - * An event handler for when a toolbar action is invoked. - * @param {string} type the type of event being processed - */ - public onClick( type: string ): void { - this.cardEvent.emit( { eventType: type, viewName: this.view.getName() } ); - } - - /** - * An event handler for when the card is clicked. - */ - public onSelect(): void { - this.selectEvent.emit( this.view ); - } - - /** - * Returns display text array for the selected view sources - * @returns {string} - */ - public get sourceTablesText(): string[] { - const sourceTextArray: string[] = []; - const sourcePaths = this.view.getSourcePaths(); - if (sourcePaths && sourcePaths.length > 0) { - for (const path of sourcePaths) { - const sourceText = "[" + PathUtils.getConnectionName(path) + "]: " + PathUtils.getSourceName(path); - sourceTextArray.push(sourceText); - } - } - return sourceTextArray; - } - -} diff --git a/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.css b/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.css deleted file mode 100644 index 89f54e0d..00000000 --- a/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.css +++ /dev/null @@ -1,4 +0,0 @@ -.views-container { - height: 90vh; - overflow: auto; -} diff --git a/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.html b/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.html deleted file mode 100644 index c49d8f19..00000000 --- a/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.html +++ /dev/null @@ -1,8 +0,0 @@ -
    -
    - -
    -
    diff --git a/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.spec.ts deleted file mode 100644 index d5480bc7..00000000 --- a/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from "@angular/router/testing"; -import { LoggerService } from "@core/logger.service"; -import { ViewCardsComponent } from "@dataservices/virtualization/view-cards/view-cards.component"; -import { ViewCardComponent } from "@dataservices/virtualization/view-cards/view-card/view-card.component"; -import { - ActionModule, - CardModule, - EmptyStateModule, - FilterModule, - ListModule, - NotificationModule, - SortModule, - TableModule, - WizardModule } from "patternfly-ng"; - -describe('ViewCardsComponent', () => { - let component: ViewCardsComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - ViewCardsComponent, - ViewCardComponent - ], - imports: [ - ActionModule, - CardModule, - EmptyStateModule, - FilterModule, - ListModule, - NotificationModule, - SortModule, - TableModule, - WizardModule, - RouterTestingModule - ], - providers: [ - LoggerService - ] - }) - .compileComponents().then(() => { - // nothing to do - }); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ViewCardsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.ts b/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.ts deleted file mode 100644 index 97aa2ca3..00000000 --- a/ngapp/src/app/dataservices/virtualization/view-cards/view-cards.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, EventEmitter, Input, Output } from "@angular/core"; -import { ViewCardComponent } from "@dataservices/virtualization/view-cards/view-card/view-card.component"; -import { LoggerService } from "@core/logger.service"; -import { ViewDefinition } from "@dataservices/shared/view-definition.model"; - -@Component({ - moduleId: module.id, - selector: "app-view-cards", - templateUrl: "view-cards.component.html", - styleUrls: ["view-cards.component.css"] -}) -export class ViewCardsComponent { - - @Input() public views: ViewDefinition[]; - @Input() public selectedViews: ViewDefinition[]; - - @Output() public viewSelected: EventEmitter = new EventEmitter(); - @Output() public viewDeselected: EventEmitter = new EventEmitter(); - @Output() public deleteView: EventEmitter = new EventEmitter(); - @Output() public editView: EventEmitter = new EventEmitter(); - - public logger: LoggerService; - - /** - * @param {LoggerService} logger the logging service - */ - constructor( logger: LoggerService ) { - this.logger = logger; - } - - public isSelected( view: ViewDefinition ): boolean { - return this.selectedViews.indexOf( view ) !== -1; - } - - public onCardEvent( event: { eventType: string, - viewName: string } ): void { - switch ( event.eventType ) { - case ViewCardComponent.deleteViewEvent: - this.deleteView.emit( event.viewName ); - break; - case ViewCardComponent.editViewEvent: - this.editView.emit( event.viewName ); - break; - default: - this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); - break; - } - } - - public onSelectEvent( view: ViewDefinition ): void { - this.viewSelected.emit( view ); - } - -} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts index 8d27c27e..b4327c2d 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts @@ -66,7 +66,9 @@ export class AddCompositionWizardComponent implements OnInit { public readonly currentSelectionMsg = ViewEditorI18n.currentSelection; public selectedCompositionType: CompositionType = CompositionType.INNER_JOIN; public selectedCompositionCondition: CompositionOperator = CompositionOperator.EQ; - public swapButtonText = ViewEditorI18n.addCompositionWizardSwapButtonText; + public readonly columnLoadFailedHeader = "Loading Failed: "; + public readonly columnLoadFailedMsg = "Columns failed to load!"; + public readonly columnLoadFailedType = NotificationType.DANGER; private selectedTreeNodePath: string; @@ -76,9 +78,6 @@ export class AddCompositionWizardComponent implements OnInit { private readonly connectionService: ConnectionService; private composition: Composition; private columnsMap = new Map(); // Maintain loaded columns map to reduce rest calls - private readonly columnLoadFailedHeader = "Loading Failed: "; - private readonly columnLoadFailedMsg = "Columns failed to load!"; - private readonly columnLoadFailedType = NotificationType.DANGER; constructor( connectionService: ConnectionService, logger: LoggerService ) { this.connectionService = connectionService; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.html new file mode 100644 index 00000000..263ccd76 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.html @@ -0,0 +1,30 @@ + + + diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts new file mode 100644 index 00000000..c5097ce6 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts @@ -0,0 +1,51 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CreateViewDialogComponent } from './create-view-dialog.component'; +import { HttpModule } from "@angular/http"; +import { BsModalRef, ModalModule } from "ngx-bootstrap"; +import { + ActionModule, + NotificationModule +} from "patternfly-ng"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; + +describe('CreateViewDialogComponent', () => { + let component: CreateViewDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + HttpModule, + FormsModule, + ReactiveFormsModule, + ModalModule.forRoot(), + ActionModule, + NotificationModule + ], + declarations: [ CreateViewDialogComponent ], + providers: [ AppSettingsService, BsModalRef, LoggerService, NotifierService, + { provide: DataserviceService, useClass: MockDataserviceService }, + { provide: VdbService, useClass: MockVdbService } + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateViewDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts new file mode 100644 index 00000000..a51eec6f --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts @@ -0,0 +1,164 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit } from "@angular/core"; +import { Output } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { BsModalRef } from "ngx-bootstrap"; +import { LoggerService } from "@core/logger.service"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { AbstractControl, FormControl, FormGroup } from "@angular/forms"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { ViewDefinition } from "@dataservices/shared/view-definition.model"; + +@Component({ + selector: "app-create-view-dialog", + templateUrl: "./create-view-dialog.component.html", + styleUrls: ["./create-view-dialog.component.css"] +}) +/** + * CreateView Dialog. Invoke this from another component as follows: + * + * this.modalRef = this.modalService.show(CreateViewDialogComponent, {initialState}); + * this.modalRef.content.okAction.take(1).subscribe((selectedNodes) => { + * // do something with array of selected nodes - selectedNodes - SchemaNode[] + * }); + * + * The expected initial state is as follows: + * const initialState = { + * title: "The dialog title", + * cancelButtonText: "Text for cancel button", + * confirmButtonText: "Text for confirm button" + * }; + */ +export class CreateViewDialogComponent implements OnInit { + + @Output() public okAction: EventEmitter = new EventEmitter(); + + public readonly title = ViewEditorI18n.createViewDialogTitle; + public readonly message = ViewEditorI18n.createViewDialogMessage; + public readonly cancelButtonText = ViewEditorI18n.cancelButtonText; + public readonly okButtonText = ViewEditorI18n.okButtonText; + public okButtonEnabled = false; + public bsModalRef: BsModalRef; + public nameValidationError = ""; + public viewPropertyForm: FormGroup; + + private loggerService: LoggerService; + private dataserviceService: DataserviceService; + private vdbService: VdbService; + private serviceVdbName = ""; + + constructor(bsModalRef: BsModalRef, logger: LoggerService, + dataserviceService: DataserviceService, vdbService: VdbService) { + this.bsModalRef = bsModalRef; + this.loggerService = logger; + this.dataserviceService = dataserviceService; + const dService = this.dataserviceService.getSelectedDataservice(); + if ( dService && dService !== null ) { + this.serviceVdbName = dService.getServiceVdbName(); + } + this.vdbService = vdbService; + this.createViewPropertyForm(); + } + + public ngOnInit(): void { + this.viewPropertyForm.controls["name"].setValue(""); + this.viewPropertyForm.controls["description"].setValue(""); + } + + /* + * Creates the view property form + */ + private createViewPropertyForm(): void { + this.viewPropertyForm = new FormGroup({ + name: new FormControl( "", this.handleNameChanged.bind( this ) ), + description: new FormControl("") + }); + // Responds to basic property changes - updates the page status + this.viewPropertyForm.valueChanges.subscribe((val) => { + // this.updatePage2aValidStatus( ); + }); + } + + /** + * Handler for view name changes. + * @param {AbstractControl} input + */ + public handleNameChanged( input: AbstractControl ): void { + const self = this; + + this.vdbService.isValidViewName( this.serviceVdbName, "views", input.value ).subscribe( + ( errorMsg ) => { + if ( errorMsg ) { + // only update if error has changed + if ( errorMsg !== self.nameValidationError ) { + self.nameValidationError = errorMsg; + } + } else { // name is valid + self.nameValidationError = ""; + } + self.setOkButtonEnablement(); + }, + ( error ) => { + self.loggerService.error( "[handleNameChanged] Error: %o", error ); + self.nameValidationError = "Error validating view name"; + self.setOkButtonEnablement(); + } ); + } + + /** + * OK selected. Emit ViewDefinition with the view, then modal is closed + */ + public onOkSelected(): void { + const theName = this.viewPropertyForm.controls["name"].value; + const theDescr = this.viewPropertyForm.controls["description"].value; + + const viewDefn = new ViewDefinition(); + viewDefn.setName(theName); + viewDefn.setDescription(theDescr); + this.okAction.emit(viewDefn); + this.bsModalRef.hide(); + } + + /** + * Cancel selected. The modal is closed. + */ + public onCancelSelected(): void { + this.bsModalRef.hide(); + } + + /* + * Return the name valid state + */ + public get nameValid(): boolean { + return this.nameValidationError == null || this.nameValidationError.length === 0; + } + + /** + * Sets the OK button enablement, based upon the selections + */ + private setOkButtonEnablement(): void { + if (this.nameValid) { + this.okButtonEnabled = true; + } else { + this.okButtonEnabled = false; + } + } + +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts index 46b288eb..423a742f 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts @@ -163,6 +163,10 @@ export class CanvasService { return this.canvasGraph.links; } + public clear(): void { + this.canvasGraph.clear(); + } + /** * Makes sure both the canvas graph and the * view are up to date and all events have diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts index 6710a87c..db9058d8 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts @@ -306,6 +306,12 @@ export class CanvasGraph { this.canvasService.update(true); } + public clear(): void { + this._nodes = []; + this._links = []; + this.layout = null; + } + /** * Refreshes / restarts / updates the layout */ diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts index 5ee83839..25135173 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts @@ -65,6 +65,7 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { private editorSubscription: Subscription; private canvasSubscription: Subscription; + private viewNameSaveInProgress: string; constructor( editorService: ViewEditorService, logger: LoggerService, @@ -105,23 +106,26 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { this.initCanvas(viewDefn); } else if ( event.typeIsEditorViewSaveProgressChanged() ) { if ( event.args.length !== 0 ) { - const viewName = this.editorService.getEditorView().getName(); - // Detect changes in view editor save progress if ( event.args[ 0 ] === ViewEditorProgressChangeId.IN_PROGRESS ) { + this.viewNameSaveInProgress = this.editorService.getEditorView().getName(); this.saveViewNotificationHeader = this.viewSaveInProgressHeader; - this.saveViewNotificationMessage = "Saving View '" + viewName + "'..."; + this.saveViewNotificationMessage = this.getViewNotificationMessage(ViewEditorProgressChangeId.IN_PROGRESS, + this.viewNameSaveInProgress); this.saveViewNotificationType = NotificationType.INFO; this.saveViewNotificationVisible = true; } else if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_SUCCESS ) { this.saveViewNotificationHeader = this.viewSaveSuccessHeader; - this.saveViewNotificationMessage = "View '" + viewName + "' save successful"; + this.saveViewNotificationMessage = this.getViewNotificationMessage(ViewEditorProgressChangeId.COMPLETED_SUCCESS, + this.viewNameSaveInProgress); + this.saveViewNotificationType = NotificationType.SUCCESS; // After 8 seconds, the notification is dismissed setTimeout(() => this.saveViewNotificationVisible = false, 8000); } else if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_FAILED ) { this.saveViewNotificationHeader = this.viewSaveFailedHeader; - this.saveViewNotificationMessage = "View '" + viewName + "' save failed"; + this.saveViewNotificationMessage = this.getViewNotificationMessage(ViewEditorProgressChangeId.COMPLETED_FAILED, + this.viewNameSaveInProgress); this.saveViewNotificationType = NotificationType.DANGER; // After 8 seconds, the notification is dismissed setTimeout(() => this.saveViewNotificationVisible = false, 8000); @@ -136,6 +140,24 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { } } + /** + * Generates a view notification message based on the progress type and viewName + * @param {ViewEditorProgressChangeId} viewProgressId the progress type + * @param {string} viewName the view name + */ + private getViewNotificationMessage(viewProgressId: ViewEditorProgressChangeId, viewName: string): string { + let msg = ""; + const viewStr = ( viewName && viewName !== null ) ? "'" + viewName + "'" : ""; + if ( viewProgressId === ViewEditorProgressChangeId.IN_PROGRESS ) { + msg = "View save in progress for " + viewStr; + } else if ( viewProgressId === ViewEditorProgressChangeId.COMPLETED_SUCCESS ) { + msg = "View save SUCCESS for " + viewStr; + } else if ( viewProgressId === ViewEditorProgressChangeId.COMPLETED_FAILED ) { + msg = "View save FAILED for " + viewStr; + } + return msg; + } + private handleCanvasEvent(event: ViewCanvasEvent): void { switch (event.type) { case ViewCanvasEventType.CREATE_SOURCE: @@ -238,6 +260,9 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { * @param {ViewDefinition} viewDefn the ViewDefinition */ private initCanvas( viewDefn: ViewDefinition ): void { + // Make sure canvas is cleared + this.canvasService.clear(); + if (viewDefn && viewDefn !== null) { // ------------------------ // Create the source nodes @@ -265,6 +290,8 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { } } } + + this.canvasService.update(true); } /** diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css index cb288f82..828d08cd 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css @@ -3,11 +3,50 @@ */ #view-editor-header-description-input { max-width: max-content; - min-height: 25px; - min-width: 600px; + min-height: 20px; + min-width: 400px; vertical-align: top; } +.list-pf-container { + -ms-flex-align: start; + align-items: flex-start; + display: -ms-flexbox; + display: flex; + padding: 0; +} + +.view-table-div { + padding-left: 0; + padding-right: 0; + margin-bottom: 5px; + min-height: 70px; + max-height: 70px; + border: 1px inset grey; + overflow-y: auto; +} + +.view-editor-header-name-input { + padding-left: 0; + padding-right: 5px; +} + +.view-editor-header-create-button { + margin-left: 0; + padding-left: 0; + padding-top: 8px; +} + +.view-editor-header-delete-button { + padding-left: 0; + padding-top: 8px; +} + +.view-editor-header-description-area { + padding-left: 0; + margin-left: 0; +} + /* * A div containing an input field in the header. */ @@ -16,6 +55,13 @@ padding: 1px; } +/* + * A type for the header title + */ +.view-editor-header-title { + margin-left: 10px; +} + /* * A type for vertically aligned labels in the header. */ @@ -45,3 +91,20 @@ #view-editor-header-virtualization-name { text-align: left; } + +/* + * Style the empty state component so that it is centered and extends the entire width. + */ +#view-editor-header-table .blank-slate-pf { + background-color: inherit; + min-width: 200px; + border: none; + padding: 0; +} + +/* + * Style text in blank slate for table + */ +#view-editor-header-table h1, .h1 { + font-size: 14px; +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html index 4c89a6a6..10f945a5 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html @@ -3,69 +3,54 @@ -
    - - {{virtualizationName}} - +
    +

    Virtualization Name: '{{virtualizationName}}'

    - -
    - +
    + Views: +
    +
    + +
    - - - - -
    +
    +
    + +
    +
    + +
    +
    - - - -
    - -
    - + + + +
    + {{viewDescriptionLabel}} +
    + diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts index 272b8cc9..21783d23 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts @@ -12,6 +12,9 @@ import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { TableModule } from "patternfly-ng"; +import { SelectionService } from "@core/selection.service"; +import { BsModalService } from "ngx-bootstrap"; describe('ViewEditorHeaderComponent', () => { let component: ViewEditorHeaderComponent; @@ -22,14 +25,17 @@ describe('ViewEditorHeaderComponent', () => { imports: [ FormsModule, HttpModule, - RouterTestingModule + RouterTestingModule, + TableModule ], declarations: [ ViewEditorHeaderComponent ], providers: [ + BsModalService, { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, LoggerService, NotifierService, + SelectionService, { provide: VdbService, useClass: MockVdbService }, ViewEditorService ] diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index 6132374b..07f72cd1 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -24,6 +24,17 @@ import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-ed import { CommandFactory } from "@dataservices/virtualization/view-editor/command/command-factory"; import { Subscription } from "rxjs/Subscription"; import { Command } from "@dataservices/virtualization/view-editor/command/command"; +import { EmptyStateConfig, NgxDataTableConfig, TableConfig } from "patternfly-ng"; +import { ViewDefinition } from "@dataservices/shared/view-definition.model"; +import { BsModalService } from "ngx-bootstrap"; +import { CreateViewDialogComponent } from "@dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { LoadingState } from "@shared/loading-state.enum"; +import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; +import { SelectionService } from "@core/selection.service"; +import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { ViewEditorProgressChangeId } from "@dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum"; @Component({ encapsulation: ViewEncapsulation.None, @@ -34,29 +45,54 @@ import { Command } from "@dataservices/virtualization/view-editor/command/comman export class ViewEditorHeaderComponent implements OnInit, OnDestroy { // used by html - public readonly descriptionLabel = ViewEditorI18n.descriptionLabel; - public readonly descriptionPlaceholder = ViewEditorI18n.descriptionPlaceholder; - public readonly showDescriptionCheckbox = ViewEditorI18n.showDescriptionCheckbox; - public readonly viewNameLabel = ViewEditorI18n.viewNameLabel; - public readonly viewNamePlaceholder = ViewEditorI18n.viewNamePlaceholder; + public readonly viewDescriptionLabel = ViewEditorI18n.viewDescriptionLabel; + public readonly viewDescriptionPlaceholder = ViewEditorI18n.viewDescriptionPlaceholder; + + public ngxTableConfig: NgxDataTableConfig; + public tableConfig: TableConfig; + public tableColumns: any[] = []; + public tableRows: ViewDefinition[] = []; + private emptyStateConfig: EmptyStateConfig; private readonly logger: LoggerService; private readonly editorService: ViewEditorService; - public showDescription = false; private subscription: Subscription; + private modalService: BsModalService; + private dataserviceService: DataserviceService; + private selectionService: SelectionService; + private viewsLoadingState: LoadingState = LoadingState.LOADING; + private selectedVirtualization: Dataservice; + private viewSavedUponCompletion: ViewDefinition; constructor( editorService: ViewEditorService, - logger: LoggerService ) { + dataserviceService: DataserviceService, + selectionService: SelectionService, + logger: LoggerService, + modalService: BsModalService) { this.editorService = editorService; + this.dataserviceService = dataserviceService; + this.selectionService = selectionService; this.logger = logger; + this.modalService = modalService; } /** * @param {ViewEditorEvent} event the event being processed */ public handleEditorEvent( event: ViewEditorEvent ): void { - // TODO implement this.logger.debug( "ViewEditorHeaderComponent received event: " + event.toString() ); + + if ( event.typeIsEditorViewSaveProgressChanged() ) { + if ( event.args.length !== 0 ) { + // Detect changes in view editor save progress + if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_SUCCESS || + event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_FAILED ) { + if (this.viewSavedUponCompletion && this.viewSavedUponCompletion !== null) { + this.createNewView(this.viewSavedUponCompletion); + } + } + } + } } /** @@ -71,6 +107,80 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { */ public ngOnInit(): void { this.subscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) ); + + // ---------------------------------- + // View Table configurations + // ---------------------------------- + this.tableColumns = [ + { + draggable: false, + name: "Views", + prop: "viewName", + resizeable: true, + sortable: false, + width: "100" + } + ]; + + this.ngxTableConfig = { + headerHeight: 0, + rowHeight: 20, + reorderable: false, + selectionType: "'single'" + } as NgxDataTableConfig; + + this.emptyStateConfig = { + title: ViewEditorI18n.noViewsFound + } as EmptyStateConfig; + + this.tableConfig = { + emptyStateConfig: this.emptyStateConfig + } as TableConfig; + + // init the available views + this.initViews(); + } + + /* + * Initialize the views for the current dataservice. Makes a rest call to get the ViewEditorStates for the serviceVdb + */ + private initViews( ): void { + this.viewsLoadingState = LoadingState.LOADING; + this.selectedVirtualization = this.dataserviceService.getSelectedDataservice(); + if ( !this.selectedVirtualization || this.selectedVirtualization === null ) { + this.tableRows = []; + } + + const vdbName = this.selectedVirtualization.getServiceVdbName(); + const editorStatesPattern = vdbName.toLowerCase() + "*"; + + const self = this; + this.dataserviceService + .getViewEditorStates(editorStatesPattern) + .subscribe( + (viewEditorStates) => { + const viewDefns: ViewDefinition[] = []; + for ( const viewState of viewEditorStates ) { + const viewDefn = viewState.getViewDefinition(); + if ( viewDefn ) { + viewDefns.push( viewDefn ); + } + } + self.tableRows = viewDefns.sort( (left, right): number => { + if (left.getName() < right.getName()) return -1; + if (left.getName() > right.getName()) return 1; + return 0; + }); + const initialView = (self.tableRows && self.tableRows.length > 0) ? self.tableRows[0] : null; + self.selectView(initialView); + self.viewsLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error updating the views for the virtualization: %o", error); + self.viewsLoadingState = LoadingState.LOADED_INVALID; + self.tableRows = []; + } + ); } /** @@ -123,66 +233,231 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { } /** - * @returns {string} the view name + * @returns {string} the name of the dataservice of the view being edited */ - public get viewName(): string { - if ( this.editorService.getEditorView() ) { - return this.editorService.getEditorView().getName(); + public get virtualizationName(): string { + const virtualization = this.editorService.getEditorVirtualization(); + + if ( virtualization ) { + return virtualization.getId(); } - return ""; + // should always have a virtualization name so shouldn't get here + return "< error >"; } /** - * @param {string} newName the new name of the view + * @returns {string} the description of the dataservice of the view being edited */ - public set viewName( newName: string ) { - if ( this.editorService.getEditorView() ) { - if ( newName !== this.editorService.getEditorView().getName() ) { - const oldName = this.editorService.getEditorView().getName(); - const temp = CommandFactory.createUpdateViewNameCommand( newName, oldName ); + public get virtualizationDescription(): string { + const virtualization = this.editorService.getEditorVirtualization(); - if ( temp instanceof Command ) { - this.editorService.fireViewStateHasChanged( ViewEditorPart.HEADER, temp as Command ); - } else { - const error = temp as Error; - this.logger.error( error.message ); - } - } - } else { - // shouldn't get here as description text input should be disabled if no view being edited - this.logger.error( "Trying to set name but there is no view being edited" ); + if ( virtualization ) { + return virtualization.getDescription(); } + + // should always have a virtualization description so shouldn't get here + return "< error >"; + } + + public get deleteViewButtonEnabled(): boolean { + return ( this.getSelectedView() !== null ); } /** - * Called when text in the view name texteditor changes. - * - * @param {string} newName the new name of the view + * Handles view selection from table + * @param $event */ - public viewNameChanged( newName: string ): void { - this.viewName = newName; + public viewSelectionChanged( $event ): void { + const selectedViews: ViewDefinition[] = $event.selected; + // If the current view has pending changes, auto save it + if ( this.editorService.hasChanges() ) { + this.editorService.saveEditorState(); + } + this.selectView(selectedViews[0]); } /** - * @returns {string} the router link of the virtualization + * Handle creation of a new View. Displays the createView dialog, + * then saves the viewDefinition and adds it to the list */ - public get virtualizationLink(): string { - return this.editorService.getVirtualizationLink(); + public onCreateView(): void { + // Open New View dialog + const initialState = { + title: ViewEditorI18n.createViewDialogTitle, + cancelButtonText: ViewEditorI18n.cancelButtonText, + okButtonText: ViewEditorI18n.okButtonText + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(CreateViewDialogComponent, {initialState}); + modalRef.content.okAction.take(1).subscribe((viewDefn) => { + // If the current view has pending changes, save them first + if ( this.editorService.hasChanges() ) { + this.viewSavedUponCompletion = viewDefn; + this.editorService.saveEditorState(); + } else { + this.createNewView(viewDefn); + } + }); + } + + private createNewView(viewDefn: ViewDefinition): void { + const selectedDs = this.dataserviceService.getSelectedDataservice(); + const editorId = this.getEditorStateId(selectedDs, viewDefn); + + // Create new editor state to save + const editorState = new ViewEditorState(); + editorState.setId(editorId); + editorState.setViewDefinition(viewDefn); + + const dsName = selectedDs.getId(); + const self = this; + this.dataserviceService + .saveViewEditorStateRefreshViews(editorState, selectedDs.getId()) + .subscribe( + (wasSuccess) => { + // Add the new ViewDefinition to the table + self.addViewDefinitionToList(viewDefn); + self.viewSavedUponCompletion = null; + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error saving the editor state: %o", error); + self.viewSavedUponCompletion = null; + } + ); } /** - * @returns {string} the name of the dataservice of the view being edited + * Construct id for the editor state + * @param {Dataservice} dataservice the dataservice + * @param {ViewDefinition} viewDefn the view definition + * @returns {string} the ID used to persist the editor state */ - public get virtualizationName(): string { - const virtualization = this.editorService.getEditorVirtualization(); + private getEditorStateId(dataservice: Dataservice, viewDefn: ViewDefinition): string { + return dataservice.getServiceVdbName().toLowerCase() + "." + viewDefn.getName(); + } - if ( virtualization ) { - return virtualization.getId(); + /** + * Handle Delete of the selected View + * @param {string} viewName + */ + public onDeleteView( ): void { + const viewName = this.getSelectedView().getName(); + + // Dialog Content + const message = "Do you really want to delete View '" + viewName + "'?"; + const initialState = { + title: "Confirm Delete", + bodyContent: message, + cancelButtonText: "Cancel", + confirmButtonText: "Delete" + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); + modalRef.content.confirmAction.take(1).subscribe((value) => { + this.doDeleteView(viewName); + }); + } + + /** + * Deletes the specified ViewEditorState from the userProfile, and removes ViewDefinition from the current list. + * @param {string} viewDefnName the name of the view + */ + private doDeleteView(viewDefnName: string): void { + const selectedViewDefn = this.tableRows.find((x) => x.getName() === viewDefnName); + const selectedDs = this.dataserviceService.getSelectedDataservice(); + const vdbName = selectedDs.getServiceVdbName(); + const editorStateId = vdbName.toLowerCase() + "." + viewDefnName; + const dataserviceName = selectedDs.getId(); + // Note: we can only doDelete selected items that we can see in the UI. + this.logger.debug("[VirtualizationComponent] Deleting selected Virtualization View."); + const self = this; + this.dataserviceService + .deleteViewEditorStateRefreshViews(editorStateId, dataserviceName) + .subscribe( + (wasSuccess) => { + self.removeViewDefinitionFromList(selectedViewDefn); + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error deleting the editor state: %o", error); + } + ); + } + + /* + * Add the specified ViewDefinition to the view definitions table + * @param {ViewDefinition} viewDefn the view definition to add + */ + private addViewDefinitionToList(viewDefn: ViewDefinition): void { + const newRows: ViewDefinition[] = []; + newRows.push(viewDefn); + for ( const row of this.tableRows ) { + if ( row.getName() !== viewDefn.getName() ) { + newRows.push( row ); + } } + this.tableRows = newRows.sort( (left, right): number => { + if (left.getName() < right.getName()) return -1; + if (left.getName() > right.getName()) return 1; + return 0; + }); + this.selectView(viewDefn); + } - // should always have a virtualization name so shouldn't get here - return "< error >"; + /* + * Remove the specified ViewDefinition from the view definitions table + * @param {ViewDefinition} viewDefn the view definition to remove + */ + private removeViewDefinitionFromList(viewDefn: ViewDefinition): void { + const origIndex = this.tableRows.findIndex( ( defn ) => defn.getName() === viewDefn.getName() ); + + const newRows: ViewDefinition[] = []; + for ( const row of this.tableRows ) { + if ( row.getName() !== viewDefn.getName() ) { + newRows.push( row ); + } + } + this.tableRows = newRows; + + // auto select another row + if ( this.tableRows.length > origIndex ) { + this.selectView( this.tableRows[origIndex] ); + } else if ( this.tableRows.length > 0 ) { + this.selectView( this.tableRows[origIndex - 1] ); + } else if ( this.tableRows.length === 0 ) { + this.selectView( null ); + } + } + + private selectView( selView: ViewDefinition ): void { + // Updates table selection display + let viewSelection = null; + if ( selView !== null ) { + for (const view of this.tableRows) { + if (view.getName() === selView.getName()) { + view.setSelected(true); + viewSelection = view; + } else { + view.setSelected(false); + } + } + } + // Update selection service, then fire event + this.selectionService.setSelectedViewDefinition(this.selectedVirtualization, selView); + this.editorService.setEditorView(viewSelection, ViewEditorPart.HEADER); + } + + private getSelectedView( ): ViewDefinition { + let selectedView: ViewDefinition = null; + for (const view of this.tableRows) { + if (view.selected) { + selectedView = view; + break; + } + } + return selectedView; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts index e252e043..962d4b16 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts @@ -38,6 +38,14 @@ export class ViewEditorI18n { public static readonly currentSelection = "Current Selection:"; public static readonly noSelection = "Nothing selected"; + // create virtualization dialog + public static readonly createVirtualizationDialogMessage = "Enter name and optional description for the virtualization and view"; + public static readonly createVirtualizationDialogTitle = "Create Virtualization"; + + // create view dialog + public static readonly createViewDialogMessage = "Enter name and description(optional) for the new view"; + public static readonly createViewDialogTitle = "Create View"; + // Add Composition Wizard public static readonly addCompositionWizardTitle = "Add Composition"; public static readonly addCompositionWizardSelectSourceMessage = "Expand connection and select a source for the composition"; @@ -46,7 +54,6 @@ export class ViewEditorI18n { public static readonly addCompositionWizardStep2Text = "Define Composition"; public static readonly addCompositionWizardLoadingPrimaryText = "Add Composition Wizard loading"; public static readonly addCompositionWizardLoadingSecondaryText = "Please wait for the wizard to finish loading..."; - public static readonly addCompositionWizardSwapButtonText = "Swap"; // editor views public static readonly messagesTabName = "Messages"; @@ -101,11 +108,9 @@ export class ViewEditorI18n { public static readonly warningsActionTooltip = "Show warning messages"; // view editor header - public static readonly descriptionLabel = "Description:"; - public static readonly descriptionPlaceholder = "Enter a view description"; - public static readonly showDescriptionCheckbox = "Show Description"; - public static readonly viewNameLabel = "View Name:"; - public static readonly viewNamePlaceholder = "Enter a view name"; + public static readonly viewDescriptionLabel = "Selected View Description"; + public static readonly viewDescriptionPlaceholder = "Enter a view description"; + public static readonly noViewsFound = "No views found"; // view preview public static readonly previewDataUnavailable = "Preview data unavailable"; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html index efbfdec4..38912bf7 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html @@ -7,8 +7,7 @@
  • -
  • -
  • +
  • diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts index ecbe9c77..40ab593b 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { AfterViewInit, Component, DoCheck, OnDestroy, OnInit, TemplateRef, ViewEncapsulation } from "@angular/core"; +import { Component, DoCheck, OnDestroy, OnInit, TemplateRef, ViewEncapsulation } from "@angular/core"; import { LoggerService } from "@core/logger.service"; import { SelectionService } from "@core/selection.service"; import { Connection } from "@connections/shared/connection.model"; @@ -24,8 +24,6 @@ import { DataservicesConstants } from "@dataservices/shared/dataservices-constan import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event"; -import { Message } from "@dataservices/virtualization/view-editor/editor-views/message-log/message"; -import { Problem } from "@dataservices/virtualization/view-editor/editor-views/message-log/problem"; import { ViewEditorEventType } from "@dataservices/virtualization/view-editor/event/view-editor-event-type.enum"; import { ConnectionTableDialogComponent } from "@dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component"; import { ViewEditorProgressChangeId } from "@dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum"; @@ -41,7 +39,8 @@ import { AddSourcesCommand } from "@dataservices/virtualization/view-editor/comm import { AddCompositionCommand } from "@dataservices/virtualization/view-editor/command/add-composition-command"; import { SchemaNode } from "@connections/shared/schema-node.model"; import { Composition } from "@dataservices/shared/composition.model"; -import { ViewDefinition } from "@dataservices/shared/view-definition.model"; +import { Router } from "@angular/router"; +import { NavigationStart } from "@angular/router"; @Component({ encapsulation: ViewEncapsulation.None, @@ -50,19 +49,19 @@ import { ViewDefinition } from "@dataservices/shared/view-definition.model"; styleUrls: ["./view-editor.component.css"], providers: [ ViewEditorService ] }) -export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit, AfterViewInit { +export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { private actionConfig: ActionConfig; private connections: Connection[] = []; private connectionService: ConnectionService; private readonly editorService: ViewEditorService; - private fatalErrorOccurred = false; - private isNewView = false; private readonly logger: LoggerService; private modalService: BsModalService; + private readonly router: Router; private selectionService: SelectionService; private subscription: Subscription; private saveInProgress = false; + private routeSub: Subscription; public toolbarConfig: ToolbarConfig; public readonly virtualizationsLink = DataservicesConstants.dataservicesRootPath; @@ -104,10 +103,12 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit, AfterVie selectionService: SelectionService, logger: LoggerService, editorService: ViewEditorService, - modalService: BsModalService ) { + modalService: BsModalService, + router: Router ) { this.connectionService = connectionService; this.logger = logger; this.modalService = modalService; + this.router = router; this.selectionService = selectionService; // this is the service that is injected into all the editor parts @@ -115,27 +116,175 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit, AfterVie this.editorService.setEditorVirtualization( selectionService.getSelectedVirtualization() ); } + /** + * Executed by javascript framework when something changes. Used to set then enable state of the toolbar buttons. + */ + public ngDoCheck(): void { + if (this.actionConfig ) { + this.actionConfig.primaryActions[ this.addCompositionActionIndex ].disabled = !this.canAddComposition(); + this.actionConfig.primaryActions[ this.addSourceActionIndex ].disabled = !this.canAddSource(); + this.actionConfig.primaryActions[ this.deleteActionIndex ].disabled = !this.canDelete(); + this.actionConfig.primaryActions[ this.errorsActionIndex ].disabled = !this.hasErrors(); + this.actionConfig.primaryActions[ this.infosActionIndex ].disabled = !this.hasInfos(); + this.actionConfig.primaryActions[ this.redoActionIndex ].disabled = !this.canRedo(); + this.actionConfig.primaryActions[ this.redoActionIndex ].tooltip = this.editorService.getRedoActionTooltip(); + this.actionConfig.primaryActions[ this.saveActionIndex ].disabled = !this.canSave(); + this.actionConfig.primaryActions[ this.undoActionIndex ].disabled = !this.canUndo(); + this.actionConfig.primaryActions[ this.undoActionIndex ].tooltip = this.editorService.getUndoActionTooltip(); + this.actionConfig.primaryActions[ this.warningsActionIndex ].disabled = !this.hasWarnings(); + } + } + + /** + * Cleanup code when destroying the editor. + */ + public ngOnDestroy(): void { + this.subscription.unsubscribe(); + this.routeSub.unsubscribe(); + } + + /** + * Initialization code run after construction. + */ + public ngOnInit(): void { + this.editorService.setEditorConfig( this.fullEditorCssType ); // this could be set via preference or last used config + this.subscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) ); + + this.toolbarConfig = { + views: [ + { + id: this.fullEditorCssType, + iconStyleClass: "fa fa-file-text-o", + tooltip: ViewEditorI18n.showEditorCanvasAndViewsActionTooltip + }, + { + id: this.canvasOnlyCssType, + iconStyleClass: "fa fa-file-image-o", + tooltip: ViewEditorI18n.showEditorCanvasOnlyActionTooltip + }, + { + id: this.viewsOnlyCssType, + iconStyleClass: "fa fa-table", + tooltip: ViewEditorI18n.showEditorViewsOnlyActionTooltip + } + ] + } as ToolbarConfig; + + // Load the connections + const self = this; + this.connectionService + .getConnections(true, true) + .subscribe( + (connectionSummaries) => { + const conns = []; + for ( const connectionSummary of connectionSummaries ) { + const connStatus = connectionSummary.getStatus(); + const conn = connectionSummary.getConnection(); + conn.setStatus(connStatus); + conns.push(conn); + self.connections = conns; + } + }, + (error) => { + // self.logger.error("[ConnectionSchemaTreeComponent] Error getting connections: %o", error); + // self.connectionLoadingState = LoadingState.LOADED_INVALID; + } + ); + + // Listen for event when user moves away from this page + this.routeSub = this.router.events.pairwise().subscribe((event) => { + if (event[1] instanceof NavigationStart) { + if (this.editorService.hasChanges()) { + this.editorService.saveEditorState(); + } + } + }); + } + + /** + * Determine if a view is currently selected + */ + private get hasSelectedView(): boolean { + const selView = this.editorService.getEditorView(); + return (selView && selView !== null); + } + + /** + * @param {ViewEditorEvent} event the event being processed + */ + public handleEditorEvent( event: ViewEditorEvent ): void { + this.logger.debug( "ViewEditorComponent received event: " + event.toString() ); + + if ( event.typeIsShowEditorPart() ) { + if ( event.args.length !== 0 ) { + // make sure the bottom area is showing if part is an additional editor view + if ( ( event.args[ 0 ] === ViewEditorPart.PREVIEW || event.args[ 0 ] === ViewEditorPart.MESSAGE_LOG ) + && !this.isShowingAdditionalViews ) { + this.editorService.setEditorConfig( this.fullEditorCssType ); + } + } + } + else if (event.typeIsCreateSource()) { + if (event.sourceIsCanvas()) { + alert("Multiple compositions not yet supported"); + } else { + this.doAddSource(); + } + } + else if (event.typeIsCreateComposition()) { + this.doAddComposition(event.args); + } + else if (event.typeIsDeleteNode()) { + const selection = []; + selection.push(event.args[0]); + this.doDelete(selection); + } + else if (event.typeIsCanvasSelectionChanged()) { + this.doSelection(event.args); + } + else if ( event.typeIsEditorViewSaveProgressChanged() ) { + if ( event.args.length !== 0 ) { + // Detect changes in view editor save progress + if ( event.args[ 0 ] === ViewEditorProgressChangeId.IN_PROGRESS ) { + this.saveInProgress = true; + } else if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_SUCCESS ) { + this.editorService.updatePreviewResults(); + this.saveInProgress = false; + } else if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_FAILED ) { + this.editorService.setPreviewResults(null, null, ViewEditorPart.EDITOR); + this.saveInProgress = false; + } + } + } + } + private canAddComposition(): boolean { - return !this.fatalErrorOccurred && !this.editorService.isReadOnly() && this.isShowingCanvas && this.canvasSingleSourceSelected; + return this.hasSelectedView && + !this.editorService.isReadOnly() && + this.isShowingCanvas && + this.canvasSingleSourceSelected; } private canAddSource(): boolean { - return !this.fatalErrorOccurred && !this.editorService.isReadOnly() && this.isShowingCanvas; + return this.hasSelectedView && + !this.editorService.isReadOnly() && + this.isShowingCanvas; } private canDelete(): boolean { - return !this.fatalErrorOccurred && - !this.editorService.isReadOnly() && - this.isShowingCanvas && - this.editorService.hasSelection(); + return this.hasSelectedView && + !this.editorService.isReadOnly() && + this.isShowingCanvas && + this.editorService.hasSelection(); } private canRedo(): boolean { - return !this.fatalErrorOccurred && this.editorService.canRedo(); + return this.hasSelectedView && + this.editorService.canRedo(); } private canSave(): boolean { - return !this.fatalErrorOccurred + return this.hasSelectedView && !this.editorService.isReadOnly() && this.editorService.canSaveView() && this.editorService.hasChanges() @@ -143,7 +292,8 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit, AfterVie } private canUndo(): boolean { - return !this.fatalErrorOccurred && this.editorService.canUndo(); + return this.hasSelectedView && + this.editorService.canUndo(); } private doAddComposition(sourcePaths: string[]): void { @@ -461,55 +611,6 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit, AfterVie } } - /** - * @param {ViewEditorEvent} event the event being processed - */ - public handleEditorEvent( event: ViewEditorEvent ): void { - this.logger.debug( "ViewEditorComponent received event: " + event.toString() ); - - if ( event.typeIsShowEditorPart() ) { - if ( event.args.length !== 0 ) { - // make sure the bottom area is showing if part is an additional editor view - if ( ( event.args[ 0 ] === ViewEditorPart.PREVIEW || event.args[ 0 ] === ViewEditorPart.MESSAGE_LOG ) - && !this.isShowingAdditionalViews ) { - this.editorService.setEditorConfig( this.fullEditorCssType ); - } - } - } - else if (event.typeIsCreateSource()) { - if (event.sourceIsCanvas()) { - alert("Multiple compositions not yet supported"); - } else { - this.doAddSource(); - } - } - else if (event.typeIsCreateComposition()) { - this.doAddComposition(event.args); - } - else if (event.typeIsDeleteNode()) { - const selection = []; - selection.push(event.args[0]); - this.doDelete(selection); - } - else if (event.typeIsCanvasSelectionChanged()) { - this.doSelection(event.args); - } - else if ( event.typeIsEditorViewSaveProgressChanged() ) { - if ( event.args.length !== 0 ) { - // Detect changes in view editor save progress - if ( event.args[ 0 ] === ViewEditorProgressChangeId.IN_PROGRESS ) { - this.saveInProgress = true; - } else if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_SUCCESS ) { - this.editorService.updatePreviewResults(); - this.saveInProgress = false; - } else if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_FAILED ) { - this.editorService.setPreviewResults(null, null, ViewEditorPart.EDITOR); - this.saveInProgress = false; - } - } - } - } - private hasErrors(): boolean { return this.errorMsgCount !== 0; } @@ -576,115 +677,4 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit, AfterVie return false; } - /** - * Executed by javascript framework when something changes. Used to set then enable state of the toolbar buttons. - */ - public ngDoCheck(): void { - if (this.actionConfig ) { - this.actionConfig.primaryActions[ this.addCompositionActionIndex ].disabled = !this.canAddComposition(); - this.actionConfig.primaryActions[ this.addSourceActionIndex ].disabled = !this.canAddSource(); - this.actionConfig.primaryActions[ this.deleteActionIndex ].disabled = !this.canDelete(); - this.actionConfig.primaryActions[ this.errorsActionIndex ].disabled = !this.hasErrors(); - this.actionConfig.primaryActions[ this.infosActionIndex ].disabled = !this.hasInfos(); - this.actionConfig.primaryActions[ this.redoActionIndex ].disabled = !this.canRedo(); - this.actionConfig.primaryActions[ this.redoActionIndex ].tooltip = this.editorService.getRedoActionTooltip(); - this.actionConfig.primaryActions[ this.saveActionIndex ].disabled = !this.canSave(); - this.actionConfig.primaryActions[ this.undoActionIndex ].disabled = !this.canUndo(); - this.actionConfig.primaryActions[ this.undoActionIndex ].tooltip = this.editorService.getUndoActionTooltip(); - this.actionConfig.primaryActions[ this.warningsActionIndex ].disabled = !this.hasWarnings(); - } - } - - /** - * Cleanup code when destroying the editor. - */ - public ngOnDestroy(): void { - this.subscription.unsubscribe(); - } - - /** - * Initialization code run after construction. - */ - public ngOnInit(): void { - this.editorService.setEditorConfig( this.fullEditorCssType ); // this could be set via preference or last used config - this.subscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) ); - - this.toolbarConfig = { - views: [ - { - id: this.fullEditorCssType, - iconStyleClass: "fa fa-file-text-o", - tooltip: ViewEditorI18n.showEditorCanvasAndViewsActionTooltip - }, - { - id: this.canvasOnlyCssType, - iconStyleClass: "fa fa-file-image-o", - tooltip: ViewEditorI18n.showEditorCanvasOnlyActionTooltip - }, - { - id: this.viewsOnlyCssType, - iconStyleClass: "fa fa-table", - tooltip: ViewEditorI18n.showEditorViewsOnlyActionTooltip - } - ] - } as ToolbarConfig; - - // Load the connections - const self = this; - this.connectionService - .getConnections(true, true) - .subscribe( - (connectionSummaries) => { - const conns = []; - for ( const connectionSummary of connectionSummaries ) { - const connStatus = connectionSummary.getStatus(); - const conn = connectionSummary.getConnection(); - conn.setStatus(connStatus); - conns.push(conn); - self.connections = conns; - } - }, - (error) => { - // self.logger.error("[ConnectionSchemaTreeComponent] Error getting connections: %o", error); - // self.connectionLoadingState = LoadingState.LOADED_INVALID; - } - ); - - } - - /** - * Lifecycle hook after the component is fully initialized. Need to set viewDefinition here to ensure that the - * child components have been fully intiialized and can receive events - */ - public ngAfterViewInit(): void { - const virtualization = this.editorService.getEditorVirtualization(); - - let selectedViewDefn = this.selectionService.getSelectedViewDefinition(); - if (!selectedViewDefn) { - this.isNewView = true; - selectedViewDefn = new ViewDefinition(); - } - - this.editorService.setOriginalViewName(selectedViewDefn.getName()); - - // must have a virtualization parent - if ( virtualization ) { - this.editorService.setEditorView(selectedViewDefn, ViewEditorPart.EDITOR); - if (!this.isNewView) { - this.editorService.updatePreviewResults(); - } - } else { - // must have a virtualization selected - this.editorService.addMessage( Message.create( Problem.ERR0100 ), ViewEditorPart.EDITOR ); - this.fatalErrorOccurred = true; - } - } - - /** - * @returns {string} the router link of the virtualization - */ - public get virtualizationLink(): string { - return this.editorService.getVirtualizationLink(); - } - } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index c4de7bb6..9d14a675 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -17,7 +17,6 @@ import { EventEmitter, Injectable, Output } from "@angular/core"; import { LoggerService } from "@core/logger.service"; -import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { QueryResults } from "@dataservices/shared/query-results.model"; import { VdbService } from "@dataservices/shared/vdb.service"; @@ -64,12 +63,12 @@ export class ViewEditorService { private _previewSql = null; private _readOnly = false; private _shouldFireEvents = true; - private readonly _undoMgr: UndoManager; + private _undoMgr: UndoManager; private readonly _dataserviceService: DataserviceService; private readonly _vdbService: VdbService; private _warningMsgCount = 0; private _selection: string[] = []; - private _originalViewName = null; + private _originalView: ViewDefinition = null; constructor( logger: LoggerService, dataserviceService: DataserviceService, @@ -303,13 +302,6 @@ export class ViewEditorService { return this._undoMgr.undoLabel(); } - /** - * @returns {string} the router link of the virtualization - */ - public getVirtualizationLink(): string { - return DataservicesConstants.virtualizationPath; - } - /** * @returns {number} the number of warning messages */ @@ -328,8 +320,11 @@ export class ViewEditorService { * @returns {boolean} `true` if the editor has unsaved changes */ public hasChanges(): boolean { - // TODO implement hasChanges - return true; + let hasChanged = false; + if ( this._editorView && this._editorView !== null ) { + hasChanged = !this._editorView.isEqual(this._originalView); + } + return hasChanged; } /** @@ -411,7 +406,7 @@ export class ViewEditorService { } /** - * Saves the current editor state. If a previous state exists, it is deleted first + * Saves the current editor state. */ public saveEditorState(): void { // fire save in progress event @@ -419,35 +414,9 @@ export class ViewEditorService { ViewEditorEventType.EDITOR_VIEW_SAVE_PROGRESS_CHANGED, [ ViewEditorProgressChangeId.IN_PROGRESS ] ) ); - // If a previous view state needs to be deleted, do that first. Then save the new state - if (this._originalViewName && this._originalViewName !== null && this._originalViewName !== this._editorView.getName()) { - // Delete the 'old' view editorState and view first - const oldEditorStateId = this.getEditorStateId(this._originalViewName); - - const self = this; - this._dataserviceService.deleteViewEditorState( oldEditorStateId ).subscribe( () => { - self.saveCurrentState(); - }, () => { - // fire save editor state failed event - this.fire( ViewEditorEvent.create( ViewEditorPart.EDITOR, - ViewEditorEventType.EDITOR_VIEW_SAVE_PROGRESS_CHANGED, - [ ViewEditorProgressChangeId.COMPLETED_FAILED ] ) ); - } - ); - } else { - this.saveCurrentState(); - } - } - - /** - * Saves the current editor's state. - * The ViewEditor state consists of the Undoables array (the current redo stack is not saved), - * plus the current ViewEditorDefinition - */ - private saveCurrentState(): void { // Save the current editorState - this._originalViewName = this._editorView.getName(); - const editorId = this.getEditorStateId(this._originalViewName); + const viewName = this._editorView.getName(); + const editorId = this.getEditorStateId(viewName); // ViewEditorState contains Undoables array plus current ViewDefinition const editorState = new ViewEditorState(); @@ -484,14 +453,6 @@ export class ViewEditorService { } } - /** - * Set the original view name (when editor initialized or last save) - * @param {string} viewName the view name - */ - public setOriginalViewName( viewName: string ): void { - this._originalViewName = viewName; - } - /** * Sets the view being edited. This should only be called once. Subsequent calls are ignored. Fires a * `ViewEditorEventType.VIEW_CHANGED` event having the view definition as an argument. @@ -501,13 +462,14 @@ export class ViewEditorService { */ public setEditorView( viewDefn: ViewDefinition, source: ViewEditorPart ): void { - if ( !this._editorView ) { - this._editorView = viewDefn; - this.fire( ViewEditorEvent.create( source, ViewEditorEventType.EDITED_VIEW_SET, [ this._editorView ] ) ); - // this.restoreUndoables(); + this._editorView = viewDefn; + if ( viewDefn !== null ) { + this._originalView = ViewDefinition.create(viewDefn.toJSON()); } else { - this._logger.debug( "setEditorView called more than once" ); + this._originalView = null; } + this.resetUndoManager(); + this.fire( ViewEditorEvent.create( source, ViewEditorEventType.EDITED_VIEW_SET, [ this._editorView ] ) ); } /** @@ -710,4 +672,11 @@ export class ViewEditorService { public hasSelection(): boolean { return this._selection.length > 0; } + + /** + * Reset the UndoManager + */ + private resetUndoManager(): void { + this._undoMgr = new UndoManager(); + } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-validator.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-validator.ts index d74fdf0d..1a2a6d75 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-validator.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-validator.ts @@ -30,7 +30,10 @@ export class ViewValidator { public static validate( viewDefn: ViewDefinition ): Message[] { const messages: Message[] = []; - if ( viewDefn ) { + if ( !viewDefn || viewDefn === null ) { + messages.push(Message.create( Problem.ERR0110)); + } + else { // View must have a name if ( !viewDefn.getName() || viewDefn.getName().length === 0 ) { messages.push( Message.create( Problem.ERR0110 ) ); diff --git a/ngapp/src/app/dataservices/virtualization/virtualization.component.css b/ngapp/src/app/dataservices/virtualization/virtualization.component.css deleted file mode 100644 index 4d4d2aee..00000000 --- a/ngapp/src/app/dataservices/virtualization/virtualization.component.css +++ /dev/null @@ -1,3 +0,0 @@ -.description-label .control-label { - text-align: left; -} diff --git a/ngapp/src/app/dataservices/virtualization/virtualization.component.html b/ngapp/src/app/dataservices/virtualization/virtualization.component.html deleted file mode 100644 index 64329653..00000000 --- a/ngapp/src/app/dataservices/virtualization/virtualization.component.html +++ /dev/null @@ -1,125 +0,0 @@ -
    -
    - -
  • -
  • -
    -
    -
    -
    -

    Virtualization

    -
    - -
    -
    - -
    - -
    {{ nameValidationError }}
    -
    - - - - - - - -
    -
    - -
    - -
    -
    - - -
    -
    - Add View -
    -
    - - -
    - - -
    -
    -
    - - -
    -
    -
    - - -
    -
    -
    - - -
    -
    -
    - - -
    -
    -
    - - -
    -
    -
    - -
    -
    -
    - - -
    -
    -
    - - The virtualization views failed to load! -
    -
    -
    - - -
    - - -
    -
    - -
    -
    diff --git a/ngapp/src/app/dataservices/virtualization/virtualization.component.spec.ts b/ngapp/src/app/dataservices/virtualization/virtualization.component.spec.ts deleted file mode 100644 index cb05a908..00000000 --- a/ngapp/src/app/dataservices/virtualization/virtualization.component.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { FormsModule, ReactiveFormsModule } from "@angular/forms"; -import { RouterTestingModule } from "@angular/router/testing"; -import { CoreModule } from "@core/core.module"; -import { MockAppSettingsService } from "@core/mock-app-settings.service"; -import { AppSettingsService } from "@core/app-settings.service"; -import { SelectionService } from "@core/selection.service"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; -import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; -import { NotifierService } from "@dataservices/shared/notifier.service"; -import { VdbService } from "@dataservices/shared/vdb.service"; -import { VirtualizationComponent } from "@dataservices/virtualization/virtualization.component"; -import { ViewCardsComponent } from "@dataservices/virtualization/view-cards/view-cards.component"; -import { ViewCardComponent } from "@dataservices/virtualization/view-cards/view-card/view-card.component"; -import { PropertyFormPropertyComponent } from "@shared/property-form/property-form-property/property-form-property.component"; -import { - ActionModule, - CardModule, - EmptyStateModule, - FilterModule, - ListModule, - NotificationModule, - SortModule, - TableModule, - WizardModule } from "patternfly-ng"; - -describe("VirtualizationComponent", () => { - let component: VirtualizationComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - CoreModule, - FormsModule, - ActionModule, - CardModule, - EmptyStateModule, - FilterModule, - ListModule, - NotificationModule, - SortModule, - TableModule, - WizardModule, - ReactiveFormsModule, - RouterTestingModule - ], - declarations: [ - PropertyFormPropertyComponent, - ViewCardComponent, - ViewCardsComponent, - VirtualizationComponent - ], - providers: [ - { provide: AppSettingsService, useClass: MockAppSettingsService }, - { provide: DataserviceService, useClass: MockDataserviceService }, - NotifierService, - SelectionService, - { provide: VdbService, useClass: MockVdbService } - ] - }) - .compileComponents().then(() => { - // nothing to do - }); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(VirtualizationComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should be created", () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/ngapp/src/app/dataservices/virtualization/virtualization.component.ts b/ngapp/src/app/dataservices/virtualization/virtualization.component.ts deleted file mode 100644 index 7643f792..00000000 --- a/ngapp/src/app/dataservices/virtualization/virtualization.component.ts +++ /dev/null @@ -1,456 +0,0 @@ -import { Component, OnInit } from "@angular/core"; -import { AbstractControl, FormControl, FormGroup } from "@angular/forms"; -import { Router } from "@angular/router"; -import { LoggerService } from "@core/logger.service"; -import { SelectionService } from "@core/selection.service"; -import { Dataservice } from "@dataservices/shared/dataservice.model"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; -import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; -import { BsModalService } from "ngx-bootstrap"; -import { ActionConfig, EmptyStateConfig } from "patternfly-ng"; -import { NewDataservice } from "@dataservices/shared/new-dataservice.model"; -import { VdbService } from "@dataservices/shared/vdb.service"; -import { LoadingState } from "@shared/loading-state.enum"; -import { ViewDefinition } from "@dataservices/shared/view-definition.model"; - -@Component({ - selector: "app-virtualization", - templateUrl: "./virtualization.component.html", - styleUrls: ["./virtualization.component.css"] -}) -export class VirtualizationComponent implements OnInit { - - public readonly virtualizationsLink = DataservicesConstants.dataservicesRootPath; - - public viewPropertyForm: FormGroup; - public nameValidationError = ""; - public viewDefinitions: ViewDefinition[] = []; - public selectedViewDefinitions: ViewDefinition[] = []; - public viewCreateInProgress = false; - public showDescription = false; - - private selectionService: SelectionService; - private dataserviceService: DataserviceService; - private modalService: BsModalService; - private vdbService: VdbService; - private router: Router; - private logger: LoggerService; - private noViewsConfig: EmptyStateConfig; - private enterNameConfig: EmptyStateConfig; - private saveNameConfig: EmptyStateConfig; - private currentVirtualization: Dataservice = null; - private originalName: string; - private newVirtualization: NewDataservice = null; - private viewsLoadingState: LoadingState = LoadingState.LOADING; - - constructor( selectionService: SelectionService, dataserviceService: DataserviceService, - vdbService: VdbService, modalService: BsModalService, router: Router, logger: LoggerService ) { - this.selectionService = selectionService; - this.dataserviceService = dataserviceService; - this.vdbService = vdbService; - this.modalService = modalService; - this.router = router; - this.logger = logger; - this.createViewPropertyForm(); - } - - public ngOnInit(): void { - // If there is a virtualization selection, edit it. Otherwise create a new virtualization - if (this.selectionService.hasSelectedVirtualization) { - this.currentVirtualization = this.selectionService.getSelectedVirtualization(); - this.originalName = this.currentVirtualization.getId(); - this.initForm(this.currentVirtualization.getId(), this.currentVirtualization.getDescription(), false); - // Init views - this.initViews(); - } else { - this.originalName = ""; - this.newVirtualization = this.dataserviceService.newDataserviceInstance(this.originalName, ""); - this.initForm(this.newVirtualization.getId(), this.newVirtualization.getDescription(), true); - // Init Views - this.viewDefinitions = []; - this.viewsLoadingState = LoadingState.LOADED_VALID; - } - } - - /** - * Get new virtualization status - * @returns {boolean} true if the virtualization has not yet been named - */ - public get isNew( ): boolean { - return this.newVirtualization && this.newVirtualization !== null; - } - - /** - * Get the virtualization view definitions - * @returns {ViewDefinition[]} the view definitions - */ - public get allViewDefinitions( ): ViewDefinition[] { - return this.viewDefinitions; - } - - /** - * Determine if the views are loading - */ - public get viewsLoading( ): boolean { - return ( this.viewsLoadingState === LoadingState.LOADING ); - } - - /** - * Determine if view loading finished successfully - */ - public get viewsLoadedSuccess( ): boolean { - return ( this.viewsLoadingState === LoadingState.LOADED_VALID ); - } - - /** - * Determine if view loading finished but with error - */ - public get viewsLoadedFailed( ): boolean { - return ( this.viewsLoadingState === LoadingState.LOADED_INVALID ); - } - - /** - * Determine if the virtualization has a pending name change - * @returns {boolean} 'true' if pending name change - */ - public get hasPendingNameChange( ): boolean { - return this.originalName !== this.viewPropertyForm.controls["name"].value.toString(); - } - - /** - * Save the dataservice using the current name value. This cannot be invoked unless there are pending changes, - * and the name is valid. - */ - public onSaveName( ): void { - const theName = this.viewPropertyForm.controls["name"].value.toString(); - let theDescription = ""; - const descr = this.viewPropertyForm.controls["description"].value; - if (descr != null) { - theDescription = descr.toString(); - } - - // If this is a brand new dataservice, create it - if (this.isNew) { - const self = this; - this.viewCreateInProgress = true; - this.newVirtualization.setId(theName); - this.newVirtualization.setDescription(theDescription); - this.dataserviceService - .createDataservice(this.newVirtualization) - .subscribe( - (wasSuccess) => { - // After create of dataservice, remove 'newVirtualization' - self.newVirtualization = null; - // Set the current virtualization to the newly created virtualization - self.selectDataservice(theName); - }, - (error) => { - self.logger.error("[VirtualizationComponent] Error creating virtualization: %o", error); - self.viewCreateInProgress = false; - } - ); - // Existing dataservice - update it - } else { - // TODO: Determine action for rename of existing - } - } - - /** - * Handler for dataservice name changes. - * @param {AbstractControl} input - */ - public handleNameChanged( input: AbstractControl ): void { - const self = this; - - this.dataserviceService.isValidName( input.value ).subscribe( - ( errorMsg ) => { - if ( errorMsg ) { - // only update if error has changed - if ( errorMsg !== self.nameValidationError ) { - self.nameValidationError = errorMsg; - } - self.setViewDefinitionsEditableState(false); - } else { // name is valid - self.nameValidationError = ""; - if (self.hasPendingNameChange) { - self.setViewDefinitionsEditableState(false); - } else { - self.setViewDefinitionsEditableState(true); - } - } - }, - ( error ) => { - self.logger.error( "[handleNameChanged] Error: %o", error ); - } ); - } - - /* - * Return the name valid state - */ - public get nameValid(): boolean { - return this.nameValidationError == null || this.nameValidationError.length === 0; - } - - /** - * The configuration for empty state (no views) - * @returns {EmptyStateConfig} the empty state config - */ - public get viewsEmptyConfig(): EmptyStateConfig { - if ( !this.noViewsConfig ) { - const actionConfig = { - primaryActions: [ - { - id: "createViewActionId", - title: "Add View", - tooltip: "Add a view" - } - ] - } as ActionConfig; - - this.noViewsConfig = { - actions: actionConfig, - iconStyleClass: "pficon-warning-triangle-o", - info: "No views are defined for this virtualization. Please click below to create a view.", - title: "No Views Defined" - } as EmptyStateConfig; - } - - return this.noViewsConfig; - } - - /** - * Empty state config which prompts the user to name the virtualization. - * @returns {EmptyStateConfig} the empty state config - */ - public get enterVirtualizationNameConfig(): EmptyStateConfig { - if ( !this.enterNameConfig ) { - this.enterNameConfig = { - iconStyleClass: "pficon-warning-triangle-o", - info: "Please enter a name for the virtualization", - title: "Enter Virtualization Name" - } as EmptyStateConfig; - } - - return this.enterNameConfig; - } - - /** - * Empty state config which prompts the user to save the virtualization. - * @returns {EmptyStateConfig} the empty state config - */ - public get saveVirtualizationNameConfig(): EmptyStateConfig { - if ( !this.saveNameConfig ) { - this.saveNameConfig = { - iconStyleClass: "pficon-warning-triangle-o", - info: "Click save icon to save the virtualization name", - title: "Save Virtualization Name" - } as EmptyStateConfig; - } - - return this.saveNameConfig; - } - - /** - * Handle Delete of the specified View - * @param {string} viewName - */ - public onDelete(viewName: string): void { - // Dialog Content - const message = "Do you really want to delete View '" + viewName + "'?"; - const initialState = { - title: "Confirm Delete", - bodyContent: message, - cancelButtonText: "Cancel", - confirmButtonText: "Delete" - }; - - // Show Dialog, act upon confirmation click - const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); - modalRef.content.confirmAction.take(1).subscribe((value) => { - this.onDeleteView(viewName); - }); - } - - /** - * Handle request for new View - */ - public onNew(): void { - // Setting the selected view definition null indicates new view - this.selectionService.setSelectedViewDefinition( this.currentVirtualization, null ); - - const link: string[] = [ DataservicesConstants.viewPath ]; - this.logger.debug("[VirtualizationComponent] Navigating to: %o", link); - this.router.navigate(link).then(() => { - // nothing to do - }); - } - - /** - * Handle Edit of the specified View - * @param {string} viewName - */ - public onEdit(viewName: string): void { - // Sets the selected view in the service - const selectedViewDefn = this.viewDefinitions.find((x) => x.getName() === viewName); - this.selectionService.setSelectedViewDefinition( this.currentVirtualization, selectedViewDefn ); - - const link: string[] = [ DataservicesConstants.viewPath ]; - this.logger.debug("[VirtualizationComponent] Navigating to: %o", link); - this.router.navigate(link).then(() => { - // nothing to do - }); - } - - public onSelected( viewDefn: ViewDefinition ): void { - this.selectionService.setSelectedViewDefinition( this.currentVirtualization, viewDefn ); - } - - // ---------------- - // Private Methods - // ---------------- - - /** - * Deletes the specified ViewEditorState from the userProfile, and removes ViewDefinition from the current list. - * @param {string} viewDefnName the name of the view - */ - private onDeleteView(viewDefnName: string): void { - const selectedViewDefn = this.viewDefinitions.find((x) => x.getName() === viewDefnName); - const vdbName = this.currentVirtualization.getServiceVdbName(); - const editorStateId = vdbName.toLowerCase() + "." + viewDefnName; - const dataserviceName = this.currentVirtualization.getId(); - // Note: we can only doDelete selected items that we can see in the UI. - this.logger.debug("[VirtualizationComponent] Deleting selected Virtualization View."); - const self = this; - this.dataserviceService - .deleteViewEditorStateRefreshViews(editorStateId, dataserviceName) - .subscribe( - (wasSuccess) => { - self.removeViewDefinitionFromList(selectedViewDefn); - }, - (error) => { - self.logger.error("[VirtualizationComponent] Error deleting the editor state: %o", error); - } - ); - } - - /* - * Creates the view property form - */ - private createViewPropertyForm(): void { - // New Virtualization is allowed to edit the name - handle name changes - if (!this.selectionService.hasSelectedVirtualization) { - this.viewPropertyForm = new FormGroup({ - name: new FormControl( "", this.handleNameChanged.bind( this ) ), - description: new FormControl("") - }); - // Responds to basic property changes - updates the page status - this.viewPropertyForm.valueChanges.subscribe((val) => { - // this.updatePage2aValidStatus( ); - }); - // Edit Virtualization is not allowed to edit the name - } else { - this.viewPropertyForm = new FormGroup({ - name: new FormControl( "" ), - description: new FormControl("") - }); - } - } - - /* - * Init the form values - * @param {string} name the dataservice name - * @param {string} description the dataservice description - * @param {boolean} nameEditable 'true' if can edit the name - */ - private initForm(name: string, descr: string, nameEditable: boolean): void { - if (!nameEditable) { - this.viewPropertyForm.get("name").disable(); - } - this.viewPropertyForm.controls["name"].setValue(name); - this.viewPropertyForm.controls["description"].setValue(descr); - } - - /* - * Select the specified Dataservice. - * @param {string} dsName the name of the dataservice - */ - private selectDataservice(dsName: string): void { - const self = this; - this.dataserviceService - .getAllDataservices() - .subscribe( - (dataservices) => { - for (const ds of dataservices) { - if (ds.getId() === dsName) { - self.currentVirtualization = ds; - self.dataserviceService.setSelectedDataservice(ds); - self.originalName = this.currentVirtualization.getId(); - self.initForm(this.currentVirtualization.getId(), this.currentVirtualization.getDescription(), false); - } - } - self.viewCreateInProgress = false; - }, - (error) => { - self.logger.error("[VirtualizationComponent] Error selecting the virtualization: %o", error); - self.viewCreateInProgress = false; - } - ); - } - - /* - * Initialize the views for the current dataservice. Makes a rest call to get the ViewEditorStates for the serviceVdb - */ - private initViews( ): void { - this.viewsLoadingState = LoadingState.LOADING; - const vdbName = this.currentVirtualization.getServiceVdbName(); - const statesPattern = vdbName.toLowerCase() + "*"; - this.setViewDefinitionsEditableState(true); - - const self = this; - this.dataserviceService - .getViewEditorStates(statesPattern) - .subscribe( - (viewEditorStates) => { - const viewDefns: ViewDefinition[] = []; - for ( const viewState of viewEditorStates ) { - const viewDefn = viewState.getViewDefinition(); - if ( viewDefn ) { - viewDefns.push( viewDefn ); - } - } - self.viewDefinitions = viewDefns.sort( (left, right): number => { - if (left.getName() < right.getName()) return -1; - if (left.getName() > right.getName()) return 1; - return 0; - }); - self.setViewDefinitionsEditableState(true); - this.viewsLoadingState = LoadingState.LOADED_VALID; - }, - (error) => { - self.logger.error("[VirtualizationComponent] Error updating the views for the virtualization: %o", error); - self.viewCreateInProgress = false; - this.viewsLoadingState = LoadingState.LOADED_INVALID; - } - ); - } - - /* - * Set the editable state of all view definitions - * @param {boolean} isEditable the editable state - */ - private setViewDefinitionsEditableState(isEditable: boolean): void { - for (const viewDefn of this.viewDefinitions) { - viewDefn.setEditable(isEditable); - } - } - - /* - * Remove the specified ViewDefinition from the list of view definitions - * @param {ViewDefinition} viewDefn the view definition to remove - */ - private removeViewDefinitionFromList(viewDefn: ViewDefinition): void { - this.viewDefinitions.splice(this.viewDefinitions.indexOf(viewDefn), 1); - } - -} diff --git a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts index 29b4253c..6f52c40d 100644 --- a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts +++ b/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts @@ -27,6 +27,7 @@ import { BsModalRef } from "ngx-bootstrap"; export class ConfirmDialogComponent implements OnInit { @Output() public confirmAction = new EventEmitter(); + @Output() public cancelAction = new EventEmitter(); public title = "Title"; public bodyContent = "Confirmation Message"; @@ -48,6 +49,7 @@ export class ConfirmDialogComponent implements OnInit { } public onCancelSelected(): void { + this.cancelAction.emit(true); this.bsModalRef.hide(); } diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index a77501a9..62145d16 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -791,9 +791,7 @@ export class TestDataService { "serviceVdbName": TestDataService.accountsVdb.getName(), "serviceVdbVersion": TestDataService.accountsVdb.getVersion(), "serviceViewModel": "views", - "serviceViews": [ - "tbl1View", - "tbl2View" + "serviceViewDefinitions": [ ], "serviceViewTables": [ "connection=" + TestDataService.conn1.getId().toLowerCase() + "/schema=public/table=tbl1", @@ -837,11 +835,9 @@ export class TestDataService { "serviceVdbName": TestDataService.employeesVdb.getName(), "serviceVdbVersion": TestDataService.employeesVdb.getVersion(), "serviceViewModel": "views", - "serviceViews": [ - "tbl1View", - "tbl2View", - "tbl3View", - "tbl4View" + "serviceViewDefinitions": [ + "employeesView1", + "employeesView2" ], "serviceViewTables": [ "connection=" + TestDataService.conn2.getId().toLowerCase() + "/schema=public/table=tbl1", @@ -883,17 +879,14 @@ export class TestDataService { "keng__dataPath": "/tko:komodo/tko:workspace/admin/Products", "keng__kType": "Dataservice", "keng__hasChildren": true, - "tko__description": "A dataservice for products.", + "tko__description": "A dataservice for products. Make this a much longer description, to see what happens... Make this a much longer description, to see what happens... Make this a much longer description, to see what happens... Make this a much longer description, to see what happens... Make this a much longer description, to see what happens... Make it even longer now and longer", "serviceVdbName": TestDataService.productsVdb.getName(), "serviceVdbVersion": TestDataService.productsVdb.getVersion(), "serviceViewModel": "views", - "serviceViews": [ - "tbl1View", - "tbl2View", - "tbl3View", - "tbl4View", - "tbl5View", - "tbl6View" + "serviceViewDefinitions": [ + "productsView1", + "productsView2", + "productsView3" ], "serviceViewTables": [ "connection=" + TestDataService.conn3.getId().toLowerCase() + "/schema=public/table=tbl1", From 7d248d26d344618c1e4b4a53bec8c0432b773b79 Mon Sep 17 00:00:00 2001 From: blafond Date: Tue, 4 Sep 2018 15:58:23 -0500 Subject: [PATCH 182/205] TEIIDTOOLS-478 * Added sample data action to canvas toolbar * fixed selection of composition node --- .../shared/view-definition.model.ts | 14 ++- .../add-composition-wizard.component.ts | 8 +- .../command/add-composition-command.ts | 18 +-- .../command/add-sources-command.ts | 17 ++- .../view-editor/command/command.ts | 7 ++ .../command/remove-composition-command.ts | 19 +-- .../command/remove-sources-command.ts | 15 ++- .../view-editor/view-canvas/canvas.service.ts | 22 +++- .../view-canvas/models/canvas-graph.ts | 10 +- .../view-canvas/models/canvas-node.spec.ts | 14 ++- .../view-canvas/models/canvas-node.ts | 12 +- .../view-canvas/view-canvas.component.ts | 112 +++++++++++++----- .../visuals/node/node-visual.component.ts | 8 +- .../view-editor/view-editor-i18n.ts | 3 + .../view-editor/view-editor.component.html | 4 + .../view-editor/view-editor.component.ts | 111 +++++++++++++---- .../view-editor/view-editor.service.ts | 19 ++- 17 files changed, 303 insertions(+), 110 deletions(-) diff --git a/ngapp/src/app/dataservices/shared/view-definition.model.ts b/ngapp/src/app/dataservices/shared/view-definition.model.ts index 270a1a61..1a4ee3c4 100644 --- a/ngapp/src/app/dataservices/shared/view-definition.model.ts +++ b/ngapp/src/app/dataservices/shared/view-definition.model.ts @@ -284,13 +284,17 @@ export class ViewDefinition { * Get the preview SQL for the view, given the current selections * @returns {string} the view SQL */ - public getPreviewSql(): string { - let previewSql = ""; + public getPreviewSql( sourcePath?: string ): string { // TODO: This method currently handles single source views, and single join views // Will need to expand capabilites in the future - as more complex joins are supported. // The preview SQL is only generated if the view is complete + if ( sourcePath != null ) { + const tableName = this.getPreviewTableName(sourcePath); + return "SELECT * FROM " + tableName + ";"; + } + // The preview SQL for the view is only generated if the view is complete if ( this.complete ) { // Join View if ( this.getCompositions().length === 1 ) { @@ -301,18 +305,18 @@ export class ViewDefinition { const rightCriteriaColName = composition.getRightCriteriaColumn(); const criteriaOperator = CompositionOperator.toSql(composition.getOperator()); const joinType = CompositionType.toSql(composition.getType()); - previewSql = "SELECT * FROM " + leftTable + " AS A " + joinType + " " + + return "SELECT * FROM " + leftTable + " AS A " + joinType + " " + rightTable + " AS B ON " + "A." + leftCriteriaColName + " " + criteriaOperator + " " + "B." + rightCriteriaColName + ";"; // Single Source View } else { const tableName = this.getPreviewTableName(this.getSourcePaths()[0]); - previewSql = "SELECT * FROM " + tableName + ";"; + return "SELECT * FROM " + tableName + ";"; } } - return previewSql; + return ""; } /** diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts index b4327c2d..45bb0fc5 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts @@ -125,7 +125,13 @@ export class AddCompositionWizardComponent implements OnInit { this.composition.setLeftSourcePath(idParts[1], true); } else { const selections = this.editorService.getSelection(); - if (selections && selections.length === 1) { + if (selections && selections.length === 2) { + // ------------------ + // this block of code should only be run if 'plus' icon is selected on a source connection node + // the second arg of the selection array should be the source path of the canvas node selected + // ------------------ + this.composition.setLeftSourcePath(selections[1], true); + } else if (selections && selections.length === 1) { const selection = selections[0]; const idParts = selection.split(Command.identDivider); this.composition.setLeftSourcePath(idParts[1], true); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts index e0a5153c..4829daed 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts @@ -60,7 +60,7 @@ export class AddCompositionCommand extends Command { // // Generate new id for this source // - id = AddCompositionCommand.id + Date.now(); + id = AddCompositionCommand.id + this.idGen; } this._args.set( Command.identArg, id); @@ -76,15 +76,17 @@ export class AddCompositionCommand extends Command { } /** - * @returns {string} a unique identifier of this command + * @returns {string} json payload for this command + */ + public getPayload(compositionName?: string): string { + return this.getArg( AddCompositionCommand.addedComposition ) as string; + } + + /** + * @returns {string} a unique short identifier of this command */ public getId(compositionName?: string): string { - let result = this.getArg( Command.identArg ) as string; - const compArgValue = this.getArg( AddCompositionCommand.addedComposition ) as string; - if (compArgValue) { - result = result + Command.identDivider + compArgValue; - } - return result; + return this.getArg( Command.identArg ) as string; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts index 425cfb69..d882ea41 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts @@ -76,7 +76,7 @@ export class AddSourcesCommand extends Command { // // Generate new id for this source // - id = AddSourcesCommand.id + Date.now(); + id = AddSourcesCommand.id + this.idGen; } this._args.set( Command.identArg, id); @@ -91,13 +91,18 @@ export class AddSourcesCommand extends Command { } /** - * @returns {string} a unique identifier of this command + * @returns {string} the json payload for this command */ - public getId(sourcePath?: string): string { - let argValue = this.getArg( Command.identArg ) as string; + public getPayload(sourcePath?: string): string { if (sourcePath) - argValue = argValue + Command.identDivider + sourcePath; + return sourcePath; + return this.getArg( Command.identArg ) as string; + } - return argValue; + /** + * @returns {string} a unique short identifier of this command + */ + public getId(sourcePath?: string): string { + return this.getArg( Command.identArg ) as string; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/command.ts index 5af8a390..dac0c431 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/command.ts @@ -115,6 +115,13 @@ export abstract class Command { return this._name; } + /** + * @returns {string} a unique 9 digit number preceeded with an underscore '_' + */ + public get idGen(): string { + return '_' + Math.random().toString(36).substr(2, 9); + } + /** * @returns {{}} a JSON representation of the command */ diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts index e1ebf68a..2db8effb 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts @@ -65,20 +65,21 @@ export class RemoveCompositionCommand extends Command { */ public getComposition(): Composition { const compStr = this.getArg( RemoveCompositionCommand.removedComposition ) as string; - const comp = Composition.create(JSON.parse(compStr)); - return comp; + return Composition.create(JSON.parse(compStr)); } /** * @param {Composition} composition the Composition to use in generating the id - * @returns {string} a unique identifier of this command + * @returns {string} the json payload for this command */ - public getId(composition?: Composition): string { - let argValue = this.getArg( Command.identArg ) as string; - if (composition) - argValue = argValue + Command.identDivider + JSON.stringify(composition); - - return argValue; + public getPayload(composition?: Composition): string { + return JSON.stringify(composition); } + /** + * @returns {string} a unique short identifier of this command + */ + public getId(composition?: Composition): string { + return this.getArg( Command.identArg ) as string; + } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts index 839707f7..d48119b8 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts @@ -83,13 +83,18 @@ export class RemoveSourcesCommand extends Command { } /** - * @returns {string} a unique identifier of this command + * @returns {string} the json payload for this command */ - public getId(sourcePath?: string): string { - let argValue = this.getArg( Command.identArg ) as string; + public getPayload(sourcePath?: string): string { if (sourcePath) - argValue = argValue + Command.identDivider + sourcePath; + return sourcePath; + return this.getArg( Command.identArg ) as string; + } - return argValue; + /** + * @returns {string} a unique identifier of this command + */ + public getId(sourcePath?: string): string { + return this.getArg( Command.identArg ) as string; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts index 423a742f..b13c550f 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts @@ -57,7 +57,7 @@ export class CanvasService { const selection = []; if (nodes) { nodes.forEach((node) => { - selection.push(node.decodedId); + selection.push(node.decodedId + Command.identDivider + node.decodePayload); }); } @@ -102,9 +102,13 @@ export class CanvasService { if (source.type === CanvasConstants.SOURCE_TYPE) { eventType = ViewCanvasEventType.CREATE_COMPOSITION; args.push(source.decodedId); + args.push(source.decodePayload); } else if (source.type === CanvasConstants.COMPOSITION_TYPE) eventType = ViewCanvasEventType.CREATE_SOURCE; + const selectionEvent = ViewCanvasEvent.create(ViewCanvasEventType.CANVAS_SELECTION_CHANGED, args); + this.canvasEvent.emit(selectionEvent); + const event = ViewCanvasEvent.create(eventType, args); this.canvasEvent.emit(event); // @@ -136,15 +140,18 @@ export class CanvasService { } private removeNodeCallback(node: CanvasNode): void { - const eventType = ViewCanvasEventType.DELETE_NODE; const args = []; // - // Send the decoded id so that it can be parsed + // Send the decoded id and payload so that it can be parsed // and the source path extracted from it if required // args.push(node.decodedId); + args.push(node.decodePayload); - const event = ViewCanvasEvent.create(eventType, args); + const selectionEvent = ViewCanvasEvent.create(ViewCanvasEventType.CANVAS_SELECTION_CHANGED, args); + this.canvasEvent.emit(selectionEvent); + + const event = ViewCanvasEvent.create(ViewCanvasEventType.DELETE_NODE, args); this.canvasEvent.emit(event); this.stopPropagation(); } @@ -261,11 +268,11 @@ export class CanvasService { /** * Create a new node and add it to the graph */ - public createNode(id: string, type: string, label: string, refresh?: boolean): string { + public createNode(id: string, payload: string, type: string, label: string, refresh?: boolean): string { if (! this.canvasGraph) throw new Error("A canvas graph is required before creating a node"); - const canvasNode = this.canvasGraph.addNode(id, type, label, refresh); + const canvasNode = this.canvasGraph.addNode(id, payload, type, label, refresh); return canvasNode.id; } @@ -281,7 +288,10 @@ export class CanvasService { // identifier has been delivered as plaintext // while the node identifiers are encoded // + nodeId = CanvasNode.encodeId(nodeId); + const idParts = nodeId.split(Command.identDivider); + nodeId = idParts[0]; } this.canvasGraph.removeNode(nodeId, refresh); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts index db9058d8..9e45f04c 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts @@ -168,9 +168,9 @@ export class CanvasGraph { /** * Add a new node to the graph */ - public addNode(id: string, type: string, label: string, update?: boolean): CanvasNode { + public addNode(id: string, payload: string, type: string, label: string, update?: boolean): CanvasNode { const isEmpty = _.isEmpty(this.nodes); - const canvasNode = new CanvasNode(id, type, label, isEmpty); + const canvasNode = new CanvasNode(id, payload, type, label, isEmpty); // // Set as fixed by default until its linked @@ -246,7 +246,7 @@ export class CanvasGraph { } // - // Remove any nodes targetted by this link + // Remove any nodes targeted by this link // (ignoring the current nodeToRemove) // if (nodeToRemove !== link.target) @@ -299,8 +299,8 @@ export class CanvasGraph { // // Remove the fix on the nodes unless it is the root // - src.setFixed(!src.root); - tgt.setFixed(!tgt.root); + src.setFixed(false); + tgt.setFixed(false); if (update !== undefined && update) this.canvasService.update(true); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts index dfe2778d..b9f9e225 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts @@ -9,24 +9,28 @@ describe("CanvasNode", () => { it("should create", () => { console.log("========== [CanvasNode] should create"); - canvasNode = new CanvasNode("AddSourcesCommand1532362832377_-_connection=conn3/schema=public/table=stuff", + canvasNode = new CanvasNode("AddSourcesCommand1532362832377", + "connection=conn3/schema=public/table=stuff", "SOURCE", "connection=conn3/schema=public/table=stuff", true); // Check the encoded id - expect(canvasNode.id).toEqual("AddSourcesCommand1532362832377_-_connection6X6conn35X5schema6X6public5X5table6X6stuff"); + expect(canvasNode.id).toEqual("AddSourcesCommand1532362832377"); + expect(canvasNode.payload).toEqual("connection6X6conn35X5schema6X6public5X5table6X6stuff"); }); it("should decodeId", () => { console.log("========== [CanvasNode] should decode id"); - canvasNode = new CanvasNode("AddSourcesCommand1532362832377_-_connection=conn3/schema=public/table=stuff", + canvasNode = new CanvasNode("AddSourcesCommand1532362832377", + "connection=conn3/schema=public/table=stuff", "SOURCE", "connection=conn3/schema=public/table=stuff", true); // Check the encoded id - expect(canvasNode.id).toEqual("AddSourcesCommand1532362832377_-_connection6X6conn35X5schema6X6public5X5table6X6stuff"); + expect(canvasNode.id).toEqual("AddSourcesCommand1532362832377"); + expect(canvasNode.payload).toEqual("connection6X6conn35X5schema6X6public5X5table6X6stuff"); // Check that the encoded id is decoded properly const decoded = canvasNode.decodedId; - expect(decoded).toEqual("AddSourcesCommand1532362832377_-_connection=conn3/schema=public/table=stuff"); + expect(CanvasNode.decodeId(canvasNode.payload)).toEqual("connection=conn3/schema=public/table=stuff"); }); }); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts index 989654e3..bb404afd 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts @@ -31,6 +31,7 @@ export class CanvasNode implements cola.Node { private readonly _id: string; private readonly _type: string; + private readonly _payload: string; private _label: string; private _selected = false; private _root = false; @@ -43,8 +44,9 @@ export class CanvasNode implements cola.Node { return id.replace(/5X5/g, '/').replace(/6X6/g, '='); } - constructor(id: string, type: string, label: string, root?: boolean) { + constructor(id: string, payload: string, type: string, label: string, root?: boolean) { this._id = CanvasNode.encodeId(id); + this._payload = CanvasNode.encodeId(payload); this._type = type; this._label = label; if (root !== undefined) @@ -59,6 +61,14 @@ export class CanvasNode implements cola.Node { return CanvasNode.decodeId(this.id); } + public get payload(): string { + return this._payload; + } + + public get decodePayload(): string { + return CanvasNode.decodeId(this.payload); + } + public get type(): string { return this._type; } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts index 25135173..8e992105 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts @@ -39,6 +39,7 @@ import { RemoveCompositionCommand } from "@dataservices/virtualization/view-edit import { Command } from "@dataservices/virtualization/view-editor/command/command"; import { CommandFactory } from "@dataservices/virtualization/view-editor/command/command-factory"; import { ViewDefinition } from "@dataservices/shared/view-definition.model"; +import { Composition } from "@dataservices/shared/composition.model"; @Component({ encapsulation: ViewEncapsulation.None, @@ -81,7 +82,7 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { if (args[0] instanceof AddSourcesCommand) { const cmd = args[0] as AddSourcesCommand; - this.createSourceNodes(cmd); + this.createSourceNode(cmd); } else if (args[0] instanceof RemoveSourcesCommand) { const cmd = args[0] as RemoveSourcesCommand; this.removeSourceNodes(cmd); @@ -265,21 +266,6 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { if (viewDefn && viewDefn !== null) { // ------------------------ - // Create the source nodes - // ------------------------ - const sourcePaths = viewDefn.getSourcePaths(); - if (sourcePaths && sourcePaths.length > 0) { - let sourcesStr = ""; - for (let i = 0; i < sourcePaths.length; i++) { - sourcesStr += sourcePaths[i]; - if (i !== sourcePaths.length - 1) { - sourcesStr += ", "; - } - } - const cmd = CommandFactory.createAddSourcesCommand(sourcesStr) as AddSourcesCommand; - this.createSourceNodes(cmd); - } - // -------------------------- // Create the compositions // -------------------------- const compositions = viewDefn.getCompositions(); @@ -289,6 +275,19 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { this.createComposition(cmd); } } + + // ------------------------ + // Create the source nodes + // ------------------------ + const sourcePaths = viewDefn.getSourcePaths(); + // ------------------------ + // create a command for each source path to correspond to + // unique canvas nodes for each source + // ------------------------ + for (const path of sourcePaths) { + const cmd = CommandFactory.createAddSourcesCommand(path) as AddSourcesCommand; + this.createSourceNode(cmd); + } } this.canvasService.update(true); @@ -298,15 +297,21 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { * Create canvas nodes using the provided AddSourcesCommand * @param {AddSourcesCommand} command the AddSourcesCommand */ - private createSourceNodes(command: AddSourcesCommand): void { + private createSourceNode(command: AddSourcesCommand): void { const sourcePaths: string[] = command.getSourcePaths(); for (let i = 0; i < sourcePaths.length; ++i) { const srcPath = sourcePaths[i]; + const existingNode = this.getCanvasNodeForSourcePath(srcPath); + if ( existingNode && existingNode !== null) { + return; + } const update = (i === (sourcePaths.length - 1)); const id = command.getId(srcPath); const label = "[" + PathUtils.getConnectionName(srcPath) + "]: " + PathUtils.getSourceName(srcPath); - this.canvasService.createNode(id, CanvasConstants.SOURCE_TYPE, label, update); + this.canvasService.createNode(id, command.getPayload(srcPath), CanvasConstants.SOURCE_TYPE, label, update); + + this.createLink(null, srcPath); } } @@ -319,8 +324,8 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { for (let i = 0; i < srcPaths.length; ++i) { const srcPath = srcPaths[i]; const update = (i === (srcPaths.length - 1)); - const id = command.getId(srcPath); - this.canvasService.deleteNode(id, update); + const srcNode = this.getCanvasNodeForSourcePath(srcPath); + this.canvasService.deleteNode(srcNode.id, update); } } @@ -330,7 +335,7 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { */ private createComposition(command: AddCompositionCommand): void { const composition = command.getComposition(); - const compNodeId = this.canvasService.createNode(command.getId(composition.getName()), CanvasConstants.COMPOSITION_TYPE, composition.getName(), true); + const compNodeId = this.canvasService.createNode(command.getId(composition.getName()), command.getPayload(composition.getName()), CanvasConstants.COMPOSITION_TYPE, composition.getName(), true); // Create links to source nodes if not found this.createLink(compNodeId, composition.getLeftSourcePath()); this.createLink(compNodeId, composition.getRightSourcePath()); @@ -342,7 +347,12 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { */ private removeComposition(command: RemoveCompositionCommand): void { const composition = command.getComposition(); - this.canvasService.deleteNode(command.getId(composition), true); + // an undo add command may be executed here where the command ID will include + // a timestamp that does not match any canvas node + // Need to find the "name" property in the composition and match it with the + // name property of the payload + const compNode = this.getCompositionNodeForCompositionName(composition.getName()); + this.canvasService.deleteNode(compNode.id, true); } /** @@ -370,8 +380,16 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { } } - if (!linkExists) { - this.canvasService.createLink(sourceNodeId, compositionNodeId, true); + if ( !linkExists ) { + if ( compositionNodeId === null ) { + const compNode = this.getCompositionNodeForSourcePath(sourcePath); + if ( compNode && compNode !== null ) { + compositionNodeId = compNode.id; + } + } + if ( compositionNodeId !== null ) { + this.canvasService.createLink(sourceNodeId, compositionNodeId, true); + } } } } @@ -380,11 +398,10 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { let nodeForPath: CanvasNode = null; const canvasNodes: CanvasNode[] = this.canvasService.nodes(); for (const canvasNode of canvasNodes) { - const nodeId = canvasNode.decodedId; + const nodeId = canvasNode.id; if (nodeId.startsWith(AddSourcesCommand.id)) { - const identBits = nodeId.split(Command.identDivider); - const path = identBits[1]; - if (path === sourcePath) { + const payload = canvasNode.decodePayload; + if (payload === sourcePath) { nodeForPath = canvasNode; break; } @@ -393,4 +410,43 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { return nodeForPath; } + /* if source path == null, then a source node has been added via undo sources command + * need to find the compositions on the canvas and check if it has an source path that matches + * then return that node + */ + private getCompositionNodeForSourcePath( sourcePath: string): CanvasNode { + const canvasNodes: CanvasNode[] = this.canvasService.nodes(); + for (const canvasNode of canvasNodes) { + const nodeId = canvasNode.id; + if (nodeId.startsWith(AddCompositionCommand.id)) { + const payload = canvasNode.decodePayload; + const comp = Composition.create(JSON.parse(payload)); + const leftPath = comp.getLeftSourcePath(); + const rightPath = comp.getRightSourcePath(); + if (leftPath === sourcePath) { + return canvasNode; + } else if ( rightPath === sourcePath) { + return canvasNode; + } + } + } + } + + private getCompositionNodeForCompositionName( compName: string): CanvasNode { + const canvasNodes: CanvasNode[] = this.canvasService.nodes(); + for (const canvasNode of canvasNodes) { + const nodeId = canvasNode.id; + if (nodeId.startsWith(AddCompositionCommand.id)) { + const payload = canvasNode.decodePayload; + const comp = Composition.create(JSON.parse(payload)); + const compNodeName = comp.getName(); + + if (compNodeName === compName) { + return canvasNode; + } + } + } + return null; + } + } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts index 5964e96d..667d8495 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts @@ -33,20 +33,20 @@ import * as _ from "lodash"; - + {{node.label}} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts index 962d4b16..15772a03 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts @@ -26,6 +26,7 @@ export class ViewEditorI18n { // commands public static readonly addSourcesCommandName = "Add Sources"; public static readonly addCompositionCommandName = "Add Composition"; + public static readonly sampleDataCommandName = "Sample Data"; public static readonly noOpCommandName = "No operation"; public static readonly removeCompositionCommandName = "Remove Composition"; public static readonly removeSourcesCommandName = "Remove Sources"; @@ -84,6 +85,8 @@ export class ViewEditorI18n { // view editor public static readonly addCompositionActionTitle = "Add Composition"; public static readonly addCompositionActionTooltip = "Add Composition"; + public static readonly sampleDataActionTitle = "Sample Data"; + public static readonly sampleDataActionTooltip = "Sample data from selected view or source"; public static readonly addSourceDialogTitle = "Select View Source"; public static readonly addSourceActionTitle = "Add Source"; public static readonly addSourceActionTooltip = "Add Source"; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html index 38912bf7..bdfe1535 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html @@ -32,6 +32,7 @@ + + + diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts index 40ab593b..eabe28c1 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts @@ -78,6 +78,7 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { // private readonly addCompositionActionId = "addCompositionActionId"; private readonly addSourceActionId = "addSourceActionId"; + private readonly sampleDataActionId = "sampleDataActionId"; private readonly deleteActionId = "deleteActionId"; private readonly errorsActionId = "errorsActionId"; private readonly infosActionId = "infosActionId"; @@ -91,13 +92,14 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { // private readonly addSourceActionIndex = 0; private readonly addCompositionActionIndex = 1; - private readonly saveActionIndex = 2; - private readonly undoActionIndex = 3; - private readonly redoActionIndex = 4; - private readonly deleteActionIndex = 5; - private readonly errorsActionIndex = 6; - private readonly warningsActionIndex = 7; - private readonly infosActionIndex = 8; + private readonly sampleDataActionIndex = 2; + private readonly saveActionIndex = 3; + private readonly undoActionIndex = 4; + private readonly redoActionIndex = 5; + private readonly deleteActionIndex = 6; + private readonly errorsActionIndex = 7; + private readonly warningsActionIndex = 8; + private readonly infosActionIndex = 9; constructor( connectionService: ConnectionService, selectionService: SelectionService, @@ -123,6 +125,7 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { if (this.actionConfig ) { this.actionConfig.primaryActions[ this.addCompositionActionIndex ].disabled = !this.canAddComposition(); this.actionConfig.primaryActions[ this.addSourceActionIndex ].disabled = !this.canAddSource(); + this.actionConfig.primaryActions[ this.sampleDataActionIndex ].disabled = !this.canSampleData(); this.actionConfig.primaryActions[ this.deleteActionIndex ].disabled = !this.canDelete(); this.actionConfig.primaryActions[ this.errorsActionIndex ].disabled = !this.hasErrors(); this.actionConfig.primaryActions[ this.infosActionIndex ].disabled = !this.hasInfos(); @@ -236,7 +239,12 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { } else if (event.typeIsDeleteNode()) { const selection = []; - selection.push(event.args[0]); + let selectionStr = event.args[0]; + if ( event.args.length > 1 ) { + // selection.push(event.args[1]); + selectionStr += Command.identDivider + event.args[1]; + } + selection.push(selectionStr); this.doDelete(selection); } else if (event.typeIsCanvasSelectionChanged()) { @@ -271,6 +279,10 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { this.isShowingCanvas; } + private canSampleData(): boolean { + return !this.editorService.isReadOnly() && this.isShowingCanvas && this.canvasSingleSourceSelected; + } + private canDelete(): boolean { return this.hasSelectedView && !this.editorService.isReadOnly() && @@ -385,16 +397,16 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { } } - private doDelete(idents: string[]): void { + private doDelete(selectionArgs: string[]): void { - if (!idents || idents.length === 0) { + if (!selectionArgs || selectionArgs.length === 0) { alert("Nothing selected for delete"); return; } // Dialog Content - let message = "Do you really want to delete the " + idents.length; - if (idents.length > 1) + let message = "Do you really want to delete the " + selectionArgs.length; + if (selectionArgs.length > 1) message = message + " items?"; else message = message + " item?"; @@ -409,21 +421,30 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { // Show Dialog, act upon confirmation click const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); modalRef.content.confirmAction.take(1).subscribe((value) => { - idents.forEach((ident) => { - const identBits = ident.split(Command.identDivider); - const commandPart = identBits[0]; - const argPart = identBits[1]; - let tempCmd: Command = null; + // ------------------ + // the selection arguments contain the command object arg[0] and the metadata object arg[1] + // 1) need to loop through each selection + // 2) create corresponding command + // 3) fire view state changed event for each + // ------------------ + + let tempCmd: Command = null; + + selectionArgs.forEach( ( nextArg ) => { + // need to parse the command to find the source path + const commandPart = this.getCommandId(nextArg); + const argPart = this.getPayload(nextArg); + if (commandPart.startsWith(AddSourcesCommand.id)) { tempCmd = CommandFactory.createRemoveSourcesCommand(argPart, commandPart); } else if (commandPart.startsWith(AddCompositionCommand.id)) { tempCmd = CommandFactory.createRemoveCompositionCommand(argPart, commandPart); } - if ( tempCmd !== null && tempCmd instanceof Command ) { + if (tempCmd !== null ) { const cmd = tempCmd as Command; - this.editorService.fireViewStateHasChanged( ViewEditorPart.EDITOR, cmd ); + this.editorService.fireViewStateHasChanged(ViewEditorPart.EDITOR, cmd); } else { - this.logger.error( "Failed to create RemoveSourcesCommand"); + this.logger.error("Failed to create RemoveSourcesCommand"); } this.editorService.select(null); @@ -431,6 +452,15 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { }); } + private doSampleData(selection: string[]): void { + if (!selection || selection.length === 0) { + alert("Nothing selected for sample data"); + return; + } + const path = selection[0]; + this.editorService.updatePreviewResults(path); + } + private doSelection(selection: string[]): void { this.editorService.select(selection); } @@ -453,6 +483,32 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { this.editorService.undo(); } + /** + * @returns {string} argument array from the selection string + */ + private getArgs(selection?: string): string[] { + if ( selection !== null ) { + return selection.split(Command.identDivider); + } + return null; + } + + private getCommandId(selection?: string): string { + if (selection !== null) { + const args = selection.split(Command.identDivider); + return args[0]; + } + return null; + } + + private getPayload(selection?: string): string { + if (selection !== null) { + const args = selection.split(Command.identDivider); + return args[1]; + } + return null; + } + /** * Callback for when a view icon is clicked on the toolbar. * @@ -476,6 +532,7 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { * * @param {TemplateRef} addSourceTemplate the template for the add source toolbar button * @param {TemplateRef} addCompositionTemplate the template for the add composition toolbar button + * @param {TemplateRef} sampleDataTemplate the template for the sample data toolbar button * @param {TemplateRef} undoTemplate the template for the undo toolbar button * @param {TemplateRef} redoTemplate the template for the redo toolbar button * @param {TemplateRef} saveTemplate the template for the save toolbar button @@ -487,6 +544,7 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { */ public getActionConfig( addSourceTemplate: TemplateRef< any >, addCompositionTemplate: TemplateRef< any >, + sampleDataTemplate: TemplateRef< any >, undoTemplate: TemplateRef< any >, redoTemplate: TemplateRef< any >, saveTemplate: TemplateRef< any >, @@ -511,6 +569,13 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { title: ViewEditorI18n.addCompositionActionTitle, tooltip: ViewEditorI18n.addCompositionActionTooltip }, + { + disabled: !this.canSampleData(), + id: this.sampleDataActionId, + template: sampleDataTemplate, + title: ViewEditorI18n.sampleDataActionTitle, + tooltip: ViewEditorI18n.sampleDataActionTooltip + }, { disabled: !this.canSave(), id: this.saveActionId, @@ -584,6 +649,10 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { case this.addSourceActionId: this.doAddSource(); break; + case this.sampleDataActionId: + const singleSelection = this.editorService.getSelection(); + this.doSampleData(singleSelection); + break; case this.deleteActionId: const selection = this.editorService.getSelection(); this.doDelete(selection); @@ -670,8 +739,6 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { public get canvasSingleSourceSelected(): boolean { const selections = this.editorService.getSelection(); if (selections && selections.length === 1) { - const selection = selections[0]; - const identBits = selection.split(Command.identDivider); return true; } return false; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index 9d14a675..fc1e01ec 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -463,6 +463,7 @@ export class ViewEditorService { public setEditorView( viewDefn: ViewDefinition, source: ViewEditorPart ): void { this._editorView = viewDefn; + this._selection = []; if ( viewDefn !== null ) { this._originalView = ViewDefinition.create(viewDefn.toJSON()); } else { @@ -490,18 +491,26 @@ export class ViewEditorService { * Update the preview results for the current view. This issues a query against the preview VDB and sets * the previewResults */ - public updatePreviewResults( ): void { + public updatePreviewResults( sourcePath?: string ): void { // Clear preview results this.setPreviewResults(null, null, ViewEditorPart.EDITOR); - // Fetch new results - const viewSql = this._editorView.getPreviewSql(); + var querySql = ""; + if ( sourcePath != null && !sourcePath.startsWith(AddCompositionCommand.id) ) { + // Fetch new results for source table + querySql = this._editorView.getPreviewSql(sourcePath); + + } else { + // Fetch new results for view + querySql = this._editorView.getPreviewSql(); + + } const self = this; // Resets all of the views in the service VDB - this._vdbService.queryVdb(viewSql, VdbsConstants.PREVIEW_VDB_NAME, 15, 0) + this._vdbService.queryVdb(querySql, VdbsConstants.PREVIEW_VDB_NAME, 15, 0) .subscribe( (queryResult) => { - self.setPreviewResults(viewSql, queryResult, ViewEditorPart.EDITOR); + self.setPreviewResults(querySql, queryResult, ViewEditorPart.EDITOR); }, (error) => { this._logger.error( "[ViewEditorService.updatePreviewResults] - error getting results" ); From 4f14705d0f4ddaf22c4a7dcbd017e0f8ab44c5ee Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 31 Aug 2018 08:27:41 -0500 Subject: [PATCH 183/205] Use selectionService exclusively --- ngapp/src/app/core/selection.service.ts | 22 +++++ ...te-virtualization-dialog.component.spec.ts | 3 +- .../create-virtualization-dialog.component.ts | 7 +- .../dataservices/dataservices.component.html | 2 +- .../dataservices/dataservices.component.ts | 18 ++-- .../odata-control/odata-control.component.ts | 8 +- .../dataservices/shared/dataservice.model.ts | 5 +- .../shared/dataservice.service.ts | 90 ------------------- .../shared/mock-dataservice.service.ts | 48 ---------- .../sql-control/sql-control.component.spec.ts | 8 +- .../sql-control/sql-control.component.ts | 8 +- .../test-dataservice.component.spec.ts | 7 +- .../test-dataservice.component.ts | 12 +-- .../create-view-dialog.component.spec.ts | 6 +- .../create-view-dialog.component.ts | 10 +-- .../editor-views.component.spec.ts | 2 + .../message-log/message-log.component.spec.ts | 2 + .../view-preview.component.spec.ts | 2 + .../view-canvas/view-canvas.component.spec.ts | 2 + .../view-editor-header.component.spec.ts | 9 ++ .../view-editor-header.component.ts | 6 +- .../view-editor/view-editor.service.spec.ts | 2 + .../view-editor/view-editor.service.ts | 6 +- .../view-property-editors.component.spec.ts | 2 + 24 files changed, 103 insertions(+), 184 deletions(-) diff --git a/ngapp/src/app/core/selection.service.ts b/ngapp/src/app/core/selection.service.ts index 0f7a844f..312cb58b 100644 --- a/ngapp/src/app/core/selection.service.ts +++ b/ngapp/src/app/core/selection.service.ts @@ -19,6 +19,7 @@ import { Injectable } from "@angular/core"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { Connection } from "@connections/shared/connection.model"; import { ViewDefinition } from "@dataservices/shared/view-definition.model"; +import { SqlView } from "@dataservices/shared/sql-view.model"; @Injectable() export class SelectionService { @@ -56,6 +57,27 @@ export class SelectionService { return this.selectedVirtualization && this.selectedVirtualization !== null; } + /** + * Get the current Virtualization selection's views.View + * The ViewDefinition name is currently set to the full "modelName"."viewName" of the view. + * @returns {SqlView[]} the selected Dataservice view definitions + */ + public getSelectedVirtualizationViewNames( ): SqlView[] { + if ( !this.hasSelectedVirtualization ) { + return []; + } + + const modelName = this.selectedVirtualization.getServiceViewModel(); + const serviceViews = this.selectedVirtualization.getServiceViewNames(); + + const allViewNames: SqlView[] = []; + for ( const serviceView of serviceViews ) { + allViewNames.push(new SqlView(modelName + "." + serviceView)); + } + + return allViewNames; + } + /** * Gets the selected connection * @returns {Connection} the selected connection diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts index f26bfcc5..8037a5d5 100644 --- a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts +++ b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts @@ -15,6 +15,7 @@ import { CreateVirtualizationDialogComponent } from "./create-virtualization-dia import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { SelectionService } from "@core/selection.service"; describe('CreateVirtualizationDialogComponent', () => { let component: CreateVirtualizationDialogComponent; @@ -31,7 +32,7 @@ describe('CreateVirtualizationDialogComponent', () => { NotificationModule ], declarations: [ CreateVirtualizationDialogComponent ], - providers: [ AppSettingsService, BsModalRef, LoggerService, NotifierService, + providers: [ AppSettingsService, BsModalRef, LoggerService, NotifierService, SelectionService, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } ] diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts index ace1d70b..0aa18adb 100644 --- a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts +++ b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts @@ -25,6 +25,7 @@ import { AbstractControl, FormControl, FormGroup } from "@angular/forms"; import { VdbService } from "@dataservices/shared/vdb.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { CreateVirtualizationResult } from "@dataservices/create-virtualization-dialog/create-virtualization-result.model"; +import { SelectionService } from "@core/selection.service"; @Component({ selector: "app-create-virtualization-dialog", @@ -62,15 +63,17 @@ export class CreateVirtualizationDialogComponent implements OnInit { private loggerService: LoggerService; private dataserviceService: DataserviceService; + private selectionService: SelectionService; private vdbService: VdbService; private serviceVdbName = ""; constructor(bsModalRef: BsModalRef, logger: LoggerService, - dataserviceService: DataserviceService, vdbService: VdbService) { + dataserviceService: DataserviceService, selectionService: SelectionService, vdbService: VdbService) { this.bsModalRef = bsModalRef; this.loggerService = logger; this.dataserviceService = dataserviceService; - const dService = this.dataserviceService.getSelectedDataservice(); + this.selectionService = selectionService; + const dService = this.selectionService.getSelectedVirtualization(); if ( dService && dService !== null ) { this.serviceVdbName = dService.getServiceVdbName(); } diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 5fc0426b..67974d12 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -72,7 +72,7 @@

    - + diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 0c1d6457..cf50f70c 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -452,8 +452,8 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn public onTest(svcName: string): void { const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); - this.dataserviceService.setSelectedDataservice(selectedService); - this.allSvcViewNames = this.dataserviceService.getSelectedDataserviceViewNames(); + this.selectionService.setSelectedVirtualization(selectedService); + this.allSvcViewNames = this.selectionService.getSelectedVirtualizationViewNames(); this.selectedSvcViewNames = []; this.selectedSvcViewNames.push(this.allServiceViewNames[0]); @@ -661,7 +661,6 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn (dataservices) => { for (const ds of dataservices) { if (ds.getId() === virtName) { - self.dataserviceService.setSelectedDataservice(ds); self.selectionService.setSelectedVirtualization(ds); self.createView(ds, viewDefn); } @@ -678,7 +677,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } private createView(dataservice: Dataservice, viewDefn: ViewDefinition): void { - const selectedDs = this.dataserviceService.getSelectedDataservice(); + const selectedDs = this.selectionService.getSelectedVirtualization(); let editorId = ""; if ( selectedDs || selectedDs !== null ) { editorId = this.getEditorStateId(selectedDs, viewDefn); @@ -731,13 +730,10 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn */ public onEdit(svcName: string): void { const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); - this.dataserviceService.setSelectedDataservice(selectedService); + this.selectionService.setSelectedVirtualization(selectedService); this.closeLookPanels(); - // Sets the selected dataservice and edit mode before transferring - this.selectionService.setSelectedVirtualization(selectedService); - const link: string[] = [ DataservicesConstants.viewPath ]; this.logger.debug("[DataservicesPageComponent] Navigating to: %o", link); this.router.navigate(link).then(() => { @@ -750,8 +746,8 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn */ public onQuickLook(svcName: string): void { const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); - this.dataserviceService.setSelectedDataservice(selectedService); - this.allSvcViewNames = this.dataserviceService.getSelectedDataserviceViewNames(); + this.selectionService.setSelectedVirtualization(selectedService); + this.allSvcViewNames = this.selectionService.getSelectedVirtualizationViewNames(); this.selectedSvcViewNames = []; this.selectedSvcViewNames.push(this.allServiceViewNames[0]); const viewName = this.selectedSvcViewNames[0]; @@ -776,7 +772,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn */ public onOdataLook(svcName: string): void { const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); - this.dataserviceService.setSelectedDataservice(selectedService); + this.selectionService.setSelectedVirtualization(selectedService); if (!this.odataEditorShowing) { this.setOdataEditorPanelOpenState(true); diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.ts b/ngapp/src/app/dataservices/odata-control/odata-control.component.ts index 70ef9b5b..c9e8d001 100644 --- a/ngapp/src/app/dataservices/odata-control/odata-control.component.ts +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.ts @@ -28,6 +28,7 @@ import { Odata } from "@dataservices/odata-control/odata.model"; import { OdataEntity } from "@dataservices/odata-control/odata-entity.model"; import { OdataColumn } from "@dataservices/odata-control/odata-column.model"; import { OdataWhere } from "@dataservices/odata-control/odata-where.model"; +import { SelectionService } from "@core/selection.service"; @Component({ encapsulation: ViewEncapsulation.None, @@ -44,6 +45,7 @@ export class OdataControlComponent implements OnChanges { private dataserviceService: DataserviceService; private dataservice: Dataservice; private logger: LoggerService; + private selectionService: SelectionService; public i18n: OdataConstants = new OdataConstants(); public searchMsg: string; @@ -91,9 +93,11 @@ export class OdataControlComponent implements OnChanges { // public results: string = null; - constructor( dataserviceService: DataserviceService, logger: LoggerService ) { + constructor( dataserviceService: DataserviceService, logger: LoggerService, + selectionService: SelectionService ) { this.dataserviceService = dataserviceService; this.logger = logger; + this.selectionService = selectionService; } public get rootUrl(): string { @@ -105,7 +109,7 @@ export class OdataControlComponent implements OnChanges { } public ngOnChanges(changes: SimpleChanges): void { - this.dataservice = this.dataserviceService.getSelectedDataservice(); + this.dataservice = this.selectionService.getSelectedVirtualization(); this.metadataFetchInProgress = false; diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ngapp/src/app/dataservices/shared/dataservice.model.ts index 73b53057..2f3bc98b 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.model.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.model.ts @@ -105,10 +105,7 @@ export class Dataservice implements Identifiable< string > { * @returns {string} the dataservice Vdb name (can be null) */ public getServiceVdbName(): string { - if (this.serviceVdbName && this.serviceVdbName !== null) { - return this.serviceVdbName; - } - return ""; + return this.serviceVdbName; } /** diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 1d14e149..84185875 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -41,8 +41,6 @@ import { Subject } from "rxjs/Subject"; import { Subscription } from "rxjs/Subscription"; import * as _ from "lodash"; import * as vkbeautify from 'vkbeautify'; -import { ViewDefinition } from "@dataservices/shared/view-definition.model"; -import { SqlView } from "@dataservices/shared/sql-view.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; @Injectable() @@ -60,8 +58,6 @@ export class DataserviceService extends ApiService { private notifierService: NotifierService; private appSettingsService: AppSettingsService; private vdbService: VdbService; - private selectedDataservice: Dataservice; - private dataserviceCurrentViewDefinition: ViewDefinition[] = []; private cachedDataserviceDeployStates: Map = new Map(); private cachedDataserviceVirtualizations: Map = new Map(); private updatesSubscription: Subscription; @@ -93,92 +89,6 @@ export class DataserviceService extends ApiService { return ds; } - /** - * Set the current Dataservice selection - * @param {Dataservice} service the Dataservice - */ - public setSelectedDataservice(service: Dataservice): void { - this.selectedDataservice = service; - // When the dataservice is selected, init the selected view - const viewDefns: ViewDefinition[] = this.getSelectedDataserviceViews(); - this.dataserviceCurrentViewDefinition = []; - if (viewDefns && viewDefns.length > 0) { - this.dataserviceCurrentViewDefinition.push(viewDefns[0]); - } - } - - /** - * Get the current Dataservice selection - * @returns {Dataservice} the selected Dataservice - */ - public getSelectedDataservice( ): Dataservice { - return this.selectedDataservice; - } - - /** - * Get the current Dataservice selection's views.View - * The ViewDefinition name is currently set to the full "modelName"."viewName" of the view. - * @returns {ViewDefinition[]} the selected Dataservice view definitions - */ - public getSelectedDataserviceViews( ): ViewDefinition[] { - if (!this.selectedDataservice || this.selectedDataservice === null) { - return []; - } - - const modelName = this.selectedDataservice.getServiceViewModel(); - const serviceViews = this.selectedDataservice.getServiceViewNames(); - - // build the views using the model and view names - const allViews: ViewDefinition[] = []; - for ( const serviceView of serviceViews ) { - const aView: ViewDefinition = new ViewDefinition(); - aView.setName(modelName + "." + serviceView); - - allViews.push(aView); - } - - return allViews; - } - - /** - * Get the current Dataservice selection's views.View - * The ViewDefinition name is currently set to the full "modelName"."viewName" of the view. - * @returns {ViewDefinition[]} the selected Dataservice view definitions - */ - public getSelectedDataserviceViewNames( ): SqlView[] { - if (!this.selectedDataservice || this.selectedDataservice === null) { - return []; - } - - const modelName = this.selectedDataservice.getServiceViewModel(); - const serviceViews = this.selectedDataservice.getServiceViewNames(); - - const allViewNames: SqlView[] = []; - for ( const serviceView of serviceViews ) { - allViewNames.push(new SqlView(modelName + "." + serviceView)); - } - - return allViewNames; - } - - /** - * Get the current Dataservice current view. The table object is used for the view, - * with the View name set to the full "modelName"."viewName" of the view. - * @returns {ViewDefinition[]} the Dataservice current view definition - */ - public getSelectedDataserviceCurrentView( ): ViewDefinition[] { - return this.dataserviceCurrentViewDefinition; - } - - /** - * Set the current Dataservice current view. The table object is used for the view, - * with the View name set to the full "modelName"."viewName" of the view. - * @param {ViewDefinition[]} view the current view - */ - public setSelectedDataserviceCurrentView( view: ViewDefinition[] ): void { - this.dataserviceCurrentViewDefinition = view; - } - /** * Validates the specified data service name. If the name contains valid characters and the name is unique, the * service returns 'null'. Otherwise, a 'string' containing an error message is returned. diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 4ae48741..2da38ef4 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -32,8 +32,6 @@ import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; import { ErrorObservable } from "rxjs/observable/ErrorObservable"; -import { ViewDefinition } from "@dataservices/shared/view-definition.model"; -import { SqlView } from "@dataservices/shared/sql-view.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; @Injectable() @@ -57,12 +55,6 @@ export class MockDataserviceService extends DataserviceService { this.queryResults = testDataService.getQueryResults(); this.editorViewStateMap = testDataService.getViewEditorStateMap(); - - // set selected dataservice, so it's not empty - const ds = new Dataservice(); - ds.setId("testDs"); - ds.setServiceVdbName("testDsVdb"); - this.setSelectedDataservice(ds); } /** @@ -101,46 +93,6 @@ export class MockDataserviceService extends DataserviceService { return Observable.of( true ); } - /** - * Set the current Dataservice selection - * @param {Dataservice} service the Dataservice - */ - public setSelectedDataservice(service: Dataservice): void { - this.selectedDs = service; - } - - /** - * Get the current Dataservice selection - * @returns {Dataservice} the selected Dataservice - */ - public getSelectedDataservice( ): Dataservice { - return this.selectedDs; - } - - /** - * Get the view definitions for the selected Dataservice - * @returns {ViewDefinition[]} the view definitions - */ - public getSelectedDataserviceViews(): ViewDefinition[] { - const table: ViewDefinition = new ViewDefinition(); - table.setName("views.View1"); - const tables: ViewDefinition[] = []; - tables.push(table); - - return tables; - } - - /** - * Get the views for the selected Dataservice - * @returns {SqlView[]} the views - */ - public getSelectedDataserviceViewNames(): SqlView[] { - const views: SqlView[] = []; - views.push(new SqlView("views.View1")); - - return views; - } - /** * Query a Dataservice via the komodo rest interface * @param {string} query the SQL query diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts index 0d05e1ab..32ccd4d2 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts @@ -7,9 +7,9 @@ import { LoggerService } from "@core/logger.service"; import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { SelectionService } from "@core/selection.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { CodemirrorModule } from "ng2-codemirror"; import { @@ -25,6 +25,7 @@ import { } from "patternfly-ng"; import { SqlControlComponent } from "./sql-control.component"; import { SqlView } from "@dataservices/shared/sql-view.model"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; describe("SqlControlComponent", () => { let component: SqlControlComponent; @@ -51,6 +52,7 @@ describe("SqlControlComponent", () => { AppSettingsService, LoggerService, NotifierService, + SelectionService, { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } @@ -66,8 +68,10 @@ describe("SqlControlComponent", () => { const service = TestBed.get( DataserviceService ); let dataservices: Dataservice[]; service.getAllDataservices().subscribe( ( values ) => { dataservices = values; } ); + + const selService = TestBed.get( SelectionService ); // noinspection JSUnusedAssignment - service.setSelectedDataservice( dataservices[ 0 ] ); + selService.setSelectedVirtualization( dataservices[ 0 ] ); fixture = TestBed.createComponent(SqlControlComponent); component = fixture.componentInstance; diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts index 866c190a..3115404e 100644 --- a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts +++ b/ngapp/src/app/dataservices/sql-control/sql-control.component.ts @@ -28,6 +28,7 @@ import "codemirror/addon/selection/active-line.js"; import "codemirror/mode/sql/sql.js"; import { NgxDataTableConfig, TableConfig } from "patternfly-ng"; import { SqlView } from "@dataservices/shared/sql-view.model"; +import { SelectionService } from "@core/selection.service"; @Component({ encapsulation: ViewEncapsulation.None, @@ -62,15 +63,18 @@ export class SqlControlComponent implements OnInit { private dataserviceService: DataserviceService; private logger: LoggerService; + private selectionService: SelectionService; private showResults = false; private queryResultsLoading: LoadingState; private queryResults: QueryResults; private queryMap: Map = new Map(); private previousViewName: string; - constructor( dataserviceService: DataserviceService, logger: LoggerService ) { + constructor( dataserviceService: DataserviceService, logger: LoggerService, + selectionService: SelectionService ) { this.dataserviceService = dataserviceService; this.logger = logger; + this.selectionService = selectionService; } public ngOnInit(): void { @@ -138,7 +142,7 @@ export class SqlControlComponent implements OnInit { * Submit the currently entered SQL */ public submitCurrentQuery( ): void { - this.submitQuery(this.queryText, this.dataserviceService.getSelectedDataservice().getId(), 15, 0); + this.submitQuery(this.queryText, this.selectionService.getSelectedVirtualization().getId(), 15, 0); } /* diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts index cefa4817..02f4b467 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts @@ -23,6 +23,7 @@ import { SortModule, TableModule, WizardModule } from "patternfly-ng"; +import { SelectionService } from "@core/selection.service"; describe("TestDataserviceComponent", () => { let component: TestDataserviceComponent; @@ -47,7 +48,7 @@ describe("TestDataserviceComponent", () => { ], declarations: [ SqlControlComponent, TestDataserviceComponent ], providers: [ - NotifierService, + NotifierService, SelectionService, { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } @@ -63,8 +64,10 @@ describe("TestDataserviceComponent", () => { const service = TestBed.get( DataserviceService ); let dataservices: Dataservice[]; service.getAllDataservices().subscribe( ( values ) => { dataservices = values; } ); + + const selService = TestBed.get( SelectionService ); // noinspection JSUnusedAssignment - service.setSelectedDataservice( dataservices[ 0 ] ); + selService.setSelectedVirtualization( dataservices[ 1 ] ); fixture = TestBed.createComponent(TestDataserviceComponent); component = fixture.componentInstance; diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts index 053bea10..49850121 100644 --- a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts +++ b/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts @@ -3,11 +3,11 @@ import { Router } from "@angular/router"; import { ActivatedRoute } from "@angular/router"; import { LoggerService } from "@core/logger.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; import { AbstractPageComponent } from "@shared/abstract-page.component"; import { LoadingState } from "@shared/loading-state.enum"; import { SqlView } from "@dataservices/shared/sql-view.model"; +import { SelectionService } from "@core/selection.service"; @Component({ selector: "app-test-dataservice", @@ -21,20 +21,20 @@ export class TestDataserviceComponent extends AbstractPageComponent { public pageError: any = ""; private dataservice: Dataservice; - private dataserviceService: DataserviceService; + private selectionService: SelectionService; private pageLoadingState: LoadingState = LoadingState.LOADED_VALID; private selectedSvcViewNames: SqlView[] = []; private allSvcViewNames: SqlView[] = []; private quickLookQueryText: string; - constructor( router: Router, route: ActivatedRoute, dataserviceService: DataserviceService, logger: LoggerService ) { + constructor( router: Router, route: ActivatedRoute, selectionService: SelectionService, logger: LoggerService ) { super(route, logger); - this.dataserviceService = dataserviceService; + this.selectionService = selectionService; } public loadAsyncPageData(): void { - this.dataservice = this.dataserviceService.getSelectedDataservice(); - this.allSvcViewNames = this.dataserviceService.getSelectedDataserviceViewNames(); + this.dataservice = this.selectionService.getSelectedVirtualization(); + this.allSvcViewNames = this.selectionService.getSelectedVirtualizationViewNames(); this.selectedSvcViewNames = []; this.selectedSvcViewNames.push(this.allSvcViewNames[0]); const viewName = this.selectedSvcViewNames[0]; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts index c5097ce6..04cfebdb 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts @@ -8,13 +8,12 @@ import { NotificationModule } from "patternfly-ng"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { SelectionService } from "@core/selection.service"; describe('CreateViewDialogComponent', () => { let component: CreateViewDialogComponent; @@ -31,8 +30,7 @@ describe('CreateViewDialogComponent', () => { NotificationModule ], declarations: [ CreateViewDialogComponent ], - providers: [ AppSettingsService, BsModalRef, LoggerService, NotifierService, - { provide: DataserviceService, useClass: MockDataserviceService }, + providers: [ AppSettingsService, BsModalRef, LoggerService, NotifierService, SelectionService, { provide: VdbService, useClass: MockVdbService } ] }) diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts index a51eec6f..b62a4457 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts @@ -23,8 +23,8 @@ import { LoggerService } from "@core/logger.service"; import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; import { AbstractControl, FormControl, FormGroup } from "@angular/forms"; import { VdbService } from "@dataservices/shared/vdb.service"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { ViewDefinition } from "@dataservices/shared/view-definition.model"; +import { SelectionService } from "@core/selection.service"; @Component({ selector: "app-create-view-dialog", @@ -60,16 +60,16 @@ export class CreateViewDialogComponent implements OnInit { public viewPropertyForm: FormGroup; private loggerService: LoggerService; - private dataserviceService: DataserviceService; + private selectionService: SelectionService; private vdbService: VdbService; private serviceVdbName = ""; constructor(bsModalRef: BsModalRef, logger: LoggerService, - dataserviceService: DataserviceService, vdbService: VdbService) { + selectionService: SelectionService, vdbService: VdbService) { this.bsModalRef = bsModalRef; this.loggerService = logger; - this.dataserviceService = dataserviceService; - const dService = this.dataserviceService.getSelectedDataservice(); + this.selectionService = selectionService; + const dService = this.selectionService.getSelectedVirtualization(); if ( dService && dService !== null ) { this.serviceVdbName = dService.getServiceVdbName(); } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts index 425a981d..ef5e7bdb 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts @@ -23,6 +23,7 @@ import { SortModule, TableModule, WizardModule } from "patternfly-ng"; +import { SelectionService } from "@core/selection.service"; describe('EditorViewsComponent', () => { let component: EditorViewsComponent; @@ -53,6 +54,7 @@ describe('EditorViewsComponent', () => { { provide: DataserviceService, useClass: MockDataserviceService }, LoggerService, NotifierService, + SelectionService, { provide: VdbService, useClass: MockVdbService }, ViewEditorService ] diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts index 0f0276f4..12d2da53 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts @@ -20,6 +20,7 @@ import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; import { MessageLogComponent } from '@dataservices/virtualization/view-editor/editor-views/message-log/message-log.component'; +import { SelectionService } from "@core/selection.service"; describe('MessageLogComponent', () => { let component: MessageLogComponent; @@ -45,6 +46,7 @@ describe('MessageLogComponent', () => { { provide: DataserviceService, useClass: MockDataserviceService }, LoggerService, NotifierService, + SelectionService, { provide: VdbService, useClass: MockVdbService }, ViewEditorService ] diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts index 38607cd0..46279900 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts @@ -21,6 +21,7 @@ import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.se import { VdbService } from "@dataservices/shared/vdb.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; +import { SelectionService } from "@core/selection.service"; describe("ViewPreviewComponent", () => { let component: ViewPreviewComponent; @@ -47,6 +48,7 @@ describe("ViewPreviewComponent", () => { { provide: DataserviceService, useClass: MockDataserviceService }, LoggerService, NotifierService, + SelectionService, { provide: VdbService, useClass: MockVdbService }, ViewEditorService ] diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts index 8172c27e..81807ab5 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts @@ -24,6 +24,7 @@ import { ViewPropertyEditorsComponent } from "@dataservices/virtualization/view- import { TabsModule } from "ngx-bootstrap"; import { GraphVisualComponent, LinkVisualComponent, NodeVisualComponent } from "@dataservices/virtualization/view-editor/view-canvas/visuals"; import { CanvasService } from "@dataservices/virtualization/view-editor/view-canvas/canvas.service"; +import { SelectionService } from "@core/selection.service"; describe('ViewCanvasComponent', () => { let component: ViewCanvasComponent; @@ -57,6 +58,7 @@ describe('ViewCanvasComponent', () => { CanvasService, LoggerService, NotifierService, + SelectionService, { provide: VdbService, useClass: MockVdbService }, ViewEditorService ] diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts index 21783d23..9eb4201b 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts @@ -15,6 +15,7 @@ import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.se import { TableModule } from "patternfly-ng"; import { SelectionService } from "@core/selection.service"; import { BsModalService } from "ngx-bootstrap"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; describe('ViewEditorHeaderComponent', () => { let component: ViewEditorHeaderComponent; @@ -46,6 +47,14 @@ describe('ViewEditorHeaderComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ViewEditorHeaderComponent); component = fixture.componentInstance; + + const selService = TestBed.get( SelectionService ); + const ds: Dataservice = new Dataservice(); + ds.setId("testDs"); + ds.setServiceVdbName("testDsVdb"); + // noinspection JSUnusedAssignment + selService.setSelectedVirtualization( ds ); + fixture.detectChanges(); }); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index 07f72cd1..73688d07 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -146,7 +146,7 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { */ private initViews( ): void { this.viewsLoadingState = LoadingState.LOADING; - this.selectedVirtualization = this.dataserviceService.getSelectedDataservice(); + this.selectedVirtualization = this.selectionService.getSelectedVirtualization(); if ( !this.selectedVirtualization || this.selectedVirtualization === null ) { this.tableRows = []; } @@ -303,7 +303,7 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { } private createNewView(viewDefn: ViewDefinition): void { - const selectedDs = this.dataserviceService.getSelectedDataservice(); + const selectedDs = this.selectionService.getSelectedVirtualization(); const editorId = this.getEditorStateId(selectedDs, viewDefn); // Create new editor state to save @@ -367,7 +367,7 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { */ private doDeleteView(viewDefnName: string): void { const selectedViewDefn = this.tableRows.find((x) => x.getName() === viewDefnName); - const selectedDs = this.dataserviceService.getSelectedDataservice(); + const selectedDs = this.selectionService.getSelectedVirtualization(); const vdbName = selectedDs.getServiceVdbName(); const editorStateId = vdbName.toLowerCase() + "." + viewDefnName; const dataserviceName = selectedDs.getId(); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts index 949da1e7..7b6ce613 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts @@ -9,6 +9,7 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { ViewEditorService } from '@dataservices/virtualization/view-editor/view-editor.service'; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { SelectionService } from "@core/selection.service"; describe('ViewEditorService', () => { beforeEach(() => { @@ -21,6 +22,7 @@ describe('ViewEditorService', () => { { provide: DataserviceService, useClass: MockDataserviceService }, LoggerService, NotifierService, + SelectionService, { provide: VdbService, useClass: MockVdbService }, ViewEditorService ] diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index fc1e01ec..f0cef83e 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -41,6 +41,7 @@ import { RemoveCompositionCommand } from "@dataservices/virtualization/view-edit import { ViewDefinition } from "@dataservices/shared/view-definition.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { SelectionService } from "@core/selection.service"; @Injectable() export class ViewEditorService { @@ -65,6 +66,7 @@ export class ViewEditorService { private _shouldFireEvents = true; private _undoMgr: UndoManager; private readonly _dataserviceService: DataserviceService; + private readonly _selectionService: SelectionService; private readonly _vdbService: VdbService; private _warningMsgCount = 0; private _selection: string[] = []; @@ -72,9 +74,11 @@ export class ViewEditorService { constructor( logger: LoggerService, dataserviceService: DataserviceService, + selectionService: SelectionService, vdbService: VdbService ) { this._logger = logger; this._dataserviceService = dataserviceService; + this._selectionService = selectionService; this._vdbService = vdbService; this._undoMgr = new UndoManager(); } @@ -424,7 +428,7 @@ export class ViewEditorService { editorState.setUndoables(this._undoMgr.toArray()); editorState.setViewDefinition(this._editorView); - const dataserviceName = this._dataserviceService.getSelectedDataservice().getId(); + const dataserviceName = this._selectionService.getSelectedVirtualization().getId(); this._dataserviceService.saveViewEditorStateRefreshViews( editorState, dataserviceName ).subscribe( () => { // fire save editor state succeeded event diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts index 9b5653d8..dc02c4ad 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts @@ -12,6 +12,7 @@ import { MockAppSettingsService } from "@core/mock-app-settings.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { SelectionService } from "@core/selection.service"; describe('ViewPropertyEditorsComponent', () => { let component: ViewPropertyEditorsComponent; @@ -29,6 +30,7 @@ describe('ViewPropertyEditorsComponent', () => { { provide: DataserviceService, useClass: MockDataserviceService }, LoggerService, NotifierService, + SelectionService, { provide: VdbService, useClass: MockVdbService }, ViewEditorService ] From fb77c1a93c14c02ffb63103966c8e98fd0b0ee73 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 4 Sep 2018 14:41:45 -0500 Subject: [PATCH 184/205] TEIIDTOOLS-480 Adjustments to layouts and selection --- .../dataservice-card.component.css | 22 +++++++++++++---- .../dataservice-card.component.html | 2 +- .../dataservice-card.component.ts | 24 +++++++++++++++++-- .../dataservices-cards.component.ts | 10 +++++--- .../dataservices-details.component.ts | 6 ++--- .../dataservices-list.component.html | 6 +++-- .../dataservices-list.component.ts | 10 ++++++-- .../views-content.component.html | 4 ++-- .../views-content.component.ts | 16 ++++++++++--- .../dataservices/dataservices.component.ts | 16 ++++++++++--- .../dataservices/shared/name-value.model.ts | 8 +++++++ .../view-editor-header.component.ts | 12 ++++++++-- .../view-editor/view-editor-i18n.ts | 2 +- .../view-editor/view-editor.service.ts | 9 ++++--- ngapp/src/styles.css | 4 ++-- 15 files changed, 118 insertions(+), 33 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index 77b7e706..45ff33af 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -46,10 +46,6 @@ a.list-pf-title.view-name { margin-left: 10px !important; } -.views-details { - background-color: var(--card-body-background-color); -} - .list-pf-container { -ms-flex-align: start; align-items: flex-start; @@ -75,3 +71,21 @@ a.list-pf-title.view-name { #publishing-card-icons .CodeMirror { height: 80vh; } + +.views-details { + background-color: transparent; +} +.views-details:hover { + background-color: transparent; +} + +.views-details .blank-slate-pf { + background-color: transparent; + min-width: 200px; + border: none; + padding: 0; +} + +.views-details h1, .h1 { + font-size: 14px; +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index 9cf1a916..d614293d 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -187,7 +187,7 @@

    Publishing Logs for '{{dataservice.getId()}}'

    - {{ item }} + {{ item }}
    diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts index 72a0af5e..5d02ce11 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts @@ -20,12 +20,13 @@ import { } from "@angular/core"; import * as _ from "lodash"; import { LoggerService } from "@core/logger.service"; -import { Action, ActionConfig, CardAction, CardConfig, ListConfig } from "patternfly-ng"; +import { Action, ActionConfig, CardAction, CardConfig, EmptyStateConfig, ListConfig } from "patternfly-ng"; import { Observable } from "rxjs/Observable"; import { Subscription } from "rxjs/Subscription"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { Connection } from "@connections/shared/connection.model"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; @Component({ encapsulation: ViewEncapsulation.None, @@ -74,6 +75,7 @@ export class DataserviceCardComponent implements DoCheck, OnInit { private isLoading = true; private logger: LoggerService; private dataserviceService: DataserviceService; + private emptyStateConfig: EmptyStateConfig; public publishLogsEditorConfig = { lineNumbers: true, @@ -216,13 +218,19 @@ export class DataserviceCardComponent implements DoCheck, OnInit { topBorder: false } as CardConfig; + this.emptyStateConfig = { + title: ViewEditorI18n.noViewsDefined + } as EmptyStateConfig; + this.listConfig = { dblClick: false, multiSelect: false, selectItems: false, showCheckbox: false, - useExpandItems: false + useExpandItems: false, + emptyStateConfig: this.emptyStateConfig } as ListConfig; + } /** @@ -233,6 +241,18 @@ export class DataserviceCardComponent implements DoCheck, OnInit { this.cardEvent.emit( { eventType: type, dataserviceName: this.dataservice.getId() } ); } + /** + * An event handler for when edit view is invoked. + * @param {string} vName the name of the view in the selected dataservice + */ + public onEditView( vName: string ): void { + this.cardEvent.emit( { + eventType: DataserviceCardComponent.editDataserviceEvent, + dataserviceName: this.dataservice.getId(), + viewName: vName + } ); + } + /** * An event handler for when the card is clicked. */ diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts index 3950a052..e2aa4d46 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts @@ -19,6 +19,7 @@ import { Component, EventEmitter, Input, Output, ViewEncapsulation } from "@angu import { LoggerService } from "@core/logger.service"; import { DataserviceCardComponent } from "@dataservices/dataservices-cards/dataservice-card/dataservice-card.component"; import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { NameValue } from "@dataservices/shared/name-value.model"; @Component({ moduleId: module.id, @@ -37,7 +38,7 @@ export class DataservicesCardsComponent { @Output() public testDataservice: EventEmitter = new EventEmitter(); @Output() public publishDataservice: EventEmitter = new EventEmitter(); @Output() public deleteDataservice: EventEmitter = new EventEmitter(); - @Output() public editDataservice: EventEmitter = new EventEmitter(); + @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); @Output() public downloadDataservice: EventEmitter = new EventEmitter(); @Output() public odataLookDataservice: EventEmitter = new EventEmitter(); @@ -55,13 +56,16 @@ export class DataservicesCardsComponent { return this.selectedDataservices.indexOf( dataservice ) !== -1; } - public onCardEvent( event: { eventType: string, dataserviceName: string } ): void { + public onCardEvent( event: { eventType: string, dataserviceName: string, viewName: string } ): void { switch ( event.eventType ) { case DataserviceCardComponent.deleteDataserviceEvent: this.deleteDataservice.emit( event.dataserviceName ); break; case DataserviceCardComponent.editDataserviceEvent: - this.editDataservice.emit( event.dataserviceName ); + const dsName = event.dataserviceName; + const viewName = event.viewName; + const nameVal = new NameValue(dsName, viewName); + this.editDataservice.emit( nameVal ); break; case DataserviceCardComponent.publishDataserviceEvent: this.publishDataservice.emit( event.dataserviceName ); diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts index e8227d8d..86a2d541 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts @@ -26,7 +26,7 @@ import { DataservicesConstants } from "../shared/dataservices-constants"; templateUrl: "dataservices-details.component.html" }) export class DataservicesDetailsComponent implements OnInit { - @Input() public item: Dataservice; + @Input() public virtualization: Dataservice; public listConfig: ListConfig; @@ -49,8 +49,8 @@ export class DataservicesDetailsComponent implements OnInit { */ public get properties(): string[][] { const props = [ - [ DataservicesConstants.dataserviceNameLabel, this.item.getId() ], - [ DataservicesConstants.descriptionLabel, this.item.getDescription() ] + [ DataservicesConstants.dataserviceNameLabel, this.virtualization.getId() ], + [ DataservicesConstants.descriptionLabel, this.virtualization.getDescription() ] ]; return props; diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index 058f55fc..2280affd 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -166,8 +166,10 @@

    Publishing Logs for '{{item.getId()}}'

    - - + +
    diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts index 4b138dff..2a643d45 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts @@ -31,6 +31,7 @@ import { Subscription } from "rxjs/Subscription"; import * as _ from "lodash"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { Dataservice } from "@dataservices/shared/dataservice.model"; +import { NameValue } from "@dataservices/shared/name-value.model"; @Component({ encapsulation: ViewEncapsulation.None, @@ -64,7 +65,7 @@ export class DataservicesListComponent implements OnInit { @Output() public publishDataservice: EventEmitter = new EventEmitter(); @Output() public downloadDataservice: EventEmitter = new EventEmitter(); @Output() public deleteDataservice: EventEmitter = new EventEmitter(); - @Output() public editDataservice: EventEmitter = new EventEmitter(); + @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); @Output() public odataLookDataservice: EventEmitter = new EventEmitter(); @@ -247,7 +248,12 @@ export class DataservicesListComponent implements OnInit { } public onEditDataservice(dataserviceName: string): void { - this.editDataservice.emit(dataserviceName); + const nameVal = new NameValue(dataserviceName, null); + this.editDataservice.emit(nameVal); + } + + public onEditView(dsNameView: NameValue): void { + this.editDataservice.emit(dsNameView); } public onPreviewDataservice( dataserviceName: string): void { diff --git a/ngapp/src/app/dataservices/dataservices-list/views-content.component.html b/ngapp/src/app/dataservices/dataservices-list/views-content.component.html index 6f745369..54f242d2 100644 --- a/ngapp/src/app/dataservices/dataservices-list/views-content.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/views-content.component.html @@ -5,11 +5,11 @@ [config]="listConfig" [itemTemplate]="itemTemplate" [expandTemplate]="expandTemplate" - [items]="getViews( item )"> + [items]="getViews( virtualization )">
    - {{ item }} + {{ item }}
    diff --git a/ngapp/src/app/dataservices/dataservices-list/views-content.component.ts b/ngapp/src/app/dataservices/dataservices-list/views-content.component.ts index 93705778..f90e9bb9 100644 --- a/ngapp/src/app/dataservices/dataservices-list/views-content.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/views-content.component.ts @@ -15,10 +15,11 @@ * limitations under the License. */ -import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core"; +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from "@angular/core"; import { Connection } from "@connections/shared/connection.model"; import { Dataservice } from "@dataservices/shared/dataservice.model"; import { ListConfig } from "patternfly-ng"; +import { NameValue } from "@dataservices/shared/name-value.model"; @Component({ encapsulation: ViewEncapsulation.None, @@ -27,8 +28,8 @@ import { ListConfig } from "patternfly-ng"; }) export class ViewsContentComponent implements OnInit { - @Input() public item: Dataservice; - @Input() public selectedDataservices: Dataservice[]; + @Input() public virtualization: Dataservice; + @Output() public editDataservice: EventEmitter = new EventEmitter(); public listConfig: ListConfig; @@ -83,4 +84,13 @@ export class ViewsContentComponent implements OnInit { } as ListConfig; } + /** + * An event handler for when edit view is invoked. + * @param {string} vName the name of the view in the selected dataservice + */ + public onEditView( vName: string ): void { + const nameVal = new NameValue(this.virtualization.getId(), vName); + this.editDataservice.emit(nameVal); + } + } diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index cf50f70c..100a8288 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -55,6 +55,7 @@ import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-ed import { CreateVirtualizationDialogComponent } from "@dataservices/create-virtualization-dialog/create-virtualization-dialog.component"; import { ViewDefinition } from "@dataservices/shared/view-definition.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; +import { NameValue } from "@dataservices/shared/name-value.model"; @Component({ moduleId: module.id, @@ -725,13 +726,22 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } /** - * Handle Edit of the specified Dataservice + * Handle Edit of the specified Dataservice and View * @param {string} svcName */ - public onEdit(svcName: string): void { - const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); + public onEdit(svcNameView: NameValue): void { + const virtName = svcNameView.getName(); + const selectedService = this.filteredDataservices.find((x) => x.getId() === virtName); this.selectionService.setSelectedVirtualization(selectedService); + const viewName = svcNameView.getValue(); + let viewDefn: ViewDefinition = null; + if (viewName && viewName !== null) { + viewDefn = new ViewDefinition(); + viewDefn.setName(viewName); + } + this.selectionService.setSelectedViewDefinition(selectedService, viewDefn); + this.closeLookPanels(); const link: string[] = [ DataservicesConstants.viewPath ]; diff --git a/ngapp/src/app/dataservices/shared/name-value.model.ts b/ngapp/src/app/dataservices/shared/name-value.model.ts index 9c6dc97c..4d901695 100644 --- a/ngapp/src/app/dataservices/shared/name-value.model.ts +++ b/ngapp/src/app/dataservices/shared/name-value.model.ts @@ -28,4 +28,12 @@ export class NameValue { this.value = value; } + public getName(): string { + return this.name; + } + + public getValue(): string { + return this.value; + } + } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index 73688d07..f6f56ea6 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -130,7 +130,7 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { } as NgxDataTableConfig; this.emptyStateConfig = { - title: ViewEditorI18n.noViewsFound + title: ViewEditorI18n.noViewsDefined } as EmptyStateConfig; this.tableConfig = { @@ -151,6 +151,8 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { this.tableRows = []; } + const selectedView = this.selectionService.getSelectedViewDefinition(); + const vdbName = this.selectedVirtualization.getServiceVdbName(); const editorStatesPattern = vdbName.toLowerCase() + "*"; @@ -171,7 +173,13 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { if (left.getName() > right.getName()) return 1; return 0; }); - const initialView = (self.tableRows && self.tableRows.length > 0) ? self.tableRows[0] : null; + + let initialView: ViewDefinition = null; + if (!selectedView || selectedView === null) { + initialView = (self.tableRows && self.tableRows.length > 0) ? self.tableRows[0] : null; + } else { + initialView = self.tableRows.find((x) => x.getName() === selectedView.getName()); + } self.selectView(initialView); self.viewsLoadingState = LoadingState.LOADED_VALID; }, diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts index 15772a03..2211742a 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts @@ -113,7 +113,7 @@ export class ViewEditorI18n { // view editor header public static readonly viewDescriptionLabel = "Selected View Description"; public static readonly viewDescriptionPlaceholder = "Enter a view description"; - public static readonly noViewsFound = "No views found"; + public static readonly noViewsDefined = "No views defined"; // view preview public static readonly previewDataUnavailable = "Preview data unavailable"; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index f0cef83e..e5ed7ae7 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -430,14 +430,17 @@ export class ViewEditorService { const dataserviceName = this._selectionService.getSelectedVirtualization().getId(); + const self = this; this._dataserviceService.saveViewEditorStateRefreshViews( editorState, dataserviceName ).subscribe( () => { + // reset original view to saved state + self._originalView = ViewDefinition.create(this._editorView.toJSON()); // fire save editor state succeeded event - this.fire( ViewEditorEvent.create( ViewEditorPart.EDITOR, + self.fire( ViewEditorEvent.create( ViewEditorPart.EDITOR, ViewEditorEventType.EDITOR_VIEW_SAVE_PROGRESS_CHANGED, [ ViewEditorProgressChangeId.COMPLETED_SUCCESS ] ) ); }, () => { // fire save editor state failed event - this.fire( ViewEditorEvent.create( ViewEditorPart.EDITOR, + self.fire( ViewEditorEvent.create( ViewEditorPart.EDITOR, ViewEditorEventType.EDITOR_VIEW_SAVE_PROGRESS_CHANGED, [ ViewEditorProgressChangeId.COMPLETED_FAILED ] ) ); } @@ -499,7 +502,7 @@ export class ViewEditorService { // Clear preview results this.setPreviewResults(null, null, ViewEditorPart.EDITOR); - var querySql = ""; + let querySql = ""; if ( sourcePath != null && !sourcePath.startsWith(AddCompositionCommand.id) ) { // Fetch new results for source table querySql = this._editorView.getPreviewSql(sourcePath); diff --git a/ngapp/src/styles.css b/ngapp/src/styles.css index e14b7091..d9ddf1f8 100644 --- a/ngapp/src/styles.css +++ b/ngapp/src/styles.css @@ -152,7 +152,7 @@ .object-card-selected .card-pf .card-pf-body, .object-card .card-pf .card-pf-body { - margin: 20px; + margin: 0; padding: 0; } @@ -170,7 +170,7 @@ } .object-card-body { - margin: 0 -20px; + margin: 0; max-height: 200px; overflow-y: auto; } From 6dabe58bccd8474ead4bd5ab561ec7994263ff47 Mon Sep 17 00:00:00 2001 From: blafond Date: Thu, 6 Sep 2018 10:17:33 -0500 Subject: [PATCH 185/205] TEIIDTOOLS-486 * deleting compositions linked to deleted source nodes --- .../view-editor/view-editor.component.ts | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts index eabe28c1..bd0812f9 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts @@ -428,23 +428,43 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { // 3) fire view state changed event for each // ------------------ - let tempCmd: Command = null; - selectionArgs.forEach( ( nextArg ) => { + // need to parse the command to find the source path const commandPart = this.getCommandId(nextArg); + // the payload for src will be the source/connection path + // the payload for the composition will be the json representing the composition properties const argPart = this.getPayload(nextArg); if (commandPart.startsWith(AddSourcesCommand.id)) { - tempCmd = CommandFactory.createRemoveSourcesCommand(argPart, commandPart); + // Look for any composition with src paths links and remove if exist + const comps: Composition[] = this.editorService.getEditorView().getCompositions(); + comps.forEach( (nextComp) => { + const leftPath = nextComp.getLeftSourcePath(); + if (leftPath && leftPath != null && argPart === leftPath) { + let addCompCmd = CommandFactory.createRemoveCompositionCommand(nextComp.toString(), AddCompositionCommand.id); + if (addCompCmd && addCompCmd != null) { + this.notifyRemoved(addCompCmd); + } + } else { + const rightPath = nextComp.getRightSourcePath(); + if (rightPath && rightPath != null && argPart === rightPath) { + let addCompCmd = CommandFactory.createRemoveCompositionCommand(nextComp.toString(), AddCompositionCommand.id); + if (addCompCmd && addCompCmd != null) { + this.notifyRemoved(addCompCmd); + } + } + } + }); + + // Remove Source Command + let addSrcsCmd = CommandFactory.createRemoveSourcesCommand(argPart, commandPart); + this.notifyRemoved(addSrcsCmd); + } else if (commandPart.startsWith(AddCompositionCommand.id)) { - tempCmd = CommandFactory.createRemoveCompositionCommand(argPart, commandPart); - } - if (tempCmd !== null ) { - const cmd = tempCmd as Command; - this.editorService.fireViewStateHasChanged(ViewEditorPart.EDITOR, cmd); - } else { - this.logger.error("Failed to create RemoveSourcesCommand"); + // Remove composition + let addCompCmd = CommandFactory.createRemoveCompositionCommand(argPart, commandPart); + this.notifyRemoved(addCompCmd); } this.editorService.select(null); @@ -452,6 +472,15 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { }); } + private notifyRemoved(command: Command): void { + if (command !== null ) { + const cmd = command as Command; + this.editorService.fireViewStateHasChanged(ViewEditorPart.EDITOR, cmd); + } else { + this.logger.error("Failed to create Remove Command"); + } + } + private doSampleData(selection: string[]): void { if (!selection || selection.length === 0) { alert("Nothing selected for sample data"); From 11a747b99c7799a8dadf0d0c8db72da9683efac4 Mon Sep 17 00:00:00 2001 From: blafond Date: Thu, 6 Sep 2018 14:33:46 -0500 Subject: [PATCH 186/205] TEIIDTOOLS-485 * changed html to use [hidden]="!isShowingCanvas" * moved initViews() call to the ngAfterViewInit() method to allow canvas creation before selection event --- .../view-editor-header/view-editor-header.component.ts | 2 ++ .../virtualization/view-editor/view-editor.component.html | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index f6f56ea6..58a8cc9c 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -136,7 +136,9 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { this.tableConfig = { emptyStateConfig: this.emptyStateConfig } as TableConfig; + } + public ngAfterViewInit(): void { // init the available views this.initViews(); } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html index bdfe1535..e0b9491b 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html @@ -84,7 +84,7 @@
    + [hidden]="!isShowingCanvas">
    From 066952e23d592fff06c7fe8f8984fc042dafa001 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 6 Sep 2018 14:13:27 -0500 Subject: [PATCH 187/205] TEIIDTOOLS-481 Improvements to virtualization activation --- .../dataservice-card.component.html | 10 ++++---- .../dataservices-list.component.html | 12 ++++++---- .../dataservices/shared/mock-vdb.service.ts | 20 ++++++++++++++++ .../view-editor-header.component.ts | 4 ++++ .../view-editor/view-editor.service.ts | 23 +++++++++++++++++++ 5 files changed, 60 insertions(+), 9 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index d614293d..535957ad 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -10,29 +10,29 @@ (onActionSelect)="handleAction($event)">
    - - - -
    - - - - } + */ + public hasWorkspaceVdb(vdbName: string): Observable { + return Observable.of(true); + } + /** * Delete a vdb via the komodo rest interface * @param {string} vdbId @@ -103,6 +114,15 @@ export class MockVdbService extends VdbService { return Observable.of(true); } + /** + * Delete a vdb if found via the komodo rest interface + * @param {string} vdbId + * @returns {Observable} + */ + public deleteVdbIfFound(vdbId: string): Observable { + return Observable.of(true); + } + /** * Deploys the workspace VDB with the provided name * @param {string} vdbName diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index 58a8cc9c..c573e8b4 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -309,6 +309,8 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { } else { this.createNewView(viewDefn); } + // addition of a view undeploys active serviceVdb + this.editorService.undeploySelectedVirtualization(); }); } @@ -389,6 +391,8 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { .subscribe( (wasSuccess) => { self.removeViewDefinitionFromList(selectedViewDefn); + // deletion of a view undeploys active serviceVdb + self.editorService.undeploySelectedVirtualization(); }, (error) => { self.logger.error("[VirtualizationComponent] Error deleting the editor state: %o", error); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index e5ed7ae7..d246a71a 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -42,6 +42,7 @@ import { ViewDefinition } from "@dataservices/shared/view-definition.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { SelectionService } from "@core/selection.service"; +import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; @Injectable() export class ViewEditorService { @@ -434,6 +435,8 @@ export class ViewEditorService { this._dataserviceService.saveViewEditorStateRefreshViews( editorState, dataserviceName ).subscribe( () => { // reset original view to saved state self._originalView = ViewDefinition.create(this._editorView.toJSON()); + // any change to service view undeploys active serviceVdb + self.undeploySelectedVirtualization(); // fire save editor state succeeded event self.fire( ViewEditorEvent.create( ViewEditorPart.EDITOR, ViewEditorEventType.EDITOR_VIEW_SAVE_PROGRESS_CHANGED, @@ -447,6 +450,26 @@ export class ViewEditorService { ); } + /** + * Undeploy the selected virtualization (only if it is active) + */ + public undeploySelectedVirtualization(): void { + this._logger.debug( "[ViewEditorService.undeploySelectedVirtualization]" ); + const selectedVirt = this._selectionService.getSelectedVirtualization(); + if (selectedVirt && selectedVirt !== null && + (selectedVirt.serviceDeploymentActive || selectedVirt.serviceDeploymentFailed)) { + const serviceVdbName = selectedVirt.getServiceVdbName(); + const self = this; + this._vdbService.undeployVdb( serviceVdbName ).subscribe( () => { + self._dataserviceService.updateDataserviceStates(); + self._logger.debug( "[ViewEditorService.undeploySelectedVirtualization] - completed" ); + }, () => { + self._logger.error( "[ViewEditorService.undeploySelectedVirtualization] - error with undeploy" ); + } + ); + } + } + /** * Sets the view being edited. This is called when the editor is first constructed and can only be called once. * Subsequent calls are ignored. From 8aef96f75de5b5eaee4b25c5867f7521bee07224 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 7 Sep 2018 12:13:23 -0500 Subject: [PATCH 188/205] Removal of unused functions and other lint error fixes --- .../add-connection-wizard.component.html | 2 +- .../add-connection-wizard.component.ts | 2 +- .../shared/composition.model.spec.ts | 6 -- .../shared/dataservice.service.ts | 83 ------------------- .../shared/mock-dataservice.service.ts | 7 -- .../dataservices/shared/mock-vdb.service.ts | 2 - .../dataservices/shared/name-value.model.ts | 4 +- .../src/app/dataservices/shared/path-utils.ts | 2 - .../shared/view-editor-state.model.ts | 2 +- .../add-composition-wizard.component.html | 2 +- .../add-composition-wizard.component.ts | 2 +- .../command/add-composition-command.ts | 4 +- .../command/add-sources-command.ts | 2 +- .../command/remove-composition-command.ts | 4 +- .../command/remove-sources-command.ts | 2 +- .../view-preview/view-preview.component.ts | 7 -- .../view-canvas/view-canvas.component.ts | 15 +--- .../view-editor-header.component.ts | 5 +- .../view-editor/view-editor.component.ts | 8 +- .../view-editor/view-editor.service.ts | 1 - 20 files changed, 20 insertions(+), 142 deletions(-) diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html index f22fd15b..fe8a7cbd 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html @@ -1,6 +1,6 @@ diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts index 7ab38a94..34069984 100644 --- a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts +++ b/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts @@ -344,7 +344,7 @@ export class AddConnectionWizardComponent implements OnInit { } } - public cancelClicked($event: WizardEvent): void { + public cancelClicked( ): void { const link: string[] = [ ConnectionsConstants.connectionsRootPath ]; this.logger.log("[AddConnectionWizardComponent] Navigating to: %o", link); this.router.navigate(link).then(() => { diff --git a/ngapp/src/app/dataservices/shared/composition.model.spec.ts b/ngapp/src/app/dataservices/shared/composition.model.spec.ts index 09e22deb..e6631ba9 100644 --- a/ngapp/src/app/dataservices/shared/composition.model.spec.ts +++ b/ngapp/src/app/dataservices/shared/composition.model.spec.ts @@ -26,12 +26,6 @@ describe("Composition", () => { expect(composition.getRightSourcePath()).toEqual("rightPath"); expect(composition.getType()).toEqual(CompositionType.INNER_JOIN); expect(composition.getOperator()).toEqual(CompositionOperator.EQ); - - const json = composition.toJSON(); - - const str = composition.toString(); - - const test = ""; }); }); diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 84185875..1a7481c7 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -17,8 +17,6 @@ import { Injectable } from "@angular/core"; import { Http, RequestOptions } from "@angular/http"; -import { Connection } from "@connections/shared/connection.model"; -import { SchemaNode } from "@connections/shared/schema-node.model"; import { ApiService } from "@core/api.service"; import { AppSettingsService } from "@core/app-settings.service"; import { LoggerService } from "@core/logger.service"; @@ -160,23 +158,6 @@ export class DataserviceService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } - /** - * Create a dataservice via the komodo rest interface - * @param {string} dataserviceName, - * @param {string[]} tablePaths, - * @param {string} modelSourcePath, - * @returns {Observable} - */ - public setServiceVdbForSingleSourceTables(dataserviceName: string, tablePaths: string[], modelSourcePath: string): Observable { - return this.http - .post(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRestPath + "/ServiceVdbForSingleSourceTables", - { dataserviceName, tablePaths, modelSourcePath}, this.getAuthRequestOptions()) - .map((response) => { - return response.ok; - }) - .catch( ( error ) => this.handleError( error ) ); - } - /** * Create a readonly datarole for the dataservice * @param {string} serviceVdbName, @@ -272,70 +253,6 @@ export class DataserviceService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } - /** - * Derive the service vdb name from the given dataservice - * - * @param {Dataservice} dataservice - * @returns {string} - */ - public deriveServiceVdbName(dataservice: NewDataservice): string { - const name = dataservice.getId() + VdbsConstants.DATASERVICE_VDB_SUFFIX; - return name.toLowerCase(); - } - - /** - * Create a dataservice which is a straight passthru to the supplied tables - * @param {NewDataservice} dataservice - * @param {SchemaNode[]} schemaNodes the source 'tables' for the service - * @param {Connection[]} connections the required connections for the schemaNodes - * @returns {Observable} - */ - public createDataserviceForSingleSourceTables(dataservice: NewDataservice, - schemaNodes: SchemaNode[], - connections: Connection[]): Observable { - // All tables currently must be from same connection - const connection: Connection = connections[0]; - const schemaVdbName = connection.schemaVdbName; - const schemaVdbModelName = connection.schemaVdbModelName; - const schemaVdbModelSourceName = connection.schemaVdbModelSourceName; - - // The schema VDB is directly under the connection in the repo - const vdbPath = this.getKomodoUserWorkspacePath() + "/" + connection.getId() + "/" + schemaVdbName; - - // Get table paths for the tables used in the service - const tablePaths = []; - for ( const connectionNode of schemaNodes ) { - const tablePath = vdbPath + "/" + schemaVdbModelName + "/" + connectionNode.getName(); - tablePaths.push(tablePath); - } - - // ModelSource path - const modelSourcePath = vdbPath + "/" + schemaVdbModelName + "/vdb:sources/" + schemaVdbModelSourceName; - - // Name of the Dataservice VDB - const dsVdbName = this.deriveServiceVdbName(dataservice); - - // Chain the individual calls together in series to build the DataService - return this.createDataservice(dataservice) - .flatMap((res) => this.setServiceVdbForSingleSourceTables(dataservice.getId(), tablePaths, modelSourcePath)) - .flatMap((res) => this.createReadonlyDataRole(dsVdbName, schemaVdbModelName)); - } - - /** - * Updates a dataservice with single table source. This is simply a create, with the added step of - * deleting the existing workspace dataservice first. - * @param {NewDataservice} dataservice - * @param {SchemaNode[]} schemaNodes - * @param {Connection[]} connections - * @returns {Observable} - */ - public updateDataserviceForSingleSourceTables(dataservice: NewDataservice, - schemaNodes: SchemaNode[], - connections: Connection[]): Observable { - return this.deleteDataservice(dataservice.getId()) - .flatMap((res) => this.createDataserviceForSingleSourceTables(dataservice, schemaNodes, connections)); - } - /** * Download a dataservice as a jar archive * @param {string} dataserviceName the dataservice name diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 2da38ef4..3f45e177 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -40,7 +40,6 @@ export class MockDataserviceService extends DataserviceService { private readonly services: Dataservice[]; private readonly queryResults: QueryResults; private editorViewStateMap = new Map(); - private selectedDs: Dataservice; constructor(http: Http, vdbService: VdbService, appSettings: AppSettingsService, notifierService: NotifierService, logger: LoggerService ) { @@ -140,12 +139,6 @@ export class MockDataserviceService extends DataserviceService { return Observable.of( "" ); } - public setServiceVdbForSingleSourceTables( dataserviceName: string, - tablePaths: string[], - modelSourcePath: string ): Observable< boolean > { - return Observable.of( true ); - } - /** * @param {ViewEditorState} editorState the view editor state * @returns {Observable} `true` if the editor state was successfully saved diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts index 0d77e99d..a3ca6f58 100644 --- a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-vdb.service.ts @@ -32,8 +32,6 @@ import "rxjs/add/observable/throw"; import "rxjs/add/operator/catch"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; -import {environment} from "@environments/environment"; -import {VdbsConstants} from "@dataservices/shared/vdbs-constants"; @Injectable() export class MockVdbService extends VdbService { diff --git a/ngapp/src/app/dataservices/shared/name-value.model.ts b/ngapp/src/app/dataservices/shared/name-value.model.ts index 4d901695..342078a6 100644 --- a/ngapp/src/app/dataservices/shared/name-value.model.ts +++ b/ngapp/src/app/dataservices/shared/name-value.model.ts @@ -20,8 +20,8 @@ */ export class NameValue { - private name: string; - private value: string; + private readonly name: string; + private readonly value: string; constructor(name: string, value: string) { this.name = name; diff --git a/ngapp/src/app/dataservices/shared/path-utils.ts b/ngapp/src/app/dataservices/shared/path-utils.ts index 3da4e72f..cfdf92f8 100644 --- a/ngapp/src/app/dataservices/shared/path-utils.ts +++ b/ngapp/src/app/dataservices/shared/path-utils.ts @@ -17,8 +17,6 @@ export class PathUtils { - private readonly undefined = "undefined"; - /** * Return the path, without the leading connection info * @param {string} sourcePath diff --git a/ngapp/src/app/dataservices/shared/view-editor-state.model.ts b/ngapp/src/app/dataservices/shared/view-editor-state.model.ts index 98af06b3..9123aa0f 100644 --- a/ngapp/src/app/dataservices/shared/view-editor-state.model.ts +++ b/ngapp/src/app/dataservices/shared/view-editor-state.model.ts @@ -29,7 +29,7 @@ export class ViewEditorState { /** * @param {Object} json the JSON representation of a ViewEditorState - * @returns {View} the new View (never null) + * @returns {ViewEditorState} the new ViewEditorState (never null) */ public static create( json: object = {} ): ViewEditorState { const editorState = new ViewEditorState(); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html index 17638931..db3ff05f 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html @@ -1,7 +1,7 @@ diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts index 45bb0fc5..554f19e4 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts @@ -404,7 +404,7 @@ export class AddCompositionWizardComponent implements OnInit { } } - public cancelClicked($event: WizardEvent): void { + public cancelClicked( ): void { this.cancelAction.emit(); } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts index 4829daed..1a3ddcaf 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts @@ -78,14 +78,14 @@ export class AddCompositionCommand extends Command { /** * @returns {string} json payload for this command */ - public getPayload(compositionName?: string): string { + public getPayload( ): string { return this.getArg( AddCompositionCommand.addedComposition ) as string; } /** * @returns {string} a unique short identifier of this command */ - public getId(compositionName?: string): string { + public getId( ): string { return this.getArg( Command.identArg ) as string; } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts index d882ea41..ab90e806 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts @@ -102,7 +102,7 @@ export class AddSourcesCommand extends Command { /** * @returns {string} a unique short identifier of this command */ - public getId(sourcePath?: string): string { + public getId( ): string { return this.getArg( Command.identArg ) as string; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts index 2db8effb..ec992c7d 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts @@ -35,8 +35,6 @@ export class RemoveCompositionCommand extends Command { */ public static readonly removedComposition = "removedComposition"; - private static readonly delim = ", "; - /** * Constructor * 'removedCompositionName' must be an array of Compositions -OR- stringified composition @@ -79,7 +77,7 @@ export class RemoveCompositionCommand extends Command { /** * @returns {string} a unique short identifier of this command */ - public getId(composition?: Composition): string { + public getId( ): string { return this.getArg( Command.identArg ) as string; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts index d48119b8..7174ee29 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts @@ -94,7 +94,7 @@ export class RemoveSourcesCommand extends Command { /** * @returns {string} a unique identifier of this command */ - public getId(sourcePath?: string): string { + public getId( ): string { return this.getArg( Command.identArg ) as string; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts index 4e4c7497..10307c5b 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts @@ -205,11 +205,4 @@ export class ViewPreviewComponent implements OnInit, OnDestroy { } } - private get previewSql(): string { - if (this._previewSql && this._previewSql !== null) { - return this._previewSql; - } - return ""; - } - } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts index 8e992105..700d026e 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts @@ -36,7 +36,6 @@ import { ViewCanvasEventType } from "@dataservices/virtualization/view-editor/vi import * as _ from "lodash"; import { AddCompositionCommand } from "@dataservices/virtualization/view-editor/command/add-composition-command"; import { RemoveCompositionCommand } from "@dataservices/virtualization/view-editor/command/remove-composition-command"; -import { Command } from "@dataservices/virtualization/view-editor/command/command"; import { CommandFactory } from "@dataservices/virtualization/view-editor/command/command-factory"; import { ViewDefinition } from "@dataservices/shared/view-definition.model"; import { Composition } from "@dataservices/shared/composition.model"; @@ -239,16 +238,6 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { return this.editorService.isReadOnly(); } - // - // /** - // * Handle removal of View Source - // * @param {SchemaNode} source the view source to be removed - // */ - // public onViewSourceRemoved( source: SchemaNode ): void { - // const cmd = CommandFactory.createRemoveSourcesCommand( [ source ] ); - // this.editorService.fireViewStateHasChanged( ViewEditorPart.CANVAS, cmd ); - // } - /** * @returns {boolean} true if save view notification is to be shown */ @@ -306,7 +295,7 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { return; } const update = (i === (sourcePaths.length - 1)); - const id = command.getId(srcPath); + const id = command.getId( ); const label = "[" + PathUtils.getConnectionName(srcPath) + "]: " + PathUtils.getSourceName(srcPath); this.canvasService.createNode(id, command.getPayload(srcPath), CanvasConstants.SOURCE_TYPE, label, update); @@ -335,7 +324,7 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { */ private createComposition(command: AddCompositionCommand): void { const composition = command.getComposition(); - const compNodeId = this.canvasService.createNode(command.getId(composition.getName()), command.getPayload(composition.getName()), CanvasConstants.COMPOSITION_TYPE, composition.getName(), true); + const compNodeId = this.canvasService.createNode(command.getId(), command.getPayload(), CanvasConstants.COMPOSITION_TYPE, composition.getName(), true); // Create links to source nodes if not found this.createLink(compNodeId, composition.getLeftSourcePath()); this.createLink(compNodeId, composition.getRightSourcePath()); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index c573e8b4..d49be48a 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core"; +import { AfterViewInit, Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core"; import { LoggerService } from "@core/logger.service"; import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; @@ -42,7 +42,7 @@ import { ViewEditorProgressChangeId } from "@dataservices/virtualization/view-ed templateUrl: "./view-editor-header.component.html", styleUrls: ["./view-editor-header.component.css"] }) -export class ViewEditorHeaderComponent implements OnInit, OnDestroy { +export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestroy { // used by html public readonly viewDescriptionLabel = ViewEditorI18n.viewDescriptionLabel; @@ -323,7 +323,6 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { editorState.setId(editorId); editorState.setViewDefinition(viewDefn); - const dsName = selectedDs.getId(); const self = this; this.dataserviceService .saveViewEditorStateRefreshViews(editorState, selectedDs.getId()) diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts index bd0812f9..df55909c 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts @@ -442,14 +442,14 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { comps.forEach( (nextComp) => { const leftPath = nextComp.getLeftSourcePath(); if (leftPath && leftPath != null && argPart === leftPath) { - let addCompCmd = CommandFactory.createRemoveCompositionCommand(nextComp.toString(), AddCompositionCommand.id); + const addCompCmd = CommandFactory.createRemoveCompositionCommand(nextComp.toString(), AddCompositionCommand.id); if (addCompCmd && addCompCmd != null) { this.notifyRemoved(addCompCmd); } } else { const rightPath = nextComp.getRightSourcePath(); if (rightPath && rightPath != null && argPart === rightPath) { - let addCompCmd = CommandFactory.createRemoveCompositionCommand(nextComp.toString(), AddCompositionCommand.id); + const addCompCmd = CommandFactory.createRemoveCompositionCommand(nextComp.toString(), AddCompositionCommand.id); if (addCompCmd && addCompCmd != null) { this.notifyRemoved(addCompCmd); } @@ -458,12 +458,12 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { }); // Remove Source Command - let addSrcsCmd = CommandFactory.createRemoveSourcesCommand(argPart, commandPart); + const addSrcsCmd = CommandFactory.createRemoveSourcesCommand(argPart, commandPart); this.notifyRemoved(addSrcsCmd); } else if (commandPart.startsWith(AddCompositionCommand.id)) { // Remove composition - let addCompCmd = CommandFactory.createRemoveCompositionCommand(argPart, commandPart); + const addCompCmd = CommandFactory.createRemoveCompositionCommand(argPart, commandPart); this.notifyRemoved(addCompCmd); } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index d246a71a..2afb433f 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -42,7 +42,6 @@ import { ViewDefinition } from "@dataservices/shared/view-definition.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { SelectionService } from "@core/selection.service"; -import { DeploymentState } from "@dataservices/shared/deployment-state.enum"; @Injectable() export class ViewEditorService { From 34584736bb8ca4cb8a9c2cd6991d6ae9aa1d3877 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Thu, 13 Sep 2018 14:10:37 -0500 Subject: [PATCH 189/205] minor fixes for formatting and odata results --- .../connection-card/connection-card.component.html | 2 +- .../app/dataservices/odata-control/odata-control.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html index 468d0c66..91dbf8a1 100644 --- a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html +++ b/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html @@ -67,7 +67,7 @@ [itemTemplate]="itemTemplate" [items]="properties"> -
    +
    {{ item[ 0 ] }}
    {{ item[ 1 ] }}
    diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.html b/ngapp/src/app/dataservices/odata-control/odata-control.component.html index 0325dc3e..270f06cd 100644 --- a/ngapp/src/app/dataservices/odata-control/odata-control.component.html +++ b/ngapp/src/app/dataservices/odata-control/odata-control.component.html @@ -45,7 +45,7 @@
    From 099b2aa614f83bb17099bc06b21153678c4ef98e Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 14 Sep 2018 14:26:49 -0500 Subject: [PATCH 190/205] TEIIDTOOLS-488 Adds ability to bulk create views --- .../create-views-dialog.component.css | 39 ++ .../create-views-dialog.component.html | 94 ++++ .../create-views-dialog.component.spec.ts} | 50 +- .../create-views-dialog.component.ts | 431 ++++++++++++++++++ .../create-views-result.model.ts} | 35 +- .../create-views-dialog/new-view.model.ts | 120 +++++ ...create-virtualization-dialog.component.css | 0 ...reate-virtualization-dialog.component.html | 50 -- .../create-virtualization-dialog.component.ts | 207 --------- .../dataservices/dataservices.component.ts | 58 ++- .../app/dataservices/dataservices.module.ts | 6 +- .../shared/dataservice.service.ts | 12 +- .../shared/mock-dataservice.service.ts | 121 +++++ .../view-editor-header.component.ts | 5 +- .../view-editor/view-editor-i18n.ts | 7 +- .../view-editor/view-editor.service.ts | 5 +- ngapp/src/app/shared/test-data.service.ts | 36 +- ngapp/src/environments/environment.prod.ts | 4 +- ngapp/src/environments/environment.ts | 4 +- 19 files changed, 945 insertions(+), 339 deletions(-) create mode 100644 ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.css create mode 100644 ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html rename ngapp/src/app/dataservices/{create-virtualization-dialog/create-virtualization-dialog.component.spec.ts => create-views-dialog/create-views-dialog.component.spec.ts} (51%) create mode 100644 ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts rename ngapp/src/app/dataservices/{create-virtualization-dialog/create-virtualization-result.model.ts => create-views-dialog/create-views-result.model.ts} (66%) create mode 100644 ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts delete mode 100644 ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.css delete mode 100644 ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.html delete mode 100644 ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.css b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.css new file mode 100644 index 00000000..94bfa236 --- /dev/null +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.css @@ -0,0 +1,39 @@ +.message-div { + margin-top: 20px; + margin-bottom: 10px; +} + +.connections-list { + padding-left: 0; + padding-right: 0; + min-height: 300px; + max-height: 300px; + border: 1px inset lightgrey; + overflow-y: auto; +} + +#views-table { + padding-left: 0; + padding-right: 0; + min-height: 300px; + max-height: 300px; + border: 1px inset lightgrey; + overflow-y: auto; +} + +/* + * Style the empty state component so that it is centered and extends the entire width. + */ +#views-table .blank-slate-pf { + background-color: inherit; + min-width: 200px; + border: none; + padding: 0; +} + +/* + * Style text in blank slate for table + */ +#views-table h1, .h1 { + font-size: 14px; +} diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html new file mode 100644 index 00000000..be7142b9 --- /dev/null +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html @@ -0,0 +1,94 @@ + + + + diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts similarity index 51% rename from ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts rename to ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts index 8037a5d5..8b33059e 100644 --- a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.spec.ts +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts @@ -1,25 +1,33 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { CreateViewsDialogComponent } from "./create-views-dialog.component"; +import { ConnectionTreeSelectorComponent } from "@dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component"; import { HttpModule } from "@angular/http"; -import { BsModalRef, ModalModule } from "ngx-bootstrap"; import { ActionModule, - NotificationModule -} from "patternfly-ng"; + CardModule, + EmptyStateModule, + FilterModule, + ListModule, + NotificationModule, + SortModule, + TableModule, + WizardModule } from "patternfly-ng"; +import { BsModalRef, ModalModule } from "ngx-bootstrap"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { MockConnectionService } from "@connections/shared/mock-connection.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { VdbService } from "@dataservices/shared/vdb.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; -import { CreateVirtualizationDialogComponent } from "./create-virtualization-dialog.component"; -import { AppSettingsService } from "@core/app-settings.service"; -import { LoggerService } from "@core/logger.service"; -import { NotifierService } from "@dataservices/shared/notifier.service"; -import { SelectionService } from "@core/selection.service"; -describe('CreateVirtualizationDialogComponent', () => { - let component: CreateVirtualizationDialogComponent; - let fixture: ComponentFixture; +describe("CreateViewsDialogComponent", () => { + let component: CreateViewsDialogComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -29,10 +37,18 @@ describe('CreateVirtualizationDialogComponent', () => { ReactiveFormsModule, ModalModule.forRoot(), ActionModule, - NotificationModule + CardModule, + EmptyStateModule, + FilterModule, + ListModule, + NotificationModule, + SortModule, + TableModule, + WizardModule ], - declarations: [ CreateVirtualizationDialogComponent ], - providers: [ AppSettingsService, BsModalRef, LoggerService, NotifierService, SelectionService, + declarations: [ CreateViewsDialogComponent ], + providers: [ AppSettingsService, BsModalRef, LoggerService, NotifierService, + { provide: ConnectionService, useClass: MockConnectionService }, { provide: DataserviceService, useClass: MockDataserviceService }, { provide: VdbService, useClass: MockVdbService } ] @@ -41,12 +57,12 @@ describe('CreateVirtualizationDialogComponent', () => { })); beforeEach(() => { - fixture = TestBed.createComponent(CreateVirtualizationDialogComponent); + fixture = TestBed.createComponent(CreateViewsDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); }); - it('should be created', () => { + it("should be created", () => { expect(component).toBeTruthy(); }); }); diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts new file mode 100644 index 00000000..f3379883 --- /dev/null +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts @@ -0,0 +1,431 @@ +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { BsModalRef } from "ngx-bootstrap"; +import { ConnectionService } from "@connections/shared/connection.service"; +import { LoggerService } from "@core/logger.service"; +import { LoadingState } from "@shared/loading-state.enum"; +import { ConnectionsConstants } from "@connections/shared/connections-constants"; +import { SchemaNode } from "@connections/shared/schema-node.model"; +import { + EmptyStateConfig, + ListConfig, + ListEvent, + NgxDataTableConfig, + NotificationType, + TableConfig +} from "patternfly-ng"; +import { NewView } from "@dataservices/create-views-dialog/new-view.model"; +import { TableEvent } from "patternfly-ng"; +import { AbstractControl, FormControl, FormGroup } from "@angular/forms"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { CreateViewsResult } from "@dataservices/create-views-dialog/create-views-result.model"; + +@Component({ + selector: 'app-create-views-dialog', + templateUrl: './create-views-dialog.component.html', + styleUrls: ['./create-views-dialog.component.css'] +}) +/** + * CreateViews Dialog. Invoke this from another component as follows: + * + * this.modalRef = this.modalService.show(CreateViewsDialogComponent, {initialState}); + * this.modalRef.content.okAction.take(1).subscribe((dialogResult) => { + * // do something with dialogResult (CreateViewsResult) + * }); + * + * The expected initial state is as follows: + * const initialState = { + * title: "The dialog title", + * cancelButtonText: "Text for cancel button", + * confirmButtonText: "Text for confirm button" + * }; + */ +export class CreateViewsDialogComponent implements OnInit { + + @Output() public okAction: EventEmitter = new EventEmitter(); + + public readonly title = ViewEditorI18n.createViewsDialogNewVirtualizationTitle; + public readonly message = ViewEditorI18n.createViewsDialogMessage; + public readonly cancelButtonText = ViewEditorI18n.cancelButtonText; + public readonly okButtonText = ViewEditorI18n.okButtonText; + public okButtonEnabled = false; + public bsModalRef: BsModalRef; + public connections: SchemaNode[] = []; + public allViews: NewView[] = []; + public listConfig: ListConfig; + public tableColumns: any[] = []; + public ngxTableConfig: NgxDataTableConfig; + public tableConfig: TableConfig; + public virtNameValidationError = ""; + public virtualizationPropertyForm: FormGroup; + public readonly connectionsLoadFailedHeader = "Loading Failed: "; + public readonly connectionsLoadFailedMsg = "Connections failed to load!"; + public readonly connectionsLoadFailedType = NotificationType.DANGER; + public readonly viewsLoadFailedHeader = "Loading Failed: "; + public readonly viewsLoadFailedMsg = "Views failed to load!"; + public readonly viewsLoadFailedType = NotificationType.DANGER; + + private connectionService: ConnectionService; + private dataserviceService: DataserviceService; + private selectedConnections: SchemaNode[] = []; + private selectedViews: NewView[] = []; + private loggerService: LoggerService; + private connectionsLoadingState: LoadingState = LoadingState.LOADING; + private viewsLoadingState: LoadingState = LoadingState.LOADED_VALID; + private emptyStateConfig: EmptyStateConfig; + + constructor(bsModalRef: BsModalRef, dataserviceService: DataserviceService, + connectionService: ConnectionService, logger: LoggerService) { + this.bsModalRef = bsModalRef; + this.connectionService = connectionService; + this.dataserviceService = dataserviceService; + this.loggerService = logger; + this.createPropertyForm(); + } + + public ngOnInit(): void { + // List configuration + this.listConfig = { + dblClick: false, + multiSelect: false, + selectItems: false, + showCheckbox: true + }; + + // ---------------------------------- + // View Table configurations + // ---------------------------------- + this.tableColumns = [ + { + draggable: false, + name: "Connection", + prop: "connectionName", + resizeable: true, + sortable: false, + maxWidth: "100", + minWidth: "100", + width: "100" + }, + { + draggable: false, + name: "View Name", + prop: "viewName", + resizeable: true, + sortable: false, + width: "100" + }, + { + draggable: false, + name: "Source Node", + prop: "pathString", + resizeable: true, + sortable: false, + width: "100" + } + ]; + this.ngxTableConfig = { + reorderable: false, + selectionType: "'single'", + sorts: [ { prop: "name", dir: "asc" } ], + } as NgxDataTableConfig; + + this.emptyStateConfig = { + title: ViewEditorI18n.noViewsDisplayedMessage + } as EmptyStateConfig; + + this.tableConfig = { + showCheckbox: true, + emptyStateConfig: this.emptyStateConfig + } as TableConfig; + + // Init virtualization name and description + this.virtualizationPropertyForm.controls["virtName"].setValue(""); + this.virtualizationPropertyForm.controls["virtDescription"].setValue(""); + + // Load the connections + this.connectionsLoadingState = LoadingState.LOADING; + const self = this; + this.connectionService + .getConnections(true, true) + .subscribe( + (connectionSummaries) => { + const conns = []; + const treeNodes = []; + for ( const connectionSummary of connectionSummaries ) { + const connStatus = connectionSummary.getStatus(); + const conn = connectionSummary.getConnection(); + conn.setStatus(connStatus); + conns.push(conn); + // Add active connection to tree root nodes + if (conn.isActive) { + const node = new SchemaNode(); + node.setName(conn.getId()); + node.setType(ConnectionsConstants.schemaNodeType_connection); + node.selected = false; + this.connections.push(node); + } + } + self.connectionsLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.loggerService.error("[ConnectionTableDialogComponent] Error getting connections: %o", error); + self.connectionsLoadingState = LoadingState.LOADED_INVALID; + } + ); + } + + /* + * Creates the view property form + */ + private createPropertyForm(): void { + this.virtualizationPropertyForm = new FormGroup({ + virtName: new FormControl( "", this.handleVirtNameChanged.bind( this ) ), + virtDescription: new FormControl(""), + }); + } + + /** + * Handler for virtualization name changes. + * @param {AbstractControl} input + */ + public handleVirtNameChanged( input: AbstractControl ): void { + const self = this; + + this.dataserviceService.isValidName( input.value ).subscribe( + ( errorMsg ) => { + if ( errorMsg ) { + // only update if error has changed + if ( errorMsg !== self.virtNameValidationError ) { + self.virtNameValidationError = errorMsg; + } + } else { // name is valid + self.virtNameValidationError = ""; + } + self.setOkButtonEnablement(); + }, + ( error ) => { + self.loggerService.error( "[handleNameChanged] Error: %o", error ); + self.virtNameValidationError = "Error validating view name"; + self.setOkButtonEnablement(); + } ); + } + + /* + * Return the virtualization name valid state + */ + public get virtNameValid(): boolean { + return this.virtNameValidationError == null || this.virtNameValidationError.length === 0; + } + + /** + * Handles change in connection selection + * @param {ListEvent} $event the list selection event + */ + public handleConnectionSelectionChange($event: ListEvent): void { + const newSelections = $event.selectedItems; + const numberNewSelections = newSelections.length; + // Find new selection that was added + if (numberNewSelections > this.selectedConnections.length) { + newSelections.forEach( ( newConn ) => { + const index = this.selectedConnections.findIndex( ( conn ) => conn.getName() === newConn.getName() ); + + if ( index === -1 ) { + this.onConnectionSelected(newConn); + } + } ); + // Find existing selection that was removed + } else { + for (const selectedConn of this.selectedConnections) { + const index = newSelections.findIndex( ( conn ) => conn.getName() === selectedConn.getName() ); + + if ( index === -1 ) { + this.onConnectionDeselected(selectedConn); + break; + } + } + } + this.selectedConnections = newSelections; + } + + /** + * Handler for connection selection + * @param {SchemaNode} conn the connection node + */ + private onConnectionSelected(conn: SchemaNode): void { + this.generateConnectionViewInfos(conn.getName()); + } + + /** + * Handler for connection deselection + * @param {SchemaNode} conn the connection node + */ + private onConnectionDeselected(conn: SchemaNode): void { + const refreshViews = this.arrayClone(this.allViews); + + let i = refreshViews.length; + while (i--) { + if (refreshViews[i].getConnectionName() === conn.getName()) { + refreshViews.splice(i, 1); + } + } + + this.allViews = refreshViews; + } + + /** + * Handles change in View selections + * @param {TableEvent} $event the table selection event + */ + public handleViewSelectionChange($event: TableEvent): void { + this.selectedViews = $event.selectedRows; + this.setOkButtonEnablement(); + } + + /** + * Determine if connections are loading + * @returns {boolean} + */ + public get connectionsLoading( ): boolean { + return ( this.connectionsLoadingState === LoadingState.LOADING ); + } + + /** + * Determine if connections loading completed, and was successful + * @returns {boolean} + */ + public get connectionsLoadedSuccess( ): boolean { + return ( this.connectionsLoadingState === LoadingState.LOADED_VALID ); + } + + /** + * Determine if connections loading completed, but failed + * @returns {boolean} + */ + public get connectionsLoadedFailed( ): boolean { + return ( this.connectionsLoadingState === LoadingState.LOADED_INVALID ); + } + + /** + * Determine if views are loading + * @returns {boolean} + */ + public get viewsLoading( ): boolean { + return ( this.viewsLoadingState === LoadingState.LOADING ); + } + + /** + * Determine if views loading completed, and was successful + * @returns {boolean} + */ + public get viewsLoadedSuccess( ): boolean { + return ( this.viewsLoadingState === LoadingState.LOADED_VALID ); + } + + /** + * Determine if views loading completed, but failed + * @returns {boolean} + */ + public get viewsLoadedFailed( ): boolean { + return ( this.viewsLoadingState === LoadingState.LOADED_INVALID ); + } + + /** + * OK selected. The array of selected SchemaNodes is emiited, then modal is closed + */ + public onOkSelected(): void { + const virtName = this.virtualizationPropertyForm.controls["virtName"].value; + const virtDescr = this.virtualizationPropertyForm.controls["virtDescription"].value; + const result = new CreateViewsResult(); + result.setVirtualizationName(virtName); + result.setVirtualizationDescription(virtDescr); + result.setViews(this.selectedViews); + + this.bsModalRef.hide(); + this.okAction.emit(result); + } + + /** + * Cancel selected. The modal is closed. + */ + public onCancelSelected(): void { + this.bsModalRef.hide(); + } + + /** + * Sets the OK button enablement, based upon the view selections + */ + private setOkButtonEnablement(): void { + if (this.virtNameValid && this.selectedViews.length > 0) { + this.okButtonEnabled = true; + } else { + this.okButtonEnabled = false; + } + } + + /** + * Generate the view infos for the supplied connection name + * @param {string} connName the connection name + */ + public generateConnectionViewInfos(connName: string): void { + // Load the connections + this.viewsLoadingState = LoadingState.LOADING; + const self = this; + this.connectionService + .getConnectionSchema(connName) + .subscribe( + (schemaNodes) => { + // Copy existing view. Need to reset array to get table to refresh?? + const refreshViews = this.arrayClone(self.allViews); + const newViews: NewView[] = []; + for ( const schemaNode of schemaNodes ) { + const nodePath: string[] = []; + self.generateViewInfos(connName, schemaNode, nodePath, newViews); + } + for (const newView of newViews) { + refreshViews.push(newView); + } + self.allViews = refreshViews; + self.viewsLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.loggerService.error("[ConnectionTableDialogComponent] Error getting connections: %o", error); + self.viewsLoadingState = LoadingState.LOADED_INVALID; + } + ); + } + + /** + * Recursively generate the view infos for this node and its children + * @param {SchemaNode} schemaNode the schema node + */ + private generateViewInfos(connName: string, schemaNode: SchemaNode, nodePath: string[], viewInfos: NewView[]): void { + const sourcePath: string[] = []; + for (const seg of nodePath) { + sourcePath.push(seg); + } + if ( schemaNode.isQueryable() ) { + const newView: NewView = new NewView(); + newView.setConnectionName(connName); + newView.setViewSourceNode(schemaNode); + newView.setNodePath(sourcePath); + const viewName = connName + "_" + schemaNode.getName(); + newView.setViewName(viewName); + viewInfos.push(newView); + } + sourcePath.push(schemaNode.getName()); + for (const childNode of schemaNode.getChildren()) { + this.generateViewInfos(connName, childNode, sourcePath, viewInfos); + } + } + + private arrayClone(oldArray: NewView[]): NewView[] { + const newArray: NewView[] = []; + oldArray.forEach((item) => { + const nView = new NewView(); + Object.assign(nView, item); + newArray.push(nView); + }); + return newArray; + } + +} diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-result.model.ts b/ngapp/src/app/dataservices/create-views-dialog/create-views-result.model.ts similarity index 66% rename from ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-result.model.ts rename to ngapp/src/app/dataservices/create-views-dialog/create-views-result.model.ts index 21b98e04..f7fb16ea 100644 --- a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-result.model.ts +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-result.model.ts @@ -15,15 +15,16 @@ * limitations under the License. */ +import { NewView } from "@dataservices/create-views-dialog/new-view.model"; + /** - * CreateVirtualizationResult model - to hold the results of the dialog entry + * CreateViewsResult model - to hold the results of the CreateViewsDialog entry */ -export class CreateVirtualizationResult { +export class CreateViewsResult { private virtName: string; private virtDescription = ""; - private viewName: string; - private viewDescription = ""; + private views: NewView[] = []; constructor() { // nothing to do @@ -58,31 +59,17 @@ export class CreateVirtualizationResult { } /** - * @returns {string} the view name - */ - public getViewName(): string { - return this.viewName; - } - - /** - * @param {string} name the view name - */ - public setViewName( name?: string ): void { - this.viewName = name ? name : null; - } - - /** - * @returns {string} the view description + * @returns {NewView[]} the views */ - public getViewDescription(): string { - return this.viewDescription; + public getViews(): NewView[] { + return this.views; } /** - * @param {string} description the view description + * @param {NewView[]} views the views to create */ - public setViewDescription( description?: string ): void { - this.viewDescription = description ? description : ""; + public setViews( views: NewView[] ): void { + this.views = views; } } diff --git a/ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts b/ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts new file mode 100644 index 00000000..f6d368d9 --- /dev/null +++ b/ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts @@ -0,0 +1,120 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { SchemaNode } from "@connections/shared/schema-node.model"; + +/** + * NewView model - to hold the NewView objects + */ +export class NewView { + + private connectionName: string; + private viewName: string; + private viewDescription = ""; + private viewSourceNode: SchemaNode; + private nodePath: string[] = []; + + constructor() { + // nothing to do + } + + /** + * @returns {string} the connection name + */ + public getConnectionName(): string { + return this.connectionName; + } + + /** + * @param {string} name the connection name + */ + public setConnectionName( name?: string ): void { + this.connectionName = name ? name : null; + } + + /** + * @returns {string} the view name + */ + public getViewName(): string { + return this.viewName; + } + + /** + * @param {string} name the view name + */ + public setViewName( name?: string ): void { + this.viewName = name ? name : null; + } + + /** + * @returns {string} the view description + */ + public getViewDescription(): string { + return this.viewDescription; + } + + /** + * @param {string} description the view description + */ + public setViewDescription( description?: string ): void { + this.viewDescription = description ? description : ""; + } + + /** + * @returns {SchemaNode} the view source node + */ + public getViewSourceNode(): SchemaNode { + return this.viewSourceNode; + } + + /** + * @param {SchemaNode} node the view source node + */ + public setViewSourceNode( node: SchemaNode ): void { + this.viewSourceNode = node; + } + + /** + * @returns {string} the stringified node path + */ + public get pathString(): string { + let path = ""; + const segLength = this.nodePath.length; + for ( let i = 0; i < segLength; i++ ) { + path += this.nodePath[i]; + if ( i !== segLength - 1 ) { + path += "."; + } + } + if (path.length === 0) { + return this.viewSourceNode.getName(); + } else { + return path + "." + this.viewSourceNode.getName(); + } + } + + /** + * @param {string[]} path the node path + */ + public setNodePath( path: string[] ): void { + this.nodePath = []; + for (const segment of path) { + this.nodePath.push(segment); + } + } + +} diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.css b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.css deleted file mode 100644 index e69de29b..00000000 diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.html b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.html deleted file mode 100644 index 4de0c55a..00000000 --- a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.html +++ /dev/null @@ -1,50 +0,0 @@ - - - diff --git a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts b/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts deleted file mode 100644 index 0aa18adb..00000000 --- a/ngapp/src/app/dataservices/create-virtualization-dialog/create-virtualization-dialog.component.ts +++ /dev/null @@ -1,207 +0,0 @@ -/** - * @license - * Copyright 2017 JBoss Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, OnInit } from "@angular/core"; -import { Output } from "@angular/core"; -import { EventEmitter } from "@angular/core"; -import { BsModalRef } from "ngx-bootstrap"; -import { LoggerService } from "@core/logger.service"; -import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; -import { AbstractControl, FormControl, FormGroup } from "@angular/forms"; -import { VdbService } from "@dataservices/shared/vdb.service"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { CreateVirtualizationResult } from "@dataservices/create-virtualization-dialog/create-virtualization-result.model"; -import { SelectionService } from "@core/selection.service"; - -@Component({ - selector: "app-create-virtualization-dialog", - templateUrl: "./create-virtualization-dialog.component.html", - styleUrls: ["./create-virtualization-dialog.component.css"] -}) -/** - * CreateVirtualization Dialog. Invoke this from another component as follows: - * - * this.modalRef = this.modalService.show(CreateVirtualizationDialogComponent, {initialState}); - * this.modalRef.content.okAction.take(1).subscribe((createResult) => { - * // do something with dialog result - CreateVirtualizationResult - * }); - * - * The expected initial state is as follows: - * const initialState = { - * title: "The dialog title", - * cancelButtonText: "Text for cancel button", - * confirmButtonText: "Text for confirm button" - * }; - */ -export class CreateVirtualizationDialogComponent implements OnInit { - - @Output() public okAction: EventEmitter = new EventEmitter(); - - public readonly title = ViewEditorI18n.createVirtualizationDialogTitle; - public readonly message = ViewEditorI18n.createVirtualizationDialogMessage; - public readonly cancelButtonText = ViewEditorI18n.cancelButtonText; - public readonly okButtonText = ViewEditorI18n.okButtonText; - public okButtonEnabled = false; - public bsModalRef: BsModalRef; - public virtNameValidationError = ""; - public viewNameValidationError = ""; - public virtualizationPropertyForm: FormGroup; - - private loggerService: LoggerService; - private dataserviceService: DataserviceService; - private selectionService: SelectionService; - private vdbService: VdbService; - private serviceVdbName = ""; - - constructor(bsModalRef: BsModalRef, logger: LoggerService, - dataserviceService: DataserviceService, selectionService: SelectionService, vdbService: VdbService) { - this.bsModalRef = bsModalRef; - this.loggerService = logger; - this.dataserviceService = dataserviceService; - this.selectionService = selectionService; - const dService = this.selectionService.getSelectedVirtualization(); - if ( dService && dService !== null ) { - this.serviceVdbName = dService.getServiceVdbName(); - } - this.vdbService = vdbService; - this.createPropertyForm(); - } - - public ngOnInit(): void { - this.virtualizationPropertyForm.controls["virtName"].setValue(""); - this.virtualizationPropertyForm.controls["virtDescription"].setValue(""); - this.virtualizationPropertyForm.controls["viewName"].setValue(""); - this.virtualizationPropertyForm.controls["viewDescription"].setValue(""); - } - - /* - * Creates the view property form - */ - private createPropertyForm(): void { - this.virtualizationPropertyForm = new FormGroup({ - virtName: new FormControl( "", this.handleVirtNameChanged.bind( this ) ), - virtDescription: new FormControl(""), - viewName: new FormControl( "", this.handleViewNameChanged.bind( this ) ), - viewDescription: new FormControl("") - }); - } - - /** - * Handler for virtualization name changes. - * @param {AbstractControl} input - */ - public handleVirtNameChanged( input: AbstractControl ): void { - const self = this; - - this.dataserviceService.isValidName( input.value ).subscribe( - ( errorMsg ) => { - if ( errorMsg ) { - // only update if error has changed - if ( errorMsg !== self.virtNameValidationError ) { - self.virtNameValidationError = errorMsg; - } - } else { // name is valid - self.virtNameValidationError = ""; - } - self.setOkButtonEnablement(); - }, - ( error ) => { - self.loggerService.error( "[handleNameChanged] Error: %o", error ); - self.virtNameValidationError = "Error validating view name"; - self.setOkButtonEnablement(); - } ); - } - - /** - * Handler for view name changes. Since this will be the first view in the virtualization, - * no need to make a service call - just do some general name checking - * @param {AbstractControl} input - */ - public handleViewNameChanged( input: AbstractControl ): void { - this.viewNameValidationError = this.validateViewName(input.value); - this.setOkButtonEnablement(); - } - - /** - * OK selected. Emit ViewDefinition with the view, then modal is closed - */ - public onOkSelected(): void { - const virtName = this.virtualizationPropertyForm.controls["virtName"].value; - const virtDescr = this.virtualizationPropertyForm.controls["virtDescription"].value; - const viewName = this.virtualizationPropertyForm.controls["viewName"].value; - const viewDescr = this.virtualizationPropertyForm.controls["viewDescription"].value; - - const result = new CreateVirtualizationResult(); - result.setVirtualizationName(virtName); - result.setVirtualizationDescription(virtDescr); - result.setViewName(viewName); - result.setViewDescription(viewDescr); - this.okAction.emit(result); - - this.bsModalRef.hide(); - } - - /** - * Cancel selected. The modal is closed. - */ - public onCancelSelected(): void { - this.bsModalRef.hide(); - } - - /* - * Return the virtualization name valid state - */ - public get virtNameValid(): boolean { - return this.virtNameValidationError == null || this.virtNameValidationError.length === 0; - } - - /* - * Return the view name valid state - */ - public get viewNameValid(): boolean { - return this.viewNameValidationError == null || this.viewNameValidationError.length === 0; - } - - /** - * Validate the provided view name. If the name is valid, an empty string will be returned. If the view is invalid, - * the error message is returned. - * @param {string} viewName the view name being validated - * @return {string} the validation message - */ - private validateViewName( viewName: string ): string { - if ( !viewName || viewName === null || viewName.length === 0 ) { - return "View name cannot be empty"; - } - const isValid = /^\w+$/.test(viewName); - if ( !isValid ) { - return "View name can only contain letters, digits and underscores"; - } - return ""; - } - - /** - * Sets the OK button enablement. Both the virtualization name and view name must be valid. - */ - private setOkButtonEnablement(): void { - if (this.virtNameValid && this.viewNameValid) { - this.okButtonEnabled = true; - } else { - this.okButtonEnabled = false; - } - } - -} diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index 100a8288..ab92379b 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -52,10 +52,10 @@ import { import { Subscription } from "rxjs/Subscription"; import { SqlView } from "@dataservices/shared/sql-view.model"; import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; -import { CreateVirtualizationDialogComponent } from "@dataservices/create-virtualization-dialog/create-virtualization-dialog.component"; import { ViewDefinition } from "@dataservices/shared/view-definition.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; import { NameValue } from "@dataservices/shared/name-value.model"; +import { CreateViewsDialogComponent } from "@dataservices/create-views-dialog/create-views-dialog.component"; @Component({ moduleId: module.id, @@ -604,23 +604,31 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn public onNew(): void { // Open New Virtualization dialog const initialState = { - title: ViewEditorI18n.createVirtualizationDialogTitle, + title: ViewEditorI18n.createViewsDialogNewVirtualizationTitle, cancelButtonText: ViewEditorI18n.cancelButtonText, okButtonText: ViewEditorI18n.okButtonText }; // Show Dialog, act upon confirmation click - const modalRef = this.modalService.show(CreateVirtualizationDialogComponent, {initialState}); + const modalRef = this.modalService.show(CreateViewsDialogComponent, {initialState, class: 'modal-lg'}); modalRef.content.okAction.take(1).subscribe((dialogResult) => { // Create the new virtualization and view. const virtName = dialogResult.getVirtualizationName(); const virtDescr = dialogResult.getVirtualizationDescription(); - const viewName = dialogResult.getViewName(); - const viewDescr = dialogResult.getViewDescription(); - const viewDefn = new ViewDefinition(); - viewDefn.setName(viewName); - viewDefn.setDescription(viewDescr); + const newViews = dialogResult.getViews(); + const viewDefns: ViewDefinition[] = []; + for (const newView of newViews) { + const viewDefn = new ViewDefinition(); + viewDefn.setName(newView.getViewName()); + viewDefn.setDescription(newView.getViewDescription()); + const srcNode = newView.getViewSourceNode(); + const srcPath = "connection=" + newView.getConnectionName() + "/" + srcNode.getPath(); + const srcPaths: string[] = []; + srcPaths.push(srcPath); + viewDefn.addSourcePaths(srcPaths); + viewDefns.push(viewDefn); + } // Display Toast notification this.setToastNotification(Toast.Type.NewVirtualization, Toast.State.InProgress, virtName); @@ -634,7 +642,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn .subscribe( (wasSuccess) => { // Set the current virtualization to the newly created virtualization - self.selectVirtualizationCreateView(virtName, viewDefn); + self.selectVirtualizationCreateViews(virtName, viewDefns); }, (error) => { self.logger.error("[VirtualizationComponent] Error creating virtualization: %o", error); @@ -650,11 +658,11 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn } /* - * Select the specified Dataservice. create a starter view under it + * Select the specified Dataservice. create views under it * @param {string} dsName the name of the dataservice - * @param {string} viewDefn the view definition to create + * @param {ViewDefinition[]} viewDefns the array of view definitions to create */ - private selectVirtualizationCreateView(virtName: string, viewDefn: ViewDefinition): void { + private selectVirtualizationCreateViews(virtName: string, viewDefns: ViewDefinition[]): void { const self = this; this.dataserviceService .getAllDataservices() @@ -663,7 +671,7 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn for (const ds of dataservices) { if (ds.getId() === virtName) { self.selectionService.setSelectedVirtualization(ds); - self.createView(ds, viewDefn); + self.createViews(ds, viewDefns); } } }, @@ -677,22 +685,28 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn ); } - private createView(dataservice: Dataservice, viewDefn: ViewDefinition): void { + private createViews(dataservice: Dataservice, viewDefns: ViewDefinition[]): void { const selectedDs = this.selectionService.getSelectedVirtualization(); - let editorId = ""; - if ( selectedDs || selectedDs !== null ) { - editorId = this.getEditorStateId(selectedDs, viewDefn); + if (!selectedDs || selectedDs === null) { + return; } + // Create the array of ViewEditorStates + const editorStates: ViewEditorState[] = []; + for (const viewDefn of viewDefns) { + const editorId = this.getEditorStateId(selectedDs, viewDefn); - // Create new editor state to save - const editorState = new ViewEditorState(); - editorState.setId(editorId); - editorState.setViewDefinition(viewDefn); + // Create new editor state to save + const editorState = new ViewEditorState(); + editorState.setId(editorId); + editorState.setViewDefinition(viewDefn); + + editorStates.push(editorState); + } const virtName = selectedDs.getId(); const self = this; this.dataserviceService - .saveViewEditorStateRefreshViews(editorState, selectedDs.getId()) + .saveViewEditorStatesRefreshViews(editorStates, selectedDs.getId()) .subscribe( (wasSuccess) => { // Dismiss toast since navigating away diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 29612eae..5b6bf694 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -73,7 +73,7 @@ import { ProgressDialogComponent } from "@shared/progress-dialog/progress-dialog import { ViewPropertyEditorsComponent } from './virtualization/view-editor/view-property-editors/view-property-editors.component'; import { AddCompositionWizardComponent } from './virtualization/view-editor/add-composition-wizard/add-composition-wizard.component'; import { CreateViewDialogComponent } from './virtualization/view-editor/create-view-dialog/create-view-dialog.component'; -import { CreateVirtualizationDialogComponent } from './create-virtualization-dialog/create-virtualization-dialog.component'; +import { CreateViewsDialogComponent } from './create-views-dialog/create-views-dialog.component'; @NgModule({ imports: [ @@ -127,7 +127,7 @@ import { CreateVirtualizationDialogComponent } from './create-virtualization-dia LinkVisualComponent, AddCompositionWizardComponent, CreateViewDialogComponent, - CreateVirtualizationDialogComponent + CreateViewsDialogComponent ], providers: [ { @@ -150,7 +150,7 @@ import { CreateVirtualizationDialogComponent } from './create-virtualization-dia exports: [ ], entryComponents: [AddCompositionWizardComponent, ConfirmDialogComponent, ConnectionTableDialogComponent, - CreateViewDialogComponent, CreateVirtualizationDialogComponent, ProgressDialogComponent] + CreateViewDialogComponent, CreateViewsDialogComponent, ProgressDialogComponent] }) export class DataservicesModule { } diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index 1a7481c7..a923915c 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -510,12 +510,12 @@ export class DataserviceService extends ApiService { } /** - * @param {ViewEditorState} editorState the view editor state + * @param {ViewEditorState[]} editorStates the view editor state array * @returns {Observable} `true` if the editor state was successfully saved */ - public saveViewEditorState( editorState: ViewEditorState ): Observable< boolean > { + public saveViewEditorStates( editorStates: ViewEditorState[] ): Observable< boolean > { - return this.http.put( environment.viewEditorState, editorState.toJSON(), this.getAuthRequestOptions() ) + return this.http.put( environment.viewEditorStates, JSON.stringify(editorStates), this.getAuthRequestOptions() ) .map( ( response ) => { return response.ok; } ) @@ -539,12 +539,12 @@ export class DataserviceService extends ApiService { } /** - * @param {ViewEditorState} editorState the view editor state + * @param {ViewEditorState[]} editorStates the view editor state array * @param {string} dataserviceName the name of the dataservice * @returns {Observable} `true` if the editor state was successfully saved */ - public saveViewEditorStateRefreshViews( editorState: ViewEditorState, dataserviceName: string ): Observable< boolean > { - return this.saveViewEditorState(editorState) + public saveViewEditorStatesRefreshViews( editorStates: ViewEditorState[], dataserviceName: string ): Observable< boolean > { + return this.saveViewEditorStates(editorStates) .flatMap((res) => this.refreshDataserviceViews(dataserviceName)); } diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 3f45e177..1acefc35 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -205,4 +205,125 @@ export class MockDataserviceService extends DataserviceService { return Observable.of(true); } + /** + * Query a Dataservice's published virtualization using odata protocol + * @param {string} url the odata url string + * @returns {Observable} + */ + public odataGet(url: string): Observable { + const result = this.getMetadata(); + + return Observable.of(result); + } + private getMetadata(): string { + const metadata = "" + + "" + + "" + + " " + + "" + + "" + + " " + + "" + + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " true" + + " " + + " " + + " false" + + " " + + " " + + " " + + " " + + " true" + + " " + + " " + + " false" + + " " + + " " + + " " + + " " + + " true" + + " " + + " " + + " false" + + " " + + " " + + " " + + " " + + " true" + + " " + + " " + + " false" + + " " + + " " + + " " + + " " + + " true" + + " " + + " " + + " false" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " truefalse" + + " " + + " " + + " true" + + " false" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " true" + + " false" + + " " + + " " + + " true" + + " false" + + " " + + " " + + " " + + " true" + + " " + + " false" + + " " + + " " + + " " + + " false" + + " " + + " " + + " false" + + " " + + " " + + " " + + " " + + " false" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + "" + + "" + + ""; + + return metadata; + } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index d49be48a..87dd90a4 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -323,9 +323,12 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr editorState.setId(editorId); editorState.setViewDefinition(viewDefn); + const editorStates: ViewEditorState[] = []; + editorStates.push(editorState); + const self = this; this.dataserviceService - .saveViewEditorStateRefreshViews(editorState, selectedDs.getId()) + .saveViewEditorStatesRefreshViews(editorStates, selectedDs.getId()) .subscribe( (wasSuccess) => { // Add the new ViewDefinition to the table diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts index 2211742a..a7641ca2 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts @@ -39,9 +39,10 @@ export class ViewEditorI18n { public static readonly currentSelection = "Current Selection:"; public static readonly noSelection = "Nothing selected"; - // create virtualization dialog - public static readonly createVirtualizationDialogMessage = "Enter name and optional description for the virtualization and view"; - public static readonly createVirtualizationDialogTitle = "Create Virtualization"; + // create views dialog + public static readonly createViewsDialogMessage = "Select the initial views for the virtualization"; + public static readonly createViewsDialogNewVirtualizationTitle = "Create Virtualization"; + public static readonly noViewsDisplayedMessage = "Select connection(s)"; // create view dialog public static readonly createViewDialogMessage = "Enter name and description(optional) for the new view"; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index 2afb433f..1e5f656a 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -428,10 +428,13 @@ export class ViewEditorService { editorState.setUndoables(this._undoMgr.toArray()); editorState.setViewDefinition(this._editorView); + const editorStates: ViewEditorState[] = []; + editorStates.push(editorState); + const dataserviceName = this._selectionService.getSelectedVirtualization().getId(); const self = this; - this._dataserviceService.saveViewEditorStateRefreshViews( editorState, dataserviceName ).subscribe( () => { + this._dataserviceService.saveViewEditorStatesRefreshViews( editorStates, dataserviceName ).subscribe( () => { // reset original view to saved state self._originalView = ViewDefinition.create(this._editorView.toJSON()); // any change to service view undeploys active serviceVdb diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 62145d16..095f0bfa 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -936,7 +936,17 @@ export class TestDataService { "build_status_message": "Accounts VDB build was successful", "namespace": "beetle-studio", "last_updated": "2018-03-29T17:02:51.181Z", - "publishState": PublishState.PUBLISHED + "publishState": PublishState.PUBLISHED, + "routes": [ + { + "name": TestDataService.accountsVdb.getName() + "-odata", + "protocol": "odata", + "target": TestDataService.accountsVdb.getName() + "-odata", + "host": TestDataService.accountsVdb.getName() + "-odata" + "-beetle-studio.192.168.xx.yy", + "port": "odata", + "secure": true + } + ] } ); @@ -949,7 +959,17 @@ export class TestDataService { "build_status_message": "Employees VDB build was successful", "namespace": "beetle-studio", "last_updated": "2018-03-29T17:02:51.181Z", - "publishState": PublishState.PUBLISHED + "publishState": PublishState.PUBLISHED, + "routes": [ + { + "name": TestDataService.employeesVdb.getName() + "-odata", + "protocol": "odata", + "target": TestDataService.employeesVdb.getName() + "-odata", + "host": TestDataService.employeesVdb.getName() + "-odata" + "-beetle-studio.192.168.xx.yy", + "port": "odata", + "secure": true + } + ] } ); @@ -962,7 +982,17 @@ export class TestDataService { "build_status_message": "Products VDB build was successful", "namespace": "beetle-studio", "last_updated": "2018-03-29T17:02:51.181Z", - "publishState": PublishState.PUBLISHED + "publishState": PublishState.PUBLISHED, + "routes": [ + { + "name": TestDataService.productsVdb.getName() + "-odata", + "protocol": "odata", + "target": TestDataService.productsVdb.getName() + "-odata", + "host": TestDataService.productsVdb.getName() + "-odata" + "-beetle-studio.192.168.xx.yy", + "port": "odata", + "secure": true + } + ] } ); diff --git a/ngapp/src/environments/environment.prod.ts b/ngapp/src/environments/environment.prod.ts index dd9777c8..db7f4673 100644 --- a/ngapp/src/environments/environment.prod.ts +++ b/ngapp/src/environments/environment.prod.ts @@ -60,6 +60,8 @@ export const environment = { userProfileUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service/userProfile", - viewEditorState: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service/userProfile/viewEditorState" + viewEditorState: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service/userProfile/viewEditorState", + + viewEditorStates: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service/userProfile/viewEditorStates" }; diff --git a/ngapp/src/environments/environment.ts b/ngapp/src/environments/environment.ts index 6fcfc4a0..f5b0480f 100644 --- a/ngapp/src/environments/environment.ts +++ b/ngapp/src/environments/environment.ts @@ -63,6 +63,8 @@ export const environment = { userProfileUrl: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service/userProfile", - viewEditorState: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service/userProfile/viewEditorState" + viewEditorState: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service/userProfile/viewEditorState", + + viewEditorStates: komodoUrlPrefix + komodoEngine + "/" + komodoRestVersion + "/service/userProfile/viewEditorStates" }; From eccd80d92392bba76f87652f4fa5faa6a8dfa5b4 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Wed, 26 Sep 2018 18:39:50 -0500 Subject: [PATCH 191/205] TTOOLS-493 Improvements to preview --- .../editor-views/view-preview/view-preview.component.ts | 4 ++++ .../virtualization/view-editor/view-editor.service.ts | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts index 10307c5b..4188d621 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts @@ -62,6 +62,10 @@ export class ViewPreviewComponent implements OnInit, OnDestroy { this.editorService = editorService; } + public get previewSql(): string { + return this._previewSql; + } + private clearResults(): void { if ( this.rows && this.columns ) { if ( this.rows.length !== 0 || this.columns.length !== 0 ) { diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index 1e5f656a..7ee7e7e5 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -502,7 +502,10 @@ export class ViewEditorService { this._originalView = null; } this.resetUndoManager(); + // Notify components that view has been reset this.fire( ViewEditorEvent.create( source, ViewEditorEventType.EDITED_VIEW_SET, [ this._editorView ] ) ); + // Reset the preview panel for this view + this.updatePreviewResults(); } /** @@ -563,7 +566,7 @@ export class ViewEditorService { source: ViewEditorPart ): void { this._previewSql = sql; this._previewResults = results; - this.fire( ViewEditorEvent.create( source, ViewEditorEventType.PREVIEW_RESULTS_CHANGED, [ results ] ) ); + this.fire( ViewEditorEvent.create( source, ViewEditorEventType.PREVIEW_RESULTS_CHANGED ) ); } /** From 4552f2d329831106fb31dc2db70a8f39fb7a1f4e Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 28 Sep 2018 11:53:30 -0500 Subject: [PATCH 192/205] TTOOLS-483 Add ability to update virtualization description --- .../dataservice-card.component.css | 6 ++ .../dataservice-card.component.html | 3 + .../dataservice-card.component.ts | 2 + .../dataservices-cards.component.ts | 4 + .../dataservices-list.component.html | 5 +- .../dataservices-list.component.ts | 5 + .../dataservices/dataservices.component.html | 6 +- .../dataservices/dataservices.component.ts | 40 ++++++++ .../app/dataservices/dataservices.module.ts | 6 +- .../set-description-dialog.component.css | 0 .../set-description-dialog.component.html | 22 +++++ .../set-description-dialog.component.spec.ts | 42 ++++++++ .../set-description-dialog.component.ts | 99 +++++++++++++++++++ .../shared/dataservice.service.ts | 15 +++ .../shared/mock-dataservice.service.ts | 11 +++ .../view-editor/view-editor-i18n.ts | 4 + .../view-editor/view-editor.service.ts | 7 +- 17 files changed, 270 insertions(+), 7 deletions(-) create mode 100644 ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.css create mode 100644 ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.html create mode 100644 ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts create mode 100644 ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css index 45ff33af..41a300dc 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css @@ -89,3 +89,9 @@ a.list-pf-title.view-name { .views-details h1, .h1 { font-size: 14px; } + +.dataservice-card-edit-icon { + color: var(--card-action-icon-color); + cursor: pointer; + margin-left: 7px; +} diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html index 535957ad..8fe3596f 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html @@ -148,6 +148,9 @@

    Publishing Logs for '{{dataservice.getId()}}'

    {{ dataservice.getId() }}
    +
    +
    +
    {{ description }}
    diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts index 5d02ce11..d4ed6e5a 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts @@ -44,12 +44,14 @@ export class DataserviceCardComponent implements DoCheck, OnInit { public static readonly testDataserviceEvent = "test"; public static readonly downloadDataserviceEvent = "download"; public static readonly odataLookDataserviceEvent = "odataLook"; + public static readonly editDescriptionDataserviceEvent = "editDescription"; public readonly editEvent = DataserviceCardComponent.editDataserviceEvent; public readonly quickLookEvent = DataserviceCardComponent.quickLookDataserviceEvent; public readonly testEvent = DataserviceCardComponent.testDataserviceEvent; public readonly downloadEvent = DataserviceCardComponent.downloadDataserviceEvent; public readonly odataLookEvent = DataserviceCardComponent.odataLookDataserviceEvent; + public readonly editDescriptionEvent = DataserviceCardComponent.editDescriptionDataserviceEvent; @Input() public dataservice: Dataservice; @Input() public selectedDataservices: Dataservice[]; diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts index e2aa4d46..27abf798 100644 --- a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts +++ b/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts @@ -42,6 +42,7 @@ export class DataservicesCardsComponent { @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); @Output() public downloadDataservice: EventEmitter = new EventEmitter(); @Output() public odataLookDataservice: EventEmitter = new EventEmitter(); + @Output() public editDescriptionDataservice: EventEmitter = new EventEmitter(); public logger: LoggerService; @@ -85,6 +86,9 @@ export class DataservicesCardsComponent { case DataserviceCardComponent.odataLookDataserviceEvent: this.odataLookDataservice.emit( event.dataserviceName ); break; + case DataserviceCardComponent.editDescriptionDataserviceEvent: + this.editDescriptionDataservice.emit( event.dataserviceName ); + break; default: this.logger.error( "Unhandled event type of '" + event.eventType + "'" ); break; diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html index d9b7ac5c..fba8d2eb 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html @@ -97,7 +97,10 @@

    Publishing Logs for '{{item.getId()}}'

    {{ item.getId() }} -
    {{ getDescription( item ) }}
    +
    + + {{ getDescription( item ) }} +
    diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts index 2a643d45..d2fdb2df 100644 --- a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts +++ b/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts @@ -68,6 +68,7 @@ export class DataservicesListComponent implements OnInit { @Output() public editDataservice: EventEmitter = new EventEmitter(); @Output() public quickLookDataservice: EventEmitter = new EventEmitter(); @Output() public odataLookDataservice: EventEmitter = new EventEmitter(); + @Output() public editDescriptionDataservice: EventEmitter = new EventEmitter(); @ViewChild('publishLogsEditor') private logEditor: any; @@ -252,6 +253,10 @@ export class DataservicesListComponent implements OnInit { this.editDataservice.emit(nameVal); } + public onEditDescription(dataserviceName: string): void { + this.editDescriptionDataservice.emit(dataserviceName); + } + public onEditView(dsNameView: NameValue): void { this.editDataservice.emit(dsNameView); } diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 67974d12..1c6ca447 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -85,14 +85,16 @@

    (publishDataservice)="onPublish($event)" (deleteDataservice)="onDelete($event)" (editDataservice)="onEdit($event)" (quickLookDataservice)="onQuickLook($event)" (downloadDataservice)="onDownload($event)" (odataLookDataservice)="onOdataLook($event)" - (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)"> + (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)" + (editDescriptionDataservice)="onEditDescription($event)"> + (dataserviceSelected)="onSelected($event)" (dataserviceDeselected)="onDeselected($event)" + (editDescriptionDataservice)="onEditDescription($event)">

    diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ngapp/src/app/dataservices/dataservices.component.ts index ab92379b..7e80c2bc 100644 --- a/ngapp/src/app/dataservices/dataservices.component.ts +++ b/ngapp/src/app/dataservices/dataservices.component.ts @@ -56,6 +56,7 @@ import { ViewDefinition } from "@dataservices/shared/view-definition.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; import { NameValue } from "@dataservices/shared/name-value.model"; import { CreateViewsDialogComponent } from "@dataservices/create-views-dialog/create-views-dialog.component"; +import { SetDescriptionDialogComponent } from "@dataservices/set-description-dialog/set-description-dialog.component"; @Component({ moduleId: module.id, @@ -805,6 +806,45 @@ export class DataservicesComponent extends AbstractPageComponent implements OnIn this.setOdataServiceName(svcName); } + /* + * Handle edit of the specified Dataservice description + */ + public onEditDescription(svcName: string): void { + const selectedService = this.filteredDataservices.find((x) => x.getId() === svcName); + this.selectionService.setSelectedVirtualization(selectedService); + const virtName = selectedService.getId(); + const descr = selectedService.getDescription(); + + // Open Dialog to set new description + const initialState = { + title: ViewEditorI18n.setDescriptionDialogTitle, + cancelButtonText: ViewEditorI18n.cancelButtonText, + okButtonText: ViewEditorI18n.okButtonText, + description: descr + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(SetDescriptionDialogComponent, {initialState}); + modalRef.content.okAction.take(1).subscribe((newDesc) => { + if (newDesc !== descr) { + selectedService.setDescription(newDesc); + // update the repo virtualization description + const updVirt = this.dataserviceService.newDataserviceInstance(virtName, newDesc); + const self = this; + this.dataserviceService + .updateDataservice(updVirt) + .subscribe( + (wasSuccess) => { + this.logger.debug("[DataservicesComponent] Updated the Dataservice."); + }, + (error) => { + self.error(error, "Error updating the dataservice"); + } + ); + } + }); + } + /** * Set the layout to list type */ diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 5b6bf694..0e7f88e7 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -74,6 +74,7 @@ import { ViewPropertyEditorsComponent } from './virtualization/view-editor/view- import { AddCompositionWizardComponent } from './virtualization/view-editor/add-composition-wizard/add-composition-wizard.component'; import { CreateViewDialogComponent } from './virtualization/view-editor/create-view-dialog/create-view-dialog.component'; import { CreateViewsDialogComponent } from './create-views-dialog/create-views-dialog.component'; +import { SetDescriptionDialogComponent } from "@dataservices/set-description-dialog/set-description-dialog.component"; @NgModule({ imports: [ @@ -127,7 +128,8 @@ import { CreateViewsDialogComponent } from './create-views-dialog/create-views-d LinkVisualComponent, AddCompositionWizardComponent, CreateViewDialogComponent, - CreateViewsDialogComponent + CreateViewsDialogComponent, + SetDescriptionDialogComponent ], providers: [ { @@ -150,7 +152,7 @@ import { CreateViewsDialogComponent } from './create-views-dialog/create-views-d exports: [ ], entryComponents: [AddCompositionWizardComponent, ConfirmDialogComponent, ConnectionTableDialogComponent, - CreateViewDialogComponent, CreateViewsDialogComponent, ProgressDialogComponent] + CreateViewDialogComponent, CreateViewsDialogComponent, ProgressDialogComponent, SetDescriptionDialogComponent] }) export class DataservicesModule { } diff --git a/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.css b/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.css new file mode 100644 index 00000000..e69de29b diff --git a/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.html b/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.html new file mode 100644 index 00000000..4bc78c28 --- /dev/null +++ b/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.html @@ -0,0 +1,22 @@ + + + diff --git a/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts b/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts new file mode 100644 index 00000000..e5f12789 --- /dev/null +++ b/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts @@ -0,0 +1,42 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SetDescriptionDialogComponent } from './set-description-dialog.component'; +import { HttpModule } from "@angular/http"; +import { BsModalRef, ModalModule } from "ngx-bootstrap"; +import { + ActionModule +} from "patternfly-ng"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { AppSettingsService } from "@core/app-settings.service"; +import { LoggerService } from "@core/logger.service"; + +describe('SetDescriptionDialogComponent', () => { + let component: SetDescriptionDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + HttpModule, + FormsModule, + ReactiveFormsModule, + ModalModule.forRoot(), + ActionModule + ], + declarations: [ SetDescriptionDialogComponent ], + providers: [ AppSettingsService, BsModalRef, LoggerService + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SetDescriptionDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts b/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts new file mode 100644 index 00000000..402b6ea5 --- /dev/null +++ b/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts @@ -0,0 +1,99 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, OnInit } from "@angular/core"; +import { Output } from "@angular/core"; +import { EventEmitter } from "@angular/core"; +import { BsModalRef } from "ngx-bootstrap"; +import { LoggerService } from "@core/logger.service"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { FormControl, FormGroup } from "@angular/forms"; + +@Component({ + selector: "app-create-view-dialog", + templateUrl: "./set-description-dialog.component.html", + styleUrls: ["./set-description-dialog.component.css"] +}) +/** + * SetDescription Dialog. Invoke this from another component as follows: + * + * this.modalRef = this.modalService.show(SetDescriptionDialogComponent, {initialState}); + * this.modalRef.content.okAction.take(1).subscribe((description) => { + * // do something with description + * }); + * + * The expected initial state is as follows: + * const initialState = { + * title: "The dialog title", + * cancelButtonText: "Text for cancel button", + * confirmButtonText: "Text for confirm button" + * }; + */ +export class SetDescriptionDialogComponent implements OnInit { + + @Output() public okAction: EventEmitter = new EventEmitter(); + + public readonly title = ViewEditorI18n.setDescriptionDialogTitle; + public readonly message = ViewEditorI18n.setDescriptionDialogMessage; + public readonly cancelButtonText = ViewEditorI18n.cancelButtonText; + public readonly okButtonText = ViewEditorI18n.okButtonText; + public description = ""; + public okButtonEnabled = true; + public bsModalRef: BsModalRef; + public viewPropertyForm: FormGroup; + + private loggerService: LoggerService; + private originalDescription = ""; + + constructor(bsModalRef: BsModalRef, logger: LoggerService) { + this.bsModalRef = bsModalRef; + this.loggerService = logger; + this.createViewPropertyForm(); + } + + public ngOnInit(): void { + this.originalDescription = this.description; + this.viewPropertyForm.controls["description"].setValue(this.description); + } + + /* + * Creates the view property form + */ + private createViewPropertyForm(): void { + this.viewPropertyForm = new FormGroup({ + description: new FormControl(this.description) + }); + } + + /** + * OK selected. Emit ViewDefinition with the view, then modal is closed + */ + public onOkSelected(): void { + const theDescr = this.viewPropertyForm.controls["description"].value; + + this.okAction.emit(theDescr); + this.bsModalRef.hide(); + } + + /** + * Cancel selected. The modal is closed. + */ + public onCancelSelected(): void { + this.bsModalRef.hide(); + } + +} diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ngapp/src/app/dataservices/shared/dataservice.service.ts index a923915c..bc7bfd2c 100644 --- a/ngapp/src/app/dataservices/shared/dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/dataservice.service.ts @@ -142,6 +142,21 @@ export class DataserviceService extends ApiService { .catch( ( error ) => this.handleError( error ) ); } + /** + * Update a dataservice via the komodo rest interface + * @param {NewDataservice} dataservice + * @returns {Observable} + */ + public updateDataservice(dataservice: NewDataservice): Observable { + return this.http + .put(environment.komodoWorkspaceUrl + DataservicesConstants.dataservicesRestPath + "/" + dataservice.getId(), + dataservice, this.getAuthRequestOptions()) + .map((response) => { + return response.ok; + }) + .catch( ( error ) => this.handleError( error ) ); + } + /** * Deploy a dataservice via the komodo rest interface * @param {string} dataserviceName diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index 1acefc35..b27a52e3 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -33,6 +33,8 @@ import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; import { ErrorObservable } from "rxjs/observable/ErrorObservable"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; +import { environment } from "@environments/environment"; +import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; @Injectable() export class MockDataserviceService extends DataserviceService { @@ -78,6 +80,15 @@ export class MockDataserviceService extends DataserviceService { return Observable.of(true); } + /** + * Update a dataservice via the komodo rest interface + * @param {NewDataservice} dataservice + * @returns {Observable} + */ + public updateDataservice(dataservice: NewDataservice): Observable { + return Observable.of(true); + } + /** * Delete a dataservice via the komodo rest interface * @param {string} dataserviceId diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts index a7641ca2..0fd05126 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts @@ -48,6 +48,10 @@ export class ViewEditorI18n { public static readonly createViewDialogMessage = "Enter name and description(optional) for the new view"; public static readonly createViewDialogTitle = "Create View"; + // set description dialog + public static readonly setDescriptionDialogTitle = "Set Virtualization Description"; + public static readonly setDescriptionDialogMessage = "Set the description for this virtualization"; + // Add Composition Wizard public static readonly addCompositionWizardTitle = "Add Composition"; public static readonly addCompositionWizardSelectSourceMessage = "Expand connection and select a source for the composition"; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index 7ee7e7e5..2103a4c8 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -61,7 +61,7 @@ export class ViewEditorService { private readonly _logger: LoggerService; private _messages: Message[] = []; private _previewResults: QueryResults; - private _previewSql = null; + private _previewSql = ""; private _readOnly = false; private _shouldFireEvents = true; private _undoMgr: UndoManager; @@ -275,7 +275,7 @@ export class ViewEditorService { } /** - * @returns {string} the preview sql or '' if not set + * @returns {string} the preview sql */ public getPreviewSql(): string { return this._previewSql; @@ -530,6 +530,9 @@ export class ViewEditorService { // Clear preview results this.setPreviewResults(null, null, ViewEditorPart.EDITOR); + if ( !this._editorView || this._editorView === null ) { + return; + } let querySql = ""; if ( sourcePath != null && !sourcePath.startsWith(AddCompositionCommand.id) ) { // Fetch new results for source table From 9ea5504f06e3014cf522f85672fe5e7121957470 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 1 Oct 2018 09:47:40 -0500 Subject: [PATCH 193/205] minor property editor addition and views dialog fix --- .../create-views-dialog.component.html | 1 - .../create-views-dialog.component.ts | 41 ++++------------- .../create-views-dialog/new-view.model.ts | 14 +++--- .../view-editor/view-editor-part.enum.ts | 7 ++- .../view-property-editors.component.css | 7 +++ .../view-property-editors.component.html | 25 ++++++---- .../view-property-editors.component.ts | 46 +++++++++++++------ 7 files changed, 77 insertions(+), 64 deletions(-) diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html index be7142b9..7ceb8b9b 100644 --- a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html @@ -69,7 +69,6 @@ diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts index f3379883..ca2b606c 100644 --- a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts @@ -54,7 +54,6 @@ export class CreateViewsDialogComponent implements OnInit { public allViews: NewView[] = []; public listConfig: ListConfig; public tableColumns: any[] = []; - public ngxTableConfig: NgxDataTableConfig; public tableConfig: TableConfig; public virtNameValidationError = ""; public virtualizationPropertyForm: FormGroup; @@ -99,17 +98,15 @@ export class CreateViewsDialogComponent implements OnInit { { draggable: false, name: "Connection", - prop: "connectionName", + prop: "connection", resizeable: true, sortable: false, - maxWidth: "100", - minWidth: "100", width: "100" }, { draggable: false, name: "View Name", - prop: "viewName", + prop: "view", resizeable: true, sortable: false, width: "100" @@ -117,17 +114,12 @@ export class CreateViewsDialogComponent implements OnInit { { draggable: false, name: "Source Node", - prop: "pathString", + prop: "path", resizeable: true, sortable: false, width: "100" } ]; - this.ngxTableConfig = { - reorderable: false, - selectionType: "'single'", - sorts: [ { prop: "name", dir: "asc" } ], - } as NgxDataTableConfig; this.emptyStateConfig = { title: ViewEditorI18n.noViewsDisplayedMessage @@ -260,16 +252,13 @@ export class CreateViewsDialogComponent implements OnInit { * @param {SchemaNode} conn the connection node */ private onConnectionDeselected(conn: SchemaNode): void { - const refreshViews = this.arrayClone(this.allViews); - - let i = refreshViews.length; + let i = this.allViews.length; while (i--) { - if (refreshViews[i].getConnectionName() === conn.getName()) { - refreshViews.splice(i, 1); + if (this.allViews[i].getConnectionName() === conn.getName()) { + this.allViews.splice(i, 1); } } - - this.allViews = refreshViews; + this.allViews = [...this.allViews]; } /** @@ -374,17 +363,15 @@ export class CreateViewsDialogComponent implements OnInit { .getConnectionSchema(connName) .subscribe( (schemaNodes) => { - // Copy existing view. Need to reset array to get table to refresh?? - const refreshViews = this.arrayClone(self.allViews); const newViews: NewView[] = []; for ( const schemaNode of schemaNodes ) { const nodePath: string[] = []; self.generateViewInfos(connName, schemaNode, nodePath, newViews); } for (const newView of newViews) { - refreshViews.push(newView); + self.allViews.push(newView); } - self.allViews = refreshViews; + self.allViews = [...self.allViews]; self.viewsLoadingState = LoadingState.LOADED_VALID; }, (error) => { @@ -418,14 +405,4 @@ export class CreateViewsDialogComponent implements OnInit { } } - private arrayClone(oldArray: NewView[]): NewView[] { - const newArray: NewView[] = []; - oldArray.forEach((item) => { - const nView = new NewView(); - Object.assign(nView, item); - newArray.push(nView); - }); - return newArray; - } - } diff --git a/ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts b/ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts index f6d368d9..37dca688 100644 --- a/ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts +++ b/ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts @@ -22,8 +22,8 @@ import { SchemaNode } from "@connections/shared/schema-node.model"; */ export class NewView { - private connectionName: string; - private viewName: string; + private connection: string; + private view: string; private viewDescription = ""; private viewSourceNode: SchemaNode; private nodePath: string[] = []; @@ -36,28 +36,28 @@ export class NewView { * @returns {string} the connection name */ public getConnectionName(): string { - return this.connectionName; + return this.connection; } /** * @param {string} name the connection name */ public setConnectionName( name?: string ): void { - this.connectionName = name ? name : null; + this.connection = name ? name : null; } /** * @returns {string} the view name */ public getViewName(): string { - return this.viewName; + return this.view; } /** * @param {string} name the view name */ public setViewName( name?: string ): void { - this.viewName = name ? name : null; + this.view = name ? name : null; } /** @@ -91,7 +91,7 @@ export class NewView { /** * @returns {string} the stringified node path */ - public get pathString(): string { + public get path(): string { let path = ""; const segLength = this.nodePath.length; for ( let i = 0; i < segLength; i++ ) { diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts index 226e2c46..824829f3 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts @@ -45,6 +45,11 @@ export enum ViewEditorPart { /** * The source of the event is the properties part. */ - PROPERTIES = "PROPERTIES" + PROPERTIES = "PROPERTIES", + + /** + * The source of the event is the properties part. + */ + COLUMNS = "COLUMNS" } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css index eca6d133..0d7cf1b8 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css @@ -21,3 +21,10 @@ .property-editors-tab-heading { font-size: smaller; } + +/* + * Adds a space to the right of the icon and before the tab heading. + */ +.property-editors-tab-icon:after { + margin-right: 2px; +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html index 0a0d1465..a94b3df6 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html @@ -1,13 +1,18 @@ - - {{tabz?.content}} + + + + View + + + + + + {{columnPropsTabName}} + diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts index 8535f0e2..564378f2 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts @@ -18,9 +18,11 @@ import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { LoggerService } from "@core/logger.service"; import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event"; import { Subscription } from "rxjs/Subscription"; +import 'dragula/dist/dragula.css'; @Component({ encapsulation: ViewEncapsulation.None, @@ -30,28 +32,27 @@ import { Subscription } from "rxjs/Subscription"; }) export class ViewPropertyEditorsComponent implements OnInit, OnDestroy { + public readonly columnPropsTabName = ViewEditorI18n.columnPropsTabName; + private columnEditorIsEnabled = true; private readonly editorService: ViewEditorService; private readonly logger: LoggerService; private subscription: Subscription; private viewEditorIsEnabled = true; - public readonly tabs: any[] = [ + private readonly viewIndex = 0; + private readonly columnIndex = 1; + + /** + * The tabs component configuration. + */ + public tabs = [ { - active: true, - content: "View properties", - customClass: "property-editors-tab-heading", - disabled: !this.viewEditorIsEnabled, - removable: false, - title: ViewEditorI18n.viewPropsTabName + "active": true // preview }, { - content: "Column editor", - customClass: "property-editors-tab-heading", - disabled: !this.columnEditorIsEnabled, - removable: false, - title: ViewEditorI18n.columnPropsTabName - } + "active": false // message log + }, ]; constructor( editorService: ViewEditorService, @@ -69,6 +70,15 @@ export class ViewPropertyEditorsComponent implements OnInit, OnDestroy { if ( event.typeIsCanvasSelectionChanged() ) { // TODO set this.viewEditorIsEnabled to true if all canvas selections are views // TODO set this.columnEditorIsEnabled to true if all canvas selections are columns + if ( event.args.length !== 0 ) { + if ( event.args[ 0 ] === ViewEditorPart.COLUMNS ) { + this.tabs[ this.viewIndex ].active = false; + this.tabs[ this.columnIndex ].active = true; + } else if ( event.args[ 0 ] === ViewEditorPart.PROPERTIES) { + this.tabs[ this.viewIndex ].active = false; + this.tabs[ this.columnIndex ].active = true; + } + } } } @@ -93,4 +103,14 @@ export class ViewPropertyEditorsComponent implements OnInit, OnDestroy { this.tabs.splice( this.tabs.indexOf( tab ), 1); } + /** + * Callback for when a tab is clicked. + * + * @param tab the tab being select or deselected + * @param selected `true` is selected + */ + public tabSelected( tab, selected ): void { + tab.active = selected; + } + } From 542bbe42c3421d0218863d7f6a265efe85ff4bd1 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Mon, 1 Oct 2018 10:24:31 -0500 Subject: [PATCH 194/205] Add spinner when views loading --- .../dataservices/dataservices.component.html | 44 +++++++++---------- .../view-editor-header.component.html | 6 ++- .../view-editor-header.component.ts | 27 +++++++++--- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ngapp/src/app/dataservices/dataservices.component.html index 1c6ca447..47282e0c 100644 --- a/ngapp/src/app/dataservices/dataservices.component.html +++ b/ngapp/src/app/dataservices/dataservices.component.html @@ -36,24 +36,32 @@

    Data Virtualiza

    -
    -
    -
    - -
    +
    + + + +
    + +
    +
    +
    +
    -
    -
    -
    - -
    +
    +
    +
    +
    +
    +
    @@ -71,14 +79,6 @@

    -
    - - - -
    -
    Virtualization Name: '{{virtualizationName}}'

    Views:
    -
    +
    Virtualization Name: '{{virtualizationName}}'

    [rows]="tableRows">
    + +
    +
    +
    diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index 87dd90a4..0a733e60 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { AfterViewInit, Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core"; +import { Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core"; import { LoggerService } from "@core/logger.service"; import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; @@ -42,7 +42,7 @@ import { ViewEditorProgressChangeId } from "@dataservices/virtualization/view-ed templateUrl: "./view-editor-header.component.html", styleUrls: ["./view-editor-header.component.css"] }) -export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestroy { +export class ViewEditorHeaderComponent implements OnInit, OnDestroy { // used by html public readonly viewDescriptionLabel = ViewEditorI18n.viewDescriptionLabel; @@ -136,9 +136,7 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr this.tableConfig = { emptyStateConfig: this.emptyStateConfig } as TableConfig; - } - public ngAfterViewInit(): void { // init the available views this.initViews(); } @@ -182,8 +180,8 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr } else { initialView = self.tableRows.find((x) => x.getName() === selectedView.getName()); } - self.selectView(initialView); self.viewsLoadingState = LoadingState.LOADED_VALID; + self.selectView(initialView); }, (error) => { self.logger.error("[VirtualizationComponent] Error updating the views for the virtualization: %o", error); @@ -200,6 +198,13 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr return !this.editorService.getEditorView() || this.editorService.isReadOnly(); } + /** + * @returns {boolean} `true` if views are being loaded + */ + public get viewsLoading(): boolean { + return this.viewsLoadingState === LoadingState.LOADING; + } + /** * @returns {string} the view description */ @@ -326,6 +331,8 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr const editorStates: ViewEditorState[] = []; editorStates.push(editorState); + this.viewsLoadingState = LoadingState.LOADING; + const self = this; this.dataserviceService .saveViewEditorStatesRefreshViews(editorStates, selectedDs.getId()) @@ -334,10 +341,12 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr // Add the new ViewDefinition to the table self.addViewDefinitionToList(viewDefn); self.viewSavedUponCompletion = null; + self.viewsLoadingState = LoadingState.LOADED_VALID; }, (error) => { self.logger.error("[VirtualizationComponent] Error saving the editor state: %o", error); self.viewSavedUponCompletion = null; + self.viewsLoadingState = LoadingState.LOADED_INVALID; } ); } @@ -385,6 +394,8 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr const vdbName = selectedDs.getServiceVdbName(); const editorStateId = vdbName.toLowerCase() + "." + viewDefnName; const dataserviceName = selectedDs.getId(); + + this.viewsLoadingState = LoadingState.LOADING; // Note: we can only doDelete selected items that we can see in the UI. this.logger.debug("[VirtualizationComponent] Deleting selected Virtualization View."); const self = this; @@ -395,9 +406,11 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr self.removeViewDefinitionFromList(selectedViewDefn); // deletion of a view undeploys active serviceVdb self.editorService.undeploySelectedVirtualization(); + this.viewsLoadingState = LoadingState.LOADED_VALID; }, (error) => { self.logger.error("[VirtualizationComponent] Error deleting the editor state: %o", error); + this.viewsLoadingState = LoadingState.LOADED_INVALID; } ); } @@ -450,7 +463,7 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr private selectView( selView: ViewDefinition ): void { // Updates table selection display let viewSelection = null; - if ( selView !== null ) { + if ( selView && selView !== null ) { for (const view of this.tableRows) { if (view.getName() === selView.getName()) { view.setSelected(true); @@ -461,7 +474,7 @@ export class ViewEditorHeaderComponent implements OnInit, AfterViewInit, OnDestr } } // Update selection service, then fire event - this.selectionService.setSelectedViewDefinition(this.selectedVirtualization, selView); + this.selectionService.setSelectedViewDefinition(this.selectedVirtualization, viewSelection); this.editorService.setEditorView(viewSelection, ViewEditorPart.HEADER); } From bb627e33dd082e1fccabfcd0ca30f33ceb2577c3 Mon Sep 17 00:00:00 2001 From: blafond Date: Mon, 1 Oct 2018 13:06:59 -0500 Subject: [PATCH 195/205] TTOOLS-489 - removed layout toolbar buttons - changed canvas/property panel width ratios - removed the editor views panel out of the view-editor-area --- .../editor-views/editor-views.component.css | 4 +++- .../view-canvas/view-canvas.component.css | 4 ++-- .../visuals/graph/graph-visual.component.ts | 4 ++-- .../view-editor/view-editor.component.css | 23 ++++--------------- .../view-editor/view-editor.component.html | 6 ++--- .../view-editor/view-editor.component.ts | 20 ---------------- 6 files changed, 14 insertions(+), 47 deletions(-) diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css index 313f9320..54a855e0 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css @@ -3,7 +3,9 @@ */ #editor-views-tabs .tab-content { border: 1px solid lightgray; - height: 75%; + height: 140px; + overflow-x: auto; + overflow-y: auto; } /* diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css index 1d37e340..50bca7a7 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css @@ -5,7 +5,7 @@ display: grid; grid-template-areas: "canvas-editor properties-editor"; - grid-template-columns: 8fr 2fr; + grid-template-columns: 50fr 50fr; height: 100%; } @@ -39,7 +39,7 @@ .canvas-node-selected { stroke: red !important; - stroke-width: 2 !important; + stroke-width: 2px !important; stroke-dasharray: 5,5; fill: transparent !important; } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts index 71657a0f..fdece176 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts @@ -107,8 +107,8 @@ export class GraphVisualComponent implements OnInit { // TODO: Need to discuss how all the layout sizes affect each other. public get options(): any { return this._options = { - width: window.innerWidth * .7, - height: window.innerHeight * .4 + width: window.innerWidth * .5, + height: window.innerHeight * .45 }; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css index 36a51591..8cae6216 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css @@ -14,7 +14,7 @@ } /* - * A view editor area (i.e., heading, canvas, properties, editor views). + * A view editor area (i.e., heading, toobar, canvas, properties). */ .view-editor-area { background-color: #ededed; @@ -58,10 +58,10 @@ "dataservices-breadcrumb-bar" "header" "toolbar" - "canvas" - "editor-views"; + "canvas"; grid-template-columns: 1fr; - grid-template-rows: 1fr 10fr 3fr 60fr 26fr; + grid-template-rows: 5fr 10fr 5fr 80fr; + grid-row-gap: 10px; } /* @@ -78,19 +78,6 @@ margin: 0; } -/* - * A view editor showing only header, toolbar, and editor views areas (missing canvas and properties). - */ -.view-editor-views-only { - grid-template-areas: - "dataservices-breadcrumb-bar" - "header" - "toolbar" - "editor-views"; - grid-template-columns: 1fr; - grid-template-rows: 5fr 10fr 5fr 80fr; -} - /* * The view editor toolbar which is below the heading section. */ @@ -183,6 +170,4 @@ * View editor bottom section containing live sample results, message log, and maybe others. */ #view-editor-views-container { - grid-area: editor-views; - overflow-y: auto; } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html index e0b9491b..50bbb4e8 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html @@ -91,9 +91,9 @@ -
    + +
    diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts index df55909c..f381af02 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts @@ -153,26 +153,6 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { this.editorService.setEditorConfig( this.fullEditorCssType ); // this could be set via preference or last used config this.subscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) ); - this.toolbarConfig = { - views: [ - { - id: this.fullEditorCssType, - iconStyleClass: "fa fa-file-text-o", - tooltip: ViewEditorI18n.showEditorCanvasAndViewsActionTooltip - }, - { - id: this.canvasOnlyCssType, - iconStyleClass: "fa fa-file-image-o", - tooltip: ViewEditorI18n.showEditorCanvasOnlyActionTooltip - }, - { - id: this.viewsOnlyCssType, - iconStyleClass: "fa fa-table", - tooltip: ViewEditorI18n.showEditorViewsOnlyActionTooltip - } - ] - } as ToolbarConfig; - // Load the connections const self = this; this.connectionService From 18a29e31f26afb22840fc6d85434d05480c3fec8 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Tue, 2 Oct 2018 16:42:39 -0500 Subject: [PATCH 196/205] TTOOLS-465 Addition of property editor component --- .../app/dataservices/dataservices.module.ts | 4 +- .../dataservices/shared/composition.model.ts | 21 +++++ .../command/add-composition-command.ts | 3 +- .../command/add-sources-command.ts | 3 +- .../view-editor/command/command-type.enum.ts | 58 ++++++++++++ .../view-editor/command/no-op-command.ts | 3 +- .../command/remove-composition-command.ts | 3 +- .../command/remove-sources-command.ts | 3 +- .../update-view-description-command.ts | 3 +- .../command/update-view-name-command.ts | 3 +- .../view-canvas/view-canvas.component.spec.ts | 2 + .../view-editor/view-editor-i18n.ts | 4 +- .../view-editor/view-editor.component.ts | 30 ++---- .../view-editor/view-editor.service.ts | 47 ++++++++++ .../property-editor.component.css | 7 ++ .../property-editor.component.html | 35 +++++++ .../property-editor.component.spec.ts | 48 ++++++++++ .../property-editor.component.ts | 86 ++++++++++++++++++ .../property-editor/selection-item.model.ts | 91 +++++++++++++++++++ .../property-editor/selection-type.enum.ts | 38 ++++++++ .../view-property-editors.component.css | 1 - .../view-property-editors.component.html | 5 +- .../view-property-editors.component.spec.ts | 3 +- .../view-property-editors.component.ts | 31 ++++--- 24 files changed, 481 insertions(+), 51 deletions(-) create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index 0e7f88e7..c0ef900d 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -75,6 +75,7 @@ import { AddCompositionWizardComponent } from './virtualization/view-editor/add- import { CreateViewDialogComponent } from './virtualization/view-editor/create-view-dialog/create-view-dialog.component'; import { CreateViewsDialogComponent } from './create-views-dialog/create-views-dialog.component'; import { SetDescriptionDialogComponent } from "@dataservices/set-description-dialog/set-description-dialog.component"; +import { PropertyEditorComponent } from './virtualization/view-editor/view-property-editors/property-editor/property-editor.component'; @NgModule({ imports: [ @@ -129,7 +130,8 @@ import { SetDescriptionDialogComponent } from "@dataservices/set-description-dia AddCompositionWizardComponent, CreateViewDialogComponent, CreateViewsDialogComponent, - SetDescriptionDialogComponent + SetDescriptionDialogComponent, + PropertyEditorComponent ], providers: [ { diff --git a/ngapp/src/app/dataservices/shared/composition.model.ts b/ngapp/src/app/dataservices/shared/composition.model.ts index 373b8f01..cb844dd2 100644 --- a/ngapp/src/app/dataservices/shared/composition.model.ts +++ b/ngapp/src/app/dataservices/shared/composition.model.ts @@ -17,6 +17,7 @@ import { CompositionType } from "@dataservices/shared/composition-type.enum"; import { CompositionOperator } from "@dataservices/shared/composition-operator.enum"; +import { PathUtils } from "@dataservices/shared/path-utils"; /** * Composition model @@ -250,4 +251,24 @@ export class Composition { return JSON.stringify(this.toJSON()); } + public getLeftSourceDisplay(): string { + const leftSrcPath = this.getLeftSourcePath(); + const leftConn = PathUtils.getConnectionName(leftSrcPath); + const leftSrc = PathUtils.getSourceName(leftSrcPath); + return "[" + leftConn + "] " + leftSrc; + } + + public getRightSourceDisplay(): string { + const rightSrcPath = this.getRightSourcePath(); + const rightConn = PathUtils.getConnectionName(rightSrcPath); + const rightSrc = PathUtils.getSourceName(rightSrcPath); + return "[" + rightConn + "] " + rightSrc; + } + + public getCriteriaDisplay(): string { + const leftColumn = this.getLeftCriteriaColumn(); + const rightColumn = this.getRightCriteriaColumn(); + return leftColumn + " " + CompositionOperator.toSql(this.getOperator()) + " " + rightColumn; + } + } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts index 1a3ddcaf..1ace8a52 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts @@ -18,6 +18,7 @@ import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; import { Command } from "@dataservices/virtualization/view-editor/command/command"; import { Composition } from "@dataservices/shared/composition.model"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; export class AddCompositionCommand extends Command { @@ -26,7 +27,7 @@ export class AddCompositionCommand extends Command { * * @type {string} */ - public static readonly id = "AddCompositionCommand"; + public static readonly id = CommandType.ADD_COMPOSITION_COMMAND; /** * The name of the command argument whose value is the stringified composition diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts index ab90e806..de69f13b 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts @@ -18,6 +18,7 @@ import { SchemaNode } from "@connections/shared/schema-node.model"; import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; import { Command } from "@dataservices/virtualization/view-editor/command/command"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; export class AddSourcesCommand extends Command { @@ -26,7 +27,7 @@ export class AddSourcesCommand extends Command { * * @type {string} */ - public static readonly id = "AddSourcesCommand"; + public static readonly id = CommandType.ADD_SOURCES_COMMAND; /** * The name of the command argument whose value is the paths of the sources being added. diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts new file mode 100644 index 00000000..5c3b52dd --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts @@ -0,0 +1,58 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Enumerates the available commands + */ +export enum CommandType { + + /** + * Command id for Add Composition + */ + ADD_COMPOSITION_COMMAND = "AddCompositionCommand", + + /** + * Command id for Add Sources + */ + ADD_SOURCES_COMMAND = "AddSourcesCommand", + + /** + * Command id for No op + */ + NO_OP_COMMAND = "NoOpCommand", + + /** + * Command id for Remove Composition + */ + REMOVE_COMPOSITION_COMMAND = "RemoveCompositionCommand", + + /** + * Command id for Remove Sources + */ + REMOVE_SOURCES_COMMAND = "RemoveSourcesCommand", + + /** + * Command id for Add Composition + */ + UPDATE_VIEW_DESCRIPTION_COMMAND = "UpdateViewDescriptionCommand", + + /** + * Command id for Add Composition + */ + UPDATE_VIEW_NAME_COMMAND = "UpdateViewNameCommand" + +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts index 4cae756a..b542dccf 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts @@ -16,6 +16,7 @@ */ import { Command } from "@dataservices/virtualization/view-editor/command/command"; import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; export class NoOpCommand extends Command { @@ -24,7 +25,7 @@ export class NoOpCommand extends Command { * * @type {string} */ - public static readonly id = "NoOpCommand"; + public static readonly id = CommandType.NO_OP_COMMAND; /** * The shared instance of the no op command. diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts index ec992c7d..334b0ee3 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts @@ -18,6 +18,7 @@ import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; import { Command } from "@dataservices/virtualization/view-editor/command/command"; import { Composition } from "@dataservices/shared/composition.model"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; export class RemoveCompositionCommand extends Command { @@ -26,7 +27,7 @@ export class RemoveCompositionCommand extends Command { * * @type {string} */ - public static readonly id = "RemoveCompositionCommand"; + public static readonly id = CommandType.REMOVE_COMPOSITION_COMMAND; /** * The name of the command argument whose value is the compositions being removed. diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts index 7174ee29..c99d8b73 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts @@ -18,6 +18,7 @@ import { SchemaNode } from "@connections/shared/schema-node.model"; import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; import { Command } from "@dataservices/virtualization/view-editor/command/command"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; export class RemoveSourcesCommand extends Command { @@ -26,7 +27,7 @@ export class RemoveSourcesCommand extends Command { * * @type {string} */ - public static readonly id = "RemoveSourcesCommand"; + public static readonly id = CommandType.REMOVE_SOURCES_COMMAND; /** * The name of the command argument whose value is the paths of the sources being removed. diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts index 051584c4..2ba0b073 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts @@ -17,6 +17,7 @@ import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; import { Command } from "@dataservices/virtualization/view-editor/command/command"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; export class UpdateViewDescriptionCommand extends Command { @@ -25,7 +26,7 @@ export class UpdateViewDescriptionCommand extends Command { * * @type {string} */ - public static readonly id = "UpdateViewDescriptionCommand"; + public static readonly id = CommandType.UPDATE_VIEW_DESCRIPTION_COMMAND; /** * The name of the command argument whose value is the new description of the view. diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts index 87fc179d..81bfc3a7 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts @@ -17,6 +17,7 @@ import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; import { Command } from "@dataservices/virtualization/view-editor/command/command"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; export class UpdateViewNameCommand extends Command { @@ -25,7 +26,7 @@ export class UpdateViewNameCommand extends Command { * * @type {string} */ - public static readonly id = "UpdateViewNameCommand"; + public static readonly id = CommandType.UPDATE_VIEW_NAME_COMMAND; /** * The name of the command argument whose value is the new name of the view. diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts index 81807ab5..e05f28f5 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts @@ -25,6 +25,7 @@ import { TabsModule } from "ngx-bootstrap"; import { GraphVisualComponent, LinkVisualComponent, NodeVisualComponent } from "@dataservices/virtualization/view-editor/view-canvas/visuals"; import { CanvasService } from "@dataservices/virtualization/view-editor/view-canvas/canvas.service"; import { SelectionService } from "@core/selection.service"; +import { PropertyEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component"; describe('ViewCanvasComponent', () => { let component: ViewCanvasComponent; @@ -49,6 +50,7 @@ describe('ViewCanvasComponent', () => { GraphVisualComponent, LinkVisualComponent, NodeVisualComponent, + PropertyEditorComponent, ViewCanvasComponent, ViewPropertyEditorsComponent ], diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts index 0fd05126..1994df2e 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts @@ -81,8 +81,8 @@ export class ViewEditorI18n { public static readonly warn0100 = "The view contains an orphan source which will be ignored"; // property editors - public static readonly columnPropsTabName = "Column"; - public static readonly viewPropsTabName = "View"; + public static readonly columnsTabName = "Columns"; + public static readonly propertiesTabName = "Properties"; // view canvas public static readonly noSourcesAlert = "Select a source for the view"; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts index f381af02..503d50ff 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts @@ -410,13 +410,13 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { selectionArgs.forEach( ( nextArg ) => { - // need to parse the command to find the source path - const commandPart = this.getCommandId(nextArg); + // get command type from the selection + const commandType = this.editorService.getSelectionCommandType(nextArg); // the payload for src will be the source/connection path // the payload for the composition will be the json representing the composition properties - const argPart = this.getPayload(nextArg); + const argPart = this.editorService.getSelectionPayload(nextArg); - if (commandPart.startsWith(AddSourcesCommand.id)) { + if ( commandType === AddSourcesCommand.id ) { // Look for any composition with src paths links and remove if exist const comps: Composition[] = this.editorService.getEditorView().getCompositions(); comps.forEach( (nextComp) => { @@ -438,12 +438,12 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { }); // Remove Source Command - const addSrcsCmd = CommandFactory.createRemoveSourcesCommand(argPart, commandPart); + const addSrcsCmd = CommandFactory.createRemoveSourcesCommand(argPart, commandType); this.notifyRemoved(addSrcsCmd); - } else if (commandPart.startsWith(AddCompositionCommand.id)) { + } else if ( commandType === AddCompositionCommand.id ) { // Remove composition - const addCompCmd = CommandFactory.createRemoveCompositionCommand(argPart, commandPart); + const addCompCmd = CommandFactory.createRemoveCompositionCommand(argPart, commandType); this.notifyRemoved(addCompCmd); } @@ -502,22 +502,6 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { return null; } - private getCommandId(selection?: string): string { - if (selection !== null) { - const args = selection.split(Command.identDivider); - return args[0]; - } - return null; - } - - private getPayload(selection?: string): string { - if (selection !== null) { - const args = selection.split(Command.identDivider); - return args[1]; - } - return null; - } - /** * Callback for when a view icon is clicked on the toolbar. * diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index 2103a4c8..1fb35cb4 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -42,6 +42,8 @@ import { ViewDefinition } from "@dataservices/shared/view-definition.model"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { SelectionService } from "@core/selection.service"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; +import { NoOpCommand } from "@dataservices/virtualization/view-editor/command/no-op-command"; @Injectable() export class ViewEditorService { @@ -720,6 +722,51 @@ export class ViewEditorService { return this._selection.length > 0; } + /** + * Get the Command type from the selection string + * @param selection the selection + * @return {CommandType} the command type + */ + public getSelectionCommandType(selection?: string): CommandType { + let argStr = null; + if (selection !== null) { + const args = selection.split(Command.identDivider); + argStr = args[0]; + } + if ( argStr !== null ) { + if ( argStr.startsWith(AddSourcesCommand.id) ) { + return AddSourcesCommand.id; + } else if ( argStr.startsWith(AddCompositionCommand.id) ) { + return AddCompositionCommand.id; + } else if ( argStr.startsWith(RemoveCompositionCommand.id) ) { + return RemoveCompositionCommand.id; + } else if ( argStr.startsWith(RemoveSourcesCommand.id) ) { + return RemoveSourcesCommand.id; + } else if ( argStr.startsWith(NoOpCommand.id) ) { + return NoOpCommand.id; + } else if ( argStr.startsWith(UpdateViewDescriptionCommand.id) ) { + return UpdateViewDescriptionCommand.id; + } else if ( argStr.startsWith(UpdateViewNameCommand.id) ) { + return UpdateViewNameCommand.id; + } + } + + return null; + } + + /** + * Get the payload from the selection string + * @param selection the selection + * @return {string} the command id + */ + public getSelectionPayload(selection?: string): string { + if (selection !== null) { + const args = selection.split(Command.identDivider); + return args[1]; + } + return null; + } + /** * Reset the UndoManager */ diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css new file mode 100644 index 00000000..5aeac588 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css @@ -0,0 +1,7 @@ +/* + * The container for the property editor + */ +#property-editor-container { + height: 100%; + margin-left: 15px; +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html new file mode 100644 index 00000000..28825a61 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html @@ -0,0 +1,35 @@ +
    +
    +

    No View Selected

    +
    + +
    +

    Multiple Items Selected

    +
    + +
    +

    {{getFirstSelection().getSelectionType()}} Properties

    +
    +
    Name:
    +
    {{getFirstSelection().getSourceName()}}
    +
    Connection:
    +
    {{getFirstSelection().getSourceConnectionName()}}
    +
    +
    +
    Name:
    +
    {{getFirstSelection().getComposition().getName()}}
    +
    Type:
    +
    {{getFirstSelection().getComposition().getType()}}
    +
    Left Source:
    +
    {{getFirstSelection().getComposition().getLeftSourceDisplay()}}
    +
    Right Source:
    +
    {{getFirstSelection().getComposition().getRightSourceDisplay()}}
    +
    Criteria:
    +
    {{getFirstSelection().getComposition().getCriteriaDisplay()}}
    +
    +
    + +
    +

    No item selected

    +
    +
    diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts new file mode 100644 index 00000000..e49e34be --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts @@ -0,0 +1,48 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PropertyEditorComponent } from './property-editor.component'; +import { SelectionService } from "@core/selection.service"; +import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; +import { LoggerService } from "@core/logger.service"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { HttpModule } from "@angular/http"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; + +describe('PropertyEditorComponent', () => { + let component: PropertyEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + HttpModule, + ], + declarations: [ PropertyEditorComponent ], + providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: DataserviceService, useClass: MockDataserviceService }, + LoggerService, + NotifierService, + SelectionService, + { provide: VdbService, useClass: MockVdbService }, + ViewEditorService + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PropertyEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts new file mode 100644 index 00000000..efe39eed --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts @@ -0,0 +1,86 @@ +import { Component, OnInit } from '@angular/core'; +import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; +import { SelectionService } from "@core/selection.service"; +import { SelectionItem } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model"; +import { SelectionType } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum"; + +@Component({ + selector: 'app-property-editor', + templateUrl: './property-editor.component.html', + styleUrls: ['./property-editor.component.css'] +}) +/** + * PropertyEditorComponent - display and edit selected items + */ +export class PropertyEditorComponent implements OnInit { + + private readonly editorService: ViewEditorService; + private readonly selectionService: SelectionService; + + private selectedObject: SelectionItem; + + constructor( selectionService: SelectionService, + editorService: ViewEditorService ) { + this.selectionService = selectionService; + this.editorService = editorService; + this.editorService.setEditorVirtualization( selectionService.getSelectedVirtualization() ); + } + + public ngOnInit(): void { + // Nothing to do + } + + /** + * Determine whether the editor has a view currently selected + * + * @return {boolean} 'true' if has a view selection + */ + public get hasSelectedView(): boolean { + const selView = this.editorService.getEditorView(); + return (selView && selView !== null); + } + + /** + * Determine if the first selection item is Source type + * @return {boolean} 'true' if the first item in the list is a 'Source' + */ + public get firstSelectionIsSource(): boolean { + const selectedItem = this.getFirstSelection(); + return selectedItem.getSelectionType() === SelectionType.SOURCE; + } + + /** + * Determine if the first selection item is Composition type + * @return {boolean} 'true' if the first item in the list is a 'Composition' + */ + public get firstSelectionIsComposition(): boolean { + const selectedItem = this.getFirstSelection(); + return selectedItem.getSelectionType() === SelectionType.COMPOSITION; + } + + /** + * Get the number of selected items + * @return {number} the number of selected items + */ + public get numberSelectedItems(): number { + const selections = this.editorService.getSelection(); + if (selections) { + return selections.length; + } + return 0; + } + + /** + * Get the first item in the selections + * @return {SelectionItem} the first item in the selection list + */ + public getFirstSelection(): SelectionItem { + const selectedObj = new SelectionItem(this.editorService); + const selections = this.editorService.getSelection(); + if (selections && selections.length > 0) { + selectedObj.setSelection(selections[0]); + } + return selectedObj; + } + +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts new file mode 100644 index 00000000..0528e2d7 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts @@ -0,0 +1,91 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; +import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; +import { Composition } from "@dataservices/shared/composition.model"; +import { PathUtils } from "@dataservices/shared/path-utils"; +import { SelectionType } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum"; + +/** + * SelectionItem model - interprets the selection string and provides the payload in object form + */ +export class SelectionItem { + + private editorService: ViewEditorService; + private selectionType = SelectionType.UNKNOWN; + private srcPath = ""; + private comp: Composition; + + constructor(editorService: ViewEditorService) { + this.editorService = editorService; + } + + /** + * Set the selection string + * @param {string} selection the selection + */ + public setSelection( selection: string ): void { + if ( !selection || selection === null ) return; + + const commandType = this.editorService.getSelectionCommandType(selection); + const payload = this.editorService.getSelectionPayload(selection); + + if ( commandType === CommandType.ADD_SOURCES_COMMAND ) { + this.selectionType = SelectionType.SOURCE; + this.srcPath = payload; + } else if ( commandType === CommandType.ADD_COMPOSITION_COMMAND ) { + this.selectionType = SelectionType.COMPOSITION; + this.comp = Composition.create(JSON.parse(payload)); + } else { + this.selectionType = SelectionType.UNKNOWN; + } + } + + /** + * Get the type of selection + * @return {SelectionType} the selection type + */ + public getSelectionType(): SelectionType { + return this.selectionType; + } + + /** + * Get the source connection name + * @return {string} the source connection name + */ + public getSourceConnectionName(): string { + return PathUtils.getConnectionName(this.srcPath); + } + + /** + * Get the source name + * @return {string} the source name + */ + public getSourceName(): string { + return PathUtils.getSourceName(this.srcPath); + } + + /** + * Get the composition + * @return {Composition} the composition + */ + public getComposition(): Composition { + return this.comp; + } + +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts new file mode 100644 index 00000000..3aac347e --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Enumeration for property editor item types + */ +export enum SelectionType { + + /** + * Source type + */ + SOURCE = "Source", + + /** + * Composition type + */ + COMPOSITION = "Composition", + + /** + * Unknown type + */ + UNKNOWN = "Unknown" + +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css index 0d7cf1b8..ec7ccda2 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css @@ -2,7 +2,6 @@ * The editor views tabset. */ #property-editors-tabs .tab-content { - border: 1px solid lightgray; } /* diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html index a94b3df6..dfda4806 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html @@ -4,15 +4,16 @@ (deselect)="tabSelected(tabs[0], false)"> - View + {{propertiesTabName}} + - {{columnPropsTabName}} + {{columnsTabName}} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts index dc02c4ad..53ed76bd 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts @@ -13,6 +13,7 @@ import { NotifierService } from "@dataservices/shared/notifier.service"; import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { SelectionService } from "@core/selection.service"; +import { PropertyEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component"; describe('ViewPropertyEditorsComponent', () => { let component: ViewPropertyEditorsComponent; @@ -24,7 +25,7 @@ describe('ViewPropertyEditorsComponent', () => { HttpModule, TabsModule.forRoot() ], - declarations: [ ViewPropertyEditorsComponent ], + declarations: [ PropertyEditorComponent, ViewPropertyEditorsComponent ], providers: [ { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts index 564378f2..c4a0a45d 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts @@ -32,7 +32,8 @@ import 'dragula/dist/dragula.css'; }) export class ViewPropertyEditorsComponent implements OnInit, OnDestroy { - public readonly columnPropsTabName = ViewEditorI18n.columnPropsTabName; + public readonly columnsTabName = ViewEditorI18n.columnsTabName; + public readonly propertiesTabName = ViewEditorI18n.propertiesTabName; private columnEditorIsEnabled = true; private readonly editorService: ViewEditorService; @@ -40,7 +41,7 @@ export class ViewPropertyEditorsComponent implements OnInit, OnDestroy { private subscription: Subscription; private viewEditorIsEnabled = true; - private readonly viewIndex = 0; + private readonly propertyIndex = 0; private readonly columnIndex = 1; /** @@ -48,10 +49,10 @@ export class ViewPropertyEditorsComponent implements OnInit, OnDestroy { */ public tabs = [ { - "active": true // preview + "active": true // properties }, { - "active": false // message log + "active": false // columns }, ]; @@ -68,16 +69,10 @@ export class ViewPropertyEditorsComponent implements OnInit, OnDestroy { this.logger.debug( "ViewPropertyEditorsComponent received event: " + event.toString() ); if ( event.typeIsCanvasSelectionChanged() ) { - // TODO set this.viewEditorIsEnabled to true if all canvas selections are views - // TODO set this.columnEditorIsEnabled to true if all canvas selections are columns - if ( event.args.length !== 0 ) { - if ( event.args[ 0 ] === ViewEditorPart.COLUMNS ) { - this.tabs[ this.viewIndex ].active = false; - this.tabs[ this.columnIndex ].active = true; - } else if ( event.args[ 0 ] === ViewEditorPart.PROPERTIES) { - this.tabs[ this.viewIndex ].active = false; - this.tabs[ this.columnIndex ].active = true; - } + // if single item is selected, show the properties tab + if ( event.args.length === 1 ) { + this.tabs[ this.propertyIndex ].active = true; + this.tabs[ this.columnIndex ].active = false; } } } @@ -113,4 +108,12 @@ export class ViewPropertyEditorsComponent implements OnInit, OnDestroy { tab.active = selected; } + public get numberSelectedItems(): number { + const selections = this.editorService.getSelection(); + if (selections) { + return selections.length; + } + return 0; + } + } From 125a6f36fb7df4f9489c3edeeeaec90b10470582 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 5 Oct 2018 16:52:21 -0500 Subject: [PATCH 197/205] TTOOLS-465 Addition of projected columns editor --- .../create-views-dialog.component.spec.ts | 1 - .../create-views-dialog.component.ts | 1 - .../app/dataservices/dataservices.module.ts | 4 +- .../dataservices/shared/composition.model.ts | 10 +- .../shared/mock-dataservice.service.ts | 10 +- .../shared/projected-column.model.spec.ts | 38 +++ .../shared/projected-column.model.ts | 91 +++++++ .../shared/view-definition.model.spec.ts | 127 ++++++++-- .../shared/view-definition.model.ts | 144 ++++++++++- .../view-editor/command/command-factory.ts | 31 ++- .../view-editor/command/command-type.enum.ts | 7 +- .../update-projected-columns-command.ts | 134 ++++++++++ .../view-editor/event/view-editor-event.ts | 8 + .../view-canvas/view-canvas.component.spec.ts | 2 + .../view-editor/view-editor-i18n.ts | 1 + .../view-editor/view-editor-part.enum.ts | 6 +- .../view-editor/view-editor.component.ts | 5 +- .../view-editor/view-editor.service.ts | 45 +++- .../projected-columns-editor.component.css | 13 + .../projected-columns-editor.component.html | 22 ++ ...projected-columns-editor.component.spec.ts | 50 ++++ .../projected-columns-editor.component.ts | 228 ++++++++++++++++++ .../view-property-editors.component.html | 1 + .../view-property-editors.component.spec.ts | 5 +- .../view-property-editors.component.ts | 1 - ngapp/src/app/shared/test-data.service.ts | 205 +++++++++++++++- 26 files changed, 1126 insertions(+), 64 deletions(-) create mode 100644 ngapp/src/app/dataservices/shared/projected-column.model.spec.ts create mode 100644 ngapp/src/app/dataservices/shared/projected-column.model.ts create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts index 8b33059e..88699bd0 100644 --- a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts @@ -1,7 +1,6 @@ import { async, ComponentFixture, TestBed } from "@angular/core/testing"; import { CreateViewsDialogComponent } from "./create-views-dialog.component"; -import { ConnectionTreeSelectorComponent } from "@dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component"; import { HttpModule } from "@angular/http"; import { ActionModule, diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts index ca2b606c..6ba9e649 100644 --- a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts +++ b/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts @@ -10,7 +10,6 @@ import { EmptyStateConfig, ListConfig, ListEvent, - NgxDataTableConfig, NotificationType, TableConfig } from "patternfly-ng"; diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index c0ef900d..ffde9b36 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -76,6 +76,7 @@ import { CreateViewDialogComponent } from './virtualization/view-editor/create-v import { CreateViewsDialogComponent } from './create-views-dialog/create-views-dialog.component'; import { SetDescriptionDialogComponent } from "@dataservices/set-description-dialog/set-description-dialog.component"; import { PropertyEditorComponent } from './virtualization/view-editor/view-property-editors/property-editor/property-editor.component'; +import { ProjectedColumnsEditorComponent } from './virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component'; @NgModule({ imports: [ @@ -131,7 +132,8 @@ import { PropertyEditorComponent } from './virtualization/view-editor/view-prope CreateViewDialogComponent, CreateViewsDialogComponent, SetDescriptionDialogComponent, - PropertyEditorComponent + PropertyEditorComponent, + ProjectedColumnsEditorComponent ], providers: [ { diff --git a/ngapp/src/app/dataservices/shared/composition.model.ts b/ngapp/src/app/dataservices/shared/composition.model.ts index cb844dd2..5fae2323 100644 --- a/ngapp/src/app/dataservices/shared/composition.model.ts +++ b/ngapp/src/app/dataservices/shared/composition.model.ts @@ -93,20 +93,14 @@ export class Composition { * @return {boolean} 'true' if initial source is set and on the left */ public get initialSourceOnLeft(): boolean { - if (this.initialSourcePath !== null && this.leftSourcePath !== null && this.initialSourcePath === this.leftSourcePath) { - return true; - } - return false; + return this.initialSourcePath !== null && this.leftSourcePath !== null && this.initialSourcePath === this.leftSourcePath; } /** * @return {boolean} 'true' if initial source is set and on the right */ public get initialSourceOnRight(): boolean { - if (this.initialSourcePath !== null && this.rightSourcePath !== null && this.initialSourcePath === this.rightSourcePath) { - return true; - } - return false; + return this.initialSourcePath !== null && this.rightSourcePath !== null && this.initialSourcePath === this.rightSourcePath; } /** diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts index b27a52e3..0cc4f337 100644 --- a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts +++ b/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts @@ -33,8 +33,6 @@ import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; import { ErrorObservable } from "rxjs/observable/ErrorObservable"; import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; -import { environment } from "@environments/environment"; -import { DataservicesConstants } from "@dataservices/shared/dataservices-constants"; @Injectable() export class MockDataserviceService extends DataserviceService { @@ -151,10 +149,10 @@ export class MockDataserviceService extends DataserviceService { } /** - * @param {ViewEditorState} editorState the view editor state + * @param {ViewEditorState[]} editorStates the view editor state array * @returns {Observable} `true` if the editor state was successfully saved */ - public saveViewEditorState( editorState: ViewEditorState ): Observable< boolean > { + public saveViewEditorStates( editorStates: ViewEditorState[] ): Observable< boolean > { return Observable.of(true); } @@ -199,11 +197,11 @@ export class MockDataserviceService extends DataserviceService { } /** - * @param {ViewEditorState} editorState the view editor state + * @param {ViewEditorState[]} editorStates the view editor state array * @param {string} dataserviceName the name of the dataservice * @returns {Observable} `true` if the editor state was successfully saved */ - public saveViewEditorStateRefreshViews( editorState: ViewEditorState, dataserviceName: string ): Observable< boolean > { + public saveViewEditorStatesRefreshViews( editorStates: ViewEditorState[], dataserviceName: string ): Observable< boolean > { return Observable.of(true); } diff --git a/ngapp/src/app/dataservices/shared/projected-column.model.spec.ts b/ngapp/src/app/dataservices/shared/projected-column.model.spec.ts new file mode 100644 index 00000000..51471a60 --- /dev/null +++ b/ngapp/src/app/dataservices/shared/projected-column.model.spec.ts @@ -0,0 +1,38 @@ +import { ProjectedColumn } from "@dataservices/shared/projected-column.model"; + +describe("ProjectedColumn", () => { + let projCol1: ProjectedColumn; + let projCol2: ProjectedColumn; + + beforeEach(() => { + projCol1 = null; + projCol2 = null; + }); + + it("should create", () => { + console.log("========== [ProjectedColumn] should create"); + projCol1 = ProjectedColumn.create( + { + "name": "colName1", + "type": "string", + "selected": true + } + ); + projCol2 = ProjectedColumn.create( + { + "name": "colName2", + "type": "integer", + "selected": false + } + ); + + expect(projCol1.getName()).toEqual("colName1"); + expect(projCol1.getType()).toEqual("string"); + expect(projCol1.selected).toEqual(true); + + expect(projCol2.getName()).toEqual("colName2"); + expect(projCol2.getType()).toEqual("integer"); + expect(projCol2.selected).toEqual(false); + }); + +}); diff --git a/ngapp/src/app/dataservices/shared/projected-column.model.ts b/ngapp/src/app/dataservices/shared/projected-column.model.ts new file mode 100644 index 00000000..50e81e8b --- /dev/null +++ b/ngapp/src/app/dataservices/shared/projected-column.model.ts @@ -0,0 +1,91 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * ProjectedColumn model - to hold the column info for projected view columns + */ +export class ProjectedColumn { + + private name: string; + private type: string; + public selected = false; + + /** + * @param {Object} json the JSON representation of ProjectedColumn + * @returns {ProjectedColumn} the new ProjectedColumn (never null) + */ + public static create( json: object = {} ): ProjectedColumn { + const projCol = new ProjectedColumn(); + for (const field of Object.keys(json)) { + if (field === "name") { + projCol.setName(json[field]); + } else if (field === "type") { + projCol.setType(json[field]); + } else if (field === "selected") { + projCol.selected = json[field]; + } + } + return projCol; + } + + constructor() { + // nothing to do + } + + /** + * @returns {string} the column name + */ + public getName(): string { + return this.name; + } + + /** + * @param {string} name the column name + */ + public setName( name?: string ): void { + this.name = name ? name : null; + } + + /** + * @returns {string} the column type + */ + public getType(): string { + return this.type; + } + + /** + * @param {string} type the column type + */ + public setType( type?: string ): void { + this.type = type ? type : ""; + } + + /** + * Determine if the supplied ProjectedColumn is equal to this + * @param {ProjectedColumn} otherCol the other column + */ + public isEqual( otherCol: ProjectedColumn ): boolean { + let equal = false; + if (this.getName() === otherCol.getName() && + this.getType() === otherCol.getType() && + this.selected === otherCol.selected ) { + equal = true; + } + return equal; + } + +} diff --git a/ngapp/src/app/dataservices/shared/view-definition.model.spec.ts b/ngapp/src/app/dataservices/shared/view-definition.model.spec.ts index 098e472d..ae859ca4 100644 --- a/ngapp/src/app/dataservices/shared/view-definition.model.spec.ts +++ b/ngapp/src/app/dataservices/shared/view-definition.model.spec.ts @@ -3,53 +3,136 @@ import { CompositionOperator } from "@dataservices/shared/composition-operator.e import { CompositionType } from "@dataservices/shared/composition-type.enum"; describe("ViewDefinition", () => { - let viewDefn: ViewDefinition; + let viewDefn1: ViewDefinition; + let viewDefn2: ViewDefinition; beforeEach(() => { - viewDefn = null; + viewDefn1 = null; + viewDefn2 = null; }); it("should create", () => { console.log("========== [ViewDefinition] should create"); - viewDefn = ViewDefinition.create( + viewDefn1 = ViewDefinition.create( { "viewName": "viewDefnName", "keng__description": "viewDescription", "isComplete": true, "sourcePaths": [ - "sourcePath1", - "sourcePath2" + "connection=pgConn/schema=public/table=account", + "connection=pgConn/schema=public/table=holdings" ], "compositions": [ { "name": "compositionName", - "leftSourcePath": "sourcePath1", - "rightSourcePath": "sourcePath2", + "leftSourcePath": "connection=pgConn/schema=public/table=account", + "rightSourcePath": "connection=pgConn/schema=public/table=holdings", "leftCriteriaColumn": "leftCriteriaCol", "rightCriteriaColumn": "rightCriteriaCol", "type": "INNER_JOIN", "operator": "EQ" } - ] + ], + "projectedColumns": [ + { + "name": "ALL", + "type": "ALL", + "selected": true + } + ] } ); - expect(viewDefn.getName()).toEqual("viewDefnName"); - expect(viewDefn.getDescription()).toEqual("viewDescription"); - expect(viewDefn.complete).toEqual(true); - expect(viewDefn.getSourcePaths().length).toEqual(2); - expect(viewDefn.getSourcePaths()[0]).toEqual("sourcePath1"); - expect(viewDefn.getSourcePaths()[1]).toEqual("sourcePath2"); - expect(viewDefn.getCompositions().length).toEqual(1); - expect(viewDefn.getCompositions()[0].getName()).toEqual("compositionName"); - expect(viewDefn.getCompositions()[0].getLeftSourcePath()).toEqual("sourcePath1"); - expect(viewDefn.getCompositions()[0].getRightSourcePath()).toEqual("sourcePath2"); - expect(viewDefn.getCompositions()[0].getLeftCriteriaColumn()).toEqual("leftCriteriaCol"); - expect(viewDefn.getCompositions()[0].getRightCriteriaColumn()).toEqual("rightCriteriaCol"); - expect(viewDefn.getCompositions()[0].getType()).toEqual(CompositionType.INNER_JOIN); - expect(viewDefn.getCompositions()[0].getOperator()).toEqual(CompositionOperator.EQ); + viewDefn2 = ViewDefinition.create( + { + "viewName": "viewDefnName", + "keng__description": "viewDescription", + "isComplete": true, + "sourcePaths": + [ + "connection=pgConn/schema=public/table=account", + "connection=pgConn/schema=public/table=holdings" + ], + "compositions": + [ + { + "name": "compositionName", + "leftSourcePath": "connection=pgConn/schema=public/table=account", + "rightSourcePath": "connection=pgConn/schema=public/table=holdings", + "leftCriteriaColumn": "leftCriteriaCol", + "rightCriteriaColumn": "rightCriteriaCol", + "type": "INNER_JOIN", + "operator": "EQ" + } + ], + "projectedColumns": [ + { + "name": "col1", + "type": "string", + "selected": true + }, + { + "name": "col2", + "type": "integer", + "selected": false + }, + { + "name": "col3", + "type": "string", + "selected": true + } + ] + } + ); + + expect(viewDefn1.getName()).toEqual("viewDefnName"); + expect(viewDefn1.getDescription()).toEqual("viewDescription"); + expect(viewDefn1.complete).toEqual(true); + expect(viewDefn1.getSourcePaths().length).toEqual(2); + expect(viewDefn1.getSourcePaths()[0]).toEqual("connection=pgConn/schema=public/table=account"); + expect(viewDefn1.getSourcePaths()[1]).toEqual("connection=pgConn/schema=public/table=holdings"); + expect(viewDefn1.getCompositions().length).toEqual(1); + expect(viewDefn1.getCompositions()[0].getName()).toEqual("compositionName"); + expect(viewDefn1.getCompositions()[0].getLeftSourcePath()).toEqual("connection=pgConn/schema=public/table=account"); + expect(viewDefn1.getCompositions()[0].getRightSourcePath()).toEqual("connection=pgConn/schema=public/table=holdings"); + expect(viewDefn1.getCompositions()[0].getLeftCriteriaColumn()).toEqual("leftCriteriaCol"); + expect(viewDefn1.getCompositions()[0].getRightCriteriaColumn()).toEqual("rightCriteriaCol"); + expect(viewDefn1.getCompositions()[0].getType()).toEqual(CompositionType.INNER_JOIN); + expect(viewDefn1.getCompositions()[0].getOperator()).toEqual(CompositionOperator.EQ); + expect(viewDefn1.getProjectedColumns().length).toEqual(1); + expect(viewDefn1.getProjectedColumns()[0].getName()).toEqual("ALL"); + expect(viewDefn1.getProjectedColumns()[0].getType()).toEqual("ALL"); + expect(viewDefn1.getProjectedColumns()[0].selected).toEqual(true); + expect(viewDefn1.getPreviewSql()).toEqual("SELECT * FROM pgconnschemamodel.account AS A INNER JOIN pgconnschemamodel.holdings AS B ON A.leftCriteriaCol = B.rightCriteriaCol;"); + + expect(viewDefn2.getName()).toEqual("viewDefnName"); + expect(viewDefn2.getDescription()).toEqual("viewDescription"); + expect(viewDefn2.complete).toEqual(true); + expect(viewDefn2.getSourcePaths().length).toEqual(2); + expect(viewDefn2.getSourcePaths()[0]).toEqual("connection=pgConn/schema=public/table=account"); + expect(viewDefn2.getSourcePaths()[1]).toEqual("connection=pgConn/schema=public/table=holdings"); + expect(viewDefn2.getCompositions().length).toEqual(1); + expect(viewDefn2.getCompositions()[0].getName()).toEqual("compositionName"); + expect(viewDefn2.getCompositions()[0].getLeftSourcePath()).toEqual("connection=pgConn/schema=public/table=account"); + expect(viewDefn2.getCompositions()[0].getRightSourcePath()).toEqual("connection=pgConn/schema=public/table=holdings"); + expect(viewDefn2.getCompositions()[0].getLeftCriteriaColumn()).toEqual("leftCriteriaCol"); + expect(viewDefn2.getCompositions()[0].getRightCriteriaColumn()).toEqual("rightCriteriaCol"); + expect(viewDefn2.getCompositions()[0].getType()).toEqual(CompositionType.INNER_JOIN); + expect(viewDefn2.getCompositions()[0].getOperator()).toEqual(CompositionOperator.EQ); + expect(viewDefn2.getProjectedColumns().length).toEqual(3); + expect(viewDefn2.getProjectedColumns()[0].getName()).toEqual("col1"); + expect(viewDefn2.getProjectedColumns()[0].getType()).toEqual("string"); + expect(viewDefn2.getProjectedColumns()[0].selected).toEqual(true); + expect(viewDefn2.getProjectedColumns()[1].getName()).toEqual("col2"); + expect(viewDefn2.getProjectedColumns()[1].getType()).toEqual("integer"); + expect(viewDefn2.getProjectedColumns()[1].selected).toEqual(false); + expect(viewDefn2.getProjectedColumns()[2].getName()).toEqual("col3"); + expect(viewDefn2.getProjectedColumns()[2].getType()).toEqual("string"); + expect(viewDefn2.getProjectedColumns()[2].selected).toEqual(true); + expect(viewDefn2.getPreviewSql()).toEqual("SELECT col1, col3 FROM pgconnschemamodel.account AS A INNER JOIN pgconnschemamodel.holdings AS B ON A.leftCriteriaCol = B.rightCriteriaCol;"); + }); }); diff --git a/ngapp/src/app/dataservices/shared/view-definition.model.ts b/ngapp/src/app/dataservices/shared/view-definition.model.ts index 1a4ee3c4..04fe7803 100644 --- a/ngapp/src/app/dataservices/shared/view-definition.model.ts +++ b/ngapp/src/app/dataservices/shared/view-definition.model.ts @@ -20,6 +20,8 @@ import { PathUtils } from "@dataservices/shared/path-utils"; import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { CompositionOperator } from "@dataservices/shared/composition-operator.enum"; import { CompositionType } from "@dataservices/shared/composition-type.enum"; +import { ProjectedColumn } from "@dataservices/shared/projected-column.model"; +import {select} from "d3-selection"; /** * ViewDefinition model @@ -31,6 +33,7 @@ export class ViewDefinition { private sourcePaths: string[] = []; private compositions: Composition[] = []; private isSelected = false; + private projectedColumns: ProjectedColumn[] = []; /** * @param {Object} json the JSON representation of a ViewDefinition @@ -59,13 +62,34 @@ export class ViewDefinition { viewDefn.addComposition(comp); } } + } else if (field === "projectedColumns") { + const arrayElems = json[field]; + const cols: ProjectedColumn[] = []; + for (const arrayElem of arrayElems) { + const compStr = JSON.stringify(arrayElem); + if (compStr.length > 2) { + const col = ProjectedColumn.create(arrayElem); + cols.push(col); + } + } + viewDefn.setProjectedColumns(cols); } } return viewDefn; } + /** + * Constructor + */ constructor() { - // nothing to do + // The ViewDefinition is initialized with 'SELECT *' + const prjCols: ProjectedColumn[] = []; + const selectStar: ProjectedColumn = new ProjectedColumn(); + selectStar.setName("ALL"); + selectStar.setType("ALL"); + selectStar.selected = true; + prjCols.push(selectStar); + this.setProjectedColumns(prjCols); } /** @@ -124,6 +148,34 @@ export class ViewDefinition { this.compositions = compositions; } + /** + * @returns {ProjectedColumn[]} the view projected columns + */ + public getProjectedColumns(): ProjectedColumn[] { + return this.projectedColumns; + } + + /** + * @param {ProjectedColumns} projColumns the projected columns + */ + public setProjectedColumns( projColumns: ProjectedColumn[] ): void { + this.projectedColumns = projColumns; + } + + /** + * Get the projected columns that are currently selected + * @returns {ProjectedColumn[]} the view selected projected columns + */ + public getSelectedProjectedColumns(): ProjectedColumn[] { + const selectedProjCols: ProjectedColumn[] = []; + for (const projCol of this.getProjectedColumns()) { + if (projCol.selected) { + selectedProjCols.push(projCol); + } + } + return selectedProjCols; + } + /** * Add Composition to the View * @@ -289,11 +341,12 @@ export class ViewDefinition { // TODO: This method currently handles single source views, and single join views // Will need to expand capabilites in the future - as more complex joins are supported. - // The preview SQL is only generated if the view is complete + // If source path is supplied, return the source SQL if ( sourcePath != null ) { const tableName = this.getPreviewTableName(sourcePath); return "SELECT * FROM " + tableName + ";"; } + // The preview SQL for the view is only generated if the view is complete if ( this.complete ) { // Join View @@ -305,20 +358,84 @@ export class ViewDefinition { const rightCriteriaColName = composition.getRightCriteriaColumn(); const criteriaOperator = CompositionOperator.toSql(composition.getOperator()); const joinType = CompositionType.toSql(composition.getType()); - return "SELECT * FROM " + leftTable + " AS A " + joinType + " " + + const projColsSql = this.getProjectedColumnsSql(); + return "SELECT " + projColsSql + " FROM " + leftTable + " AS A " + joinType + " " + rightTable + " AS B ON " + "A." + leftCriteriaColName + " " + criteriaOperator + " " + "B." + rightCriteriaColName + ";"; // Single Source View } else { const tableName = this.getPreviewTableName(this.getSourcePaths()[0]); - return "SELECT * FROM " + tableName + ";"; + const projColsSql = this.getProjectedColumnsSql(); + return "SELECT " + projColsSql + " FROM " + tableName + ";"; } } return ""; } + /** + * Determine if the current projected columns is '*' + * @return {boolean} 'true' if select all + */ + public isProjectAllColumns(): boolean { + return this.getProjectedColumns().length === 1 && this.getProjectedColumns()[0].getName() === "ALL" && this.getProjectedColumns()[0].getType() === "ALL"; + } + + /** + * Get the SQL string for the current projected columns + * @return {string} the projected columns SQL + */ + private getProjectedColumnsSql(): string { + // TODO: This function will need more work as the ViewDefinition is refined (addition of aliases, etc) + const finalColumnNames: string[] = []; + const duplicateNames: string[] = []; + let sql = ""; + // Loop thru columns - create list and tag any duplicates + const selectedCols = this.getSelectedProjectedColumns(); + for ( let i = 0; i < selectedCols.length; i++ ) { + const col = selectedCols[i]; + const colName = this.getSqlColumnName(col); + // If column is a duplicate, flag it as such. Leave out of final list + if (finalColumnNames.indexOf(colName) !== -1) { + duplicateNames.push(colName); + } else { + finalColumnNames.push(colName); + } + } + + // Build the sql from the final list + for ( let j = 0; j < finalColumnNames.length; j++ ) { + // If column was a duplicate, qualify it as left table + const cName = finalColumnNames[j]; + if ( duplicateNames.indexOf(cName) !== -1 ) { + sql = sql.concat("A." + cName); + } else { + sql = sql.concat(cName); + } + if ( j < finalColumnNames.length - 1 ) { + sql = sql.concat(", "); + } + } + return sql; + } + + /** + * Get the name of the supplied column + * @param col the column + * @return {string} the column sql name + */ + private getSqlColumnName(col: ProjectedColumn): string { + if (col && col !== null) { + if (col.getName() === "ALL" && col.getType() === "ALL") { + return "*"; + } else { + return col.getName(); + } + } + return ""; + } + /** * Generates the table name for the preview query, given the source path * @param {string} sourcePath the path for the view source @@ -358,7 +475,8 @@ export class ViewDefinition { if (this.getName() === otherView.getName() && this.getDescription() === otherView.getDescription() && this.pathsEqual(this.getSourcePaths(), otherView.getSourcePaths()) && - this.compositionsEqual(this.getCompositions(), otherView.getCompositions()) ) { + this.compositionsEqual(this.getCompositions(), otherView.getCompositions()) && + this.projectedColumnsEqual(this.getProjectedColumns(), otherView.getProjectedColumns()) ) { equal = true; } return equal; @@ -390,6 +508,19 @@ export class ViewDefinition { return true; } + private projectedColumnsEqual(left: ProjectedColumn[], right: ProjectedColumn[]): boolean { + if (left === right) return true; + if (left == null || right == null) return false; + if (left.length !== right.length) return false; + + left.sort(); + right.sort(); + for (let i = 0; i < right.length; ++i) { + if (!left[i].isEqual(right[i])) return false; + } + return true; + } + /** * Set all object values using the supplied ViewDefinition json * @param {Object} values @@ -407,7 +538,8 @@ export class ViewDefinition { keng__description: this.keng__description, isComplete: this.complete, sourcePaths: this.sourcePaths, - compositions: this.compositions + compositions: this.compositions, + projectedColumns: this.projectedColumns }; } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/command-factory.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/command-factory.ts index 52e0b76b..7f07dc07 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/command-factory.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/command-factory.ts @@ -26,6 +26,7 @@ import { NoOpCommand } from "@dataservices/virtualization/view-editor/command/no import { Undoable } from "@dataservices/virtualization/view-editor/command/undo-redo/undoable"; import { Composition } from "@dataservices/shared/composition.model"; import { RemoveCompositionCommand } from "@dataservices/virtualization/view-editor/command/remove-composition-command"; +import { UpdateProjectedColumnsCommand } from "@dataservices/virtualization/view-editor/command/update-projected-columns-command"; export class CommandFactory { @@ -133,7 +134,11 @@ export class CommandFactory { } case UpdateViewNameCommand.id: { return CommandFactory.createUpdateViewNameCommand( cmd.getArg( UpdateViewNameCommand.oldName ), - cmd.getArg( UpdateViewNameCommand.newName ) ); + cmd.getArg( UpdateViewNameCommand.newName ) ); + } + case UpdateProjectedColumnsCommand.id: { + return CommandFactory.createUpdateProjectedColumnsCommand( cmd.getArg( UpdateProjectedColumnsCommand.oldProjectedColumns ), + cmd.getArg( UpdateProjectedColumnsCommand.newProjectedColumns ) ); } default: { return new Error( "The '" + cmd.id + "' command does not have an undo command" ); @@ -177,6 +182,20 @@ export class CommandFactory { return new Error( "Must have either a new name or an old name when creating an UpdateViewNameCommand" ); } + /** + * @param {string | ProjectedColumns} newProjColumns the stringified representation of or the new projected columns + * @param {string | ProjectedColumns} oldProjColumns the stringified representation of or the old projected columns + * @returns {Command} the update projected columns command or a no op command if args are not supplied + */ + public static createUpdateProjectedColumnsCommand( newProjColumns: string, + oldProjColumns: string ): Command { + if ( !newProjColumns || newProjColumns === null || !oldProjColumns || oldProjColumns === null ) { + return NoOpCommand.NO_OP; + } + + return new UpdateProjectedColumnsCommand( newProjColumns, oldProjColumns ); + } + /** * Constructs a command object from JSON. * @@ -246,6 +265,16 @@ export class CommandFactory { return new Error( "Unable to decode UpdateViewNameCommand: " + json ); } + case UpdateProjectedColumnsCommand.id: { + const newProjectedCols = args[ UpdateProjectedColumnsCommand.newProjectedColumns ]; + const replacedProjectedCols = args[ UpdateProjectedColumnsCommand.oldProjectedColumns ]; + + if ( newProjectedCols || replacedProjectedCols ) { + return CommandFactory.createUpdateProjectedColumnsCommand( newProjectedCols, replacedProjectedCols ); + } + + return new Error( "Unable to decode UpdateProjectedColumnsCommand: " + json ); + } default: { return new Error( "Unhandled command: " + cmdId ); } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts index 5c3b52dd..8a1ebbdc 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts @@ -53,6 +53,11 @@ export enum CommandType { /** * Command id for Add Composition */ - UPDATE_VIEW_NAME_COMMAND = "UpdateViewNameCommand" + UPDATE_VIEW_NAME_COMMAND = "UpdateViewNameCommand", + + /** + * Command id for Update Projected Columns + */ + UPDATE_PROJECTED_COLUMNS_COMMAND = "UpdateProjectedColumnsCommand" } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts b/ngapp/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts new file mode 100644 index 00000000..e9eb427c --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts @@ -0,0 +1,134 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { Command } from "@dataservices/virtualization/view-editor/command/command"; +import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; +import { ProjectedColumn } from "@dataservices/shared/projected-column.model"; + +export class UpdateProjectedColumnsCommand extends Command { + + /** + * The command identifier. + * + * @type {string} + */ + public static readonly id = CommandType.UPDATE_PROJECTED_COLUMNS_COMMAND; + + /** + * The name of the command argument whose value is the new projected columns of the view. + * + * @type {string} + */ + public static readonly newProjectedColumns = "newProjectedColumns"; + + /** + * The name of the command argument whose value is the replaced projected columns of the view. + * + * @type {string} + */ + public static readonly oldProjectedColumns = "oldProjectedColumns"; + + /** + * Constructor + * the specified ProjectedColumns must be a ProjectedColumns object -OR- stringified projected columns + * @param {string | ProjectedColumn[]} newProjectedColumns the new projected columns or stringified projected columns + * (cannot be `null` or empty) + * @param {string | ProjectedColumn[]} oldProjectedColumns the projected columns being replaced or stringified columns + * (cannot be `null` or empty) + * @param {string} id the command id. If not supplied, an id is generated. + */ + public constructor( newProjectedColumns: string | ProjectedColumn[], + oldProjectedColumns: string | ProjectedColumn[], id?: string) { + super( UpdateProjectedColumnsCommand.id, ViewEditorI18n.updateProjectedColumnsCommandName ); + + let newColsArg: string; + if ( typeof newProjectedColumns === 'string' ) { + newColsArg = newProjectedColumns as string; + } else { + newColsArg = JSON.stringify(newProjectedColumns); + } + this._args.set( UpdateProjectedColumnsCommand.newProjectedColumns, newColsArg ); + + let oldColsArg: string; + if ( typeof oldProjectedColumns === 'string' ) { + oldColsArg = oldProjectedColumns as string; + } else { + oldColsArg = JSON.stringify(oldProjectedColumns); + } + this._args.set( UpdateProjectedColumnsCommand.oldProjectedColumns, oldColsArg ); + + if (!id) { + // + // Generate new id + // + id = UpdateProjectedColumnsCommand.id + this.idGen; + } + + this._args.set( Command.identArg, id); + } + + /** + * @returns {ProjectedColumns} the new projected columns + */ + public getNewProjectedColumns(): ProjectedColumn[] { + const newColsStr = this.getArg( UpdateProjectedColumnsCommand.newProjectedColumns ) as string; + const newCols = JSON.parse(newColsStr); + const cols: ProjectedColumn[] = []; + for (const elem of newCols) { + const col: ProjectedColumn = ProjectedColumn.create(elem); + cols.push(col); + } + return cols; + } + + /** + * @returns {string} json payload for new projected columns + */ + public getNewProjecteColumnsPayload( ): string { + return this.getArg( UpdateProjectedColumnsCommand.newProjectedColumns ) as string; + } + + /** + * @returns {ProjectedColumn[]} the old projected columns + */ + public getOldProjectedColumns(): ProjectedColumn[] { + const oldColsStr = this.getArg( UpdateProjectedColumnsCommand.oldProjectedColumns ) as string; + const oldCols = JSON.parse(oldColsStr); + const cols: ProjectedColumn[] = []; + for (const elem of oldCols) { + const col: ProjectedColumn = ProjectedColumn.create(elem); + cols.push(col); + } + return cols; + } + + /** + * @returns {string} json payload for old projected columns + */ + public getOldProjecteColumnsPayload( ): string { + return this.getArg( UpdateProjectedColumnsCommand.oldProjectedColumns ) as string; + } + + /** + * @returns {string} a unique short identifier of this command + */ + public getId( ): string { + return this.getArg( Command.identArg ) as string; + } + +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts b/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts index 9ef93d8e..f541aab4 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts @@ -105,6 +105,13 @@ export class ViewEditorEvent { return this.source === ViewEditorPart.PROPERTIES; } + /** + * @returns {boolean} `true` if the projected columns editor part was the source of the event + */ + public sourceIsProjectedSymbols(): boolean { + return this.source === ViewEditorPart.PROJECTED_COLUMNS; + } + /** * @returns {string} a string representation of the event */ @@ -238,4 +245,5 @@ export class ViewEditorEvent { public typeIsDeleteNode(): boolean { return this.type === ViewEditorEventType.DELETE_NODE; } + } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts index e05f28f5..7ab84fb1 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts @@ -26,6 +26,7 @@ import { GraphVisualComponent, LinkVisualComponent, NodeVisualComponent } from " import { CanvasService } from "@dataservices/virtualization/view-editor/view-canvas/canvas.service"; import { SelectionService } from "@core/selection.service"; import { PropertyEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component"; +import { ProjectedColumnsEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component"; describe('ViewCanvasComponent', () => { let component: ViewCanvasComponent; @@ -50,6 +51,7 @@ describe('ViewCanvasComponent', () => { GraphVisualComponent, LinkVisualComponent, NodeVisualComponent, + ProjectedColumnsEditorComponent, PropertyEditorComponent, ViewCanvasComponent, ViewPropertyEditorsComponent diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts index 1994df2e..40ca54cd 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts @@ -32,6 +32,7 @@ export class ViewEditorI18n { public static readonly removeSourcesCommandName = "Remove Sources"; public static readonly updateViewNameCommandName = "Update View Name"; public static readonly updateViewDescriptionCommandName = "Update View Description"; + public static readonly updateProjectedColumnsCommandName = "Update Projected Columns"; // connection table dialog public static readonly connectionTableSelectionDialogMessage = "Expand connection and select a source for your view"; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts index 824829f3..e7ceff3e 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts @@ -43,13 +43,13 @@ export enum ViewEditorPart { PREVIEW = "PREVIEW", /** - * The source of the event is the properties part. + * The source of the event is the properties editor part. */ PROPERTIES = "PROPERTIES", /** - * The source of the event is the properties part. + * The source of the event is the projected columns editor part. */ - COLUMNS = "COLUMNS" + PROJECTED_COLUMNS = "PROJECTED_COLUMNS" } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts index 503d50ff..4f324715 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts @@ -731,10 +731,7 @@ export class ViewEditorComponent implements DoCheck, OnDestroy, OnInit { */ public get canvasSingleSourceSelected(): boolean { const selections = this.editorService.getSelection(); - if (selections && selections.length === 1) { - return true; - } - return false; + return selections && selections.length === 1; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts index 1fb35cb4..1fb28f30 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts @@ -44,6 +44,8 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { SelectionService } from "@core/selection.service"; import { CommandType } from "@dataservices/virtualization/view-editor/command/command-type.enum"; import { NoOpCommand } from "@dataservices/virtualization/view-editor/command/no-op-command"; +import { UpdateProjectedColumnsCommand } from "@dataservices/virtualization/view-editor/command/update-projected-columns-command"; +import { ProjectedColumn } from "@dataservices/shared/projected-column.model"; @Injectable() export class ViewEditorService { @@ -536,21 +538,31 @@ export class ViewEditorService { return; } let querySql = ""; + let isSelectAll = false; if ( sourcePath != null && !sourcePath.startsWith(AddCompositionCommand.id) ) { // Fetch new results for source table querySql = this._editorView.getPreviewSql(sourcePath); - } else { + // Determine if view is select * + if (this._editorView.isProjectAllColumns()) { + isSelectAll = true; + } // Fetch new results for view querySql = this._editorView.getPreviewSql(); - } + const self = this; // Resets all of the views in the service VDB this._vdbService.queryVdb(querySql, VdbsConstants.PREVIEW_VDB_NAME, 15, 0) .subscribe( (queryResult) => { - self.setPreviewResults(querySql, queryResult, ViewEditorPart.EDITOR); + // If view query was select *, auto expand it and save + if (isSelectAll) { + self.expandProjCols(queryResult); + } + else { + self.setPreviewResults(querySql, queryResult, ViewEditorPart.EDITOR); + } }, (error) => { this._logger.error( "[ViewEditorService.updatePreviewResults] - error getting results" ); @@ -558,6 +570,25 @@ export class ViewEditorService { ); } + /** + * Expand the views projected columns using the query result columns, then save the view + * @param queryResults the query results + */ + private expandProjCols(queryResults: QueryResults): void { + const resultCols = queryResults.getColumns(); + const projCols: ProjectedColumn[] = []; + for (const resultCol of resultCols) { + const projCol: ProjectedColumn = new ProjectedColumn(); + projCol.setName(resultCol.getName()); + projCol.setType(resultCol.getType()); + projCol.selected = true; + projCols.push(projCol); + } + this._editorView.setProjectedColumns(projCols); + // After expanding, reset the view + this.setEditorView(this._editorView, ViewEditorPart.HEADER); + } + /** * Sets the preview results. Fires a `ViewEditorEventType.PREVIEW_RESULTS_CHANGED` event having the results as an * argument. @@ -669,6 +700,12 @@ export class ViewEditorService { this.getEditorView().setName( cmd.getArg( UpdateViewNameCommand.newName ) ); break; } + case UpdateProjectedColumnsCommand.id: { + const updateProjColsCommand = cmd as UpdateProjectedColumnsCommand; + const newProjCols = updateProjColsCommand.getNewProjectedColumns(); + this.getEditorView().setProjectedColumns( newProjCols ); + break; + } default: { this._logger.error( "The '" + cmd.id + "' was not handled by updateViewState"); break; @@ -748,6 +785,8 @@ export class ViewEditorService { return UpdateViewDescriptionCommand.id; } else if ( argStr.startsWith(UpdateViewNameCommand.id) ) { return UpdateViewNameCommand.id; + } else if ( argStr.startsWith(UpdateProjectedColumnsCommand.id) ) { + return UpdateProjectedColumnsCommand.id; } } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css new file mode 100644 index 00000000..1ed7ad4d --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css @@ -0,0 +1,13 @@ +/* + * The container for the projected columns editor + */ +#projected-columns-editor-container { + height: 100%; + margin-left: 15px; +} + +.datatable-body-row.active .datatable-row-group { + /* background-color: #0088ce !important; */ + /* border-bottom-color: #00659c !important; */ + /* color: #fff; */ +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html new file mode 100644 index 00000000..9dc48718 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html @@ -0,0 +1,22 @@ +
    +
    +

    No View Selected

    +
    + +
    +

    View Columns

    + +
    +

    All columns included. Save the view to populate the specific columns

    +
    + +
    + + +
    +
    +
    diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts new file mode 100644 index 00000000..56a225c8 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts @@ -0,0 +1,50 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProjectedColumnsEditorComponent } from './projected-columns-editor.component'; +import { TableModule } from "patternfly-ng"; +import { LoggerService } from "@core/logger.service"; +import { SelectionService } from "@core/selection.service"; +import { AppSettingsService } from "@core/app-settings.service"; +import { MockAppSettingsService } from "@core/mock-app-settings.service"; +import { DataserviceService } from "@dataservices/shared/dataservice.service"; +import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; +import { NotifierService } from "@dataservices/shared/notifier.service"; +import { VdbService } from "@dataservices/shared/vdb.service"; +import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; +import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; +import { HttpModule } from "@angular/http"; + +describe('ProjectedColumnsEditorComponent', () => { + let component: ProjectedColumnsEditorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + HttpModule, + TableModule + ], + declarations: [ ProjectedColumnsEditorComponent ], + providers: [ + { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: DataserviceService, useClass: MockDataserviceService }, + LoggerService, + NotifierService, + SelectionService, + { provide: VdbService, useClass: MockVdbService }, + ViewEditorService + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ProjectedColumnsEditorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts new file mode 100644 index 00000000..261bbfb7 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts @@ -0,0 +1,228 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; +import { SelectionService } from "@core/selection.service"; +import { EmptyStateConfig, TableConfig, TableEvent } from "patternfly-ng"; +import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import { ProjectedColumn } from "@dataservices/shared/projected-column.model"; +import { CommandFactory } from "@dataservices/virtualization/view-editor/command/command-factory"; +import { Command } from "@dataservices/virtualization/view-editor/command/command"; +import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; +import { LoggerService } from "@core/logger.service"; +import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event"; +import { Subscription } from "rxjs/Subscription"; +import { UpdateProjectedColumnsCommand } from "@dataservices/virtualization/view-editor/command/update-projected-columns-command"; + +@Component({ + selector: 'app-projected-columns-editor', + templateUrl: './projected-columns-editor.component.html', + styleUrls: ['./projected-columns-editor.component.css'] +}) +export class ProjectedColumnsEditorComponent implements OnInit, OnDestroy { + + public tableColumns: any[] = []; + public tableConfig: TableConfig; + + private readonly editorService: ViewEditorService; + private readonly selectionService: SelectionService; + private readonly logger: LoggerService; + private editorSubscription: Subscription; + + private readonly emptyStateConfig: EmptyStateConfig; + public projectedColumns: ProjectedColumn[] = []; + private originalColumns: ProjectedColumn[] = []; + + constructor( selectionService: SelectionService, + logger: LoggerService, + editorService: ViewEditorService ) { + this.selectionService = selectionService; + this.editorService = editorService; + this.logger = logger; + + // ---------------------------------- + // View Table configurations + // ---------------------------------- + this.tableColumns = [ + { + draggable: false, + name: "Name", + prop: "name", + resizeable: true, + sortable: false, + width: "60" + }, + { + draggable: false, + name: "Type", + prop: "type", + resizeable: true, + sortable: false, + width: "60" + } + ]; + + this.emptyStateConfig = { + title: ViewEditorI18n.noViewsDisplayedMessage + } as EmptyStateConfig; + + this.tableConfig = { + showCheckbox: true, + emptyStateConfig: this.emptyStateConfig, + } as TableConfig; + + this.editorService.setEditorVirtualization( selectionService.getSelectedVirtualization() ); + } + + public ngOnInit(): void { + this.editorSubscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) ); + } + + /** + * Cleanup code when destroying the canvas and properties parts. + */ + public ngOnDestroy(): void { + this.editorSubscription.unsubscribe(); + } + + /** + * @param {ViewEditorEvent} event the event being processed + */ + public handleEditorEvent( event: ViewEditorEvent ): void { + this.logger.debug( "ProjectedColumnsEditor received event: " + event.toString() ); + + // Initialize the projected columns editor when the ViewDefinition is set + if ( event.typeIsEditedViewSet()) { + const viewDefn = this.editorService.getEditorView(); + this.initProjectedColumns(viewDefn.getProjectedColumns()); + } + else if (event.typeIsViewStateChanged()) { + // Reset project columns if change came from the editor + if ( event.sourceIsEditor() ) { + if ( event.args.length === 1 && event.args[ 0 ] instanceof Command ) { + const cmd = event.args[ 0 ] as Command; + + if ( cmd instanceof UpdateProjectedColumnsCommand ) { + this.updateProjectedColumns(cmd.getNewProjectedColumns()); + } + } + } + } + else { + this.logger.debug( "ProjectedColumnsEditor not handling received editor event: " + event.toString()); + } + } + + /** + * Initializes the projected columns + * @param {ProjectedColumn[]} prjCols the projected columns + */ + private initProjectedColumns(prjCols: ProjectedColumn[]): void { + this.projectedColumns = []; + this.originalColumns = []; + + // Clone view definition projected columns; save original state + const copyPrjCols: ProjectedColumn[] = []; + const copyOrigCols: ProjectedColumn[] = []; + if (prjCols && prjCols !== null) { + for (const pCol of prjCols) { + copyPrjCols.push(ProjectedColumn.create(pCol)); + copyOrigCols.push(ProjectedColumn.create(pCol)); + } + } + this.projectedColumns = copyPrjCols; + this.originalColumns = copyOrigCols; + + this.projectedColumns = [...this.projectedColumns]; + } + + /** + * Updates the projected columns + * @param {ProjectedColumn[]} prjCols the projected columns + */ + private updateProjectedColumns(prjCols: ProjectedColumn[]): void { + const copyPrjCols: ProjectedColumn[] = []; + const copyOrigCols: ProjectedColumn[] = []; + if (prjCols && prjCols !== null) { + for (const pCol of prjCols) { + copyPrjCols.push(ProjectedColumn.create(pCol)); + copyOrigCols.push(ProjectedColumn.create(pCol)); + } + } + this.originalColumns = copyOrigCols; + // Handle case where current columns are SELECT * + if (this.hasSelectAllProjectedColumns) { + // Incoming is also SELECT * - no need to do anything + if (this.isSelectStar(copyPrjCols)) { + return; + } + // Incoming is full column set. Need to remove current SELECT * + else { + this.projectedColumns = []; + for (const col of copyPrjCols) { + this.projectedColumns.push(col); + } + } + } + // Iterate existing columns, setting selection state + else { + for (const col of copyPrjCols) { + for (const projCol of this.projectedColumns) { + if (projCol.getName() === col.getName()) { + projCol.selected = col.selected; + break; + } + } + } + } + } + + /** + * Determine if a view has select all projected columns + * + * @return {boolean} 'true' if view has select all projected columns + */ + public get hasSelectAllProjectedColumns(): boolean { + return this.isSelectStar(this.projectedColumns); + } + + private isSelectStar(projCols: ProjectedColumn[]): boolean { + return projCols && projCols !== null && projCols.length === 1 && projCols[0].getName() === "ALL" && projCols[0].getType() === "ALL"; + } + + /** + * Determine whether the editor has a view currently selected + * + * @return {boolean} 'true' if has a view selection + */ + public get hasSelectedView(): boolean { + const selView = this.editorService.getEditorView(); + return (selView && selView !== null); + } + + /** + * Handles change in Column selections + * @param {TableEvent} $event the column selection event + */ + public handleColumnSelectionChange($event: TableEvent): void { + // Change in projected column selections fire change event + if (this.hasSelectedView) { + // Fire update event with new and old columns + const temp = CommandFactory.createUpdateProjectedColumnsCommand( JSON.stringify(this.projectedColumns), JSON.stringify(this.originalColumns) ); + if ( temp instanceof Command ) { + this.editorService.fireViewStateHasChanged( ViewEditorPart.PROJECTED_COLUMNS, temp as Command ); + } else { + const error = temp as Error; + this.logger.error( error.message ); + } + // Update the original columns + const origCols: ProjectedColumn[] = []; + for (const col of this.projectedColumns) { + origCols.push(ProjectedColumn.create(col)); + } + this.originalColumns = origCols; + } else { + // shouldn't get here as description text input should be disabled if no view being edited + this.logger.error( "Trying to set description but there is no view being edited" ); + } + } + +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html index dfda4806..e47785f7 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html @@ -15,5 +15,6 @@ {{columnsTabName}} + diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts index 53ed76bd..33cbe53f 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts @@ -14,6 +14,8 @@ import { DataserviceService } from "@dataservices/shared/dataservice.service"; import { MockDataserviceService } from "@dataservices/shared/mock-dataservice.service"; import { SelectionService } from "@core/selection.service"; import { PropertyEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component"; +import { ProjectedColumnsEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component"; +import { TableModule } from "patternfly-ng"; describe('ViewPropertyEditorsComponent', () => { let component: ViewPropertyEditorsComponent; @@ -23,9 +25,10 @@ describe('ViewPropertyEditorsComponent', () => { TestBed.configureTestingModule({ imports: [ HttpModule, + TableModule, TabsModule.forRoot() ], - declarations: [ PropertyEditorComponent, ViewPropertyEditorsComponent ], + declarations: [ ProjectedColumnsEditorComponent, PropertyEditorComponent, ViewPropertyEditorsComponent ], providers: [ { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts index c4a0a45d..472257c6 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts @@ -18,7 +18,6 @@ import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { LoggerService } from "@core/logger.service"; import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; -import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event"; import { Subscription } from "rxjs/Subscription"; diff --git a/ngapp/src/app/shared/test-data.service.ts b/ngapp/src/app/shared/test-data.service.ts index 095f0bfa..99f8926c 100644 --- a/ngapp/src/app/shared/test-data.service.ts +++ b/ngapp/src/app/shared/test-data.service.ts @@ -1124,7 +1124,54 @@ export class TestDataService { "sourcePaths": [ "connection=conn1/schema=public/table=customer" - ] + ], + "projectedColumns": [ + { + "name": "SSN", + "type": "string", + "selected": false + }, + { + "name": "FIRSTNAME", + "type": "string", + "selected": true + }, + { + "name": "LASTNAME", + "type": "string", + "selected": true + }, + { + "name": "ST_ADDRESS", + "type": "string", + "selected": false + }, + { + "name": "APT_NUMBER", + "type": "string", + "selected": false + }, + { + "name": "CITY", + "type": "string", + "selected": true + }, + { + "name": "STATE", + "type": "string", + "selected": true + }, + { + "name": "ZIPCODE", + "type": "string", + "selected": true + }, + { + "name": "PHONE", + "type": "string", + "selected": false + } + ] } } ); @@ -1266,7 +1313,54 @@ export class TestDataService { "type": "INNER_JOIN", "operator": "EQ" } - ] + ], + "projectedColumns": [ + { + "name": "SSN", + "type": "string", + "selected": false + }, + { + "name": "FIRSTNAME", + "type": "string", + "selected": true + }, + { + "name": "LASTNAME", + "type": "string", + "selected": true + }, + { + "name": "ST_ADDRESS", + "type": "string", + "selected": false + }, + { + "name": "APT_NUMBER", + "type": "string", + "selected": false + }, + { + "name": "CITY", + "type": "string", + "selected": true + }, + { + "name": "STATE", + "type": "string", + "selected": true + }, + { + "name": "ZIPCODE", + "type": "string", + "selected": true + }, + { + "name": "PHONE", + "type": "string", + "selected": false + } + ] } } ); @@ -1395,7 +1489,54 @@ export class TestDataService { "sourcePaths": [ "connection=conn1/schema=public/table=stuff" - ] + ], + "projectedColumns": [ + { + "name": "SSN", + "type": "string", + "selected": false + }, + { + "name": "FIRSTNAME", + "type": "string", + "selected": true + }, + { + "name": "LASTNAME", + "type": "string", + "selected": true + }, + { + "name": "ST_ADDRESS", + "type": "string", + "selected": false + }, + { + "name": "APT_NUMBER", + "type": "string", + "selected": false + }, + { + "name": "CITY", + "type": "string", + "selected": true + }, + { + "name": "STATE", + "type": "string", + "selected": true + }, + { + "name": "ZIPCODE", + "type": "string", + "selected": true + }, + { + "name": "PHONE", + "type": "string", + "selected": false + } + ] } } ); @@ -1537,7 +1678,14 @@ export class TestDataService { "type": "INNER_JOIN", "operator": "EQ" } - ] + ], + "projectedColumns": [ + { + "name": "ALL", + "type": "ALL", + "selected": true + } + ] } } ); @@ -1679,7 +1827,54 @@ export class TestDataService { "type": "INNER_JOIN", "operator": "EQ" } - ] + ], + "projectedColumns": [ + { + "name": "SSN", + "type": "string", + "selected": false + }, + { + "name": "FIRSTNAME", + "type": "string", + "selected": true + }, + { + "name": "LASTNAME", + "type": "string", + "selected": true + }, + { + "name": "ST_ADDRESS", + "type": "string", + "selected": false + }, + { + "name": "APT_NUMBER", + "type": "string", + "selected": false + }, + { + "name": "CITY", + "type": "string", + "selected": true + }, + { + "name": "STATE", + "type": "string", + "selected": true + }, + { + "name": "ZIPCODE", + "type": "string", + "selected": true + }, + { + "name": "PHONE", + "type": "string", + "selected": false + } + ] } } ); From e839ce86eefefe67f7d8abffa5e3a99e524ee417 Mon Sep 17 00:00:00 2001 From: Barry LaFond Date: Mon, 22 Oct 2018 13:02:10 -0500 Subject: [PATCH 198/205] TTOOLS-500 --- .../app/dataservices/dataservices.module.ts | 4 +- .../view-editor/view-canvas/canvas.service.ts | 2 + .../view-canvas/view-canvas.component.css | 11 +- .../view-canvas/view-canvas.component.html | 5 + .../view-canvas/view-canvas.component.spec.ts | 17 +- .../visuals/node/node-visual.component.ts | 2 +- .../view-editor-header.component.css | 103 ---- .../view-editor-header.component.html | 52 +- .../view-editor-header.component.ts | 428 +--------------- .../view-editor/view-editor.component.css | 4 +- .../views-list/views-list.component.css | 79 +++ .../views-list/views-list.component.html | 37 ++ .../views-list/views-list.component.spec.ts | 66 +++ .../views-list/views-list.component.ts | 468 ++++++++++++++++++ ngapp/src/assets/table.png | Bin 0 -> 3877 bytes 15 files changed, 691 insertions(+), 587 deletions(-) create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts create mode 100644 ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts create mode 100644 ngapp/src/assets/table.png diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts index ffde9b36..875abbaf 100644 --- a/ngapp/src/app/dataservices/dataservices.module.ts +++ b/ngapp/src/app/dataservices/dataservices.module.ts @@ -77,6 +77,7 @@ import { CreateViewsDialogComponent } from './create-views-dialog/create-views-d import { SetDescriptionDialogComponent } from "@dataservices/set-description-dialog/set-description-dialog.component"; import { PropertyEditorComponent } from './virtualization/view-editor/view-property-editors/property-editor/property-editor.component'; import { ProjectedColumnsEditorComponent } from './virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component'; +import { ViewsListComponent} from './virtualization/view-editor/views-list/views-list.component'; @NgModule({ imports: [ @@ -133,7 +134,8 @@ import { ProjectedColumnsEditorComponent } from './virtualization/view-editor/vi CreateViewsDialogComponent, SetDescriptionDialogComponent, PropertyEditorComponent, - ProjectedColumnsEditorComponent + ProjectedColumnsEditorComponent, + ViewsListComponent ], providers: [ { diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts index b13c550f..ef0addca 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts @@ -171,6 +171,8 @@ export class CanvasService { } public clear(): void { + if (this.canvasGraph == null) + return; this.canvasGraph.clear(); } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css index 50bca7a7..b521ac0d 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css @@ -4,8 +4,8 @@ #view-editor-canvas-editor { display: grid; grid-template-areas: - "canvas-editor properties-editor"; - grid-template-columns: 50fr 50fr; + "views-list-panel canvas-editor properties-editor"; + grid-template-columns: 20fr 50fr 30fr; height: 100%; } @@ -17,6 +17,13 @@ grid-area: canvas-editor; } +/* + * Views List Panel + */ +#views-list-container { + grid-area: views-list-panel; +} + /* * Configures the alert when view has no sources. */ diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html index e7d6709b..555f09bf 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html @@ -1,5 +1,10 @@
    +
    + +
    + diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts index 7ab84fb1..ebb1dee8 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts @@ -21,12 +21,15 @@ import { VdbService } from "@dataservices/shared/vdb.service"; import { MockVdbService } from "@dataservices/shared/mock-vdb.service"; import { NotifierService } from "@dataservices/shared/notifier.service"; import { ViewPropertyEditorsComponent } from "@dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component"; -import { TabsModule } from "ngx-bootstrap"; +import { TabsModule} from "ngx-bootstrap"; import { GraphVisualComponent, LinkVisualComponent, NodeVisualComponent } from "@dataservices/virtualization/view-editor/view-canvas/visuals"; import { CanvasService } from "@dataservices/virtualization/view-editor/view-canvas/canvas.service"; import { SelectionService } from "@core/selection.service"; import { PropertyEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component"; import { ProjectedColumnsEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component"; +import { ViewsListComponent } from "@dataservices/virtualization/view-editor/views-list/views-list.component"; +import { BsModalService } from "ngx-bootstrap"; +import { Dataservice } from "@dataservices/shared/dataservice.model"; describe('ViewCanvasComponent', () => { let component: ViewCanvasComponent; @@ -54,9 +57,11 @@ describe('ViewCanvasComponent', () => { ProjectedColumnsEditorComponent, PropertyEditorComponent, ViewCanvasComponent, - ViewPropertyEditorsComponent + ViewPropertyEditorsComponent, + ViewsListComponent ], providers: [ + BsModalService, { provide: AppSettingsService, useClass: MockAppSettingsService }, { provide: DataserviceService, useClass: MockDataserviceService }, CanvasService, @@ -75,6 +80,14 @@ describe('ViewCanvasComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ViewCanvasComponent); component = fixture.componentInstance; + + const selService = TestBed.get( SelectionService ); + const ds: Dataservice = new Dataservice(); + ds.setId("testDs"); + ds.setServiceVdbName("testDsVdb"); + // noinspection JSUnusedAssignment + selService.setSelectedVirtualization( ds ); + fixture.detectChanges(); }); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts index 667d8495..68a7cb7f 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts @@ -77,7 +77,7 @@ export class NodeVisualComponent { public get icon(): string { if (this.node.type === CanvasConstants.SOURCE_TYPE) - return "/assets/graphicsfuel/database-64.png"; + return "/assets/table.png"; else if (this.node.type === CanvasConstants.COMPOSITION_TYPE) return "/assets/composition.png"; diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css index 828d08cd..9b87ebfc 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css @@ -1,60 +1,3 @@ -/* - * The view description textarea. - */ -#view-editor-header-description-input { - max-width: max-content; - min-height: 20px; - min-width: 400px; - vertical-align: top; -} - -.list-pf-container { - -ms-flex-align: start; - align-items: flex-start; - display: -ms-flexbox; - display: flex; - padding: 0; -} - -.view-table-div { - padding-left: 0; - padding-right: 0; - margin-bottom: 5px; - min-height: 70px; - max-height: 70px; - border: 1px inset grey; - overflow-y: auto; -} - -.view-editor-header-name-input { - padding-left: 0; - padding-right: 5px; -} - -.view-editor-header-create-button { - margin-left: 0; - padding-left: 0; - padding-top: 8px; -} - -.view-editor-header-delete-button { - padding-left: 0; - padding-top: 8px; -} - -.view-editor-header-description-area { - padding-left: 0; - margin-left: 0; -} - -/* - * A div containing an input field in the header. - */ -.view-editor-header-input-div { - margin: 1px; - padding: 1px; -} - /* * A type for the header title */ @@ -62,49 +5,3 @@ margin-left: 10px; } -/* - * A type for vertically aligned labels in the header. - */ -.view-editor-header-label { - margin: 2px; - padding: 2px; -} - -/* - * The checkbox that shows/hides the virtualization description. - */ -#view-editor-header-show-description { - margin-right: 4px; -} - -/* - * The label for the checkbox that shows/hides the view description. - */ -#view-editor-header-show-description-label { - margin-top: 2px; - text-align: left; -} - -/* - * The label where the virtualization name is the content. - */ -#view-editor-header-virtualization-name { - text-align: left; -} - -/* - * Style the empty state component so that it is centered and extends the entire width. - */ -#view-editor-header-table .blank-slate-pf { - background-color: inherit; - min-width: 200px; - border: none; - padding: 0; -} - -/* - * Style text in blank slate for table - */ -#view-editor-header-table h1, .h1 { - font-size: 14px; -} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html index bd386954..6167371c 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html @@ -4,57 +4,7 @@
    -

    Virtualization Name: '{{virtualizationName}}'

    -
    - - - - -
    -
    - Views: -
    -
    - - -
    - -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    - - - - -
    - {{viewDescriptionLabel}} - -
    +

    Virtualization Name: {{virtualizationName}}

    diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts index 0a733e60..bb46a189 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts @@ -16,25 +16,7 @@ */ import { Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core"; -import { LoggerService } from "@core/logger.service"; -import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum"; import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service"; -import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event"; -import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n"; -import { CommandFactory } from "@dataservices/virtualization/view-editor/command/command-factory"; -import { Subscription } from "rxjs/Subscription"; -import { Command } from "@dataservices/virtualization/view-editor/command/command"; -import { EmptyStateConfig, NgxDataTableConfig, TableConfig } from "patternfly-ng"; -import { ViewDefinition } from "@dataservices/shared/view-definition.model"; -import { BsModalService } from "ngx-bootstrap"; -import { CreateViewDialogComponent } from "@dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component"; -import { DataserviceService } from "@dataservices/shared/dataservice.service"; -import { LoadingState } from "@shared/loading-state.enum"; -import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component"; -import { SelectionService } from "@core/selection.service"; -import { ViewEditorState } from "@dataservices/shared/view-editor-state.model"; -import { Dataservice } from "@dataservices/shared/dataservice.model"; -import { ViewEditorProgressChangeId } from "@dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum"; @Component({ encapsulation: ViewEncapsulation.None, @@ -44,151 +26,23 @@ import { ViewEditorProgressChangeId } from "@dataservices/virtualization/view-ed }) export class ViewEditorHeaderComponent implements OnInit, OnDestroy { - // used by html - public readonly viewDescriptionLabel = ViewEditorI18n.viewDescriptionLabel; - public readonly viewDescriptionPlaceholder = ViewEditorI18n.viewDescriptionPlaceholder; - - public ngxTableConfig: NgxDataTableConfig; - public tableConfig: TableConfig; - public tableColumns: any[] = []; - public tableRows: ViewDefinition[] = []; - private emptyStateConfig: EmptyStateConfig; - - private readonly logger: LoggerService; private readonly editorService: ViewEditorService; - private subscription: Subscription; - private modalService: BsModalService; - private dataserviceService: DataserviceService; - private selectionService: SelectionService; - private viewsLoadingState: LoadingState = LoadingState.LOADING; - private selectedVirtualization: Dataservice; - private viewSavedUponCompletion: ViewDefinition; - constructor( editorService: ViewEditorService, - dataserviceService: DataserviceService, - selectionService: SelectionService, - logger: LoggerService, - modalService: BsModalService) { + constructor( editorService: ViewEditorService) { this.editorService = editorService; - this.dataserviceService = dataserviceService; - this.selectionService = selectionService; - this.logger = logger; - this.modalService = modalService; - } - - /** - * @param {ViewEditorEvent} event the event being processed - */ - public handleEditorEvent( event: ViewEditorEvent ): void { - this.logger.debug( "ViewEditorHeaderComponent received event: " + event.toString() ); - - if ( event.typeIsEditorViewSaveProgressChanged() ) { - if ( event.args.length !== 0 ) { - // Detect changes in view editor save progress - if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_SUCCESS || - event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_FAILED ) { - if (this.viewSavedUponCompletion && this.viewSavedUponCompletion !== null) { - this.createNewView(this.viewSavedUponCompletion); - } - } - } - } } /** * Cleanup code when destroying the view editor header. */ public ngOnDestroy(): void { - this.subscription.unsubscribe(); + } /** * Initialization code run after construction. */ public ngOnInit(): void { - this.subscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) ); - - // ---------------------------------- - // View Table configurations - // ---------------------------------- - this.tableColumns = [ - { - draggable: false, - name: "Views", - prop: "viewName", - resizeable: true, - sortable: false, - width: "100" - } - ]; - - this.ngxTableConfig = { - headerHeight: 0, - rowHeight: 20, - reorderable: false, - selectionType: "'single'" - } as NgxDataTableConfig; - - this.emptyStateConfig = { - title: ViewEditorI18n.noViewsDefined - } as EmptyStateConfig; - - this.tableConfig = { - emptyStateConfig: this.emptyStateConfig - } as TableConfig; - - // init the available views - this.initViews(); - } - - /* - * Initialize the views for the current dataservice. Makes a rest call to get the ViewEditorStates for the serviceVdb - */ - private initViews( ): void { - this.viewsLoadingState = LoadingState.LOADING; - this.selectedVirtualization = this.selectionService.getSelectedVirtualization(); - if ( !this.selectedVirtualization || this.selectedVirtualization === null ) { - this.tableRows = []; - } - - const selectedView = this.selectionService.getSelectedViewDefinition(); - - const vdbName = this.selectedVirtualization.getServiceVdbName(); - const editorStatesPattern = vdbName.toLowerCase() + "*"; - - const self = this; - this.dataserviceService - .getViewEditorStates(editorStatesPattern) - .subscribe( - (viewEditorStates) => { - const viewDefns: ViewDefinition[] = []; - for ( const viewState of viewEditorStates ) { - const viewDefn = viewState.getViewDefinition(); - if ( viewDefn ) { - viewDefns.push( viewDefn ); - } - } - self.tableRows = viewDefns.sort( (left, right): number => { - if (left.getName() < right.getName()) return -1; - if (left.getName() > right.getName()) return 1; - return 0; - }); - - let initialView: ViewDefinition = null; - if (!selectedView || selectedView === null) { - initialView = (self.tableRows && self.tableRows.length > 0) ? self.tableRows[0] : null; - } else { - initialView = self.tableRows.find((x) => x.getName() === selectedView.getName()); - } - self.viewsLoadingState = LoadingState.LOADED_VALID; - self.selectView(initialView); - }, - (error) => { - self.logger.error("[VirtualizationComponent] Error updating the views for the virtualization: %o", error); - self.viewsLoadingState = LoadingState.LOADED_INVALID; - self.tableRows = []; - } - ); } /** @@ -198,55 +52,6 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { return !this.editorService.getEditorView() || this.editorService.isReadOnly(); } - /** - * @returns {boolean} `true` if views are being loaded - */ - public get viewsLoading(): boolean { - return this.viewsLoadingState === LoadingState.LOADING; - } - - /** - * @returns {string} the view description - */ - public get viewDescription(): string { - if ( this.editorService.getEditorView() ) { - return this.editorService.getEditorView().getDescription(); - } - - return ""; - } - - /** - * @param {string} newDescription the new description - */ - public set viewDescription( newDescription: string ) { - if ( this.editorService.getEditorView() ) { - if ( newDescription !== this.editorService.getEditorView().getDescription() ) { - const oldDescription = this.editorService.getEditorView().getDescription(); - const temp = CommandFactory.createUpdateViewDescriptionCommand( newDescription, oldDescription ); - - if ( temp instanceof Command ) { - this.editorService.fireViewStateHasChanged( ViewEditorPart.HEADER, temp as Command ); - } else { - const error = temp as Error; - this.logger.error( error.message ); - } - } - } else { - // shouldn't get here as description text input should be disabled if no view being edited - this.logger.error( "Trying to set description but there is no view being edited" ); - } - } - - /** - * Called when text in the view description textarea changes. - * - * @param {string} newDescription the new description of the view - */ - public viewDescriptionChanged( newDescription: string ): void { - this.viewDescription = newDescription; - } - /** * @returns {string} the name of the dataservice of the view being edited */ @@ -260,233 +65,4 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy { // should always have a virtualization name so shouldn't get here return "< error >"; } - - /** - * @returns {string} the description of the dataservice of the view being edited - */ - public get virtualizationDescription(): string { - const virtualization = this.editorService.getEditorVirtualization(); - - if ( virtualization ) { - return virtualization.getDescription(); - } - - // should always have a virtualization description so shouldn't get here - return "< error >"; - } - - public get deleteViewButtonEnabled(): boolean { - return ( this.getSelectedView() !== null ); - } - - /** - * Handles view selection from table - * @param $event - */ - public viewSelectionChanged( $event ): void { - const selectedViews: ViewDefinition[] = $event.selected; - // If the current view has pending changes, auto save it - if ( this.editorService.hasChanges() ) { - this.editorService.saveEditorState(); - } - this.selectView(selectedViews[0]); - } - - /** - * Handle creation of a new View. Displays the createView dialog, - * then saves the viewDefinition and adds it to the list - */ - public onCreateView(): void { - // Open New View dialog - const initialState = { - title: ViewEditorI18n.createViewDialogTitle, - cancelButtonText: ViewEditorI18n.cancelButtonText, - okButtonText: ViewEditorI18n.okButtonText - }; - - // Show Dialog, act upon confirmation click - const modalRef = this.modalService.show(CreateViewDialogComponent, {initialState}); - modalRef.content.okAction.take(1).subscribe((viewDefn) => { - // If the current view has pending changes, save them first - if ( this.editorService.hasChanges() ) { - this.viewSavedUponCompletion = viewDefn; - this.editorService.saveEditorState(); - } else { - this.createNewView(viewDefn); - } - // addition of a view undeploys active serviceVdb - this.editorService.undeploySelectedVirtualization(); - }); - } - - private createNewView(viewDefn: ViewDefinition): void { - const selectedDs = this.selectionService.getSelectedVirtualization(); - const editorId = this.getEditorStateId(selectedDs, viewDefn); - - // Create new editor state to save - const editorState = new ViewEditorState(); - editorState.setId(editorId); - editorState.setViewDefinition(viewDefn); - - const editorStates: ViewEditorState[] = []; - editorStates.push(editorState); - - this.viewsLoadingState = LoadingState.LOADING; - - const self = this; - this.dataserviceService - .saveViewEditorStatesRefreshViews(editorStates, selectedDs.getId()) - .subscribe( - (wasSuccess) => { - // Add the new ViewDefinition to the table - self.addViewDefinitionToList(viewDefn); - self.viewSavedUponCompletion = null; - self.viewsLoadingState = LoadingState.LOADED_VALID; - }, - (error) => { - self.logger.error("[VirtualizationComponent] Error saving the editor state: %o", error); - self.viewSavedUponCompletion = null; - self.viewsLoadingState = LoadingState.LOADED_INVALID; - } - ); - } - - /** - * Construct id for the editor state - * @param {Dataservice} dataservice the dataservice - * @param {ViewDefinition} viewDefn the view definition - * @returns {string} the ID used to persist the editor state - */ - private getEditorStateId(dataservice: Dataservice, viewDefn: ViewDefinition): string { - return dataservice.getServiceVdbName().toLowerCase() + "." + viewDefn.getName(); - } - - /** - * Handle Delete of the selected View - * @param {string} viewName - */ - public onDeleteView( ): void { - const viewName = this.getSelectedView().getName(); - - // Dialog Content - const message = "Do you really want to delete View '" + viewName + "'?"; - const initialState = { - title: "Confirm Delete", - bodyContent: message, - cancelButtonText: "Cancel", - confirmButtonText: "Delete" - }; - - // Show Dialog, act upon confirmation click - const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); - modalRef.content.confirmAction.take(1).subscribe((value) => { - this.doDeleteView(viewName); - }); - } - - /** - * Deletes the specified ViewEditorState from the userProfile, and removes ViewDefinition from the current list. - * @param {string} viewDefnName the name of the view - */ - private doDeleteView(viewDefnName: string): void { - const selectedViewDefn = this.tableRows.find((x) => x.getName() === viewDefnName); - const selectedDs = this.selectionService.getSelectedVirtualization(); - const vdbName = selectedDs.getServiceVdbName(); - const editorStateId = vdbName.toLowerCase() + "." + viewDefnName; - const dataserviceName = selectedDs.getId(); - - this.viewsLoadingState = LoadingState.LOADING; - // Note: we can only doDelete selected items that we can see in the UI. - this.logger.debug("[VirtualizationComponent] Deleting selected Virtualization View."); - const self = this; - this.dataserviceService - .deleteViewEditorStateRefreshViews(editorStateId, dataserviceName) - .subscribe( - (wasSuccess) => { - self.removeViewDefinitionFromList(selectedViewDefn); - // deletion of a view undeploys active serviceVdb - self.editorService.undeploySelectedVirtualization(); - this.viewsLoadingState = LoadingState.LOADED_VALID; - }, - (error) => { - self.logger.error("[VirtualizationComponent] Error deleting the editor state: %o", error); - this.viewsLoadingState = LoadingState.LOADED_INVALID; - } - ); - } - - /* - * Add the specified ViewDefinition to the view definitions table - * @param {ViewDefinition} viewDefn the view definition to add - */ - private addViewDefinitionToList(viewDefn: ViewDefinition): void { - const newRows: ViewDefinition[] = []; - newRows.push(viewDefn); - for ( const row of this.tableRows ) { - if ( row.getName() !== viewDefn.getName() ) { - newRows.push( row ); - } - } - this.tableRows = newRows.sort( (left, right): number => { - if (left.getName() < right.getName()) return -1; - if (left.getName() > right.getName()) return 1; - return 0; - }); - this.selectView(viewDefn); - } - - /* - * Remove the specified ViewDefinition from the view definitions table - * @param {ViewDefinition} viewDefn the view definition to remove - */ - private removeViewDefinitionFromList(viewDefn: ViewDefinition): void { - const origIndex = this.tableRows.findIndex( ( defn ) => defn.getName() === viewDefn.getName() ); - - const newRows: ViewDefinition[] = []; - for ( const row of this.tableRows ) { - if ( row.getName() !== viewDefn.getName() ) { - newRows.push( row ); - } - } - this.tableRows = newRows; - - // auto select another row - if ( this.tableRows.length > origIndex ) { - this.selectView( this.tableRows[origIndex] ); - } else if ( this.tableRows.length > 0 ) { - this.selectView( this.tableRows[origIndex - 1] ); - } else if ( this.tableRows.length === 0 ) { - this.selectView( null ); - } - } - - private selectView( selView: ViewDefinition ): void { - // Updates table selection display - let viewSelection = null; - if ( selView && selView !== null ) { - for (const view of this.tableRows) { - if (view.getName() === selView.getName()) { - view.setSelected(true); - viewSelection = view; - } else { - view.setSelected(false); - } - } - } - // Update selection service, then fire event - this.selectionService.setSelectedViewDefinition(this.selectedVirtualization, viewSelection); - this.editorService.setEditorView(viewSelection, ViewEditorPart.HEADER); - } - - private getSelectedView( ): ViewDefinition { - let selectedView: ViewDefinition = null; - for (const view of this.tableRows) { - if (view.selected) { - selectedView = view; - break; - } - } - return selectedView; - } - } diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css index 8cae6216..9a69e1f9 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css @@ -90,6 +90,8 @@ */ #view-editor-toolbar .form-group { margin: 2px; + padding-left: 5px; + padding-right: 5px; } /* @@ -99,7 +101,7 @@ background-color: inherit; border: none; box-shadow: none; - padding: 0; + padding: 0px; } /* diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css new file mode 100644 index 00000000..c0ccdd80 --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css @@ -0,0 +1,79 @@ +.list-pf-container { + -ms-flex-align: start; + align-items: flex-start; + display: -ms-flexbox; + display: flex; + padding: 0; +} + +.views-list-title { + padding-left: 10px; + text-align: left; +} + +.create-delete-buttons { + horiz-align: left; + padding-top: 5px; + padding-bottom: 5px; + grid-row-gap: 1px; + vertical-align: middle; +} + +.views-list-create-button { + margin-left: 0px; + padding-left: 0; + padding-top: 8px; + padding-bottom: 8px; + background-color: aquamarine; +} + +.views-list-delete-button { + padding-left: 0px; + padding-top: 8px; + padding-bottom: 8px; +} + +.views-list-description-area { + padding-left: 0; + margin-left: 0; +} + +.views-list-div { + padding-left: 1px; + padding-right: 1px; + margin-bottom: 5px; + min-height: 400px; + max-height: 400px; + height: 100%; + width: 100%; + border: 1px inset grey; + overflow-y: auto; +} + +/* + * Style the empty state component so that it is centered and extends the entire width. + */ +#views-list-table .blank-slate-pf { + background-color: inherit; + min-width: 200px; + border: none; + padding: 0; + min-height: 400px; + max-height: 400px; +} + +/* + * Style text in blank slate for table + */ +#views-list-table h1, .h1 { + font-size: 14px; +} + +/* + * The view description text area. + */ +#views-list-description-input { + min-height: 20px; + min-width: 300px; + vertical-align: top; +} diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html new file mode 100644 index 00000000..18ccdd3b --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html @@ -0,0 +1,37 @@ +
    + +
    +
    + Views +
    + + + +
    + +
    +
    + +
    +
    + + + + + +
    +
    + + +
    +
    + + diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts new file mode 100644 index 00000000..50ea4c2c --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts @@ -0,0 +1,66 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ViewsListComponent } from './views-list.component'; +import {SelectionService} from "@core/selection.service"; +import {Dataservice} from "@dataservices/shared/dataservice.model"; +import {ViewEditorService} from "@dataservices/virtualization/view-editor/view-editor.service"; +import {MockAppSettingsService} from "@core/mock-app-settings.service"; +import {LoggerService} from "@core/logger.service"; +import {AppSettingsService} from "@core/app-settings.service"; +import {DataserviceService} from "@dataservices/shared/dataservice.service"; +import {MockVdbService} from "@dataservices/shared/mock-vdb.service"; +import {BsModalService, ComponentLoaderFactory} from "ngx-bootstrap"; +import {MockDataserviceService} from "@dataservices/shared/mock-dataservice.service"; +import {NotifierService} from "@dataservices/shared/notifier.service"; +import {VdbService} from "@dataservices/shared/vdb.service"; +import {HttpModule} from "@angular/http"; +import {FormsModule} from "@angular/forms"; +import {TableModule} from "patternfly-ng"; +import {RouterTestingModule} from "@angular/router/testing"; + +describe('ViewsListComponent', () => { + let component: ViewsListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + FormsModule, + HttpModule, + RouterTestingModule, + TableModule + ], + declarations: [ ViewsListComponent ], + providers: [ + BsModalService, + { provide: AppSettingsService, useClass: MockAppSettingsService }, + { provide: DataserviceService, useClass: MockDataserviceService }, + LoggerService, + NotifierService, + SelectionService, + { provide: VdbService, useClass: MockVdbService }, + ComponentLoaderFactory, + ViewEditorService + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ViewsListComponent); + component = fixture.componentInstance; + + const selService = TestBed.get( SelectionService ); + const ds: Dataservice = new Dataservice(); + ds.setId("testDs"); + ds.setServiceVdbName("testDsVdb"); + // noinspection JSUnusedAssignment + selService.setSelectedVirtualization( ds ); + + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts new file mode 100644 index 00000000..4ab1a34a --- /dev/null +++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts @@ -0,0 +1,468 @@ +/** + * @license + * Copyright 2017 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import {AfterViewInit, Component, OnDestroy, OnInit, ViewEncapsulation} from '@angular/core'; +import {LoadingState} from "@shared/loading-state.enum"; +import {ViewDefinition} from "@dataservices/shared/view-definition.model"; +import {ViewEditorPart} from "@dataservices/virtualization/view-editor/view-editor-part.enum"; +import {EmptyStateConfig, NgxDataTableConfig, TableConfig} from "patternfly-ng"; +import {ViewEditorI18n} from "@dataservices/virtualization/view-editor/view-editor-i18n"; +import {ViewEditorProgressChangeId} from "@dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum"; +import {ViewEditorState} from "@dataservices/shared/view-editor-state.model"; +import {ViewEditorService} from "@dataservices/virtualization/view-editor/view-editor.service"; +import {Dataservice} from "@dataservices/shared/dataservice.model"; +import {LoggerService} from "@core/logger.service"; +import {ViewEditorEvent} from "@dataservices/virtualization/view-editor/event/view-editor-event"; +import {Subscription} from "rxjs/Subscription"; +import {BsModalService} from "ngx-bootstrap"; +import {DataserviceService} from "@dataservices/shared/dataservice.service"; +import {SelectionService} from "@core/selection.service"; +import {ConfirmDialogComponent} from "@shared/confirm-dialog/confirm-dialog.component"; +import {CommandFactory} from "@dataservices/virtualization/view-editor/command/command-factory"; +import {Command} from "@dataservices/virtualization/view-editor/command/command"; +import {CreateViewDialogComponent} from "@dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component"; + +@Component({ + encapsulation: ViewEncapsulation.None, + selector: 'app-views-list', + templateUrl: './views-list.component.html', + styleUrls: ['./views-list.component.css'] +}) +export class ViewsListComponent implements OnInit, OnDestroy, AfterViewInit { + + // used by html + public readonly viewDescriptionLabel = ViewEditorI18n.viewDescriptionLabel; + public readonly viewDescriptionPlaceholder = ViewEditorI18n.viewDescriptionPlaceholder; + + public ngxTableConfig: NgxDataTableConfig; + public tableConfig: TableConfig; + public tableColumns: any[] = []; + public tableRows: ViewDefinition[] = []; + private emptyStateConfig: EmptyStateConfig; + + private readonly logger: LoggerService; + private readonly editorService: ViewEditorService; + private subscription: Subscription; + private modalService: BsModalService; + private dataserviceService: DataserviceService; + private selectionService: SelectionService; + private viewsLoadingState: LoadingState = LoadingState.LOADING; + private selectedVirtualization: Dataservice; + private viewSavedUponCompletion: ViewDefinition; + + constructor( editorService: ViewEditorService, + dataserviceService: DataserviceService, + selectionService: SelectionService, + logger: LoggerService, + modalService: BsModalService) { + this.editorService = editorService; + this.dataserviceService = dataserviceService; + this.selectionService = selectionService; + this.logger = logger; + this.modalService = modalService; + } + + /** + * @param {ViewEditorEvent} event the event being processed + */ + public handleEditorEvent( event: ViewEditorEvent ): void { + this.logger.debug( "ViewsListComponent received event: " + event.toString() ); + + if ( event.typeIsEditorViewSaveProgressChanged() ) { + if ( event.args.length !== 0 ) { + // Detect changes in view editor save progress + if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_SUCCESS || + event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_FAILED ) { + if (this.viewSavedUponCompletion && this.viewSavedUponCompletion !== null) { + this.createNewView(this.viewSavedUponCompletion); + } + } + } + } + } + + /** + * Cleanup code when destroying the view editor header. + */ + public ngOnDestroy(): void { + this.subscription.unsubscribe(); + } + + /** + * Initialization code run after construction. + */ + public ngOnInit(): void { + this.subscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) ); + + // ---------------------------------- + // View Table configurations + // ---------------------------------- + this.tableColumns = [ + { + draggable: false, + name: "Views", + prop: "viewName", + resizeable: true, + sortable: false, + width: "100" + } + ]; + + this.ngxTableConfig = { + headerHeight: 0, + rowHeight: 20, + reorderable: false, + selectionType: "'single'" + } as NgxDataTableConfig; + + this.emptyStateConfig = { + title: ViewEditorI18n.noViewsDefined + } as EmptyStateConfig; + + this.tableConfig = { + emptyStateConfig: this.emptyStateConfig + } as TableConfig; + + + } + + public ngAfterViewInit(): void { + // init the available views + this.initViews(); + } + + /* + * Initialize the views for the current dataservice. Makes a rest call to get the ViewEditorStates for the serviceVdb + */ + private initViews( ): void { + this.viewsLoadingState = LoadingState.LOADING; + this.selectedVirtualization = this.selectionService.getSelectedVirtualization(); + if ( !this.selectedVirtualization || this.selectedVirtualization === null ) { + this.tableRows = []; + } + + const selectedView = this.selectionService.getSelectedViewDefinition(); + + const vdbName = this.selectedVirtualization.getServiceVdbName(); + const editorStatesPattern = vdbName.toLowerCase() + "*"; + + const self = this; + this.dataserviceService + .getViewEditorStates(editorStatesPattern) + .subscribe( + (viewEditorStates) => { + const viewDefns: ViewDefinition[] = []; + for ( const viewState of viewEditorStates ) { + const viewDefn = viewState.getViewDefinition(); + if ( viewDefn ) { + viewDefns.push( viewDefn ); + } + } + self.tableRows = viewDefns.sort( (left, right): number => { + if (left.getName() < right.getName()) return -1; + if (left.getName() > right.getName()) return 1; + return 0; + }); + + let initialView: ViewDefinition = null; + if (!selectedView || selectedView === null) { + initialView = (self.tableRows && self.tableRows.length > 0) ? self.tableRows[0] : null; + } else { + initialView = self.tableRows.find((x) => x.getName() === selectedView.getName()); + } + self.viewsLoadingState = LoadingState.LOADED_VALID; + if( initialView !== null) { + self.selectView(initialView); + } + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error updating the views for the virtualization: %o", error); + self.viewsLoadingState = LoadingState.LOADED_INVALID; + self.tableRows = []; + } + ); + } + + /** + * @returns {boolean} `true` if view being edited is readonly + */ + public get readOnly(): boolean { + return !this.editorService.getEditorView() || this.editorService.isReadOnly(); + } + + /** + * @returns {boolean} `true` if views are being loaded + */ + public get viewsLoading(): boolean { + return this.viewsLoadingState === LoadingState.LOADING; + } + + /** + * Handles view selection from table + * @param $event + */ + public viewSelectionChanged( $event ): void { + const selectedViews: ViewDefinition[] = $event.selected; + // If the current view has pending changes, auto save it + if ( this.editorService.hasChanges() ) { + this.editorService.saveEditorState(); + } + this.selectView(selectedViews[0]); + } + + public get deleteViewButtonEnabled(): boolean { + return ( this.getSelectedView() !== null ); + } + + private createNewView(viewDefn: ViewDefinition): void { + const selectedDs = this.selectionService.getSelectedVirtualization(); + const editorId = this.getEditorStateId(selectedDs, viewDefn); + + // Create new editor state to save + const editorState = new ViewEditorState(); + editorState.setId(editorId); + editorState.setViewDefinition(viewDefn); + + const editorStates: ViewEditorState[] = []; + editorStates.push(editorState); + + this.viewsLoadingState = LoadingState.LOADING; + + const self = this; + this.dataserviceService + .saveViewEditorStatesRefreshViews(editorStates, selectedDs.getId()) + .subscribe( + (wasSuccess) => { + // Add the new ViewDefinition to the table + self.addViewDefinitionToList(viewDefn); + self.viewSavedUponCompletion = null; + self.viewsLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error saving the editor state: %o", error); + self.viewSavedUponCompletion = null; + self.viewsLoadingState = LoadingState.LOADED_INVALID; + } + ); + } + + /** + * Handle creation of a new View. Displays the createView dialog, + * then saves the viewDefinition and adds it to the list + */ + public onCreateView(): void { + // Open New View dialog + const initialState = { + title: ViewEditorI18n.createViewDialogTitle, + cancelButtonText: ViewEditorI18n.cancelButtonText, + okButtonText: ViewEditorI18n.okButtonText + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(CreateViewDialogComponent, {initialState}); + modalRef.content.okAction.take(1).subscribe((viewDefn) => { + // If the current view has pending changes, save them first + if ( this.editorService.hasChanges() ) { + this.viewSavedUponCompletion = viewDefn; + this.editorService.saveEditorState(); + } else { + this.createNewView(viewDefn); + } + // addition of a view undeploys active serviceVdb + this.editorService.undeploySelectedVirtualization(); + }); + } + + /** + * Construct id for the editor state + * @param {Dataservice} dataservice the dataservice + * @param {ViewDefinition} viewDefn the view definition + * @returns {string} the ID used to persist the editor state + */ + private getEditorStateId(dataservice: Dataservice, viewDefn: ViewDefinition): string { + return dataservice.getServiceVdbName().toLowerCase() + "." + viewDefn.getName(); + } + + /** + * Handle Delete of the selected View + * @param {string} viewName + */ + public onDeleteView( ): void { + const viewName = this.getSelectedView().getName(); + + // Dialog Content + const message = "Do you really want to delete View '" + viewName + "'?"; + const initialState = { + title: "Confirm Delete", + bodyContent: message, + cancelButtonText: "Cancel", + confirmButtonText: "Delete" + }; + + // Show Dialog, act upon confirmation click + const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState}); + modalRef.content.confirmAction.take(1).subscribe((value) => { + this.doDeleteView(viewName); + }); + } + + /** + * Deletes the specified ViewEditorState from the userProfile, and removes ViewDefinition from the current list. + * @param {string} viewDefnName the name of the view + */ + private doDeleteView(viewDefnName: string): void { + const selectedViewDefn = this.tableRows.find((x) => x.getName() === viewDefnName); + const selectedDs = this.selectionService.getSelectedVirtualization(); + const vdbName = selectedDs.getServiceVdbName(); + const editorStateId = vdbName.toLowerCase() + "." + viewDefnName; + const dataserviceName = selectedDs.getId(); + + this.viewsLoadingState = LoadingState.LOADING; + // Note: we can only doDelete selected items that we can see in the UI. + this.logger.debug("[VirtualizationComponent] Deleting selected Virtualization View."); + const self = this; + this.dataserviceService + .deleteViewEditorStateRefreshViews(editorStateId, dataserviceName) + .subscribe( + (wasSuccess) => { + self.removeViewDefinitionFromList(selectedViewDefn); + // deletion of a view undeploys active serviceVdb + self.editorService.undeploySelectedVirtualization(); + this.viewsLoadingState = LoadingState.LOADED_VALID; + }, + (error) => { + self.logger.error("[VirtualizationComponent] Error deleting the editor state: %o", error); + this.viewsLoadingState = LoadingState.LOADED_INVALID; + } + ); + } + + /* + * Add the specified ViewDefinition to the view definitions table + * @param {ViewDefinition} viewDefn the view definition to add + */ + private addViewDefinitionToList(viewDefn: ViewDefinition): void { + const newRows: ViewDefinition[] = []; + newRows.push(viewDefn); + for ( const row of this.tableRows ) { + if ( row.getName() !== viewDefn.getName() ) { + newRows.push( row ); + } + } + this.tableRows = newRows.sort( (left, right): number => { + if (left.getName() < right.getName()) return -1; + if (left.getName() > right.getName()) return 1; + return 0; + }); + this.selectView(viewDefn); + } + + /* + * Remove the specified ViewDefinition from the view definitions table + * @param {ViewDefinition} viewDefn the view definition to remove + */ + private removeViewDefinitionFromList(viewDefn: ViewDefinition): void { + const origIndex = this.tableRows.findIndex( ( defn ) => defn.getName() === viewDefn.getName() ); + + const newRows: ViewDefinition[] = []; + for ( const row of this.tableRows ) { + if ( row.getName() !== viewDefn.getName() ) { + newRows.push( row ); + } + } + this.tableRows = newRows; + + // auto select another row + if ( this.tableRows.length > origIndex ) { + this.selectView( this.tableRows[origIndex] ); + } else if ( this.tableRows.length > 0 ) { + this.selectView( this.tableRows[origIndex - 1] ); + } else if ( this.tableRows.length === 0 ) { + this.selectView( null ); + } + } + + private selectView( selView: ViewDefinition ): void { + // Updates table selection display + let viewSelection = null; + if ( selView && selView !== null ) { + for (const view of this.tableRows) { + if (view.getName() === selView.getName()) { + view.setSelected(true); + viewSelection = view; + } else { + view.setSelected(false); + } + } + } + // Update selection service, then fire event + this.selectionService.setSelectedViewDefinition(this.selectedVirtualization, viewSelection); + this.editorService.setEditorView(viewSelection, ViewEditorPart.HEADER); + } + + private getSelectedView( ): ViewDefinition { + let selectedView: ViewDefinition = null; + for (const view of this.tableRows) { + if (view.selected) { + selectedView = view; + break; + } + } + return selectedView; + } + + /** + * @returns {string} the view description + */ + public get viewDescription(): string { + if ( this.editorService.getEditorView() ) { + return this.editorService.getEditorView().getDescription(); + } + + return ""; + } + + /** + * @param {string} newDescription the new description + */ + public set viewDescription( newDescription: string ) { + if ( this.editorService.getEditorView() ) { + if ( newDescription !== this.editorService.getEditorView().getDescription() ) { + const oldDescription = this.editorService.getEditorView().getDescription(); + const temp = CommandFactory.createUpdateViewDescriptionCommand( newDescription, oldDescription ); + + if ( temp instanceof Command ) { + this.editorService.fireViewStateHasChanged( ViewEditorPart.HEADER, temp as Command ); + } else { + const error = temp as Error; + this.logger.error( error.message ); + } + } + } else { + // shouldn't get here as description text input should be disabled if no view being edited + this.logger.error( "Trying to set description but there is no view being edited" ); + } + } + + /** + * Called when text in the view description textarea changes. + * + * @param {string} newDescription the new description of the view + */ + public viewDescriptionChanged( newDescription: string ): void { + this.viewDescription = newDescription; + } +} diff --git a/ngapp/src/assets/table.png b/ngapp/src/assets/table.png new file mode 100644 index 0000000000000000000000000000000000000000..99a133d4090537ef071856175c3946ea3073cb8e GIT binary patch literal 3877 zcmV+=58CjFP)WFU8GbZ8()Nlj2>E@cM*01k;sL_t(|+U=WLjGfn2 z$A4?>{hc#ckFU+uY3w*o8z+wAv=NPywx~&{dJ*D*@&Hw#JVPrUCl=X`tbwRkw=@thfZe5RCAJK54V zIuGCe_Fn(JZvVCRz&qoe@wOfUu=SZ8+;Q6m9{9$?hj#AWXH`{QQbOk9s0OO2{M6=~ z%T-mTwDS>4nT~NloG)+V@pSwoNSR(;q@a&KYr%j834>7 zrxryF(?Oy*$vVVph@9$Ky7Ch*Jt0=O8<&ua1*I#=zP4P;^NM;l(DB=7jFyrm~(g}m+p3i#mUd7h8dnWh}0P_sM1{s|4Jf2sNM@H#9B{Y30Z>swbf!*EF5mY2j^Fpt zcrW6oe$*WNheX#(DO;+l@wJ@lPrLg{4dE$ZL`05Qv71EYu((fvizBOI)qLWyr?!2N zH~Rp<0o6bt@Zy1^8(uzqY(uBrrlGy{0aeAU3#yqBLL|mWE;XeTP(fYi96~q$>ed<@ z%QYcXL6qfV!%R-L{;bZK(*5w7FmIM%RtO0`a zLReS>O3u>)7Fv^2gb>K7H!C!&5fMbXIEAQ4DgbQSV*I70fdtgFEc|`DLE0V2oCO!i1wtx z=V5~ZFPXKgFMn-pY~<@z5ZrwZ0M^wO5k$4d%I`k+;z3fKx$Tw>VC^rec(dobQekyX z6_sRxQxlV)efhwll_l3~y77i%NV>m@I`1U2DFX^2gwE;7&VA4C-j8D3zG>sPOYS_U z>LMa@w9N@Ikm^JTu^fEu*l!*^elj3kO;ptde1HZ@>ac3*$SWVXW6KxTy=(Y_hWW4G z{$9t?FP75g2hV>0?qB}QXCA$E&B_JM{K0Si`^N~?O6m#LT(Ru+k8Iieg$u3o%}2K0 z$G#@Hb%On`?)ls=eCp?S-f+c|1?Ozry+`&Oc;f@A`eC28#o2)AT<27BCP@W|^dmd~ zRTy=zsX}0AU})q*!UGhka7%PTL}Tb{nV=P#rVwq=Y&PSCga^3g`gJ}SLo~}6kgRn5 z)Q>V1me~wL79SCQJjClAGIa5iA^&jzpsHP0xtNcrE-^D)6r?{JZ~-rdi1xjlNcWEm zAi8Ma@Lx21P^vWGLq{?iw+7N}n0Dl8LGmgVJZwRd903-F0&R6)T$tSQs;SG&4j&R1ppAJ8*cJijzv=>UHb>eD9v!UwUNg z4|-KC1Zpo>F)AW^4v$}7Ql^R(r>9!ie|PJ1+pDU9m5kY$Snbmx6Pl{FMLJ+$PXQxK&>WAMJNe!hbbSV z5$C8|G0Y0F8Oa$$BQY2*0e7S1G+j?PyP{jcL!_iaG$_LrBW{eXyn<72jFUZ57elps zQf5vFiaD4Im9>%PC>0$#I)Hbk5Fkr~K%SGS0#Yb$3=Iw==9n9TAeMOl=1u(K$M2ML zYCshfw?GvuQci?sh0bwo5(Kvzi4g%ph=?adryZJx?$bkRDy$gIp(e#M(P3sVCPS6VXgcU-P*bLfa&QrC!GtrrD|~Ap~~qe{JpYlc$HynErxXAOs=hHp`X_Kl`aq-g8$!PUh?1 z`p&Psdi1UPizN;p-2dyJ|Mai@^M&U8&EGw=z17J#St+btedX?-`QYt0Uue$5k3Hl2 z4jrb{H3ts8_H%#mxzE1P&;Gvnmw*2~LGBa*w*|OB_o$R0ff)M_gF!@Ftu~?&?=yTZ zS@|v`glSr>edZ31mrNCv!A7;HC}8J_8uM#{p@I2)3cS!58Xml|St$y{K7~1PvPFu&!yj1bj|CYTn9bKJCmFkq4A~O5{vAy}wMbIWRE8-TP)x z?lbQ%=70o8q$ei*|8s%ap7?D^hU6#Y#)V#xKKG@WzUWr+Y!#OOb1b}n0D?eN!4_d- z166fRN~xP3hyIkRQbTbniA<&b+HeIS1R+GBiv34{OvHhJp%^0J`~a9kDh8^)^Wc%b z7MPrvcxiBW6fcGL#Od_X`0)#$iM25alv4U{Lgl(Ef(flor>`m7c8z0ZSw*MyKo+LM zxfDbq$KN`A_1`}5^-uoxSH7xZy*O#3B6|iml831}4BcOM+KdbhvhLdTpTGaFAK<<} z`m3tUAt{YUlbkcfoi|VUk~(FYF>+x1@RHy9(x3dS%D|irIufCnqxI>DV<%2iN+DE( z6z8Y!`|_V&m%Qq^@BmQ7206E>2Ae$iPybdgU9o&i7j!>I2Vo8wBDV>Hqm;TuX`e<1 zSDP{iV zfqC{CG*IV)<|(8xN|YLF4CCzyaHHrz??A4*ZjW0OvH!oUz%LBw(G z!aF+^o@WA4x?Q1-H>`d0=%MjDZoc)ldtcnX{gDvPdbebSIJS&ZGH;!3Pj0#WroG>L zdOKb+ciz64v4Q5VKE3Vvry5l?qnmZ7m2Ta*;m+~HM_)K`{MhLgmyJEXZP&?Fsjk_w z@jWN%cI#txZE13Hsy%x@$;}4_hT_RLkG{2b&D#A>?|6|Y@bQn_#i_TB-90!mwtCmD zJx}*mfQ(}1t5z%@8yp&{jvP7u`2N@5=sI>`VIL4fAmz+RLtl8`NAKCS>4w$2Uf6ex zo334XUPtqvPyE*tQ+55JN`%KBee~Y1e))I4^YZ>9tbg}qGwZ$#~xk#$M^lltLNL( zo`XkNx4OIjm;U0R$KClbBJ=VOogbeCcgSYC>4wz+3knbL{JulKClV2<7+bPz2NZwYyZbuNI3qlODadq)Uiq$73wCYJ2v4_#7agDJ8!pHO4Z&SO zLf>(A&)X;=i-{^J8ycGZr`>LJ3(7h#1=n*C2ZAh$ z44s5qAzWT=}YIBJG3g0EMh8Y!g^;vgyax5G}I z5Ov%Wb*DcBidKY5@Zgk1bP6praAbxI>8vY1^X~~}!&L|&^u0oZyrMBMMBSOdtv>_? z%Ovg*QNiiYg@n!o=0XS!M5OQil~VkymUZtBoj(zZk-8M7I(gOMqi5W@)qXr=EM6QVOoh?VE0ScKb^&Kar$yb9Ni- z0m_wJ5{+iWvhc{(XNIL4-{#jMW|N`uV-tkZVQ_RQkwj^qX40F8({r^%MQ{vvBWROi zhLdSlP27w+wNPpFI0VBGjdVISAx5GImI@44gu2Gv5Q)8B#2pWTj8o+{gc00Y&>SJ8 zNi5ZP9GvHOOq5jGG#gEr{k&ArR4O?Ertdgh`b3itxKjl{F5NSO7Va}|_*I+01!yG>_`$e}^;ZU^pM z&OkJr2{O0}?K%^hgR~}3vV8fnS9<{X_LI+W@13{F1ONCR?N|06YKEK{6h*WvoLuDB zhD%P24K>N_7B_8t@AyaWxMl5*{m0qx?iIb}vt#d}aPq`SK@_E1LNc3H--~#3>JB5L nBcx7S?$~@|;+^r%m>K^A>Q-KnXyW(k00000NkvXXu0mjf Date: Mon, 22 Oct 2018 17:01:29 -0500 Subject: [PATCH 199/205] minor adjustment to property panel layout --- .../property-editor.component.html | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html index 28825a61..1b00991e 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html @@ -10,22 +10,22 @@

    Multiple Items Selected

    {{getFirstSelection().getSelectionType()}} Properties

    -
    Name:
    -
    {{getFirstSelection().getSourceName()}}
    -
    Connection:
    -
    {{getFirstSelection().getSourceConnectionName()}}
    +
    Name:
    +
    {{getFirstSelection().getSourceName()}}
    +
    Connection:
    +
    {{getFirstSelection().getSourceConnectionName()}}
    -
    Name:
    -
    {{getFirstSelection().getComposition().getName()}}
    -
    Type:
    -
    {{getFirstSelection().getComposition().getType()}}
    -
    Left Source:
    -
    {{getFirstSelection().getComposition().getLeftSourceDisplay()}}
    -
    Right Source:
    -
    {{getFirstSelection().getComposition().getRightSourceDisplay()}}
    -
    Criteria:
    -
    {{getFirstSelection().getComposition().getCriteriaDisplay()}}
    +
    Name:
    +
    {{getFirstSelection().getComposition().getName()}}
    +
    Type:
    +
    {{getFirstSelection().getComposition().getType()}}
    +
    Left Source:
    +
    {{getFirstSelection().getComposition().getLeftSourceDisplay()}}
    +
    Right Source:
    +
    {{getFirstSelection().getComposition().getRightSourceDisplay()}}
    +
    Criteria:
    +
    {{getFirstSelection().getComposition().getCriteriaDisplay()}}
    From 493fb583d57513e96f808c87015116a2ff86027a Mon Sep 17 00:00:00 2001 From: blafond Date: Tue, 23 Oct 2018 09:44:34 -0500 Subject: [PATCH 200/205] TTOOLS-500 - additional tweaks to fix unit test --- .../view-canvas/view-canvas.component.ts | 36 +------------------ .../visuals/graph/graph-visual.component.ts | 4 +-- .../views-list/views-list.component.ts | 8 +++-- 3 files changed, 8 insertions(+), 40 deletions(-) diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts index 700d026e..9946f225 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts @@ -46,7 +46,7 @@ import { Composition } from "@dataservices/shared/composition.model"; templateUrl: "./view-canvas.component.html", styleUrls: ["./view-canvas.component.css"] }) -export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { +export class ViewCanvasComponent implements OnInit, OnDestroy { // used by html public readonly noSourcesAlert = ViewEditorI18n.noSourcesAlert; @@ -197,40 +197,6 @@ export class ViewCanvasComponent implements OnInit, AfterViewInit, OnDestroy { this.canvasSubscription = this.canvasService.canvasEvent.subscribe((event) => this.handleCanvasEvent(event)); } - public ngAfterViewInit(): void { - // const labels:string[] = ['Employee', 'Admin', 'Payroll', 'EmployeeAdmin', 'EmployeePayDay']; - // const type:string[] = [ - // CanvasConstants.SOURCE_TYPE, - // CanvasConstants.SOURCE_TYPE, - // CanvasConstants.SOURCE_TYPE, - // CanvasConstants.COMPOSITION_TYPE, - // CanvasConstants.COMPOSITION_TYPE - // ]; - // - // /** constructing the nodes array */ - // const nodeIds: string[] = []; - // for (let i = 0; i < 5; i++) { - // const id = this.canvasService.createNode(type[i], labels[i]); - // nodeIds.push(id); - // } - // - // this.canvasService.createLink(nodeIds[0], nodeIds[3]); - // this.canvasService.createLink(nodeIds[1], nodeIds[3]); - // this.canvasService.createLink(nodeIds[2], nodeIds[4]); - // this.canvasService.createLink(nodeIds[3], nodeIds[4], true); - - this.canvasService.canvasEvent.subscribe((nodes) => { - if (_.isEmpty(nodes)) { - console.log("No nodes selected"); - return; - } - - for (const node of nodes) { - console.log("Node " + node.label + " selected"); - } - }); - } - /** * @returns {boolean} `true` if view being edited is readonly */ diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts index fdece176..f8ea0525 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts @@ -87,6 +87,7 @@ export class GraphVisualComponent implements OnInit { constructor(canvasService: CanvasService, ref: ChangeDetectorRef) { this.canvasService = canvasService; this.ref = ref; + this.canvasGraph = this.canvasService.newCanvasGraph(this.options, this.ref); } public get nodes(): CanvasNode[] { @@ -99,9 +100,6 @@ export class GraphVisualComponent implements OnInit { public ngOnInit(): void { console.log("graph-visual: ngOnInit"); - - /** Receiving an initialized simulated graph from our custom canvas.service */ - this.canvasGraph = this.canvasService.newCanvasGraph(this.options, this.ref); } // TODO: Need to discuss how all the layout sizes affect each other. diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts index 4ab1a34a..1a67a828 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts @@ -34,6 +34,7 @@ import {ConfirmDialogComponent} from "@shared/confirm-dialog/confirm-dialog.comp import {CommandFactory} from "@dataservices/virtualization/view-editor/command/command-factory"; import {Command} from "@dataservices/virtualization/view-editor/command/command"; import {CreateViewDialogComponent} from "@dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component"; +import {ChangeDetectorRef} from "@angular/core"; @Component({ encapsulation: ViewEncapsulation.None, @@ -62,17 +63,20 @@ export class ViewsListComponent implements OnInit, OnDestroy, AfterViewInit { private viewsLoadingState: LoadingState = LoadingState.LOADING; private selectedVirtualization: Dataservice; private viewSavedUponCompletion: ViewDefinition; + private cdRef: ChangeDetectorRef; constructor( editorService: ViewEditorService, dataserviceService: DataserviceService, selectionService: SelectionService, logger: LoggerService, - modalService: BsModalService) { + modalService: BsModalService, + cdRef: ChangeDetectorRef) { this.editorService = editorService; this.dataserviceService = dataserviceService; this.selectionService = selectionService; this.logger = logger; this.modalService = modalService; + this.cdRef = cdRef; } /** @@ -136,12 +140,12 @@ export class ViewsListComponent implements OnInit, OnDestroy, AfterViewInit { emptyStateConfig: this.emptyStateConfig } as TableConfig; - } public ngAfterViewInit(): void { // init the available views this.initViews(); + this.cdRef.detectChanges(); } /* From ec4980b776c8bfadd6366c33f1c9199536010c27 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Wed, 24 Oct 2018 14:58:40 -0500 Subject: [PATCH 201/205] TT-465 Adjust preview SQL for duplicate symbols --- .../shared/view-definition.model.ts | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/ngapp/src/app/dataservices/shared/view-definition.model.ts b/ngapp/src/app/dataservices/shared/view-definition.model.ts index 04fe7803..815eb989 100644 --- a/ngapp/src/app/dataservices/shared/view-definition.model.ts +++ b/ngapp/src/app/dataservices/shared/view-definition.model.ts @@ -21,7 +21,7 @@ import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { CompositionOperator } from "@dataservices/shared/composition-operator.enum"; import { CompositionType } from "@dataservices/shared/composition-type.enum"; import { ProjectedColumn } from "@dataservices/shared/projected-column.model"; -import {select} from "d3-selection"; +import { select } from "d3-selection"; /** * ViewDefinition model @@ -388,38 +388,47 @@ export class ViewDefinition { */ private getProjectedColumnsSql(): string { // TODO: This function will need more work as the ViewDefinition is refined (addition of aliases, etc) - const finalColumnNames: string[] = []; - const duplicateNames: string[] = []; let sql = ""; - // Loop thru columns - create list and tag any duplicates + + // Determine duplicate names from all projected columns. They will need to be aliased so they are not ambiguous + const duplicateNames = this.getDuplicateColumnNames(this.getProjectedColumns()); + + // Build the sql from the selected columns const selectedCols = this.getSelectedProjectedColumns(); for ( let i = 0; i < selectedCols.length; i++ ) { - const col = selectedCols[i]; - const colName = this.getSqlColumnName(col); - // If column is a duplicate, flag it as such. Leave out of final list - if (finalColumnNames.indexOf(colName) !== -1) { - duplicateNames.push(colName); - } else { - finalColumnNames.push(colName); - } - } - - // Build the sql from the final list - for ( let j = 0; j < finalColumnNames.length; j++ ) { - // If column was a duplicate, qualify it as left table - const cName = finalColumnNames[j]; + // If column is a duplicate, qualify it as left table + const cName = this.getSqlColumnName(selectedCols[i]); if ( duplicateNames.indexOf(cName) !== -1 ) { sql = sql.concat("A." + cName); } else { sql = sql.concat(cName); } - if ( j < finalColumnNames.length - 1 ) { + if ( i < selectedCols.length - 1 ) { sql = sql.concat(", "); } } return sql; } + /** + * Get the array of duplicate column names. If no duplicates, an empty array is returned + * @param columns the array of columns to test + * @return the array of duplicate names in the supplied columns + */ + private getDuplicateColumnNames(columns: ProjectedColumn[]): string[] { + const allColNames: string[] = []; + const duplicateNames: string[] = []; + for ( const col of columns ) { + const colName = this.getSqlColumnName(col); + if (allColNames.indexOf(colName) !== -1) { + duplicateNames.push(colName); + } else { + allColNames.push(colName); + } + } + return duplicateNames; + } + /** * Get the name of the supplied column * @param col the column From b994c2da9b8bea432b29185fba8c6eefc567aba1 Mon Sep 17 00:00:00 2001 From: Mark Drilling Date: Fri, 26 Oct 2018 12:26:59 -0500 Subject: [PATCH 202/205] TT-465 fix ViewDefinition issue --- .../shared/view-definition.model.ts | 30 +++++++++++++++---- .../projected-columns-editor.component.html | 3 +- .../projected-columns-editor.component.ts | 11 +++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/ngapp/src/app/dataservices/shared/view-definition.model.ts b/ngapp/src/app/dataservices/shared/view-definition.model.ts index 815eb989..2c26a5df 100644 --- a/ngapp/src/app/dataservices/shared/view-definition.model.ts +++ b/ngapp/src/app/dataservices/shared/view-definition.model.ts @@ -21,7 +21,6 @@ import { VdbsConstants } from "@dataservices/shared/vdbs-constants"; import { CompositionOperator } from "@dataservices/shared/composition-operator.enum"; import { CompositionType } from "@dataservices/shared/composition-type.enum"; import { ProjectedColumn } from "@dataservices/shared/projected-column.model"; -import { select } from "d3-selection"; /** * ViewDefinition model @@ -34,6 +33,7 @@ export class ViewDefinition { private compositions: Composition[] = []; private isSelected = false; private projectedColumns: ProjectedColumn[] = []; + private defaultProjectedColumns: ProjectedColumn[] = []; /** * @param {Object} json the JSON representation of a ViewDefinition @@ -82,14 +82,15 @@ export class ViewDefinition { * Constructor */ constructor() { - // The ViewDefinition is initialized with 'SELECT *' - const prjCols: ProjectedColumn[] = []; + // Define the default projected columns ('SELECT *') const selectStar: ProjectedColumn = new ProjectedColumn(); selectStar.setName("ALL"); selectStar.setType("ALL"); selectStar.selected = true; - prjCols.push(selectStar); - this.setProjectedColumns(prjCols); + this.defaultProjectedColumns.push(selectStar); + + // Init the ViewDefinition with default projected columns + this.initProjectedColumns(); } /** @@ -132,6 +133,8 @@ export class ViewDefinition { */ public setSourcePaths( sourcePaths: string[] = [] ): void { this.sourcePaths = sourcePaths; + // change in source paths will re-init the projected columns + this.initProjectedColumns(); } /** @@ -146,6 +149,8 @@ export class ViewDefinition { */ public setCompositions( compositions: Composition[] = [] ): void { this.compositions = compositions; + // change in compositions will re-init the projected columns + this.initProjectedColumns(); } /** @@ -186,6 +191,8 @@ export class ViewDefinition { if ( index === -1 ) { this.compositions.push( compositionToAdd ); + // adding composition will re-init the projected columns + this.initProjectedColumns(); } } @@ -197,6 +204,8 @@ export class ViewDefinition { if ( index !== -1 ) { this.compositions.splice( index, 1 ); + // removing composition will re-init the projected columns + this.initProjectedColumns(); } } @@ -212,6 +221,8 @@ export class ViewDefinition { if ( index === -1 ) { this.sourcePaths.push( sourcePathToAdd ); + // adding source will re-init the projected columns + this.initProjectedColumns(); } } @@ -237,6 +248,8 @@ export class ViewDefinition { if ( index !== -1 ) { this.sourcePaths.splice( index, 1 ); + // remove source will re-init the projected columns + this.initProjectedColumns(); } } @@ -382,6 +395,13 @@ export class ViewDefinition { return this.getProjectedColumns().length === 1 && this.getProjectedColumns()[0].getName() === "ALL" && this.getProjectedColumns()[0].getType() === "ALL"; } + /** + * Initializes the projected columns for this view. This resets the view projected columns to "*" ("ALL") + */ + private initProjectedColumns(): void { + this.setProjectedColumns(this.defaultProjectedColumns); + } + /** * Get the SQL string for the current projected columns * @return {string} the projected columns SQL diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html index 9dc48718..3d61ebbe 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html @@ -7,7 +7,8 @@

    No View Selected

    View Columns

    -

    All columns included. Save the view to populate the specific columns

    +

    All view columns are included.

    +
    Save the view to populate columns table
    diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts index 261bbfb7..4198c63f 100644 --- a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts +++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts @@ -11,6 +11,10 @@ import { LoggerService } from "@core/logger.service"; import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event"; import { Subscription } from "rxjs/Subscription"; import { UpdateProjectedColumnsCommand } from "@dataservices/virtualization/view-editor/command/update-projected-columns-command"; +import { AddSourcesCommand } from "@dataservices/virtualization/view-editor/command/add-sources-command"; +import { RemoveSourcesCommand } from "@dataservices/virtualization/view-editor/command/remove-sources-command"; +import { AddCompositionCommand } from "@dataservices/virtualization/view-editor/command/add-composition-command"; +import { RemoveCompositionCommand } from "@dataservices/virtualization/view-editor/command/remove-composition-command"; @Component({ selector: 'app-projected-columns-editor', @@ -100,9 +104,16 @@ export class ProjectedColumnsEditorComponent implements OnInit, OnDestroy { if ( event.args.length === 1 && event.args[ 0 ] instanceof Command ) { const cmd = event.args[ 0 ] as Command; + // Handle updated projected columns if ( cmd instanceof UpdateProjectedColumnsCommand ) { this.updateProjectedColumns(cmd.getNewProjectedColumns()); } + // Change in sources or compositions - forces a reset of the columns + else if ( cmd instanceof AddSourcesCommand || cmd instanceof RemoveSourcesCommand || + cmd instanceof AddCompositionCommand || cmd instanceof RemoveCompositionCommand ) { + const viewDefn = this.editorService.getEditorView(); + this.initProjectedColumns(viewDefn.getProjectedColumns()); + } } } } From f5cea9c567d3c2d7387281ff03014934d46c5408 Mon Sep 17 00:00:00 2001 From: Ramesh Reddy Date: Wed, 31 Oct 2018 16:05:21 -0500 Subject: [PATCH 203/205] beetle move --- {ngapp => ui}/.angular-cli.json | 0 {ngapp => ui}/.editorconfig | 0 {ngapp => ui}/README.md | 0 {ngapp => ui}/e2e/app.e2e-spec.ts | 0 {ngapp => ui}/e2e/app.po.ts | 0 {ngapp => ui}/e2e/tsconfig.e2e.json | 0 {ngapp => ui}/karma.conf.js | 0 {ngapp => ui}/locale/README.md | 0 {ngapp => ui}/locale/messages.es.xlf | 0 {ngapp => ui}/messages.xlf | 0 {ngapp => ui}/package-lock.json | 0 {ngapp => ui}/package.json | 0 {ngapp => ui}/protractor.conf.js | 0 {ngapp => ui}/server.js | 0 {ngapp => ui}/src/app/app-routing.module.ts | 0 {ngapp => ui}/src/app/app.component.css | 0 {ngapp => ui}/src/app/app.component.html | 0 {ngapp => ui}/src/app/app.component.spec.ts | 0 {ngapp => ui}/src/app/app.component.ts | 0 {ngapp => ui}/src/app/app.module.ts | 0 .../add-connection-wizard.component.css | 0 .../add-connection-wizard.component.html | 0 .../add-connection-wizard.component.spec.ts | 0 .../add-connection-wizard.component.ts | 0 .../add-connection/add-connection.component.css | 0 .../add-connection/add-connection.component.html | 0 .../add-connection/add-connection.component.spec.ts | 0 .../add-connection/add-connection.component.ts | 0 .../connection-type-card.component.css | 0 .../connection-type-card.component.html | 0 .../connection-type-card.component.spec.ts | 0 .../connection-type-card.component.ts | 0 .../connection-type-cards.component.css | 0 .../connection-type-cards.component.html | 0 .../connection-type-cards.component.spec.ts | 0 .../connection-type-cards.component.ts | 0 .../connection-card/connection-card.component.css | 0 .../connection-card/connection-card.component.html | 0 .../connection-card.component.spec.ts | 0 .../connection-card/connection-card.component.ts | 0 .../connections-cards.component.css | 0 .../connections-cards.component.html | 0 .../connections-cards.component.spec.ts | 0 .../connections-cards.component.ts | 0 .../connection-details.component.html | 0 .../connection-details.component.ts | 0 .../connections-list/connections-list.component.css | 0 .../connections-list.component.html | 0 .../connections-list.component.spec.ts | 0 .../connections-list/connections-list.component.ts | 0 .../app/connections/connections-routing.module.ts | 0 .../src/app/connections/connections.component.css | 0 .../src/app/connections/connections.component.html | 0 .../app/connections/connections.component.spec.ts | 0 .../src/app/connections/connections.component.ts | 0 .../src/app/connections/connections.module.ts | 0 .../connections/shared/connection-status.spec.ts | 0 .../src/app/connections/shared/connection-status.ts | 0 .../app/connections/shared/connection-type.model.ts | 0 .../app/connections/shared/connection.model.spec.ts | 0 .../src/app/connections/shared/connection.model.ts | 0 .../connections/shared/connection.service.spec.ts | 0 .../app/connections/shared/connection.service.ts | 0 .../app/connections/shared/connections-constants.ts | 0 .../connections/shared/mock-connection.service.ts | 0 .../app/connections/shared/new-connection.model.ts | 0 .../connections/shared/schema-node.model.spec.ts | 0 .../src/app/connections/shared/schema-node.model.ts | 0 .../shared/service-catalog-source.model.spec.ts | 0 .../shared/service-catalog-source.model.ts | 0 .../core/about-dialog/about-dialog.component.css | 0 .../core/about-dialog/about-dialog.component.html | 0 .../about-dialog/about-dialog.component.spec.ts | 0 .../app/core/about-dialog/about-dialog.component.ts | 0 .../src/app/core/about-dialog/about-event.ts | 0 .../src/app/core/about-dialog/about.model.ts | 0 .../src/app/core/about-dialog/about.service.spec.ts | 0 .../src/app/core/about-dialog/about.service.ts | 0 .../src/app/core/about-dialog/mock-about.service.ts | 0 {ngapp => ui}/src/app/core/api.service.spec.ts | 0 {ngapp => ui}/src/app/core/api.service.ts | 0 .../src/app/core/app-settings.service.spec.ts | 0 {ngapp => ui}/src/app/core/app-settings.service.ts | 0 .../breadcrumbs/breadcrumb/breadcrumb.component.css | 0 .../breadcrumb/breadcrumb.component.html | 0 .../breadcrumb/breadcrumb.component.spec.ts | 0 .../breadcrumbs/breadcrumb/breadcrumb.component.ts | 0 .../app/core/breadcrumbs/breadcrumbs.component.css | 0 .../app/core/breadcrumbs/breadcrumbs.component.html | 0 .../core/breadcrumbs/breadcrumbs.component.spec.ts | 0 .../app/core/breadcrumbs/breadcrumbs.component.ts | 0 {ngapp => ui}/src/app/core/core.less | 0 {ngapp => ui}/src/app/core/core.module.ts | 0 {ngapp => ui}/src/app/core/logger.service.spec.ts | 0 {ngapp => ui}/src/app/core/logger.service.ts | 0 .../src/app/core/mock-app-settings.service.ts | 0 .../src/app/core/selection.service.spec.ts | 0 {ngapp => ui}/src/app/core/selection.service.ts | 0 {ngapp => ui}/src/app/core/utils/array-utils.ts | 0 {ngapp => ui}/src/app/core/utils/object-utils.ts | 0 .../core/vertical-nav/vertical-nav.component.css | 0 .../core/vertical-nav/vertical-nav.component.html | 0 .../vertical-nav/vertical-nav.component.spec.ts | 0 .../app/core/vertical-nav/vertical-nav.component.ts | 0 .../create-views-dialog.component.css | 0 .../create-views-dialog.component.html | 0 .../create-views-dialog.component.spec.ts | 0 .../create-views-dialog.component.ts | 0 .../create-views-result.model.ts | 0 .../create-views-dialog/new-view.model.ts | 0 .../dataservice-card/dataservice-card.component.css | 0 .../dataservice-card.component.html | 0 .../dataservice-card.component.spec.ts | 0 .../dataservice-card/dataservice-card.component.ts | 0 .../dataservices-cards.component.css | 0 .../dataservices-cards.component.html | 0 .../dataservices-cards.component.spec.ts | 0 .../dataservices-cards.component.ts | 0 .../dataservices-details.component.html | 0 .../dataservices-details.component.ts | 0 .../dataservices-list.component.css | 0 .../dataservices-list.component.html | 0 .../dataservices-list.component.spec.ts | 0 .../dataservices-list.component.ts | 0 .../dataservices-list/views-content.component.html | 0 .../dataservices-list/views-content.component.ts | 0 .../app/dataservices/dataservices-routing.module.ts | 0 .../src/app/dataservices/dataservices.component.css | 0 .../app/dataservices/dataservices.component.html | 0 .../app/dataservices/dataservices.component.spec.ts | 0 .../src/app/dataservices/dataservices.component.ts | 0 .../src/app/dataservices/dataservices.module.ts | 0 .../odata-control/odata-column.model.ts | 0 .../odata-control/odata-conditions.model.ts | 0 .../dataservices/odata-control/odata-constants.ts | 0 .../odata-control/odata-control.component.css | 0 .../odata-control/odata-control.component.html | 0 .../odata-control/odata-control.component.ts | 0 .../odata-control/odata-entity.model.ts | 0 .../dataservices/odata-control/odata-where.model.ts | 0 .../app/dataservices/odata-control/odata.model.ts | 0 .../selected-node/selected-node.component.css | 0 .../selected-node/selected-node.component.html | 0 .../selected-node/selected-node.component.spec.ts | 0 .../selected-node/selected-node.component.ts | 0 .../selected-nodes-list.component.css | 0 .../selected-nodes-list.component.html | 0 .../selected-nodes-list.component.spec.ts | 0 .../selected-nodes-list.component.ts | 0 .../set-description-dialog.component.css | 0 .../set-description-dialog.component.html | 0 .../set-description-dialog.component.spec.ts | 0 .../set-description-dialog.component.ts | 0 .../app/dataservices/shared/column-data.model.ts | 0 .../app/dataservices/shared/column.model.spec.ts | 0 .../src/app/dataservices/shared/column.model.ts | 0 .../shared/composition-operator.enum.ts | 0 .../dataservices/shared/composition-type.enum.ts | 0 .../dataservices/shared/composition.model.spec.ts | 0 .../app/dataservices/shared/composition.model.ts | 0 .../shared/connection-summary.model.spec.ts | 0 .../dataservices/shared/connection-summary.model.ts | 0 .../dataservices/shared/dataservice.model.spec.ts | 0 .../app/dataservices/shared/dataservice.model.ts | 0 .../dataservices/shared/dataservice.service.spec.ts | 0 .../app/dataservices/shared/dataservice.service.ts | 0 .../dataservices/shared/dataservices-constants.ts | 0 .../dataservices/shared/deployment-state.enum.ts | 0 .../dataservices/shared/mock-dataservice.service.ts | 0 .../src/app/dataservices/shared/mock-vdb.service.ts | 0 .../src/app/dataservices/shared/name-value.model.ts | 0 .../dataservices/shared/new-dataservice.model.ts | 0 .../src/app/dataservices/shared/node-selector.ts | 0 .../dataservices/shared/notifier.service.spec.ts | 0 .../src/app/dataservices/shared/notifier.service.ts | 0 .../src/app/dataservices/shared/path-utils.ts | 0 .../shared/projected-column.model.spec.ts | 0 .../dataservices/shared/projected-column.model.ts | 0 .../app/dataservices/shared/publish-state.enum.ts | 0 .../dataservices/shared/query-results.model.spec.ts | 0 .../app/dataservices/shared/query-results.model.ts | 0 .../src/app/dataservices/shared/row-data.model.ts | 0 .../src/app/dataservices/shared/sql-view.model.ts | 0 .../dataservices/shared/vdb-model-source.model.ts | 0 .../src/app/dataservices/shared/vdb-model.model.ts | 0 .../dataservices/shared/vdb-status.model.spec.ts | 0 .../src/app/dataservices/shared/vdb-status.model.ts | 0 .../src/app/dataservices/shared/vdb.model.ts | 0 .../src/app/dataservices/shared/vdb.service.spec.ts | 0 .../src/app/dataservices/shared/vdb.service.ts | 0 .../src/app/dataservices/shared/vdbs-constants.ts | 0 .../shared/view-definition.model.spec.ts | 0 .../dataservices/shared/view-definition.model.ts | 0 .../shared/view-editor-state.model.spec.ts | 0 .../dataservices/shared/view-editor-state.model.ts | 0 .../src/app/dataservices/shared/virt-route.model.ts | 0 .../shared/virtualization.model.spec.ts | 0 .../app/dataservices/shared/virtualization.model.ts | 0 .../sql-control/sql-control.component.css | 0 .../sql-control/sql-control.component.html | 0 .../sql-control/sql-control.component.spec.ts | 0 .../sql-control/sql-control.component.ts | 0 .../test-dataservice/test-dataservice.component.css | 0 .../test-dataservice.component.html | 0 .../test-dataservice.component.spec.ts | 0 .../test-dataservice/test-dataservice.component.ts | 0 .../add-composition-wizard.component.css | 0 .../add-composition-wizard.component.html | 0 .../add-composition-wizard.component.spec.ts | 0 .../add-composition-wizard.component.ts | 0 .../view-editor/command/add-composition-command.ts | 0 .../view-editor/command/add-sources-command.ts | 0 .../view-editor/command/command-factory.spec.ts | 0 .../view-editor/command/command-factory.ts | 0 .../view-editor/command/command-type.enum.ts | 0 .../virtualization/view-editor/command/command.ts | 0 .../view-editor/command/no-op-command.ts | 0 .../command/remove-composition-command.ts | 0 .../view-editor/command/remove-sources-command.ts | 0 .../command/undo-redo/undo-manager.spec.ts | 0 .../view-editor/command/undo-redo/undo-manager.ts | 0 .../view-editor/command/undo-redo/undo-node.ts | 0 .../view-editor/command/undo-redo/undoable.spec.ts | 0 .../view-editor/command/undo-redo/undoable.ts | 0 .../command/update-projected-columns-command.ts | 0 .../command/update-view-description-command.ts | 0 .../view-editor/command/update-view-name-command.ts | 0 .../connection-table-dialog.component.css | 0 .../connection-table-dialog.component.html | 0 .../connection-table-dialog.component.spec.ts | 0 .../connection-table-dialog.component.ts | 0 .../connection-tree-selector.component.css | 0 .../connection-tree-selector.component.html | 0 .../connection-tree-selector.component.spec.ts | 0 .../connection-tree-selector.component.ts | 0 .../create-view-dialog.component.css | 0 .../create-view-dialog.component.html | 0 .../create-view-dialog.component.spec.ts | 0 .../create-view-dialog.component.ts | 0 .../editor-views/editor-views.component.css | 0 .../editor-views/editor-views.component.html | 0 .../editor-views/editor-views.component.spec.ts | 0 .../editor-views/editor-views.component.ts | 0 .../message-log/message-log.component.css | 0 .../message-log/message-log.component.html | 0 .../message-log/message-log.component.spec.ts | 0 .../message-log/message-log.component.ts | 0 .../editor-views/message-log/message-type.enum.ts | 0 .../view-editor/editor-views/message-log/message.ts | 0 .../view-editor/editor-views/message-log/problem.ts | 0 .../view-preview/view-preview.component.css | 0 .../view-preview/view-preview.component.html | 0 .../view-preview/view-preview.component.spec.ts | 0 .../view-preview/view-preview.component.ts | 0 .../event/view-editor-event-type.enum.ts | 0 .../view-editor/event/view-editor-event.ts | 0 .../view-editor-save-progress-change-id.enum.ts | 0 .../view-editor/view-canvas/canvas-constants.ts | 0 .../view-editor/view-canvas/canvas.service.ts | 0 .../event/view-canvas-event-type.enum.ts | 0 .../view-canvas/event/view-canvas-event.ts | 0 .../view-editor/view-canvas/models/canvas-graph.ts | 0 .../view-editor/view-canvas/models/canvas-link.ts | 0 .../view-canvas/models/canvas-node.spec.ts | 0 .../view-editor/view-canvas/models/canvas-node.ts | 0 .../view-editor/view-canvas/models/index.ts | 0 .../view-canvas/view-canvas.component.css | 0 .../view-canvas/view-canvas.component.html | 0 .../view-canvas/view-canvas.component.spec.ts | 0 .../view-canvas/view-canvas.component.ts | 0 .../visuals/graph/graph-visual.component.css | 0 .../visuals/graph/graph-visual.component.ts | 0 .../view-editor/view-canvas/visuals/index.ts | 0 .../visuals/link/link-visual.component.css | 0 .../visuals/link/link-visual.component.ts | 0 .../visuals/node/node-visual.component.css | 0 .../visuals/node/node-visual.component.ts | 0 .../view-editor-header.component.css | 0 .../view-editor-header.component.html | 0 .../view-editor-header.component.spec.ts | 0 .../view-editor-header.component.ts | 0 .../virtualization/view-editor/view-editor-i18n.ts | 0 .../view-editor/view-editor-part.enum.ts | 0 .../view-editor/view-editor.component.css | 0 .../view-editor/view-editor.component.html | 0 .../view-editor/view-editor.component.spec.ts | 0 .../view-editor/view-editor.component.ts | 0 .../view-editor/view-editor.service.spec.ts | 0 .../view-editor/view-editor.service.ts | 0 .../projected-columns-editor.component.css | 0 .../projected-columns-editor.component.html | 0 .../projected-columns-editor.component.spec.ts | 0 .../projected-columns-editor.component.ts | 0 .../property-editor/property-editor.component.css | 0 .../property-editor/property-editor.component.html | 0 .../property-editor.component.spec.ts | 0 .../property-editor/property-editor.component.ts | 0 .../property-editor/selection-item.model.ts | 0 .../property-editor/selection-type.enum.ts | 0 .../view-property-editors.component.css | 0 .../view-property-editors.component.html | 0 .../view-property-editors.component.spec.ts | 0 .../view-property-editors.component.ts | 0 .../virtualization/view-editor/view-validator.ts | 0 .../view-editor/views-list/views-list.component.css | 0 .../views-list/views-list.component.html | 0 .../views-list/views-list.component.spec.ts | 0 .../view-editor/views-list/views-list.component.ts | 0 .../src/app/shared/abstract-page.component.ts | 0 .../confirm-dialog/confirm-dialog.component.css | 0 .../confirm-dialog/confirm-dialog.component.html | 0 .../confirm-dialog/confirm-dialog.component.spec.ts | 0 .../confirm-dialog/confirm-dialog.component.ts | 0 {ngapp => ui}/src/app/shared/id-filter.ts | 0 {ngapp => ui}/src/app/shared/identifiable.ts | 0 {ngapp => ui}/src/app/shared/layout-type.enum.ts | 0 {ngapp => ui}/src/app/shared/loading-state.enum.ts | 0 .../app/shared/page-error/page-error.component.css | 0 .../app/shared/page-error/page-error.component.html | 0 .../shared/page-error/page-error.component.spec.ts | 0 .../app/shared/page-error/page-error.component.ts | 0 .../page-not-found/page-not-found.component.css | 0 .../page-not-found/page-not-found.component.html | 0 .../page-not-found/page-not-found.component.spec.ts | 0 .../page-not-found/page-not-found.component.ts | 0 .../progress-dialog/progress-dialog.component.css | 0 .../progress-dialog/progress-dialog.component.html | 0 .../progress-dialog.component.spec.ts | 0 .../progress-dialog/progress-dialog.component.ts | 0 .../property-form/property-control-type.enum.ts | 0 .../property-form/property-definition.model.ts | 0 .../property-form-property.component.css | 0 .../property-form-property.component.html | 0 .../property-form-property.component.spec.ts | 0 .../property-form-property.component.ts | 0 .../property-form/property-form.component.css | 0 .../property-form/property-form.component.html | 0 .../property-form/property-form.component.spec.ts | 0 .../shared/property-form/property-form.component.ts | 0 {ngapp => ui}/src/app/shared/shared.module.ts | 0 .../src/app/shared/slide-in/slide-in.component.css | 0 .../src/app/shared/slide-in/slide-in.component.html | 0 .../app/shared/slide-in/slide-in.component.spec.ts | 0 .../src/app/shared/slide-in/slide-in.component.ts | 0 {ngapp => ui}/src/app/shared/sort-direction.enum.ts | 0 .../src/app/shared/test-data.service.spec.ts | 0 {ngapp => ui}/src/app/shared/test-data.service.ts | 0 .../src/app/shared/validators/name-validator.ts | 0 {ngapp => ui}/src/assets/.gitkeep | 0 {ngapp => ui}/src/assets/MongoDB_70x40.png | Bin {ngapp => ui}/src/assets/MySQL_70x40.png | Bin {ngapp => ui}/src/assets/PostgresSql_70x40.png | Bin {ngapp => ui}/src/assets/composition.png | Bin .../src/assets/graphicsfuel/database-64.png | Bin {ngapp => ui}/src/assets/graphicsfuel/readme.txt | 0 .../src/assets/iconfinder/Aha-soft/license.pdf | Bin .../assets/iconfinder/Aha-soft/minus-depressed.png | Bin .../src/assets/iconfinder/Aha-soft/minus.png | Bin .../assets/iconfinder/Aha-soft/plus-depressed.png | Bin .../src/assets/iconfinder/Aha-soft/plus.png | Bin .../assets/iconfinder/Natalya-Skidan/license.pdf | 0 .../iconfinder/Natalya-Skidan/question-mark.png | Bin .../src/assets/iconfinder/creative-commons.pdf | Bin {ngapp => ui}/src/assets/redhat-iot.png | Bin {ngapp => ui}/src/assets/salesforce_40x40.png | Bin {ngapp => ui}/src/assets/table.png | Bin .../src/assets/teiid-lizard-gradient-bgd.png | Bin {ngapp => ui}/src/assets/vdb.png | Bin {ngapp => ui}/src/environments/environment.prod.ts | 0 {ngapp => ui}/src/environments/environment.ts | 0 {ngapp => ui}/src/favicon.ico | Bin {ngapp => ui}/src/index.html | 0 {ngapp => ui}/src/main.ts | 0 {ngapp => ui}/src/polyfills.ts | 0 {ngapp => ui}/src/styles.css | 0 {ngapp => ui}/src/test.ts | 0 {ngapp => ui}/src/tsconfig.app.json | 0 {ngapp => ui}/src/tsconfig.spec.json | 0 {ngapp => ui}/src/typings.d.ts | 0 {ngapp => ui}/start.sh | 0 {ngapp => ui}/tsconfig.json | 0 {ngapp => ui}/tslint.json | 0 382 files changed, 0 insertions(+), 0 deletions(-) rename {ngapp => ui}/.angular-cli.json (100%) rename {ngapp => ui}/.editorconfig (100%) rename {ngapp => ui}/README.md (100%) rename {ngapp => ui}/e2e/app.e2e-spec.ts (100%) rename {ngapp => ui}/e2e/app.po.ts (100%) rename {ngapp => ui}/e2e/tsconfig.e2e.json (100%) rename {ngapp => ui}/karma.conf.js (100%) rename {ngapp => ui}/locale/README.md (100%) rename {ngapp => ui}/locale/messages.es.xlf (100%) rename {ngapp => ui}/messages.xlf (100%) rename {ngapp => ui}/package-lock.json (100%) rename {ngapp => ui}/package.json (100%) rename {ngapp => ui}/protractor.conf.js (100%) rename {ngapp => ui}/server.js (100%) rename {ngapp => ui}/src/app/app-routing.module.ts (100%) rename {ngapp => ui}/src/app/app.component.css (100%) rename {ngapp => ui}/src/app/app.component.html (100%) rename {ngapp => ui}/src/app/app.component.spec.ts (100%) rename {ngapp => ui}/src/app/app.component.ts (100%) rename {ngapp => ui}/src/app/app.module.ts (100%) rename {ngapp => ui}/src/app/connections/add-connection-wizard/add-connection-wizard.component.css (100%) rename {ngapp => ui}/src/app/connections/add-connection-wizard/add-connection-wizard.component.html (100%) rename {ngapp => ui}/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts (100%) rename {ngapp => ui}/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts (100%) rename {ngapp => ui}/src/app/connections/add-connection/add-connection.component.css (100%) rename {ngapp => ui}/src/app/connections/add-connection/add-connection.component.html (100%) rename {ngapp => ui}/src/app/connections/add-connection/add-connection.component.spec.ts (100%) rename {ngapp => ui}/src/app/connections/add-connection/add-connection.component.ts (100%) rename {ngapp => ui}/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css (100%) rename {ngapp => ui}/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.html (100%) rename {ngapp => ui}/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.spec.ts (100%) rename {ngapp => ui}/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.ts (100%) rename {ngapp => ui}/src/app/connections/connection-type-cards/connection-type-cards.component.css (100%) rename {ngapp => ui}/src/app/connections/connection-type-cards/connection-type-cards.component.html (100%) rename {ngapp => ui}/src/app/connections/connection-type-cards/connection-type-cards.component.spec.ts (100%) rename {ngapp => ui}/src/app/connections/connection-type-cards/connection-type-cards.component.ts (100%) rename {ngapp => ui}/src/app/connections/connections-cards/connection-card/connection-card.component.css (100%) rename {ngapp => ui}/src/app/connections/connections-cards/connection-card/connection-card.component.html (100%) rename {ngapp => ui}/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts (100%) rename {ngapp => ui}/src/app/connections/connections-cards/connection-card/connection-card.component.ts (100%) rename {ngapp => ui}/src/app/connections/connections-cards/connections-cards.component.css (100%) rename {ngapp => ui}/src/app/connections/connections-cards/connections-cards.component.html (100%) rename {ngapp => ui}/src/app/connections/connections-cards/connections-cards.component.spec.ts (100%) rename {ngapp => ui}/src/app/connections/connections-cards/connections-cards.component.ts (100%) rename {ngapp => ui}/src/app/connections/connections-list/connection-details.component.html (100%) rename {ngapp => ui}/src/app/connections/connections-list/connection-details.component.ts (100%) rename {ngapp => ui}/src/app/connections/connections-list/connections-list.component.css (100%) rename {ngapp => ui}/src/app/connections/connections-list/connections-list.component.html (100%) rename {ngapp => ui}/src/app/connections/connections-list/connections-list.component.spec.ts (100%) rename {ngapp => ui}/src/app/connections/connections-list/connections-list.component.ts (100%) rename {ngapp => ui}/src/app/connections/connections-routing.module.ts (100%) rename {ngapp => ui}/src/app/connections/connections.component.css (100%) rename {ngapp => ui}/src/app/connections/connections.component.html (100%) rename {ngapp => ui}/src/app/connections/connections.component.spec.ts (100%) rename {ngapp => ui}/src/app/connections/connections.component.ts (100%) rename {ngapp => ui}/src/app/connections/connections.module.ts (100%) rename {ngapp => ui}/src/app/connections/shared/connection-status.spec.ts (100%) rename {ngapp => ui}/src/app/connections/shared/connection-status.ts (100%) rename {ngapp => ui}/src/app/connections/shared/connection-type.model.ts (100%) rename {ngapp => ui}/src/app/connections/shared/connection.model.spec.ts (100%) rename {ngapp => ui}/src/app/connections/shared/connection.model.ts (100%) rename {ngapp => ui}/src/app/connections/shared/connection.service.spec.ts (100%) rename {ngapp => ui}/src/app/connections/shared/connection.service.ts (100%) rename {ngapp => ui}/src/app/connections/shared/connections-constants.ts (100%) rename {ngapp => ui}/src/app/connections/shared/mock-connection.service.ts (100%) rename {ngapp => ui}/src/app/connections/shared/new-connection.model.ts (100%) rename {ngapp => ui}/src/app/connections/shared/schema-node.model.spec.ts (100%) rename {ngapp => ui}/src/app/connections/shared/schema-node.model.ts (100%) rename {ngapp => ui}/src/app/connections/shared/service-catalog-source.model.spec.ts (100%) rename {ngapp => ui}/src/app/connections/shared/service-catalog-source.model.ts (100%) rename {ngapp => ui}/src/app/core/about-dialog/about-dialog.component.css (100%) rename {ngapp => ui}/src/app/core/about-dialog/about-dialog.component.html (100%) rename {ngapp => ui}/src/app/core/about-dialog/about-dialog.component.spec.ts (100%) rename {ngapp => ui}/src/app/core/about-dialog/about-dialog.component.ts (100%) rename {ngapp => ui}/src/app/core/about-dialog/about-event.ts (100%) rename {ngapp => ui}/src/app/core/about-dialog/about.model.ts (100%) rename {ngapp => ui}/src/app/core/about-dialog/about.service.spec.ts (100%) rename {ngapp => ui}/src/app/core/about-dialog/about.service.ts (100%) rename {ngapp => ui}/src/app/core/about-dialog/mock-about.service.ts (100%) rename {ngapp => ui}/src/app/core/api.service.spec.ts (100%) rename {ngapp => ui}/src/app/core/api.service.ts (100%) rename {ngapp => ui}/src/app/core/app-settings.service.spec.ts (100%) rename {ngapp => ui}/src/app/core/app-settings.service.ts (100%) rename {ngapp => ui}/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css (100%) rename {ngapp => ui}/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html (100%) rename {ngapp => ui}/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts (100%) rename {ngapp => ui}/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts (100%) rename {ngapp => ui}/src/app/core/breadcrumbs/breadcrumbs.component.css (100%) rename {ngapp => ui}/src/app/core/breadcrumbs/breadcrumbs.component.html (100%) rename {ngapp => ui}/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts (100%) rename {ngapp => ui}/src/app/core/breadcrumbs/breadcrumbs.component.ts (100%) rename {ngapp => ui}/src/app/core/core.less (100%) rename {ngapp => ui}/src/app/core/core.module.ts (100%) rename {ngapp => ui}/src/app/core/logger.service.spec.ts (100%) rename {ngapp => ui}/src/app/core/logger.service.ts (100%) rename {ngapp => ui}/src/app/core/mock-app-settings.service.ts (100%) rename {ngapp => ui}/src/app/core/selection.service.spec.ts (100%) rename {ngapp => ui}/src/app/core/selection.service.ts (100%) rename {ngapp => ui}/src/app/core/utils/array-utils.ts (100%) rename {ngapp => ui}/src/app/core/utils/object-utils.ts (100%) rename {ngapp => ui}/src/app/core/vertical-nav/vertical-nav.component.css (100%) rename {ngapp => ui}/src/app/core/vertical-nav/vertical-nav.component.html (100%) rename {ngapp => ui}/src/app/core/vertical-nav/vertical-nav.component.spec.ts (100%) rename {ngapp => ui}/src/app/core/vertical-nav/vertical-nav.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/create-views-dialog/create-views-dialog.component.css (100%) rename {ngapp => ui}/src/app/dataservices/create-views-dialog/create-views-dialog.component.html (100%) rename {ngapp => ui}/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/create-views-dialog/create-views-result.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/create-views-dialog/new-view.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-cards/dataservices-cards.component.css (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-cards/dataservices-cards.component.html (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-list/dataservices-details.component.html (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-list/dataservices-details.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-list/dataservices-list.component.css (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-list/dataservices-list.component.html (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-list/dataservices-list.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-list/views-content.component.html (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-list/views-content.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices-routing.module.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices.component.css (100%) rename {ngapp => ui}/src/app/dataservices/dataservices.component.html (100%) rename {ngapp => ui}/src/app/dataservices/dataservices.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/dataservices.module.ts (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata-column.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata-conditions.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata-constants.ts (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata-control.component.css (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata-control.component.html (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata-control.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata-entity.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata-where.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/odata-control/odata.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/selected-node/selected-node.component.css (100%) rename {ngapp => ui}/src/app/dataservices/selected-node/selected-node.component.html (100%) rename {ngapp => ui}/src/app/dataservices/selected-node/selected-node.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/selected-node/selected-node.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css (100%) rename {ngapp => ui}/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html (100%) rename {ngapp => ui}/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/set-description-dialog/set-description-dialog.component.css (100%) rename {ngapp => ui}/src/app/dataservices/set-description-dialog/set-description-dialog.component.html (100%) rename {ngapp => ui}/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/column-data.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/column.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/column.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/composition-operator.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/composition-type.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/composition.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/composition.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/connection-summary.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/connection-summary.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/dataservice.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/dataservice.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/dataservice.service.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/dataservice.service.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/dataservices-constants.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/deployment-state.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/mock-dataservice.service.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/mock-vdb.service.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/name-value.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/new-dataservice.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/node-selector.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/notifier.service.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/notifier.service.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/path-utils.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/projected-column.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/projected-column.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/publish-state.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/query-results.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/query-results.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/row-data.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/sql-view.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/vdb-model-source.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/vdb-model.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/vdb-status.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/vdb-status.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/vdb.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/vdb.service.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/vdb.service.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/vdbs-constants.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/view-definition.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/view-definition.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/view-editor-state.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/view-editor-state.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/virt-route.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/virtualization.model.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/shared/virtualization.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/sql-control/sql-control.component.css (100%) rename {ngapp => ui}/src/app/dataservices/sql-control/sql-control.component.html (100%) rename {ngapp => ui}/src/app/dataservices/sql-control/sql-control.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/sql-control/sql-control.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/test-dataservice/test-dataservice.component.css (100%) rename {ngapp => ui}/src/app/dataservices/test-dataservice/test-dataservice.component.html (100%) rename {ngapp => ui}/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/test-dataservice/test-dataservice.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/command-factory.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/command-factory.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-node.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-type.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/event/view-editor-event-type.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/canvas-constants.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event-type.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-link.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/models/index.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/index.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-editor.service.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/view-validator.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts (100%) rename {ngapp => ui}/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts (100%) rename {ngapp => ui}/src/app/shared/abstract-page.component.ts (100%) rename {ngapp => ui}/src/app/shared/confirm-dialog/confirm-dialog.component.css (100%) rename {ngapp => ui}/src/app/shared/confirm-dialog/confirm-dialog.component.html (100%) rename {ngapp => ui}/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts (100%) rename {ngapp => ui}/src/app/shared/confirm-dialog/confirm-dialog.component.ts (100%) rename {ngapp => ui}/src/app/shared/id-filter.ts (100%) rename {ngapp => ui}/src/app/shared/identifiable.ts (100%) rename {ngapp => ui}/src/app/shared/layout-type.enum.ts (100%) rename {ngapp => ui}/src/app/shared/loading-state.enum.ts (100%) rename {ngapp => ui}/src/app/shared/page-error/page-error.component.css (100%) rename {ngapp => ui}/src/app/shared/page-error/page-error.component.html (100%) rename {ngapp => ui}/src/app/shared/page-error/page-error.component.spec.ts (100%) rename {ngapp => ui}/src/app/shared/page-error/page-error.component.ts (100%) rename {ngapp => ui}/src/app/shared/page-not-found/page-not-found.component.css (100%) rename {ngapp => ui}/src/app/shared/page-not-found/page-not-found.component.html (100%) rename {ngapp => ui}/src/app/shared/page-not-found/page-not-found.component.spec.ts (100%) rename {ngapp => ui}/src/app/shared/page-not-found/page-not-found.component.ts (100%) rename {ngapp => ui}/src/app/shared/progress-dialog/progress-dialog.component.css (100%) rename {ngapp => ui}/src/app/shared/progress-dialog/progress-dialog.component.html (100%) rename {ngapp => ui}/src/app/shared/progress-dialog/progress-dialog.component.spec.ts (100%) rename {ngapp => ui}/src/app/shared/progress-dialog/progress-dialog.component.ts (100%) rename {ngapp => ui}/src/app/shared/property-form/property-control-type.enum.ts (100%) rename {ngapp => ui}/src/app/shared/property-form/property-definition.model.ts (100%) rename {ngapp => ui}/src/app/shared/property-form/property-form-property/property-form-property.component.css (100%) rename {ngapp => ui}/src/app/shared/property-form/property-form-property/property-form-property.component.html (100%) rename {ngapp => ui}/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts (100%) rename {ngapp => ui}/src/app/shared/property-form/property-form-property/property-form-property.component.ts (100%) rename {ngapp => ui}/src/app/shared/property-form/property-form.component.css (100%) rename {ngapp => ui}/src/app/shared/property-form/property-form.component.html (100%) rename {ngapp => ui}/src/app/shared/property-form/property-form.component.spec.ts (100%) rename {ngapp => ui}/src/app/shared/property-form/property-form.component.ts (100%) rename {ngapp => ui}/src/app/shared/shared.module.ts (100%) rename {ngapp => ui}/src/app/shared/slide-in/slide-in.component.css (100%) rename {ngapp => ui}/src/app/shared/slide-in/slide-in.component.html (100%) rename {ngapp => ui}/src/app/shared/slide-in/slide-in.component.spec.ts (100%) rename {ngapp => ui}/src/app/shared/slide-in/slide-in.component.ts (100%) rename {ngapp => ui}/src/app/shared/sort-direction.enum.ts (100%) rename {ngapp => ui}/src/app/shared/test-data.service.spec.ts (100%) rename {ngapp => ui}/src/app/shared/test-data.service.ts (100%) rename {ngapp => ui}/src/app/shared/validators/name-validator.ts (100%) rename {ngapp => ui}/src/assets/.gitkeep (100%) rename {ngapp => ui}/src/assets/MongoDB_70x40.png (100%) rename {ngapp => ui}/src/assets/MySQL_70x40.png (100%) rename {ngapp => ui}/src/assets/PostgresSql_70x40.png (100%) rename {ngapp => ui}/src/assets/composition.png (100%) rename {ngapp => ui}/src/assets/graphicsfuel/database-64.png (100%) rename {ngapp => ui}/src/assets/graphicsfuel/readme.txt (100%) rename {ngapp => ui}/src/assets/iconfinder/Aha-soft/license.pdf (100%) rename {ngapp => ui}/src/assets/iconfinder/Aha-soft/minus-depressed.png (100%) rename {ngapp => ui}/src/assets/iconfinder/Aha-soft/minus.png (100%) rename {ngapp => ui}/src/assets/iconfinder/Aha-soft/plus-depressed.png (100%) rename {ngapp => ui}/src/assets/iconfinder/Aha-soft/plus.png (100%) rename {ngapp => ui}/src/assets/iconfinder/Natalya-Skidan/license.pdf (100%) rename {ngapp => ui}/src/assets/iconfinder/Natalya-Skidan/question-mark.png (100%) rename {ngapp => ui}/src/assets/iconfinder/creative-commons.pdf (100%) rename {ngapp => ui}/src/assets/redhat-iot.png (100%) rename {ngapp => ui}/src/assets/salesforce_40x40.png (100%) rename {ngapp => ui}/src/assets/table.png (100%) rename {ngapp => ui}/src/assets/teiid-lizard-gradient-bgd.png (100%) rename {ngapp => ui}/src/assets/vdb.png (100%) rename {ngapp => ui}/src/environments/environment.prod.ts (100%) rename {ngapp => ui}/src/environments/environment.ts (100%) rename {ngapp => ui}/src/favicon.ico (100%) rename {ngapp => ui}/src/index.html (100%) rename {ngapp => ui}/src/main.ts (100%) rename {ngapp => ui}/src/polyfills.ts (100%) rename {ngapp => ui}/src/styles.css (100%) rename {ngapp => ui}/src/test.ts (100%) rename {ngapp => ui}/src/tsconfig.app.json (100%) rename {ngapp => ui}/src/tsconfig.spec.json (100%) rename {ngapp => ui}/src/typings.d.ts (100%) rename {ngapp => ui}/start.sh (100%) rename {ngapp => ui}/tsconfig.json (100%) rename {ngapp => ui}/tslint.json (100%) diff --git a/ngapp/.angular-cli.json b/ui/.angular-cli.json similarity index 100% rename from ngapp/.angular-cli.json rename to ui/.angular-cli.json diff --git a/ngapp/.editorconfig b/ui/.editorconfig similarity index 100% rename from ngapp/.editorconfig rename to ui/.editorconfig diff --git a/ngapp/README.md b/ui/README.md similarity index 100% rename from ngapp/README.md rename to ui/README.md diff --git a/ngapp/e2e/app.e2e-spec.ts b/ui/e2e/app.e2e-spec.ts similarity index 100% rename from ngapp/e2e/app.e2e-spec.ts rename to ui/e2e/app.e2e-spec.ts diff --git a/ngapp/e2e/app.po.ts b/ui/e2e/app.po.ts similarity index 100% rename from ngapp/e2e/app.po.ts rename to ui/e2e/app.po.ts diff --git a/ngapp/e2e/tsconfig.e2e.json b/ui/e2e/tsconfig.e2e.json similarity index 100% rename from ngapp/e2e/tsconfig.e2e.json rename to ui/e2e/tsconfig.e2e.json diff --git a/ngapp/karma.conf.js b/ui/karma.conf.js similarity index 100% rename from ngapp/karma.conf.js rename to ui/karma.conf.js diff --git a/ngapp/locale/README.md b/ui/locale/README.md similarity index 100% rename from ngapp/locale/README.md rename to ui/locale/README.md diff --git a/ngapp/locale/messages.es.xlf b/ui/locale/messages.es.xlf similarity index 100% rename from ngapp/locale/messages.es.xlf rename to ui/locale/messages.es.xlf diff --git a/ngapp/messages.xlf b/ui/messages.xlf similarity index 100% rename from ngapp/messages.xlf rename to ui/messages.xlf diff --git a/ngapp/package-lock.json b/ui/package-lock.json similarity index 100% rename from ngapp/package-lock.json rename to ui/package-lock.json diff --git a/ngapp/package.json b/ui/package.json similarity index 100% rename from ngapp/package.json rename to ui/package.json diff --git a/ngapp/protractor.conf.js b/ui/protractor.conf.js similarity index 100% rename from ngapp/protractor.conf.js rename to ui/protractor.conf.js diff --git a/ngapp/server.js b/ui/server.js similarity index 100% rename from ngapp/server.js rename to ui/server.js diff --git a/ngapp/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts similarity index 100% rename from ngapp/src/app/app-routing.module.ts rename to ui/src/app/app-routing.module.ts diff --git a/ngapp/src/app/app.component.css b/ui/src/app/app.component.css similarity index 100% rename from ngapp/src/app/app.component.css rename to ui/src/app/app.component.css diff --git a/ngapp/src/app/app.component.html b/ui/src/app/app.component.html similarity index 100% rename from ngapp/src/app/app.component.html rename to ui/src/app/app.component.html diff --git a/ngapp/src/app/app.component.spec.ts b/ui/src/app/app.component.spec.ts similarity index 100% rename from ngapp/src/app/app.component.spec.ts rename to ui/src/app/app.component.spec.ts diff --git a/ngapp/src/app/app.component.ts b/ui/src/app/app.component.ts similarity index 100% rename from ngapp/src/app/app.component.ts rename to ui/src/app/app.component.ts diff --git a/ngapp/src/app/app.module.ts b/ui/src/app/app.module.ts similarity index 100% rename from ngapp/src/app/app.module.ts rename to ui/src/app/app.module.ts diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.css b/ui/src/app/connections/add-connection-wizard/add-connection-wizard.component.css similarity index 100% rename from ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.css rename to ui/src/app/connections/add-connection-wizard/add-connection-wizard.component.css diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html b/ui/src/app/connections/add-connection-wizard/add-connection-wizard.component.html similarity index 100% rename from ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.html rename to ui/src/app/connections/add-connection-wizard/add-connection-wizard.component.html diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts b/ui/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts similarity index 100% rename from ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts rename to ui/src/app/connections/add-connection-wizard/add-connection-wizard.component.spec.ts diff --git a/ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts b/ui/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts similarity index 100% rename from ngapp/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts rename to ui/src/app/connections/add-connection-wizard/add-connection-wizard.component.ts diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.css b/ui/src/app/connections/add-connection/add-connection.component.css similarity index 100% rename from ngapp/src/app/connections/add-connection/add-connection.component.css rename to ui/src/app/connections/add-connection/add-connection.component.css diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.html b/ui/src/app/connections/add-connection/add-connection.component.html similarity index 100% rename from ngapp/src/app/connections/add-connection/add-connection.component.html rename to ui/src/app/connections/add-connection/add-connection.component.html diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.spec.ts b/ui/src/app/connections/add-connection/add-connection.component.spec.ts similarity index 100% rename from ngapp/src/app/connections/add-connection/add-connection.component.spec.ts rename to ui/src/app/connections/add-connection/add-connection.component.spec.ts diff --git a/ngapp/src/app/connections/add-connection/add-connection.component.ts b/ui/src/app/connections/add-connection/add-connection.component.ts similarity index 100% rename from ngapp/src/app/connections/add-connection/add-connection.component.ts rename to ui/src/app/connections/add-connection/add-connection.component.ts diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css b/ui/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css similarity index 100% rename from ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css rename to ui/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.css diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.html b/ui/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.html similarity index 100% rename from ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.html rename to ui/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.html diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.spec.ts b/ui/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.spec.ts similarity index 100% rename from ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.spec.ts rename to ui/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.spec.ts diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.ts b/ui/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.ts similarity index 100% rename from ngapp/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.ts rename to ui/src/app/connections/connection-type-cards/connection-type-card/connection-type-card.component.ts diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.css b/ui/src/app/connections/connection-type-cards/connection-type-cards.component.css similarity index 100% rename from ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.css rename to ui/src/app/connections/connection-type-cards/connection-type-cards.component.css diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.html b/ui/src/app/connections/connection-type-cards/connection-type-cards.component.html similarity index 100% rename from ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.html rename to ui/src/app/connections/connection-type-cards/connection-type-cards.component.html diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.spec.ts b/ui/src/app/connections/connection-type-cards/connection-type-cards.component.spec.ts similarity index 100% rename from ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.spec.ts rename to ui/src/app/connections/connection-type-cards/connection-type-cards.component.spec.ts diff --git a/ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.ts b/ui/src/app/connections/connection-type-cards/connection-type-cards.component.ts similarity index 100% rename from ngapp/src/app/connections/connection-type-cards/connection-type-cards.component.ts rename to ui/src/app/connections/connection-type-cards/connection-type-cards.component.ts diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css b/ui/src/app/connections/connections-cards/connection-card/connection-card.component.css similarity index 100% rename from ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.css rename to ui/src/app/connections/connections-cards/connection-card/connection-card.component.css diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html b/ui/src/app/connections/connections-cards/connection-card/connection-card.component.html similarity index 100% rename from ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.html rename to ui/src/app/connections/connections-cards/connection-card/connection-card.component.html diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts b/ui/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts similarity index 100% rename from ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts rename to ui/src/app/connections/connections-cards/connection-card/connection-card.component.spec.ts diff --git a/ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts b/ui/src/app/connections/connections-cards/connection-card/connection-card.component.ts similarity index 100% rename from ngapp/src/app/connections/connections-cards/connection-card/connection-card.component.ts rename to ui/src/app/connections/connections-cards/connection-card/connection-card.component.ts diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.css b/ui/src/app/connections/connections-cards/connections-cards.component.css similarity index 100% rename from ngapp/src/app/connections/connections-cards/connections-cards.component.css rename to ui/src/app/connections/connections-cards/connections-cards.component.css diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.html b/ui/src/app/connections/connections-cards/connections-cards.component.html similarity index 100% rename from ngapp/src/app/connections/connections-cards/connections-cards.component.html rename to ui/src/app/connections/connections-cards/connections-cards.component.html diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts b/ui/src/app/connections/connections-cards/connections-cards.component.spec.ts similarity index 100% rename from ngapp/src/app/connections/connections-cards/connections-cards.component.spec.ts rename to ui/src/app/connections/connections-cards/connections-cards.component.spec.ts diff --git a/ngapp/src/app/connections/connections-cards/connections-cards.component.ts b/ui/src/app/connections/connections-cards/connections-cards.component.ts similarity index 100% rename from ngapp/src/app/connections/connections-cards/connections-cards.component.ts rename to ui/src/app/connections/connections-cards/connections-cards.component.ts diff --git a/ngapp/src/app/connections/connections-list/connection-details.component.html b/ui/src/app/connections/connections-list/connection-details.component.html similarity index 100% rename from ngapp/src/app/connections/connections-list/connection-details.component.html rename to ui/src/app/connections/connections-list/connection-details.component.html diff --git a/ngapp/src/app/connections/connections-list/connection-details.component.ts b/ui/src/app/connections/connections-list/connection-details.component.ts similarity index 100% rename from ngapp/src/app/connections/connections-list/connection-details.component.ts rename to ui/src/app/connections/connections-list/connection-details.component.ts diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.css b/ui/src/app/connections/connections-list/connections-list.component.css similarity index 100% rename from ngapp/src/app/connections/connections-list/connections-list.component.css rename to ui/src/app/connections/connections-list/connections-list.component.css diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.html b/ui/src/app/connections/connections-list/connections-list.component.html similarity index 100% rename from ngapp/src/app/connections/connections-list/connections-list.component.html rename to ui/src/app/connections/connections-list/connections-list.component.html diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.spec.ts b/ui/src/app/connections/connections-list/connections-list.component.spec.ts similarity index 100% rename from ngapp/src/app/connections/connections-list/connections-list.component.spec.ts rename to ui/src/app/connections/connections-list/connections-list.component.spec.ts diff --git a/ngapp/src/app/connections/connections-list/connections-list.component.ts b/ui/src/app/connections/connections-list/connections-list.component.ts similarity index 100% rename from ngapp/src/app/connections/connections-list/connections-list.component.ts rename to ui/src/app/connections/connections-list/connections-list.component.ts diff --git a/ngapp/src/app/connections/connections-routing.module.ts b/ui/src/app/connections/connections-routing.module.ts similarity index 100% rename from ngapp/src/app/connections/connections-routing.module.ts rename to ui/src/app/connections/connections-routing.module.ts diff --git a/ngapp/src/app/connections/connections.component.css b/ui/src/app/connections/connections.component.css similarity index 100% rename from ngapp/src/app/connections/connections.component.css rename to ui/src/app/connections/connections.component.css diff --git a/ngapp/src/app/connections/connections.component.html b/ui/src/app/connections/connections.component.html similarity index 100% rename from ngapp/src/app/connections/connections.component.html rename to ui/src/app/connections/connections.component.html diff --git a/ngapp/src/app/connections/connections.component.spec.ts b/ui/src/app/connections/connections.component.spec.ts similarity index 100% rename from ngapp/src/app/connections/connections.component.spec.ts rename to ui/src/app/connections/connections.component.spec.ts diff --git a/ngapp/src/app/connections/connections.component.ts b/ui/src/app/connections/connections.component.ts similarity index 100% rename from ngapp/src/app/connections/connections.component.ts rename to ui/src/app/connections/connections.component.ts diff --git a/ngapp/src/app/connections/connections.module.ts b/ui/src/app/connections/connections.module.ts similarity index 100% rename from ngapp/src/app/connections/connections.module.ts rename to ui/src/app/connections/connections.module.ts diff --git a/ngapp/src/app/connections/shared/connection-status.spec.ts b/ui/src/app/connections/shared/connection-status.spec.ts similarity index 100% rename from ngapp/src/app/connections/shared/connection-status.spec.ts rename to ui/src/app/connections/shared/connection-status.spec.ts diff --git a/ngapp/src/app/connections/shared/connection-status.ts b/ui/src/app/connections/shared/connection-status.ts similarity index 100% rename from ngapp/src/app/connections/shared/connection-status.ts rename to ui/src/app/connections/shared/connection-status.ts diff --git a/ngapp/src/app/connections/shared/connection-type.model.ts b/ui/src/app/connections/shared/connection-type.model.ts similarity index 100% rename from ngapp/src/app/connections/shared/connection-type.model.ts rename to ui/src/app/connections/shared/connection-type.model.ts diff --git a/ngapp/src/app/connections/shared/connection.model.spec.ts b/ui/src/app/connections/shared/connection.model.spec.ts similarity index 100% rename from ngapp/src/app/connections/shared/connection.model.spec.ts rename to ui/src/app/connections/shared/connection.model.spec.ts diff --git a/ngapp/src/app/connections/shared/connection.model.ts b/ui/src/app/connections/shared/connection.model.ts similarity index 100% rename from ngapp/src/app/connections/shared/connection.model.ts rename to ui/src/app/connections/shared/connection.model.ts diff --git a/ngapp/src/app/connections/shared/connection.service.spec.ts b/ui/src/app/connections/shared/connection.service.spec.ts similarity index 100% rename from ngapp/src/app/connections/shared/connection.service.spec.ts rename to ui/src/app/connections/shared/connection.service.spec.ts diff --git a/ngapp/src/app/connections/shared/connection.service.ts b/ui/src/app/connections/shared/connection.service.ts similarity index 100% rename from ngapp/src/app/connections/shared/connection.service.ts rename to ui/src/app/connections/shared/connection.service.ts diff --git a/ngapp/src/app/connections/shared/connections-constants.ts b/ui/src/app/connections/shared/connections-constants.ts similarity index 100% rename from ngapp/src/app/connections/shared/connections-constants.ts rename to ui/src/app/connections/shared/connections-constants.ts diff --git a/ngapp/src/app/connections/shared/mock-connection.service.ts b/ui/src/app/connections/shared/mock-connection.service.ts similarity index 100% rename from ngapp/src/app/connections/shared/mock-connection.service.ts rename to ui/src/app/connections/shared/mock-connection.service.ts diff --git a/ngapp/src/app/connections/shared/new-connection.model.ts b/ui/src/app/connections/shared/new-connection.model.ts similarity index 100% rename from ngapp/src/app/connections/shared/new-connection.model.ts rename to ui/src/app/connections/shared/new-connection.model.ts diff --git a/ngapp/src/app/connections/shared/schema-node.model.spec.ts b/ui/src/app/connections/shared/schema-node.model.spec.ts similarity index 100% rename from ngapp/src/app/connections/shared/schema-node.model.spec.ts rename to ui/src/app/connections/shared/schema-node.model.spec.ts diff --git a/ngapp/src/app/connections/shared/schema-node.model.ts b/ui/src/app/connections/shared/schema-node.model.ts similarity index 100% rename from ngapp/src/app/connections/shared/schema-node.model.ts rename to ui/src/app/connections/shared/schema-node.model.ts diff --git a/ngapp/src/app/connections/shared/service-catalog-source.model.spec.ts b/ui/src/app/connections/shared/service-catalog-source.model.spec.ts similarity index 100% rename from ngapp/src/app/connections/shared/service-catalog-source.model.spec.ts rename to ui/src/app/connections/shared/service-catalog-source.model.spec.ts diff --git a/ngapp/src/app/connections/shared/service-catalog-source.model.ts b/ui/src/app/connections/shared/service-catalog-source.model.ts similarity index 100% rename from ngapp/src/app/connections/shared/service-catalog-source.model.ts rename to ui/src/app/connections/shared/service-catalog-source.model.ts diff --git a/ngapp/src/app/core/about-dialog/about-dialog.component.css b/ui/src/app/core/about-dialog/about-dialog.component.css similarity index 100% rename from ngapp/src/app/core/about-dialog/about-dialog.component.css rename to ui/src/app/core/about-dialog/about-dialog.component.css diff --git a/ngapp/src/app/core/about-dialog/about-dialog.component.html b/ui/src/app/core/about-dialog/about-dialog.component.html similarity index 100% rename from ngapp/src/app/core/about-dialog/about-dialog.component.html rename to ui/src/app/core/about-dialog/about-dialog.component.html diff --git a/ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts b/ui/src/app/core/about-dialog/about-dialog.component.spec.ts similarity index 100% rename from ngapp/src/app/core/about-dialog/about-dialog.component.spec.ts rename to ui/src/app/core/about-dialog/about-dialog.component.spec.ts diff --git a/ngapp/src/app/core/about-dialog/about-dialog.component.ts b/ui/src/app/core/about-dialog/about-dialog.component.ts similarity index 100% rename from ngapp/src/app/core/about-dialog/about-dialog.component.ts rename to ui/src/app/core/about-dialog/about-dialog.component.ts diff --git a/ngapp/src/app/core/about-dialog/about-event.ts b/ui/src/app/core/about-dialog/about-event.ts similarity index 100% rename from ngapp/src/app/core/about-dialog/about-event.ts rename to ui/src/app/core/about-dialog/about-event.ts diff --git a/ngapp/src/app/core/about-dialog/about.model.ts b/ui/src/app/core/about-dialog/about.model.ts similarity index 100% rename from ngapp/src/app/core/about-dialog/about.model.ts rename to ui/src/app/core/about-dialog/about.model.ts diff --git a/ngapp/src/app/core/about-dialog/about.service.spec.ts b/ui/src/app/core/about-dialog/about.service.spec.ts similarity index 100% rename from ngapp/src/app/core/about-dialog/about.service.spec.ts rename to ui/src/app/core/about-dialog/about.service.spec.ts diff --git a/ngapp/src/app/core/about-dialog/about.service.ts b/ui/src/app/core/about-dialog/about.service.ts similarity index 100% rename from ngapp/src/app/core/about-dialog/about.service.ts rename to ui/src/app/core/about-dialog/about.service.ts diff --git a/ngapp/src/app/core/about-dialog/mock-about.service.ts b/ui/src/app/core/about-dialog/mock-about.service.ts similarity index 100% rename from ngapp/src/app/core/about-dialog/mock-about.service.ts rename to ui/src/app/core/about-dialog/mock-about.service.ts diff --git a/ngapp/src/app/core/api.service.spec.ts b/ui/src/app/core/api.service.spec.ts similarity index 100% rename from ngapp/src/app/core/api.service.spec.ts rename to ui/src/app/core/api.service.spec.ts diff --git a/ngapp/src/app/core/api.service.ts b/ui/src/app/core/api.service.ts similarity index 100% rename from ngapp/src/app/core/api.service.ts rename to ui/src/app/core/api.service.ts diff --git a/ngapp/src/app/core/app-settings.service.spec.ts b/ui/src/app/core/app-settings.service.spec.ts similarity index 100% rename from ngapp/src/app/core/app-settings.service.spec.ts rename to ui/src/app/core/app-settings.service.spec.ts diff --git a/ngapp/src/app/core/app-settings.service.ts b/ui/src/app/core/app-settings.service.ts similarity index 100% rename from ngapp/src/app/core/app-settings.service.ts rename to ui/src/app/core/app-settings.service.ts diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css b/ui/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css similarity index 100% rename from ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css rename to ui/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.css diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html b/ui/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html similarity index 100% rename from ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html rename to ui/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.html diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts b/ui/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts similarity index 100% rename from ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts rename to ui/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.spec.ts diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts b/ui/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts similarity index 100% rename from ngapp/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts rename to ui/src/app/core/breadcrumbs/breadcrumb/breadcrumb.component.ts diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.css b/ui/src/app/core/breadcrumbs/breadcrumbs.component.css similarity index 100% rename from ngapp/src/app/core/breadcrumbs/breadcrumbs.component.css rename to ui/src/app/core/breadcrumbs/breadcrumbs.component.css diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.html b/ui/src/app/core/breadcrumbs/breadcrumbs.component.html similarity index 100% rename from ngapp/src/app/core/breadcrumbs/breadcrumbs.component.html rename to ui/src/app/core/breadcrumbs/breadcrumbs.component.html diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts b/ui/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts similarity index 100% rename from ngapp/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts rename to ui/src/app/core/breadcrumbs/breadcrumbs.component.spec.ts diff --git a/ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts b/ui/src/app/core/breadcrumbs/breadcrumbs.component.ts similarity index 100% rename from ngapp/src/app/core/breadcrumbs/breadcrumbs.component.ts rename to ui/src/app/core/breadcrumbs/breadcrumbs.component.ts diff --git a/ngapp/src/app/core/core.less b/ui/src/app/core/core.less similarity index 100% rename from ngapp/src/app/core/core.less rename to ui/src/app/core/core.less diff --git a/ngapp/src/app/core/core.module.ts b/ui/src/app/core/core.module.ts similarity index 100% rename from ngapp/src/app/core/core.module.ts rename to ui/src/app/core/core.module.ts diff --git a/ngapp/src/app/core/logger.service.spec.ts b/ui/src/app/core/logger.service.spec.ts similarity index 100% rename from ngapp/src/app/core/logger.service.spec.ts rename to ui/src/app/core/logger.service.spec.ts diff --git a/ngapp/src/app/core/logger.service.ts b/ui/src/app/core/logger.service.ts similarity index 100% rename from ngapp/src/app/core/logger.service.ts rename to ui/src/app/core/logger.service.ts diff --git a/ngapp/src/app/core/mock-app-settings.service.ts b/ui/src/app/core/mock-app-settings.service.ts similarity index 100% rename from ngapp/src/app/core/mock-app-settings.service.ts rename to ui/src/app/core/mock-app-settings.service.ts diff --git a/ngapp/src/app/core/selection.service.spec.ts b/ui/src/app/core/selection.service.spec.ts similarity index 100% rename from ngapp/src/app/core/selection.service.spec.ts rename to ui/src/app/core/selection.service.spec.ts diff --git a/ngapp/src/app/core/selection.service.ts b/ui/src/app/core/selection.service.ts similarity index 100% rename from ngapp/src/app/core/selection.service.ts rename to ui/src/app/core/selection.service.ts diff --git a/ngapp/src/app/core/utils/array-utils.ts b/ui/src/app/core/utils/array-utils.ts similarity index 100% rename from ngapp/src/app/core/utils/array-utils.ts rename to ui/src/app/core/utils/array-utils.ts diff --git a/ngapp/src/app/core/utils/object-utils.ts b/ui/src/app/core/utils/object-utils.ts similarity index 100% rename from ngapp/src/app/core/utils/object-utils.ts rename to ui/src/app/core/utils/object-utils.ts diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.css b/ui/src/app/core/vertical-nav/vertical-nav.component.css similarity index 100% rename from ngapp/src/app/core/vertical-nav/vertical-nav.component.css rename to ui/src/app/core/vertical-nav/vertical-nav.component.css diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.html b/ui/src/app/core/vertical-nav/vertical-nav.component.html similarity index 100% rename from ngapp/src/app/core/vertical-nav/vertical-nav.component.html rename to ui/src/app/core/vertical-nav/vertical-nav.component.html diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts b/ui/src/app/core/vertical-nav/vertical-nav.component.spec.ts similarity index 100% rename from ngapp/src/app/core/vertical-nav/vertical-nav.component.spec.ts rename to ui/src/app/core/vertical-nav/vertical-nav.component.spec.ts diff --git a/ngapp/src/app/core/vertical-nav/vertical-nav.component.ts b/ui/src/app/core/vertical-nav/vertical-nav.component.ts similarity index 100% rename from ngapp/src/app/core/vertical-nav/vertical-nav.component.ts rename to ui/src/app/core/vertical-nav/vertical-nav.component.ts diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.css b/ui/src/app/dataservices/create-views-dialog/create-views-dialog.component.css similarity index 100% rename from ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.css rename to ui/src/app/dataservices/create-views-dialog/create-views-dialog.component.css diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html b/ui/src/app/dataservices/create-views-dialog/create-views-dialog.component.html similarity index 100% rename from ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.html rename to ui/src/app/dataservices/create-views-dialog/create-views-dialog.component.html diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts b/ui/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts rename to ui/src/app/dataservices/create-views-dialog/create-views-dialog.component.spec.ts diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts b/ui/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts similarity index 100% rename from ngapp/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts rename to ui/src/app/dataservices/create-views-dialog/create-views-dialog.component.ts diff --git a/ngapp/src/app/dataservices/create-views-dialog/create-views-result.model.ts b/ui/src/app/dataservices/create-views-dialog/create-views-result.model.ts similarity index 100% rename from ngapp/src/app/dataservices/create-views-dialog/create-views-result.model.ts rename to ui/src/app/dataservices/create-views-dialog/create-views-result.model.ts diff --git a/ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts b/ui/src/app/dataservices/create-views-dialog/new-view.model.ts similarity index 100% rename from ngapp/src/app/dataservices/create-views-dialog/new-view.model.ts rename to ui/src/app/dataservices/create-views-dialog/new-view.model.ts diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css b/ui/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css similarity index 100% rename from ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css rename to ui/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.css diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html b/ui/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html similarity index 100% rename from ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html rename to ui/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.html diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.spec.ts b/ui/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.spec.ts rename to ui/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.spec.ts diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts b/ui/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts rename to ui/src/app/dataservices/dataservices-cards/dataservice-card/dataservice-card.component.ts diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css b/ui/src/app/dataservices/dataservices-cards/dataservices-cards.component.css similarity index 100% rename from ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.css rename to ui/src/app/dataservices/dataservices-cards/dataservices-cards.component.css diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html b/ui/src/app/dataservices/dataservices-cards/dataservices-cards.component.html similarity index 100% rename from ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.html rename to ui/src/app/dataservices/dataservices-cards/dataservices-cards.component.html diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts b/ui/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts rename to ui/src/app/dataservices/dataservices-cards/dataservices-cards.component.spec.ts diff --git a/ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts b/ui/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts rename to ui/src/app/dataservices/dataservices-cards/dataservices-cards.component.ts diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.html b/ui/src/app/dataservices/dataservices-list/dataservices-details.component.html similarity index 100% rename from ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.html rename to ui/src/app/dataservices/dataservices-list/dataservices-details.component.html diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts b/ui/src/app/dataservices/dataservices-list/dataservices-details.component.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-list/dataservices-details.component.ts rename to ui/src/app/dataservices/dataservices-list/dataservices-details.component.ts diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css b/ui/src/app/dataservices/dataservices-list/dataservices-list.component.css similarity index 100% rename from ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.css rename to ui/src/app/dataservices/dataservices-list/dataservices-list.component.css diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html b/ui/src/app/dataservices/dataservices-list/dataservices-list.component.html similarity index 100% rename from ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.html rename to ui/src/app/dataservices/dataservices-list/dataservices-list.component.html diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts b/ui/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts rename to ui/src/app/dataservices/dataservices-list/dataservices-list.component.spec.ts diff --git a/ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts b/ui/src/app/dataservices/dataservices-list/dataservices-list.component.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-list/dataservices-list.component.ts rename to ui/src/app/dataservices/dataservices-list/dataservices-list.component.ts diff --git a/ngapp/src/app/dataservices/dataservices-list/views-content.component.html b/ui/src/app/dataservices/dataservices-list/views-content.component.html similarity index 100% rename from ngapp/src/app/dataservices/dataservices-list/views-content.component.html rename to ui/src/app/dataservices/dataservices-list/views-content.component.html diff --git a/ngapp/src/app/dataservices/dataservices-list/views-content.component.ts b/ui/src/app/dataservices/dataservices-list/views-content.component.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-list/views-content.component.ts rename to ui/src/app/dataservices/dataservices-list/views-content.component.ts diff --git a/ngapp/src/app/dataservices/dataservices-routing.module.ts b/ui/src/app/dataservices/dataservices-routing.module.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices-routing.module.ts rename to ui/src/app/dataservices/dataservices-routing.module.ts diff --git a/ngapp/src/app/dataservices/dataservices.component.css b/ui/src/app/dataservices/dataservices.component.css similarity index 100% rename from ngapp/src/app/dataservices/dataservices.component.css rename to ui/src/app/dataservices/dataservices.component.css diff --git a/ngapp/src/app/dataservices/dataservices.component.html b/ui/src/app/dataservices/dataservices.component.html similarity index 100% rename from ngapp/src/app/dataservices/dataservices.component.html rename to ui/src/app/dataservices/dataservices.component.html diff --git a/ngapp/src/app/dataservices/dataservices.component.spec.ts b/ui/src/app/dataservices/dataservices.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices.component.spec.ts rename to ui/src/app/dataservices/dataservices.component.spec.ts diff --git a/ngapp/src/app/dataservices/dataservices.component.ts b/ui/src/app/dataservices/dataservices.component.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices.component.ts rename to ui/src/app/dataservices/dataservices.component.ts diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ui/src/app/dataservices/dataservices.module.ts similarity index 100% rename from ngapp/src/app/dataservices/dataservices.module.ts rename to ui/src/app/dataservices/dataservices.module.ts diff --git a/ngapp/src/app/dataservices/odata-control/odata-column.model.ts b/ui/src/app/dataservices/odata-control/odata-column.model.ts similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata-column.model.ts rename to ui/src/app/dataservices/odata-control/odata-column.model.ts diff --git a/ngapp/src/app/dataservices/odata-control/odata-conditions.model.ts b/ui/src/app/dataservices/odata-control/odata-conditions.model.ts similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata-conditions.model.ts rename to ui/src/app/dataservices/odata-control/odata-conditions.model.ts diff --git a/ngapp/src/app/dataservices/odata-control/odata-constants.ts b/ui/src/app/dataservices/odata-control/odata-constants.ts similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata-constants.ts rename to ui/src/app/dataservices/odata-control/odata-constants.ts diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.css b/ui/src/app/dataservices/odata-control/odata-control.component.css similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata-control.component.css rename to ui/src/app/dataservices/odata-control/odata-control.component.css diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.html b/ui/src/app/dataservices/odata-control/odata-control.component.html similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata-control.component.html rename to ui/src/app/dataservices/odata-control/odata-control.component.html diff --git a/ngapp/src/app/dataservices/odata-control/odata-control.component.ts b/ui/src/app/dataservices/odata-control/odata-control.component.ts similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata-control.component.ts rename to ui/src/app/dataservices/odata-control/odata-control.component.ts diff --git a/ngapp/src/app/dataservices/odata-control/odata-entity.model.ts b/ui/src/app/dataservices/odata-control/odata-entity.model.ts similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata-entity.model.ts rename to ui/src/app/dataservices/odata-control/odata-entity.model.ts diff --git a/ngapp/src/app/dataservices/odata-control/odata-where.model.ts b/ui/src/app/dataservices/odata-control/odata-where.model.ts similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata-where.model.ts rename to ui/src/app/dataservices/odata-control/odata-where.model.ts diff --git a/ngapp/src/app/dataservices/odata-control/odata.model.ts b/ui/src/app/dataservices/odata-control/odata.model.ts similarity index 100% rename from ngapp/src/app/dataservices/odata-control/odata.model.ts rename to ui/src/app/dataservices/odata-control/odata.model.ts diff --git a/ngapp/src/app/dataservices/selected-node/selected-node.component.css b/ui/src/app/dataservices/selected-node/selected-node.component.css similarity index 100% rename from ngapp/src/app/dataservices/selected-node/selected-node.component.css rename to ui/src/app/dataservices/selected-node/selected-node.component.css diff --git a/ngapp/src/app/dataservices/selected-node/selected-node.component.html b/ui/src/app/dataservices/selected-node/selected-node.component.html similarity index 100% rename from ngapp/src/app/dataservices/selected-node/selected-node.component.html rename to ui/src/app/dataservices/selected-node/selected-node.component.html diff --git a/ngapp/src/app/dataservices/selected-node/selected-node.component.spec.ts b/ui/src/app/dataservices/selected-node/selected-node.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/selected-node/selected-node.component.spec.ts rename to ui/src/app/dataservices/selected-node/selected-node.component.spec.ts diff --git a/ngapp/src/app/dataservices/selected-node/selected-node.component.ts b/ui/src/app/dataservices/selected-node/selected-node.component.ts similarity index 100% rename from ngapp/src/app/dataservices/selected-node/selected-node.component.ts rename to ui/src/app/dataservices/selected-node/selected-node.component.ts diff --git a/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css b/ui/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css similarity index 100% rename from ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css rename to ui/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.css diff --git a/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html b/ui/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html similarity index 100% rename from ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html rename to ui/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.html diff --git a/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts b/ui/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts rename to ui/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.spec.ts diff --git a/ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts b/ui/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts similarity index 100% rename from ngapp/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts rename to ui/src/app/dataservices/selected-nodes-list/selected-nodes-list.component.ts diff --git a/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.css b/ui/src/app/dataservices/set-description-dialog/set-description-dialog.component.css similarity index 100% rename from ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.css rename to ui/src/app/dataservices/set-description-dialog/set-description-dialog.component.css diff --git a/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.html b/ui/src/app/dataservices/set-description-dialog/set-description-dialog.component.html similarity index 100% rename from ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.html rename to ui/src/app/dataservices/set-description-dialog/set-description-dialog.component.html diff --git a/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts b/ui/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts rename to ui/src/app/dataservices/set-description-dialog/set-description-dialog.component.spec.ts diff --git a/ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts b/ui/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts similarity index 100% rename from ngapp/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts rename to ui/src/app/dataservices/set-description-dialog/set-description-dialog.component.ts diff --git a/ngapp/src/app/dataservices/shared/column-data.model.ts b/ui/src/app/dataservices/shared/column-data.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/column-data.model.ts rename to ui/src/app/dataservices/shared/column-data.model.ts diff --git a/ngapp/src/app/dataservices/shared/column.model.spec.ts b/ui/src/app/dataservices/shared/column.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/column.model.spec.ts rename to ui/src/app/dataservices/shared/column.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/column.model.ts b/ui/src/app/dataservices/shared/column.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/column.model.ts rename to ui/src/app/dataservices/shared/column.model.ts diff --git a/ngapp/src/app/dataservices/shared/composition-operator.enum.ts b/ui/src/app/dataservices/shared/composition-operator.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/composition-operator.enum.ts rename to ui/src/app/dataservices/shared/composition-operator.enum.ts diff --git a/ngapp/src/app/dataservices/shared/composition-type.enum.ts b/ui/src/app/dataservices/shared/composition-type.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/composition-type.enum.ts rename to ui/src/app/dataservices/shared/composition-type.enum.ts diff --git a/ngapp/src/app/dataservices/shared/composition.model.spec.ts b/ui/src/app/dataservices/shared/composition.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/composition.model.spec.ts rename to ui/src/app/dataservices/shared/composition.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/composition.model.ts b/ui/src/app/dataservices/shared/composition.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/composition.model.ts rename to ui/src/app/dataservices/shared/composition.model.ts diff --git a/ngapp/src/app/dataservices/shared/connection-summary.model.spec.ts b/ui/src/app/dataservices/shared/connection-summary.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/connection-summary.model.spec.ts rename to ui/src/app/dataservices/shared/connection-summary.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/connection-summary.model.ts b/ui/src/app/dataservices/shared/connection-summary.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/connection-summary.model.ts rename to ui/src/app/dataservices/shared/connection-summary.model.ts diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.spec.ts b/ui/src/app/dataservices/shared/dataservice.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/dataservice.model.spec.ts rename to ui/src/app/dataservices/shared/dataservice.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/dataservice.model.ts b/ui/src/app/dataservices/shared/dataservice.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/dataservice.model.ts rename to ui/src/app/dataservices/shared/dataservice.model.ts diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.spec.ts b/ui/src/app/dataservices/shared/dataservice.service.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/dataservice.service.spec.ts rename to ui/src/app/dataservices/shared/dataservice.service.spec.ts diff --git a/ngapp/src/app/dataservices/shared/dataservice.service.ts b/ui/src/app/dataservices/shared/dataservice.service.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/dataservice.service.ts rename to ui/src/app/dataservices/shared/dataservice.service.ts diff --git a/ngapp/src/app/dataservices/shared/dataservices-constants.ts b/ui/src/app/dataservices/shared/dataservices-constants.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/dataservices-constants.ts rename to ui/src/app/dataservices/shared/dataservices-constants.ts diff --git a/ngapp/src/app/dataservices/shared/deployment-state.enum.ts b/ui/src/app/dataservices/shared/deployment-state.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/deployment-state.enum.ts rename to ui/src/app/dataservices/shared/deployment-state.enum.ts diff --git a/ngapp/src/app/dataservices/shared/mock-dataservice.service.ts b/ui/src/app/dataservices/shared/mock-dataservice.service.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/mock-dataservice.service.ts rename to ui/src/app/dataservices/shared/mock-dataservice.service.ts diff --git a/ngapp/src/app/dataservices/shared/mock-vdb.service.ts b/ui/src/app/dataservices/shared/mock-vdb.service.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/mock-vdb.service.ts rename to ui/src/app/dataservices/shared/mock-vdb.service.ts diff --git a/ngapp/src/app/dataservices/shared/name-value.model.ts b/ui/src/app/dataservices/shared/name-value.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/name-value.model.ts rename to ui/src/app/dataservices/shared/name-value.model.ts diff --git a/ngapp/src/app/dataservices/shared/new-dataservice.model.ts b/ui/src/app/dataservices/shared/new-dataservice.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/new-dataservice.model.ts rename to ui/src/app/dataservices/shared/new-dataservice.model.ts diff --git a/ngapp/src/app/dataservices/shared/node-selector.ts b/ui/src/app/dataservices/shared/node-selector.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/node-selector.ts rename to ui/src/app/dataservices/shared/node-selector.ts diff --git a/ngapp/src/app/dataservices/shared/notifier.service.spec.ts b/ui/src/app/dataservices/shared/notifier.service.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/notifier.service.spec.ts rename to ui/src/app/dataservices/shared/notifier.service.spec.ts diff --git a/ngapp/src/app/dataservices/shared/notifier.service.ts b/ui/src/app/dataservices/shared/notifier.service.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/notifier.service.ts rename to ui/src/app/dataservices/shared/notifier.service.ts diff --git a/ngapp/src/app/dataservices/shared/path-utils.ts b/ui/src/app/dataservices/shared/path-utils.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/path-utils.ts rename to ui/src/app/dataservices/shared/path-utils.ts diff --git a/ngapp/src/app/dataservices/shared/projected-column.model.spec.ts b/ui/src/app/dataservices/shared/projected-column.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/projected-column.model.spec.ts rename to ui/src/app/dataservices/shared/projected-column.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/projected-column.model.ts b/ui/src/app/dataservices/shared/projected-column.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/projected-column.model.ts rename to ui/src/app/dataservices/shared/projected-column.model.ts diff --git a/ngapp/src/app/dataservices/shared/publish-state.enum.ts b/ui/src/app/dataservices/shared/publish-state.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/publish-state.enum.ts rename to ui/src/app/dataservices/shared/publish-state.enum.ts diff --git a/ngapp/src/app/dataservices/shared/query-results.model.spec.ts b/ui/src/app/dataservices/shared/query-results.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/query-results.model.spec.ts rename to ui/src/app/dataservices/shared/query-results.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/query-results.model.ts b/ui/src/app/dataservices/shared/query-results.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/query-results.model.ts rename to ui/src/app/dataservices/shared/query-results.model.ts diff --git a/ngapp/src/app/dataservices/shared/row-data.model.ts b/ui/src/app/dataservices/shared/row-data.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/row-data.model.ts rename to ui/src/app/dataservices/shared/row-data.model.ts diff --git a/ngapp/src/app/dataservices/shared/sql-view.model.ts b/ui/src/app/dataservices/shared/sql-view.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/sql-view.model.ts rename to ui/src/app/dataservices/shared/sql-view.model.ts diff --git a/ngapp/src/app/dataservices/shared/vdb-model-source.model.ts b/ui/src/app/dataservices/shared/vdb-model-source.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/vdb-model-source.model.ts rename to ui/src/app/dataservices/shared/vdb-model-source.model.ts diff --git a/ngapp/src/app/dataservices/shared/vdb-model.model.ts b/ui/src/app/dataservices/shared/vdb-model.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/vdb-model.model.ts rename to ui/src/app/dataservices/shared/vdb-model.model.ts diff --git a/ngapp/src/app/dataservices/shared/vdb-status.model.spec.ts b/ui/src/app/dataservices/shared/vdb-status.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/vdb-status.model.spec.ts rename to ui/src/app/dataservices/shared/vdb-status.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/vdb-status.model.ts b/ui/src/app/dataservices/shared/vdb-status.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/vdb-status.model.ts rename to ui/src/app/dataservices/shared/vdb-status.model.ts diff --git a/ngapp/src/app/dataservices/shared/vdb.model.ts b/ui/src/app/dataservices/shared/vdb.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/vdb.model.ts rename to ui/src/app/dataservices/shared/vdb.model.ts diff --git a/ngapp/src/app/dataservices/shared/vdb.service.spec.ts b/ui/src/app/dataservices/shared/vdb.service.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/vdb.service.spec.ts rename to ui/src/app/dataservices/shared/vdb.service.spec.ts diff --git a/ngapp/src/app/dataservices/shared/vdb.service.ts b/ui/src/app/dataservices/shared/vdb.service.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/vdb.service.ts rename to ui/src/app/dataservices/shared/vdb.service.ts diff --git a/ngapp/src/app/dataservices/shared/vdbs-constants.ts b/ui/src/app/dataservices/shared/vdbs-constants.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/vdbs-constants.ts rename to ui/src/app/dataservices/shared/vdbs-constants.ts diff --git a/ngapp/src/app/dataservices/shared/view-definition.model.spec.ts b/ui/src/app/dataservices/shared/view-definition.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/view-definition.model.spec.ts rename to ui/src/app/dataservices/shared/view-definition.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/view-definition.model.ts b/ui/src/app/dataservices/shared/view-definition.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/view-definition.model.ts rename to ui/src/app/dataservices/shared/view-definition.model.ts diff --git a/ngapp/src/app/dataservices/shared/view-editor-state.model.spec.ts b/ui/src/app/dataservices/shared/view-editor-state.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/view-editor-state.model.spec.ts rename to ui/src/app/dataservices/shared/view-editor-state.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/view-editor-state.model.ts b/ui/src/app/dataservices/shared/view-editor-state.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/view-editor-state.model.ts rename to ui/src/app/dataservices/shared/view-editor-state.model.ts diff --git a/ngapp/src/app/dataservices/shared/virt-route.model.ts b/ui/src/app/dataservices/shared/virt-route.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/virt-route.model.ts rename to ui/src/app/dataservices/shared/virt-route.model.ts diff --git a/ngapp/src/app/dataservices/shared/virtualization.model.spec.ts b/ui/src/app/dataservices/shared/virtualization.model.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/virtualization.model.spec.ts rename to ui/src/app/dataservices/shared/virtualization.model.spec.ts diff --git a/ngapp/src/app/dataservices/shared/virtualization.model.ts b/ui/src/app/dataservices/shared/virtualization.model.ts similarity index 100% rename from ngapp/src/app/dataservices/shared/virtualization.model.ts rename to ui/src/app/dataservices/shared/virtualization.model.ts diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.css b/ui/src/app/dataservices/sql-control/sql-control.component.css similarity index 100% rename from ngapp/src/app/dataservices/sql-control/sql-control.component.css rename to ui/src/app/dataservices/sql-control/sql-control.component.css diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.html b/ui/src/app/dataservices/sql-control/sql-control.component.html similarity index 100% rename from ngapp/src/app/dataservices/sql-control/sql-control.component.html rename to ui/src/app/dataservices/sql-control/sql-control.component.html diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts b/ui/src/app/dataservices/sql-control/sql-control.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/sql-control/sql-control.component.spec.ts rename to ui/src/app/dataservices/sql-control/sql-control.component.spec.ts diff --git a/ngapp/src/app/dataservices/sql-control/sql-control.component.ts b/ui/src/app/dataservices/sql-control/sql-control.component.ts similarity index 100% rename from ngapp/src/app/dataservices/sql-control/sql-control.component.ts rename to ui/src/app/dataservices/sql-control/sql-control.component.ts diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.css b/ui/src/app/dataservices/test-dataservice/test-dataservice.component.css similarity index 100% rename from ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.css rename to ui/src/app/dataservices/test-dataservice/test-dataservice.component.css diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html b/ui/src/app/dataservices/test-dataservice/test-dataservice.component.html similarity index 100% rename from ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.html rename to ui/src/app/dataservices/test-dataservice/test-dataservice.component.html diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts b/ui/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts rename to ui/src/app/dataservices/test-dataservice/test-dataservice.component.spec.ts diff --git a/ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts b/ui/src/app/dataservices/test-dataservice/test-dataservice.component.ts similarity index 100% rename from ngapp/src/app/dataservices/test-dataservice/test-dataservice.component.ts rename to ui/src/app/dataservices/test-dataservice/test-dataservice.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.css b/ui/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.css rename to ui/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html b/ui/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html rename to ui/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts b/ui/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/add-composition-wizard/add-composition-wizard.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/add-composition-command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/add-sources-command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/command-factory.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/command/command-factory.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/command-factory.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/command-factory.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/command-factory.ts b/ui/src/app/dataservices/virtualization/view-editor/command/command-factory.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/command-factory.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/command-factory.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts b/ui/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/command-type.enum.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/no-op-command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/remove-composition-command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/remove-sources-command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.ts b/ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-manager.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-node.ts b/ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-node.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-node.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undo-node.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.ts b/ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/undo-redo/undoable.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/update-projected-columns-command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/update-view-description-command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts b/ui/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts rename to ui/src/app/dataservices/virtualization/view-editor/command/update-view-name-command.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.css b/ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.css rename to ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.html b/ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.html rename to ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts b/ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-table-dialog.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.css b/ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.css rename to ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.html b/ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.html rename to ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.ts b/ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/connection-table-dialog/connection-tree-selector/connection-tree-selector.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.css b/ui/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.css rename to ui/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.html b/ui/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.html rename to ui/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts b/ui/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css b/ui/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html b/ui/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/editor-views.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css b/ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.html b/ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.html rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-log.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-type.enum.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-type.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-type.enum.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message-type.enum.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/message.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/message-log/problem.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.css b/ui/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.css rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.html b/ui/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.html rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts b/ui/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/editor-views/view-preview/view-preview.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-event-type.enum.ts b/ui/src/app/dataservices/virtualization/view-editor/event/view-editor-event-type.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-event-type.enum.ts rename to ui/src/app/dataservices/virtualization/view-editor/event/view-editor-event-type.enum.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts b/ui/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts rename to ui/src/app/dataservices/virtualization/view-editor/event/view-editor-event.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts b/ui/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts rename to ui/src/app/dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas-constants.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/canvas-constants.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas-constants.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/canvas-constants.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event-type.enum.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event-type.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event-type.enum.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event-type.enum.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/event/view-canvas-event.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-graph.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-link.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-link.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-link.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-link.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/canvas-node.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/index.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/index.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/models/index.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/models/index.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/graph/graph-visual.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/index.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/index.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/index.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/index.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/link/link-visual.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html b/ui/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html rename to ui/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts b/ui/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-editor-i18n.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts b/ui/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-editor-part.enum.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-editor.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-editor.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html b/ui/src/app/dataservices/virtualization/view-editor/view-editor.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.html rename to ui/src/app/dataservices/virtualization/view-editor/view-editor.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/view-editor.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-editor.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-editor.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-editor.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-editor.service.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts b/ui/src/app/dataservices/virtualization/view-editor/view-editor.service.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-editor.service.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-editor.service.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-item.model.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/property-editor/selection-type.enum.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts b/ui/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-validator.ts b/ui/src/app/dataservices/virtualization/view-editor/view-validator.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/view-validator.ts rename to ui/src/app/dataservices/virtualization/view-editor/view-validator.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css b/ui/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css rename to ui/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html b/ui/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html rename to ui/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts b/ui/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts rename to ui/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts b/ui/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts similarity index 100% rename from ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts rename to ui/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts diff --git a/ngapp/src/app/shared/abstract-page.component.ts b/ui/src/app/shared/abstract-page.component.ts similarity index 100% rename from ngapp/src/app/shared/abstract-page.component.ts rename to ui/src/app/shared/abstract-page.component.ts diff --git a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.css b/ui/src/app/shared/confirm-dialog/confirm-dialog.component.css similarity index 100% rename from ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.css rename to ui/src/app/shared/confirm-dialog/confirm-dialog.component.css diff --git a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.html b/ui/src/app/shared/confirm-dialog/confirm-dialog.component.html similarity index 100% rename from ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.html rename to ui/src/app/shared/confirm-dialog/confirm-dialog.component.html diff --git a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts b/ui/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts similarity index 100% rename from ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts rename to ui/src/app/shared/confirm-dialog/confirm-dialog.component.spec.ts diff --git a/ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts b/ui/src/app/shared/confirm-dialog/confirm-dialog.component.ts similarity index 100% rename from ngapp/src/app/shared/confirm-dialog/confirm-dialog.component.ts rename to ui/src/app/shared/confirm-dialog/confirm-dialog.component.ts diff --git a/ngapp/src/app/shared/id-filter.ts b/ui/src/app/shared/id-filter.ts similarity index 100% rename from ngapp/src/app/shared/id-filter.ts rename to ui/src/app/shared/id-filter.ts diff --git a/ngapp/src/app/shared/identifiable.ts b/ui/src/app/shared/identifiable.ts similarity index 100% rename from ngapp/src/app/shared/identifiable.ts rename to ui/src/app/shared/identifiable.ts diff --git a/ngapp/src/app/shared/layout-type.enum.ts b/ui/src/app/shared/layout-type.enum.ts similarity index 100% rename from ngapp/src/app/shared/layout-type.enum.ts rename to ui/src/app/shared/layout-type.enum.ts diff --git a/ngapp/src/app/shared/loading-state.enum.ts b/ui/src/app/shared/loading-state.enum.ts similarity index 100% rename from ngapp/src/app/shared/loading-state.enum.ts rename to ui/src/app/shared/loading-state.enum.ts diff --git a/ngapp/src/app/shared/page-error/page-error.component.css b/ui/src/app/shared/page-error/page-error.component.css similarity index 100% rename from ngapp/src/app/shared/page-error/page-error.component.css rename to ui/src/app/shared/page-error/page-error.component.css diff --git a/ngapp/src/app/shared/page-error/page-error.component.html b/ui/src/app/shared/page-error/page-error.component.html similarity index 100% rename from ngapp/src/app/shared/page-error/page-error.component.html rename to ui/src/app/shared/page-error/page-error.component.html diff --git a/ngapp/src/app/shared/page-error/page-error.component.spec.ts b/ui/src/app/shared/page-error/page-error.component.spec.ts similarity index 100% rename from ngapp/src/app/shared/page-error/page-error.component.spec.ts rename to ui/src/app/shared/page-error/page-error.component.spec.ts diff --git a/ngapp/src/app/shared/page-error/page-error.component.ts b/ui/src/app/shared/page-error/page-error.component.ts similarity index 100% rename from ngapp/src/app/shared/page-error/page-error.component.ts rename to ui/src/app/shared/page-error/page-error.component.ts diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.css b/ui/src/app/shared/page-not-found/page-not-found.component.css similarity index 100% rename from ngapp/src/app/shared/page-not-found/page-not-found.component.css rename to ui/src/app/shared/page-not-found/page-not-found.component.css diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.html b/ui/src/app/shared/page-not-found/page-not-found.component.html similarity index 100% rename from ngapp/src/app/shared/page-not-found/page-not-found.component.html rename to ui/src/app/shared/page-not-found/page-not-found.component.html diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts b/ui/src/app/shared/page-not-found/page-not-found.component.spec.ts similarity index 100% rename from ngapp/src/app/shared/page-not-found/page-not-found.component.spec.ts rename to ui/src/app/shared/page-not-found/page-not-found.component.spec.ts diff --git a/ngapp/src/app/shared/page-not-found/page-not-found.component.ts b/ui/src/app/shared/page-not-found/page-not-found.component.ts similarity index 100% rename from ngapp/src/app/shared/page-not-found/page-not-found.component.ts rename to ui/src/app/shared/page-not-found/page-not-found.component.ts diff --git a/ngapp/src/app/shared/progress-dialog/progress-dialog.component.css b/ui/src/app/shared/progress-dialog/progress-dialog.component.css similarity index 100% rename from ngapp/src/app/shared/progress-dialog/progress-dialog.component.css rename to ui/src/app/shared/progress-dialog/progress-dialog.component.css diff --git a/ngapp/src/app/shared/progress-dialog/progress-dialog.component.html b/ui/src/app/shared/progress-dialog/progress-dialog.component.html similarity index 100% rename from ngapp/src/app/shared/progress-dialog/progress-dialog.component.html rename to ui/src/app/shared/progress-dialog/progress-dialog.component.html diff --git a/ngapp/src/app/shared/progress-dialog/progress-dialog.component.spec.ts b/ui/src/app/shared/progress-dialog/progress-dialog.component.spec.ts similarity index 100% rename from ngapp/src/app/shared/progress-dialog/progress-dialog.component.spec.ts rename to ui/src/app/shared/progress-dialog/progress-dialog.component.spec.ts diff --git a/ngapp/src/app/shared/progress-dialog/progress-dialog.component.ts b/ui/src/app/shared/progress-dialog/progress-dialog.component.ts similarity index 100% rename from ngapp/src/app/shared/progress-dialog/progress-dialog.component.ts rename to ui/src/app/shared/progress-dialog/progress-dialog.component.ts diff --git a/ngapp/src/app/shared/property-form/property-control-type.enum.ts b/ui/src/app/shared/property-form/property-control-type.enum.ts similarity index 100% rename from ngapp/src/app/shared/property-form/property-control-type.enum.ts rename to ui/src/app/shared/property-form/property-control-type.enum.ts diff --git a/ngapp/src/app/shared/property-form/property-definition.model.ts b/ui/src/app/shared/property-form/property-definition.model.ts similarity index 100% rename from ngapp/src/app/shared/property-form/property-definition.model.ts rename to ui/src/app/shared/property-form/property-definition.model.ts diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.css b/ui/src/app/shared/property-form/property-form-property/property-form-property.component.css similarity index 100% rename from ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.css rename to ui/src/app/shared/property-form/property-form-property/property-form-property.component.css diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html b/ui/src/app/shared/property-form/property-form-property/property-form-property.component.html similarity index 100% rename from ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.html rename to ui/src/app/shared/property-form/property-form-property/property-form-property.component.html diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts b/ui/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts similarity index 100% rename from ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts rename to ui/src/app/shared/property-form/property-form-property/property-form-property.component.spec.ts diff --git a/ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts b/ui/src/app/shared/property-form/property-form-property/property-form-property.component.ts similarity index 100% rename from ngapp/src/app/shared/property-form/property-form-property/property-form-property.component.ts rename to ui/src/app/shared/property-form/property-form-property/property-form-property.component.ts diff --git a/ngapp/src/app/shared/property-form/property-form.component.css b/ui/src/app/shared/property-form/property-form.component.css similarity index 100% rename from ngapp/src/app/shared/property-form/property-form.component.css rename to ui/src/app/shared/property-form/property-form.component.css diff --git a/ngapp/src/app/shared/property-form/property-form.component.html b/ui/src/app/shared/property-form/property-form.component.html similarity index 100% rename from ngapp/src/app/shared/property-form/property-form.component.html rename to ui/src/app/shared/property-form/property-form.component.html diff --git a/ngapp/src/app/shared/property-form/property-form.component.spec.ts b/ui/src/app/shared/property-form/property-form.component.spec.ts similarity index 100% rename from ngapp/src/app/shared/property-form/property-form.component.spec.ts rename to ui/src/app/shared/property-form/property-form.component.spec.ts diff --git a/ngapp/src/app/shared/property-form/property-form.component.ts b/ui/src/app/shared/property-form/property-form.component.ts similarity index 100% rename from ngapp/src/app/shared/property-form/property-form.component.ts rename to ui/src/app/shared/property-form/property-form.component.ts diff --git a/ngapp/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts similarity index 100% rename from ngapp/src/app/shared/shared.module.ts rename to ui/src/app/shared/shared.module.ts diff --git a/ngapp/src/app/shared/slide-in/slide-in.component.css b/ui/src/app/shared/slide-in/slide-in.component.css similarity index 100% rename from ngapp/src/app/shared/slide-in/slide-in.component.css rename to ui/src/app/shared/slide-in/slide-in.component.css diff --git a/ngapp/src/app/shared/slide-in/slide-in.component.html b/ui/src/app/shared/slide-in/slide-in.component.html similarity index 100% rename from ngapp/src/app/shared/slide-in/slide-in.component.html rename to ui/src/app/shared/slide-in/slide-in.component.html diff --git a/ngapp/src/app/shared/slide-in/slide-in.component.spec.ts b/ui/src/app/shared/slide-in/slide-in.component.spec.ts similarity index 100% rename from ngapp/src/app/shared/slide-in/slide-in.component.spec.ts rename to ui/src/app/shared/slide-in/slide-in.component.spec.ts diff --git a/ngapp/src/app/shared/slide-in/slide-in.component.ts b/ui/src/app/shared/slide-in/slide-in.component.ts similarity index 100% rename from ngapp/src/app/shared/slide-in/slide-in.component.ts rename to ui/src/app/shared/slide-in/slide-in.component.ts diff --git a/ngapp/src/app/shared/sort-direction.enum.ts b/ui/src/app/shared/sort-direction.enum.ts similarity index 100% rename from ngapp/src/app/shared/sort-direction.enum.ts rename to ui/src/app/shared/sort-direction.enum.ts diff --git a/ngapp/src/app/shared/test-data.service.spec.ts b/ui/src/app/shared/test-data.service.spec.ts similarity index 100% rename from ngapp/src/app/shared/test-data.service.spec.ts rename to ui/src/app/shared/test-data.service.spec.ts diff --git a/ngapp/src/app/shared/test-data.service.ts b/ui/src/app/shared/test-data.service.ts similarity index 100% rename from ngapp/src/app/shared/test-data.service.ts rename to ui/src/app/shared/test-data.service.ts diff --git a/ngapp/src/app/shared/validators/name-validator.ts b/ui/src/app/shared/validators/name-validator.ts similarity index 100% rename from ngapp/src/app/shared/validators/name-validator.ts rename to ui/src/app/shared/validators/name-validator.ts diff --git a/ngapp/src/assets/.gitkeep b/ui/src/assets/.gitkeep similarity index 100% rename from ngapp/src/assets/.gitkeep rename to ui/src/assets/.gitkeep diff --git a/ngapp/src/assets/MongoDB_70x40.png b/ui/src/assets/MongoDB_70x40.png similarity index 100% rename from ngapp/src/assets/MongoDB_70x40.png rename to ui/src/assets/MongoDB_70x40.png diff --git a/ngapp/src/assets/MySQL_70x40.png b/ui/src/assets/MySQL_70x40.png similarity index 100% rename from ngapp/src/assets/MySQL_70x40.png rename to ui/src/assets/MySQL_70x40.png diff --git a/ngapp/src/assets/PostgresSql_70x40.png b/ui/src/assets/PostgresSql_70x40.png similarity index 100% rename from ngapp/src/assets/PostgresSql_70x40.png rename to ui/src/assets/PostgresSql_70x40.png diff --git a/ngapp/src/assets/composition.png b/ui/src/assets/composition.png similarity index 100% rename from ngapp/src/assets/composition.png rename to ui/src/assets/composition.png diff --git a/ngapp/src/assets/graphicsfuel/database-64.png b/ui/src/assets/graphicsfuel/database-64.png similarity index 100% rename from ngapp/src/assets/graphicsfuel/database-64.png rename to ui/src/assets/graphicsfuel/database-64.png diff --git a/ngapp/src/assets/graphicsfuel/readme.txt b/ui/src/assets/graphicsfuel/readme.txt similarity index 100% rename from ngapp/src/assets/graphicsfuel/readme.txt rename to ui/src/assets/graphicsfuel/readme.txt diff --git a/ngapp/src/assets/iconfinder/Aha-soft/license.pdf b/ui/src/assets/iconfinder/Aha-soft/license.pdf similarity index 100% rename from ngapp/src/assets/iconfinder/Aha-soft/license.pdf rename to ui/src/assets/iconfinder/Aha-soft/license.pdf diff --git a/ngapp/src/assets/iconfinder/Aha-soft/minus-depressed.png b/ui/src/assets/iconfinder/Aha-soft/minus-depressed.png similarity index 100% rename from ngapp/src/assets/iconfinder/Aha-soft/minus-depressed.png rename to ui/src/assets/iconfinder/Aha-soft/minus-depressed.png diff --git a/ngapp/src/assets/iconfinder/Aha-soft/minus.png b/ui/src/assets/iconfinder/Aha-soft/minus.png similarity index 100% rename from ngapp/src/assets/iconfinder/Aha-soft/minus.png rename to ui/src/assets/iconfinder/Aha-soft/minus.png diff --git a/ngapp/src/assets/iconfinder/Aha-soft/plus-depressed.png b/ui/src/assets/iconfinder/Aha-soft/plus-depressed.png similarity index 100% rename from ngapp/src/assets/iconfinder/Aha-soft/plus-depressed.png rename to ui/src/assets/iconfinder/Aha-soft/plus-depressed.png diff --git a/ngapp/src/assets/iconfinder/Aha-soft/plus.png b/ui/src/assets/iconfinder/Aha-soft/plus.png similarity index 100% rename from ngapp/src/assets/iconfinder/Aha-soft/plus.png rename to ui/src/assets/iconfinder/Aha-soft/plus.png diff --git a/ngapp/src/assets/iconfinder/Natalya-Skidan/license.pdf b/ui/src/assets/iconfinder/Natalya-Skidan/license.pdf similarity index 100% rename from ngapp/src/assets/iconfinder/Natalya-Skidan/license.pdf rename to ui/src/assets/iconfinder/Natalya-Skidan/license.pdf diff --git a/ngapp/src/assets/iconfinder/Natalya-Skidan/question-mark.png b/ui/src/assets/iconfinder/Natalya-Skidan/question-mark.png similarity index 100% rename from ngapp/src/assets/iconfinder/Natalya-Skidan/question-mark.png rename to ui/src/assets/iconfinder/Natalya-Skidan/question-mark.png diff --git a/ngapp/src/assets/iconfinder/creative-commons.pdf b/ui/src/assets/iconfinder/creative-commons.pdf similarity index 100% rename from ngapp/src/assets/iconfinder/creative-commons.pdf rename to ui/src/assets/iconfinder/creative-commons.pdf diff --git a/ngapp/src/assets/redhat-iot.png b/ui/src/assets/redhat-iot.png similarity index 100% rename from ngapp/src/assets/redhat-iot.png rename to ui/src/assets/redhat-iot.png diff --git a/ngapp/src/assets/salesforce_40x40.png b/ui/src/assets/salesforce_40x40.png similarity index 100% rename from ngapp/src/assets/salesforce_40x40.png rename to ui/src/assets/salesforce_40x40.png diff --git a/ngapp/src/assets/table.png b/ui/src/assets/table.png similarity index 100% rename from ngapp/src/assets/table.png rename to ui/src/assets/table.png diff --git a/ngapp/src/assets/teiid-lizard-gradient-bgd.png b/ui/src/assets/teiid-lizard-gradient-bgd.png similarity index 100% rename from ngapp/src/assets/teiid-lizard-gradient-bgd.png rename to ui/src/assets/teiid-lizard-gradient-bgd.png diff --git a/ngapp/src/assets/vdb.png b/ui/src/assets/vdb.png similarity index 100% rename from ngapp/src/assets/vdb.png rename to ui/src/assets/vdb.png diff --git a/ngapp/src/environments/environment.prod.ts b/ui/src/environments/environment.prod.ts similarity index 100% rename from ngapp/src/environments/environment.prod.ts rename to ui/src/environments/environment.prod.ts diff --git a/ngapp/src/environments/environment.ts b/ui/src/environments/environment.ts similarity index 100% rename from ngapp/src/environments/environment.ts rename to ui/src/environments/environment.ts diff --git a/ngapp/src/favicon.ico b/ui/src/favicon.ico similarity index 100% rename from ngapp/src/favicon.ico rename to ui/src/favicon.ico diff --git a/ngapp/src/index.html b/ui/src/index.html similarity index 100% rename from ngapp/src/index.html rename to ui/src/index.html diff --git a/ngapp/src/main.ts b/ui/src/main.ts similarity index 100% rename from ngapp/src/main.ts rename to ui/src/main.ts diff --git a/ngapp/src/polyfills.ts b/ui/src/polyfills.ts similarity index 100% rename from ngapp/src/polyfills.ts rename to ui/src/polyfills.ts diff --git a/ngapp/src/styles.css b/ui/src/styles.css similarity index 100% rename from ngapp/src/styles.css rename to ui/src/styles.css diff --git a/ngapp/src/test.ts b/ui/src/test.ts similarity index 100% rename from ngapp/src/test.ts rename to ui/src/test.ts diff --git a/ngapp/src/tsconfig.app.json b/ui/src/tsconfig.app.json similarity index 100% rename from ngapp/src/tsconfig.app.json rename to ui/src/tsconfig.app.json diff --git a/ngapp/src/tsconfig.spec.json b/ui/src/tsconfig.spec.json similarity index 100% rename from ngapp/src/tsconfig.spec.json rename to ui/src/tsconfig.spec.json diff --git a/ngapp/src/typings.d.ts b/ui/src/typings.d.ts similarity index 100% rename from ngapp/src/typings.d.ts rename to ui/src/typings.d.ts diff --git a/ngapp/start.sh b/ui/start.sh similarity index 100% rename from ngapp/start.sh rename to ui/start.sh diff --git a/ngapp/tsconfig.json b/ui/tsconfig.json similarity index 100% rename from ngapp/tsconfig.json rename to ui/tsconfig.json diff --git a/ngapp/tslint.json b/ui/tslint.json similarity index 100% rename from ngapp/tslint.json rename to ui/tslint.json From 9b053c900707595761cf1e38b1d40098452f261e Mon Sep 17 00:00:00 2001 From: Ramesh Reddy Date: Wed, 31 Oct 2018 16:32:17 -0500 Subject: [PATCH 204/205] TEIIDTOOLS-523: Beetle move to Komodo --- documentation/dev-notes/dev-notes.md | 38 ++++ documentation/i18n/README.md | 39 ++++ documentation/ide/webstorm-guide.md | 62 +++++ .../openshift-setup/openshift-setup.md | 30 +++ documentation/style-guide/style-guide.md | 71 ++++++ pom.xml | 1 + ui/pom.xml | 215 ++++++++++++++++++ 7 files changed, 456 insertions(+) create mode 100644 documentation/dev-notes/dev-notes.md create mode 100644 documentation/i18n/README.md create mode 100644 documentation/ide/webstorm-guide.md create mode 100644 documentation/openshift-setup/openshift-setup.md create mode 100644 documentation/style-guide/style-guide.md create mode 100644 ui/pom.xml diff --git a/documentation/dev-notes/dev-notes.md b/documentation/dev-notes/dev-notes.md new file mode 100644 index 00000000..dacd8d09 --- /dev/null +++ b/documentation/dev-notes/dev-notes.md @@ -0,0 +1,38 @@ +# Beetle Studio Developer Notes + +This document is intended to be the "landing place" for information that would make a Beetle Studio +developer's life easier. Each note should highlight in **bold** the keywords. Developers should add +to this document any task steps, processes, debugging steps, URLs, or anything else to save the +"next" developer time and effort. + +- When upgrading `patternfly-ng`, you will also need to update the version of the **Patternfly** stylesheets referenced +in `src/index.html`. One thing that may happen when the stylesheet version and the library version +are not in sync is the components may not display. + +- If running tests in the **IDE** and the **test** immediately aborts, kill the **Karma** server and rerun +the test. + +- If a variable of a class is `nil` when you know it really isn't, you are probably trying to +access it from a `callback` handler. Change your code to save the object reference +in a constant and use that in the handler code. Here is an example: + +```typescript + const self = this; + + this.connectionService + .getAllConnections() + .subscribe( + (connections) => { + self.allConns = connections; + self.filteredConns = this.filterConnections(); + self.loaded("connections"); + }, + (error) => { + self.logger.error("[ConnectionsComponent] Error getting connections."); + self.error(error); + } + ); +``` + +- When using `Response` and `ResponseOptions` classes, make sure you use the version from the +`@angular/http` library. diff --git a/documentation/i18n/README.md b/documentation/i18n/README.md new file mode 100644 index 00000000..62db6176 --- /dev/null +++ b/documentation/i18n/README.md @@ -0,0 +1,39 @@ +# Internationalization in Beetle + +`Beetle` uses the built-in i8n functionality provided by **Angular**. It is well-documented here: https://angular.io/guide/i18n, but we document the steps here as well for purposes of brevity and clarity as i18n applies to `Beetle`. + +The steps to i8n are as follows: + +1. Add your attribute. Adding the **`i18n`** you would like made available for translation. + +For example: + +`

    Hello text

    ` + +`

    Hello text

    ` + +`

    Hello text

    ` + +`

    Hello {name}

    ` + +Where **meaning** is the name of the text field to translate, **description** is short description of the text and the **id** is a unique value we specify to easily identify the text in the i18n file and in code. + +If the **id** is omitted, one will be generated for you, but it is long, complex and not easily identifiable as to it's association. The format for the id is file name of the html where the translation lives, a dot(.), filed by the meaning value CamelCase and without dashes or spaces. For Example: If the **id** is omitted, one will be generated for you, but it is long, complex and not easily identifiable as to it's association. The format for the id is file name of the html where the translation lives, a dot, filed by the meaning value CamelCase and without dashes. For Example: +`i18n="Connection Properties|Properties for a connection@@addConnectionForm.connectionProperties"` + +There are other acceptable formats such as for plural values and image titles. Please see the Angular documentation for these additional formats. + +2. Run the messages generator. Open a terminal window at /src/main/ngapp/ of the application project and enter the ng-xi18n command: `./node_modules/.bin/ng-xi18n --i18nFormat=xlf --outFile=messages.xlf` which will generate `messages.xlf` in the root folder of project. This file will contain all the translatable fields. You will need to compare this `messages.xlf` to the latest in `master`. Add any new translations to each messages.{language}.xlf file in {root}/src/locale. For example, messages.es.xlf for Spanish translations. If this is the first time a translation file is being generated for a language, just copy the generates message file over to the src/locale folder, rename the new file messages.{languagecode}.xlf. + +You will then need to add the correct translation: + + + Hello i18n! + ¡Hola i18n! + An introduction header for this sample + User welcome + + +3. Generate the war for each language. Run `ng serve --aot --locale es --i18n-format xlf --i18n-file ./locale/messages.{languageCode}.xlf` +Running the maven build will likely handle this step as well. + diff --git a/documentation/ide/webstorm-guide.md b/documentation/ide/webstorm-guide.md new file mode 100644 index 00000000..42fe5fef --- /dev/null +++ b/documentation/ide/webstorm-guide.md @@ -0,0 +1,62 @@ +# Beetle Studio WebStorm IDE Guide + +## Settings and Preferences: + +- Enable TSLint. Select menu item `WebStorm > Preferences... > Languages & Frameworks > Typescript > TSLint` +Make sure the `Enabled` checkbox is selected. +- Exclude the `target/` directory from being looked at by TSLint. Go to menu item `WebStorm > Preferences... > Directories`. +Add the `target/` directory as being `Excluded`. If the directory does not exist, run a maven build +first. + +## TSLint + +TSLint is a code analysis tool used during development to facilitate the improvement of TypeScript +code quality. TSLint should be run before checking in any code. Any errors or warnings that TSLint +identifies should be fixed prior to promoting any code to the Github repository. Errors and warnings +in the `Spelling` category can generally be ignored though can be fixed if it would improve code quality. + +To run TSLint, select the `Code > Inspect Code...` menu item. Make sure `Whole project` and +`Include test sources` are both selected and then `OK` the dialog. The errors and warnings found will +be displayed in the `Inspection Results` panel which is displayed at the bottom of the IDE window. + +The TSLint rule configuration file is located here: `.../beetle-studio/src/main/ngapp/tslint.json`. See +our [Beetle Studio Style Guide](https://github.com/teiid/beetle-studio/documentation/style-guide/style-guide.md) +for more information on our TypeScript style guidelines. + +## Angular CLI + +_WebStorm_ has builtin support for [Angular CLI](https://cli.angular.io). As the name suggests _Angular CLI_ +is a command line interface for Angular. _Beetle Studio_ has been created as an _Angular CLI_ project so using +_Angular CLI_ commands is something you will do daily. These CLI commands will be executed in the +_.../beetle-studio/src/main/ngapp_ directory. + +Here are 2 commands that are used a lot: + +- **ng serve** - runs the debug test server. +- **ng test** - runs the tests found in the project + +_WebStorm_ has a menu that uses other CLI commands to create components, services, modules, and +other object types. Select _File > New > Angular CLI..._ when needing to create a new object. Then +select the appropriate type. _WebStorm_ then executes the appropriate _Angular CLI_ command to create +the object and related objects (test, css, html) in the recommended directories. + +## Debugging + +1. Create Debug Configuration. To create a debug configuration, select the menu item `Run > Edit Configurations...`. In the +`Run/Debug Configurations` dialog, select the `+` in the menubar and then the `JavaScript Debug` type. Name the +configuration and set the `URL` to `http://localhost:4200/`. +1. Start the debug server by opening a terminal in the `.../beetle-studio/src/main/ngapp` directory +and running the following command: `ng serve`. +1. Set your breakpoints by clicking in the left margin of the line of code you want the breakpoint to be on. +1. Open browser to `http://localhost:4200/` to see _Beetle Studio_. +1. Select the `Run > Debug...` menu item and then on the popup select your debug configuration. _Shortcut: the "bug" +in the toolbar starts the last debug configuration that was run._ +1. Now interact with _Beetle Studio_ so that your breakpoints are hit. + +## TODO Comments + +`TODO` comments should be used when there is some task that should be done at a future date. If the +task is a blocker or critical to the software a Jira issue should be created instead of, or in addition +to, this type of comment. The format of a `TODO` comment is this: + +`// TODO description of task goes here` diff --git a/documentation/openshift-setup/openshift-setup.md b/documentation/openshift-setup/openshift-setup.md new file mode 100644 index 00000000..7d103d52 --- /dev/null +++ b/documentation/openshift-setup/openshift-setup.md @@ -0,0 +1,30 @@ +# Openshift Setup + +_Beetle Studio_ requires an Openshift instance for deployment. A number of Openshift installations are available to install and any one can be used as the application platform. _Beetle Studio_ can then access datasources provisioned from the Openshift Service Catalog. If you already have a shared Openshift installation, you can install _Beetle Studio_ to the shared installation. + +## Openshift CDK Installation + +A self-contained installation of the Openshift container platform has been published: [Openshift CDK Installation](http://www.schabell.org/2017/12/cloud-happiness-how-to-install-new-openshift-v37-in-minutes.html) . This is an excellent option for getting an Openshift installation up-and-running quickly. + +## Minishift + +[Minishift](https://github.com/minishift/minishift) can also be used to provide your local installation. See the [Minishift README](https://github.com/minishift/minishift/blob/master/README.adoc) for installation instructions. + +By default, minishift is configured to use 2GB of memory and 20GB of storage space. For serious development, since 4 pods are required to be deployed (requiring 0.5GB each), this has proven insufficient. Therefore, it is recommended to configure minishift with 6GB of memory and 50GB of storage space. If this proves problematic then lower values may be sufficient but will require some experimentation. These configuration options can only be configured when minishift is not running. They can be set with the following commands: +```bash + $ minishift config set disk-size 60GB + $ minishfit config set memory 6GB +``` +Minishift provides a virtual machine (VM) with the Openshift installation installed and configured. Once installed, all that remains is to start minishift. The configuration options should be observed when minishift is started. Once the VM has started, it is possible to remote-login to the VM using the command: +```bash + $ minishift ssh +``` +This is useful for problem-finding. + +To update to minishift’s latest release requires executing the update command. +```bash + $ minishift update +``` +Once minishift has been started, Openshift should be available for access on the ip address assigned, eg. https://192.168.42.143:8443. +To ensure command-line access to Openshift, the oc application should be added to the PATH environment variable. A copy of this binary is available from minishift for example at ${HOME}/.minishift/cache/oc/v3.6.1/linux/oc. + diff --git a/documentation/style-guide/style-guide.md b/documentation/style-guide/style-guide.md new file mode 100644 index 00000000..6342bbf1 --- /dev/null +++ b/documentation/style-guide/style-guide.md @@ -0,0 +1,71 @@ +# Beetle Studio Style Guide + +_Beetle Studio_'s TypeScript style conventions are based on the [angular.io style guide](https://angular.io/guide/styleguide). +The _Beetle Studio_'s [tslint.json](https://github.com/teiid/beetle-studio/src/main/ngapp/tslint.json) file describes the +rules used to "enforce" the guidelines and project structure recommended by the _angular.io_ document. + +The goal of having style guidelines and conventions is to increase maintainability and readability. + +## Project Structure + +_Beetle Studio_ has tried to use the file structure recommended by _angular.io_, with minor +modifications due to facilitating a maven build process. + +So _Beetle Studio_ has feature modules (connections, dataservices), a _CoreModule_ (for singletons and +single use objects), and a _SharedModule_ (for reusable objects). Within each feature +module there may be a _shared_ folder for services and other shared objects). See the +_Overall structural guidelines_ section of the [angular.io style guide](https://angular.io/guide/styleguide) +for more details. + +## Naming Conventions + +In general, file names have the following syntax: ..ts. _Note: if has +multiple words, separate words by dashes. Uppercase letters should not be used._ + +Here are some examples: + +- connection.service.ts - a service name `ConnectionService`. +- connection.service.spec.ts - a test for the `ConnectionService`. +- connections.module.ts - a feature module called `ConnectionsModule`. +- add-connection.component.ts - a component called `AddConnectionComponent`. +- connection.model.ts - a class called `Connection`. + +See the _Naming_ section of the [angular.io style guide](https://angular.io/guide/styleguide) +for more details. + +## TSLint Settings + +Our _TSLint_ configuration file (`tslint.json`) inherits recommended rules. We also have included added and overwritten +rules. _Note: Rules can be overridden on a case by case if needed by adding a special comment to the +offending line of code. WebStorm has a quick fix that will do this for you._ + +Here are a **few** of the TSLint rules defined in our configuration file used: + +- **align** - used to align member properties and statements. +- **component-class-suffix** - all components need to have `Component` as the name suffix. +- **directive-class-suffix** - all directives need to have `Directive` as the name suffix. +- **max-classes-per-file** - value is set to one so that classes, enums, types, etc. can easily be found. +- **max-line-length** - set to 140. (which is plenty long!) +- **member-ordering** - public declarations must come before private declarations, static declarations +must come before instance declarations, and variables must come before functions. +- **no-consecutive-blank-lines** - only one blank line can appear together. +- **no-empty** - empty blocks are not allowed. Fill in with a comment like `// nothing to do` if you +really need an empty block. +- **one-variable-per-declaration** - promotes better readability and maintenance. +- **ordered-imports** - imports are ordered alphabetically so that they can be found easier. +- **quotemark** - set to use double quotes. Prevents both single and double being used and mixed within the codebase. +- **typedef** - return type, parameter type, property type must be explicitly set if an initializer is not used. + +## Notable Style Guidelines + +- **Style 01-01** - Limit files to 400 lines. +- **Style 01-02** - Limit functions to 75 lines. +- **Style 02-01** - Use consistent names for all symbols. +- **Style 03-01** - Use upper camel case when naming classes. +- **Style 03-02** - Spell `const` variables in lower camel case. +- **Style 03-03** - Do not name with an `I` prefix. +- **Style 03-04** - Do use lower camel case to name properties and methods. +- **Style 05-04** - Extract templates and styles into a separate file, when more than 3 lines. +- **Style 05-16** - Do name events without the prefix `on`. Do name event handler methods with the +prefix `on` followed by the event name. +- **Style 05-17** - diff --git a/pom.xml b/pom.xml index da0927e1..d4a80afd 100644 --- a/pom.xml +++ b/pom.xml @@ -126,6 +126,7 @@ server + ui diff --git a/ui/pom.xml b/ui/pom.xml new file mode 100644 index 00000000..37c9bc70 --- /dev/null +++ b/ui/pom.xml @@ -0,0 +1,215 @@ + + + org.teiid + komodo-parent + 0.0.5-SNAPSHOT + ../pom.xml + + + + + 4.0.0 + beetle-studio + Web tooling supporting the Teiid project. + BeETLe Studio + war + 0.0.5-SNAPSHOT + + + + + + + Mark Drilling + mdrillin + mdrillin@redhat.com + Red Hat + + Project Lead + Developer + + -6 + + + Dan Florian + elvisisking + dflorian@redhat.com + Red Hat + + Developer + + -6 + + + Ted Jones + tejones + tejones@redhat.com + Red Hat + + Developer + + -6 + + + + + + + + ${basedir}/target/copy-src + yyyy-MM-dd HH:mm:ss + UTF-8 + ${maven.build.timestamp} + 1.5.0 + 1.8 + 3.0.0 + 3.5.1 + 2.7 + 2.6 + beetle-studio + + + + + + + ${finalName} + + + + + maven-resources-plugin + org.apache.maven.plugins + ${version.maven-resources-plugin} + + + copy-angular-sources + validate + + copy-resources + + + ${target.src.dir} + + + ${basedir} + + **/* + + + **/node_modules/** + + + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${version.maven-antrun-plugin} + + + chmod-ng-cmd + process-resources + + run + + + + run chmod in ${basedir} + + + + + + + + + + exec-maven-plugin + org.codehaus.mojo + ${version.exec-maven-plugin} + + + npm-install + + exec + + generate-resources + + npm + + install + + ${target.src.dir} + + + + + + + + + angular-cli-build + + exec + + compile + + node_modules/@angular/cli/bin/ng + + build + --prod + --bh + ./ + + ${target.src.dir} + + + + + + karmaTest + + exec + + test + + ng + + test + + ${target.src.dir} + + + + + + + + maven-war-plugin + org.apache.maven.plugins + ${version.maven-war-plugin} + + false + + + ${target.src.dir}/dist + + **/*.* + + + + + + + + From 65decef6b56fd536bc586f3a446530a09630f52e Mon Sep 17 00:00:00 2001 From: Ramesh Reddy Date: Thu, 1 Nov 2018 10:20:35 -0500 Subject: [PATCH 205/205] Updating the .gitignore for UI --- .gitignore | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/.gitignore b/.gitignore index 0e329821..7179bb25 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,49 @@ tmp **/_remote.repositories .metadata/ .recommenders/ + +# compiled output +/dist +/tmp +/out-tsc +/src/main/ngapp/dist + +# dependencies +node_modules/ + +# IDEs and editors +/.idea +*.iml +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +testem.log +/typings +yarn-error.log + +# e2e +/e2e/*.js +/e2e/*.map + +# System Files +.DS_Store +Thumbs.db + +target/