You are viewing a plain text version of this content. The canonical link for it is here.
Posted to submarine-dev@hadoop.apache.org by zh...@apache.org on 2019/10/22 08:14:51 UTC
[hadoop-submarine] branch master updated: SUBMARINE-241. Workbench
web ng
This is an automated email from the ASF dual-hosted git repository.
zhouquan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hadoop-submarine.git
The following commit(s) were added to refs/heads/master by this push:
new 15c18b0 SUBMARINE-241. Workbench web ng
15c18b0 is described below
commit 15c18b004aab4376107d3830b85f969c91d25ef9
Author: lleohao <ll...@hotmail.com>
AuthorDate: Tue Oct 22 12:24:03 2019 +0800
SUBMARINE-241. Workbench web ng
### What is this PR for?
Develop Web Framework with Angular and Ng-zero
Init project and add user module ( login and regisiter )
### What type of PR is it?
[Feature]
### What is the Jira issue?
https://issues.apache.org/jira/browse/SUBMARINE-241
### How should this be tested?
No test
### Screenshots (if appropriate)
![image](https://user-images.githubusercontent.com/12764126/67159475-c0a1d580-f377-11e9-865e-d934a6bf9be3.png)
### Questions:
* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No
Author: lleohao <ll...@hotmail.com>
Closes #58 from lleohao/workbench-web-ng and squashes the following commits:
52b819a [lleohao] [SUBMARINE-241] refactor: translate to english
7b6c726 [lleohao] [SUBMARINE-241] fix: fix package error
c529061 [lleohao] [SUBMARINE-241] feat: LocalStorageService add error log
bda54d7 [lleohao] [SUBMARINE-241] refactor: change register title
b5228a8 [lleohao] [SUBMARINE-241] refactor: translate to english
884c46e [lleohao] [SUBMARINE-241] refactor: remove unused pom config
0cb5548 [lleohao] [SUBMARINE-241] refactor: update copyright
db779a4 [lleohao] SUBMARINE-241. Fix workbench-web-ng pom error
d7edee3 [lleohao] SUBMARINE-241. Fix rat check
49dd692 [lleohao] SUBMARINE-241. Add workbench-web-ng LICENSE
3908d06 [lleohao] SUBMARINE-241. Remove commit lint
fa4041d [lleohao] SUBMARINE-241. Add login page and auth guard
5a0d1b5 [lleohao] feat: init angular project
---
submarine-workbench/pom.xml | 1 +
submarine-workbench/workbench-web-ng/.editorconfig | 14 +
submarine-workbench/workbench-web-ng/.gitignore | 46 ++
.../workbench-web-ng/.prettierignore | 4 +
submarine-workbench/workbench-web-ng/.prettierrc | 15 +
submarine-workbench/workbench-web-ng/LICENSE | 16 +
submarine-workbench/workbench-web-ng/README.md | 29 ++
submarine-workbench/workbench-web-ng/angular.json | 136 +++++
submarine-workbench/workbench-web-ng/browserslist | 12 +
.../workbench-web-ng/e2e/protractor.conf.js | 51 ++
.../workbench-web-ng/e2e/src/app.e2e-spec.ts | 42 ++
.../workbench-web-ng/e2e/src/app.po.ts | 30 ++
.../workbench-web-ng/e2e/tsconfig.json | 13 +
submarine-workbench/workbench-web-ng/karma.conf.js | 51 ++
submarine-workbench/workbench-web-ng/package.json | 52 ++
submarine-workbench/workbench-web-ng/pom.xml | 62 +++
submarine-workbench/workbench-web-ng/proxy.conf.js | 66 +++
.../workbench-web-ng/src/WEB-INF/web.xml | 47 ++
.../workbench-web-ng/src/app/app-routing.module.ts | 45 ++
.../workbench-web-ng/src/app/app.component.html | 74 +++
.../workbench-web-ng/src/app/app.component.scss | 99 ++++
.../workbench-web-ng/src/app/app.component.spec.ts | 50 ++
.../workbench-web-ng/src/app/app.component.ts | 40 ++
.../workbench-web-ng/src/app/app.module.ts | 50 ++
.../src/app/core/auth/auth.guard.ts | 48 ++
.../workbench-web-ng/src/app/core/index.ts | 20 +
.../workbench-web-ng/src/app/core/publick-api.ts | 20 +
.../src/app/icons-provider.module.ts | 30 ++
.../workbench-web-ng/src/app/interfaces/index.ts | 20 +
.../src/app/interfaces/permission.ts | 35 ++
.../src/app/interfaces/public-api.ts | 23 +
.../workbench-web-ng/src/app/interfaces/rest.ts | 26 +
.../workbench-web-ng/src/app/interfaces/role.ts | 31 ++
.../workbench-web-ng/src/app/interfaces/user.ts | 31 ++
.../app/pages/manager/manager-routing.module.ts | 47 ++
.../src/app/pages/manager/manager.component.html | 21 +
.../src/app/pages/manager/manager.component.scss | 19 +
.../src/app/pages/manager/manager.component.ts | 31 ++
.../src/app/pages/manager/manager.module.ts | 31 ++
.../src/app/pages/manager/user/user.component.html | 20 +
.../src/app/pages/manager/user/user.component.scss | 19 +
.../src/app/pages/manager/user/user.component.ts | 31 ++
.../app/pages/user/login/login-routing.module.ts | 30 ++
.../src/app/pages/user/login/login.component.html | 46 ++
.../src/app/pages/user/login/login.component.scss | 31 ++
.../src/app/pages/user/login/login.component.ts | 86 ++++
.../pages/user/register/register.component.html | 20 +
.../pages/user/register/register.component.scss | 19 +
.../app/pages/user/register/register.component.ts | 31 ++
.../src/app/pages/user/user-routing.module.ts | 52 ++
.../src/app/pages/user/user.component.html | 31 ++
.../src/app/pages/user/user.component.scss | 55 ++
.../src/app/pages/user/user.component.ts | 31 ++
.../src/app/pages/user/user.module.ts | 33 ++
.../src/app/services/auth.service.ts | 70 +++
.../src/app/services/base-api.service.ts | 58 +++
.../workbench-web-ng/src/app/services/index.ts | 20 +
.../src/app/services/local-storage.service.ts | 53 ++
.../src/app/services/public-api.ts | 20 +
.../workbench-web-ng/src/assets/.gitkeep | 0
.../workbench-web-ng/src/assets/background.svg | 69 +++
.../workbench-web-ng/src/assets/logo-128.png | Bin 0 -> 6098 bytes
.../workbench-web-ng/src/assets/submarine-logo.svg | 133 +++++
.../src/environments/environment.prod.ts | 22 +
.../src/environments/environment.ts | 35 ++
.../workbench-web-ng/src/favicon.ico | Bin 0 -> 113805 bytes
.../workbench-web-ng/src/index.html | 32 ++
submarine-workbench/workbench-web-ng/src/main.ts | 31 ++
.../workbench-web-ng/src/polyfills.ts | 82 +++
.../workbench-web-ng/src/styles.scss | 20 +
submarine-workbench/workbench-web-ng/src/test.ts | 39 ++
.../workbench-web-ng/src/theme.less | 561 +++++++++++++++++++++
.../workbench-web-ng/tsconfig.app.json | 18 +
submarine-workbench/workbench-web-ng/tsconfig.json | 32 ++
.../workbench-web-ng/tsconfig.spec.json | 18 +
submarine-workbench/workbench-web-ng/tslint.json | 142 ++++++
76 files changed, 3468 insertions(+)
diff --git a/submarine-workbench/pom.xml b/submarine-workbench/pom.xml
index 7238f42..0fc9ae9 100644
--- a/submarine-workbench/pom.xml
+++ b/submarine-workbench/pom.xml
@@ -39,6 +39,7 @@
<modules>
<module>interpreter</module>
<module>workbench-web</module>
+ <module>workbench-web-ng</module>
<module>workbench-server</module>
</modules>
diff --git a/submarine-workbench/workbench-web-ng/.editorconfig b/submarine-workbench/workbench-web-ng/.editorconfig
new file mode 100644
index 0000000..c97d1a4
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/.editorconfig
@@ -0,0 +1,14 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+end_of_line=lf
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/submarine-workbench/workbench-web-ng/.gitignore b/submarine-workbench/workbench-web-ng/.gitignore
new file mode 100644
index 0000000..86d943a
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/.gitignore
@@ -0,0 +1,46 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+# compiled output
+/dist
+/tmp
+/out-tsc
+# Only exists if Bazel was run
+/bazel-out
+
+# dependencies
+/node_modules
+
+# profiling files
+chrome-profiler-events*.json
+speed-measure-plugin*.json
+
+# 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
+.history/*
+
+# misc
+/.sass-cache
+/connect.lock
+/coverage
+/libpeerconnection.log
+npm-debug.log
+yarn-error.log
+testem.log
+/typings
+
+# System Files
+.DS_Store
+Thumbs.db
diff --git a/submarine-workbench/workbench-web-ng/.prettierignore b/submarine-workbench/workbench-web-ng/.prettierignore
new file mode 100644
index 0000000..02a039a
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/.prettierignore
@@ -0,0 +1,4 @@
+**/*.md
+**/*.less
+**/*.scss
+**/*.svg
diff --git a/submarine-workbench/workbench-web-ng/.prettierrc b/submarine-workbench/workbench-web-ng/.prettierrc
new file mode 100644
index 0000000..4b9bb8a
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/.prettierrc
@@ -0,0 +1,15 @@
+{
+ "singleQuote": true,
+ "printWidth": 120,
+ "tabWidth": 2,
+ "useTabs": false,
+ "htmlWhitespaceSensitivity": "ignore",
+ "overrides": [
+ {
+ "files": ".prettierrc",
+ "options": {
+ "parser": "json"
+ }
+ }
+ ]
+}
diff --git a/submarine-workbench/workbench-web-ng/LICENSE b/submarine-workbench/workbench-web-ng/LICENSE
new file mode 100644
index 0000000..60b675e
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/LICENSE
@@ -0,0 +1,16 @@
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
diff --git a/submarine-workbench/workbench-web-ng/README.md b/submarine-workbench/workbench-web-ng/README.md
new file mode 100644
index 0000000..e6019dc
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/README.md
@@ -0,0 +1,29 @@
+# Submarine Web
+
+This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.9.
+
+## Development server
+
+> Start the Submarine server first
+
+Run `npm start` 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/).
+
+## 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/submarine-workbench/workbench-web-ng/angular.json b/submarine-workbench/workbench-web-ng/angular.json
new file mode 100644
index 0000000..c47d29d
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/angular.json
@@ -0,0 +1,136 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "workbench-web-ng": {
+ "projectType": "application",
+ "schematics": {
+ "@schematics/angular:component": {
+ "style": "scss"
+ }
+ },
+ "root": "",
+ "sourceRoot": "src",
+ "prefix": "app",
+ "architect": {
+ "build": {
+ "builder": "@angular-devkit/build-angular:browser",
+ "options": {
+ "outputPath": "dist/workbench-web-ng",
+ "index": "src/index.html",
+ "main": "src/main.ts",
+ "polyfills": "src/polyfills.ts",
+ "tsConfig": "tsconfig.app.json",
+ "aot": false,
+ "assets": [
+ "src/favicon.ico",
+ "src/assets",
+ {
+ "glob": "**/*",
+ "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
+ "output": "/assets/"
+ }
+ ],
+ "styles": [
+ "src/theme.less",
+ "src/styles.scss"
+ ],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "fileReplacements": [
+ {
+ "replace": "src/environments/environment.ts",
+ "with": "src/environments/environment.prod.ts"
+ }
+ ],
+ "optimization": true,
+ "outputHashing": "all",
+ "sourceMap": false,
+ "extractCss": true,
+ "namedChunks": false,
+ "aot": true,
+ "extractLicenses": true,
+ "vendorChunk": false,
+ "buildOptimizer": true,
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "2mb",
+ "maximumError": "5mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "6kb",
+ "maximumError": "10kb"
+ }
+ ]
+ }
+ }
+ },
+ "serve": {
+ "builder": "@angular-devkit/build-angular:dev-server",
+ "options": {
+ "browserTarget": "workbench-web-ng:build"
+ },
+ "configurations": {
+ "production": {
+ "browserTarget": "workbench-web-ng:build:production"
+ }
+ }
+ },
+ "extract-i18n": {
+ "builder": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "workbench-web-ng:build"
+ }
+ },
+ "test": {
+ "builder": "@angular-devkit/build-angular:karma",
+ "options": {
+ "main": "src/test.ts",
+ "polyfills": "src/polyfills.ts",
+ "tsConfig": "tsconfig.spec.json",
+ "karmaConfig": "karma.conf.js",
+ "assets": [
+ "src/favicon.ico",
+ "src/assets"
+ ],
+ "styles": [
+ "src/styles.scss"
+ ],
+ "scripts": []
+ }
+ },
+ "lint": {
+ "builder": "@angular-devkit/build-angular:tslint",
+ "options": {
+ "tsConfig": [
+ "tsconfig.app.json",
+ "tsconfig.spec.json",
+ "e2e/tsconfig.json"
+ ],
+ "exclude": [
+ "**/node_modules/**"
+ ]
+ }
+ },
+ "e2e": {
+ "builder": "@angular-devkit/build-angular:protractor",
+ "options": {
+ "protractorConfig": "e2e/protractor.conf.js",
+ "devServerTarget": "workbench-web-ng:serve"
+ },
+ "configurations": {
+ "production": {
+ "devServerTarget": "workbench-web-ng:serve:production"
+ }
+ }
+ }
+ }
+ }
+ },
+ "defaultProject": "workbench-web-ng"
+}
\ No newline at end of file
diff --git a/submarine-workbench/workbench-web-ng/browserslist b/submarine-workbench/workbench-web-ng/browserslist
new file mode 100644
index 0000000..8084853
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/browserslist
@@ -0,0 +1,12 @@
+# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
+# For additional information regarding the format and rule options, please see:
+# https://github.com/browserslist/browserslist#queries
+
+# You can see what browsers were selected by your queries by running:
+# npx browserslist
+
+> 0.5%
+last 2 versions
+Firefox ESR
+not dead
+not IE 9-11 # For IE 9-11 support, remove 'not'.
\ No newline at end of file
diff --git a/submarine-workbench/workbench-web-ng/e2e/protractor.conf.js b/submarine-workbench/workbench-web-ng/e2e/protractor.conf.js
new file mode 100644
index 0000000..77cf687
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/e2e/protractor.conf.js
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// @ts-check
+// Protractor configuration file, see link for more information
+// https://github.com/angular/protractor/blob/master/lib/config.ts
+
+const { SpecReporter } = require('jasmine-spec-reporter');
+
+/**
+ * @type { import("protractor").Config }
+ */
+exports.config = {
+ allScriptsTimeout: 11000,
+ specs: [
+ './src/**/*.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: require('path').join(__dirname, './tsconfig.json')
+ });
+ jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
+ }
+};
diff --git a/submarine-workbench/workbench-web-ng/e2e/src/app.e2e-spec.ts b/submarine-workbench/workbench-web-ng/e2e/src/app.e2e-spec.ts
new file mode 100644
index 0000000..5b0d8f6
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/e2e/src/app.e2e-spec.ts
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { AppPage } from './app.po';
+import { browser, logging } from 'protractor';
+
+describe('workspace-project App', () => {
+ let page: AppPage;
+
+ beforeEach(() => {
+ page = new AppPage();
+ });
+
+ it('should display welcome message', () => {
+ page.navigateTo();
+ expect(page.getTitleText()).toEqual('workbench-web-ng app is running!');
+ });
+
+ afterEach(async () => {
+ // Assert that there are no errors emitted from the browser
+ const logs = await browser.manage().logs().get(logging.Type.BROWSER);
+ expect(logs).not.toContain(jasmine.objectContaining({
+ level: logging.Level.SEVERE,
+ } as logging.Entry));
+ });
+});
diff --git a/submarine-workbench/workbench-web-ng/e2e/src/app.po.ts b/submarine-workbench/workbench-web-ng/e2e/src/app.po.ts
new file mode 100644
index 0000000..493318b
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/e2e/src/app.po.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { browser, by, element } from 'protractor';
+
+export class AppPage {
+ navigateTo() {
+ return browser.get(browser.baseUrl) as Promise<any>;
+ }
+
+ getTitleText() {
+ return element(by.css('app-root .content span')).getText() as Promise<string>;
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/e2e/tsconfig.json b/submarine-workbench/workbench-web-ng/e2e/tsconfig.json
new file mode 100644
index 0000000..39b800f
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/e2e/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../out-tsc/e2e",
+ "module": "commonjs",
+ "target": "es5",
+ "types": [
+ "jasmine",
+ "jasminewd2",
+ "node"
+ ]
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/karma.conf.js b/submarine-workbench/workbench-web-ng/karma.conf.js
new file mode 100644
index 0000000..00f2741
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/karma.conf.js
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+module.exports = function (config) {
+ config.set({
+ basePath: '',
+ frameworks: ['jasmine', '@angular-devkit/build-angular'],
+ plugins: [
+ require('karma-jasmine'),
+ require('karma-chrome-launcher'),
+ require('karma-jasmine-html-reporter'),
+ require('karma-coverage-istanbul-reporter'),
+ require('@angular-devkit/build-angular/plugins/karma')
+ ],
+ client: {
+ clearContext: false // leave Jasmine Spec Runner output visible in browser
+ },
+ coverageIstanbulReporter: {
+ dir: require('path').join(__dirname, './coverage/workbench-web-ng'),
+ reports: ['html', 'lcovonly', 'text-summary'],
+ fixWebpackSourcePaths: true
+ },
+ reporters: ['progress', 'kjhtml'],
+ port: 9876,
+ colors: true,
+ logLevel: config.LOG_INFO,
+ autoWatch: true,
+ browsers: ['Chrome'],
+ singleRun: false,
+ restartOnFileChange: true
+ });
+};
diff --git a/submarine-workbench/workbench-web-ng/package.json b/submarine-workbench/workbench-web-ng/package.json
new file mode 100644
index 0000000..c2deab2
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "workbench-web-ng",
+ "version": "0.0.0",
+ "scripts": {
+ "ng": "ng",
+ "start": "ng serve --proxy-config proxy.conf.js",
+ "build": "ng build",
+ "test": "ng test",
+ "lint": "ng lint",
+ "e2e": "ng e2e"
+ },
+ "private": true,
+ "dependencies": {
+ "@angular/animations": "~8.2.9",
+ "@angular/common": "~8.2.9",
+ "@angular/compiler": "~8.2.9",
+ "@angular/core": "~8.2.9",
+ "@angular/forms": "~8.2.9",
+ "@angular/platform-browser": "~8.2.9",
+ "@angular/platform-browser-dynamic": "~8.2.9",
+ "@angular/router": "~8.2.9",
+ "md5": "^2.2.1",
+ "ng-zorro-antd": "8.1.2",
+ "rxjs": "~6.4.0",
+ "tslib": "^1.10.0",
+ "zone.js": "~0.9.1"
+ },
+ "devDependencies": {
+ "@angular-devkit/build-angular": "~0.803.9",
+ "@angular/cli": "~8.3.9",
+ "@angular/compiler-cli": "~8.2.9",
+ "@angular/language-service": "~8.2.9",
+ "@types/jasmine": "~3.3.8",
+ "@types/jasminewd2": "~2.0.3",
+ "@types/node": "~8.9.4",
+ "codelyzer": "^5.1.2",
+ "dotenv": "^8.0.0",
+ "https-proxy-agent": "^2.2.1",
+ "jasmine-core": "~3.4.0",
+ "jasmine-spec-reporter": "~4.2.1",
+ "karma": "~4.1.0",
+ "karma-chrome-launcher": "~2.2.0",
+ "karma-coverage-istanbul-reporter": "~2.0.1",
+ "karma-jasmine": "~2.0.1",
+ "karma-jasmine-html-reporter": "^1.4.0",
+ "prettier": "^1.17.0",
+ "protractor": "~5.4.0",
+ "ts-node": "~7.0.0",
+ "tslint": "~5.15.0",
+ "typescript": "~3.5.3"
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/pom.xml b/submarine-workbench/workbench-web-ng/pom.xml
new file mode 100644
index 0000000..9b4fca3
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.submarine</groupId>
+ <artifactId>submarine-workbench</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <groupId>org.apache.submarine</groupId>
+ <artifactId>workbench-web-ng</artifactId>
+ <!-- <packaging>war</packaging>-->
+ <!-- <version>0.3.0-SNAPSHOT</version>-->
+ <!-- <name>Submarine: Workbench Web Angular</name>-->
+
+ <!-- See https://github.com/eirslett/frontend-maven-plugin/issues/229 -->
+ <prerequisites>
+ <maven>3.1.0</maven>
+ </prerequisites>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+ <!--plugin versions-->
+ <plugin.frontend.nodeDownloadRoot>https://nodejs.org/dist/</plugin.frontend.nodeDownloadRoot>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/submarine-workbench/workbench-web-ng/proxy.conf.js b/submarine-workbench/workbench-web-ng/proxy.conf.js
new file mode 100644
index 0000000..3f07d6b
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/proxy.conf.js
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+const dotenv = require('dotenv');
+const HttpsProxyAgent = require('https-proxy-agent');
+dotenv.config();
+
+const proxyConfig = [
+ {
+ context: ['/api'],
+ target: 'http://localhost:8080',
+ secure: false,
+ changeOrigin: true
+ },
+ {
+ context: '/ws',
+ target: 'ws://localhost:8080',
+ secure: false,
+ ws:true,
+ changeOrigin: true
+ }
+];
+
+function httpUrlToWSUrl(url) {
+ return url.replace(/(http)(s)?\/\//, "ws$2://");
+}
+
+function setupForCorporateProxy(proxyConfig) {
+ const proxyServer = process.env.SERVER_PROXY;
+ const httpProxy = process.env.HTTP_PROXY;
+ if (proxyServer) {
+ let agent = null;
+ if (httpProxy) {
+ agent = new HttpsProxyAgent(httpProxy);
+ }
+ proxyConfig.forEach(function(entry) {
+ if (entry.context === '/ws') {
+ entry.target = httpUrlToWSUrl(proxyServer)
+ } else {
+ entry.target = proxyServer;
+ }
+ if (agent) {
+ entry.agent = agent;
+ }
+ });
+ }
+ return proxyConfig;
+}
+
+module.exports = setupForCorporateProxy(proxyConfig);
diff --git a/submarine-workbench/workbench-web-ng/src/WEB-INF/web.xml b/submarine-workbench/workbench-web-ng/src/WEB-INF/web.xml
new file mode 100644
index 0000000..2374dec
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/WEB-INF/web.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <display-name>workbench-web</display-name>
+ <servlet>
+ <servlet-name>default</servlet-name>
+ <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>jersey.config.server.provider.packages</param-name>
+ <param-value>org.apache.submarine.rest</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <context-param>
+ <param-name>configuration</param-name>
+ <param-value>deployment</param-value>
+ </context-param>
+
+ <session-config>
+ <cookie-config>
+ <http-only>true</http-only>
+ <secure>true</secure>
+ </cookie-config>
+ </session-config>
+</web-app>
diff --git a/submarine-workbench/workbench-web-ng/src/app/app-routing.module.ts b/submarine-workbench/workbench-web-ng/src/app/app-routing.module.ts
new file mode 100644
index 0000000..6cb4725
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/app-routing.module.ts
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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, Routes } from '@angular/router';
+import { AuthGuard } from '@submarine/core';
+
+const routes: Routes = [
+ {
+ path: '',
+ pathMatch: 'full',
+ redirectTo: '/manager/user'
+ },
+ {
+ path: 'manager',
+ canActivate: [AuthGuard],
+ loadChildren: () => import('./pages/manager/manager.module').then(m => m.ManagerModule)
+ },
+ {
+ path: 'user',
+ loadChildren: () => import('./pages/user/user.module').then(m => m.UserModule)
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forRoot(routes)],
+ exports: [RouterModule]
+})
+export class AppRoutingModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/app.component.html b/submarine-workbench/workbench-web-ng/src/app/app.component.html
new file mode 100644
index 0000000..6c447c0
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/app.component.html
@@ -0,0 +1,74 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<nz-layout class="app-layout">
+ <router-outlet></router-outlet>
+<!-- <nz-sider class="menu-sidebar"-->
+<!-- nzCollapsible-->
+<!-- nzWidth="256px"-->
+<!-- nzBreakpoint="md"-->
+<!-- [(nzCollapsed)]="isCollapsed"-->
+<!-- [nzTrigger]="null">-->
+<!-- <div class="sidebar-logo">-->
+<!-- <a href="https://ng.ant.design/" target="_blank">-->
+<!-- <img src="https://ng.ant.design/assets/img/logo.svg" alt="logo">-->
+<!-- <h1>Ant Design Of Angular</h1>-->
+<!-- </a>-->
+<!-- </div>-->
+<!-- <ul nz-menu nzTheme="dark" nzMode="inline" [nzInlineCollapsed]="isCollapsed">-->
+<!-- <li nz-submenu nzOpen nzTitle="Dashboard" nzIcon="dashboard">-->
+<!-- <ul>-->
+<!-- <li nz-menu-item nzMatchRouter>-->
+<!-- <a routerLink="/welcome">Welcome</a>-->
+<!-- </li>-->
+<!-- <li nz-menu-item nzMatchRouter>-->
+<!-- <a>Monitor</a>-->
+<!-- </li>-->
+<!-- <li nz-menu-item nzMatchRouter>-->
+<!-- <a>Workplace</a>-->
+<!-- </li>-->
+<!-- </ul>-->
+<!-- </li>-->
+<!-- <li nz-submenu nzOpen nzTitle="Form" nzIcon="form">-->
+<!-- <ul>-->
+<!-- <li nz-menu-item nzMatchRouter>-->
+<!-- <a>Basic Form</a>-->
+<!-- </li>-->
+<!-- </ul>-->
+<!-- </li>-->
+<!-- </ul>-->
+<!-- </nz-sider>-->
+<!-- <nz-layout>-->
+<!-- <nz-header>-->
+<!-- <div class="app-header">-->
+<!-- <span class="header-trigger" (click)="isCollapsed = !isCollapsed">-->
+<!-- <i class="trigger"-->
+<!-- nz-icon-->
+<!-- [nzType]="isCollapsed ? 'menu-unfold' : 'menu-fold'"-->
+<!-- ></i>-->
+<!-- </span>-->
+<!-- </div>-->
+<!-- </nz-header>-->
+<!-- <nz-content>-->
+<!-- <div class="inner-content">-->
+<!-- <router-outlet></router-outlet>-->
+<!-- </div>-->
+<!-- </nz-content>-->
+<!-- </nz-layout>-->
+</nz-layout>
diff --git a/submarine-workbench/workbench-web-ng/src/app/app.component.scss b/submarine-workbench/workbench-web-ng/src/app/app.component.scss
new file mode 100644
index 0000000..67bafe6
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/app.component.scss
@@ -0,0 +1,99 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+:host {
+ display: flex;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.app-layout {
+ height: 100vh;
+}
+
+.menu-sidebar {
+ position: relative;
+ z-index: 10;
+ min-height: 100vh;
+ box-shadow: 2px 0 6px rgba(0,21,41,.35);
+}
+
+.header-trigger {
+ height: 64px;
+ padding: 20px 24px;
+ font-size: 20px;
+ cursor: pointer;
+ transition: all .3s,padding 0s;
+}
+
+.trigger:hover {
+ color: #1890ff;
+}
+
+.sidebar-logo {
+ position: relative;
+ height: 64px;
+ padding-left: 24px;
+ overflow: hidden;
+ line-height: 64px;
+ background: #001529;
+ transition: all .3s;
+}
+
+.sidebar-logo img {
+ display: inline-block;
+ height: 32px;
+ width: 32px;
+ vertical-align: middle;
+}
+
+.sidebar-logo h1 {
+ display: inline-block;
+ margin: 0 0 0 20px;
+ color: #fff;
+ font-weight: 600;
+ font-size: 14px;
+ font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;
+ vertical-align: middle;
+}
+
+nz-header {
+ padding: 0;
+ width: 100%;
+ z-index: 2;
+}
+
+.app-header {
+ position: relative;
+ height: 64px;
+ padding: 0;
+ background: #fff;
+ box-shadow: 0 1px 4px rgba(0,21,41,.08);
+}
+
+nz-content {
+ margin: 24px;
+}
+
+.inner-content {
+ padding: 24px;
+ background: #fff;
+ height: 100%;
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/app.component.spec.ts b/submarine-workbench/workbench-web-ng/src/app/app.component.spec.ts
new file mode 100644
index 0000000..e59a500
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/app.component.spec.ts
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { async, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { AppComponent } from './app.component';
+
+describe('AppComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [RouterTestingModule],
+ declarations: [AppComponent]
+ }).compileComponents();
+ }));
+
+ it('should create the app', () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app).toBeTruthy();
+ });
+
+ it(`should have as title 'workbench-web-ng'`, () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.title).toEqual('workbench-web-ng');
+ });
+
+ it('should render title', () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+ const compiled = fixture.debugElement.nativeElement;
+ expect(compiled.querySelector('.content span').textContent).toContain('workbench-web-ng app is running!');
+ });
+});
diff --git a/submarine-workbench/workbench-web-ng/src/app/app.component.ts b/submarine-workbench/workbench-web-ng/src/app/app.component.ts
new file mode 100644
index 0000000..51425c4
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/app.component.ts
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { Title } from '@angular/platform-browser';
+import { NavigationEnd, Router } from '@angular/router';
+import { filter } from 'rxjs/operators';
+
+@Component({
+ selector: 'submarine-root',
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.scss']
+})
+export class AppComponent implements OnInit {
+ constructor(private router: Router, private title: Title) {}
+
+ ngOnInit(): void {
+ this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
+ const paths = this.router.url.split('/');
+
+ this.title.setTitle(`Submarine - ${paths[paths.length - 1]}`);
+ });
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/app.module.ts b/submarine-workbench/workbench-web-ng/src/app/app.module.ts
new file mode 100644
index 0000000..59c9cfd
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/app.module.ts
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { BrowserModule } from '@angular/platform-browser';
+
+import { registerLocaleData } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import zh from '@angular/common/locales/zh';
+import { FormsModule } from '@angular/forms';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { LocalStorageService } from '@submarine/services/local-storage.service';
+import { zh_CN, NgZorroAntdModule, NZ_I18N } from 'ng-zorro-antd';
+import { AppRoutingModule } from './app-routing.module';
+import { AppComponent } from './app.component';
+import { IconsProviderModule } from './icons-provider.module';
+
+registerLocaleData(zh);
+
+@NgModule({
+ declarations: [AppComponent],
+ imports: [
+ BrowserModule,
+ AppRoutingModule,
+ IconsProviderModule,
+ NgZorroAntdModule,
+ FormsModule,
+ HttpClientModule,
+ BrowserAnimationsModule
+ ],
+ providers: [{ provide: NZ_I18N, useValue: zh_CN }, LocalStorageService],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/core/auth/auth.guard.ts b/submarine-workbench/workbench-web-ng/src/app/core/auth/auth.guard.ts
new file mode 100644
index 0000000..63a9a8b
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/core/auth/auth.guard.ts
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
+import { AuthService } from '@submarine/services';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthGuard implements CanActivate {
+ constructor(private authService: AuthService, private router: Router) {}
+
+ canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
+ const url: string = state.url;
+
+ return this.checkLogin(url);
+ }
+
+ checkLogin(url: string): boolean {
+ if (this.authService.isLoggedIn) {
+ return true;
+ }
+
+ // Store the attempted URL for redirecting
+ this.authService.redirectUrl = url;
+
+ // Navigate to the login page with extras
+ this.router.navigate(['/user/login']);
+ return false;
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/core/index.ts b/submarine-workbench/workbench-web-ng/src/app/core/index.ts
new file mode 100644
index 0000000..30631d0
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/core/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 * from './publick-api';
diff --git a/submarine-workbench/workbench-web-ng/src/app/core/publick-api.ts b/submarine-workbench/workbench-web-ng/src/app/core/publick-api.ts
new file mode 100644
index 0000000..498014e
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/core/publick-api.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 * from './auth/auth.guard';
diff --git a/submarine-workbench/workbench-web-ng/src/app/icons-provider.module.ts b/submarine-workbench/workbench-web-ng/src/app/icons-provider.module.ts
new file mode 100644
index 0000000..8f51cf1
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/icons-provider.module.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { NZ_ICONS } from 'ng-zorro-antd';
+
+import { DashboardOutline, FormOutline, MenuFoldOutline, MenuUnfoldOutline } from '@ant-design/icons-angular/icons';
+
+const icons = [MenuFoldOutline, MenuUnfoldOutline, DashboardOutline, FormOutline];
+
+@NgModule({
+ providers: [{ provide: NZ_ICONS, useValue: icons }]
+})
+export class IconsProviderModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/interfaces/index.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/index.ts
new file mode 100644
index 0000000..630627e
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 * from './public-api';
diff --git a/submarine-workbench/workbench-web-ng/src/app/interfaces/permission.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/permission.ts
new file mode 100644
index 0000000..fffef9e
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/permission.ts
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 interface PermissionActionEntitySet {
+ action: string;
+ defaultChecked: boolean;
+ describe: string;
+}
+
+export type PermissionAction = PermissionActionEntitySet;
+
+export class Permission {
+ permissionId = '';
+ permissionName = '';
+ roleId = '';
+ actionList = null;
+ actionEntitySet: PermissionActionEntitySet[] = [];
+ actions: PermissionAction[] = [];
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/interfaces/public-api.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/public-api.ts
new file mode 100644
index 0000000..8958522
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/public-api.ts
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 * from './permission';
+export * from './role';
+export * from './user';
+export * from './rest';
diff --git a/submarine-workbench/workbench-web-ng/src/app/interfaces/rest.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/rest.ts
new file mode 100644
index 0000000..dcf39fc
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/rest.ts
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 interface Rest<T> {
+ result: T;
+ code: number;
+ message: string;
+ status: string;
+ success: boolean;
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/interfaces/role.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/role.ts
new file mode 100644
index 0000000..f3f8669
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/role.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { Permission } from './permission';
+
+export type RoleId = string;
+
+export class Role {
+ createTime: number = -1;
+ creatorId = '';
+ describe = '';
+ id = '';
+ name = '';
+ permissions: Permission[];
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/interfaces/user.ts b/submarine-workbench/workbench-web-ng/src/app/interfaces/user.ts
new file mode 100644
index 0000000..c68c424
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/interfaces/user.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { Role } from './role';
+
+export class User {
+ avatar = '';
+ id = '';
+ name = '';
+ telephone = '';
+ username = '';
+ role: Role;
+ roleId: number;
+ token: string;
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager-routing.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager-routing.module.ts
new file mode 100644
index 0000000..97c775f
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager-routing.module.ts
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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, Routes } from '@angular/router';
+import { ManagerComponent } from './manager.component';
+import { UserComponent } from './user/user.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: ManagerComponent,
+ children: [
+ {
+ path: '',
+ pathMatch: 'full',
+ redirectTo: '/manager/user'
+ },
+ {
+ path: 'user',
+ component: UserComponent
+ }
+ ]
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class ManagerRoutingModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.html b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.html
new file mode 100644
index 0000000..4f806ff
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.html
@@ -0,0 +1,21 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<p>manager works!</p>
+<router-outlet></router-outlet>
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.scss b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.scss
new file mode 100644
index 0000000..510f082
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.scss
@@ -0,0 +1,19 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.ts
new file mode 100644
index 0000000..efa6503
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.component.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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';
+
+@Component({
+ selector: 'submarine-manager',
+ templateUrl: './manager.component.html',
+ styleUrls: ['./manager.component.scss']
+})
+export class ManagerComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.module.ts
new file mode 100644
index 0000000..cfabafe
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/manager/manager.module.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { NgZorroAntdModule } from 'ng-zorro-antd';
+import { ManagerRoutingModule } from './manager-routing.module';
+import { ManagerComponent } from './manager.component';
+import { UserComponent } from './user/user.component';
+
+@NgModule({
+ declarations: [UserComponent, ManagerComponent],
+ imports: [CommonModule, ManagerRoutingModule, NgZorroAntdModule]
+})
+export class ManagerModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.html b/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.html
new file mode 100644
index 0000000..c5412cf
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.html
@@ -0,0 +1,20 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<p>user works!</p>
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.scss b/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.scss
new file mode 100644
index 0000000..510f082
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.scss
@@ -0,0 +1,19 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.ts
new file mode 100644
index 0000000..8c3d582
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/manager/user/user.component.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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';
+
+@Component({
+ selector: 'submarine-manager-user',
+ templateUrl: './user.component.html',
+ styleUrls: ['./user.component.scss']
+})
+export class UserComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login-routing.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login-routing.module.ts
new file mode 100644
index 0000000..b9c11e5
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login-routing.module.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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, Routes } from '@angular/router';
+import { LoginComponent } from './login.component';
+
+const routes: Routes = [{ path: '', component: LoginComponent }];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class LoginRoutingModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.html b/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.html
new file mode 100644
index 0000000..294cc71
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.html
@@ -0,0 +1,46 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<form nz-form [formGroup]="validateForm" class="login-form" (ngSubmit)="submitForm()">
+ <nz-form-item>
+ <nz-form-control nzErrorTip="Please input your username!">
+ <nz-input-group nzPrefixIcon="user">
+ <input type="text" nz-input formControlName="userName" placeholder="Username" />
+ </nz-input-group>
+ </nz-form-control>
+ </nz-form-item>
+ <nz-form-item>
+ <nz-form-control nzErrorTip="Please input your Password!">
+ <nz-input-group nzPrefixIcon="lock">
+ <input type="password" nz-input formControlName="password" placeholder="Password" />
+ </nz-input-group>
+ </nz-form-control>
+ </nz-form-item>
+ <nz-form-item>
+ <nz-form-control>
+ <label nz-checkbox formControlName="remember">
+ <span>Remember me</span>
+ </label>
+ <a class="login-form-forgot" [routerLink]="['/user/register']">Forgot password</a>
+ <button nz-button class="login-form-button" [nzType]="'primary'">Log in</button>
+ Or
+ <a [routerLink]="['/user/register']">register account!</a>
+ </nz-form-control>
+ </nz-form-item>
+</form>
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.scss b/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.scss
new file mode 100644
index 0000000..f0c18d5
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.scss
@@ -0,0 +1,31 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+.login-form {
+ max-width: 320px;
+}
+
+.login-form-forgot {
+ float: right;
+}
+
+.login-form-button {
+ width: 100%;
+}
+
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.ts
new file mode 100644
index 0000000..9190cea
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/login/login.component.ts
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { NzNotificationService } from 'ng-zorro-antd';
+import { AuthService } from '../../../services';
+
+@Component({
+ selector: 'submarine-login',
+ templateUrl: './login.component.html',
+ styleUrls: ['./login.component.scss']
+})
+export class LoginComponent implements OnInit {
+ validateForm: FormGroup;
+
+ constructor(
+ private fb: FormBuilder,
+ private authService: AuthService,
+ private nzNotificationService: NzNotificationService,
+ private router: Router
+ ) {
+ if (this.authService.isLoggedIn) {
+ this.router.navigate(['/manager/user']);
+ }
+ }
+
+ submitForm(): void {
+ for (const i in this.validateForm.controls) {
+ this.validateForm.controls[i].markAsDirty();
+ this.validateForm.controls[i].updateValueAndValidity();
+ }
+
+ if (this.validateForm.status === 'VALID') {
+ const { value } = this.validateForm;
+ this.authService.login(value).subscribe(
+ () => {
+ this.loginSuccess();
+ },
+ error => {
+ console.log(error);
+ this.requestFailed(error);
+ }
+ );
+ }
+ }
+
+ ngOnInit(): void {
+ this.validateForm = this.fb.group({
+ userName: [null, [Validators.required]],
+ password: [null, [Validators.required]],
+ remember: [true]
+ });
+ }
+
+ loginSuccess() {
+ this.router.navigate(['/manager/user']);
+
+ setTimeout(() => {
+ this.nzNotificationService.success('Welcome', 'Welcome back');
+ }, 1000);
+ }
+
+ requestFailed(error: Error) {
+ this.nzNotificationService.error('Request error', error.message || 'Request error, please try again', {
+ nzDuration: 4000
+ });
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.html b/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.html
new file mode 100644
index 0000000..8955bef
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.html
@@ -0,0 +1,20 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<p>register works!</p>
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.scss b/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.scss
new file mode 100644
index 0000000..510f082
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.scss
@@ -0,0 +1,19 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.ts
new file mode 100644
index 0000000..c8e9c62
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/register/register.component.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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';
+
+@Component({
+ selector: 'submarine-register',
+ templateUrl: './register.component.html',
+ styleUrls: ['./register.component.scss']
+})
+export class RegisterComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/user-routing.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/user/user-routing.module.ts
new file mode 100644
index 0000000..9098a99
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/user-routing.module.ts
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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, Routes } from '@angular/router';
+import { LoginComponent } from './login/login.component';
+import { RegisterComponent } from './register/register.component';
+import { UserComponent } from './user.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: UserComponent,
+ children: [
+ {
+ path: '',
+ redirectTo: '/user/login',
+ pathMatch: 'full'
+ },
+ {
+ path: 'login',
+ component: LoginComponent
+ },
+ {
+ path: 'register',
+ component: RegisterComponent
+ }
+ ]
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class UserRoutingModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.html b/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.html
new file mode 100644
index 0000000..7469e9d
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.html
@@ -0,0 +1,31 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<nz-content class="content">
+ <div class="inner">
+ <div class="logo">
+ <img src="/assets/logo-128.png" alt="submarine-logo" />
+ <span class="title">Submarine</span>
+ </div>
+ <div class="desc">
+ Apache Submarine Machine Learning Workbench
+ </div>
+ <router-outlet></router-outlet>
+ </div>
+</nz-content>
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.scss b/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.scss
new file mode 100644
index 0000000..34990ff
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.scss
@@ -0,0 +1,55 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+.content {
+ height: 100vh;
+ padding-top: 110px;
+ background: url("/assets/background.svg") no-repeat 50%;
+ background-size: 100%;
+}
+
+.inner {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.logo {
+ height: 44px;
+ display: flex;
+
+ img {
+ height: inherit;
+ margin-right: 16px;
+ }
+}
+
+.title {
+ font-size: 33px;
+ color: rgba(0,0,0,.85);
+ font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif;
+ font-weight: 600;
+}
+
+.desc {
+ font-size: 14px;
+ color: rgba(0,0,0,.45);
+ margin-top: 12px;
+ margin-bottom: 40px
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.ts b/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.ts
new file mode 100644
index 0000000..b38a643
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/user.component.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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';
+
+@Component({
+ selector: 'submarine-user',
+ templateUrl: './user.component.html',
+ styleUrls: ['./user.component.scss']
+})
+export class UserComponent implements OnInit {
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/pages/user/user.module.ts b/submarine-workbench/workbench-web-ng/src/app/pages/user/user.module.ts
new file mode 100644
index 0000000..9d6d0ca
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/pages/user/user.module.ts
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { ReactiveFormsModule } from '@angular/forms';
+import { NgZorroAntdModule } from 'ng-zorro-antd';
+import { LoginComponent } from './login/login.component';
+import { RegisterComponent } from './register/register.component';
+import { UserRoutingModule } from './user-routing.module';
+import { UserComponent } from './user.component';
+
+@NgModule({
+ declarations: [RegisterComponent, UserComponent, LoginComponent],
+ imports: [CommonModule, UserRoutingModule, ReactiveFormsModule, NgZorroAntdModule]
+})
+export class UserModule {}
diff --git a/submarine-workbench/workbench-web-ng/src/app/services/auth.service.ts b/submarine-workbench/workbench-web-ng/src/app/services/auth.service.ts
new file mode 100644
index 0000000..1f3865a
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/services/auth.service.ts
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 { HttpClient } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Rest, User } from '@submarine/interfaces';
+import { BaseApiService } from '@submarine/services/base-api.service';
+import { LocalStorageService } from '@submarine/services/local-storage.service';
+import * as md5 from 'md5';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthService {
+ isLoggedIn = false;
+ authTokenKey = 'auth_token';
+
+ // store the URL so we can redirect after logging in
+ redirectUrl: string;
+
+ constructor(
+ private localStorageService: LocalStorageService,
+ private baseApi: BaseApiService,
+ private httpClient: HttpClient
+ ) {
+ const authToken = this.localStorageService.get<string>(this.authTokenKey);
+ this.isLoggedIn = !!authToken;
+ }
+
+ login(userForm: { userName: string; password: string }): Observable<boolean> {
+ return this.httpClient
+ .post<Rest<User>>(this.baseApi.getRestApi('/auth/login'), {
+ username: userForm.userName,
+ password: md5(userForm.password)
+ })
+ .pipe(
+ map(res => {
+ if (res.success) {
+ this.isLoggedIn = true;
+ this.localStorageService.set(this.authTokenKey, res.result.token);
+ }
+
+ return res.success;
+ })
+ );
+ }
+
+ logout(): void {
+ this.isLoggedIn = false;
+ this.localStorageService.remove(this.authTokenKey);
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/services/base-api.service.ts b/submarine-workbench/workbench-web-ng/src/app/services/base-api.service.ts
new file mode 100644
index 0000000..076ab1f
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/services/base-api.service.ts
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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({
+ providedIn: 'root'
+})
+export class BaseApiService {
+ baseApi: string;
+
+ getPort() {
+ let port = Number(location.port);
+ if (!port) {
+ port = 80;
+ if (location.protocol === 'https:') {
+ port = 443;
+ }
+ }
+ return port;
+ }
+
+ getBase() {
+ return `${location.protocol}//${location.hostname}:${this.getPort()}`;
+ }
+
+ getRestApiBase() {
+ if (!this.baseApi) {
+ this.baseApi = this.skipTrailingSlash(this.getBase()) + '/api';
+ }
+
+ return this.baseApi;
+ }
+
+ getRestApi(str: string): string {
+ return `${this.getRestApiBase()}${str}`;
+ }
+
+ private skipTrailingSlash(path) {
+ return path.replace(/\/$/, '');
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/services/index.ts b/submarine-workbench/workbench-web-ng/src/app/services/index.ts
new file mode 100644
index 0000000..630627e
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/services/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 * from './public-api';
diff --git a/submarine-workbench/workbench-web-ng/src/app/services/local-storage.service.ts b/submarine-workbench/workbench-web-ng/src/app/services/local-storage.service.ts
new file mode 100644
index 0000000..e9ea620
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/services/local-storage.service.ts
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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({
+ providedIn: 'root'
+})
+export class LocalStorageService {
+ prefix = 'submarine';
+
+ generateKey(key: string) {
+ return `${this.prefix}_${key.toLowerCase()}`;
+ }
+
+ get<T>(key: string): T {
+ try {
+ return JSON.parse(localStorage.getItem(this.generateKey(key)));
+ } catch (e) {
+ return null;
+ }
+ }
+
+ set(key: string, value: string | number | object | any[]) {
+ try {
+ const saveValue = JSON.stringify(value);
+
+ window.localStorage.setItem(this.generateKey(key), saveValue);
+ } catch (e) {
+ console.error(`key: ${key}, value: ${value} save error`, e);
+ }
+ }
+
+ remove(key: string) {
+ window.localStorage.removeItem(this.generateKey(key));
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/src/app/services/public-api.ts b/submarine-workbench/workbench-web-ng/src/app/services/public-api.ts
new file mode 100644
index 0000000..a853cff
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/app/services/public-api.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 * from './auth.service';
diff --git a/submarine-workbench/workbench-web-ng/src/assets/.gitkeep b/submarine-workbench/workbench-web-ng/src/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/submarine-workbench/workbench-web-ng/src/assets/background.svg b/submarine-workbench/workbench-web-ng/src/assets/background.svg
new file mode 100644
index 0000000..ce9aa89
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/assets/background.svg
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
+ <title>Group 21</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g transform="translate(-79.000000, -82.000000)">
+ <g id="Group-21" transform="translate(77.000000, 73.000000)">
+ <g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
+ <ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
+ <ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
+ <path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
+ <path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
+ <path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+ <path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+ <g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
+ <ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
+ <path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
+ </g>
+ </g>
+ <g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
+ <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
+ <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
+ <ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
+ <ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
+ <path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
+ <g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
+ <ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
+ <path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
+ </g>
+ <ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
+ <ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
+ <ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
+ <path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
+ </g>
+ <g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
+ <ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
+ <g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
+ <ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
+ <path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
+ </g>
+ <path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+ <ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
+ <ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
+ <path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+ </g>
+ <g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
+ <g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
+ <circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
+ <path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
+ </g>
+ <circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
+ <path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
+ <path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
+ <polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
+ <path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
+ <path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
+ <path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
+ <circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
+ <circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
+ <circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
+ <circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
+ <circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/submarine-workbench/workbench-web-ng/src/assets/logo-128.png b/submarine-workbench/workbench-web-ng/src/assets/logo-128.png
new file mode 100644
index 0000000..47d1be9
Binary files /dev/null and b/submarine-workbench/workbench-web-ng/src/assets/logo-128.png differ
diff --git a/submarine-workbench/workbench-web-ng/src/assets/submarine-logo.svg b/submarine-workbench/workbench-web-ng/src/assets/submarine-logo.svg
new file mode 100644
index 0000000..8575466
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/assets/submarine-logo.svg
@@ -0,0 +1,133 @@
+<svg id="logo-sprint" data-name="logo-sprint" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 638.26 796.53">
+ <defs>
+ <style>
+ .cls-1{fill:none;}.cls-2{fill:#2e51bf;}.cls-3{fill:#3cddc9;}.cls-4{clip-path:url(#clip-path);}.cls-5{fill:#3090d8;}.cls-6{fill:#3fbfde;}.cls-7{fill:#1d1d1d;}.cls-8{clip-path:url(#clip-path-2);}.cls-9{fill:#313131;}.cls-10{fill:#454545;}.cls-11{fill:#686868;}.cls-12{fill:#fff;}.cls-13{clip-path:url(#clip-path-3);}.cls-14{fill:#cecece;}.cls-15{fill:#bababa;}.cls-16{fill:#979797;}
+ </style>
+ <clipPath id="clip-path">
+ <path class="cls-1"
+ d="M413.18,66.76H354a121.42,121.42,0,0,0-47,9.58h0L218,115a2,2,0,0,0,0,3.53l103.26,44.79a52,52,0,0,0,18.15,3.44H366.7a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ </clipPath>
+ <clipPath id="clip-path-2">
+ <path class="cls-1"
+ d="M403.33,305.77H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,354a2,2,0,0,0,0,3.53l103.26,44.79a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ </clipPath>
+ <clipPath id="clip-path-3">
+ <path class="cls-1"
+ d="M403.33,583.75H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,632a2,2,0,0,0,0,3.53l103.26,44.79a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ </clipPath>
+ </defs>
+ <title>logo</title>
+ <rect x="-1.28" y="520.68" width="638.26" height="275.85"/>
+ <path class="cls-2"
+ d="M243.33,138.29l-21.09-9.17a1,1,0,0,0-1.32.52l-9.53,21.92a2,2,0,0,0,1.83,2.8h20.13a6.33,6.33,0,0,0,5.77-3.88l4.73-10.87A1,1,0,0,0,243.33,138.29Z"/>
+ <path class="cls-2"
+ d="M220.92,103.89a1,1,0,0,0,1.32.52l21.09-9.17a1,1,0,0,0,.52-1.32L239.12,83a6.33,6.33,0,0,0-5.77-3.88H213.22a2,2,0,0,0-1.83,2.8Z"/>
+ <path class="cls-3"
+ d="M235.94,196.28h4v18.29c0,4.57,2,6.78,6.11,6.78,4,0,6.94-2.31,7-6.73V196.28h4v28H254l-.77-2.93H253c-.77,1.08-3.29,3.49-8,3.49-5.76,0-8.94-3-9.1-9.4Z"/>
+ <path class="cls-3"
+ d="M265.65,185.24h4v12.95h.21a11.06,11.06,0,0,1,6.78-2.16c5.86,0,10.64,3.8,10.64,13.36,0,9.09-4.47,15.36-13.72,15.36a17.71,17.71,0,0,1-7.86-1.49ZM283.22,210c0-8.12-3.8-10.43-7.71-10.43a7.46,7.46,0,0,0-5.86,2.77v18.19a12,12,0,0,0,4.47.77C279.57,221.26,283.22,217.51,283.22,210Z"/>
+ <path class="cls-3"
+ d="M356.55,204.35V217c0,2.52.77,4.21,2.72,4.21H360v2.93a3.13,3.13,0,0,1-1.44.31,5,5,0,0,1-5.09-3.39h-.21a10.09,10.09,0,0,1-8.32,3.75c-5.19,0-8.07-3.65-8.07-7.45,0-6.17,6.06-9.2,16-9v-3c0-4.57-2.21-5.91-5.91-5.91a7,7,0,0,0-6.37,3.39l-2.93-2.31a10.91,10.91,0,0,1,9.4-4.57C353,195.87,356.55,198.49,356.55,204.35Zm-3.7,7.09c-6.73-.26-12,1.39-12,5.6,0,2.47,1.8,4.47,5,4.47a8.63,8.63,0,0,0,7-3.8Z"/>
+ <path class="cls-3" d="M388.05,185.19a2.9,2.9,0,1,1,0,5.81,2.9,2.9,0,0,1,0-5.81Zm-1.75,11.1h4v28h-4Z"/>
+ <path class="cls-3"
+ d="M448.89,222.08a14.54,14.54,0,0,1-8.79,2.52c-8,0-12.28-4.06-12.28-14.49,0-10.12,5.65-14.28,11.87-14.28,6.63,0,10.17,4.32,10.17,10.94a43.49,43.49,0,0,1-.31,4.83H431.78c.36,6.89,3.24,9.51,8.84,9.51a10.61,10.61,0,0,0,6.47-2.11Zm-17.06-13.77h14c.05-.62.05-1.23.05-1.59,0-4.78-2.05-7.45-6.58-7.45C435.69,199.26,432.19,201.58,431.83,208.31Z"/>
+ <path class="cls-3"
+ d="M321.4,195.72c-4.37,0-7.09,2.16-8.17,4.42H313c-1-2.52-3.24-4.42-7.4-4.42a8.25,8.25,0,0,0-7.25,3.55h-.1v-3h-4v28h4v-20a6.49,6.49,0,0,1,6.32-5c3.6,0,5.55,2.42,5.55,6.83v18.14h4v-20.3a6.69,6.69,0,0,1,6.42-4.68c3.44,0,5.5,2.21,5.5,6.53v18.45h4V205C330,198.85,326.95,195.72,321.4,195.72Z"/>
+ <path class="cls-3"
+ d="M411.84,195.72a10.6,10.6,0,0,0-8,3.49h-.05v-2.93h-4v28h4v-20a7.54,7.54,0,0,1,7.09-5c3.9,0,6,2.36,6,6.63v18.34h4V205C420.78,198.75,417.44,195.72,411.84,195.72Z"/>
+ <path class="cls-3"
+ d="M366.4,196.63h3.88l.4,5h.17c1.88-3.48,4.74-5.71,7.88-5.71a6.88,6.88,0,0,1,3,.57l-.91,4.11a7.76,7.76,0,0,0-2.68-.46c-2.34,0-5.14,1.71-7,6.39v17.81H366.4Z"/>
+ <path class="cls-3"
+ d="M212.15,197.11c0-3.29,2.52-5.65,6.73-5.65a10.79,10.79,0,0,1,7,2.47l2.52-3.19a14.55,14.55,0,0,0-9.3-3c-6.47,0-11.15,4.21-11.15,9.66,0,11.36,17.16,9.51,17.16,17.68,0,3.33-2.61,6-7.48,6h-21.2a20,20,0,0,0-2.34,3.69h23.16c7.71,0,12-4.52,12-10C229.31,203.68,212.15,205.43,212.15,197.11Z"/>
+ <path class="cls-2"
+ d="M413.18,66.76H354a121.42,121.42,0,0,0-47,9.58h0L218,115a2,2,0,0,0,0,3.53l103.26,44.79a52,52,0,0,0,18.15,3.44H366.7a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-1"
+ d="M413.18,66.76H354a121.42,121.42,0,0,0-47,9.58h0L218,115a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44H366.7a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-1"
+ d="M413.18,66.76H354a121.42,121.42,0,0,0-47,9.58h0L218,115a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44H366.7a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <g class="cls-4">
+ <path class="cls-5" d="M474.56,65.74H352.22v0a119.86,119.86,0,1,0,118,88.08h4.28Z"/>
+ <path class="cls-6" d="M454.52,86.09V66.76H400.07a86.42,86.42,0,1,0,54.45,19.33Z"/>
+ <path class="cls-1"
+ d="M413.18,66.76H354a121.42,121.42,0,0,0-47,9.58h0L218,115a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44H366.7a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-3"
+ d="M419,120.85a28.73,28.73,0,0,1-12.9,3.61h0a62.88,62.88,0,0,0-55.84,42.3H352A63.3,63.3,0,1,0,475,187.64C475,152.68,416.64,122.3,419,120.85Z"/>
+ <path class="cls-1"
+ d="M413.18,66.76H354a121.42,121.42,0,0,0-47,9.58h0L218,115a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44H366.7a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ </g>
+ <path class="cls-7"
+ d="M233.48,377.29l-21.09-9.17a1,1,0,0,0-1.32.52l-9.53,21.92a2,2,0,0,0,1.83,2.8H223.5a6.33,6.33,0,0,0,5.77-3.88L234,378.61A1,1,0,0,0,233.48,377.29Z"/>
+ <path class="cls-7"
+ d="M211.07,342.89a1,1,0,0,0,1.32.52l21.09-9.17a1,1,0,0,0,.52-1.32l-4.73-10.87a6.33,6.33,0,0,0-5.77-3.88H203.37a2,2,0,0,0-1.83,2.8Z"/>
+ <path class="cls-7"
+ d="M226.09,435.29h4v18.29c0,4.57,2,6.78,6.11,6.78,4,0,6.94-2.31,7-6.73V435.29h4v28h-3.13l-.77-2.93h-.21c-.77,1.08-3.29,3.49-8,3.49-5.76,0-8.94-3-9.1-9.4Z"/>
+ <path class="cls-7"
+ d="M255.8,424.24h4v12.95H260a11.06,11.06,0,0,1,6.78-2.16c5.86,0,10.64,3.8,10.64,13.36,0,9.09-4.47,15.36-13.72,15.36a17.71,17.71,0,0,1-7.86-1.49ZM273.37,449c0-8.12-3.8-10.43-7.71-10.43a7.46,7.46,0,0,0-5.86,2.77v18.19a12,12,0,0,0,4.47.77C269.72,460.26,273.37,456.51,273.37,449Z"/>
+ <path class="cls-7"
+ d="M346.7,443.36V456c0,2.52.77,4.21,2.72,4.21h.72v2.93a3.13,3.13,0,0,1-1.44.31,5,5,0,0,1-5.09-3.39h-.21a10.09,10.09,0,0,1-8.32,3.75c-5.19,0-8.07-3.65-8.07-7.45,0-6.17,6.06-9.2,16-9v-3c0-4.57-2.21-5.91-5.91-5.91a7,7,0,0,0-6.37,3.39l-2.93-2.31a10.91,10.91,0,0,1,9.4-4.57C343.15,434.88,346.7,437.5,346.7,443.36Zm-3.7,7.09c-6.73-.26-12,1.39-12,5.6,0,2.47,1.8,4.47,5,4.47a8.63,8.63,0,0,0,7-3.8Z"/>
+ <path class="cls-7" d="M378.2,424.19a2.9,2.9,0,1,1,0,5.81,2.9,2.9,0,0,1,0-5.81Zm-1.75,11.1h4v28h-4Z"/>
+ <path class="cls-7"
+ d="M439,461.08a14.54,14.54,0,0,1-8.79,2.52c-8,0-12.28-4.06-12.28-14.49,0-10.12,5.65-14.28,11.87-14.28,6.63,0,10.17,4.32,10.17,10.94a43.49,43.49,0,0,1-.31,4.83H421.93c.36,6.89,3.24,9.51,8.84,9.51a10.61,10.61,0,0,0,6.47-2.11ZM422,447.31h14c.05-.62.05-1.23.05-1.59,0-4.78-2.05-7.45-6.58-7.45C425.84,438.27,422.34,440.58,422,447.31Z"/>
+ <path class="cls-7"
+ d="M311.55,434.73c-4.37,0-7.09,2.16-8.17,4.42h-.21c-1-2.52-3.24-4.42-7.4-4.42a8.25,8.25,0,0,0-7.25,3.55h-.1v-3h-4v28h4v-20a6.49,6.49,0,0,1,6.32-5c3.6,0,5.55,2.42,5.55,6.83v18.14h4v-20.3a6.69,6.69,0,0,1,6.42-4.68c3.44,0,5.5,2.21,5.5,6.53v18.45h4V444C320.18,437.86,317.1,434.73,311.55,434.73Z"/>
+ <path class="cls-7"
+ d="M402,434.73a10.6,10.6,0,0,0-8,3.49H394v-2.93h-4v28h4v-20a7.54,7.54,0,0,1,7.09-5c3.9,0,6,2.36,6,6.63v18.34h4V444C410.93,437.76,407.59,434.73,402,434.73Z"/>
+ <path class="cls-7"
+ d="M356.55,435.63h3.88l.4,5H361c1.88-3.48,4.74-5.71,7.88-5.71a6.88,6.88,0,0,1,3,.57l-.91,4.11a7.76,7.76,0,0,0-2.68-.46c-2.34,0-5.14,1.71-7,6.39v17.81h-4.68Z"/>
+ <path class="cls-7"
+ d="M202.3,436.11c0-3.29,2.52-5.65,6.73-5.65a10.79,10.79,0,0,1,7,2.47l2.52-3.19a14.55,14.55,0,0,0-9.3-3c-6.47,0-11.15,4.21-11.15,9.66,0,11.36,17.16,9.51,17.16,17.68,0,3.33-2.61,6-7.48,6h-21.2a20,20,0,0,0-2.34,3.69h23.16c7.71,0,12-4.52,12-10C219.46,442.69,202.3,444.44,202.3,436.11Z"/>
+ <path class="cls-7"
+ d="M403.33,305.77H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,354a2,2,0,0,0,0,3.53l103.26,44.79a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-1"
+ d="M403.33,305.77H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,354a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-1"
+ d="M403.33,305.77H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,354a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <g class="cls-8">
+ <path class="cls-9" d="M464.7,304.74H342.37v0a119.86,119.86,0,1,0,118,88.08h4.28Z"/>
+ <path class="cls-10" d="M444.67,325.1V305.77H390.22a86.42,86.42,0,1,0,54.45,19.33Z"/>
+ <path class="cls-1"
+ d="M403.33,305.77H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,354a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-11"
+ d="M409.18,359.86a28.73,28.73,0,0,1-12.9,3.61h0a62.88,62.88,0,0,0-55.84,42.3h1.69a63.3,63.3,0,1,0,123.06,20.88C465.18,391.69,406.79,361.3,409.18,359.86Z"/>
+ <path class="cls-1"
+ d="M403.33,305.77H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,354a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ </g>
+ <path class="cls-12"
+ d="M233.48,655.28l-21.09-9.17a1,1,0,0,0-1.32.52l-9.53,21.92a2,2,0,0,0,1.83,2.8H223.5a6.33,6.33,0,0,0,5.77-3.88L234,656.59A1,1,0,0,0,233.48,655.28Z"/>
+ <path class="cls-12"
+ d="M211.07,620.88a1,1,0,0,0,1.32.52l21.09-9.17a1,1,0,0,0,.52-1.32L229.27,600a6.33,6.33,0,0,0-5.77-3.88H203.37a2,2,0,0,0-1.83,2.8Z"/>
+ <path class="cls-12"
+ d="M226.09,713.28h4v18.29c0,4.57,2,6.78,6.11,6.78,4,0,6.94-2.31,7-6.73V713.28h4v28h-3.13l-.77-2.93h-.21c-.77,1.08-3.29,3.49-8,3.49-5.76,0-8.94-3-9.1-9.4Z"/>
+ <path class="cls-12"
+ d="M255.8,702.23h4v12.95H260a11.06,11.06,0,0,1,6.78-2.16c5.86,0,10.64,3.8,10.64,13.36,0,9.09-4.47,15.36-13.72,15.36a17.71,17.71,0,0,1-7.86-1.49Zm17.57,24.72c0-8.12-3.8-10.43-7.71-10.43a7.46,7.46,0,0,0-5.86,2.77v18.19a12,12,0,0,0,4.47.77C269.72,738.25,273.37,734.5,273.37,726.94Z"/>
+ <path class="cls-12"
+ d="M346.7,721.34V734c0,2.52.77,4.21,2.72,4.21h.72v2.93a3.13,3.13,0,0,1-1.44.31,5,5,0,0,1-5.09-3.39h-.21a10.09,10.09,0,0,1-8.32,3.75c-5.19,0-8.07-3.65-8.07-7.45,0-6.17,6.06-9.2,16-9v-3c0-4.57-2.21-5.91-5.91-5.91a7,7,0,0,0-6.37,3.39l-2.93-2.31a10.91,10.91,0,0,1,9.4-4.57C343.15,712.86,346.7,715.49,346.7,721.34Zm-3.7,7.09c-6.73-.26-12,1.39-12,5.6,0,2.47,1.8,4.47,5,4.47a8.63,8.63,0,0,0,7-3.8Z"/>
+ <path class="cls-12" d="M378.2,702.18a2.9,2.9,0,1,1,0,5.81,2.9,2.9,0,0,1,0-5.81Zm-1.75,11.1h4v28h-4Z"/>
+ <path class="cls-12"
+ d="M439,739.07a14.54,14.54,0,0,1-8.79,2.52c-8,0-12.28-4.06-12.28-14.49,0-10.12,5.65-14.28,11.87-14.28,6.63,0,10.17,4.32,10.17,10.94a43.49,43.49,0,0,1-.31,4.83H421.93c.36,6.89,3.24,9.51,8.84,9.51a10.61,10.61,0,0,0,6.47-2.11ZM422,725.3h14c.05-.62.05-1.23.05-1.59,0-4.78-2.05-7.45-6.58-7.45C425.84,716.26,422.34,718.57,422,725.3Z"/>
+ <path class="cls-12"
+ d="M311.55,712.71c-4.37,0-7.09,2.16-8.17,4.42h-.21c-1-2.52-3.24-4.42-7.4-4.42a8.25,8.25,0,0,0-7.25,3.55h-.1v-3h-4v28h4v-20a6.49,6.49,0,0,1,6.32-5c3.6,0,5.55,2.42,5.55,6.83v18.14h4v-20.3a6.69,6.69,0,0,1,6.42-4.68c3.44,0,5.5,2.21,5.5,6.53v18.45h4V722C320.18,715.84,317.1,712.71,311.55,712.71Z"/>
+ <path class="cls-12"
+ d="M402,712.71a10.6,10.6,0,0,0-8,3.49H394v-2.93h-4v28h4v-20a7.54,7.54,0,0,1,7.09-5c3.9,0,6,2.36,6,6.63v18.34h4V722C410.93,715.74,407.59,712.71,402,712.71Z"/>
+ <path class="cls-12"
+ d="M356.55,713.62h3.88l.4,5H361c1.88-3.48,4.74-5.71,7.88-5.71a6.88,6.88,0,0,1,3,.57l-.91,4.11a7.76,7.76,0,0,0-2.68-.46c-2.34,0-5.14,1.71-7,6.39v17.81h-4.68Z"/>
+ <path class="cls-12"
+ d="M202.3,714.1c0-3.29,2.52-5.65,6.73-5.65a10.79,10.79,0,0,1,7,2.47l2.52-3.19a14.55,14.55,0,0,0-9.3-3c-6.47,0-11.15,4.21-11.15,9.66,0,11.36,17.16,9.51,17.16,17.68,0,3.33-2.61,6-7.48,6h-21.2a20,20,0,0,0-2.34,3.69h23.16c7.71,0,12-4.52,12-10C219.46,720.68,202.3,722.42,202.3,714.1Z"/>
+ <path class="cls-12"
+ d="M403.33,583.75H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,632a2,2,0,0,0,0,3.53l103.26,44.79a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-1"
+ d="M403.33,583.75H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,632a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-1"
+ d="M403.33,583.75H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,632a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <g class="cls-13">
+ <path class="cls-14" d="M464.7,582.73H342.37v0a119.86,119.86,0,1,0,118,88.08h4.28Z"/>
+ <path class="cls-15" d="M444.67,603.08V583.75H390.22a86.42,86.42,0,1,0,54.45,19.33Z"/>
+ <path class="cls-1"
+ d="M403.33,583.75H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,632a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ <path class="cls-16"
+ d="M409.18,637.84a28.73,28.73,0,0,1-12.9,3.61h0a62.88,62.88,0,0,0-55.84,42.3h1.69a63.3,63.3,0,1,0,123.06,20.88C465.18,669.68,406.79,639.29,409.18,637.84Z"/>
+ <path class="cls-1"
+ d="M403.33,583.75H344.16a121.42,121.42,0,0,0-47,9.58h0L208.13,632a2,2,0,0,0,0,3.53l100.59,43.65,2.67,1.14a52,52,0,0,0,18.15,3.44h27.32a20,20,0,0,0,19.67-16.44h0a31.32,31.32,0,0,1,17.58-22.91h0l5.24-2c12.41-4.58,22.37-11.82,27.22-23.25l.4-1a25.31,25.31,0,0,0-23.63-34.38Z"/>
+ </g>
+</svg>
diff --git a/submarine-workbench/workbench-web-ng/src/environments/environment.prod.ts b/submarine-workbench/workbench-web-ng/src/environments/environment.prod.ts
new file mode 100644
index 0000000..4982e3c
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/environments/environment.prod.ts
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 const environment = {
+ production: true
+};
diff --git a/submarine-workbench/workbench-web-ng/src/environments/environment.ts b/submarine-workbench/workbench-web-ng/src/environments/environment.ts
new file mode 100644
index 0000000..1241921
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/environments/environment.ts
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// This file can be replaced during build by using the `fileReplacements` array.
+// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
+// The list of file replacements can be found in `angular.json`.
+
+export const environment = {
+ production: false
+};
+
+/*
+ * For easier debugging in development mode, you can import the following file
+ * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
+ *
+ * This import should be commented out in production mode because it will have a negative impact
+ * on performance if an error is thrown.
+ */
+// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
diff --git a/submarine-workbench/workbench-web-ng/src/favicon.ico b/submarine-workbench/workbench-web-ng/src/favicon.ico
new file mode 100644
index 0000000..4465ca9
Binary files /dev/null and b/submarine-workbench/workbench-web-ng/src/favicon.ico differ
diff --git a/submarine-workbench/workbench-web-ng/src/index.html b/submarine-workbench/workbench-web-ng/src/index.html
new file mode 100644
index 0000000..2134e57
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/index.html
@@ -0,0 +1,32 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Submarine</title>
+ <base href="/">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="icon" type="image/x-icon" href="favicon.ico">
+</head>
+<body>
+ <submarine-root></submarine-root>
+</body>
+</html>
diff --git a/submarine-workbench/workbench-web-ng/src/main.ts b/submarine-workbench/workbench-web-ng/src/main.ts
new file mode 100644
index 0000000..6274974
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/main.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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';
+import { environment } from '@submarine/environment';
+
+if (environment.production) {
+ enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule)
+ .catch(err => console.error(err));
diff --git a/submarine-workbench/workbench-web-ng/src/polyfills.ts b/submarine-workbench/workbench-web-ng/src/polyfills.ts
new file mode 100644
index 0000000..15f6f9c
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/polyfills.ts
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * 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/guide/browser-support
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js'; // Run `npm install --save classlist.js`.
+
+/**
+ * Web Animations `@angular/platform-browser/animations`
+ * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
+ * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
+ */
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+/**
+ * By default, zone.js will patch all possible macroTask and DomEvents
+ * user can disable parts of macroTask/DomEvents patch by setting following flags
+ * because those flags need to be set before `zone.js` being loaded, and webpack
+ * will put import in the top of bundle, so user need to create a separate file
+ * in this directory (for example: zone-flags.ts), and put the following flags
+ * into that file, and then add the following code before importing zone.js.
+ * import './zone-flags.ts';
+ *
+ * The flags allowed in zone-flags.ts are listed here.
+ *
+ * The following flags will work for all browsers.
+ *
+ * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
+ * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
+ * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
+ *
+ * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
+ * with the following flag, it will bypass `zone.js` patch for IE/Edge
+ *
+ * (window as any).__Zone_enable_cross_context_check = true;
+ *
+ */
+
+/***************************************************************************************************
+ * Zone JS is required by default for Angular itself.
+ */
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
diff --git a/submarine-workbench/workbench-web-ng/src/styles.scss b/submarine-workbench/workbench-web-ng/src/styles.scss
new file mode 100644
index 0000000..6d93bff
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/styles.scss
@@ -0,0 +1,20 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/* You can add global styles to this file, and also import other style files */
diff --git a/submarine-workbench/workbench-web-ng/src/test.ts b/submarine-workbench/workbench-web-ng/src/test.ts
new file mode 100644
index 0000000..b90b1d8
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/test.ts
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/zone-testing';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/submarine-workbench/workbench-web-ng/src/theme.less b/submarine-workbench/workbench-web-ng/src/theme.less
new file mode 100644
index 0000000..ab88f5d
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/src/theme.less
@@ -0,0 +1,561 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "../node_modules/ng-zorro-antd/ng-zorro-antd.less";
+// The prefix to use on all css classes from ant.
+@ant-prefix : ant;
+
+// -------- Colors -----------
+@primary-color : @blue-6;
+@info-color : @blue-6;
+@success-color : @green-6;
+@processing-color : @blue-6;
+@error-color : @red-6;
+@highlight-color : @red-6;
+@warning-color : @gold-6;
+@normal-color : #d9d9d9;
+
+// Color used by default to control hover and active backgrounds and for
+// alert info backgrounds.
+@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%)
+@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%)
+@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused
+@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused
+@primary-5: color(
+ ~`colorPalette('@{primary-color}', 5) `
+); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%)
+@primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color
+@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%)
+@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused
+@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused
+@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused
+
+// Base Scaffolding Variables
+// ---
+
+// Background color for `<body>`
+@body-background : #fff;
+// Base background color for most components
+@component-background : #fff;
+@font-family : "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif,
+"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+@code-family : "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+@heading-color : fade(#000, 85%);
+@text-color : fade(#000, 65%);
+@text-color-secondary : fade(#000, 45%);
+@heading-color-dark : fade(#fff, 100%);
+@text-color-dark : fade(#fff, 85%);
+@text-color-secondary-dark: fade(#fff, 65%);
+@font-variant-base : tabular-nums;
+@font-size-base : 14px;
+@font-size-lg : @font-size-base + 2px;
+@font-size-sm : 12px;
+@line-height-base : 1.5;
+@border-radius-base : 4px;
+@border-radius-sm : 2px;
+
+// vertical paddings
+@padding-lg : 24px; // containers
+@padding-md : 16px; // small containers and buttons
+@padding-sm : 12px; // Form controls and items
+@padding-xs : 8px; // small items
+
+// vertical padding for all form controls
+@control-padding-horizontal: @padding-sm;
+@control-padding-horizontal-sm: @padding-xs;
+
+// The background colors for active and hover states for things like
+// list items or table cells.
+@item-active-bg : @primary-1;
+@item-hover-bg : @primary-1;
+
+// ICONFONT
+@iconfont-css-prefix : anticon;
+
+// LINK
+@link-color : @primary-color;
+@link-hover-color : color(~`colorPalette("@{link-color}", 5)`);
+@link-active-color : color(~`colorPalette("@{link-color}", 7)`);
+@link-decoration : none;
+@link-hover-decoration : none;
+
+// Animation
+@ease-base-out : cubic-bezier(0.7, 0.3, 0.1, 1);
+@ease-base-in : cubic-bezier(0.9, 0, 0.3, 0.7);
+@ease-out : cubic-bezier(0.215, 0.61, 0.355, 1);
+@ease-in : cubic-bezier(0.55, 0.055, 0.675, 0.19);
+@ease-in-out : cubic-bezier(0.645, 0.045, 0.355, 1);
+@ease-out-back : cubic-bezier(0.12, 0.4, 0.29, 1.46);
+@ease-in-back : cubic-bezier(0.71, -0.46, 0.88, 0.6);
+@ease-in-out-back : cubic-bezier(0.71, -0.46, 0.29, 1.46);
+@ease-out-circ : cubic-bezier(0.08, 0.82, 0.17, 1);
+@ease-in-circ : cubic-bezier(0.6, 0.04, 0.98, 0.34);
+@ease-in-out-circ : cubic-bezier(0.78, 0.14, 0.15, 0.86);
+@ease-out-quint : cubic-bezier(0.23, 1, 0.32, 1);
+@ease-in-quint : cubic-bezier(0.755, 0.05, 0.855, 0.06);
+@ease-in-out-quint : cubic-bezier(0.86, 0, 0.07, 1);
+
+// Border color
+@border-color-base : hsv(0, 0, 85%); // base border outline a component
+@border-color-split : hsv(0, 0, 91%); // split border inside a component
+@border-width-base : 1px; // width of the border for a component
+@border-style-base : solid; // style of a components border
+
+// Outline
+@outline-blur-size : 0;
+@outline-width : 2px;
+@outline-color : @primary-color;
+
+@background-color-light : hsv(0, 0, 98%); // background of header and selected item
+@background-color-base : hsv(0, 0, 96%); // Default grey background color
+
+// Disabled states
+@disabled-color : fade(#000, 25%);
+@disabled-bg : @background-color-base;
+@disabled-color-dark : fade(#fff, 35%);
+
+// Shadow
+@shadow-color : rgba(0, 0, 0, .15);
+@box-shadow-base : @shadow-1-down;
+@shadow-1-up : 0 -2px 8px @shadow-color;
+@shadow-1-down : 0 2px 8px @shadow-color;
+@shadow-1-left : -2px 0 8px @shadow-color;
+@shadow-1-right : 2px 0 8px @shadow-color;
+@shadow-2 : 0 4px 12px @shadow-color;
+
+// Buttons
+@btn-font-weight : 400;
+@btn-border-radius-base : @border-radius-base;
+@btn-border-radius-sm : @border-radius-base;
+
+@btn-primary-color : #fff;
+@btn-primary-bg : @primary-color;
+
+@btn-default-color : @text-color;
+@btn-default-bg : #fff;
+@btn-default-border : @border-color-base;
+
+@btn-danger-color : @error-color;
+@btn-danger-bg : @background-color-base;
+@btn-danger-border : @border-color-base;
+
+@btn-disable-color : @disabled-color;
+@btn-disable-bg : @disabled-bg;
+@btn-disable-border : @border-color-base;
+
+@btn-padding-base : 0 @padding-md - 1px;
+@btn-font-size-lg : @font-size-lg;
+@btn-font-size-sm : @font-size-base;
+@btn-padding-lg : @btn-padding-base;
+@btn-padding-sm : 0 @padding-xs - 1px;
+
+@btn-height-base : 32px;
+@btn-height-lg : 40px;
+@btn-height-sm : 24px;
+
+@btn-circle-size : @btn-height-base;
+@btn-circle-size-lg : @btn-height-lg;
+@btn-circle-size-sm : @btn-height-sm;
+
+@btn-group-border : @primary-5;
+
+// Checkbox
+@checkbox-size : 16px;
+@checkbox-color : @primary-color;
+@checkbox-check-color : #fff;
+@checkbox-border-width : @border-width-base;
+
+// Radio
+@radio-size : 16px;
+@radio-dot-color : @primary-color;
+
+// Radio buttons
+@radio-button-bg : @btn-default-bg;
+@radio-button-color : @btn-default-color;
+@radio-button-hover-color : @primary-5;
+@radio-button-active-color : @primary-7;
+
+// Media queries breakpoints
+// Extra small screen / phone
+@screen-xs : 480px;
+@screen-xs-min : @screen-xs;
+
+// Small screen / tablet
+@screen-sm : 576px;
+@screen-sm-min : @screen-sm;
+
+// Medium screen / desktop
+@screen-md : 768px;
+@screen-md-min : @screen-md;
+
+// Large screen / wide desktop
+@screen-lg : 992px;
+@screen-lg-min : @screen-lg;
+
+// Extra large screen / full hd
+@screen-xl : 1200px;
+@screen-xl-min : @screen-xl;
+
+// Extra extra large screen / large descktop
+@screen-xxl : 1600px;
+@screen-xxl-min : @screen-xxl;
+
+// provide a maximum
+@screen-xs-max : (@screen-sm-min - 1px);
+@screen-sm-max : (@screen-md-min - 1px);
+@screen-md-max : (@screen-lg-min - 1px);
+@screen-lg-max : (@screen-xl-min - 1px);
+@screen-xl-max : (@screen-xxl-min - 1px);
+
+// Grid system
+@grid-columns : 24;
+@grid-gutter-width : 0;
+
+// Layout
+@layout-body-background : #f0f2f5;
+@layout-header-background : #001529;
+@layout-footer-background : @layout-body-background;
+@layout-header-height : 64px;
+@layout-header-padding : 0 50px;
+@layout-footer-padding : 24px 50px;
+@layout-sider-background : @layout-header-background;
+@layout-trigger-height : 48px;
+@layout-trigger-background : #002140;
+@layout-trigger-color : #fff;
+@layout-zero-trigger-width : 36px;
+@layout-zero-trigger-height : 42px;
+// Layout light theme
+@layout-sider-background-light : #fff;
+@layout-trigger-background-light: #fff;
+@layout-trigger-color-light : @text-color;
+
+// z-index list
+@zindex-affix : 10;
+@zindex-back-top : 10;
+@zindex-modal-mask : 1000;
+@zindex-modal : 1000;
+@zindex-notification : 1010;
+@zindex-message : 1010;
+@zindex-popover : 1030;
+@zindex-picker : 1050;
+@zindex-dropdown : 1050;
+@zindex-tooltip : 1060;
+
+// Animation
+@animation-duration-slow: 0.3s; // Modal
+@animation-duration-base: 0.2s;
+@animation-duration-fast: 0.1s; // Tooltip
+
+// Form
+// ---
+@label-required-color : @highlight-color;
+@label-color : @heading-color;
+@form-item-margin-bottom : 24px;
+@form-item-trailing-colon : true;
+@form-vertical-label-padding : 0 0 8px;
+@form-vertical-label-margin : 0;
+
+// Input
+// ---
+@input-height-base : 32px;
+@input-height-lg : 40px;
+@input-height-sm : 24px;
+@input-padding-horizontal : @control-padding-horizontal - 1px;
+@input-padding-horizontal-base: @input-padding-horizontal;
+@input-padding-horizontal-sm : @control-padding-horizontal-sm - 1px;
+@input-padding-horizontal-lg : @input-padding-horizontal;
+@input-padding-vertical-base : 4px;
+@input-padding-vertical-sm : 1px;
+@input-padding-vertical-lg : 6px;
+@input-placeholder-color : hsv(0, 0, 75%);
+@input-color : @text-color;
+@input-border-color : @border-color-base;
+@input-bg : #fff;
+@input-addon-bg : @background-color-light;
+@input-hover-border-color : @primary-color;
+@input-disabled-bg : @disabled-bg;
+@input-outline-offset : 0 0;
+
+// Tooltip
+// ---
+//* Tooltip max width
+@tooltip-max-width: 250px;
+//** Tooltip text color
+@tooltip-color: #fff;
+//** Tooltip background color
+@tooltip-bg: rgba(0, 0, 0, 0.75);
+//** Tooltip arrow width
+@tooltip-arrow-width: 5px;
+//** Tooltip distance with trigger
+@tooltip-distance: @tooltip-arrow-width - 1px + 4px;
+//** Tooltip arrow color
+@tooltip-arrow-color: @tooltip-bg;
+
+// Popover
+// ---
+//** Popover body background color
+@popover-bg: #fff;
+//** Popover text color
+@popover-color: @text-color;
+//** Popover maximum width
+@popover-min-width: 177px;
+//** Popover arrow width
+@popover-arrow-width: 6px;
+//** Popover arrow color
+@popover-arrow-color: @popover-bg;
+//** Popover outer arrow width
+//** Popover outer arrow color
+@popover-arrow-outer-color: @popover-bg;
+//** Popover distance with trigger
+@popover-distance: @popover-arrow-width + 4px;
+
+// Modal
+// --
+@modal-header-bg: @component-background;
+@modal-mask-bg: rgba(0, 0, 0, 0.65);
+
+// Progress
+// --
+@progress-default-color: @processing-color;
+@progress-remaining-color: @background-color-base;
+@progress-text-color: @text-color;
+
+// Menu
+// ---
+@menu-inline-toplevel-item-height: 40px;
+@menu-item-height: 40px;
+@menu-collapsed-width: 80px;
+@menu-bg: @component-background;
+@menu-popup-bg: @component-background;
+@menu-item-color: @text-color;
+@menu-highlight-color: @primary-color;
+@menu-item-active-bg: @item-active-bg;
+@menu-item-active-border-width: 3px;
+@menu-item-group-title-color: @text-color-secondary;
+// dark theme
+@menu-dark-color: @text-color-secondary-dark;
+@menu-dark-bg: @layout-header-background;
+@menu-dark-arrow-color: #fff;
+@menu-dark-submenu-bg: #000c17;
+@menu-dark-highlight-color: #fff;
+@menu-dark-item-active-bg: @primary-color;
+
+// Spin
+// ---
+@spin-dot-size-sm: 14px;
+@spin-dot-size: 20px;
+@spin-dot-size-lg: 32px;
+
+// Table
+// --
+@table-header-bg: @background-color-light;
+@table-header-color: @heading-color;
+@table-header-sort-bg: @background-color-base;
+@table-body-sort-bg: rgba(0, 0, 0, 0.01);
+@table-row-hover-bg: @primary-1;
+@table-selected-row-bg: #fafafa;
+@table-expanded-row-bg: #fbfbfb;
+@table-padding-vertical: 16px;
+@table-padding-horizontal: 16px;
+
+// Tag
+// --
+@tag-default-bg: @background-color-light;
+@tag-default-color: @text-color;
+@tag-font-size: @font-size-sm;
+
+// TimePicker
+// ---
+@time-picker-panel-column-width: 56px;
+@time-picker-panel-width: @time-picker-panel-column-width * 3;
+@time-picker-selected-bg: @background-color-base;
+
+// Carousel
+// ---
+@carousel-dot-width: 16px;
+@carousel-dot-height: 3px;
+@carousel-dot-active-width: 24px;
+
+// Badge
+// ---
+@badge-height: 20px;
+@badge-dot-size: 6px;
+@badge-font-size: @font-size-sm;
+@badge-font-weight: normal;
+@badge-status-size: 6px;
+
+// Rate
+// ---
+@rate-star-color: @yellow-6;
+@rate-star-bg: @border-color-split;
+
+// Card
+// ---
+@card-head-color: @heading-color;
+@card-head-background: transparent;
+@card-head-padding: 16px;
+@card-inner-head-padding: 12px;
+@card-padding-base: 24px;
+@card-padding-wider: 32px;
+@card-actions-background: @background-color-light;
+@card-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
+
+// Comment
+// ---
+@comment-padding-base: 16px 0;
+@comment-nest-indent: 44px;
+@comment-author-name-color: @text-color-secondary;
+@comment-author-time-color: #ccc;
+@comment-action-color: @text-color-secondary;
+@comment-action-hover-color: #595959;
+
+// Tabs
+// ---
+@tabs-card-head-background: @background-color-light;
+@tabs-card-height: 40px;
+@tabs-card-active-color: @primary-color;
+@tabs-title-font-size: @font-size-base;
+@tabs-title-font-size-lg: @font-size-lg;
+@tabs-title-font-size-sm: @font-size-base;
+@tabs-ink-bar-color: @primary-color;
+@tabs-bar-margin: 0 0 16px 0;
+@tabs-horizontal-margin: 0 32px 0 0;
+@tabs-horizontal-padding: 12px 16px;
+@tabs-vertical-padding: 8px 24px;
+@tabs-vertical-margin: 0 0 16px 0;
+@tabs-scrolling-size: 32px;
+@tabs-highlight-color: @primary-color;
+@tabs-hover-color: @primary-5;
+@tabs-active-color: @primary-7;
+
+// BackTop
+// ---
+@back-top-color: #fff;
+@back-top-bg: @text-color-secondary;
+@back-top-hover-bg: @text-color;
+
+// Avatar
+// ---
+@avatar-size-base: 32px;
+@avatar-size-lg: 40px;
+@avatar-size-sm: 24px;
+@avatar-font-size-base: 18px;
+@avatar-font-size-lg: 24px;
+@avatar-font-size-sm: 14px;
+@avatar-bg: #ccc;
+@avatar-color: #fff;
+@avatar-border-radius: @border-radius-base;
+
+// Switch
+// ---
+@switch-height: 22px;
+@switch-sm-height: 16px;
+@switch-sm-checked-margin-left: -(@switch-sm-height - 3px);
+@switch-disabled-opacity: 0.4;
+@switch-color: @primary-color;
+
+// Pagination
+// ---
+@pagination-item-size: 32px;
+@pagination-item-size-sm: 24px;
+@pagination-font-family: Arial;
+@pagination-font-weight-active: 500;
+
+// Breadcrumb
+// ---
+@breadcrumb-base-color: @text-color-secondary;
+@breadcrumb-last-item-color: @text-color;
+@breadcrumb-font-size: @font-size-base;
+@breadcrumb-icon-font-size: @font-size-base;
+@breadcrumb-link-color: @text-color-secondary;
+@breadcrumb-link-color-hover: @primary-5;
+@breadcrumb-separator-color: @text-color-secondary;
+@breadcrumb-separator-margin: 0 @padding-xs;
+
+// Slider
+// ---
+@slider-margin: 14px 6px 10px;
+@slider-rail-background-color: @background-color-base;
+@slider-rail-background-color-hover: #e1e1e1;
+@slider-track-background-color: @primary-5;
+@slider-track-background-color-hover: @primary-6;
+@slider-handle-color: @primary-5;
+@slider-handle-color-hover: @primary-6;
+@slider-handle-color-focus: tint(@primary-color, 20%);
+@slider-handle-color-focus-shadow: fade(@primary-color, 20%);
+@slider-handle-color-tooltip-open: @primary-color;
+@slider-dot-border-color: @border-color-split;
+@slider-dot-border-color-active: @primary-5;
+@slider-disabled-color: @disabled-color;
+@slider-disabled-background-color: @component-background;
+
+// Tree
+// ---
+@tree-title-height: 24px;
+@tree-child-padding: 18px;
+@tree-directory-selected-color: #fff;
+@tree-directory-selected-bg: @primary-color;
+
+// Collapse
+// ---
+@collapse-header-padding: 12px 16px 12px 40px;
+@collapse-header-bg: @background-color-light;
+@collapse-content-padding: @padding-md;
+@collapse-content-bg: @component-background;
+
+// Skeleton
+// ---
+@skeleton-color: #f2f2f2;
+
+// Transfer
+// ---
+@transfer-disabled-bg: @disabled-bg;
+
+// Message
+// ---
+@message-notice-content-padding: 10px 16px;
+
+// Motion
+// ---
+@wave-animation-width: 6px;
+
+// Alert
+// ---
+@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `;
+@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `;
+@alert-success-icon-color: @success-color;
+@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `;
+@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `;
+@alert-info-icon-color: @info-color;
+@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `;
+@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `;
+@alert-warning-icon-color: @warning-color;
+@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `;
+@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `;
+@alert-error-icon-color: @error-color;
+
+// List
+// ---
+@list-empty-text-padding: @padding-md;
+@list-item-padding: @padding-sm 0;
+@list-item-content-margin: 0 0 @padding-md 0;
+@list-item-meta-margin-bottom: @padding-md;
+@list-item-meta-avatar-margin-right: @padding-md;
+@list-item-meta-title-margin-bottom: @padding-sm;
+
diff --git a/submarine-workbench/workbench-web-ng/tsconfig.app.json b/submarine-workbench/workbench-web-ng/tsconfig.app.json
new file mode 100644
index 0000000..565a11a
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/tsconfig.app.json
@@ -0,0 +1,18 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/app",
+ "types": []
+ },
+ "files": [
+ "src/main.ts",
+ "src/polyfills.ts"
+ ],
+ "include": [
+ "src/**/*.ts"
+ ],
+ "exclude": [
+ "src/test.ts",
+ "src/**/*.spec.ts"
+ ]
+}
diff --git a/submarine-workbench/workbench-web-ng/tsconfig.json b/submarine-workbench/workbench-web-ng/tsconfig.json
new file mode 100644
index 0000000..a9a1c46
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "baseUrl": "./",
+ "paths": {
+ "@submarine/*": [
+ "./src/app/*",
+ "./src/environments/*"
+ ]
+ },
+ "outDir": "./dist/out-tsc",
+ "sourceMap": true,
+ "declaration": false,
+ "downlevelIteration": true,
+ "experimentalDecorators": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "importHelpers": true,
+ "target": "es2015",
+ "typeRoots": [
+ "node_modules/@types"
+ ],
+ "lib": [
+ "es2018",
+ "dom"
+ ]
+ },
+ "angularCompilerOptions": {
+ "fullTemplateTypeCheck": true,
+ "strictInjectionParameters": true
+ }
+}
diff --git a/submarine-workbench/workbench-web-ng/tsconfig.spec.json b/submarine-workbench/workbench-web-ng/tsconfig.spec.json
new file mode 100644
index 0000000..6400fde
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/tsconfig.spec.json
@@ -0,0 +1,18 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "./out-tsc/spec",
+ "types": [
+ "jasmine",
+ "node"
+ ]
+ },
+ "files": [
+ "src/test.ts",
+ "src/polyfills.ts"
+ ],
+ "include": [
+ "src/**/*.spec.ts",
+ "src/**/*.d.ts"
+ ]
+}
diff --git a/submarine-workbench/workbench-web-ng/tslint.json b/submarine-workbench/workbench-web-ng/tslint.json
new file mode 100644
index 0000000..ae8d3ae
--- /dev/null
+++ b/submarine-workbench/workbench-web-ng/tslint.json
@@ -0,0 +1,142 @@
+{
+ "rulesDirectory": ["node_modules/codelyzer"],
+ "linterOptions": {
+ "exclude": [
+ "e2e/**",
+ "src/main.ts",
+ "src/polyfills.ts",
+ "src/test.ts"
+ ]
+ },
+ "rules": {
+ "no-life-cycle-call": false,
+ "prefer-output-readonly": true,
+ "no-conflicting-life-cycle-hooks": false,
+ "enforce-component-selector": false,
+ "use-host-property-decorator": false,
+ "use-view-encapsulation": false,
+ "no-output-rename": true,
+ "no-output-on-prefix": true,
+ "no-forward-ref": false,
+ "use-life-cycle-interface": true,
+ "contextual-life-cycle": true,
+ "trackBy-function": false,
+ "use-pipe-transform-interface": true,
+ "component-class-suffix": true,
+ "directive-class-suffix": true,
+ "angular-whitespace": [false, "check-interpolation"],
+ "directive-selector": [true, "attribute", ["submarine"], ["camelCase", "kebab-case"]],
+ "component-selector": [true, ["element", "attribute"], ["submarine"], "kebab-case"],
+ "callable-types": true,
+ "class-name": true,
+ "comment-format": [true, "check-space"],
+ "align": [true, "parameters", "statements"],
+ "array-type": [true, "array-simple"],
+ "arrow-return-shorthand": true,
+ "ban-types": [
+ true,
+ ["Object", "Use {} instead."],
+ ["String", "Use string instead."],
+ ["Number", "Use number instead."],
+ ["Boolean", "Use boolean instead."],
+ ["Function", "Use specific callable interface instead."]
+ ],
+ "binary-expression-operand-order": true,
+ "curly": true,
+ "encoding": true,
+ "eofline": true,
+ "deprecation": {
+ "severity": "warn"
+ },
+ "import-spacing": true,
+ "indent": [true, "spaces"],
+ "interface-name": [true, "never-prefix"],
+ "interface-over-type-literal": true,
+ "label-position": true,
+ "new-parens": true,
+ "no-angle-bracket-type-assertion": true,
+ "member-access": false,
+ "member-ordering": [
+ true,
+ {
+ "order": ["static-field", "instance-field", "static-method", "instance-method"]
+ }
+ ],
+ "no-any": false,
+ "no-arg": true,
+ "no-bitwise": false,
+ "no-consecutive-blank-lines": [true],
+ "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
+ "no-duplicate-variable": true,
+ "no-conditional-assignment": true,
+ "no-construct": true,
+ "no-debugger": true,
+ "no-duplicate-imports": true,
+ "no-duplicate-super": true,
+ "no-empty": false,
+ "no-empty-interface": true,
+ "no-eval": true,
+ "no-floating-promises": false,
+ "no-for-in-array": true,
+ "no-import-side-effect": true,
+ "no-inferrable-types": [true, "ignore-params", "ignore-properties"],
+ "no-invalid-template-strings": true,
+ "no-invalid-this": true,
+ "no-irregular-whitespace": true,
+ "no-magic-numbers": false,
+ "no-misused-new": true,
+ "no-namespace": [true, "allow-declarations"],
+ "no-non-null-assertion": false,
+ "no-shadowed-variable": true,
+ "no-sparse-arrays": true,
+ "no-string-literal": true,
+ "no-string-throw": true,
+ "no-switch-case-fall-through": true,
+ "no-this-assignment": true,
+ "no-trailing-whitespace": true,
+ "no-parameter-reassignment": true,
+ "no-unnecessary-initializer": true,
+ "no-unused-expression": true,
+ "no-use-before-declare": true,
+ "no-var-keyword": true,
+ "number-literal-format": true,
+ "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"],
+ "one-variable-per-declaration": [true, "ignore-for-loop"],
+ "ordered-imports": [
+ true,
+ {
+ "import-sources-order": "lowercase-last",
+ "named-imports-order": "lowercase-first"
+ }
+ ],
+ "prefer-conditional-expression": false,
+ "prefer-const": true,
+ "prefer-method-signature": true,
+ "prefer-object-spread": true,
+ "prefer-template": [true, "allow-single-concat"],
+ "radix": true,
+ "trailing-comma": [
+ true,
+ {
+ "multiline": "never",
+ "singleline": "never"
+ }
+ ],
+ "triple-equals": [true, "allow-null-check"],
+ "typedef-whitespace": [
+ true,
+ {
+ "call-signature": "nospace",
+ "index-signature": "nospace",
+ "parameter": "nospace",
+ "property-declaration": "nospace",
+ "variable-declaration": "nospace"
+ }
+ ],
+ "unified-signatures": true,
+ "use-isnan": true,
+ "variable-name": [true, "ban-keywords", "allow-leading-underscore"],
+ "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"],
+ "no-input-rename": true
+ }
+}