You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by ki...@apache.org on 2020/07/17 10:50:25 UTC

[shardingsphere-elasticjob-ui] branch master updated (05c2ae9 -> eaf171d)

This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git.


    from 05c2ae9  Merge pull request #3 from menghaoranss/add-help
     new 8d74d84  Guest user just read only
     new 46f6743  Fixes checkstyle
     new eaf171d  Merge pull request #4 from menghaoranss/guest-user

The 11 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../src/views/data-source/module/dataSource.vue    |  4 ++++
 .../src/views/help/index.vue                       | 22 +++++++++++-----------
 .../src/views/login/index.vue                      |  5 +++--
 .../registry-center/module/registryCenter.vue      |  8 ++++++--
 4 files changed, 24 insertions(+), 15 deletions(-)


[shardingsphere-elasticjob-ui] 01/11: init ui project

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit 5b41d495d880c653b8106fc8d389fe3bddefafd7
Author: kimmking <ki...@apache.org>
AuthorDate: Wed Jul 15 22:23:33 2020 +0800

    init ui project
---
 .asf.yaml                                          |  34 ++
 .gitignore                                         |  38 ++
 .mvn/jvm.config                                    |   1 +
 .mvn/wrapper/MavenWrapperDownloader.java           | 114 ++++++
 .mvn/wrapper/maven-wrapper.properties              |   3 +
 LICENSE                                            | 218 +++++++++++
 NOTICE                                             |   5 +
 README.md                                          |  28 ++
 README_ZH.md                                       |  28 ++
 RELEASE-NOTES.md                                   |   1 +
 mvnw                                               | 310 ++++++++++++++++
 mvnw.cmd                                           | 182 ++++++++++
 pom.xml                                            | 159 ++++++++
 shardingsphere-elasticjob-ui-backend/pom.xml       |  62 ++++
 .../shardingsphere-elasticjob-ui-backend-API.md    |   0
 .../apache/shardingsphere/elasticjob/ui/README.md  |   0
 .../src/main/resources/application.properties      |  21 ++
 .../src/main/resources/logback.xml                 |  33 ++
 shardingsphere-elasticjob-ui-distribution/pom.xml  |  38 ++
 .../Dockerfile                                     |  27 ++
 .../pom.xml                                        | 115 ++++++
 ...ardingsphere-elasticjob-ui-bin-distribution.xml |  63 ++++
 .../src/main/release-docs/LICENSE                  | 288 +++++++++++++++
 .../src/main/release-docs/NOTICE                   | 219 +++++++++++
 .../src/main/release-docs/licenses/LICENSE-axios   |  19 +
 .../licenses/LICENSE-echarts-liquidfill            |   7 +
 .../main/release-docs/licenses/LICENSE-element-ui  |  21 ++
 .../main/release-docs/licenses/LICENSE-groovy.txt  | 217 +++++++++++
 .../licenses/LICENSE-incubator-echarts             | 223 ++++++++++++
 .../licenses/LICENSE-jcl-over-slf4j.txt            |  24 ++
 .../main/release-docs/licenses/LICENSE-jline.txt   |  37 ++
 .../src/main/release-docs/licenses/LICENSE-js-yaml |  21 ++
 .../release-docs/licenses/LICENSE-jul-to-slf4j.txt |  24 ++
 .../src/main/release-docs/licenses/LICENSE-lodash  |  49 +++
 .../main/release-docs/licenses/LICENSE-logback.txt |  14 +
 .../src/main/release-docs/licenses/LICENSE-moment  |  22 ++
 .../main/release-docs/licenses/LICENSE-normalize   |  21 ++
 .../release-docs/licenses/LICENSE-resize-detector  |  43 +++
 .../main/release-docs/licenses/LICENSE-slf4j.txt   |  24 ++
 .../src/main/release-docs/licenses/LICENSE-vue     |  21 ++
 .../main/release-docs/licenses/LICENSE-vue-i18n    |  20 +
 .../main/release-docs/licenses/LICENSE-vue-router  |  21 ++
 .../src/main/release-docs/licenses/LICENSE-vuex    |  21 ++
 .../src/main/resources/application.properties      |  21 ++
 .../src/main/resources/bin/start.bat               |  34 ++
 .../src/main/resources/bin/start.sh                |  47 +++
 .../src/main/resources/bin/stop.sh                 |  51 +++
 .../src/main/resources/logback.xml                 |  33 ++
 .../pom.xml                                        |  70 ++++
 ...ardingsphere-elasticjob-ui-src-distribution.xml |  87 +++++
 shardingsphere-elasticjob-ui-frontend/.babelrc     |  27 ++
 .../.editorconfig                                  |   9 +
 .../.eslintignore                                  |   4 +
 shardingsphere-elasticjob-ui-frontend/.eslintrc.js | 221 +++++++++++
 shardingsphere-elasticjob-ui-frontend/.gitignore   |  18 +
 .../.postcssrc.js                                  |  27 ++
 shardingsphere-elasticjob-ui-frontend/README.md    |  24 ++
 shardingsphere-elasticjob-ui-frontend/README_ZH.md |  24 ++
 .../build/build.js                                 |  58 +++
 .../build/check-versions.js                        |  71 ++++
 .../build/rimraf.js                                | 404 +++++++++++++++++++++
 .../build/utils.js                                 | 125 +++++++
 .../build/vue-loader.conf.js                       |  22 ++
 .../build/webpack.base.conf.js                     | 119 ++++++
 .../build/webpack.dev.conf.js                      | 131 +++++++
 .../build/webpack.prod.conf.js                     | 152 ++++++++
 .../build/webpack.unit.conf.js                     |  84 +++++
 .../config/dev.env.js                              |  24 ++
 .../config/index.js                                | 100 +++++
 .../config/prod.env.js                             |  21 ++
 shardingsphere-elasticjob-ui-frontend/index.html   |  29 ++
 shardingsphere-elasticjob-ui-frontend/package.json | 109 ++++++
 shardingsphere-elasticjob-ui-frontend/pom.xml      | 165 +++++++++
 shardingsphere-elasticjob-ui-frontend/src/App.vue  |  76 ++++
 .../src/assets/img/bg.png                          | Bin 0 -> 613830 bytes
 .../src/assets/img/close.png                       | Bin 0 -> 1386 bytes
 .../src/assets/img/data-source.png                 | Bin 0 -> 1280 bytes
 .../src/assets/img/del.png                         | Bin 0 -> 1233 bytes
 .../src/assets/img/edit.png                        | Bin 0 -> 1157 bytes
 .../src/assets/img/expand.png                      | Bin 0 -> 1173 bytes
 .../src/assets/img/link.png                        | Bin 0 -> 1234 bytes
 .../src/assets/img/login-logo.png                  | Bin 0 -> 13035 bytes
 .../src/assets/img/logo.png                        | Bin 0 -> 24930 bytes
 .../src/assets/img/open.png                        | Bin 0 -> 1387 bytes
 .../src/assets/img/password.png                    | Bin 0 -> 1400 bytes
 .../src/assets/img/rules.png                       | Bin 0 -> 1163 bytes
 .../src/assets/img/shrink.png                      | Bin 0 -> 1172 bytes
 .../src/assets/img/sidebar-icon.png                | Bin 0 -> 1196 bytes
 .../src/assets/img/sidebar-logo.png                | Bin 0 -> 6445 bytes
 .../src/assets/img/user.png                        | Bin 0 -> 1381 bytes
 .../src/assets/logo.png                            | Bin 0 -> 24930 bytes
 .../src/assets/styles/index.scss                   | 108 ++++++
 .../src/assets/styles/theme.scss                   |  19 +
 .../src/components/ChartBase/index.vue             | 305 ++++++++++++++++
 .../src/components/Container/index.vue             |  65 ++++
 .../src/components/Footer/index.vue                |  40 ++
 .../src/components/Head/index.vue                  | 163 +++++++++
 .../src/components/Logo/index.vue                  |  58 +++
 .../src/components/Menu/index.vue                  | 148 ++++++++
 .../src/lang/en-US.js                              | 246 +++++++++++++
 .../src/lang/index.js                              |  23 ++
 .../src/lang/zh-CN.js                              | 246 +++++++++++++
 shardingsphere-elasticjob-ui-frontend/src/main.js  |  61 ++++
 .../src/router/index.js                            |  34 ++
 .../src/store/actions.js                           |  24 ++
 .../src/store/index.js                             |  30 ++
 .../src/store/modules/global.js                    |  33 ++
 .../src/store/modules/index.js                     |  26 ++
 .../src/store/mutation-types.js                    |  19 +
 .../src/utils/api.js                               | 126 +++++++
 .../src/utils/conf.js                              |  24 ++
 .../src/views/login/api.js                         |  22 ++
 .../src/views/login/index.vue                      | 205 +++++++++++
 .../static/404.html                                |  31 ++
 .../static/favicon.png                             | Bin 0 -> 24930 bytes
 .../test/karma.conf.js                             |  35 ++
 .../test/specs/components/Container.spec.js        |  39 ++
 .../test/specs/components/Footer.spec.js           |  26 ++
 .../test/specs/components/Head.spec.js             |  79 ++++
 .../test/specs/components/Logo.spec.js             |  26 ++
 .../test/specs/components/Menu.spec.js             |  74 ++++
 .../test/specs/views/login.spec.js                 |  60 +++
 122 files changed, 7618 insertions(+)

diff --git a/.asf.yaml b/.asf.yaml
new file mode 100644
index 0000000..619e11a
--- /dev/null
+++ b/.asf.yaml
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+notifications:
+  commits: notifications@shardingsphere.apache.org
+  issues: notifications@shardingsphere.apache.org
+  pullrequests: notifications@shardingsphere.apache.org
+
+github:
+  description: Distributed scheduled job framework
+  labels:
+    - elasticjob
+    - database
+    - scheduled-jobs
+    - cron
+    - job
+    - job-management
+    - shard
+    - quartz
+    - middleware
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dd1f195
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+# maven ignore
+target/
+*.class
+*.jar
+*.war
+*.zip
+*.tar
+*.tar.gz
+
+# maven plugin ignore
+release.properties
+cobertura.ser
+*.gpg
+
+# eclipse ignore
+.settings/
+.project
+.classpath
+
+# idea ignore
+.idea/
+*.ipr
+*.iml
+*.iws
+
+# temp ignore
+logs/
+*.log
+*.doc
+*.cache
+*.diff
+*.patch
+*.tmp
+
+# system ignore
+.DS_Store
+Thumbs.db
+node_modules/
diff --git a/.mvn/jvm.config b/.mvn/jvm.config
new file mode 100644
index 0000000..20be3f8
--- /dev/null
+++ b/.mvn/jvm.config
@@ -0,0 +1 @@
+-Xmx1024m -XX:MaxMetaspaceSize=256m
diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..b8dbdcd
--- /dev/null
+++ b/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+    private static final String WRAPPER_VERSION = "0.5.5";
+    /**
+     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+     */
+    private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+        + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+    /**
+     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+     * use instead of the default one.
+     */
+    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+        ".mvn/wrapper/maven-wrapper.properties";
+
+    /**
+     * Path where the maven-wrapper.jar will be saved to.
+     */
+    private static final String MAVEN_WRAPPER_JAR_PATH =
+        ".mvn/wrapper/maven-wrapper.jar";
+
+    /**
+     * Name of the property which should be used to override the default download url for the wrapper.
+     */
+    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+    public static void main(String args[]) {
+        System.out.println("- Downloader started");
+        File baseDirectory = new File(args[0]);
+        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+        // If the maven-wrapper.properties exists, read it and check if it contains a custom
+        // wrapperUrl parameter.
+        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+        String url = DEFAULT_DOWNLOAD_URL;
+        if(mavenWrapperPropertyFile.exists()) {
+            FileInputStream mavenWrapperPropertyFileInputStream = null;
+            try {
+                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+                Properties mavenWrapperProperties = new Properties();
+                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+            } catch (IOException e) {
+                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+            } finally {
+                try {
+                    if(mavenWrapperPropertyFileInputStream != null) {
+                        mavenWrapperPropertyFileInputStream.close();
+                    }
+                } catch (IOException e) {
+                    // Ignore ...
+                }
+            }
+        }
+        System.out.println("- Downloading from: " + url);
+
+        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+        if(!outputFile.getParentFile().exists()) {
+            if(!outputFile.getParentFile().mkdirs()) {
+                System.out.println(
+                    "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+            }
+        }
+        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+        try {
+            downloadFileFromURL(url, outputFile);
+            System.out.println("Done");
+            System.exit(0);
+        } catch (Throwable e) {
+            System.out.println("- Error downloading");
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+        if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+            String username = System.getenv("MVNW_USERNAME");
+            char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+            Authenticator.setDefault(new Authenticator() {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    return new PasswordAuthentication(username, password);
+                }
+            });
+        }
+        URL website = new URL(urlString);
+        ReadableByteChannel rbc;
+        rbc = Channels.newChannel(website.openStream());
+        FileOutputStream fos = new FileOutputStream(destination);
+        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+        fos.close();
+        rbc.close();
+    }
+
+}
\ No newline at end of file
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..54ab0bc
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,3 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..89cad8c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,218 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=======================================================================
+Apache ShardingSphere Subcomponents:
+
+The Apache ShardingSphere project contains subcomponents with separate copyright
+notices and license terms. Your use of the source code for the these
+subcomponents is subject to the terms and conditions of the following
+licenses.
+
+========================================================================
+Apache 2.0 licenses
+========================================================================
+
+The following components are provided under the Apache License. See project link for details.
+The text of each license is the standard Apache 2.0 license.
+
+    Maven Wrapper(mvnw, mvnw.cmd files in root path), https://github.com/takari/maven-wrapper   Apache 2.0
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..1611478
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,5 @@
+Apache ShardingSphere ElasticJob
+Copyright 2018-2020 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d89abbe
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+# ShardingSphere ElasticJob UI
+
+[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
+
+## Overview
+
+ShardingSphere ElasticJob UI is a management background for [ShardingSphere-ElasticJob ](https://shardingsphere.apache.org/).
+
+### ShardingSphere ElasticJob UI Frontend
+
+shardingsphere-elasticjob-ui-frontend based on [vue](https://github.com/vuejs/vue) and use the UI Toolkit [element](https://github.com/ElemeFE/element).
+
+* [shardingsphere-elasticjob-ui-frontend/README.md](shardingsphere-elasticjob-ui-frontend/README.md)
+
+### ShardingSphere ElasticJob UI Backend
+
+shardingsphere-elasticjob-ui-backend is a standard spring boot project.
+
+## How to Build
+
+```bash
+git clone https://github.com/apache/shardingsphere-elasticjob-ui.git
+cd shardingsphere-elasticjob-ui/
+mvn clean package -Prelease
+```
+
+Get the package in `shardingsphere-elasticjob-ui/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/target/apache-shardingsphere-${latest.release.version}-shardingsphere-elasticjob-ui-bin.tar.gz`
+
diff --git a/README_ZH.md b/README_ZH.md
new file mode 100644
index 0000000..d206bfc
--- /dev/null
+++ b/README_ZH.md
@@ -0,0 +1,28 @@
+# ShardingSphere ElasticJob UI
+
+[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
+
+## 概述
+
+ShardingSphere ElasticJob UI是 [ShardingSphere ElasticJob](https://shardingsphere.apache.org/) 的管理后台,包含了动态配置、数据编排等功能。
+
+### ShardingSphere ElasticJob UI 前端
+
+shardingsphere-elasticjob-ui-frontend模块基于 [vue](https://github.com/vuejs/vue) ,并使用了UI工具包 [element](https://github.com/ElemeFE/element) 。
+
+* [shardingsphere-elasticjob-ui-frontend/README.md](shardingsphere-elasticjob-ui-frontend/README.md)
+
+### ShardingSphere ElasticJob UI 后端
+
+shardingsphere-ui-backend 模块是一个标准的 spring boot 项目。
+
+## 如何构建
+
+```bash
+git clone https://github.com/apache/shardingsphere-elasticjob-ui.git
+cd shardingsphere-elasticjob-ui/
+mvn clean package -Prelease
+```
+
+从 `shardingsphere-elasticjob-ui/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/target/apache-shardingsphere-${latest.release.version}-shardingsphere-elasticjob-ui-bin.tar.gz` 中获取软件包。
+
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
new file mode 100644
index 0000000..1f2b81d
--- /dev/null
+++ b/RELEASE-NOTES.md
@@ -0,0 +1 @@
+1. 
\ No newline at end of file
diff --git a/mvnw b/mvnw
new file mode 100644
index 0000000..a3925bb
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# 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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   M2_HOME - location of maven2's installed home dir
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+  if [ -f /etc/mavenrc ] ; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ] ; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  MINGW*) mingw=true;;
+  Darwin*) darwin=true
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+    if [ -z "$JAVA_HOME" ]; then
+      if [ -x "/usr/libexec/java_home" ]; then
+        export JAVA_HOME="`/usr/libexec/java_home`"
+      else
+        export JAVA_HOME="/Library/Java/Home"
+      fi
+    fi
+    ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=`java-config --jre-home`
+  fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+  ## resolve links - $0 may be a link to maven's home
+  PRG="$0"
+
+  # need this for relative symlinks
+  while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+      PRG="$link"
+    else
+      PRG="`dirname "$PRG"`/$link"
+    fi
+  done
+
+  saveddir=`pwd`
+
+  M2_HOME=`dirname "$PRG"`/..
+
+  # make it fully qualified
+  M2_HOME=`cd "$M2_HOME" && pwd`
+
+  cd "$saveddir"
+  # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --unix "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME="`(cd "$M2_HOME"; pwd)`"
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="`which javac`"
+  if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=`which readlink`
+    if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+      if $darwin ; then
+        javaHome="`dirname \"$javaExecutable\"`"
+        javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+      else
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
+      fi
+      javaHome="`dirname \"$javaExecutable\"`"
+      javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD="`which java`"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+  if [ -z "$1" ]
+  then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ] ; do
+    if [ -d "$wdir"/.mvn ] ; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=`cd "$wdir/.."; pwd`
+    fi
+    # end of workaround
+  done
+  echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "$(tr -s '\n' ' ' < "$1")"
+  fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+  exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+    fi
+    if [ -n "$MVNW_REPOURL" ]; then
+      jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    else
+      jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    fi
+    while IFS="=" read key value; do
+      case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+      esac
+    done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Downloading from: $jarUrl"
+    fi
+    wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+    if $cygwin; then
+      wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+    fi
+
+    if command -v wget > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found wget ... using wget"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget "$jarUrl" -O "$wrapperJarPath"
+        else
+            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found curl ... using curl"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl -o "$wrapperJarPath" "$jarUrl" -f
+        else
+            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+        fi
+
+    else
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Falling back to using Java to download"
+        fi
+        javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        # For Cygwin, switch paths to Windows format before running javac
+        if $cygwin; then
+          javaClass=`cygpath --path --windows "$javaClass"`
+        fi
+        if [ -e "$javaClass" ]; then
+            if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Compiling MavenWrapperDownloader.java ..."
+                fi
+                # Compiling the Java class
+                ("$JAVA_HOME/bin/javac" "$javaClass")
+            fi
+            if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                # Running the downloader
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Running MavenWrapperDownloader.java ..."
+                fi
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 0000000..6a64c97
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM    http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %DOWNLOAD_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..f6fdef3
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,159 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache</groupId>
+        <artifactId>apache</artifactId>
+        <version>21</version>
+    </parent>
+    <groupId>org.apache.shardingsphere</groupId>
+    <artifactId>shardingsphere-elasticjob-ui</artifactId>
+    <version>3.0.0.M1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>${project.artifactId}</name>
+    
+    <modules>
+        <module>shardingsphere-elasticjob-ui-frontend</module>
+        <module>shardingsphere-elasticjob-ui-backend</module>
+        <module>shardingsphere-elasticjob-ui-distribution</module>
+    </modules>
+    
+    <properties>
+        <java.version>1.8</java.version>
+        <spring-boot.version>1.5.21.RELEASE</spring-boot.version>
+        
+        <apache-rat-plugin.version>0.12</apache-rat-plugin.version>
+        <maven-compiler-plugin.version>3.3</maven-compiler-plugin.version>
+        <frontend-maven-plugin.version>1.6</frontend-maven-plugin.version>
+        <os-maven-plugin.version>1.5.0.Final</os-maven-plugin.version>
+        <takari-maven-plugin.version>0.6.1</takari-maven-plugin.version>
+        
+        <maven.deploy.skip>true</maven.deploy.skip>
+    </properties>
+    
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    
+    <build>
+        <finalName>apache-shardingsphere-elasticjob-${project.version}</finalName>
+        <extensions>
+            <extension>
+                <groupId>kr.motd.maven</groupId>
+                <artifactId>os-maven-plugin</artifactId>
+                <version>${os-maven-plugin.version}</version>
+            </extension>
+        </extensions>
+
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <configuration>
+                        <source>${java.version}</source>
+                        <target>${java.version}</target>
+                        <testSource>${java.version}</testSource>
+                        <testTarget>${java.version}</testTarget>
+                    </configuration>
+                    <version>${maven-compiler-plugin.version}</version>
+                </plugin>
+                <!-- mvn -N io.takari:maven:wrapper -Dmaven=3.5.4 -->
+                <plugin>
+                    <groupId>io.takari</groupId>
+                    <artifactId>maven</artifactId>
+                    <version>${takari-maven-plugin.version}</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        
+        <plugins>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <version>${apache-rat-plugin.version}</version>
+                <configuration>
+                    <excludes>
+                        <exclude>**/target/**</exclude>
+                        <exclude>**/logs/**</exclude>
+                        <exclude>**/*.log</exclude>
+                        <!-- IDE files -->
+                        <exclude>**/*.iml</exclude>
+                        <exclude>**/.idea/**</exclude>
+                        <exclude>**/*.classpath</exclude>
+                        <exclude>**/.project</exclude>
+                        <exclude>**/.settings/**</exclude>
+                        <exclude>**/dependency-reduced-pom.xml</exclude>
+                        <!-- git files -->
+                        <exclude>**/.gitignore</exclude>
+                        <exclude>**/.gitmodules</exclude>
+                        <exclude>**/.git/**</exclude>
+                        <!-- CI files -->
+                        <exclude>**/.travis.yml</exclude>
+                        <exclude>**/.mvn/jvm.config</exclude>
+                        <exclude>**/.mvn/wrapper/maven-wrapper.properties</exclude>
+                        <!-- GitHub files -->
+                        <exclude>**/.github/**</exclude>
+                        <!-- document files -->
+                        <exclude>**/*.md</exclude>
+                        <excldue>**/*.MD</excldue>
+                        <exclude>**/*.txt</exclude>
+                        <exclude>**/docs/**</exclude>
+                        <!-- UI files -->
+                        <exclude>**/.babelrc</exclude>
+                        <exclude>**/.editorconfig</exclude>
+                        <exclude>**/.eslintignore</exclude>
+                        <exclude>**/package.json</exclude>
+                        <exclude>**/assets/**</exclude>
+                        <exclude>**/dist/**</exclude>
+                        <exclude>**/etc/**</exclude>
+                        <exclude>**/node/**</exclude>
+                        <exclude>**/node_modules/**</exclude>
+                        <exclude>**/test/coverage/**</exclude>
+                        <exclude>**/package-lock.json</exclude>
+                    </excludes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <scm>
+        <connection>scm:git:https://github.com/apache/shardingsphere-elasticjob-ui.git</connection>
+        <developerConnection>scm:git:https://github.com/apache/shardingsphere-elasticjob-ui.git</developerConnection>
+        <url>https://github.com/apache/shardingsphere-elasticjob-ui.git</url>
+        <tag>HEAD</tag>
+    </scm>
+</project>
diff --git a/shardingsphere-elasticjob-ui-backend/pom.xml b/shardingsphere-elasticjob-ui-backend/pom.xml
new file mode 100644
index 0000000..302129e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.shardingsphere</groupId>
+        <artifactId>shardingsphere-elasticjob-ui</artifactId>
+        <version>3.0.0.M1-SNAPSHOT</version>
+    </parent>
+    <artifactId>shardingsphere-elasticjob-ui-backend</artifactId>
+    <name>${project.artifactId}</name>
+    
+    <dependencies>
+        
+    </dependencies>
+    
+    <build>
+        <finalName>shardingsphere-elasticjob-ui</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <configuration>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                    <outputDirectory>${project.build.outputDirectory}</outputDirectory>
+                    <resources>
+                        <resource>
+                            <targetPath>${project.build.directory}/classes/public</targetPath>
+                            <directory>${project.parent.basedir}/shardingsphere-elasticjob-ui-frontend/dist</directory>
+                        </resource>
+                        <resource>
+                            <targetPath>${project.build.directory}/classes</targetPath>
+                            <directory>src/main/resources</directory>
+                        </resource>
+                    </resources>
+                </configuration>
+            </plugin>
+            
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/shardingsphere-elasticjob-ui-backend/shardingsphere-elasticjob-ui-backend-API.md b/shardingsphere-elasticjob-ui-backend/shardingsphere-elasticjob-ui-backend-API.md
new file mode 100644
index 0000000..e69de29
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/README.md b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties b/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties
new file mode 100644
index 0000000..51e047a
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties
@@ -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.
+#
+
+server.port=8088
+
+user.admin.username=admin
+user.admin.password=admin
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/resources/logback.xml b/shardingsphere-elasticjob-ui-backend/src/main/resources/logback.xml
new file mode 100644
index 0000000..51f54a4
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/resources/logback.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+  -->
+
+<configuration>
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="io.shardingsphere" level="info" additivity="false">
+        <appender-ref ref="console"/>
+    </logger>
+    
+    <root>
+        <level value="info" />
+        <appender-ref ref="console" />
+    </root>
+</configuration> 
diff --git a/shardingsphere-elasticjob-ui-distribution/pom.xml b/shardingsphere-elasticjob-ui-distribution/pom.xml
new file mode 100644
index 0000000..761d9c8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/pom.xml
@@ -0,0 +1,38 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.shardingsphere</groupId>
+        <artifactId>shardingsphere-elasticjob-ui</artifactId>
+        <version>3.0.0.M1-SNAPSHOT</version>
+    </parent>
+    <artifactId>shardingsphere-elasticjob-ui-distribution</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>pom</packaging>
+    
+    <properties>
+        <maven.deploy.skip>true</maven.deploy.skip>
+    </properties>
+    
+    <modules>
+        <module>shardingsphere-elasticjob-ui-src-distribution</module>
+        <module>shardingsphere-elasticjob-ui-bin-distribution</module>
+    </modules>
+</project>
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/Dockerfile b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/Dockerfile
new file mode 100644
index 0000000..86e410b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/Dockerfile
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+FROM java:8
+MAINTAINER ShardingSphere "dev@shardingsphere.apache.org"
+
+ARG APP_NAME
+ENV LOCAL_PATH /opt/shardingsphere-elasticjob-ui
+
+ADD target/${APP_NAME}.tar.gz /opt
+RUN mv /opt/${APP_NAME} ${LOCAL_PATH}
+
+ENTRYPOINT ${LOCAL_PATH}/bin/start.sh ${PORT} && tail -f ${LOCAL_PATH}/logs/stdout.log
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/pom.xml b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/pom.xml
new file mode 100644
index 0000000..100b94e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/pom.xml
@@ -0,0 +1,115 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.shardingsphere</groupId>
+        <artifactId>shardingsphere-elasticjob-ui-distribution</artifactId>
+        <version>3.0.0.M1-SNAPSHOT</version>
+    </parent>
+    <artifactId>shardingsphere-elasticjob-ui-bin-distribution</artifactId>
+    <name>${project.artifactId}</name>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-elasticjob-ui-backend</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>log4j-over-slf4j</artifactId>
+                    <groupId>org.slf4j</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>runtime</scope>
+            <exclusions>
+                <exclusion>
+                    <artifactId>hibernate-validator</artifactId>
+                    <groupId>org.hibernate</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+    
+    <profiles>
+        <profile>
+            <id>release</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/assembly/shardingsphere-elasticjob-ui-bin-distribution.xml</descriptor>
+                            </descriptors>
+                        </configuration>
+                        <executions>
+                            <execution>
+                                <id>shardingsphere-elasticjob-ui-bin</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>single</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>docker</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.spotify</groupId>
+                        <artifactId>dockerfile-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>shardingsphere-elasticjob-ui-bin</id>
+                                <goals>
+                                    <goal>build</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <repository>apache/shardingsphere-elasticjob-ui</repository>
+                            <tag>${project.version}</tag>
+                            <buildArgs>
+                                <APP_NAME>${project.build.finalName}-shardingsphere-elasticjob-ui-bin</APP_NAME>
+                            </buildArgs>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/assembly/shardingsphere-elasticjob-ui-bin-distribution.xml b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/assembly/shardingsphere-elasticjob-ui-bin-distribution.xml
new file mode 100644
index 0000000..d80885c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/assembly/shardingsphere-elasticjob-ui-bin-distribution.xml
@@ -0,0 +1,63 @@
+<!--
+  ~ 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.
+  -->
+
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+    <id>shardingsphere-elasticjob-ui-bin</id>
+    <formats>
+        <format>tar.gz</format>
+    </formats>
+    <includeBaseDirectory>true</includeBaseDirectory>
+    <baseDirectory>${project.build.finalName}-shardingsphere-elasticjob-ui-bin</baseDirectory>
+    
+    <fileSets>
+        <fileSet>
+            <directory>src/main/resources/bin</directory>
+            <outputDirectory>bin</outputDirectory>
+            <fileMode>0755</fileMode>
+        </fileSet>
+        <fileSet>
+            <directory>src/main/resources</directory>
+            <includes>
+                <include>application.properties</include>
+                <include>logback.xml</include>
+            </includes>
+            <outputDirectory>conf</outputDirectory>
+            <fileMode>0644</fileMode>
+        </fileSet>
+        <fileSet>
+            <directory>../../</directory>
+            <includes>
+                <include>DISCLAIMER</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>src/main/release-docs</directory>
+            <includes>
+                <include>**/*</include>
+            </includes>
+            <outputDirectory>/</outputDirectory>
+        </fileSet>
+    </fileSets>
+
+    <dependencySets>
+        <dependencySet>
+            <outputDirectory>lib</outputDirectory>
+            <fileMode>0644</fileMode>
+        </dependencySet>
+    </dependencySets>
+</assembly>
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/LICENSE b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/LICENSE
new file mode 100644
index 0000000..64cc9a9
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/LICENSE
@@ -0,0 +1,288 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=======================================================================
+Apache ShardingSphere Subcomponents:
+
+The Apache ShardingSphere project contains subcomponents with separate
+copyright notices and license terms. Your use of the source code for these
+subcomponents is subject to the terms and conditions of the following
+licenses.
+
+========================================================================
+Apache 2.0 licenses
+========================================================================
+
+The following components are provided under the Apache License. See project link for details.
+The text of each license is also included at licenses/LICENSE-[project].txt.
+
+    groovy 2.4.5-indy: https://github.com/apache/groovy, Apache 2.0
+    echarts 4.6.0: https://github.com/apache/incubator-echarts, Apache 2.0
+
+========================================================================
+Apache 2.0 licenses
+========================================================================
+
+The following components are provided under the Apache License. See project link for details.
+The text of each license is the standard Apache 2.0 license.
+
+    commons-codec 1.10: https://github.com/apache/commons-codec, Apache 2.0
+    commons-logging 1.2 https://raw.githubusercontent.com/apache/commons-logging, Apache 2.0
+    curator-client 2.10.0:  https://github.com/apache/curator,  Apache 2.0
+    curator-framework 2.10.0:  https://github.com/apache/curator,  Apache 2.0
+    curator-recipes 2.10.0:  https://github.com/apache/curator,  Apache 2.0
+    guava 18.0: https://github.com/google/guava, Apache 2.0
+    httpclient 4.5.8: https://github.com/apache/httpcomponents-client, Apache 2.0
+    httpcore 4.4.11: https://github.com/apache/httpcomponents-core, Apache 2.0
+    log4j 1.2.16: http://logging.apache.org/log4j/1.2/, Apache 2.0
+    SnakeYAML 1.16: http://www.snakeyaml.org , Apache 2.0
+    zookeeper 3.4.6: https://github.com/apache/zookeeper, Apache 2.0
+    jackson-databind 2.8.11.3: https://github.com/FasterXML/jackson-databind, Apache 2.0
+    jackson-annotations 2.8.0: https://github.com/FasterXML/jackson-annotations, Apache 2.0
+    jackson-core 2.8.10: https://github.com/FasterXML/jackson-core, Apache 2.0
+    spring-boot 1.5.21.RELEASE: https://raw.githubusercontent.com/spring-projects/spring-boot, Apache 2.0
+    spring-framework 4.3.24.RELEASE: https://raw.githubusercontent.com/spring-projects/spring-framework, Apache 2.0
+    tomcat 8.5.40: http://svn.apache.org/repos/asf/tomcat, Apache 2.0
+    gson 2.8.5: https://github.com/google/gson, Apache 2.0
+
+========================================================================
+BSD licenses
+========================================================================
+
+The following components are provided under a BSD license. See project link for details.
+The text of each license is also included at licenses/LICENSE-[project].txt.
+
+    jline 0.9.94: https://github.com/jline/jline1, BSD-3-Clause
+
+========================================================================
+EPL licenses
+========================================================================
+
+The following components are provided under the EPL License. See project link for details.
+The text of each license is also included at licenses/LICENSE-[project].txt.
+
+    logback-classic 1.2.0: https://github.com/qos-ch/logback: EPL 1.0
+    logback-core 1.2.0: https://github.com/qos-ch/logback: EPL 1.0
+
+========================================================================
+MIT licenses
+========================================================================
+
+The following components are provided under the MIT License. See project link for details.
+The text of each license is also included at licenses/LICENSE-[project].txt.
+
+   jcl-over-slf4j 1.7.7: https://www.slf4j.org, MIT
+   slf4j 1.7.7: https://www.slf4j.org, MIT
+   jul-to-slf4j 1.7.26: https://www.slf4j.org, MIT
+
+   axios 0.18.0: https://github.com/axios/axios, MIT
+   element-ui 2.4.9: https://github.com/ElemeFE/element, MIT
+   js-yaml 3.12.0: https://github.com/nodeca/js-yaml, MIT
+   lodash 4.17.11: https://github.com/lodash/lodash, MIT
+   normalize.css 8.0.1: https://github.com/necolas/normalize.css, MIT
+   vue 2.5.2: https://github.com/vuejs/vue, MIT
+   vue-i18n 8.4.0: https://github.com/kazupon/vue-i18n, MIT
+   vue-router 3.0.1: https://github.com/vuejs/vue-router, MIT
+   vuex 3.0.1: https://github.com/vuejs/vuex, MIT
+   resize-detector 0.2.1: https://github.com/Justineo/resize-detector, MIT
+   echarts-liquidfill 2.0.5: https://github.com/ecomfe/echarts-liquidfill, MIT
+   moment 2.24.0: https://github.com/moment/moment, MIT
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/NOTICE b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/NOTICE
new file mode 100644
index 0000000..57a297f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/NOTICE
@@ -0,0 +1,219 @@
+Apache ShardingSphere
+Copyright 2018-2020 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+========================================================================
+
+Apache Curator NOTICE
+
+========================================================================
+
+Apache Curator
+Copyright 2013-2014 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+========================================================================
+
+Apache log4j NOTICE
+
+========================================================================
+
+Apache log4j
+Copyright 2010 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+========================================================================
+
+Apache ZooKeeper NOTICE
+
+========================================================================
+
+Apache ZooKeeper
+Copyright 2009-2014 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product includes software components originally
+developed for Airlift (https://github.com/airlift/airlift),
+licensed under the Apache 2.0 license. The licensing terms
+for Airlift code can be found at:
+https://github.com/airlift/airlift/blob/master/LICENSE
+
+========================================================================
+
+Apache Commons Codec NOTICE
+
+========================================================================
+
+Apache Commons Codec
+Copyright 2002-2019 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (https://www.apache.org/).
+
+src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java
+contains test data from http://aspell.net/test/orig/batch0.tab.
+Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org)
+
+===============================================================================
+
+The content of package org.apache.commons.codec.language.bm has been translated
+from the original php source code available at http://stevemorse.org/phoneticinfo.htm
+with permission from the original authors.
+Original source copyright:
+Copyright (c) 2008 Alexander Beider & Stephen P. Morse.
+
+========================================================================
+
+Apache HttpComponents Client NOTICE
+
+========================================================================
+
+Apache HttpComponents Client
+Copyright 1999-2020 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+========================================================================
+
+Apache HttpComponents Core NOTICE
+
+========================================================================
+
+Apache HttpComponents Core
+Copyright 2005-2020 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+========================================================================
+
+Apache Commons Logging NOTICE
+
+========================================================================
+
+Apache Commons Logging
+Copyright 2003-2016 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+========================================================================
+
+Apache Tomcat NOTICE
+
+========================================================================
+
+Apache Tomcat
+Copyright 1999-2019 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (https://www.apache.org/).
+
+This software contains code derived from netty-native
+developed by the Netty project
+(https://netty.io, https://github.com/netty/netty-tcnative/)
+and from finagle-native developed at Twitter
+(https://github.com/twitter/finagle).
+
+This software contains code derived from jgroups-kubernetes
+developed by the JGroups project (http://www.jgroups.org/).
+
+The Windows Installer is built with the Nullsoft
+Scriptable Install System (NSIS), which is
+open source software.  The original software and
+related information is available at
+http://nsis.sourceforge.net.
+
+Java compilation software for JSP pages is provided by the Eclipse
+JDT Core Batch Compiler component, which is open source software.
+The original software and related information is available at
+https://www.eclipse.org/jdt/core/.
+
+org.apache.tomcat.util.json.JSONParser.jj is a public domain javacc grammar
+for JSON written by Robert Fischer.
+https://github.com/RobertFischer/json-parser
+
+For portions of the Tomcat JNI OpenSSL API and the OpenSSL JSSE integration
+The org.apache.tomcat.jni and the org.apache.tomcat.net.openssl packages
+are derivative work originating from the Netty project and the finagle-native
+project developed at Twitter
+* Copyright 2014 The Netty Project
+* Copyright 2014 Twitter
+
+For portions of the Tomcat cloud support
+The org.apache.catalina.tribes.membership.cloud package contains derivative
+work originating from the jgroups project.
+https://github.com/jgroups-extras/jgroups-kubernetes
+Copyright 2002-2018 Red Hat Inc.
+
+The original XML Schemas for Java EE Deployment Descriptors:
+ - javaee_5.xsd
+ - javaee_web_services_1_2.xsd
+ - javaee_web_services_client_1_2.xsd
+ - javaee_6.xsd
+ - javaee_web_services_1_3.xsd
+ - javaee_web_services_client_1_3.xsd
+ - jsp_2_2.xsd
+ - web-app_3_0.xsd
+ - web-common_3_0.xsd
+ - web-fragment_3_0.xsd
+ - javaee_7.xsd
+ - javaee_web_services_1_4.xsd
+ - javaee_web_services_client_1_4.xsd
+ - jsp_2_3.xsd
+ - web-app_3_1.xsd
+ - web-common_3_1.xsd
+ - web-fragment_3_1.xsd
+ - javaee_8.xsd
+ - web-app_4_0.xsd
+ - web-common_4_0.xsd
+ - web-fragment_4_0.xsd
+
+may be obtained from:
+http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/index.html
+
+
+This product contains the Maven wrapper scripts from 'Maven Wrapper', that provides an easy way to ensure a user has everything necessary to run the Maven build.
+
+  * LICENSE:
+    * license/LICENSE.mvn-wrapper.txt (Apache License 2.0)
+  * HOMEPAGE:
+    * https://github.com/takari/maven-wrapper
+
+========================================================================
+
+Apache groovy NOTICE
+
+========================================================================
+
+Apache Groovy
+Copyright 2003-2018 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product bundles icons from the famfamfam.com silk icons set
+http://www.famfamfam.com/lab/icons/silk/
+Licensed under the Creative Commons Attribution Licence v2.5
+http://creativecommons.org/licenses/by/2.5/
+
+========================================================================
+
+Apache ECharts (incubating) NOTICE
+
+========================================================================
+
+Apache ECharts (incubating)
+Copyright 2017-2020 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-axios b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-axios
new file mode 100644
index 0000000..2d8d66a
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-axios
@@ -0,0 +1,19 @@
+Copyright (c) 2014-present Matt Zabriskie
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-echarts-liquidfill b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-echarts-liquidfill
new file mode 100644
index 0000000..c008c53
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-echarts-liquidfill
@@ -0,0 +1,7 @@
+Copyright 2019 Ovilia
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-element-ui b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-element-ui
new file mode 100644
index 0000000..d4462f3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-element-ui
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016-present ElemeFE
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-groovy.txt b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-groovy.txt
new file mode 100644
index 0000000..586a54e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-groovy.txt
@@ -0,0 +1,217 @@
+Apache Groovy License
+---------------
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+------------------------------------------------------------------------
+
+ANTLR 2 License
+
+Antlr2 is released in the public domain.
+See licenses/antlr2-license.txt for details.
+
+------------------------------------------------------------------------
+
+ASM 4 License
+
+ASM 4 uses a 3-clause BSD license. For details, see licenses/asm-license.txt.
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-incubator-echarts b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-incubator-echarts
new file mode 100644
index 0000000..1f1111a
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-incubator-echarts
@@ -0,0 +1,223 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+
+
+========================================================================
+Apache ECharts Subcomponents:
+
+The Apache ECharts project contains subcomponents with separate copyright
+notices and license terms. Your use of the source code for these
+subcomponents is also subject to the terms and conditions of the following
+licenses.
+
+BSD 3-Clause (d3.js):
+The following files embed [d3.js](https://github.com/d3/d3) BSD 3-Clause:
+    `/src/chart/treemap/treemapLayout.js`,
+    `/src/chart/tree/layoutHelper.js`,
+    `/src/chart/graph/forceHelper.js`,
+    `/src/util/number.js`,
+    `/src/scale/Time.js`,
+See `/licenses/LICENSE-d3` for details of the license.
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jcl-over-slf4j.txt b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jcl-over-slf4j.txt
new file mode 100644
index 0000000..075d57e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jcl-over-slf4j.txt
@@ -0,0 +1,24 @@
+jcl-over-slf4j License
+---------------
+
+Copyright (c) 2004-2017 QOS.ch
+ All rights reserved.
+
+ Permission is hereby granted, free  of charge, to any person obtaining
+ a  copy  of this  software  and  associated  documentation files  (the
+ "Software"), to  deal in  the Software without  restriction, including
+ without limitation  the rights to  use, copy, modify,  merge, publish,
+ distribute,  sublicense, and/or sell  copies of  the Software,  and to
+ permit persons to whom the Software  is furnished to do so, subject to
+ the following conditions:
+ 
+ The  above  copyright  notice  and  this permission  notice  shall  be
+ included in all copies or substantial portions of the Software.
+ 
+ THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+ EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+ MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jline.txt b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jline.txt
new file mode 100644
index 0000000..c04e96f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jline.txt
@@ -0,0 +1,37 @@
+jline license
+---------------
+
+Copyright (c) 2002-2017, the original author or authors.
+All rights reserved.
+
+http://www.opensource.org/licenses/bsd-license.php
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following
+conditions are met:
+
+Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with
+the distribution.
+
+Neither the name of JLine nor the names of its contributors
+may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-js-yaml b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-js-yaml
new file mode 100644
index 0000000..965fe3e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-js-yaml
@@ -0,0 +1,21 @@
+(The MIT License)
+
+Copyright (C) 2011-2015 by Vitaly Puzrin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jul-to-slf4j.txt b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jul-to-slf4j.txt
new file mode 100644
index 0000000..49bfdb9
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-jul-to-slf4j.txt
@@ -0,0 +1,24 @@
+jul-to-slf4j License
+---------------
+
+Copyright (c) 2004-2017 QOS.ch
+ All rights reserved.
+
+ Permission is hereby granted, free  of charge, to any person obtaining
+ a  copy  of this  software  and  associated  documentation files  (the
+ "Software"), to  deal in  the Software without  restriction, including
+ without limitation  the rights to  use, copy, modify,  merge, publish,
+ distribute,  sublicense, and/or sell  copies of  the Software,  and to
+ permit persons to whom the Software  is furnished to do so, subject to
+ the following conditions:
+ 
+ The  above  copyright  notice  and  this permission  notice  shall  be
+ included in all copies or substantial portions of the Software.
+ 
+ THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+ EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+ MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-lodash b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-lodash
new file mode 100644
index 0000000..5b80741
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-lodash
@@ -0,0 +1,49 @@
+The MIT License
+
+Copyright JS Foundation and other contributors <https://js.foundation/>
+
+Based on Underscore.js, copyright Jeremy Ashkenas,
+DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+available at https://github.com/lodash/lodash
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+Copyright and related rights for sample code are waived via CC0. Sample
+code is defined as all source code displayed within the prose of the
+documentation.
+
+CC0: http://creativecommons.org/publicdomain/zero/1.0/
+
+====
+
+Files located in the node_modules and vendor directories are externally
+maintained libraries used by this software which have their own
+licenses; we recommend you read them, as their terms may differ from the
+terms above.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-logback.txt b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-logback.txt
new file mode 100644
index 0000000..1a6915c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-logback.txt
@@ -0,0 +1,14 @@
+Logback License
+---------------
+
+Logback: the reliable, generic, fast and flexible logging framework.
+Copyright (C) 1999-2015, QOS.ch. All rights reserved.
+
+This program and the accompanying materials are dual-licensed under
+either the terms of the Eclipse Public License v1.0 as published by
+the Eclipse Foundation
+
+  or (per the licensee's choosing)
+
+under the terms of the GNU Lesser General Public License version 2.1
+as published by the Free Software Foundation.
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-moment b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-moment
new file mode 100644
index 0000000..96ad692
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-moment
@@ -0,0 +1,22 @@
+Copyright (c) JS Foundation and other contributors
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-normalize b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-normalize
new file mode 100644
index 0000000..9433637
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-normalize
@@ -0,0 +1,21 @@
+# The MIT License (MIT)
+
+Copyright © Nicolas Gallagher and Jonathan Neal
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-resize-detector b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-resize-detector
new file mode 100644
index 0000000..8492f95
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-resize-detector
@@ -0,0 +1,43 @@
+MIT License
+
+Copyright (c) 2018-present, GU Yiling.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+The MIT License (MIT)
+
+Copyright (c) 2013 Sebastián Décima
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-slf4j.txt b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-slf4j.txt
new file mode 100644
index 0000000..ee59090
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-slf4j.txt
@@ -0,0 +1,24 @@
+SLF4J License
+---------------
+
+Copyright (c) 2004-2017 QOS.ch
+ All rights reserved.
+
+ Permission is hereby granted, free  of charge, to any person obtaining
+ a  copy  of this  software  and  associated  documentation files  (the
+ "Software"), to  deal in  the Software without  restriction, including
+ without limitation  the rights to  use, copy, modify,  merge, publish,
+ distribute,  sublicense, and/or sell  copies of  the Software,  and to
+ permit persons to whom the Software  is furnished to do so, subject to
+ the following conditions:
+ 
+ The  above  copyright  notice  and  this permission  notice  shall  be
+ included in all copies or substantial portions of the Software.
+ 
+ THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
+ EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
+ MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue
new file mode 100644
index 0000000..51e3f9f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-present, Yuxi (Evan) You
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue-i18n b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue-i18n
new file mode 100644
index 0000000..e28fb1a
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue-i18n
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 kazuya kawaguchi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue-router b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue-router
new file mode 100644
index 0000000..bbfcc77
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vue-router
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2013-2016 Evan You
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vuex b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vuex
new file mode 100644
index 0000000..fa6dd9b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/release-docs/licenses/LICENSE-vuex
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-2016 Evan You
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/application.properties b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/application.properties
new file mode 100644
index 0000000..66a405f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/application.properties
@@ -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.
+#
+
+server.port=8089
+
+user.admin.username=admin
+user.admin.password=admin
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/start.bat b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/start.bat
new file mode 100644
index 0000000..20d4e79
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/start.bat
@@ -0,0 +1,34 @@
+@rem
+@rem Licensed to the Apache Software Foundation (ASF) under one or more
+@rem contributor license agreements.  See the NOTICE file distributed with
+@rem this work for additional information regarding copyright ownership.
+@rem The ASF licenses this file to You under the Apache License, Version 2.0
+@rem (the "License"); you may not use this file except in compliance with
+@rem the License.  You may obtain a copy of the License at
+@rem
+@rem     http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@echo off & setlocal enabledelayedexpansion
+
+cd %~dp0
+
+set SERVER_NAME=ShardingSphere-ElasticJob-UI
+
+set CLASS_PATH=".;..\conf;..\lib\*"
+
+set JAVA_OPTS=-server -Xmx1g -Xms1g -Xmn512m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70
+
+set MAIN_CLASS=org.apache.shardingsphere.elasticjob.ui.Bootstrap
+
+echo Starting the %SERVER_NAME% ...
+
+java %JAVA_OPTS% -Dfile.encoding=UTF-8 -classpath %CLASS_PATH% %MAIN_CLASS%
+
+pause
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/start.sh b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/start.sh
new file mode 100644
index 0000000..829c488
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/start.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# 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.
+#
+
+SERVER_NAME=ShardingSphere-ElasticJob-UI
+
+cd `dirname $0`
+cd ..
+DEPLOY_DIR=`pwd`
+
+LOGS_DIR=${DEPLOY_DIR}/logs
+if [ ! -d ${LOGS_DIR} ]; then
+    mkdir ${LOGS_DIR}
+fi
+
+STDOUT_FILE=${LOGS_DIR}/stdout.log
+
+PIDS=`ps -ef | grep java | grep "$DEPLOY_DIR" | grep -v grep | awk '{print $2}'`
+if [ -n "$PIDS" ]; then
+    echo "ERROR: The $SERVER_NAME already started!"
+    echo "PID: $PIDS"
+    exit 1
+fi
+
+CLASS_PATH=.:${DEPLOY_DIR}/conf:${DEPLOY_DIR}/lib/*
+JAVA_OPTS=" -server -Xmx1g -Xms1g -Xmn512m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
+
+MAIN_CLASS=org.apache.shardingsphere.elasticjob.ui.Bootstrap
+echo "Starting the $SERVER_NAME ..."
+
+nohup java ${JAVA_OPTS} -classpath ${CLASS_PATH} ${MAIN_CLASS} > ${STDOUT_FILE} 2>&1 &
+sleep 1
+echo "Please check the STDOUT file: $STDOUT_FILE"
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/stop.sh b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/stop.sh
new file mode 100644
index 0000000..eb9406d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/bin/stop.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# 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.
+#
+
+SERVER_NAME=ShardingSphere-ElasticJob-UI
+
+cd `dirname $0`
+cd ..
+DEPLOY_DIR=`pwd`
+
+PIDS=`ps -ef | grep java | grep "$DEPLOY_DIR" | grep -v grep |awk '{print $2}'`
+if [ -z "$PIDS" ]; then
+    echo "ERROR: The $SERVER_NAME does not started!"
+    exit 1
+fi
+
+echo -e "Stopping the $SERVER_NAME ...\c"
+for PID in ${PIDS} ; do
+    kill ${PID} > /dev/null 2>&1
+done
+
+COUNT=0
+while [ ${COUNT} -lt 1 ]; do
+    echo -e ".\c"
+    sleep 1
+    COUNT=1
+    for PID in ${PIDS} ; do
+        PID_EXIST=`ps -f -p ${PID} | grep java`
+        if [ -n "$PID_EXIST" ]; then
+            COUNT=0
+            break
+        fi
+    done
+done
+
+echo "OK!"
+echo "PID: $PIDS"
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/logback.xml b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/logback.xml
new file mode 100644
index 0000000..51f54a4
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-bin-distribution/src/main/resources/logback.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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.
+  -->
+
+<configuration>
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+    <logger name="io.shardingsphere" level="info" additivity="false">
+        <appender-ref ref="console"/>
+    </logger>
+    
+    <root>
+        <level value="info" />
+        <appender-ref ref="console" />
+    </root>
+</configuration> 
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-src-distribution/pom.xml b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-src-distribution/pom.xml
new file mode 100644
index 0000000..e798017
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-src-distribution/pom.xml
@@ -0,0 +1,70 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.shardingsphere</groupId>
+        <artifactId>shardingsphere-elasticjob-ui-distribution</artifactId>
+        <version>3.0.0.M1-SNAPSHOT</version>
+    </parent>
+    <artifactId>shardingsphere-elasticjob-ui-src-distribution</artifactId>
+    <name>${project.artifactId}</name>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-elasticjob-ui-frontend</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-elasticjob-ui-backend</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+    
+    <profiles>
+        <profile>
+            <id>release</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>shardingsphere-elasticjob-ui-src</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>single</goal>
+                                </goals>
+                                <configuration>
+                                    <descriptors>
+                                        <descriptor>src/main/assembly/shardingsphere-elasticjob-ui-src-distribution.xml</descriptor>
+                                    </descriptors>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-src-distribution/src/main/assembly/shardingsphere-elasticjob-ui-src-distribution.xml b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-src-distribution/src/main/assembly/shardingsphere-elasticjob-ui-src-distribution.xml
new file mode 100644
index 0000000..6e7ea84
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-ui-src-distribution/src/main/assembly/shardingsphere-elasticjob-ui-src-distribution.xml
@@ -0,0 +1,87 @@
+<!--
+  ~ 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.
+  -->
+
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+    <id>shardingsphere-elasticjob-ui-src</id>
+    <formats>
+        <format>zip</format>
+    </formats>
+    <includeBaseDirectory>true</includeBaseDirectory>
+    <baseDirectory>${project.build.finalName}-shardingsphere-elasticjob-ui-src</baseDirectory>
+    
+    <fileSets>
+        <fileSet>
+            <directory>../../</directory>
+            <useDefaultExcludes>true</useDefaultExcludes>
+            <includes>
+                <include>**/*</include>
+            </includes>
+            <excludes>
+                <!-- github ignore -->
+                <exclude>**/.github/**</exclude>
+                <exclude>.travis.yml</exclude>
+                
+                <!-- maven ignore -->
+                <exclude>**/target/**</exclude>
+                <exclude>**/*.class</exclude>
+                <exclude>**/*.jar</exclude>
+                <exclude>**/*.war</exclude>
+                <exclude>**/*.zip</exclude>
+                <exclude>**/*.tar</exclude>
+                <exclude>**/*.tar.gz</exclude>
+                
+                <!-- maven plugin ignore -->
+                <exclude>release.properties</exclude>
+                <exclude>**/pom.xml.releaseBackup</exclude>
+                <exclude>**/cobertura.ser</exclude>
+                <exclude>*.gpg</exclude>
+                
+                <!-- node ignore -->
+                <exclude>**/shardingsphere-elasticjob-ui-frontend/test/coverage/**</exclude>
+                <exclude>**/shardingsphere-elasticjob-ui-frontend/dist/**</exclude>
+                <exclude>**/shardingsphere-elasticjob-ui-frontend/node/**</exclude>
+                <exclude>**/shardingsphere-elasticjob-ui-frontend/node_modules/**</exclude>
+                <exclude>**/shardingsphere-elasticjob-ui-frontend/etc/**</exclude>
+                
+                <!-- eclipse ignore -->
+                <exclude>**/.settings/**</exclude>
+                <exclude>**/.project</exclude>
+                <exclude>**/.classpath</exclude>
+                
+                <!-- idea ignore -->
+                <exclude>**/.idea/**</exclude>
+                <exclude>**/*.ipr</exclude>
+                <exclude>**/*.iml</exclude>
+                <exclude>**/*.iws</exclude>
+                
+                <!-- temp ignore -->
+                <exclude>**/logs/**</exclude>
+                <exclude>**/*.log</exclude>
+                <exclude>**/*.doc</exclude>
+                <exclude>**/*.cache</exclude>
+                <exclude>**/*.diff</exclude>
+                <exclude>**/*.patch</exclude>
+                <exclude>**/*.tmp</exclude>
+                
+                <!-- system ignore -->
+                <exclude>**/.DS_Store</exclude>
+                <exclude>**/Thumbs.db</exclude>
+            </excludes>
+        </fileSet>
+    </fileSets>
+</assembly>
diff --git a/shardingsphere-elasticjob-ui-frontend/.babelrc b/shardingsphere-elasticjob-ui-frontend/.babelrc
new file mode 100644
index 0000000..f261300
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/.babelrc
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+{
+  "presets": [
+    "@babel/preset-env"
+  ],
+  "plugins": ["transform-vue-jsx", "@babel/plugin-transform-runtime", "@babel/plugin-syntax-dynamic-import"],
+  "env": {
+    "test": {
+      "plugins": ["istanbul"]
+    }
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/.editorconfig b/shardingsphere-elasticjob-ui-frontend/.editorconfig
new file mode 100644
index 0000000..9d08a1a
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
diff --git a/shardingsphere-elasticjob-ui-frontend/.eslintignore b/shardingsphere-elasticjob-ui-frontend/.eslintignore
new file mode 100644
index 0000000..e1fcc9c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/.eslintignore
@@ -0,0 +1,4 @@
+/build/
+/config/
+/dist/
+/*.js
diff --git a/shardingsphere-elasticjob-ui-frontend/.eslintrc.js b/shardingsphere-elasticjob-ui-frontend/.eslintrc.js
new file mode 100644
index 0000000..4295c7f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/.eslintrc.js
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+
+module.exports = {
+  root: true,
+  parserOptions: {
+    parser: 'babel-eslint',
+    sourceType: 'module'
+  },
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  extends: ['plugin:vue/recommended', 'eslint:recommended'],
+
+  // add your custom rules here
+  //it is base on https://github.com/vuejs/eslint-config-vue
+  rules: {
+    "vue/max-attributes-per-line": [2, {
+      "singleline": 10,
+      "multiline": {
+        "max": 1,
+        "allowFirstLine": false
+      }
+    }],
+    "vue/html-self-closing": ["error", {
+      "html": {
+        "void": "any",
+        "normal": "any",
+        "component": "any"
+      },
+      "svg": "any",
+      "math": "any"
+    }],
+    "vue/name-property-casing": ["error", "PascalCase"],
+    'accessor-pairs': 2,
+    'arrow-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'block-spacing': [2, 'always'],
+    'brace-style': [2, '1tbs', {
+      'allowSingleLine': true
+    }],
+    'camelcase': [0, {
+      'properties': 'always'
+    }],
+    'comma-dangle': [2, 'never'],
+    'comma-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'comma-style': [2, 'last'],
+    'constructor-super': 2,
+    'curly': [2, 'multi-line'],
+    'dot-location': [2, 'property'],
+    'eol-last': 0,
+    'eqeqeq': [2, 'allow-null'],
+    'generator-star-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'handle-callback-err': [2, '^(err|error)$'],
+    'indent': [2, 2, {
+      'SwitchCase': 1
+    }],
+    'jsx-quotes': [2, 'prefer-single'],
+    'key-spacing': [2, {
+      'beforeColon': false,
+      'afterColon': true
+    }],
+    'keyword-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'new-cap': [2, {
+      'newIsCap': true,
+      'capIsNew': false
+    }],
+    'new-parens': 2,
+    'no-array-constructor': 2,
+    'no-caller': 2,
+    'no-console': 'off',
+    'no-class-assign': 2,
+    'no-cond-assign': 2,
+    'no-const-assign': 2,
+    'no-control-regex': 2,
+    'no-delete-var': 2,
+    'no-dupe-args': 2,
+    'no-dupe-class-members': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty-character-class': 2,
+    'no-empty-pattern': 2,
+    'no-eval': 2,
+    'no-ex-assign': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': [2, 'functions'],
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-func-assign': 2,
+    'no-implied-eval': 2,
+    'no-inner-declarations': [2, 'functions'],
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-iterator': 2,
+    'no-label-var': 2,
+    'no-labels': [2, {
+      'allowLoop': false,
+      'allowSwitch': false
+    }],
+    'no-lone-blocks': 2,
+    'no-mixed-spaces-and-tabs': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-multiple-empty-lines': [2, {
+      'max': 1
+    }],
+    'no-native-reassign': 2,
+    'no-negated-in-lhs': 2,
+    'no-new-object': 2,
+    'no-new-require': 2,
+    'no-new-symbol': 2,
+    'no-new-wrappers': 2,
+    'no-obj-calls': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-path-concat': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-regex-spaces': 2,
+    'no-return-assign': [2, 'except-parens'],
+    'no-self-assign': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-shadow-restricted-names': 2,
+    'no-spaced-func': 2,
+    'no-sparse-arrays': 2,
+    'no-this-before-super': 2,
+    'no-throw-literal': 2,
+    'no-trailing-spaces': 2,
+    'no-undef': 2,
+    'no-undef-init': 2,
+    'no-unexpected-multiline': 2,
+    'no-unmodified-loop-condition': 2,
+    'no-unneeded-ternary': [2, {
+      'defaultAssignment': false
+    }],
+    'no-unreachable': 2,
+    'no-unsafe-finally': 2,
+    'no-unused-vars': [2, {
+      'vars': 'all',
+      'args': 'none'
+    }],
+    'no-useless-call': 2,
+    'no-useless-computed-key': 2,
+    'no-useless-constructor': 2,
+    'no-useless-escape': 0,
+    'no-whitespace-before-property': 2,
+    'no-with': 2,
+    'one-var': [2, {
+      'initialized': 'never'
+    }],
+    'operator-linebreak': [2, 'after', {
+      'overrides': {
+        '?': 'before',
+        ':': 'before'
+      }
+    }],
+    'padded-blocks': [2, 'never'],
+    'quotes': [2, 'single', {
+      'avoidEscape': true,
+      'allowTemplateLiterals': true
+    }],
+    'semi': [2, 'never'],
+    'semi-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'space-before-blocks': [2, 'always'],
+    'space-before-function-paren': [2, 'never'],
+    'space-in-parens': [2, 'never'],
+    'space-infix-ops': 2,
+    'space-unary-ops': [2, {
+      'words': true,
+      'nonwords': false
+    }],
+    'spaced-comment': [2, 'always', {
+      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+    }],
+    'template-curly-spacing': [2, 'never'],
+    'use-isnan': 2,
+    'valid-typeof': 2,
+    'wrap-iife': [2, 'any'],
+    'yield-star-spacing': [2, 'both'],
+    'yoda': [2, 'never'],
+    'prefer-const': 2,
+    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never']
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/.gitignore b/shardingsphere-elasticjob-ui-frontend/.gitignore
new file mode 100644
index 0000000..414c011
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/.gitignore
@@ -0,0 +1,18 @@
+.DS_Store
+node_modules/
+node/
+/dist/
+/test/coverage/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+package-lock.json
+
+# Editor directories and files
+.prettierrc
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
diff --git a/shardingsphere-elasticjob-ui-frontend/.postcssrc.js b/shardingsphere-elasticjob-ui-frontend/.postcssrc.js
new file mode 100644
index 0000000..dc9c58f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/.postcssrc.js
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+// https://github.com/michael-ciniawsky/postcss-load-config
+
+module.exports = {
+  "plugins": {
+    "postcss-import": {},
+    "postcss-url": {},
+    // to edit target browsers: use "browserslist" field in package.json
+    "autoprefixer": {}
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/README.md b/shardingsphere-elasticjob-ui-frontend/README.md
new file mode 100644
index 0000000..0767dcb
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/README.md
@@ -0,0 +1,24 @@
+# ShardingSphere ElasticJob UI Frontend
+
+## How to Build
+
+```bash
+# install dependencies
+npm install
+
+# serve with hot reload at localhost:8080
+npm run dev
+
+# build for production with minification
+npm run build
+
+# build for production and view the bundle analyzer report
+npm run build --report
+```
+
+## How to Run unit tests
+
+```bash
+# Karma does unit testing for components and pages
+npm run unit
+```
diff --git a/shardingsphere-elasticjob-ui-frontend/README_ZH.md b/shardingsphere-elasticjob-ui-frontend/README_ZH.md
new file mode 100644
index 0000000..25f8c96
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/README_ZH.md
@@ -0,0 +1,24 @@
+# ShardingSphere ElasticJob UI 前端
+
+## 如何构建
+
+```bash
+# install dependencies
+npm install
+
+# serve with hot reload at localhost:8080
+npm run dev
+
+# build for production with minification
+npm run build
+
+# build for production and view the bundle analyzer report
+npm run build --report
+```
+
+## 如何运行单元测试
+
+```bash
+# Karma does unit testing for components and pages
+npm run unit
+```
diff --git a/shardingsphere-elasticjob-ui-frontend/build/build.js b/shardingsphere-elasticjob-ui-frontend/build/build.js
new file mode 100644
index 0000000..b6d0ada
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/build.js
@@ -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.
+ */
+
+'use strict'
+require('./check-versions')()
+
+process.env.NODE_ENV = 'production'
+
+const ora = require('ora')
+const rm = require('rimraf')
+const path = require('path')
+const chalk = require('chalk')
+const webpack = require('webpack')
+const config = require('../config')
+const webpackConfig = require('./webpack.prod.conf')
+
+const spinner = ora('building for production...')
+spinner.start()
+
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
+  if (err) throw err
+  webpack(webpackConfig, (err, stats) => {
+    spinner.stop()
+    if (err) throw err
+    process.stdout.write(stats.toString({
+      colors: true,
+      modules: false,
+      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
+      chunks: false,
+      chunkModules: false
+    }) + '\n\n')
+
+    if (stats.hasErrors()) {
+      console.log(chalk.red('  Build failed with errors.\n'))
+      process.exit(1)
+    }
+
+    console.log(chalk.cyan('  Build complete.\n'))
+    console.log(chalk.yellow(
+      '  Tip: built files are meant to be served over an HTTP server.\n' +
+      '  Opening index.html over file:// won\'t work.\n'
+    ))
+  })
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/build/check-versions.js b/shardingsphere-elasticjob-ui-frontend/build/check-versions.js
new file mode 100644
index 0000000..b07e6e8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/check-versions.js
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+'use strict'
+const chalk = require('chalk')
+const semver = require('semver')
+const packageConfig = require('../package.json')
+const shell = require('shelljs')
+
+function exec (cmd) {
+  return require('child_process').execSync(cmd).toString().trim()
+}
+
+const versionRequirements = [
+  {
+    name: 'node',
+    currentVersion: semver.clean(process.version),
+    versionRequirement: packageConfig.engines.node
+  }
+]
+
+if (shell.which('npm')) {
+  versionRequirements.push({
+    name: 'npm',
+    currentVersion: exec('npm --version'),
+    versionRequirement: packageConfig.engines.npm
+  })
+}
+
+module.exports = function () {
+  const warnings = []
+
+  for (let i = 0; i < versionRequirements.length; i++) {
+    const mod = versionRequirements[i]
+
+    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
+      warnings.push(mod.name + ': ' +
+        chalk.red(mod.currentVersion) + ' should be ' +
+        chalk.green(mod.versionRequirement)
+      )
+    }
+  }
+
+  if (warnings.length) {
+    console.log('')
+    console.log(chalk.yellow('To use this template, you must update following to modules:'))
+    console.log()
+
+    for (let i = 0; i < warnings.length; i++) {
+      const warning = warnings[i]
+      console.log('  ' + warning)
+    }
+
+    console.log()
+    process.exit(1)
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/build/rimraf.js b/shardingsphere-elasticjob-ui-frontend/build/rimraf.js
new file mode 100644
index 0000000..62ee932
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/rimraf.js
@@ -0,0 +1,404 @@
+/*
+ * 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 assert = require("assert")
+const path = require("path")
+const fs = require("fs")
+let glob = undefined
+try {
+  glob = require("glob")
+} catch (_err) {
+  // treat glob as optional.
+}
+
+const defaultGlobOpts = {
+  nosort: true,
+  silent: true
+}
+
+// for EMFILE handling
+let timeout = 0
+
+const isWindows = (process.platform === "win32")
+
+const defaults = options => {
+  const methods = [
+    'unlink',
+    'chmod',
+    'stat',
+    'lstat',
+    'rmdir',
+    'readdir'
+  ]
+  methods.forEach(m => {
+    options[m] = options[m] || fs[m]
+    m = m + 'Sync'
+    options[m] = options[m] || fs[m]
+  })
+
+  options.maxBusyTries = options.maxBusyTries || 3
+  options.emfileWait = options.emfileWait || 1000
+  if (options.glob === false) {
+    options.disableGlob = true
+  }
+  if (options.disableGlob !== true && glob === undefined) {
+    throw Error('glob dependency not found, set `options.disableGlob = true` if intentional')
+  }
+  options.disableGlob = options.disableGlob || false
+  options.glob = options.glob || defaultGlobOpts
+}
+
+const rimraf = (p, options, cb) => {
+  if (typeof options === 'function') {
+    cb = options
+    options = {}
+  }
+
+  assert(p, 'rimraf: missing path')
+  assert.equal(typeof p, 'string', 'rimraf: path should be a string')
+  assert.equal(typeof cb, 'function', 'rimraf: callback function required')
+  assert(options, 'rimraf: invalid options argument provided')
+  assert.equal(typeof options, 'object', 'rimraf: options should be object')
+
+  defaults(options)
+
+  let busyTries = 0
+  let errState = null
+  let n = 0
+
+  const next = (er) => {
+    errState = errState || er
+    if (--n === 0)
+      cb(errState)
+  }
+
+  const afterGlob = (er, results) => {
+    if (er)
+      return cb(er)
+
+    n = results.length
+    if (n === 0)
+      return cb()
+
+    results.forEach(p => {
+      const CB = (er) => {
+        if (er) {
+          if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") &&
+              busyTries < options.maxBusyTries) {
+            busyTries ++
+            // try again, with the same exact callback as this one.
+            return setTimeout(() => rimraf_(p, options, CB), busyTries * 100)
+          }
+
+          // this one won't happen if graceful-fs is used.
+          if (er.code === "EMFILE" && timeout < options.emfileWait) {
+            return setTimeout(() => rimraf_(p, options, CB), timeout ++)
+          }
+
+          // already gone
+          if (er.code === "ENOENT") er = null
+        }
+
+        timeout = 0
+        next(er)
+      }
+      rimraf_(p, options, CB)
+    })
+  }
+
+  if (options.disableGlob || !glob.hasMagic(p))
+    return afterGlob(null, [p])
+
+  options.lstat(p, (er, stat) => {
+    if (!er)
+      return afterGlob(null, [p])
+
+    glob(p, options.glob, afterGlob)
+  })
+
+}
+
+// Two possible strategies.
+// 1. Assume it's a file.  unlink it, then do the dir stuff on EPERM or EISDIR
+// 2. Assume it's a directory.  readdir, then do the file stuff on ENOTDIR
+//
+// Both result in an extra syscall when you guess wrong.  However, there
+// are likely far more normal files in the world than directories.  This
+// is based on the assumption that a the average number of files per
+// directory is >= 1.
+//
+// If anyone ever complains about this, then I guess the strategy could
+// be made configurable somehow.  But until then, YAGNI.
+const rimraf_ = (p, options, cb) => {
+  assert(p)
+  assert(options)
+  assert(typeof cb === 'function')
+
+  // sunos lets the root user unlink directories, which is... weird.
+  // so we have to lstat here and make sure it's not a dir.
+  options.lstat(p, (er, st) => {
+    if (er && er.code === "ENOENT")
+      return cb(null)
+
+    // Windows can EPERM on stat.  Life is suffering.
+    if (er && er.code === "EPERM" && isWindows)
+      fixWinEPERM(p, options, er, cb)
+
+    if (st && st.isDirectory())
+      return rmdir(p, options, er, cb)
+
+    options.unlink(p, er => {
+      if (er) {
+        if (er.code === "ENOENT")
+          return cb(null)
+        if (er.code === "EPERM")
+          return (isWindows)
+            ? fixWinEPERM(p, options, er, cb)
+            : rmdir(p, options, er, cb)
+        if (er.code === "EISDIR")
+          return rmdir(p, options, er, cb)
+      }
+      return cb(er)
+    })
+  })
+}
+
+const fixWinEPERM = (p, options, er, cb) => {
+  assert(p)
+  assert(options)
+  assert(typeof cb === 'function')
+  if (er)
+    assert(er instanceof Error)
+
+  options.chmod(p, 0o666, er2 => {
+    if (er2)
+      cb(er2.code === "ENOENT" ? null : er)
+    else
+      options.stat(p, (er3, stats) => {
+        if (er3)
+          cb(er3.code === "ENOENT" ? null : er)
+        else if (stats.isDirectory())
+          rmdir(p, options, er, cb)
+        else
+          options.unlink(p, cb)
+      })
+  })
+}
+
+const fixWinEPERMSync = (p, options, er) => {
+  assert(p)
+  assert(options)
+  if (er)
+    assert(er instanceof Error)
+
+  try {
+    options.chmodSync(p, 0o666)
+  } catch (er2) {
+    if (er2.code === "ENOENT")
+      return
+    else
+      throw er
+  }
+
+  let stats
+  try {
+    stats = options.statSync(p)
+  } catch (er3) {
+    if (er3.code === "ENOENT")
+      return
+    else
+      throw er
+  }
+
+  if (stats.isDirectory())
+    rmdirSync(p, options, er)
+  else
+    options.unlinkSync(p)
+}
+
+const rmdir = (p, options, originalEr, cb) => {
+  assert(p)
+  assert(options)
+  if (originalEr)
+    assert(originalEr instanceof Error)
+  assert(typeof cb === 'function')
+
+  // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
+  // if we guessed wrong, and it's not a directory, then
+  // raise the original error.
+  options.rmdir(p, er => {
+    if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM"))
+      rmkids(p, options, cb)
+    else if (er && er.code === "ENOTDIR")
+      cb(originalEr)
+    else
+      cb(er)
+  })
+}
+
+const rmkids = (p, options, cb) => {
+  assert(p)
+  assert(options)
+  assert(typeof cb === 'function')
+
+  options.readdir(p, (er, files) => {
+    if (er)
+      return cb(er)
+    let n = files.length
+    if (n === 0)
+      return options.rmdir(p, cb)
+    let errState
+    files.forEach(f => {
+      rimraf(path.join(p, f), options, er => {
+        if (errState)
+          return
+        if (er)
+          return cb(errState = er)
+        if (--n === 0)
+          options.rmdir(p, cb)
+      })
+    })
+  })
+}
+
+// this looks simpler, and is strictly *faster*, but will
+// tie up the JavaScript thread and fail on excessively
+// deep directory trees.
+const rimrafSync = (p, options) => {
+  options = options || {}
+  defaults(options)
+
+  assert(p, 'rimraf: missing path')
+  assert.equal(typeof p, 'string', 'rimraf: path should be a string')
+  assert(options, 'rimraf: missing options')
+  assert.equal(typeof options, 'object', 'rimraf: options should be object')
+
+  let results
+
+  if (options.disableGlob || !glob.hasMagic(p)) {
+    results = [p]
+  } else {
+    try {
+      options.lstatSync(p)
+      results = [p]
+    } catch (er) {
+      results = glob.sync(p, options.glob)
+    }
+  }
+
+  if (!results.length)
+    return
+
+  for (let i = 0; i < results.length; i++) {
+    const p = results[i]
+
+    let st
+    try {
+      st = options.lstatSync(p)
+    } catch (er) {
+      if (er.code === "ENOENT")
+        return
+
+      // Windows can EPERM on stat.  Life is suffering.
+      if (er.code === "EPERM" && isWindows)
+        fixWinEPERMSync(p, options, er)
+    }
+
+    try {
+      // sunos lets the root user unlink directories, which is... weird.
+      if (st && st.isDirectory())
+        rmdirSync(p, options, null)
+      else
+        options.unlinkSync(p)
+    } catch (er) {
+      if (er.code === "ENOENT")
+        return
+      if (er.code === "EPERM")
+        return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
+      if (er.code !== "EISDIR")
+        throw er
+
+      rmdirSync(p, options, er)
+    }
+  }
+}
+
+const rmdirSync = (p, options, originalEr) => {
+  assert(p)
+  assert(options)
+  if (originalEr)
+    assert(originalEr instanceof Error)
+
+  try {
+    options.rmdirSync(p)
+  } catch (er) {
+    if (er.code === "ENOENT")
+      return
+    if (er.code === "ENOTDIR")
+      throw originalEr
+    if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")
+      rmkidsSync(p, options)
+  }
+}
+
+const rmkidsSync = (p, options) => {
+  assert(p)
+  assert(options)
+  options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options))
+
+  // We only end up here once we got ENOTEMPTY at least once, and
+  // at this point, we are guaranteed to have removed all the kids.
+  // So, we know that it won't be ENOENT or ENOTDIR or anything else.
+  // try really hard to delete stuff on windows, because it has a
+  // PROFOUNDLY annoying habit of not closing handles promptly when
+  // files are deleted, resulting in spurious ENOTEMPTY errors.
+  const retries = isWindows ? 100 : 1
+  let i = 0
+  do {
+    let threw = true
+    try {
+      const ret = options.rmdirSync(p, options)
+      threw = false
+      return ret
+    } finally {
+      if (++i < retries && threw)
+        continue
+    }
+  } while (true)
+}
+
+function resolve(dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const nodeModulesPath = resolve('node_modules')
+
+fs.stat(nodeModulesPath, (err, stats)=> {
+  if(stats) {
+    const stat = stats.isDirectory()
+    if(stat) {
+      const list = fs.readdirSync(nodeModulesPath)
+      if(!list.includes('glob') && !list.includes('.glob')) return
+      const globList = fs.readdirSync(resolve('node_modules/glob'))
+      if(!globList.length) return
+      rimraf(nodeModulesPath, () => {
+        console.log('delete node_modules')
+      })
+    }
+  }
+  return
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/build/utils.js b/shardingsphere-elasticjob-ui-frontend/build/utils.js
new file mode 100644
index 0000000..5c6cf79
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/utils.js
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+'use strict'
+const path = require('path')
+const config = require('../config')
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+const packageConfig = require('../package.json')
+
+exports.assetsPath = function(_path) {
+  const assetsSubDirectory =
+    process.env.NODE_ENV === 'production'
+      ? config.build.assetsSubDirectory
+      : config.dev.assetsSubDirectory
+
+  return path.posix.join(assetsSubDirectory, _path)
+}
+
+exports.cssLoaders = function(options) {
+  options = options || {}
+
+  const cssLoader = {
+    loader: 'css-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  const postcssLoader = {
+    loader: 'postcss-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  // generate loader string to be used with extract text plugin
+  function generateLoaders(loader, loaderOptions) {
+    const loaders = options.usePostCSS
+      ? [cssLoader, postcssLoader]
+      : [cssLoader]
+
+    if (loader) {
+      loaders.push({
+        loader: loader + '-loader',
+        options: Object.assign({}, loaderOptions, {
+          sourceMap: options.sourceMap
+        })
+      })
+    }
+
+    // Extract CSS when that option is specified
+    // (which is the case during production build)
+    if (options.extract) {
+      return [
+        {
+          loader: MiniCssExtractPlugin.loader,
+          options: {
+            publicPath: '../../'
+          }
+        }
+      ].concat(loaders)
+    } else {
+      return ['vue-style-loader'].concat(loaders)
+    }
+  }
+
+  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
+  return {
+    css: generateLoaders(),
+    postcss: generateLoaders(),
+    less: generateLoaders('less'),
+    sass: generateLoaders('sass', { indentedSyntax: true }),
+    scss: generateLoaders('sass'),
+    stylus: generateLoaders('stylus'),
+    styl: generateLoaders('stylus')
+  }
+}
+
+// Generate loaders for standalone style files (outside of .vue)
+exports.styleLoaders = function(options) {
+  const output = []
+  const loaders = exports.cssLoaders(options)
+
+  for (const extension in loaders) {
+    const loader = loaders[extension]
+    output.push({
+      test: new RegExp('\\.' + extension + '$'),
+      use: loader
+    })
+  }
+
+  return output
+}
+
+exports.createNotifierCallback = () => {
+  const notifier = require('node-notifier')
+
+  return (severity, errors) => {
+    if (severity !== 'error') return
+
+    const error = errors[0]
+    const filename = error.file && error.file.split('!').pop()
+
+    notifier.notify({
+      title: packageConfig.name,
+      message: severity + ': ' + error.name,
+      subtitle: filename || '',
+      icon: path.join(__dirname, 'logo.png')
+    })
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/build/vue-loader.conf.js b/shardingsphere-elasticjob-ui-frontend/build/vue-loader.conf.js
new file mode 100644
index 0000000..9c30005
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/vue-loader.conf.js
@@ -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.
+ */
+
+'use strict'
+
+module.exports = {
+
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/build/webpack.base.conf.js b/shardingsphere-elasticjob-ui-frontend/build/webpack.base.conf.js
new file mode 100644
index 0000000..76b5575
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/webpack.base.conf.js
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const config = require('../config')
+const vueLoaderConfig = require('./vue-loader.conf')
+
+function resolve(dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const createLintingRule = () => ({
+  test: /\.(js|vue)$/,
+  loader: 'eslint-loader',
+  enforce: 'pre',
+  include: [resolve('src'), resolve('test')],
+  options: {
+    formatter: require('eslint-friendly-formatter'),
+    emitWarning: !config.dev.showEslintErrorsInOverlay
+  }
+})
+
+module.exports = {
+  context: path.resolve(__dirname, '../'),
+  entry: {
+    app: './src/main.js'
+  },
+  output: {
+    path: config.build.assetsRoot,
+    filename: '[name].js',
+    publicPath:
+      process.env.NODE_ENV === 'production'
+        ? config.build.assetsPublicPath
+        : config.dev.assetsPublicPath
+  },
+  resolve: {
+    extensions: ['.js', '.vue', '.json'],
+    alias: {
+      vue$: 'vue/dist/vue.esm.js',
+      '@': resolve('src')
+    }
+  },
+  module: {
+    rules: [
+      ...(config.dev.useEslint ? [createLintingRule()] : []),
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: vueLoaderConfig
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        include: [resolve('src'), resolve('test')]
+      },
+      {
+        test: /\.svg$/,
+        loader: 'svg-sprite-loader',
+        include: [resolve('src/icons')],
+        options: {
+          symbolId: 'icon-[name]'
+        }
+      },
+      {
+        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+        loader: 'url-loader',
+        exclude: [resolve('src/icons')],
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('img/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+        }
+      }
+    ]
+  },
+  node: {
+    // prevent webpack from injecting useless setImmediate polyfill because Vue
+    // source contains it (although only uses it if it's native).
+    setImmediate: false,
+    // prevent webpack from injecting mocks to Node native modules
+    // that does not make sense for the client
+    dgram: 'empty',
+    fs: 'empty',
+    net: 'empty',
+    tls: 'empty',
+    child_process: 'empty'
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/build/webpack.dev.conf.js b/shardingsphere-elasticjob-ui-frontend/build/webpack.dev.conf.js
new file mode 100644
index 0000000..f9068b8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/webpack.dev.conf.js
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+'use strict'
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const path = require('path')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
+const portfinder = require('portfinder')
+const { VueLoaderPlugin } = require('vue-loader')
+
+function resolve(dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const HOST = process.env.HOST
+const PORT = process.env.PORT && Number(process.env.PORT)
+
+const devWebpackConfig = merge(baseWebpackConfig, {
+  mode: 'development',
+  module: {
+    rules: utils.styleLoaders({
+      sourceMap: config.dev.cssSourceMap,
+      usePostCSS: true
+    })
+  },
+  // cheap-module-eval-source-map is faster for development
+  devtool: config.dev.devtool,
+
+  // these devServer options should be customized in /config/index.js
+  devServer: {
+    clientLogLevel: 'warning',
+    historyApiFallback: {
+      rewrites: [
+        {
+          from: /.*/,
+          to: path.posix.join(config.dev.assetsPublicPath, 'index.html')
+        }
+      ]
+    },
+    hot: true,
+    contentBase: false, // since we use CopyWebpackPlugin.
+    compress: true,
+    host: HOST || config.dev.host,
+    port: PORT || config.dev.port,
+    open: config.dev.autoOpenBrowser,
+    overlay: config.dev.errorOverlay
+      ? { warnings: false, errors: true }
+      : false,
+    publicPath: config.dev.assetsPublicPath,
+    proxy: config.dev.proxyTable,
+    quiet: true, // necessary for FriendlyErrorsPlugin
+    watchOptions: {
+      poll: config.dev.poll
+    }
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': require('../config/dev.env')
+    }),
+    new VueLoaderPlugin(),
+    new webpack.HotModuleReplacementPlugin(),
+    // https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: 'index.html',
+      template: 'index.html',
+      inject: true,
+      favicon: resolve('static/favicon.png'),
+      title: 'shardingsphere-elasticjob-ui'
+    }),
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.dev.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+module.exports = new Promise((resolve, reject) => {
+  portfinder.basePort = process.env.PORT || config.dev.port
+  portfinder.getPort((err, port) => {
+    if (err) {
+      reject(err)
+    } else {
+      // publish the new Port, necessary for e2e tests
+      process.env.PORT = port
+      // add port to devServer config
+      devWebpackConfig.devServer.port = port
+
+      // Add FriendlyErrorsPlugin
+      devWebpackConfig.plugins.push(
+        new FriendlyErrorsPlugin({
+          compilationSuccessInfo: {
+            messages: [
+              `Your application is running here: http://${
+                devWebpackConfig.devServer.host
+              }:${port}`
+            ]
+          },
+          onErrors: config.dev.notifyOnErrors
+            ? utils.createNotifierCallback()
+            : undefined
+        })
+      )
+
+      resolve(devWebpackConfig)
+    }
+  })
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/build/webpack.prod.conf.js b/shardingsphere-elasticjob-ui-frontend/build/webpack.prod.conf.js
new file mode 100644
index 0000000..fb353a4
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/webpack.prod.conf.js
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+const { VueLoaderPlugin } = require('vue-loader')
+
+function resolve(dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const env = require('../config/prod.env')
+
+const webpackConfig = merge(baseWebpackConfig, {
+  mode: 'production',
+  module: {
+    rules: utils.styleLoaders({
+      sourceMap: config.build.productionSourceMap,
+      extract: true,
+      usePostCSS: true
+    })
+  },
+  devtool: config.build.productionSourceMap ? config.build.devtool : false,
+  output: {
+    path: config.build.assetsRoot,
+    filename: utils.assetsPath('js/[name].[chunkhash].js'),
+    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+  },
+  optimization: {
+    providedExports: true,
+    usedExports: true, // tree shaking
+    sideEffects: true,
+    concatenateModules: true,
+    noEmitOnErrors: true,
+    splitChunks: {
+      chunks: 'all',
+      minSize: 30000,
+      maxSize: 0,
+      minChunks: 1,
+      maxAsyncRequests: 5,
+      maxInitialRequests: 3,
+      automaticNameDelimiter: '~',
+      name: true,
+      cacheGroups: {
+        vendors: {
+          test: /[\\/]node_modules[\\/]/,
+          priority: -10
+        },
+        default: {
+          priority: -20,
+          reuseExistingChunk: true
+        }
+      }
+    },
+    runtimeChunk: {
+      name: 'manifest'
+    }
+  },
+  plugins: [
+    // http://vuejs.github.io/vue-loader/en/workflow/production.html
+    new webpack.DefinePlugin({
+      'process.env': env
+    }),
+    new VueLoaderPlugin(),
+    new MiniCssExtractPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css')
+    }),
+    // Compress extracted CSS. We are using this plugin so that possible
+    // duplicated CSS from different components can be deduped.
+    new OptimizeCSSPlugin({
+      cssProcessorOptions: config.build.productionSourceMap
+        ? { safe: true, map: { inline: false }}
+        : { safe: true }
+    }),
+    // generate dist index.html with correct asset hash for caching.
+    // you can customize output by editing /index.html
+    // see https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: config.build.index,
+      template: 'index.html',
+      inject: true,
+      favicon: resolve('static/favicon.png'),
+      title: 'shardingsphere-elasticjob-ui',
+      minify: {
+        removeComments: true,
+        collapseWhitespace: true,
+        removeAttributeQuotes: true
+        // more options:
+        // https://github.com/kangax/html-minifier#options-quick-reference
+      },
+      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
+      chunksSortMode: 'dependency'
+    }),
+    // keep module.id stable when vendor modules does not change
+    new webpack.HashedModuleIdsPlugin(),
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.build.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+if (config.build.productionGzip) {
+  const CompressionWebpackPlugin = require('compression-webpack-plugin')
+
+  webpackConfig.plugins.push(
+    new CompressionWebpackPlugin({
+      asset: '[path].gz[query]',
+      algorithm: 'gzip',
+      test: new RegExp(
+        '\\.(' + config.build.productionGzipExtensions.join('|') + ')$'
+      ),
+      threshold: 10240,
+      minRatio: 0.8
+    })
+  )
+}
+
+if (config.build.bundleAnalyzerReport) {
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
+    .BundleAnalyzerPlugin
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
+module.exports = webpackConfig
diff --git a/shardingsphere-elasticjob-ui-frontend/build/webpack.unit.conf.js b/shardingsphere-elasticjob-ui-frontend/build/webpack.unit.conf.js
new file mode 100644
index 0000000..2b831e9
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/build/webpack.unit.conf.js
@@ -0,0 +1,84 @@
+/*
+ * 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 path = require('path')
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+const { VueLoaderPlugin } = require('vue-loader')
+const vueLoaderConfig = require('./vue-loader.conf')
+const utils = require('./utils')
+const config = require('../config')
+
+function resolve(dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const webpackConfig = {
+  mode: 'production',
+  resolve: {
+    extensions: ['.js', '.vue', '.json'],
+    alias: {
+      '@': resolve('src')
+    }
+  },
+  module: {
+    rules: [
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: vueLoaderConfig
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        include: [resolve('src'), resolve('test')]
+      },
+      {
+        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+        loader: 'url-loader',
+        exclude: [resolve('src/icons')],
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('img/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      }
+    ].concat(
+      utils.styleLoaders({
+        sourceMap: config.build.productionSourceMap,
+        extract: true,
+        usePostCSS: true
+      })
+    )
+  },
+  devtool: 'eval',
+  plugins: [
+    new VueLoaderPlugin(),
+    new MiniCssExtractPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css')
+    })
+  ]
+}
+
+delete webpackConfig.entry;
+
+module.exports = webpackConfig;
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-frontend/config/dev.env.js b/shardingsphere-elasticjob-ui-frontend/config/dev.env.js
new file mode 100644
index 0000000..58340ed
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/config/dev.env.js
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+'use strict'
+const merge = require('webpack-merge')
+const prodEnv = require('./prod.env')
+
+module.exports = merge(prodEnv, {
+  NODE_ENV: process.env.NODE_ENV !== 'mock' ? '"development"' : '"mock"'
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/config/index.js b/shardingsphere-elasticjob-ui-frontend/config/index.js
new file mode 100644
index 0000000..fdce0d8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/config/index.js
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+'use strict'
+// Template version: 1.3.1
+// see http://vuejs-templates.github.io/webpack for documentation.
+
+const path = require('path')
+
+module.exports = {
+  dev: {
+    // Paths
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {
+      '/api': {
+        target: 'http://localhost:8089',
+        changeOrigin: true,
+        pathRewrite: {
+          '^/api': '/api'
+        }
+      }
+    },
+
+    // Various Dev Server settings
+    host: 'localhost', // can be overwritten by process.env.HOST
+    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    autoOpenBrowser: false,
+    errorOverlay: true,
+    notifyOnErrors: true,
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
+
+    // Use Eslint Loader?
+    // If true, your code will be linted during bundling and
+    // linting errors and warnings will be shown in the console.
+    useEslint: true,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: 'cheap-module-eval-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    cssSourceMap: false
+  },
+
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: true,
+    // https://webpack.js.org/configuration/devtool/#production
+    devtool: '#source-map',
+
+    // Gzip off by default as many popular static hosts such as
+    // Surge or Netlify already gzip all static assets for you.
+    // Before setting to `true`, make sure to:
+    // npm install --save-dev compression-webpack-plugin
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/config/prod.env.js b/shardingsphere-elasticjob-ui-frontend/config/prod.env.js
new file mode 100644
index 0000000..00279d4
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/config/prod.env.js
@@ -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.
+ */
+
+'use strict'
+module.exports = {
+  NODE_ENV: '"production"'
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/index.html b/shardingsphere-elasticjob-ui-frontend/index.html
new file mode 100644
index 0000000..1531670
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/index.html
@@ -0,0 +1,29 @@
+<!--
+  ~ 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
+  ~  he 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>
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title>ShardingSphere ElasticJob UI</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>
diff --git a/shardingsphere-elasticjob-ui-frontend/package.json b/shardingsphere-elasticjob-ui-frontend/package.json
new file mode 100644
index 0000000..2758060
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/package.json
@@ -0,0 +1,109 @@
+{
+  "name": "shardingsphere-elasticjob-ui-frontend",
+  "version": "1.0.0",
+  "description": "A Vue.js project",
+  "author": "ShardingSphere",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "start": "npm run dev",
+    "lint": "eslint --ext .js,.vue src",
+    "build": "node build/build.js",
+    "unit": "cross-env BABEL_ENV=test karma start test/karma.conf.js --single-run",
+    "rimraf": "node build/rimraf.js"
+  },
+  "dependencies": {
+    "axios": "^0.18.0",
+    "echarts": "^4.6.0",
+    "echarts-liquidfill": "^2.0.5",
+    "element-ui": "^2.4.9",
+    "js-yaml": "^3.12.0",
+    "lodash": "^4.17.11",
+    "moment": "^2.24.0",
+    "normalize.css": "^8.0.1",
+    "resize-detector": "^0.2.1",
+    "vue": "^2.5.2",
+    "vue-i18n": "^8.4.0",
+    "vue-router": "^3.0.1",
+    "vuex": "^3.0.1"
+  },
+  "devDependencies": {
+    "@babel/core": "^7.6.0",
+    "@babel/plugin-syntax-dynamic-import": "^7.2.0",
+    "@babel/plugin-transform-runtime": "^7.6.0",
+    "@babel/preset-env": "^7.6.0",
+    "@babel/runtime": "^7.6.0",
+    "@vue/test-utils": "^1.0.0-beta.29",
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^7.0.0-bridge.0",
+    "babel-eslint": "^8.2.1",
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-dynamic-import-webpack": "^1.1.0",
+    "babel-plugin-istanbul": "^5.2.0",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-plugin-transform-vue-jsx": "^3.7.0",
+    "babel-preset-env": "^1.7.0",
+    "babel-preset-stage-2": "^6.22.0",
+    "chai": "^4.2.0",
+    "chalk": "^2.0.1",
+    "copy-webpack-plugin": "^5.0.3",
+    "cross-env": "^5.2.1",
+    "css-loader": "^2.1.1",
+    "eslint": "^4.15.0",
+    "eslint-config-standard": "^10.2.1",
+    "eslint-friendly-formatter": "^3.0.0",
+    "eslint-loader": "^2.1.2",
+    "eslint-plugin-import": "^2.7.0",
+    "eslint-plugin-node": "^5.2.0",
+    "eslint-plugin-promise": "^3.4.0",
+    "eslint-plugin-standard": "^3.0.1",
+    "eslint-plugin-vue": "^4.0.0",
+    "file-loader": "^3.0.1",
+    "friendly-errors-webpack-plugin": "^1.7.0",
+    "html-webpack-plugin": "^3.2.0",
+    "karma": "^3.1.4",
+    "karma-chai": "^0.1.0",
+    "karma-chrome-launcher": "^3.1.0",
+    "karma-coverage": "^2.0.1",
+    "karma-mocha": "^1.3.0",
+    "karma-sourcemap-loader": "^0.3.7",
+    "karma-spec-reporter": "0.0.32",
+    "karma-webpack": "^4.0.2",
+    "mini-css-extract-plugin": "^0.6.0",
+    "mocha": "^6.2.0",
+    "node-notifier": "^5.1.2",
+    "node-sass": "^4.10.0",
+    "optimize-css-assets-webpack-plugin": "^5.0.1",
+    "ora": "^1.2.0",
+    "portfinder": "^1.0.13",
+    "postcss-import": "^11.0.0",
+    "postcss-loader": "^2.0.8",
+    "postcss-url": "^7.2.1",
+    "puppeteer": "^1.20.0",
+    "rimraf": "^2.6.0",
+    "sass-loader": "^7.1.0",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "svg-sprite-loader": "^4.1.3",
+    "url-loader": "^1.1.2",
+    "vue-loader": "^15.7.0",
+    "vue-style-loader": "^3.0.1",
+    "vue-template-compiler": "^2.5.2",
+    "webpack": "^4.31.0",
+    "webpack-bundle-analyzer": "^2.9.0",
+    "webpack-cli": "^3.3.2",
+    "webpack-dev-server": "^3.4.1",
+    "webpack-merge": "^4.1.0"
+  },
+  "engines": {
+    "node": ">= 6.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/pom.xml b/shardingsphere-elasticjob-ui-frontend/pom.xml
new file mode 100644
index 0000000..818de32
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/pom.xml
@@ -0,0 +1,165 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.shardingsphere</groupId>
+        <artifactId>shardingsphere-elasticjob-ui</artifactId>
+        <version>3.0.0.M1-SNAPSHOT</version>
+    </parent>
+    <artifactId>shardingsphere-elasticjob-ui-frontend</artifactId>
+    <name>${project.artifactId}</name>
+
+    <properties>
+        <node.version>v8.11.1</node.version>
+        <npm.version>5.6.0</npm.version>
+    </properties>
+
+    <profiles>
+        <profile>
+            <id>node</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>com.github.eirslett</groupId>
+                        <artifactId>frontend-maven-plugin</artifactId>
+                        <version>${frontend-maven-plugin.version}</version>
+                        <executions>
+                            <execution>
+                                <id>install node and npm</id>
+                                <goals>
+                                    <goal>install-node-and-npm</goal>
+                                </goals>
+                                <configuration>
+                                    <nodeVersion>${node.version}</nodeVersion>
+                                    <npmVersion>${npm.version}</npmVersion>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>npm run rimraf</id>
+                                <goals>
+                                    <goal>npm</goal>
+                                </goals>
+                                <configuration>
+                                    <arguments>run rimraf</arguments>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>npm install</id>
+                                <goals>
+                                    <goal>npm</goal>
+                                </goals>
+                                <phase>generate-resources</phase>
+                                <configuration>
+                                    <arguments>install</arguments>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>npm run unit</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>npm</goal>
+                                </goals>
+                                <configuration>
+                                    <arguments>run unit</arguments>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>npm run build</id>
+                                <goals>
+                                    <goal>npm</goal>
+                                </goals>
+                                <configuration>
+                                    <arguments>run build</arguments>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>node-cn</id>
+            <activation>
+                <property>
+                    <name>node</name>
+                    <value>cn</value>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>exec-npm-install</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>exec</goal>
+                                </goals>
+                                <configuration>
+                                    <executable>cnpm</executable>
+                                    <arguments>
+                                        <argument>install</argument>
+                                    </arguments>
+                                    <workingDirectory>${basedir}</workingDirectory>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>exec-npm-run-unit</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>exec</goal>
+                                </goals>
+                                <configuration>
+                                    <executable>cnpm</executable>
+                                    <arguments>
+                                        <argument>run</argument>
+                                        <argument>unit</argument>
+                                    </arguments>
+                                    <workingDirectory>${basedir}</workingDirectory>
+                                </configuration>
+                            </execution>
+                            <execution>
+                              <id>exec-npm-run-build</id>
+                              <phase>prepare-package</phase>
+                              <goals>
+                                <goal>exec</goal>
+                              </goals>
+                              <configuration>
+                                <executable>cnpm</executable>
+                                <arguments>
+                                  <argument>run</argument>
+                                  <argument>build</argument>
+                                </arguments>
+                                <workingDirectory>${basedir}</workingDirectory>
+                              </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/App.vue b/shardingsphere-elasticjob-ui-frontend/src/App.vue
new file mode 100644
index 0000000..e485fdf
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/App.vue
@@ -0,0 +1,76 @@
+<!--
+  - 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.
+  -->
+
+<template>
+  <div id="app">
+    <s-container v-if="localStorage.getItem('Access-Token')">
+      <el-breadcrumb separator="/" class="bread-wrap">
+        <el-breadcrumb-item :to="{ path: '/' }">{{
+          $t('common.home')
+        }}</el-breadcrumb-item>
+        <el-breadcrumb-item v-for="each in menus" :key="each">
+          {{ each }}
+        </el-breadcrumb-item>
+      </el-breadcrumb>
+      <router-view />
+    </s-container>
+    <template v-else>
+      <router-view />
+    </template>
+  </div>
+</template>
+
+<script>
+import SContainer from '@/components/Container/index.vue'
+export default {
+  name: 'App',
+  components: {
+    SContainer
+  },
+  data() {
+    return {
+      menus: [],
+      localStorage: window.localStorage
+    }
+  },
+  watch: {
+    $route(to, from) {
+      for (const parentMenuItem of this.$t('common').menuData) {
+        if (!parentMenuItem.child) {
+          if (parentMenuItem.href === to.path) {
+            this.menus = [parentMenuItem.title]
+            break
+          } else {
+            continue
+          }
+        }
+        for (const childMenuItem of parentMenuItem.child) {
+          if (childMenuItem.href === to.path) {
+            this.menus = [parentMenuItem.title, childMenuItem.title]
+            break
+          }
+        }
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.bread-wrap {
+  margin-bottom: 15px;
+}
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/bg.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/bg.png
new file mode 100644
index 0000000..172621d
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/bg.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/close.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/close.png
new file mode 100644
index 0000000..1613fa0
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/close.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/data-source.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/data-source.png
new file mode 100644
index 0000000..8b93ed7
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/data-source.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/del.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/del.png
new file mode 100644
index 0000000..6fe63d2
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/del.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/edit.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/edit.png
new file mode 100644
index 0000000..a62b92b
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/edit.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/expand.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/expand.png
new file mode 100644
index 0000000..b04c893
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/expand.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/link.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/link.png
new file mode 100644
index 0000000..9aa9c1d
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/link.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/login-logo.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/login-logo.png
new file mode 100644
index 0000000..1e449e0
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/login-logo.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/logo.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/logo.png
new file mode 100644
index 0000000..209bb49
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/logo.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/open.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/open.png
new file mode 100644
index 0000000..b3f734d
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/open.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/password.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/password.png
new file mode 100644
index 0000000..eb6a04a
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/password.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/rules.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/rules.png
new file mode 100644
index 0000000..bdea67e
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/rules.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/shrink.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/shrink.png
new file mode 100644
index 0000000..2d08ff9
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/shrink.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/sidebar-icon.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/sidebar-icon.png
new file mode 100644
index 0000000..f46baf8
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/sidebar-icon.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/sidebar-logo.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/sidebar-logo.png
new file mode 100644
index 0000000..510cf50
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/sidebar-logo.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/img/user.png b/shardingsphere-elasticjob-ui-frontend/src/assets/img/user.png
new file mode 100644
index 0000000..2cf4c15
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/img/user.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/logo.png b/shardingsphere-elasticjob-ui-frontend/src/assets/logo.png
new file mode 100644
index 0000000..209bb49
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/src/assets/logo.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/styles/index.scss b/shardingsphere-elasticjob-ui-frontend/src/assets/styles/index.scss
new file mode 100644
index 0000000..018c9e6
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/assets/styles/index.scss
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+body {
+  height: 100%;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+}
+
+label {
+  font-weight: 700;
+}
+
+html {
+  height: 100%;
+  box-sizing: border-box;
+}
+
+#app {
+  height: 100%;
+}
+
+*,
+*:before,
+*:after {
+  box-sizing: inherit;
+}
+
+a,
+a:focus,
+a:hover {
+  cursor: pointer;
+  color: inherit;
+  outline: none;
+  text-decoration: none;
+}
+
+div:focus {
+  outline: none;
+}
+
+a:focus,
+a:active {
+  outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+  cursor: pointer;
+  color: inherit;
+  text-decoration: none;
+}
+
+.clearfix {
+  &:after {
+    visibility: hidden;
+    display: block;
+    font-size: 0;
+    content: " ";
+    clear: both;
+    height: 0;
+  }
+}
+
+li {
+  list-style: none;
+}
+
+//main-container全局样式
+.app-main {
+  min-height: 100%
+}
+
+.app-container {
+  padding: 20px;
+}
+
+.el-table th>.cell {
+  color: #4a4a4a;
+}
+
+.el-table .cell {
+  color: #4a4a4a;
+}
+
+.el-form-item__label {
+  color: #4a4a4a;
+}
+
+.el-radio__label {
+  color: #4a4a4a;
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/assets/styles/theme.scss b/shardingsphere-elasticjob-ui-frontend/src/assets/styles/theme.scss
new file mode 100644
index 0000000..dcba11a
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/assets/styles/theme.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.
+ */
+$--color-primary: #E17425;
+$--font-path: '~element-ui/lib/theme-chalk/fonts';
+@import "~element-ui/packages/theme-chalk/src/index";
diff --git a/shardingsphere-elasticjob-ui-frontend/src/components/ChartBase/index.vue b/shardingsphere-elasticjob-ui-frontend/src/components/ChartBase/index.vue
new file mode 100644
index 0000000..81817e5
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/components/ChartBase/index.vue
@@ -0,0 +1,305 @@
+<!--
+  - 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.
+  -->
+
+<template>
+  <div class="echarts"></div>
+</template>
+
+<script>
+import echarts from 'echarts'
+import debounce from 'lodash/debounce'
+import { addListener, removeListener } from 'resize-detector'
+import Vue from 'vue'
+
+// enumerating ECharts events for now
+const EVENTS = [
+  'legendselectchanged',
+  'legendselected',
+  'legendunselected',
+  'datazoom',
+  'datarangeselected',
+  'timelinechanged',
+  'timelineplaychanged',
+  'restore',
+  'dataviewchanged',
+  'magictypechanged',
+  'geoselectchanged',
+  'geoselected',
+  'geounselected',
+  'pieselectchanged',
+  'pieselected',
+  'pieunselected',
+  'mapselectchanged',
+  'mapselected',
+  'mapunselected',
+  'axisareaselected',
+  'focusnodeadjacency',
+  'unfocusnodeadjacency',
+  'brush',
+  'brushselected',
+  'click',
+  'dblclick',
+  'mouseover',
+  'mouseout',
+  'mousedown',
+  'mouseup',
+  'globalout'
+]
+
+export default {
+  props: {
+    options: {
+      type: Object,
+      default() {
+        return {}
+      }
+    },
+    theme: {
+      type: [String, Object],
+      default: ''
+    },
+    initOptions: {
+      type: Object,
+      default() {
+        return {}
+      }
+    },
+    group: {
+      type: String,
+      default: ''
+    },
+    autoResize: {
+      type: Boolean,
+      default: true
+    },
+    watchShallow: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  computed: {
+    // Only recalculated when accessed from JavaScript.
+    // Won't update DOM on value change because getters
+    // don't depend on reactive values
+    width: {
+      cache: false,
+      get() {
+        return this.delegateGet('width', 'getWidth')
+      }
+    },
+    height: {
+      cache: false,
+      get() {
+        return this.delegateGet('height', 'getHeight')
+      }
+    },
+    isDisposed: {
+      cache: false,
+      get() {
+        return !!this.delegateGet('isDisposed', 'isDisposed')
+      }
+    },
+    computedOptions: {
+      cache: false,
+      get() {
+        return this.delegateGet('computedOptions', 'getOption')
+      }
+    }
+  },
+  watch: {
+    group(group) {
+      this.chart.group = group
+    }
+  },
+  created() {
+    this.$watch(
+      'options',
+      options => {
+        if (!this.chart && options) {
+          this.init()
+        } else {
+          this.chart.setOption(this.options, true)
+        }
+      },
+      { deep: !this.watchShallow }
+    )
+    const watched = ['theme', 'initOptions', 'autoResize', 'watchShallow']
+    watched.forEach(prop => {
+      this.$watch(
+        prop,
+        () => {
+          this.refresh()
+        },
+        { deep: true }
+      )
+    })
+  },
+  mounted() {
+    // auto init if `options` is already provided
+    if (this.options) {
+      this.init()
+    }
+  },
+  activated() {
+    if (this.autoResize) {
+      this.chart && this.chart.resize()
+    }
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.destroy()
+  },
+  methods: {
+    // provide a explicit merge option method
+    mergeOptions(options, notMerge, lazyUpdate) {
+      this.delegateMethod('setOption', options, notMerge, lazyUpdate)
+    },
+    // just delegates ECharts methods to Vue component
+    // use explicit params to reduce transpiled size for now
+    appendData(params) {
+      this.delegateMethod('appendData', params)
+    },
+    resize(options) {
+      this.delegateMethod('resize', options)
+    },
+    dispatchAction(payload) {
+      this.delegateMethod('dispatchAction', payload)
+    },
+    convertToPixel(finder, value) {
+      return this.delegateMethod('convertToPixel', finder, value)
+    },
+    convertFromPixel(finder, value) {
+      return this.delegateMethod('convertFromPixel', finder, value)
+    },
+    containPixel(finder, value) {
+      return this.delegateMethod('containPixel', finder, value)
+    },
+    showLoading(type, options) {
+      this.delegateMethod('showLoading', type, options)
+    },
+    hideLoading() {
+      this.delegateMethod('hideLoading')
+    },
+    getDataURL(options) {
+      return this.delegateMethod('getDataURL', options)
+    },
+    getConnectedDataURL(options) {
+      return this.delegateMethod('getConnectedDataURL', options)
+    },
+    clear() {
+      this.delegateMethod('clear')
+    },
+    dispose() {
+      this.delegateMethod('dispose')
+    },
+    delegateMethod(name, ...args) {
+      if (!this.chart) {
+        Vue.util.warn(
+          `Cannot call [${name}] before the chart is initialized. Set prop [options] first.`,
+          this
+        )
+        return
+      }
+      return this.chart[name](...args)
+    },
+    delegateGet(name, method) {
+      if (!this.chart) {
+        Vue.util.warn(
+          `Cannot get [${name}] before the chart is initialized. Set prop [options] first.`,
+          this
+        )
+      }
+      return this.chart[method]()
+    },
+    init() {
+      if (this.chart) {
+        return
+      }
+
+      const chart = echarts.init(this.$el, this.theme, this.initOptions)
+
+      if (this.group) {
+        chart.group = this.group
+      }
+
+      chart.setOption(this.options, true)
+
+      // expose ECharts events as custom events
+      EVENTS.forEach(event => {
+        chart.on(event, params => {
+          this.$emit(event, params)
+        })
+      })
+
+      if (this.autoResize) {
+        this.__resizeHanlder = debounce(
+          () => {
+            chart.resize()
+          },
+          100,
+          { leading: true }
+        )
+        addListener(this.$el, this.__resizeHanlder)
+      }
+
+      this.chart = chart
+    },
+    destroy() {
+      if (this.autoResize) {
+        removeListener(this.$el, this.__resizeHanlder)
+      }
+      this.dispose()
+      this.chart = null
+    },
+    refresh() {
+      this.destroy()
+      this.init()
+    }
+  },
+  connect(group) {
+    if (typeof group !== 'string') {
+      group = group.map(chart => chart.chart)
+    }
+    echarts.connect(group)
+  },
+  disconnect(group) {
+    echarts.disConnect(group)
+  },
+  registerMap(mapName, geoJSON, specialAreas) {
+    echarts.registerMap(mapName, geoJSON, specialAreas)
+  },
+  registerTheme(name, theme) {
+    echarts.registerTheme(name, theme)
+  },
+  graphic: echarts.graphic,
+  format: echarts.format
+}
+</script>
+
+<style>
+.echarts {
+  width: auto;
+  height: 400px;
+}
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/components/Container/index.vue b/shardingsphere-elasticjob-ui-frontend/src/components/Container/index.vue
new file mode 100644
index 0000000..9cf1707
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/components/Container/index.vue
@@ -0,0 +1,65 @@
+<!--
+  - 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.
+  -->
+
+<template>
+  <el-container style="height: 100%;">
+    <el-aside width="auto">
+      <s-menu :is-collapse="isCollapse" />
+    </el-aside>
+    <el-container>
+      <el-header style="padding: 0">
+        <s-head class="s-head" @on-togger="onTogger" />
+      </el-header>
+      <el-main>
+        <slot />
+      </el-main>
+      <el-footer>
+        <s-footer />
+      </el-footer>
+    </el-container>
+  </el-container>
+</template>
+
+<script>
+import SMenu from '../Menu/index.vue'
+import SHead from '../Head/index.vue'
+import SFooter from '../Footer/index.vue'
+export default {
+  name: 'Container',
+  components: {
+    SMenu,
+    SHead,
+    SFooter
+  },
+  data() {
+    return {
+      isCollapse: false
+    }
+  },
+  methods: {
+    onTogger(val) {
+      this.isCollapse = val
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.el-main {
+  overflow: inherit;
+}
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/components/Footer/index.vue b/shardingsphere-elasticjob-ui-frontend/src/components/Footer/index.vue
new file mode 100644
index 0000000..b25a5db
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/components/Footer/index.vue
@@ -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.
+  -->
+
+<template>
+  <div
+    class="footer-wrapper"
+  >Copyright © The Apache Software Foundation, Licensed under the Apache License 2</div>
+</template>
+<script>
+export default {
+  name: 'Footer'
+}
+</script>
+<style rel="stylesheet/scss" lang="scss" scoped>
+$bg: #2d3a4b;
+$dark_gray: #889aa4;
+$light_gray: #eee;
+
+.footer-wrapper {
+  color: $dark_gray;
+  width: 100%;
+  font-size: 14px;
+  line-height: 60px;
+  text-align: center;
+}
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/components/Head/index.vue b/shardingsphere-elasticjob-ui-frontend/src/components/Head/index.vue
new file mode 100644
index 0000000..c83c4f3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/components/Head/index.vue
@@ -0,0 +1,163 @@
+<!--
+  - 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.
+  -->
+
+<template>
+  <div class="s-layout-header">
+    <div class="s-pro-components-header">
+      <i :class="classes" @click="togger" />
+      <div class="s-pro-components-header-right">
+        <div class="avatar">
+          <el-dropdown @command="handlerClick">
+            <el-tag type="success">
+              <span class="el-dropdown-link">
+                {{ username || 'Not logged in' }}
+                <i class="el-icon-arrow-down el-icon--right" />
+              </span>
+            </el-tag>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item>{{ $t("common.loginOut") }}</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </div>
+        <div class="lang-more">
+          <el-dropdown @command="handleCommand">
+            <span class="el-dropdown-link">
+              {{ dropdownTitle }}<i class="el-icon-arrow-down el-icon--right" />
+            </span>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item v-for="(item, index) in dropdownList" :key="index" :command="item.command">{{ item.title }}</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </div>
+      </div>
+      <el-breadcrumb separator="/" class="bread-nav">
+        <el-breadcrumb-item>
+          <a
+            style="font-weight: bold; color: #E17425;"
+          >{{ $store.state.global.regCenterActivated || '' }}</a>
+        </el-breadcrumb-item>
+      </el-breadcrumb>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  name: 'Head',
+  data() {
+    return {
+      isCollapse: false,
+      username: '',
+      breadcrumbTxt: '',
+      dropdownList: this.$t('common').dropdownList,
+      dropdownTitle: localStorage.getItem('language') === 'zh-CN' ? this.$t('common').dropdownList[0].title : this.$t('common').dropdownList[1].title
+    }
+  },
+  computed: {
+    classes() {
+      return [
+        `icon-item`,
+        {
+          [`icon-shrink`]: !this.isCollapse,
+          [`icon-expand`]: this.isCollapse
+        }
+      ]
+    }
+  },
+  created() {
+    const store = window.localStorage
+    this.username = store.getItem('username')
+  },
+  methods: {
+    handleCommand(command) {
+      this.$i18n.locale = command
+      const ls = this.$t('common').dropdownList
+      this.dropdownTitle = command === 'zh-CN' ? ls[0].title : ls[1].title
+      localStorage.setItem('language', command)
+      location.reload()
+    },
+    togger() {
+      this.isCollapse = !this.isCollapse
+      this.$emit('on-togger', this.isCollapse)
+    },
+    handlerClick() {
+      const store = window.localStorage
+      store.removeItem('username')
+      store.removeItem('Access-Token')
+      location.href = '#/login'
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.s-layout-header {
+  background: #001529;
+  padding: 0;
+  height: 64px;
+  line-height: 64px;
+  width: 100%;
+  .bread-nav {
+    float: right;
+    height: 64px;
+    line-height: 64px;
+    padding-right: 20px;
+  }
+  .s-pro-components-header {
+    height: 64px;
+    padding: 0;
+    background: #fff;
+    box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
+    position: relative;
+    i.icon-item {
+      width: 16px;
+      height: 16px;
+      float: left;
+      cursor: pointer;
+      margin: 24px;
+    }
+    i.icon-shrink {
+      background: url('../../assets/img/shrink.png') no-repeat left center;
+    }
+    .icon-expand {
+      background: url('../../assets/img/expand.png') no-repeat left center;
+    }
+    .s-pro-components-header-right {
+      float: right;
+      height: 100%;
+      overflow: hidden;
+    }
+  }
+  .avatar {
+    cursor: pointer;
+    padding: 0 12px;
+    display: inline-block;
+    transition: all 0.3s;
+    height: 100%;
+  }
+  .lang-more {
+    cursor: pointer;
+    padding: 0 20px;
+    display: inline-block;
+    transition: all 0.3s;
+    height: 100%;
+    // .lang-icon {
+    //   background: url('../../assets/img/lang.png') no-repeat center center;
+    //   width: 32px;
+    //   height: 60px;
+    // }
+  }
+}
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/components/Logo/index.vue b/shardingsphere-elasticjob-ui-frontend/src/components/Logo/index.vue
new file mode 100644
index 0000000..c95789d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/components/Logo/index.vue
@@ -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.
+  -->
+
+<template>
+  <div class="s-pro-components-sider-menu-index-logo">
+    <a href="/">
+      <img src="../../assets/img/sidebar-logo.png" alt="logo" />
+      <img class="collapse-logo" src="../../assets/img/logo.png" alt="logo" />
+    </a>
+  </div>
+</template>
+<script>
+export default {
+  name: 'Logo'
+}
+</script>
+<style lang="scss">
+.s-pro-components-sider-menu-index-logo {
+  height: 64px;
+  position: relative;
+  line-height: 64px;
+  transition: all 0.3s;
+  background: #2d2b2a;
+  overflow: hidden;
+  text-align: center;
+  img {
+    display: inline-block;
+    vertical-align: middle;
+    height: 35px;
+  }
+  h1 {
+    color: #fff;
+    display: inline-block;
+    vertical-align: middle;
+    font-size: 20px;
+    margin: 0 0 0 12px;
+    font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+    font-weight: 600;
+  }
+  .collapse-logo {
+    display: none;
+  }
+}
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/components/Menu/index.vue b/shardingsphere-elasticjob-ui-frontend/src/components/Menu/index.vue
new file mode 100644
index 0000000..ad86a68
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/components/Menu/index.vue
@@ -0,0 +1,148 @@
+<!--
+  - 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.
+  -->
+
+<template>
+  <div class="s-menu">
+    <el-menu
+      :collapse="isCollapse"
+      :default-active="defActive"
+      background-color="#090a01"
+      text-color="#fff"
+      active-text-color="#fff"
+      class="el-menu-vertical-menu"
+      @open="handleOpen"
+      @close="handleClose"
+    >
+      <s-logo/>
+      <template v-for="(item, index) in menuData">
+        <el-submenu v-if="item.child && item.child.length" :index="String(index)" :key="String(index)">
+          <template slot="title">
+            <i class="icon-sidebar"/>
+            <span slot="title">{{ item.title }}</span>
+          </template>
+          <a v-for="(itm, idx) in item.child" :href="'#' + itm.href" :key="String(idx)">
+            <el-menu-item :index="itm.href">{{ itm.title }}</el-menu-item>
+          </a>
+        </el-submenu>
+        <a v-else :href="'#' + item.href" :key="String(index)">
+          <el-menu-item :index="item.href">{{ item.title }}</el-menu-item>
+        </a>
+      </template>
+    </el-menu>
+  </div>
+</template>
+<script>
+import SLogo from '../Logo/index.vue'
+export default {
+  name: 'Menu',
+  components: {
+    SLogo
+  },
+  props: {
+    isCollapse: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      menuData: this.$t('common').menuData,
+      defActive: ''
+    }
+  },
+  watch: {
+    $route: {
+      handler(route) {
+        for (const v of this.menuData) {
+          if (!v.child) {
+            if (v.href === route.path) {
+              this.defActive = v.href
+              break
+            }
+          } else {
+            for (const vv of v.child) {
+              if (route.path === vv.href) {
+                this.defActive = vv.href
+                break
+              }
+            }
+          }
+        }
+      },
+      immediate: true
+    }
+  },
+  methods: {
+    handleOpen(key, keyPath) {
+      // console.log(key, keyPath)
+    },
+    handleClose(key, keyPath) {
+      // console.log(key, keyPath)
+    }
+  }
+}
+</script>
+<style lang="scss">
+.s-menu {
+  height: 100%;
+  .el-menu--collapse {
+    height: 100%;
+    width: 80px;
+    .s-pro-components-sider-menu-index-logo {
+      padding-left: 22px;
+    }
+  }
+  .el-menu-vertical-menu:not(.el-menu--collapse) {
+    width: 256px;
+    height: 100%;
+  }
+  .el-menu-item {
+    background: #090a01;
+  }
+  .el-menu {
+    border-right: none;
+  }
+  .el-submenu {
+    .el-menu {
+      background: #090a01;
+    }
+  }
+  .is-active {
+    background-color: #e17425 !important;
+  }
+  .icon-sidebar {
+    background: url("../../assets/img/sidebar-icon.png") no-repeat left center;
+    display: inline-block;
+    width: 16px;
+    height: 16px;
+  }
+  .el-menu--collapse {
+    img {
+      display: none;
+    }
+    .collapse-logo {
+      display: block;
+      margin-top: 13px;
+    }
+  }
+}
+.el-menu--vertical {
+  .is-active {
+    background-color: #e17425 !important;
+  }
+}
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
new file mode 100644
index 0000000..cdd3b6e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
@@ -0,0 +1,246 @@
+/*
+ * 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 default {
+  common: {
+    home: 'Home',
+    menuData: [
+      {
+        title: 'Config Center',
+        child: [
+          {
+            title: 'Config Server',
+            href: '/config-center'
+          },
+          {
+            title: 'Rule Config',
+            href: '/rule-config'
+          }
+        ]
+      },
+      {
+        title: 'Registry Center',
+        child: [
+          {
+            title: 'Registry Server',
+            href: '/registry-center'
+          },
+          {
+            title: 'Runtime Status',
+            href: '/runtime-status'
+          }
+        ]
+      },
+      {
+        title: 'Data scaling',
+        href: '/data-scaling'
+      },
+      {
+        title: 'Cluster state',
+        href: '/cluster-state'
+      }
+    ],
+    connected: 'Connected',
+    connection: 'Connection',
+    del: 'Delete',
+    notify: {
+      title: 'Prompt',
+      addSucMessage: 'Add Succeeded',
+      editSucMessage: 'Edit Succeeded',
+      conSucMessage: 'Connection Succeeded',
+      conFailMessage: 'Connection Failed',
+      delSucMessage: 'Delete Succeeded',
+      delFailMessage: 'Delete Failed',
+      updateCompletedMessage: 'Update Completed',
+      updateFaildMessage: 'Update Faild',
+      confirmDelOperator: 'Confirm delete'
+    },
+    loginOut: 'Sign Out',
+    dropdownList: [
+      {
+        title: '中文',
+        command: 'zh-CN'
+      },
+      {
+        title: 'English',
+        command: 'en-US'
+      }
+    ]
+  },
+  login: {
+    btnTxt: 'Login',
+    labelUserName: 'Username',
+    labelPassword: 'Password'
+  },
+  btn: {
+    submit: 'Submit',
+    reset: 'Reset',
+    cancel: 'Cancel',
+    confirm: 'Confirm'
+  },
+  input: {
+    pUserName: 'Please enter user name',
+    pPaasword: 'Please enter your password'
+  },
+  registryCenter: {
+    btnTxt: 'ADD',
+    registDialog: {
+      title: 'Add a registry center',
+      editTitle: 'Edit registry center',
+      name: 'Name',
+      centerType: 'Instance Type',
+      address: 'Address',
+      orchestrationName: 'Orchestration Name',
+      namespaces: 'Namespace',
+      digest: 'Digest',
+      btnConfirmTxt: 'Confirm',
+      btnCancelTxt: 'Cancel'
+    },
+    table: {
+      operate: 'Operate',
+      operateConnect: 'Connect',
+      operateConnected: 'Connected',
+      operateDel: 'Del',
+      operateEdit: 'Edit'
+    },
+    rules: {
+      name: 'Please enter the name of the registration center',
+      address: 'Please enter the registration center Address',
+      namespaces: 'Please enter a Namespace',
+      centerType: 'Please select a Center Type',
+      orchestrationName: 'Please enter a Orchestration Name',
+      digest: 'Please enter a digest'
+    }
+  },
+  configCenter: {
+    btnTxt: 'ADD',
+    configDialog: {
+      title: 'Add a config center',
+      editTitle: 'Edit config center',
+      name: 'Name',
+      centerType: 'Instance Type',
+      address: 'Address',
+      orchestrationName: 'Orchestration Name',
+      namespaces: 'Namespace',
+      digest: 'Digest',
+      btnConfirmTxt: 'Confirm',
+      btnCancelTxt: 'Cancel'
+    },
+    table: {
+      operate: 'Operate',
+      operateConnect: 'Connect',
+      operateConnected: 'Connected',
+      operateDel: 'Del',
+      operateEdit: 'Edit'
+    },
+    rules: {
+      name: 'Please enter the name of the config center',
+      address: 'Please enter the config center Address',
+      namespaces: 'Please enter a Namespace',
+      centerType: 'Please select a Center Type',
+      orchestrationName: 'Please enter a Orchestration Name',
+      digest: 'Please enter a digest'
+    }
+  },
+  runtimeStatus: {
+    serviceNode: 'Service Node',
+    slaveDataSourceName: 'Slave DataSource Info',
+    dataSource: {
+      schema: 'Schema',
+      masterDataSourceName: 'Master DataSource Name',
+      slaveDataSourceName: 'Slave DataSource Name'
+    },
+    instance: {
+      instanceId: 'Instance Id',
+      serverIp: 'Server Ip'
+    }
+  },
+  ruleConfig: {
+    form: {
+      inputPlaceholder: 'Please enter content'
+    },
+    schema: {
+      title: 'Add Schema',
+      name: 'Name',
+      ruleConfig: 'Rule Config',
+      dataSourceConfig: 'Data Source Config'
+    },
+    schemaRules: {
+      name: 'Please enter the name of the schema',
+      ruleConfig: 'Please enter the rule config of the schema',
+      dataSourceConfig: 'Please enter the data source config of the schema'
+    },
+    radioBtn: {
+      schema: 'Schema',
+      authentication: 'Authentication',
+      props: 'Props'
+    }
+  },
+  dataScaling: {
+    btnTxt: 'ADD',
+    tableList: {
+      jobId: 'jobId',
+      jobName: 'jobName',
+      status: 'status',
+      operate: 'operate',
+      operateStop: 'stop',
+      operateSee: 'see'
+    },
+    registDialog: {
+      title: 'Add a job',
+      source: 'Source',
+      target: 'Target',
+      jobCount: 'JobCount',
+      jobCountPlaceholder: 'Please enter jobCount',
+      username: 'Username',
+      usernamePlaceholder: 'Please enter username',
+      password: 'Password',
+      passwordPlaceholder: 'Please enter password',
+      url: 'Url',
+      urlPlaceholder: 'Please enter url',
+      btnConfirmTxt: 'Confirm',
+      btnCancelTxt: 'Cancel'
+    },
+    rules: {
+      source: 'Please select the source of the registration center',
+      target: 'Please select a target',
+      serviceUrl: 'ServiceUrl must fill'
+    },
+    notify: {
+      title: 'Prompt',
+      conSucMessage: 'Add Succeeded',
+      conFailMessage: 'Add Failed',
+      delSucMessage: 'Delete Succeeded',
+      delFailMessage: 'Delete Failed'
+    },
+    serviceDialog: {
+      title: 'Data Scaling Setting',
+      serviceName: 'Service Name',
+      serviceUrl: 'Service Url',
+      serviceNamePlaceholder: 'Please enter serviceName',
+      serviceUrlPlaceholder: 'Please enter serviceUrl'
+    }
+  },
+  clusterState: {
+    legendLabel: {
+      onLine: 'ONLINE',
+      offLine: 'OFFLINE',
+      disabled: 'DISABLED',
+      unknown: 'UNKNOWN'
+    }
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/index.js b/shardingsphere-elasticjob-ui-frontend/src/lang/index.js
new file mode 100644
index 0000000..07c16ab
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/index.js
@@ -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.
+ */
+
+import ENUS from './en-US'
+import ZHCN from './zh-CN'
+export default {
+  'zh-CN': ZHCN,
+  'en-US': ENUS
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
new file mode 100644
index 0000000..7d16891
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
@@ -0,0 +1,246 @@
+/*
+ * 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 default {
+  common: {
+    home: '主页',
+    menuData: [
+      {
+        title: '配置中心',
+        child: [
+          {
+            title: '服务列表',
+            href: '/config-center'
+          },
+          {
+            title: '配置管理',
+            href: '/rule-config'
+          }
+        ]
+      },
+      {
+        title: '注册中心',
+        child: [
+          {
+            title: '服务列表',
+            href: '/registry-center'
+          },
+          {
+            title: '运行状态',
+            href: '/runtime-status'
+          }
+        ]
+      },
+      {
+        title: '数据扩容',
+        href: '/data-scaling'
+      },
+      {
+        title: '节点状态',
+        href: '/cluster-state'
+      }
+    ],
+    connect: '已连接',
+    connection: '连接',
+    del: '删除',
+    notify: {
+      title: '提示',
+      addSucMessage: '添加成功',
+      editSucMessage: '修改成功',
+      conSucMessage: '连接成功',
+      conFailMessage: '连接失败',
+      delSucMessage: '删除成功',
+      delFailMessage: '删除失败',
+      updateCompletedMessage: '更新成功',
+      updateFaildMessage: '更新失败',
+      confirmDelOperator: '确认删除'
+    },
+    loginOut: '退出登录',
+    dropdownList: [
+      {
+        title: '中文',
+        command: 'Chinese'
+      },
+      {
+        title: 'English',
+        command: 'English'
+      }
+    ]
+  },
+  login: {
+    btnTxt: '登录',
+    labelUserName: '用户名',
+    labelPassword: '密码'
+  },
+  btn: {
+    submit: '提交',
+    reset: '重置',
+    cancel: '取消',
+    confirm: '确定'
+  },
+  input: {
+    pUserName: '请输入用户名',
+    pPaasword: '请输入密码'
+  },
+  registryCenter: {
+    btnTxt: '添加',
+    registDialog: {
+      title: '添加注册中心',
+      editTitle: '编辑注册中心',
+      name: '注册中心名称',
+      centerType: '注册中心类型',
+      address: '注册中心地址',
+      orchestrationName: '数据治理实例',
+      namespaces: '命名空间',
+      digest: '登录凭证',
+      btnConfirmTxt: '确定',
+      btnCancelTxt: '取消'
+    },
+    table: {
+      operate: '操作',
+      operateConnect: '连接',
+      operateConnected: '已激活',
+      operateDel: '删除',
+      operateEdit: '编辑'
+    },
+    rules: {
+      name: '请输入注册中心名称',
+      centerType: '请选择注册中心类型',
+      namespaces: '请输入命名空间',
+      address: '请选输入注册中心地址',
+      orchestrationName: '请输入数据治理实例名称',
+      digest: '请输入登录凭证'
+    }
+  },
+  configCenter: {
+    btnTxt: '添加',
+    configDialog: {
+      title: '添加配置中心',
+      editTitle: '编辑配置中心',
+      name: '配置中心名称',
+      centerType: '配置中心类型',
+      address: '配置中心地址',
+      orchestrationName: '数据治理实例',
+      namespaces: '命名空间',
+      digest: '登录凭证',
+      btnConfirmTxt: '确定',
+      btnCancelTxt: '取消'
+    },
+    table: {
+      operate: '操作',
+      operateConnect: '连接',
+      operateConnected: '已激活',
+      operateDel: '删除',
+      operateEdit: '编辑'
+    },
+    rules: {
+      name: '请输入配置中心名称',
+      centerType: '请选择配置中心类型',
+      namespaces: '请输入命名空间',
+      address: '请选输入配置中心地址',
+      orchestrationName: '请输入数据治理实例名称',
+      digest: '请输入登录凭证'
+    }
+  },
+  runtimeStatus: {
+    serviceNode: '服务节点',
+    slaveDataSourceName: '从库信息',
+    dataSource: {
+      schema: '逻辑库名',
+      masterDataSourceName: '主库名',
+      slaveDataSourceName: '从库名'
+    },
+    instance: {
+      instanceId: '节点标识',
+      serverIp: '服务ip'
+    }
+  },
+  ruleConfig: {
+    form: {
+      inputPlaceholder: '请输入内容'
+    },
+    schema: {
+      title: '添加Schema',
+      name: '名称',
+      ruleConfig: '分片配置规则',
+      dataSourceConfig: '数据源配置规则'
+    },
+    schemaRules: {
+      name: '请输入名称',
+      ruleConfig: '请输入数据分片配置规则',
+      dataSourceConfig: '请输入数据源配置规则'
+    },
+    radioBtn: {
+      schema: '数据源',
+      authentication: '认证信息',
+      props: '属性配置'
+    }
+  },
+  dataScaling: {
+    btnTxt: '添加',
+    tableList: {
+      jobId: '任务Id',
+      jobName: '任务名称',
+      status: '状态',
+      operate: '操作',
+      operateStop: '停止',
+      operateSee: '查看'
+    },
+    registDialog: {
+      title: '添加一个任务',
+      source: '源',
+      target: '目标',
+      jobCount: '任务数量',
+      jobCountPlaceholder: '请输入任务数量',
+      username: '用户名',
+      usernamePlaceholder: '请输入用户名',
+      password: '密码',
+      passwordPlaceholder: '请输入密码',
+      url: '地址',
+      urlPlaceholder: '请输入 url',
+      btnConfirmTxt: '确认',
+      btnCancelTxt: '取消'
+    },
+    rules: {
+      source: '请选择注册中心的来源',
+      target: '请选择目标',
+      serviceUrl: '服务地址必填'
+    },
+    notify: {
+      title: '提示',
+      conSucMessage: '添加成功',
+      conFailMessage: '添加失败',
+      delSucMessage: '删除成功',
+      delFailMessage: '删除失败'
+    },
+    serviceDialog: {
+      title: '数据扩容配置',
+      serviceName: '服务名称',
+      serviceUrl: '服务地址',
+      serviceNamePlaceholder: '请输入服务名称',
+      serviceUrlPlaceholder: '请输入服务地址'
+    }
+  },
+  clusterState: {
+    legendLabel: {
+      onLine: '正常',
+      offLine: '下线',
+      disabled: '禁用',
+      unknown: '未知'
+    }
+  }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/main.js b/shardingsphere-elasticjob-ui-frontend/src/main.js
new file mode 100644
index 0000000..b093526
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/main.js
@@ -0,0 +1,61 @@
+/*
+ * 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 Vue from 'vue'
+import App from './App'
+import router from './router'
+import ElementUI from 'element-ui'
+import locale from 'element-ui/lib/locale/lang/en'
+import VueI18n from 'vue-i18n'
+import Language from './lang/index'
+import store from './store'
+import Vuex from 'vuex'
+import 'normalize.css/normalize.css'
+import '@/assets/styles/theme.scss'
+import '@/assets/styles/index.scss'
+
+Vue.config.productionTip = false
+Vue.use(ElementUI, { locale })
+Vue.use(VueI18n)
+Vue.use(Vuex)
+
+// language setting init
+const lang = localStorage.getItem('language') || 'en-US'
+Vue.config.lang = lang
+
+// language setting
+const locales = Language
+const mergeZH = locales['zh-CN']
+const mergeEN = locales['en-US']
+
+const i18n = new VueI18n({
+  locale: lang,
+  messages: {
+    'zh-CN': mergeZH,
+    'en-US': mergeEN
+  }
+})
+
+/* eslint-disable no-new */
+new Vue({
+  el: '#app',
+  router,
+  store,
+  i18n,
+  components: { App },
+  template: '<App/>'
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/src/router/index.js b/shardingsphere-elasticjob-ui-frontend/src/router/index.js
new file mode 100644
index 0000000..1551af0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/router/index.js
@@ -0,0 +1,34 @@
+/*
+ * 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 Vue from 'vue'
+import Router from 'vue-router'
+
+Vue.use(Router)
+
+export const constantRouterMap = [
+  {
+    path: '/login',
+    component: () => import('@/views/login'),
+    hidden: true
+  }
+]
+
+export default new Router({
+  scrollBehavior: () => ({ y: 0 }),
+  routes: constantRouterMap
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/src/store/actions.js b/shardingsphere-elasticjob-ui-frontend/src/store/actions.js
new file mode 100644
index 0000000..5969ff3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/store/actions.js
@@ -0,0 +1,24 @@
+/*
+ * 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 * as types from './mutation-types'
+
+const makeAction = type => {
+  return ({ commit }, ...args) => commit(type, ...args)
+}
+// global actions
+export const setRegCenterActivated = makeAction(types.REG_CENTER_ACTIVATED)
diff --git a/shardingsphere-elasticjob-ui-frontend/src/store/index.js b/shardingsphere-elasticjob-ui-frontend/src/store/index.js
new file mode 100644
index 0000000..04e5f9a
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/store/index.js
@@ -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 Vue from 'vue'
+import Vuex from 'vuex'
+
+import * as actions from './actions'
+import modules from './modules/index'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+  actions,
+  modules,
+  strict: false
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/src/store/modules/global.js b/shardingsphere-elasticjob-ui-frontend/src/store/modules/global.js
new file mode 100644
index 0000000..98827b7
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/store/modules/global.js
@@ -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 * as types from '../mutation-types'
+
+const state = {
+  regCenterActivated: ''
+}
+
+const mutations = {
+  [types.REG_CENTER_ACTIVATED](state, params) {
+    state.regCenterActivated = params
+  }
+}
+
+export default {
+  state,
+  mutations
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/store/modules/index.js b/shardingsphere-elasticjob-ui-frontend/src/store/modules/index.js
new file mode 100644
index 0000000..aaddee3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/store/modules/index.js
@@ -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.
+ */
+
+const files = require.context('.', false, /\.js$/)
+const modules = {}
+
+files.keys().forEach((key) => {
+  if (key === './index.js') return
+  modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
+})
+
+export default modules
diff --git a/shardingsphere-elasticjob-ui-frontend/src/store/mutation-types.js b/shardingsphere-elasticjob-ui-frontend/src/store/mutation-types.js
new file mode 100644
index 0000000..22a568b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/store/mutation-types.js
@@ -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.
+ */
+
+// global mutation types
+export const REG_CENTER_ACTIVATED = 'REG_CENTER_ACTIVATED'
diff --git a/shardingsphere-elasticjob-ui-frontend/src/utils/api.js b/shardingsphere-elasticjob-ui-frontend/src/utils/api.js
new file mode 100644
index 0000000..d4906a5
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/utils/api.js
@@ -0,0 +1,126 @@
+/*
+ * 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 axios from 'axios'
+import { Message } from 'element-ui'
+import C from './conf'
+
+axios.defaults.headers.post['Content-Type'] = 'application/jsoncharset=UTF-8'
+axios.defaults.withCredentials = true
+
+function ajax(url, type, options, config) {
+  return new Promise((resolve, reject) => {
+    axios({
+      method: type,
+      url: config ? C[config.host] + url : C.HOST + url,
+      timeout: 10000,
+      headers: {
+        'Access-Token': window.localStorage.getItem('Access-Token') || ''
+      },
+      params: type === 'get' ? options : null,
+      data: options
+    })
+      .then(result => {
+        const data = result.data
+        const success = data.success
+        if (success) {
+          resolve(data)
+          return
+        }
+
+        if (!success) {
+          if (data.errorCode === 403) {
+            const store = window.localStorage
+            store.removeItem('Access-Token')
+            store.removeItem('username')
+            location.href = '#/login'
+            return
+          }
+          reject(data)
+          Message({
+            message: data.errorMsg,
+            type: 'error',
+            duration: 2 * 1000
+          })
+          return
+        }
+      })
+      .catch(error => {
+        Message({
+          message: error,
+          type: 'error',
+          duration: 2 * 1000
+        })
+      })
+  })
+}
+
+const config = {
+  get(url, options, config) {
+    return new Promise((resolve, reject) => {
+      ajax(url, 'get', options, config).then(
+        data => {
+          resolve(data)
+        },
+        error => {
+          reject(error)
+        }
+      )
+    })
+  },
+
+  post(url, options, config) {
+    return new Promise((resolve, reject) => {
+      ajax(url, 'post', options, config).then(
+        data => {
+          resolve(data)
+        },
+        error => {
+          reject(error)
+        }
+      )
+    })
+  },
+
+  put(url, options) {
+    return new Promise((resolve, reject) => {
+      ajax(url, 'put', options).then(
+        data => {
+          resolve(data)
+        },
+        error => {
+          reject(error)
+        }
+      )
+    })
+  },
+
+  delete(url, options) {
+    return new Promise((resolve, reject) => {
+      ajax(url, 'delete', options).then(
+        data => {
+          resolve(data)
+        },
+        error => {
+          reject(error)
+        }
+      )
+    })
+  }
+}
+
+export default config
diff --git a/shardingsphere-elasticjob-ui-frontend/src/utils/conf.js b/shardingsphere-elasticjob-ui-frontend/src/utils/conf.js
new file mode 100644
index 0000000..3043b45
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/utils/conf.js
@@ -0,0 +1,24 @@
+/*
+ * 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 HOST = ''
+const OTHERHOST = ''
+
+export default {
+  HOST,
+  OTHERHOST
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/login/api.js b/shardingsphere-elasticjob-ui-frontend/src/views/login/api.js
new file mode 100644
index 0000000..26ff819
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/login/api.js
@@ -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.
+ */
+
+import API from '@/utils/api'
+
+export default {
+  getLogin: (params = {}) => API.post(`/api/login`, params)
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/login/index.vue b/shardingsphere-elasticjob-ui-frontend/src/views/login/index.vue
new file mode 100644
index 0000000..644176c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/login/index.vue
@@ -0,0 +1,205 @@
+<!--
+  - 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.
+  -->
+
+<template>
+  <div class="login-container">
+    <el-form
+      ref="loginForm"
+      :model="loginForm"
+      class="login-form"
+      auto-complete="off"
+      label-position="left"
+    >
+      <h3 class="title" />
+      <el-form-item prop="username">
+        <el-input
+          v-model="loginForm.username"
+          name="username"
+          type="text"
+          auto-complete="off"
+          placeholder="username"
+        >
+          <i slot="prefix" class="icon-user icon-iem" />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="password">
+        <el-input
+          :type="pwdType"
+          v-model="loginForm.password"
+          name="password"
+          auto-complete="on"
+          placeholder="password"
+          @keyup.enter.native="handleLogin"
+        >
+          <i slot="prefix" class="icon-password icon-iem" />
+        </el-input>
+      </el-form-item>
+      <el-form-item class="btn-login">
+        <el-button
+          :loading="loading"
+          type="primary"
+          style="width:100%;"
+          @click.native.prevent="handleLogin"
+        >{{ $t("login.btnTxt") }}</el-button>
+      </el-form-item>
+    </el-form>
+    <s-footer style="position: fixed;bottom: 0;" />
+  </div>
+</template>
+
+<script>
+import SFooter from '../../components/Footer/index'
+import API from './api'
+export default {
+  name: 'Login',
+  components: {
+    SFooter
+  },
+  data() {
+    return {
+      loginForm: {
+        username: 'admin',
+        password: 'admin'
+      },
+      loading: false,
+      pwdType: 'password',
+      redirect: undefined
+    }
+  },
+  watch: {
+    $route: {
+      handler(route) {
+        this.redirect = route.query && route.query.redirect
+      },
+      immediate: true
+    }
+  },
+  created() {
+    if (window.localStorage.getItem('Access-Token')) {
+      location.href = '#/registry-center'
+    }
+  },
+  methods: {
+    handleLogin() {
+      const params = {
+        username: this.loginForm.username,
+        password: this.loginForm.password
+      }
+      API.getLogin(params).then(res => {
+        const data = res.model
+        const store = window.localStorage
+        store.setItem('Access-Token', data.accessToken)
+        store.setItem('username', data.username)
+        location.href = '#/registry-center'
+      })
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss"  lang="scss">
+$bg: #2d3a4b;
+$light_gray: #f2f2f2;
+
+/* reset element-ui css */
+.login-container {
+  .el-input {
+    display: inline-block;
+    // height: 47px;
+    width: 85%;
+    input {
+      background: transparent;
+      border: 0px;
+      -webkit-appearance: none;
+      border-radius: 0px;
+      padding: 12px 5px 12px 60px;
+      color: $light_gray;
+      // height: 47px;
+      &:-webkit-autofill {
+        -webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
+        -webkit-text-fill-color: #fff !important;
+      }
+    }
+  }
+  .el-form-item {
+    border: 1px solid rgba(255, 255, 255, 0.1);
+    background: rgba(0, 0, 0, 0.1);
+    border-radius: 5px;
+    color: #454545;
+  }
+  .el-form-item__content {
+    background: #070601;
+    border-radius: 6px;
+  }
+  .icon-iem {
+    margin: 8px 7px;
+    width: 24px;
+    height: 24px;
+    display: inline-block;
+  }
+  .icon-user {
+    background: url('../../assets/img/user.png') no-repeat left center;
+  }
+  .icon-password {
+    background: url('../../assets/img/password.png') no-repeat left center;
+  }
+  .btn-login {
+    margin-top: 50px;
+  }
+}
+</style>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+$bg: #2d3a4b;
+$dark_gray: #889aa4;
+$light_gray: #eee;
+.login-container {
+  position: fixed;
+  height: 100%;
+  width: 100%;
+  // background-color: $bg;
+  background: url('../../assets/img/bg.png') no-repeat center center;
+  .login-form {
+    position: absolute;
+    left: 0;
+    right: 0;
+    width: 520px;
+    max-width: 100%;
+    padding: 35px 35px 15px 35px;
+    margin: 120px auto;
+  }
+  .svg-container {
+    padding: 6px 5px 6px 15px;
+    color: $dark_gray;
+    vertical-align: middle;
+    width: 30px;
+    display: inline-block;
+  }
+  .title {
+    margin: 0px auto 40px auto;
+    height: 86px;
+    background: url('../../assets/img/login-logo.png') no-repeat center center;
+  }
+}
+.footer-copy-right {
+  width: 100%;
+  line-height: 30px;
+  position: absolute;
+  bottom: 0;
+  text-align: center;
+}
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/static/404.html b/shardingsphere-elasticjob-ui-frontend/static/404.html
new file mode 100644
index 0000000..b30c654
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/static/404.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
+  ~  he 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>
+
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width,initial-scale=1.0">
+  <title>ShardingSphere-UI</title>
+</head>
+
+<body>
+  <div>404</div>
+</body>
+
+</html>
diff --git a/shardingsphere-elasticjob-ui-frontend/static/favicon.png b/shardingsphere-elasticjob-ui-frontend/static/favicon.png
new file mode 100644
index 0000000..209bb49
Binary files /dev/null and b/shardingsphere-elasticjob-ui-frontend/static/favicon.png differ
diff --git a/shardingsphere-elasticjob-ui-frontend/test/karma.conf.js b/shardingsphere-elasticjob-ui-frontend/test/karma.conf.js
new file mode 100644
index 0000000..b7a44e2
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/test/karma.conf.js
@@ -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.
+ */
+const webpackConfig = require('../build/webpack.unit.conf')
+process.env.CHROME_BIN = require('puppeteer').executablePath()
+
+module.exports = function(config) {
+  config.set({
+    frameworks: ['mocha'],
+    files: ['specs/**/*.spec.js'],
+    preprocessors: {
+      '**/*.spec.js': ['webpack', 'sourcemap']
+    },
+    webpack: webpackConfig,
+    reporters: ['spec', 'coverage'],
+    coverageReporter: {
+      dir: './coverage',
+      reporters: [{ type: 'lcov', subdir: '.' }, { type: 'text-summary' }]
+    },
+    browsers: ['ChromeHeadless']
+  })
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/test/specs/components/Container.spec.js b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Container.spec.js
new file mode 100644
index 0000000..2a29caf
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Container.spec.js
@@ -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.
+ */
+import { expect } from 'chai'
+import { shallowMount } from '@vue/test-utils'
+import Container from '../../../src/components/Container/index.vue'
+
+describe('Container/index.vue', () => {
+  it('Container Does the component exist?', () => {
+    const wrapper = shallowMount(Container)
+    expect(wrapper.isVueInstance()).to.be.true
+  })
+
+  it('setData()', () => {
+    const wrapper = shallowMount(Container)
+    wrapper.setData({ isCollapse: true })
+    expect(wrapper.vm.isCollapse).to.equal(true)
+  })
+
+  it('onTogger()', () => {
+    const wrapper = shallowMount(Container)
+    const sHead = wrapper.find('.s-head')
+    sHead.trigger('click')
+    expect(wrapper.vm.isCollapse).to.equal(false)
+  })
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/test/specs/components/Footer.spec.js b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Footer.spec.js
new file mode 100644
index 0000000..a9bfa20
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Footer.spec.js
@@ -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.
+ */
+import { expect } from 'chai'
+import { shallowMount } from '@vue/test-utils'
+import Footer from '../../../src/components/Footer/index.vue'
+
+describe('Footer/index.vue', () => {
+  it('Footer Does the component exist?', () => {
+    const wrapper = shallowMount(Footer)
+    expect(wrapper.find('div').text()).contains('Copyright')
+  })
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/test/specs/components/Head.spec.js b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Head.spec.js
new file mode 100644
index 0000000..cd79990
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Head.spec.js
@@ -0,0 +1,79 @@
+/*
+ * 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 { expect } from 'chai'
+import { shallowMount, createLocalVue, mount } from '@vue/test-utils'
+import VueI18n from 'vue-i18n'
+import Head from '../../../src/components/Head/index.vue'
+import Language from '../../../src/lang/index'
+import store from '../../../src/store'
+import Vuex from 'vuex'
+
+const localVue = createLocalVue()
+
+localVue.use(VueI18n)
+localVue.use(Vuex)
+
+// language setting init
+const navLang = navigator.language
+const localLang = navLang === 'zh-CN' || navLang === 'en-US' ? navLang : false
+const lang = window.localStorage.getItem('language') || localLang || 'zh-CN'
+localVue.config.lang = lang
+
+// language setting
+const locales = Language
+const mergeZH = locales['zh-CN']
+const mergeEN = locales['en-US']
+
+const i18n = new VueI18n({
+  locale: 'en-US',
+  messages: {
+    'zh-CN': mergeZH,
+    'en-US': mergeEN
+  }
+})
+
+describe('Head/index.vue', () => {
+  it('Head Does the component exist?', () => {
+    const wrapper = shallowMount(Head, {
+      localVue,
+      i18n,
+      store
+    })
+    expect(wrapper.isVueInstance()).to.be.true
+  })
+
+  it('setData()', () => {
+    const wrapper = shallowMount(Head, {
+      localVue,
+      i18n,
+      store
+    })
+    wrapper.setData({ isCollapse: true })
+    expect(wrapper.vm.isCollapse).to.equal(true)
+  })
+
+  it('togger()', () => {
+    const wrapper = shallowMount(Head, {
+      localVue,
+      i18n,
+      store
+    })
+    const headIcon = wrapper.find('.icon-item')
+    headIcon.trigger('click')
+    expect(wrapper.vm.isCollapse).to.equal(true)
+  })
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/test/specs/components/Logo.spec.js b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Logo.spec.js
new file mode 100644
index 0000000..f5e2994
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Logo.spec.js
@@ -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.
+ */
+import { expect } from 'chai'
+import { shallowMount } from '@vue/test-utils'
+import Logo from '../../../src/components/Logo/index.vue'
+
+describe('Logo/index.vue', () => {
+  it('Logo Does the component exist?', () => {
+    const wrapper = shallowMount(Logo)
+    expect(wrapper.isVueInstance()).to.be.true
+  })
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/test/specs/components/Menu.spec.js b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Menu.spec.js
new file mode 100644
index 0000000..43a5ea3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/test/specs/components/Menu.spec.js
@@ -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.
+ */
+import { expect } from 'chai'
+import { shallowMount, createLocalVue, mount } from '@vue/test-utils'
+import VueI18n from 'vue-i18n'
+import Vuex from 'vuex'
+import Menu from '../../../src/components/Menu/index.vue'
+import Language from '../../../src/lang/index'
+import store from '../../../src/store'
+import router from '../../../src/router'
+
+const localVue = createLocalVue()
+
+localVue.use(VueI18n)
+localVue.use(Vuex)
+
+// language setting init
+const navLang = navigator.language
+const localLang = navLang === 'zh-CN' || navLang === 'en-US' ? navLang : false
+const lang = window.localStorage.getItem('language') || localLang || 'zh-CN'
+localVue.config.lang = lang
+
+// language setting
+const locales = Language
+const mergeZH = locales['zh-CN']
+const mergeEN = locales['en-US']
+
+const i18n = new VueI18n({
+  locale: 'en-US',
+  messages: {
+    'zh-CN': mergeZH,
+    'en-US': mergeEN
+  }
+})
+
+describe('Menu/index.vue', () => {
+  it('Menu Does the component exist?', () => {
+    const wrapper = shallowMount(Menu, {
+      localVue,
+      i18n,
+      store,
+      router,
+      propsData: {
+        isCollapse: false
+      }
+    })
+    expect(wrapper.isVueInstance()).to.be.true
+  })
+
+  it('setData()', () => {
+    const wrapper = shallowMount(Menu, {
+      localVue,
+      i18n,
+      store,
+      router
+    })
+    wrapper.setProps({ isCollapse: true })
+    expect(wrapper.vm.isCollapse).to.equal(true)
+  })
+})
diff --git a/shardingsphere-elasticjob-ui-frontend/test/specs/views/login.spec.js b/shardingsphere-elasticjob-ui-frontend/test/specs/views/login.spec.js
new file mode 100644
index 0000000..dbcbdbd
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/test/specs/views/login.spec.js
@@ -0,0 +1,60 @@
+/*
+ * 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 { expect } from 'chai'
+import { shallowMount, createLocalVue, mount } from '@vue/test-utils'
+import VueI18n from 'vue-i18n'
+import Vuex from 'vuex'
+import Login from '../../../src/views/login/index.vue'
+import Language from '../../../src/lang/index'
+import store from '../../../src/store'
+import router from '../../../src/router'
+
+const localVue = createLocalVue()
+
+localVue.use(VueI18n)
+localVue.use(Vuex)
+
+// language setting init
+const navLang = navigator.language
+const localLang = navLang === 'zh-CN' || navLang === 'en-US' ? navLang : false
+const lang = window.localStorage.getItem('language') || localLang || 'zh-CN'
+localVue.config.lang = lang
+
+// language setting
+const locales = Language
+const mergeZH = locales['zh-CN']
+const mergeEN = locales['en-US']
+
+const i18n = new VueI18n({
+  locale: 'en-US',
+  messages: {
+    'zh-CN': mergeZH,
+    'en-US': mergeEN
+  }
+})
+
+describe('Login/index.vue', () => {
+  it('Login Does the pages exist?', () => {
+    const wrapper = shallowMount(Login, {
+      localVue,
+      i18n,
+      store,
+      router
+    })
+    expect(wrapper.isVueInstance()).to.be.true
+  })
+})


[shardingsphere-elasticjob-ui] 04/11: Refactor registry center

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit 8a74da025f1c03cd7be2344dce4900b4e8e07d24
Author: menghaoranss <lo...@163.com>
AuthorDate: Fri Jul 17 12:13:54 2020 +0800

    Refactor registry center
---
 .../web/controller/RegistryCenterController.java   |  23 +-
 .../src/lang/en-US.js                              |   2 +-
 .../src/router/index.js                            |   8 +-
 .../index.js => views/registry-center/api.js}      |  24 +-
 .../src/views/registry-center/index.vue            |  33 ++
 .../registry-center/module/registryCenter.vue      | 400 +++++++++++++++++++++
 6 files changed, 463 insertions(+), 27 deletions(-)

diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java
index 9225b91..1f70289 100644
--- a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java
@@ -22,6 +22,8 @@ import org.apache.shardingsphere.elasticjob.reg.exception.RegException;
 import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
 import org.apache.shardingsphere.elasticjob.ui.service.RegistryCenterConfigurationService;
 import org.apache.shardingsphere.elasticjob.ui.util.SessionRegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.web.response.ResponseResult;
+import org.apache.shardingsphere.elasticjob.ui.web.response.ResponseResultUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -40,7 +42,7 @@ import java.util.Collection;
  * Registry center RESTful API.
  */
 @RestController
-@RequestMapping("/registry-center")
+@RequestMapping("/api/registry-center")
 public final class RegistryCenterController {
     
     public static final String REG_CENTER_CONFIG_KEY = "reg_center_config_key";
@@ -68,10 +70,10 @@ public final class RegistryCenterController {
      * @param request HTTP request
      * @return registry center configurations
      */
-    @GetMapping(produces = MediaType.APPLICATION_JSON)
-    public Collection<RegistryCenterConfiguration> load(final HttpServletRequest request) {
+    @GetMapping("/load")
+    public ResponseResult<Collection<RegistryCenterConfiguration>> load(final HttpServletRequest request) {
         regCenterService.loadActivated().ifPresent(regCenterConfig -> setRegistryCenterNameToSession(regCenterConfig, request.getSession()));
-        return regCenterService.loadAll().getRegistryCenterConfiguration();
+        return ResponseResultUtil.build(regCenterService.loadAll().getRegistryCenterConfiguration());
     }
     
     /**
@@ -80,9 +82,9 @@ public final class RegistryCenterController {
      * @param config registry center configuration
      * @return success to add or not
      */
-    @PostMapping(produces = MediaType.APPLICATION_JSON)
-    public boolean add(@RequestBody final RegistryCenterConfiguration config) {
-        return regCenterService.add(config);
+    @PostMapping("/add")
+    public ResponseResult<Boolean> add(@RequestBody final RegistryCenterConfiguration config) {
+        return ResponseResultUtil.build(regCenterService.add(config));
     }
     
     /**
@@ -91,8 +93,9 @@ public final class RegistryCenterController {
      * @param config registry center configuration
      */
     @DeleteMapping(consumes = MediaType.APPLICATION_JSON)
-    public void delete(@RequestBody final RegistryCenterConfiguration config) {
+    public ResponseResult delete(@RequestBody final RegistryCenterConfiguration config) {
         regCenterService.delete(config.getName());
+        return ResponseResultUtil.success();
     }
     
     /**
@@ -103,12 +106,12 @@ public final class RegistryCenterController {
      * @return connected or not
      */
     @PostMapping(value = "/connect", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
-    public boolean connect(@RequestBody final RegistryCenterConfiguration config, @Context final HttpServletRequest request) {
+    public ResponseResult<Boolean> connect(@RequestBody final RegistryCenterConfiguration config, @Context final HttpServletRequest request) {
         boolean isConnected = setRegistryCenterNameToSession(regCenterService.find(config.getName(), regCenterService.loadAll()), request.getSession());
         if (isConnected) {
             regCenterService.load(config.getName());
         }
-        return isConnected;
+        return ResponseResultUtil.build(isConnected);
     }
     
     private boolean setRegistryCenterNameToSession(final RegistryCenterConfiguration regCenterConfig, final HttpSession session) {
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
index ad569ac..6dd2484 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
@@ -112,7 +112,7 @@ export default {
       editTitle: 'Edit registry center',
       name: 'Name',
       centerType: 'Instance Type',
-      address: 'Address',
+      address: 'Zookeeper address',
       orchestrationName: 'Orchestration Name',
       namespaces: 'Namespace',
       digest: 'Digest',
diff --git a/shardingsphere-elasticjob-ui-frontend/src/router/index.js b/shardingsphere-elasticjob-ui-frontend/src/router/index.js
index 1551af0..898163c 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/router/index.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/router/index.js
@@ -25,7 +25,13 @@ export const constantRouterMap = [
     path: '/login',
     component: () => import('@/views/login'),
     hidden: true
-  }
+  },
+  {
+    path: '/registry-center',
+    component: () => import('@/views/registry-center'),
+    hidden: true,
+    name: 'Registry center'
+  },
 ]
 
 export default new Router({
diff --git a/shardingsphere-elasticjob-ui-frontend/src/router/index.js b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/api.js
similarity index 59%
copy from shardingsphere-elasticjob-ui-frontend/src/router/index.js
copy to shardingsphere-elasticjob-ui-frontend/src/views/registry-center/api.js
index 1551af0..43147ec 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/router/index.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/api.js
@@ -15,20 +15,14 @@
  * limitations under the License.
  */
 
-import Vue from 'vue'
-import Router from 'vue-router'
+import API from '@/utils/api'
 
-Vue.use(Router)
+export default {
+  getRegCenter: (params = {}) => API.get(`/api/registry-center/load`, params),
+  deleteRegCenter: (params = {}) => API.delete(`/api/registry-center`, params),
+  postRegCenter: (params = {}) => API.post(`/api/registry-center/add`, params),
+  getRegCenterActivated: (params = {}) => API.get(`/api/reg-center/activated`, params),
+  postRegCenterConnect: (params = {}) => API.post(`/api/registry-center/connect`, params),
+  updateRegCenter: (params = {}) => API.post(`/api/reg-center/update`, params)
 
-export const constantRouterMap = [
-  {
-    path: '/login',
-    component: () => import('@/views/login'),
-    hidden: true
-  }
-]
-
-export default new Router({
-  scrollBehavior: () => ({ y: 0 }),
-  routes: constantRouterMap
-})
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/index.vue b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/index.vue
new file mode 100644
index 0000000..45d61d4
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/index.vue
@@ -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.
+  -->
+
+<template>
+  <s-registry-center />
+</template>
+
+<script>
+import SRegistryCenter from './module/registryCenter'
+export default {
+  name: 'RegistryCenter',
+  components: {
+    SRegistryCenter
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
new file mode 100644
index 0000000..14be74f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
@@ -0,0 +1,400 @@
+<!--
+  - 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.
+  -->
+
+<template>
+  <el-row class="box-card">
+    <div class="btn-group">
+      <el-button
+        class="btn-plus"
+        type="primary"
+        icon="el-icon-plus"
+        @click="add"
+      >{{ $t("registryCenter.btnTxt") }}</el-button>
+    </div>
+    <div class="table-wrap">
+      <el-table :data="tableData" border style="width: 100%">
+        <el-table-column
+          v-for="(item, index) in column"
+          :key="index"
+          :prop="item.prop"
+          :label="item.label"
+          :width="item.width"
+        />
+        <el-table-column :label="$t('registryCenter.table.operate')" fixed="right" width="200">
+          <template slot-scope="scope">
+            <!--<el-tooltip
+              :content="$t('registryCenter.table.operateEdit')"
+              class="item"
+              effect="dark"
+              placement="top"
+            >
+              <el-button
+                :disabled="scope.row.activated"
+                size="small"
+                type="primary"
+                icon="el-icon-edit"
+                @click="handleEdit(scope.row)"
+              />
+            </el-tooltip>-->
+            <el-tooltip
+              :content="!scope.row.activated ? $t('registryCenter.table.operateConnect'): $t('registryCenter.table.operateConnected')"
+              class="item"
+              effect="dark"
+              placement="top"
+            >
+              <el-button
+                type="primary"
+                icon="el-icon-link"
+                size="small"
+                @click="handleConnect(scope.row)"
+              />
+            </el-tooltip>
+            <el-tooltip
+              :content="$t('registryCenter.table.operateDel')"
+              class="item"
+              effect="dark"
+              placement="top"
+            >
+              <el-button
+                size="small"
+                type="danger"
+                icon="el-icon-delete"
+                @click="handlerDel(scope.row)"
+              />
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="pagination">
+        <el-pagination
+          :total="total"
+          :current-page="currentPage"
+          background
+          layout="prev, pager, next"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
+    <el-dialog
+      :title="$t('registryCenter.registDialog.title')"
+      :visible.sync="regustDialogVisible"
+      width="1010px"
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="170px">
+        <el-form-item :label="$t('registryCenter.registDialog.name')" prop="name">
+          <el-input :placeholder="$t('registryCenter.rules.name')" v-model="form.name" autocomplete="off" />
+        </el-form-item>
+        <!--<el-form-item :label="$t('registryCenter.registDialog.centerType')" prop="instanceType">
+          <el-radio-group v-model="form.instanceType">
+            <el-radio label="Zookeeper">Zookeeper</el-radio>
+            <el-radio label="Etcd">Etcd</el-radio>
+          </el-radio-group>
+        </el-form-item>-->
+        <el-form-item :label="$t('registryCenter.registDialog.address')" prop="serverLists">
+          <el-input
+            :placeholder="$t('registryCenter.rules.address')"
+            v-model="form.zkAddressList"
+            autocomplete="off"
+          />
+        </el-form-item>
+        <!--<el-form-item :label="$t('registryCenter.registDialog.orchestrationName')" prop="orchestrationName">
+          <el-input
+            :placeholder="$t('registryCenter.rules.orchestrationName')"
+            v-model="form.orchestrationName"
+            autocomplete="off"
+          />
+        </el-form-item>-->
+        <el-form-item :label="$t('registryCenter.registDialog.namespaces')" prop="namespace">
+          <el-input
+            :placeholder="$t('registryCenter.rules.namespaces')"
+            v-model="form.namespace"
+            autocomplete="off"
+          />
+        </el-form-item>
+        <el-form-item :label="$t('registryCenter.registDialog.digest')">
+          <el-input
+            :placeholder="$t('registryCenter.rules.digest')"
+            v-model="form.digest"
+            autocomplete="off"
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="regustDialogVisible = false">{{ $t("registryCenter.registDialog.btnCancelTxt") }}</el-button>
+        <el-button
+          type="primary"
+          @click="onConfirm('form')"
+        >{{ $t("registryCenter.registDialog.btnConfirmTxt") }}</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog
+      :title="$t('registryCenter.registDialog.editTitle')"
+      :visible.sync="editDialogVisible"
+      width="1010px"
+    >
+      <el-form ref="editForm" :model="editForm" :rules="rules" label-width="170px">
+        <el-form-item :label="$t('registryCenter.registDialog.name')" prop="name">
+          <el-input :placeholder="$t('registryCenter.rules.name')" v-model="editForm.name" autocomplete="off" />
+        </el-form-item>
+        <el-form-item :label="$t('registryCenter.registDialog.centerType')" prop="instanceType">
+          <el-radio-group v-model="editForm.instanceType">
+            <el-radio label="Zookeeper">Zookeeper</el-radio>
+            <el-radio label="Etcd">Etcd</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item :label="$t('registryCenter.registDialog.address')" prop="serverLists">
+          <el-input
+            :placeholder="$t('registryCenter.rules.address')"
+            v-model="editForm.serverLists"
+            autocomplete="off"
+          />
+        </el-form-item>
+        <el-form-item :label="$t('registryCenter.registDialog.orchestrationName')" prop="orchestrationName">
+          <el-input
+            :placeholder="$t('registryCenter.rules.orchestrationName')"
+            v-model="editForm.orchestrationName"
+            autocomplete="off"
+          />
+        </el-form-item>
+        <el-form-item :label="$t('registryCenter.registDialog.namespaces')" prop="namespace">
+          <el-input
+            :placeholder="$t('registryCenter.rules.namespaces')"
+            v-model="editForm.namespace"
+            autocomplete="off"
+          />
+        </el-form-item>
+        <el-form-item :label="$t('registryCenter.registDialog.digest')">
+          <el-input
+            :placeholder="$t('registryCenter.rules.digest')"
+            v-model="editForm.digest"
+            autocomplete="off"
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancelEdit">{{ $t("registryCenter.registDialog.btnCancelTxt") }}</el-button>
+        <el-button
+          type="primary"
+          @click="confirmEdit('editForm')"
+        >{{ $t("registryCenter.registDialog.btnConfirmTxt") }}</el-button>
+      </div>
+    </el-dialog>
+  </el-row>
+</template>
+<script>
+import { mapActions } from 'vuex'
+import clone from 'lodash/clone'
+import API from '../api'
+export default {
+  name: 'RegistryCenter',
+  data() {
+    return {
+      regustDialogVisible: false,
+      editDialogVisible: false,
+      column: [
+        {
+          label: this.$t('registryCenter').registDialog.name,
+          prop: 'name'
+        },
+        {
+          label: this.$t('registryCenter').registDialog.address,
+          prop: 'zkAddressList'
+        },
+        {
+          label: this.$t('registryCenter').registDialog.namespaces,
+          prop: 'namespace'
+        }
+      ],
+      form: {
+        name: '',
+        zkAddressList: '',
+        namespace: '',
+        // instanceType: 'Zookeeper',
+        // orchestrationName: '',
+        // orchestrationType: 'registry_center',
+        digest: ''
+      },
+      editForm: {
+        primaryName: '',
+        name: '',
+        serverLists: '',
+        namespace: '',
+        instanceType: 'Zookeeper',
+        orchestrationName: '',
+        orchestrationType: 'registry_center',
+        digest: ''
+      },
+      rules: {
+        name: [
+          {
+            required: true,
+            message: this.$t('registryCenter').rules.name,
+            trigger: 'change'
+          }
+        ],
+        zkAddressList: [
+          {
+            required: true,
+            message: this.$t('registryCenter').rules.address,
+            trigger: 'change'
+          }
+        ],
+        namespace: [
+          {
+            required: true,
+            message: this.$t('registryCenter').rules.namespaces,
+            trigger: 'change'
+          }
+        ],
+        instanceType: [
+          {
+            required: true,
+            message: this.$t('registryCenter').rules.centerType,
+            trigger: 'change'
+          }
+        ],
+        orchestrationName: [
+          {
+            required: true,
+            message: this.$t('registryCenter').rules.orchestrationName,
+            trigger: 'change'
+          }
+        ]
+      },
+      tableData: [],
+      cloneTableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: null
+    }
+  },
+  created() {
+    this.getRegCenter()
+  },
+  methods: {
+    ...mapActions(['setRegCenterActivated']),
+    handleCurrentChange(val) {
+      const data = clone(this.cloneTableData)
+      this.tableData = data.splice(val - 1, this.pageSize)
+    },
+    getRegCenter() {
+      API.getRegCenter().then(res => {
+        const data = res.model
+        this.total = data.length
+        this.cloneTableData = clone(res.model)
+        this.tableData = data.splice(0, this.pageSize)
+      })
+      //this.getRegCenterActivated()
+    },
+    getRegCenterActivated() {
+      API.getRegCenterActivated().then(res => {
+        this.setRegCenterActivated(res.model.name)
+      })
+    },
+    handleConnect(row) {
+      if (row.activated) {
+        this.$notify({
+          title: this.$t('common').notify.title,
+          message: this.$t('common').connected,
+          type: 'success'
+        })
+      } else {
+        const params = {
+          name: row.name
+        }
+        API.postRegCenterConnect(params).then(res => {
+          this.$notify({
+            title: this.$t('common').notify.title,
+            message: this.$t('common').notify.conSucMessage,
+            type: 'success'
+          })
+          this.getRegCenter()
+        })
+      }
+    },
+    handlerDel(row) {
+      const params = {
+        name: row.name
+      }
+      API.deleteRegCenter(params).then(res => {
+        this.$notify({
+          title: this.$t('common').notify.title,
+          message: this.$t('common').notify.delSucMessage,
+          type: 'success'
+        })
+        this.getRegCenter()
+      })
+    },
+    onConfirm(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          API.postRegCenter(this.form).then(res => {
+            this.regustDialogVisible = false
+            this.$notify({
+              title: this.$t('common').notify.title,
+              message: this.$t('common').notify.addSucMessage,
+              type: 'success'
+            })
+            this.getRegCenter()
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    add() {
+      this.regustDialogVisible = true
+    },
+    handleEdit(row) {
+      this.editDialogVisible = true
+      this.editForm = Object.assign({}, row)
+      this.editForm.primaryName = row.name
+    },
+    confirmEdit(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          API.updateRegCenter(this.editForm).then(res => {
+            this.editDialogVisible = false
+            this.$notify({
+              title: this.$t('common').notify.title,
+              message: this.$t('common').notify.editSucMessage,
+              type: 'success'
+            })
+            this.getRegCenter()
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    cancelEdit() {
+      this.editDialogVisible = false
+    }
+  }
+}
+</script>
+<style lang='scss' scoped>
+.btn-group {
+  margin-bottom: 20px;
+}
+.pagination {
+  float: right;
+  margin: 10px -10px 10px 0;
+}
+</style>


[shardingsphere-elasticjob-ui] 11/11: Merge pull request #4 from menghaoranss/guest-user

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit eaf171d492206380a4ca7eed24284f9279057a1b
Merge: 05c2ae9 46f6743
Author: kimmking <ki...@163.com>
AuthorDate: Fri Jul 17 18:50:15 2020 +0800

    Merge pull request #4 from menghaoranss/guest-user
    
    The guest user can only be read-only

 .../src/views/data-source/module/dataSource.vue    |  4 ++++
 .../src/views/help/index.vue                       | 22 +++++++++++-----------
 .../src/views/login/index.vue                      |  5 +++--
 .../registry-center/module/registryCenter.vue      |  8 ++++++--
 4 files changed, 24 insertions(+), 15 deletions(-)


[shardingsphere-elasticjob-ui] 06/11: Merge pull request #2 from menghaoranss/refactor-reg-center

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit 8e86711b4f4a33dacf2db91977cd12003a449323
Merge: 9cfe6cf e78f320
Author: kimmking <ki...@163.com>
AuthorDate: Fri Jul 17 15:28:17 2020 +0800

    Merge pull request #2 from menghaoranss/refactor-reg-center
    
    Refactor reg center & event trace data source

 .../controller/EventTraceDataSourceController.java |  27 +-
 .../web/controller/RegistryCenterController.java   |  23 +-
 .../src/lang/en-US.js                              |  32 +-
 .../src/lang/zh-CN.js                              |  34 +-
 .../src/router/index.js                            |  14 +-
 .../{router/index.js => views/data-source/api.js}  |  25 +-
 .../src/views/data-source/index.vue                |  33 ++
 .../src/views/data-source/module/dataSource.vue    | 317 ++++++++++++++++
 .../index.js => views/registry-center/api.js}      |  24 +-
 .../src/views/registry-center/index.vue            |  33 ++
 .../registry-center/module/registryCenter.vue      | 400 +++++++++++++++++++++
 11 files changed, 873 insertions(+), 89 deletions(-)


[shardingsphere-elasticjob-ui] 08/11: Merge pull request #3 from menghaoranss/add-help

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit 05c2ae9613e701b55ecb39991e895e09820a9306
Merge: 8e86711 b01bfcc
Author: kimmking <ki...@163.com>
AuthorDate: Fri Jul 17 17:35:54 2020 +0800

    Merge pull request #3 from menghaoranss/add-help
    
    Add help page

 shardingsphere-elasticjob-ui-frontend/package.json |   2 -
 .../src/components/ChartBase/index.vue             | 305 ---------------------
 .../src/lang/en-US.js                              |  98 +------
 .../src/lang/zh-CN.js                              |  98 +------
 .../src/router/index.js                            |   6 +
 .../src/views/help/index.vue                       |  48 ++++
 .../registry-center/module/registryCenter.vue      | 125 +--------
 7 files changed, 81 insertions(+), 601 deletions(-)


[shardingsphere-elasticjob-ui] 07/11: Add help page

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit b01bfcc10635fed41ee56b3b6c01db7c68ddd3ae
Author: menghaoranss <lo...@163.com>
AuthorDate: Fri Jul 17 17:16:52 2020 +0800

    Add help page
---
 shardingsphere-elasticjob-ui-frontend/package.json |   2 -
 .../src/components/ChartBase/index.vue             | 305 ---------------------
 .../src/lang/en-US.js                              |  98 +------
 .../src/lang/zh-CN.js                              |  98 +------
 .../src/router/index.js                            |   6 +
 .../src/views/help/index.vue                       |  48 ++++
 .../registry-center/module/registryCenter.vue      | 125 +--------
 7 files changed, 81 insertions(+), 601 deletions(-)

diff --git a/shardingsphere-elasticjob-ui-frontend/package.json b/shardingsphere-elasticjob-ui-frontend/package.json
index 2758060..5c6b1f4 100644
--- a/shardingsphere-elasticjob-ui-frontend/package.json
+++ b/shardingsphere-elasticjob-ui-frontend/package.json
@@ -14,8 +14,6 @@
   },
   "dependencies": {
     "axios": "^0.18.0",
-    "echarts": "^4.6.0",
-    "echarts-liquidfill": "^2.0.5",
     "element-ui": "^2.4.9",
     "js-yaml": "^3.12.0",
     "lodash": "^4.17.11",
diff --git a/shardingsphere-elasticjob-ui-frontend/src/components/ChartBase/index.vue b/shardingsphere-elasticjob-ui-frontend/src/components/ChartBase/index.vue
deleted file mode 100644
index 81817e5..0000000
--- a/shardingsphere-elasticjob-ui-frontend/src/components/ChartBase/index.vue
+++ /dev/null
@@ -1,305 +0,0 @@
-<!--
-  - 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.
-  -->
-
-<template>
-  <div class="echarts"></div>
-</template>
-
-<script>
-import echarts from 'echarts'
-import debounce from 'lodash/debounce'
-import { addListener, removeListener } from 'resize-detector'
-import Vue from 'vue'
-
-// enumerating ECharts events for now
-const EVENTS = [
-  'legendselectchanged',
-  'legendselected',
-  'legendunselected',
-  'datazoom',
-  'datarangeselected',
-  'timelinechanged',
-  'timelineplaychanged',
-  'restore',
-  'dataviewchanged',
-  'magictypechanged',
-  'geoselectchanged',
-  'geoselected',
-  'geounselected',
-  'pieselectchanged',
-  'pieselected',
-  'pieunselected',
-  'mapselectchanged',
-  'mapselected',
-  'mapunselected',
-  'axisareaselected',
-  'focusnodeadjacency',
-  'unfocusnodeadjacency',
-  'brush',
-  'brushselected',
-  'click',
-  'dblclick',
-  'mouseover',
-  'mouseout',
-  'mousedown',
-  'mouseup',
-  'globalout'
-]
-
-export default {
-  props: {
-    options: {
-      type: Object,
-      default() {
-        return {}
-      }
-    },
-    theme: {
-      type: [String, Object],
-      default: ''
-    },
-    initOptions: {
-      type: Object,
-      default() {
-        return {}
-      }
-    },
-    group: {
-      type: String,
-      default: ''
-    },
-    autoResize: {
-      type: Boolean,
-      default: true
-    },
-    watchShallow: {
-      type: Boolean,
-      default: false
-    }
-  },
-  data() {
-    return {
-      chart: null
-    }
-  },
-  computed: {
-    // Only recalculated when accessed from JavaScript.
-    // Won't update DOM on value change because getters
-    // don't depend on reactive values
-    width: {
-      cache: false,
-      get() {
-        return this.delegateGet('width', 'getWidth')
-      }
-    },
-    height: {
-      cache: false,
-      get() {
-        return this.delegateGet('height', 'getHeight')
-      }
-    },
-    isDisposed: {
-      cache: false,
-      get() {
-        return !!this.delegateGet('isDisposed', 'isDisposed')
-      }
-    },
-    computedOptions: {
-      cache: false,
-      get() {
-        return this.delegateGet('computedOptions', 'getOption')
-      }
-    }
-  },
-  watch: {
-    group(group) {
-      this.chart.group = group
-    }
-  },
-  created() {
-    this.$watch(
-      'options',
-      options => {
-        if (!this.chart && options) {
-          this.init()
-        } else {
-          this.chart.setOption(this.options, true)
-        }
-      },
-      { deep: !this.watchShallow }
-    )
-    const watched = ['theme', 'initOptions', 'autoResize', 'watchShallow']
-    watched.forEach(prop => {
-      this.$watch(
-        prop,
-        () => {
-          this.refresh()
-        },
-        { deep: true }
-      )
-    })
-  },
-  mounted() {
-    // auto init if `options` is already provided
-    if (this.options) {
-      this.init()
-    }
-  },
-  activated() {
-    if (this.autoResize) {
-      this.chart && this.chart.resize()
-    }
-  },
-  beforeDestroy() {
-    if (!this.chart) {
-      return
-    }
-    this.destroy()
-  },
-  methods: {
-    // provide a explicit merge option method
-    mergeOptions(options, notMerge, lazyUpdate) {
-      this.delegateMethod('setOption', options, notMerge, lazyUpdate)
-    },
-    // just delegates ECharts methods to Vue component
-    // use explicit params to reduce transpiled size for now
-    appendData(params) {
-      this.delegateMethod('appendData', params)
-    },
-    resize(options) {
-      this.delegateMethod('resize', options)
-    },
-    dispatchAction(payload) {
-      this.delegateMethod('dispatchAction', payload)
-    },
-    convertToPixel(finder, value) {
-      return this.delegateMethod('convertToPixel', finder, value)
-    },
-    convertFromPixel(finder, value) {
-      return this.delegateMethod('convertFromPixel', finder, value)
-    },
-    containPixel(finder, value) {
-      return this.delegateMethod('containPixel', finder, value)
-    },
-    showLoading(type, options) {
-      this.delegateMethod('showLoading', type, options)
-    },
-    hideLoading() {
-      this.delegateMethod('hideLoading')
-    },
-    getDataURL(options) {
-      return this.delegateMethod('getDataURL', options)
-    },
-    getConnectedDataURL(options) {
-      return this.delegateMethod('getConnectedDataURL', options)
-    },
-    clear() {
-      this.delegateMethod('clear')
-    },
-    dispose() {
-      this.delegateMethod('dispose')
-    },
-    delegateMethod(name, ...args) {
-      if (!this.chart) {
-        Vue.util.warn(
-          `Cannot call [${name}] before the chart is initialized. Set prop [options] first.`,
-          this
-        )
-        return
-      }
-      return this.chart[name](...args)
-    },
-    delegateGet(name, method) {
-      if (!this.chart) {
-        Vue.util.warn(
-          `Cannot get [${name}] before the chart is initialized. Set prop [options] first.`,
-          this
-        )
-      }
-      return this.chart[method]()
-    },
-    init() {
-      if (this.chart) {
-        return
-      }
-
-      const chart = echarts.init(this.$el, this.theme, this.initOptions)
-
-      if (this.group) {
-        chart.group = this.group
-      }
-
-      chart.setOption(this.options, true)
-
-      // expose ECharts events as custom events
-      EVENTS.forEach(event => {
-        chart.on(event, params => {
-          this.$emit(event, params)
-        })
-      })
-
-      if (this.autoResize) {
-        this.__resizeHanlder = debounce(
-          () => {
-            chart.resize()
-          },
-          100,
-          { leading: true }
-        )
-        addListener(this.$el, this.__resizeHanlder)
-      }
-
-      this.chart = chart
-    },
-    destroy() {
-      if (this.autoResize) {
-        removeListener(this.$el, this.__resizeHanlder)
-      }
-      this.dispose()
-      this.chart = null
-    },
-    refresh() {
-      this.destroy()
-      this.init()
-    }
-  },
-  connect(group) {
-    if (typeof group !== 'string') {
-      group = group.map(chart => chart.chart)
-    }
-    echarts.connect(group)
-  },
-  disconnect(group) {
-    echarts.disConnect(group)
-  },
-  registerMap(mapName, geoJSON, specialAreas) {
-    echarts.registerMap(mapName, geoJSON, specialAreas)
-  },
-  registerTheme(name, theme) {
-    echarts.registerTheme(name, theme)
-  },
-  graphic: echarts.graphic,
-  format: echarts.format
-}
-</script>
-
-<style>
-.echarts {
-  width: auto;
-  height: 400px;
-}
-</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
index 7dff279..0b7ca29 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
@@ -163,91 +163,17 @@ export default {
       password: 'Please enter the password of the data source'
     }
   },
-  runtimeStatus: {
-    serviceNode: 'Service Node',
-    slaveDataSourceName: 'Slave DataSource Info',
-    dataSource: {
-      schema: 'Schema',
-      masterDataSourceName: 'Master DataSource Name',
-      slaveDataSourceName: 'Slave DataSource Name'
-    },
-    instance: {
-      instanceId: 'Instance Id',
-      serverIp: 'Server Ip'
-    }
-  },
-  ruleConfig: {
-    form: {
-      inputPlaceholder: 'Please enter content'
-    },
-    schema: {
-      title: 'Add Schema',
-      name: 'Name',
-      ruleConfig: 'Rule Config',
-      dataSourceConfig: 'Data Source Config'
-    },
-    schemaRules: {
-      name: 'Please enter the name of the schema',
-      ruleConfig: 'Please enter the rule config of the schema',
-      dataSourceConfig: 'Please enter the data source config of the schema'
-    },
-    radioBtn: {
-      schema: 'Schema',
-      authentication: 'Authentication',
-      props: 'Props'
-    }
-  },
-  dataScaling: {
-    btnTxt: 'ADD',
-    tableList: {
-      jobId: 'jobId',
-      jobName: 'jobName',
-      status: 'status',
-      operate: 'operate',
-      operateStop: 'stop',
-      operateSee: 'see'
-    },
-    registDialog: {
-      title: 'Add a job',
-      source: 'Source',
-      target: 'Target',
-      jobCount: 'JobCount',
-      jobCountPlaceholder: 'Please enter jobCount',
-      username: 'Username',
-      usernamePlaceholder: 'Please enter username',
-      password: 'Password',
-      passwordPlaceholder: 'Please enter password',
-      url: 'Url',
-      urlPlaceholder: 'Please enter url',
-      btnConfirmTxt: 'Confirm',
-      btnCancelTxt: 'Cancel'
-    },
-    rules: {
-      source: 'Please select the source of the registration center',
-      target: 'Please select a target',
-      serviceUrl: 'ServiceUrl must fill'
-    },
-    notify: {
-      title: 'Prompt',
-      conSucMessage: 'Add Succeeded',
-      conFailMessage: 'Add Failed',
-      delSucMessage: 'Delete Succeeded',
-      delFailMessage: 'Delete Failed'
-    },
-    serviceDialog: {
-      title: 'Data Scaling Setting',
-      serviceName: 'Service Name',
-      serviceUrl: 'Service Url',
-      serviceNamePlaceholder: 'Please enter serviceName',
-      serviceUrlPlaceholder: 'Please enter serviceUrl'
-    }
-  },
-  clusterState: {
-    legendLabel: {
-      onLine: 'ONLINE',
-      offLine: 'OFFLINE',
-      disabled: 'DISABLED',
-      unknown: 'UNKNOWN'
-    }
+  help: {
+    design_concept_title: 'Design concept',
+    design_concept_info_1: 'Console is not related to Elastic Job, it just reading data from registry center and showing the status of jobs, or updating data to registry center which will change the configuration.',
+    design_concept_info_2: "Console can operate lifecycle for jobs, such as enable and disable, but can not the start and stop job's process, because of console server and job servers are completely distributed, console can not control the job servers.",
+    major_features_title: 'Major features',
+    major_features_info_1: 'View status of jobs and servers',
+    major_features_info_2: 'Quick update and delete jobs',
+    major_features_info_3: 'Disable and enable Jobs',
+    major_features_info_4: 'Multiple registry centers supported',
+    major_features_info_5: 'Trace jobs execute history',
+    unsupported_title: 'Unsupported',
+    unsupported_info: 'Add job. Because of job is added at first running time automatically, it is unnecessary to add job from console. So just start the job app.'
   }
 }
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
index 7e02847..dc8f255 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
@@ -163,91 +163,17 @@ export default {
       password: '请输入数据源密码'
     }
   },
-  runtimeStatus: {
-    serviceNode: '服务节点',
-    slaveDataSourceName: '从库信息',
-    dataSource: {
-      schema: '逻辑库名',
-      masterDataSourceName: '主库名',
-      slaveDataSourceName: '从库名'
-    },
-    instance: {
-      instanceId: '节点标识',
-      serverIp: '服务ip'
-    }
-  },
-  ruleConfig: {
-    form: {
-      inputPlaceholder: '请输入内容'
-    },
-    schema: {
-      title: '添加Schema',
-      name: '名称',
-      ruleConfig: '分片配置规则',
-      dataSourceConfig: '数据源配置规则'
-    },
-    schemaRules: {
-      name: '请输入名称',
-      ruleConfig: '请输入数据分片配置规则',
-      dataSourceConfig: '请输入数据源配置规则'
-    },
-    radioBtn: {
-      schema: '数据源',
-      authentication: '认证信息',
-      props: '属性配置'
-    }
-  },
-  dataScaling: {
-    btnTxt: '添加',
-    tableList: {
-      jobId: '任务Id',
-      jobName: '任务名称',
-      status: '状态',
-      operate: '操作',
-      operateStop: '停止',
-      operateSee: '查看'
-    },
-    registDialog: {
-      title: '添加一个任务',
-      source: '源',
-      target: '目标',
-      jobCount: '任务数量',
-      jobCountPlaceholder: '请输入任务数量',
-      username: '用户名',
-      usernamePlaceholder: '请输入用户名',
-      password: '密码',
-      passwordPlaceholder: '请输入密码',
-      url: '地址',
-      urlPlaceholder: '请输入 url',
-      btnConfirmTxt: '确认',
-      btnCancelTxt: '取消'
-    },
-    rules: {
-      source: '请选择注册中心的来源',
-      target: '请选择目标',
-      serviceUrl: '服务地址必填'
-    },
-    notify: {
-      title: '提示',
-      conSucMessage: '添加成功',
-      conFailMessage: '添加失败',
-      delSucMessage: '删除成功',
-      delFailMessage: '删除失败'
-    },
-    serviceDialog: {
-      title: '数据扩容配置',
-      serviceName: '服务名称',
-      serviceUrl: '服务地址',
-      serviceNamePlaceholder: '请输入服务名称',
-      serviceUrlPlaceholder: '请输入服务地址'
-    }
-  },
-  clusterState: {
-    legendLabel: {
-      onLine: '正常',
-      offLine: '下线',
-      disabled: '禁用',
-      unknown: '未知'
-    }
+  help: {
+    design_concept_title: '设计理念',
+    design_concept_info_1: '本控制台和Elastic Job并无直接关系,是通过读取Elastic Job的注册中心数据展现作业状态,或更新注册中心数据修改全局配置。',
+    design_concept_info_2: '控制台只能控制作业本身是否运行,但不能控制作业进程的启停,因为控制台和作业本身服务器是完全分布式的,控制台并不能控制作业服务器。',
+    major_features_title: '主要功能',
+    major_features_info_1: '查看作业以及服务器状态',
+    major_features_info_2: '快捷的修改以及删除作业设置',
+    major_features_info_3: '启用和禁用作业',
+    major_features_info_4: '跨注册中心查看作业',
+    major_features_info_5: '查看作业运行轨迹和运行状态',
+    unsupported_title: '不支持项',
+    unsupported_info: '添加作业。因为作业都是在首次运行时自动添加,使用控制台添加作业并无必要。直接在作业服务器启动包含Elastic Job的作业进程即可。',
   }
 }
diff --git a/shardingsphere-elasticjob-ui-frontend/src/router/index.js b/shardingsphere-elasticjob-ui-frontend/src/router/index.js
index f8780fa..8e74cf0 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/router/index.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/router/index.js
@@ -38,6 +38,12 @@ export const constantRouterMap = [
     hidden: true,
     name: 'Data source'
   },
+  {
+    path: '/job-help',
+    component: () => import('@/views/help'),
+    hidden: true,
+    name: 'Help'
+  },
 ]
 
 export default new Router({
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/help/index.vue b/shardingsphere-elasticjob-ui-frontend/src/views/help/index.vue
new file mode 100644
index 0000000..a6874d8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/help/index.vue
@@ -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.
+  -->
+
+<template>
+  <div class="help-content">
+    <section class="content">
+      <h2>{{$t('help.design_concept_title')}}</h2>
+      <ol>
+        <li>{{$t('help.design_concept_info_1')}}</li>
+        <li>{{$t('help.design_concept_info_2')}}</li>
+      </ol>
+      <h2>{{$t('help.major_features_title')}}</h2>
+      <ol>
+        <li>{{$t('help.major_features_info_1')}}</li>
+        <li>{{$t('help.major_features_info_2')}}</li>
+        <li>{{$t('help.major_features_info_3')}}</li>
+        <li>{{$t('help.major_features_info_4')}}</li>
+        <li>{{$t('help.major_features_info_5')}}</li>
+      </ol>
+      <h2>{{$t('help.unsupported_title')}}</h2>
+      <ol>
+        <li>{{$t('help.unsupported_info')}}</li>
+      </ol>
+    </section>
+  </div>
+</template>
+<style>
+  .help-content {
+    padding-top: 10px;
+  }
+  .help-content li {
+    list-style: inside;
+  }
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
index 14be74f..13669f8 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
@@ -36,20 +36,6 @@
         />
         <el-table-column :label="$t('registryCenter.table.operate')" fixed="right" width="200">
           <template slot-scope="scope">
-            <!--<el-tooltip
-              :content="$t('registryCenter.table.operateEdit')"
-              class="item"
-              effect="dark"
-              placement="top"
-            >
-              <el-button
-                :disabled="scope.row.activated"
-                size="small"
-                type="primary"
-                icon="el-icon-edit"
-                @click="handleEdit(scope.row)"
-              />
-            </el-tooltip>-->
             <el-tooltip
               :content="!scope.row.activated ? $t('registryCenter.table.operateConnect'): $t('registryCenter.table.operateConnected')"
               class="item"
@@ -98,12 +84,6 @@
         <el-form-item :label="$t('registryCenter.registDialog.name')" prop="name">
           <el-input :placeholder="$t('registryCenter.rules.name')" v-model="form.name" autocomplete="off" />
         </el-form-item>
-        <!--<el-form-item :label="$t('registryCenter.registDialog.centerType')" prop="instanceType">
-          <el-radio-group v-model="form.instanceType">
-            <el-radio label="Zookeeper">Zookeeper</el-radio>
-            <el-radio label="Etcd">Etcd</el-radio>
-          </el-radio-group>
-        </el-form-item>-->
         <el-form-item :label="$t('registryCenter.registDialog.address')" prop="serverLists">
           <el-input
             :placeholder="$t('registryCenter.rules.address')"
@@ -111,13 +91,6 @@
             autocomplete="off"
           />
         </el-form-item>
-        <!--<el-form-item :label="$t('registryCenter.registDialog.orchestrationName')" prop="orchestrationName">
-          <el-input
-            :placeholder="$t('registryCenter.rules.orchestrationName')"
-            v-model="form.orchestrationName"
-            autocomplete="off"
-          />
-        </el-form-item>-->
         <el-form-item :label="$t('registryCenter.registDialog.namespaces')" prop="namespace">
           <el-input
             :placeholder="$t('registryCenter.rules.namespaces')"
@@ -141,58 +114,6 @@
         >{{ $t("registryCenter.registDialog.btnConfirmTxt") }}</el-button>
       </div>
     </el-dialog>
-    <el-dialog
-      :title="$t('registryCenter.registDialog.editTitle')"
-      :visible.sync="editDialogVisible"
-      width="1010px"
-    >
-      <el-form ref="editForm" :model="editForm" :rules="rules" label-width="170px">
-        <el-form-item :label="$t('registryCenter.registDialog.name')" prop="name">
-          <el-input :placeholder="$t('registryCenter.rules.name')" v-model="editForm.name" autocomplete="off" />
-        </el-form-item>
-        <el-form-item :label="$t('registryCenter.registDialog.centerType')" prop="instanceType">
-          <el-radio-group v-model="editForm.instanceType">
-            <el-radio label="Zookeeper">Zookeeper</el-radio>
-            <el-radio label="Etcd">Etcd</el-radio>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item :label="$t('registryCenter.registDialog.address')" prop="serverLists">
-          <el-input
-            :placeholder="$t('registryCenter.rules.address')"
-            v-model="editForm.serverLists"
-            autocomplete="off"
-          />
-        </el-form-item>
-        <el-form-item :label="$t('registryCenter.registDialog.orchestrationName')" prop="orchestrationName">
-          <el-input
-            :placeholder="$t('registryCenter.rules.orchestrationName')"
-            v-model="editForm.orchestrationName"
-            autocomplete="off"
-          />
-        </el-form-item>
-        <el-form-item :label="$t('registryCenter.registDialog.namespaces')" prop="namespace">
-          <el-input
-            :placeholder="$t('registryCenter.rules.namespaces')"
-            v-model="editForm.namespace"
-            autocomplete="off"
-          />
-        </el-form-item>
-        <el-form-item :label="$t('registryCenter.registDialog.digest')">
-          <el-input
-            :placeholder="$t('registryCenter.rules.digest')"
-            v-model="editForm.digest"
-            autocomplete="off"
-          />
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button @click="cancelEdit">{{ $t("registryCenter.registDialog.btnCancelTxt") }}</el-button>
-        <el-button
-          type="primary"
-          @click="confirmEdit('editForm')"
-        >{{ $t("registryCenter.registDialog.btnConfirmTxt") }}</el-button>
-      </div>
-    </el-dialog>
   </el-row>
 </template>
 <script>
@@ -203,8 +124,7 @@ export default {
   name: 'RegistryCenter',
   data() {
     return {
-      regustDialogVisible: false,
-      editDialogVisible: false,
+      addDialogVisible: false,
       column: [
         {
           label: this.$t('registryCenter').registDialog.name,
@@ -223,19 +143,6 @@ export default {
         name: '',
         zkAddressList: '',
         namespace: '',
-        // instanceType: 'Zookeeper',
-        // orchestrationName: '',
-        // orchestrationType: 'registry_center',
-        digest: ''
-      },
-      editForm: {
-        primaryName: '',
-        name: '',
-        serverLists: '',
-        namespace: '',
-        instanceType: 'Zookeeper',
-        orchestrationName: '',
-        orchestrationType: 'registry_center',
         digest: ''
       },
       rules: {
@@ -343,7 +250,7 @@ export default {
       this.$refs[formName].validate(valid => {
         if (valid) {
           API.postRegCenter(this.form).then(res => {
-            this.regustDialogVisible = false
+            this.addDialogVisible = false
             this.$notify({
               title: this.$t('common').notify.title,
               message: this.$t('common').notify.addSucMessage,
@@ -358,33 +265,7 @@ export default {
       })
     },
     add() {
-      this.regustDialogVisible = true
-    },
-    handleEdit(row) {
-      this.editDialogVisible = true
-      this.editForm = Object.assign({}, row)
-      this.editForm.primaryName = row.name
-    },
-    confirmEdit(formName) {
-      this.$refs[formName].validate(valid => {
-        if (valid) {
-          API.updateRegCenter(this.editForm).then(res => {
-            this.editDialogVisible = false
-            this.$notify({
-              title: this.$t('common').notify.title,
-              message: this.$t('common').notify.editSucMessage,
-              type: 'success'
-            })
-            this.getRegCenter()
-          })
-        } else {
-          console.log('error submit!!')
-          return false
-        }
-      })
-    },
-    cancelEdit() {
-      this.editDialogVisible = false
+      this.addDialogVisible = true
     }
   }
 }


[shardingsphere-elasticjob-ui] 03/11: Merge pull request #1 from menghaoranss/ui-refactor

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit 9cfe6cf890ad95fc4bc6dd989bf7fce305be66f3
Merge: 5b41d49 61f0d23
Author: kimmking <ki...@163.com>
AuthorDate: Thu Jul 16 12:42:50 2020 +0800

    Merge pull request #1 from menghaoranss/ui-refactor
    
    UI refactor

 shardingsphere-elasticjob-ui-backend/pom.xml       |  93 ++++++++-
 .../shardingsphere/elasticjob/ui/Bootstrap.java    |  39 ++++
 .../ui/config/DynamicDataSourceConfig.java         | 116 +++++++++++
 .../elasticjob/ui/config/FilterConfiguration.java  |  73 +++++++
 .../config/advice/ConsoleRestControllerAdvice.java |  67 +++++++
 .../ui/dao/search/JobExecutionLogRepository.java   |  25 +++
 .../ui/dao/search/JobStatusTraceLogRepository.java |  25 +++
 .../JobRegisterStatisticsRepository.java           |  43 ++++
 .../statistics/JobRunningStatisticsRepository.java |  43 ++++
 .../ui/dao/statistics/StatisticInterval.java       |  37 ++++
 .../statistics/TaskResultStatisticsRepository.java |  55 ++++++
 .../TaskRunningStatisticsRepository.java           |  43 ++++
 .../type/job/JobExecutionTypeStatistics.java       |  33 ++++
 .../dao/statistics/type/job/JobTypeStatistics.java |  35 ++++
 .../elasticjob/ui/domain/DataSourceFactory.java    |  41 ++++
 .../elasticjob/ui/domain/EventTraceDataSource.java |  52 +++++
 .../domain/EventTraceDataSourceConfiguration.java  |  66 +++++++
 .../domain/EventTraceDataSourceConfigurations.java |  37 ++++
 .../ui/domain/EventTraceDataSourceFactory.java     |  66 +++++++
 .../elasticjob/ui/domain/GlobalConfiguration.java  |  39 ++++
 .../elasticjob/ui/domain/JobExecutionLog.java      |  86 ++++++++
 .../ui/domain/JobRegisterStatistics.java           |  59 ++++++
 .../elasticjob/ui/domain/JobRunningStatistics.java |  59 ++++++
 .../elasticjob/ui/domain/JobStatusTraceLog.java    |  86 ++++++++
 .../ui/domain/RegistryCenterConfiguration.java     |  56 ++++++
 .../ui/domain/RegistryCenterConfigurations.java    |  37 ++++
 .../elasticjob/ui/domain/TaskResultStatistics.java |  72 +++++++
 .../ui/domain/TaskRunningStatistics.java           |  59 ++++++
 .../elasticjob/ui/dto/request/BasePageRequest.java |  60 ++++++
 .../dto/request/FindJobExecutionEventsRequest.java |  76 ++++++++
 .../request/FindJobStatusTraceEventsRequest.java   |  63 ++++++
 .../ui/dto/response/BasePageResponse.java          |  65 ++++++
 .../ui/exception/JobConsoleException.java          |  45 +++++
 .../ui/repository/ConfigurationsXmlRepository.java |  26 +++
 .../elasticjob/ui/repository/XmlRepository.java    |  40 ++++
 .../repository/impl/AbstractXmlRepositoryImpl.java |  80 ++++++++
 .../impl/ConfigurationsXmlRepositoryImpl.java      |  31 +++
 .../ui/security/AuthenticationFilter.java          |  99 ++++++++++
 .../ui/security/AuthenticationResult.java          |  39 ++++
 .../elasticjob/ui/security/UserAccount.java        |  33 ++++
 .../ui/security/UserAuthenticationService.java     |  74 +++++++
 .../EventTraceDataSourceConfigurationService.java  |  75 +++++++
 .../ui/service/EventTraceHistoryService.java       |  46 +++++
 .../elasticjob/ui/service/JobAPIService.java       |  70 +++++++
 .../RegistryCenterConfigurationService.java        |  75 +++++++
 ...entTraceDataSourceConfigurationServiceImpl.java | 124 ++++++++++++
 .../service/impl/EventTraceHistoryServiceImpl.java | 132 +++++++++++++
 .../ui/service/impl/JobAPIServiceImpl.java         |  73 +++++++
 .../RegistryCenterConfigurationServiceImpl.java    | 113 +++++++++++
 .../elasticjob/ui/util/BeanUtils.java              |  56 ++++++
 .../elasticjob/ui/util/HomeFolderUtils.java        |  58 ++++++
 .../SessionEventTraceDataSourceConfiguration.java  |  42 ++++
 .../util/SessionRegistryCenterConfiguration.java   |  49 +++++
 .../controller/EventTraceDataSourceController.java | 138 +++++++++++++
 .../controller/EventTraceHistoryController.java    |  67 +++++++
 .../ui/web/controller/JobConfigController.java     |  77 ++++++++
 .../ui/web/controller/JobOperationController.java  | 139 +++++++++++++
 .../web/controller/RegistryCenterController.java   | 124 ++++++++++++
 .../web/controller/ServerOperationController.java  | 162 +++++++++++++++
 .../elasticjob/ui/web/filter/CORSFilter.java       |  60 ++++++
 .../elasticjob/ui/web/response/ResponseResult.java |  45 +++++
 .../ui/web/response/ResponseResultUtil.java        | 120 ++++++++++++
 .../src/main/resources/application.properties      |  15 +-
 .../ui/dao/search/RDBJobEventSearchTest.java       | 217 +++++++++++++++++++++
 .../search/RDBJobEventSearchTestConfiguration.java |  70 +++++++
 .../statistics/rdb/RDBStatisticRepositoryTest.java | 175 +++++++++++++++++
 .../elasticjob/ui/util/HomeFolderUtilsTest.java    |  35 ++++
 .../config/index.js                                |   2 +-
 .../src/lang/en-US.js                              |  37 ++--
 .../src/lang/zh-CN.js                              |  37 ++--
 70 files changed, 4672 insertions(+), 34 deletions(-)


[shardingsphere-elasticjob-ui] 09/11: Guest user just read only

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit 8d74d84cd29e7b1c7b47097726898e9fc02bce55
Author: menghaoranss <lo...@163.com>
AuthorDate: Fri Jul 17 18:38:39 2020 +0800

    Guest user just read only
---
 .../src/views/data-source/module/dataSource.vue                   | 4 ++++
 shardingsphere-elasticjob-ui-frontend/src/views/login/index.vue   | 5 +++--
 .../src/views/registry-center/module/registryCenter.vue           | 8 ++++++--
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue
index c9a9f6e..3da97a7 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue
@@ -23,6 +23,7 @@
         type="primary"
         icon="el-icon-plus"
         @click="add"
+        :disabled="isGuest"
       >{{ $t("dataSource.btnTxt") }}</el-button>
     </div>
     <div class="table-wrap">
@@ -46,6 +47,7 @@
                 type="primary"
                 icon="el-icon-link"
                 size="small"
+                :disabled="isGuest"
                 @click="handleConnect(scope.row)"
               />
             </el-tooltip>
@@ -59,6 +61,7 @@
                 size="small"
                 type="danger"
                 icon="el-icon-delete"
+                :disabled="isGuest"
                 @click="handlerDel(scope.row)"
               />
             </el-tooltip>
@@ -137,6 +140,7 @@ export default {
   data() {
     return {
       regustDialogVisible: false,
+      isGuest: window.localStorage.getItem('isGuest') == 'true',
       column: [
         {
           label: this.$t('dataSource').addDialog.name,
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/login/index.vue b/shardingsphere-elasticjob-ui-frontend/src/views/login/index.vue
index 644176c..03373ba 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/views/login/index.vue
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/login/index.vue
@@ -72,8 +72,8 @@ export default {
   data() {
     return {
       loginForm: {
-        username: 'admin',
-        password: 'admin'
+        username: '',
+        password: ''
       },
       loading: false,
       pwdType: 'password',
@@ -104,6 +104,7 @@ export default {
         const store = window.localStorage
         store.setItem('Access-Token', data.accessToken)
         store.setItem('username', data.username)
+        store.setItem('isGuest', data.isGuest)
         location.href = '#/registry-center'
       })
     }
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
index 13669f8..d762f6e 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
@@ -23,6 +23,7 @@
         type="primary"
         icon="el-icon-plus"
         @click="add"
+        :disabled="isGuest"
       >{{ $t("registryCenter.btnTxt") }}</el-button>
     </div>
     <div class="table-wrap">
@@ -47,6 +48,7 @@
                 icon="el-icon-link"
                 size="small"
                 @click="handleConnect(scope.row)"
+                :disabled="isGuest"
               />
             </el-tooltip>
             <el-tooltip
@@ -60,6 +62,7 @@
                 type="danger"
                 icon="el-icon-delete"
                 @click="handlerDel(scope.row)"
+                :disabled="isGuest"
               />
             </el-tooltip>
           </template>
@@ -77,14 +80,14 @@
     </div>
     <el-dialog
       :title="$t('registryCenter.registDialog.title')"
-      :visible.sync="regustDialogVisible"
+      :visible.sync="addDialogVisible"
       width="1010px"
     >
       <el-form ref="form" :model="form" :rules="rules" label-width="170px">
         <el-form-item :label="$t('registryCenter.registDialog.name')" prop="name">
           <el-input :placeholder="$t('registryCenter.rules.name')" v-model="form.name" autocomplete="off" />
         </el-form-item>
-        <el-form-item :label="$t('registryCenter.registDialog.address')" prop="serverLists">
+        <el-form-item :label="$t('registryCenter.registDialog.address')" prop="zkAddressList">
           <el-input
             :placeholder="$t('registryCenter.rules.address')"
             v-model="form.zkAddressList"
@@ -125,6 +128,7 @@ export default {
   data() {
     return {
       addDialogVisible: false,
+      isGuest: window.localStorage.getItem('isGuest') == 'true',
       column: [
         {
           label: this.$t('registryCenter').registDialog.name,


[shardingsphere-elasticjob-ui] 02/11: UI refactor

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit 61f0d2361dabca697d232ee041b6363b34d7245e
Author: menghaoranss <lo...@163.com>
AuthorDate: Thu Jul 16 12:37:31 2020 +0800

    UI refactor
---
 shardingsphere-elasticjob-ui-backend/pom.xml       |  93 ++++++++-
 .../shardingsphere/elasticjob/ui/Bootstrap.java    |  39 ++++
 .../ui/config/DynamicDataSourceConfig.java         | 116 +++++++++++
 .../elasticjob/ui/config/FilterConfiguration.java  |  73 +++++++
 .../config/advice/ConsoleRestControllerAdvice.java |  67 +++++++
 .../ui/dao/search/JobExecutionLogRepository.java   |  25 +++
 .../ui/dao/search/JobStatusTraceLogRepository.java |  25 +++
 .../JobRegisterStatisticsRepository.java           |  43 ++++
 .../statistics/JobRunningStatisticsRepository.java |  43 ++++
 .../ui/dao/statistics/StatisticInterval.java       |  37 ++++
 .../statistics/TaskResultStatisticsRepository.java |  55 ++++++
 .../TaskRunningStatisticsRepository.java           |  43 ++++
 .../type/job/JobExecutionTypeStatistics.java       |  33 ++++
 .../dao/statistics/type/job/JobTypeStatistics.java |  35 ++++
 .../elasticjob/ui/domain/DataSourceFactory.java    |  41 ++++
 .../elasticjob/ui/domain/EventTraceDataSource.java |  52 +++++
 .../domain/EventTraceDataSourceConfiguration.java  |  66 +++++++
 .../domain/EventTraceDataSourceConfigurations.java |  37 ++++
 .../ui/domain/EventTraceDataSourceFactory.java     |  66 +++++++
 .../elasticjob/ui/domain/GlobalConfiguration.java  |  39 ++++
 .../elasticjob/ui/domain/JobExecutionLog.java      |  86 ++++++++
 .../ui/domain/JobRegisterStatistics.java           |  59 ++++++
 .../elasticjob/ui/domain/JobRunningStatistics.java |  59 ++++++
 .../elasticjob/ui/domain/JobStatusTraceLog.java    |  86 ++++++++
 .../ui/domain/RegistryCenterConfiguration.java     |  56 ++++++
 .../ui/domain/RegistryCenterConfigurations.java    |  37 ++++
 .../elasticjob/ui/domain/TaskResultStatistics.java |  72 +++++++
 .../ui/domain/TaskRunningStatistics.java           |  59 ++++++
 .../elasticjob/ui/dto/request/BasePageRequest.java |  60 ++++++
 .../dto/request/FindJobExecutionEventsRequest.java |  76 ++++++++
 .../request/FindJobStatusTraceEventsRequest.java   |  63 ++++++
 .../ui/dto/response/BasePageResponse.java          |  65 ++++++
 .../ui/exception/JobConsoleException.java          |  45 +++++
 .../ui/repository/ConfigurationsXmlRepository.java |  26 +++
 .../elasticjob/ui/repository/XmlRepository.java    |  40 ++++
 .../repository/impl/AbstractXmlRepositoryImpl.java |  80 ++++++++
 .../impl/ConfigurationsXmlRepositoryImpl.java      |  31 +++
 .../ui/security/AuthenticationFilter.java          |  99 ++++++++++
 .../ui/security/AuthenticationResult.java          |  39 ++++
 .../elasticjob/ui/security/UserAccount.java        |  33 ++++
 .../ui/security/UserAuthenticationService.java     |  74 +++++++
 .../EventTraceDataSourceConfigurationService.java  |  75 +++++++
 .../ui/service/EventTraceHistoryService.java       |  46 +++++
 .../elasticjob/ui/service/JobAPIService.java       |  70 +++++++
 .../RegistryCenterConfigurationService.java        |  75 +++++++
 ...entTraceDataSourceConfigurationServiceImpl.java | 124 ++++++++++++
 .../service/impl/EventTraceHistoryServiceImpl.java | 132 +++++++++++++
 .../ui/service/impl/JobAPIServiceImpl.java         |  73 +++++++
 .../RegistryCenterConfigurationServiceImpl.java    | 113 +++++++++++
 .../elasticjob/ui/util/BeanUtils.java              |  56 ++++++
 .../elasticjob/ui/util/HomeFolderUtils.java        |  58 ++++++
 .../SessionEventTraceDataSourceConfiguration.java  |  42 ++++
 .../util/SessionRegistryCenterConfiguration.java   |  49 +++++
 .../controller/EventTraceDataSourceController.java | 138 +++++++++++++
 .../controller/EventTraceHistoryController.java    |  67 +++++++
 .../ui/web/controller/JobConfigController.java     |  77 ++++++++
 .../ui/web/controller/JobOperationController.java  | 139 +++++++++++++
 .../web/controller/RegistryCenterController.java   | 124 ++++++++++++
 .../web/controller/ServerOperationController.java  | 162 +++++++++++++++
 .../elasticjob/ui/web/filter/CORSFilter.java       |  60 ++++++
 .../elasticjob/ui/web/response/ResponseResult.java |  45 +++++
 .../ui/web/response/ResponseResultUtil.java        | 120 ++++++++++++
 .../src/main/resources/application.properties      |  15 +-
 .../ui/dao/search/RDBJobEventSearchTest.java       | 217 +++++++++++++++++++++
 .../search/RDBJobEventSearchTestConfiguration.java |  70 +++++++
 .../statistics/rdb/RDBStatisticRepositoryTest.java | 175 +++++++++++++++++
 .../elasticjob/ui/util/HomeFolderUtilsTest.java    |  35 ++++
 .../config/index.js                                |   2 +-
 .../src/lang/en-US.js                              |  37 ++--
 .../src/lang/zh-CN.js                              |  37 ++--
 70 files changed, 4672 insertions(+), 34 deletions(-)

diff --git a/shardingsphere-elasticjob-ui-backend/pom.xml b/shardingsphere-elasticjob-ui-backend/pom.xml
index 302129e..ac95197 100644
--- a/shardingsphere-elasticjob-ui-backend/pom.xml
+++ b/shardingsphere-elasticjob-ui-backend/pom.xml
@@ -25,9 +25,98 @@
     </parent>
     <artifactId>shardingsphere-elasticjob-ui-backend</artifactId>
     <name>${project.artifactId}</name>
-    
+
+    <properties>
+        <spring-boot.version>2.3.1.RELEASE</spring-boot.version>
+        <springframework.version>5.2.7.RELEASE</springframework.version>
+    </properties>
+
     <dependencies>
-        
+        <dependency>
+            <groupId>org.apache.shardingsphere.elasticjob</groupId>
+            <artifactId>elasticjob-lite-lifecycle</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${spring-boot.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <version>${springframework.version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+            <version>${springframework.version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <version>${springframework.version}</version>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-web</artifactId>
+                    <groupId>org.springframework</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>spring-context</artifactId>
+                    <groupId>org.springframework</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>log4j-over-slf4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-dbcp2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-dbcp</groupId>
+            <artifactId>commons-dbcp</artifactId>
+            <version>1.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
     
     <build>
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/Bootstrap.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/Bootstrap.java
new file mode 100644
index 0000000..3af08d0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/Bootstrap.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Console bootstrap.
+ */
+@SpringBootApplication
+public class Bootstrap {
+    
+    /**
+     * Startup RESTful server.
+     *
+     * @param args arguments
+     */
+    //CHECKSTYLE:OFF
+    public static void main(final String[] args) {
+    //CHECKSTYLE:ON
+        SpringApplication.run(Bootstrap.class, args);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/DynamicDataSourceConfig.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/DynamicDataSourceConfig.java
new file mode 100644
index 0000000..8e87862
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/DynamicDataSourceConfig.java
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.config;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Dynamic datasource config.
+ */
+@Configuration
+public class DynamicDataSourceConfig {
+    
+    public static final String DRIVER_CLASS_NAME = "spring.datasource.default.driver-class-name";
+    
+    public static final String DATASOURCE_URL = "spring.datasource.default.url";
+    
+    public static final String DATASOURCE_USERNAME = "spring.datasource.default.username";
+    
+    public static final String DATASOURCE_PASSWORD = "spring.datasource.default.password";
+    
+    public static final String DEFAULT_DATASOURCE_NAME = "default";
+    
+    /**
+     * Declare dynamicDataSource instead of default dataSource.
+     * @param environment spring environment
+     * @return A subClass of AbstractRoutingDataSource
+     */
+    @Bean(name = "dynamicDataSource")
+    @Primary
+    public DynamicDataSource dynamicDataSource(final Environment environment) {
+        DataSource defaultDataSource = createDefaultDataSource(environment);
+        DynamicDataSource dynamicDataSource = new DynamicDataSource();
+        dynamicDataSource.addDataSource(DEFAULT_DATASOURCE_NAME, defaultDataSource);
+        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
+        return dynamicDataSource;
+    }
+    
+    private DataSource createDefaultDataSource(final Environment environment) {
+        String driverName = environment.getProperty(DRIVER_CLASS_NAME);
+        String url = environment.getProperty(DATASOURCE_URL);
+        String username = environment.getProperty(DATASOURCE_USERNAME);
+        String password = environment.getProperty(DATASOURCE_PASSWORD);
+        return DataSourceBuilder.create().driverClassName(driverName).type(BasicDataSource.class).url(url)
+            .username(username).password(password).build();
+    }
+    
+    public static class DynamicDataSource extends AbstractRoutingDataSource {
+        
+        private final Map<Object, Object> dataSourceMap = new HashMap<>(10);
+        
+        @Override
+        protected Object determineCurrentLookupKey() {
+            return DynamicDataSourceContextHolder.getDataSourceName();
+        }
+        
+        /**
+         * Add a data source.
+         * 
+         * @param dataSourceName data source name
+         * @param dataSource data source
+         */
+        public void addDataSource(final String dataSourceName, final DataSource dataSource) {
+            dataSourceMap.put(dataSourceName, dataSource);
+            setTargetDataSources(dataSourceMap);
+            afterPropertiesSet();
+        }
+    }
+    
+    public static class DynamicDataSourceContextHolder {
+        
+        private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
+        
+        /**
+         * Get the specify dataSource.
+         * 
+         * @return data source name
+         */
+        public static String getDataSourceName() {
+            return CONTEXT_HOLDER.get();
+        }
+        
+        /**
+         * Specify a dataSource.
+         * 
+         * @param dataSourceName data source name
+         */
+        public static void setDataSourceName(final String dataSourceName) {
+            CONTEXT_HOLDER.set(dataSourceName);
+        }
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/FilterConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/FilterConfiguration.java
new file mode 100644
index 0000000..32f45b9
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/FilterConfiguration.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.config;
+
+import org.apache.shardingsphere.elasticjob.ui.security.AuthenticationFilter;
+import org.apache.shardingsphere.elasticjob.ui.security.UserAuthenticationService;
+import org.apache.shardingsphere.elasticjob.ui.web.filter.CORSFilter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Web filter configuration.
+ */
+@Configuration
+public class FilterConfiguration {
+    
+    @Autowired
+    private UserAuthenticationService userAuthenticationService;
+    
+    /**
+     * Register the CORS filter.
+     *
+     * @return filter registration bean
+     */
+    @Bean
+    public FilterRegistrationBean corsFilter() {
+        CORSFilter corsFilter = new CORSFilter();
+        FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
+        filterRegBean.setFilter(corsFilter);
+        List<String> urlPatterns = new ArrayList<>();
+        urlPatterns.add("/api/*");
+        filterRegBean.setUrlPatterns(urlPatterns);
+        return filterRegBean;
+    }
+    
+    /**
+     * Register the authentication filter.
+     *
+     * @return filter registration bean
+     */
+    @Bean
+    public FilterRegistrationBean authenticationFilter() {
+        AuthenticationFilter authenticationFilter = new AuthenticationFilter();
+        authenticationFilter.setUserAuthenticationService(userAuthenticationService);
+        FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
+        filterRegBean.setFilter(authenticationFilter);
+        List<String> urlPatterns = new ArrayList<>();
+        urlPatterns.add("/api/*");
+        filterRegBean.setUrlPatterns(urlPatterns);
+        return filterRegBean;
+    }
+    
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/advice/ConsoleRestControllerAdvice.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/advice/ConsoleRestControllerAdvice.java
new file mode 100644
index 0000000..e3e6898
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/advice/ConsoleRestControllerAdvice.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.config.advice;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.infra.exception.ExceptionUtils;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+/**
+ * Console rest controller advice.
+ **/
+@RestControllerAdvice
+@Slf4j
+public final class ConsoleRestControllerAdvice implements ResponseBodyAdvice<Object> {
+    
+    @Override
+    public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) {
+        //only advice return void method.
+        if (null == returnType.getMethod()) {
+            return false;
+        }
+        return void.class.isAssignableFrom(returnType.getMethod().getReturnType());
+    }
+    
+    @Override
+    public Object beforeBodyWrite(final Object body, final MethodParameter returnType, final MediaType selectedContentType,
+                                  final Class<? extends HttpMessageConverter<?>> selectedConverterType, final ServerHttpRequest request, final ServerHttpResponse response) {
+        //if the method return void, then the value is true and returns.
+        return null == body ? true : body;
+    }
+    
+    /**
+     * Handle exception.
+     *
+     * @param ex exception
+     * @return response result
+     */
+    @ExceptionHandler(Exception.class)
+    public ResponseEntity<String> toResponse(final Exception ex) {
+        log.error("CONSOLE ERROR", ex);
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ExceptionUtils.transform(ex));
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobExecutionLogRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobExecutionLogRepository.java
new file mode 100644
index 0000000..c27d2c1
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobExecutionLogRepository.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.search;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.JobExecutionLog;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface JobExecutionLogRepository extends JpaRepository<JobExecutionLog, String>, JpaSpecificationExecutor<JobExecutionLog> {
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobStatusTraceLogRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobStatusTraceLogRepository.java
new file mode 100644
index 0000000..ee451f0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobStatusTraceLogRepository.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.search;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.JobStatusTraceLog;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface JobStatusTraceLogRepository extends JpaRepository<JobStatusTraceLog, String>, JpaSpecificationExecutor<JobStatusTraceLog> {
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRegisterStatisticsRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRegisterStatisticsRepository.java
new file mode 100644
index 0000000..393bd89
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRegisterStatisticsRepository.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.JobRegisterStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Job register statistics repository.
+ */
+@Repository
+public interface JobRegisterStatisticsRepository extends JpaRepository<JobRegisterStatistics, Long> {
+    
+    /**
+     * Find job register statistics.
+     *
+     * @param fromTime from date to statistics
+     * @return job register statistics
+     */
+    @Query("FROM JobRegisterStatistics WHERE statisticsTime >= :fromTime")
+    List<JobRegisterStatistics> findJobRegisterStatistics(@Param("fromTime") Date fromTime);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRunningStatisticsRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRunningStatisticsRepository.java
new file mode 100644
index 0000000..a5b8a1d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRunningStatisticsRepository.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.JobRunningStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Job running statistics repository.
+ */
+@Repository
+public interface JobRunningStatisticsRepository extends JpaRepository<JobRunningStatistics, Long> {
+    
+    /**
+     * Find job running statistics.
+     *
+     * @param fromTime from date to statistics
+     * @return job running statistics
+     */
+    @Query("FROM JobRunningStatistics WHERE statisticsTime >= :fromTime")
+    List<JobRunningStatistics> findJobRunningStatistics(@Param("fromTime") Date fromTime);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/StatisticInterval.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/StatisticInterval.java
new file mode 100644
index 0000000..0322a03
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/StatisticInterval.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Statistic interval.
+ */
+@Getter
+@RequiredArgsConstructor
+public enum StatisticInterval {
+    
+    MINUTE("0 * * * * ?"),
+    
+    HOUR("0 0 * * * ?"), 
+    
+    DAY("0 0 0 * * ?");
+    
+    private final String cron;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskResultStatisticsRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskResultStatisticsRepository.java
new file mode 100644
index 0000000..248f027
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskResultStatisticsRepository.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.TaskResultStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Task result statistics repository.
+ */
+@Repository
+public interface TaskResultStatisticsRepository extends JpaRepository<TaskResultStatistics, Long> {
+    
+    /**
+     * Find task result statistics.
+     *
+     * @param fromTime from date to statistics
+     * @param statisticInterval statistic interval
+     * @return task result statistics
+     */
+    @Query("FROM TaskResultStatistics WHERE statisticInterval = :statisticInterval AND statisticsTime >= :fromTime ORDER BY id ASC")
+    List<TaskResultStatistics> findTaskResultStatistics(@Param("fromTime") Date fromTime, @Param("statisticInterval") String statisticInterval);
+    
+    /**
+     * Get summed task result statistics.
+     *
+     * @param fromTime from date to statistics
+     * @param statisticInterval statistic interval
+     * @return summed task result statistics
+     */
+    @Query("SELECT new TaskResultStatistics(SUM(successCount), SUM(failedCount)) FROM TaskResultStatistics WHERE "
+        + "statisticInterval = :statisticInterval AND statisticsTime >= :fromTime")
+    TaskResultStatistics getSummedTaskResultStatistics(@Param("fromTime") Date fromTime, @Param("statisticInterval") String statisticInterval);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskRunningStatisticsRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskRunningStatisticsRepository.java
new file mode 100644
index 0000000..328028c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskRunningStatisticsRepository.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.TaskRunningStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Task running statistics repository.
+ */
+@Repository
+public interface TaskRunningStatisticsRepository extends JpaRepository<TaskRunningStatistics, Long> {
+    
+    /**
+     * Find task running statistics.
+     *
+     * @param fromTime from date to statistics
+     * @return Task running statistics
+     */
+    @Query("FROM TaskRunningStatistics where statisticsTime >= :fromTime")
+    List<TaskRunningStatistics> findTaskRunningStatistics(@Param("fromTime") Date fromTime);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobExecutionTypeStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobExecutionTypeStatistics.java
new file mode 100644
index 0000000..8aace8d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobExecutionTypeStatistics.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics.type.job;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * Job execution type statistics.
+ */
+@Getter
+@AllArgsConstructor
+public final class JobExecutionTypeStatistics {
+    
+    private int transientJobCount;
+    
+    private int daemonJobCount;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobTypeStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobTypeStatistics.java
new file mode 100644
index 0000000..1a9a00c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobTypeStatistics.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics.type.job;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * Job type statistics.
+ */
+@Getter
+@AllArgsConstructor
+public final class JobTypeStatistics {
+    
+    private int scriptJobCount;
+    
+    private int simpleJobCount;
+    
+    private int dataflowJobCount;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/DataSourceFactory.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/DataSourceFactory.java
new file mode 100644
index 0000000..d7abd7b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/DataSourceFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+
+import javax.sql.DataSource;
+
+/**
+ * Dynamic data source factory.
+ */
+public final class DataSourceFactory {
+    
+    /**
+     * Create a DataSource.
+     * @param config event trace data source config
+     * @return data source
+     */
+    public static DataSource createDataSource(final EventTraceDataSourceConfiguration config) {
+        // Determine whether the data source is valid.
+        new EventTraceDataSource(config).init();
+        return DataSourceBuilder.create().type(BasicDataSource.class).driverClassName(config.getDriver()).url(config.getUrl())
+            .username(config.getUsername()).password(config.getPassword()).build();
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSource.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSource.java
new file mode 100644
index 0000000..bc0cad0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSource.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * Event tracing data source.
+ */
+@Slf4j
+public final class EventTraceDataSource {
+    
+    @Getter(AccessLevel.PROTECTED)
+    private EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration;
+    
+    public EventTraceDataSource(final EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration) {
+        this.eventTraceDataSourceConfiguration = eventTraceDataSourceConfiguration;
+    }
+    
+    /**
+     * Initialize data source.
+     */
+    public void init() {
+        log.debug("Elastic job: data source init, connection url is: {}.", eventTraceDataSourceConfiguration.getUrl());
+        try {
+            Class.forName(eventTraceDataSourceConfiguration.getDriver());
+            DriverManager.getConnection(eventTraceDataSourceConfiguration.getUrl(), eventTraceDataSourceConfiguration.getUsername(), eventTraceDataSourceConfiguration.getPassword());
+        } catch (final ClassNotFoundException | SQLException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfiguration.java
new file mode 100644
index 0000000..dc683f7
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfiguration.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * Event trace data source configuration.
+ */
+@NoArgsConstructor
+@Getter
+@Setter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public final class EventTraceDataSourceConfiguration implements Serializable {
+    
+    private static final long serialVersionUID = -5996257770767863699L;
+    
+    @XmlAttribute(required = true)
+    private String name;
+    
+    @XmlAttribute(required = true)
+    private String driver;
+    
+    @XmlAttribute
+    private String url;
+    
+    @XmlAttribute
+    private String username;
+    
+    @XmlAttribute
+    private String password;
+    
+    @XmlAttribute
+    private boolean activated;
+    
+    public EventTraceDataSourceConfiguration(final String driver, final String url, final String username, final String password) {
+        this.driver = driver;
+        this.url = url;
+        this.username = username;
+        this.password = password;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfigurations.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfigurations.java
new file mode 100644
index 0000000..9250f7f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfigurations.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Event trace data source configurations.
+ */
+@Getter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public final class EventTraceDataSourceConfigurations {
+    
+    private Set<EventTraceDataSourceConfiguration> eventTraceDataSourceConfiguration = new LinkedHashSet<>();
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceFactory.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceFactory.java
new file mode 100644
index 0000000..36fc116
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceFactory.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Strings;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Event trace data source factory.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class EventTraceDataSourceFactory {
+    
+    private static final ConcurrentHashMap<HashCode, EventTraceDataSource> DATA_SOURCE_REGISTRY = new ConcurrentHashMap<>();
+    
+    /**
+     * Create event trace data source.
+     * 
+     * @param driverClassName database driver class name
+     * @param url database URL
+     * @param username database username
+     * @param password database password
+     * @return event trace data source
+     */
+    public static EventTraceDataSource createEventTraceDataSource(final String driverClassName, final String url, final String username, final String password) {
+        Hasher hasher = Hashing.sha256().newHasher().putString(driverClassName, Charsets.UTF_8).putString(url, Charsets.UTF_8);
+        if (!Strings.isNullOrEmpty(username)) {
+            hasher.putString(username, Charsets.UTF_8);
+        }
+        if (null != password) {
+            hasher.putString(password, Charsets.UTF_8);
+        }
+        HashCode hashCode = hasher.hash();
+        EventTraceDataSource result = DATA_SOURCE_REGISTRY.get(hashCode);
+        if (null != result) {
+            return result;
+        }
+        EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration = new EventTraceDataSourceConfiguration(driverClassName, url, username, password);
+        result = new EventTraceDataSource(eventTraceDataSourceConfiguration);
+        result.init();
+        DATA_SOURCE_REGISTRY.put(hashCode, result);
+        return result;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/GlobalConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/GlobalConfiguration.java
new file mode 100644
index 0000000..273a90d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/GlobalConfiguration.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Global configuration.
+ */
+@Getter
+@Setter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public final class GlobalConfiguration {
+    
+    private RegistryCenterConfigurations registryCenterConfigurations;
+    
+    private EventTraceDataSourceConfigurations eventTraceDataSourceConfigurations;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobExecutionLog.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobExecutionLog.java
new file mode 100644
index 0000000..ce98008
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobExecutionLog.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Data;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.Date;
+
+@Data
+@Entity(name = "JOB_EXECUTION_LOG")
+public class JobExecutionLog {
+    
+    @Id
+    private String id;
+    
+    @Column(name = "job_name")
+    private String jobName;
+    
+    @Column(name = "task_id")
+    private String taskId;
+    
+    @Column(name = "hostname")
+    private String hostname;
+    
+    @Column(name = "ip")
+    private String ip;
+    
+    @Column(name = "sharding_item")
+    private Integer shardingItem;
+    
+    @Column(name = "execution_source")
+    private String executionSource;
+    
+    @Column(name = "failure_cause")
+    private String failureCause;
+    
+    @Column(name = "is_success")
+    private Boolean isSuccess;
+    
+    @Column(name = "start_time")
+    private Date startTime;
+    
+    @Column(name = "complete_time")
+    private Date completeTime;
+    
+    /**
+     * JobExecutionLog convert to JobExecutionEvent.
+     *
+     * @return JobExecutionEvent entity
+     */
+    public JobExecutionEvent toJobExecutionEvent() {
+        return new JobExecutionEvent(
+                id,
+                hostname,
+                ip,
+                taskId,
+                jobName,
+                JobExecutionEvent.ExecutionSource.valueOf(executionSource),
+                shardingItem,
+                startTime,
+                completeTime,
+                isSuccess,
+                failureCause
+        );
+    }
+    
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRegisterStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRegisterStatistics.java
new file mode 100644
index 0000000..62f3713
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRegisterStatistics.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * Job register statistics.
+ */
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "JOB_REGISTER_STATISTICS")
+public final class JobRegisterStatistics {
+    
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+    
+    @Column(name = "registered_count", length = 11)
+    private Integer registeredCount;
+    
+    @Column(name = "statistics_time", nullable = false)
+    private Date statisticsTime;
+    
+    @Column(name = "creation_time", nullable = false)
+    private Date creationTime = new Date();
+    
+    public JobRegisterStatistics(final Integer registeredCount, final Date statisticsTime) {
+        this.registeredCount = registeredCount;
+        this.statisticsTime = statisticsTime;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRunningStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRunningStatistics.java
new file mode 100644
index 0000000..e8e5eea
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRunningStatistics.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * Job running statistics.
+ */
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "JOB_RUNNING_STATISTICS")
+public final class JobRunningStatistics {
+    
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+    
+    @Column(name = "running_count", length = 11)
+    private Integer runningCount;
+    
+    @Column(name = "statistics_time", nullable = false)
+    private Date statisticsTime;
+    
+    @Column(name = "creation_time", nullable = false)
+    private Date creationTime = new Date();
+    
+    public JobRunningStatistics(final Integer runningCount, final Date statisticsTime) {
+        this.runningCount = runningCount;
+        this.statisticsTime = statisticsTime;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobStatusTraceLog.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobStatusTraceLog.java
new file mode 100644
index 0000000..7803e09
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobStatusTraceLog.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Data;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.Date;
+
+@Data
+@Entity(name = "JOB_STATUS_TRACE_LOG")
+public class JobStatusTraceLog {
+    
+    @Id
+    private String id;
+    
+    @Column(name = "job_name")
+    private String jobName;
+    
+    @Column(name = "original_task_id")
+    private String originalTaskId;
+    
+    @Column(name = "task_id")
+    private String taskId;
+    
+    @Column(name = "slave_id")
+    private String slaveId;
+    
+    @Column(name = "source")
+    private String source;
+    
+    @Column(name = "execution_type")
+    private String executionType;
+    
+    @Column(name = "sharding_item")
+    private String shardingItem;
+    
+    @Column(name = "state")
+    private String state;
+    
+    @Column(name = "message")
+    private String message;
+    
+    @Column(name = "creation_time")
+    private Date creationTime;
+    
+    /**
+     * JobStatusTraceLog convert to JobStatusTraceEvent.
+     *
+     * @return JobStatusTraceEvent entity
+     */
+    public JobStatusTraceEvent toJobStatusTraceEvent() {
+        return new JobStatusTraceEvent(
+                id,
+                jobName,
+                originalTaskId,
+                taskId,
+                slaveId,
+                JobStatusTraceEvent.Source.valueOf(source),
+                executionType,
+                shardingItem,
+                JobStatusTraceEvent.State.valueOf(state),
+                message,
+                creationTime
+        );
+    }
+    
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfiguration.java
new file mode 100644
index 0000000..6f46434
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfiguration.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * Registry center configuration.
+ */
+@Getter
+@Setter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+@NoArgsConstructor
+public final class RegistryCenterConfiguration implements Serializable {
+    
+    private static final long serialVersionUID = -5996257770767863699L;
+    
+    @XmlAttribute(required = true)
+    private String name;
+    
+    @XmlAttribute(required = true)
+    private String zkAddressList;
+    
+    @XmlAttribute
+    private String namespace;
+    
+    @XmlAttribute
+    private String digest;
+    
+    @XmlAttribute
+    private boolean activated;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfigurations.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfigurations.java
new file mode 100644
index 0000000..403d29f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfigurations.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Registry center configurations.
+ */
+@Getter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public final class RegistryCenterConfigurations {
+    
+    private Set<RegistryCenterConfiguration> registryCenterConfiguration = new LinkedHashSet<>();
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskResultStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskResultStatistics.java
new file mode 100644
index 0000000..e0006d8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskResultStatistics.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * Task result statistics.
+ */
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Table(name = "TASK_RESULT_STATISTICS")
+public final class TaskResultStatistics {
+    
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+    
+    @Column(name = "success_count", length = 11)
+    private Long successCount;
+    
+    @Column(name = "failed_count", length = 11)
+    private Long failedCount;
+    
+    @Column(name = "statistic_interval", length = 10)
+    private String statisticInterval;
+    
+    @Column(name = "statistics_time", nullable = false)
+    private Date statisticsTime;
+    
+    @Column(name = "creation_time", nullable = false)
+    private Date creationTime = new Date();
+    
+    public TaskResultStatistics(final Long successCount, final Long failedCount) {
+        this.successCount = successCount;
+        this.failedCount = failedCount;
+    }
+    
+    public TaskResultStatistics(final Long successCount, final Long failedCount, final String statisticInterval, final Date statisticsTime) {
+        this.successCount = successCount;
+        this.failedCount = failedCount;
+        this.statisticInterval = statisticInterval;
+        this.statisticsTime = statisticsTime;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskRunningStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskRunningStatistics.java
new file mode 100644
index 0000000..638ff6c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskRunningStatistics.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * Task running statistics.
+ */
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "TASK_RUNNING_STATISTICS")
+public final class TaskRunningStatistics {
+    
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+    
+    @Column(name = "running_count", length = 11)
+    private Integer runningCount;
+    
+    @Column(name = "statistics_time", nullable = false)
+    private Date statisticsTime;
+    
+    @Column(name = "creation_time", nullable = false)
+    private Date creationTime = new Date();
+    
+    public TaskRunningStatistics(final Integer runningCount, final Date statisticsTime) {
+        this.runningCount = runningCount;
+        this.statisticsTime = statisticsTime;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/BasePageRequest.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/BasePageRequest.java
new file mode 100644
index 0000000..2358c03
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/BasePageRequest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dto.request;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Pageable request base request.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class BasePageRequest {
+    
+    public static final int DEFAULT_PAGE_SIZE = 10;
+    
+    /**
+     * Page size of request.
+     */
+    @JsonProperty("per_page")
+    private Integer pageSize = DEFAULT_PAGE_SIZE;
+    
+    /**
+     * Page number of request.
+     */
+    @JsonProperty("page")
+    private Integer pageNumber = 1;
+    
+    /**
+     * The field name for sort by.
+     */
+    @JsonProperty("sort")
+    private String sortBy;
+    
+    /**
+     * Order type, asc or desc.
+     */
+    @JsonProperty("order")
+    private String orderType;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobExecutionEventsRequest.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobExecutionEventsRequest.java
new file mode 100644
index 0000000..c937059
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobExecutionEventsRequest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dto.request;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * Request object of uri '/event-trace/execution'.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class FindJobExecutionEventsRequest extends BasePageRequest {
+    
+    private String jobName;
+    
+    private String ip;
+    
+    private Boolean isSuccess;
+    
+    @JsonProperty("startTime")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date start;
+    
+    @JsonProperty("endTime")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date end;
+    
+    /**
+     * Create new FindJobExecutionEventsRequest with pageSize and pageNumber.
+     * @param pageNumber page number
+     * @param pageSize page size
+     */
+    public FindJobExecutionEventsRequest(final Integer pageSize, final Integer pageNumber) {
+        super(pageSize, pageNumber, null, null);
+    }
+    
+    /**
+     * Create new FindJobExecutionEventsRequest with properties.
+     * @param pageNumber page number
+     * @param pageSize page size
+     * @param sortBy the field name sort by
+     * @param orderType order type, asc or desc
+     * @param startTime start time
+     * @param endTime end time
+     */
+    public FindJobExecutionEventsRequest(final Integer pageSize, final Integer pageNumber, final String sortBy,
+                                         final String orderType, final Date startTime, final Date endTime) {
+        super(pageSize, pageNumber, sortBy, orderType);
+        this.start = startTime;
+        this.end = endTime;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobStatusTraceEventsRequest.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobStatusTraceEventsRequest.java
new file mode 100644
index 0000000..f10e0e6
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobStatusTraceEventsRequest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dto.request;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * Request object of uri '/event-trace/status'.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class FindJobStatusTraceEventsRequest extends BasePageRequest {
+    
+    private String jobName;
+    
+    private String source;
+    
+    private String executionType;
+    
+    private String state;
+    
+    @JsonProperty("startTime")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date start;
+    
+    @JsonProperty("endTime")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date end;
+    
+    public FindJobStatusTraceEventsRequest(final Integer pageSize, final Integer pageNumber) {
+        super(pageSize, pageNumber, null, null);
+    }
+    
+    public FindJobStatusTraceEventsRequest(final Integer pageSize, final Integer pageNumber, final String sortBy, final String orderType, final Date startTime, final Date endTime) {
+        super(pageSize, pageNumber, sortBy, orderType);
+        this.start = startTime;
+        this.end = endTime;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/response/BasePageResponse.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/response/BasePageResponse.java
new file mode 100644
index 0000000..fdfd767
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/response/BasePageResponse.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dto.response;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.springframework.data.domain.Page;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BasePageResponse<T> implements Serializable {
+    
+    /**
+     * Total count of rows.
+     */
+    private Long total;
+    
+    /**
+     * Rows data.
+     */
+    private List<T> rows;
+    
+    /**
+     * Create new BasePageResponse with total and data.
+     * @param total Total count of match data
+     * @param data Current page of data
+     * @param <T> Data type
+     * @return BasePageResponse
+     */
+    public static <T> BasePageResponse of(final Long total, final List<T> data) {
+        return new BasePageResponse(total, data);
+    }
+    
+    /**
+     * Create new BasePageResponse with Page.
+     * @param page match data info.
+     * @param <T> Data type
+     * @return BasePageResponse
+     */
+    public static <T> BasePageResponse of(final Page<T> page) {
+        return new BasePageResponse(page.getTotalElements(), page.getContent());
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/exception/JobConsoleException.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/exception/JobConsoleException.java
new file mode 100644
index 0000000..d2c0f29
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/exception/JobConsoleException.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.exception;
+
+import lombok.Getter;
+
+/**
+ * Job console exception.
+ */
+@Getter
+public final class JobConsoleException extends RuntimeException {
+    
+    private static final long serialVersionUID = 1393957353478034407L;
+    
+    public static final int INVALID_PARAM = 400;
+    
+    public static final int NO_RIGHT = 403;
+    
+    public static final int SERVER_ERROR = 500;
+    
+    private final int errorCode;
+    
+    private final String errorMessage;
+    
+    public JobConsoleException(final int errorCode, final String errorMessage) {
+        super(errorMessage);
+        this.errorCode = errorCode;
+        this.errorMessage = errorMessage;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/ConfigurationsXmlRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/ConfigurationsXmlRepository.java
new file mode 100644
index 0000000..c9e644c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/ConfigurationsXmlRepository.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.repository;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.GlobalConfiguration;
+
+/**
+ * Configurations XML repository.
+ */
+public interface ConfigurationsXmlRepository extends XmlRepository<GlobalConfiguration> {
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/XmlRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/XmlRepository.java
new file mode 100644
index 0000000..e8f0caf
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/XmlRepository.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.repository;
+
+/**
+ * XML repository.
+ *
+ * @param <E> type of data
+ */
+public interface XmlRepository<E> {
+    
+    /**
+     * Load data.
+     * 
+     * @return load result
+     */
+    E load();
+    
+    /**
+     * Save data.
+     * 
+     * @param entity entity
+     */
+    void save(E entity);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/AbstractXmlRepositoryImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/AbstractXmlRepositoryImpl.java
new file mode 100644
index 0000000..fcb9247
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/AbstractXmlRepositoryImpl.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.repository.impl;
+
+import org.apache.shardingsphere.elasticjob.ui.exception.JobConsoleException;
+import org.apache.shardingsphere.elasticjob.ui.repository.XmlRepository;
+import org.apache.shardingsphere.elasticjob.ui.util.HomeFolderUtils;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import java.io.File;
+
+/**
+ * Abstract XML repository implementation.
+ *
+ * @param <E> type of data
+ */
+public abstract class AbstractXmlRepositoryImpl<E> implements XmlRepository<E> {
+    
+    private final File file;
+    
+    private final Class<E> clazz;
+    
+    private JAXBContext jaxbContext;
+    
+    protected AbstractXmlRepositoryImpl(final String fileName, final Class<E> clazz) {
+        file = new File(HomeFolderUtils.getFilePathInHomeFolder(fileName));
+        this.clazz = clazz;
+        HomeFolderUtils.createHomeFolderIfNotExisted();
+        try {
+            jaxbContext = JAXBContext.newInstance(clazz);
+        } catch (final JAXBException ex) {
+            throw new JobConsoleException(JobConsoleException.SERVER_ERROR, ex.getMessage());
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized E load() {
+        if (!file.exists()) {
+            try {
+                return clazz.newInstance();
+            } catch (final InstantiationException | IllegalAccessException ex) {
+                throw new JobConsoleException(JobConsoleException.SERVER_ERROR, ex.getMessage());
+            }
+        }
+        try {
+            return (E) jaxbContext.createUnmarshaller().unmarshal(file);
+        } catch (final JAXBException ex) {
+            throw new JobConsoleException(JobConsoleException.SERVER_ERROR, ex.getMessage());
+        }
+    }
+    
+    @Override
+    public synchronized void save(final E entity) {
+        try {
+            Marshaller marshaller = jaxbContext.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            marshaller.marshal(entity, file);
+        } catch (final JAXBException ex) {
+            throw new JobConsoleException(JobConsoleException.SERVER_ERROR, ex.getMessage());
+        }
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/ConfigurationsXmlRepositoryImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/ConfigurationsXmlRepositoryImpl.java
new file mode 100644
index 0000000..5b4b64e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/ConfigurationsXmlRepositoryImpl.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.repository.impl;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.GlobalConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.repository.ConfigurationsXmlRepository;
+
+/**
+ * Configurations XML repository implementation.
+ */
+public final class ConfigurationsXmlRepositoryImpl extends AbstractXmlRepositoryImpl<GlobalConfiguration> implements ConfigurationsXmlRepository {
+    
+    public ConfigurationsXmlRepositoryImpl() {
+        super("Configurations.xml", GlobalConfiguration.class);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationFilter.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationFilter.java
new file mode 100644
index 0000000..a892759
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationFilter.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.security;
+
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import lombok.Setter;
+import org.apache.shardingsphere.elasticjob.ui.web.response.ResponseResultUtil;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Authentication filter.
+ */
+public final class AuthenticationFilter implements Filter {
+    
+    private static final String LOGIN_URI = "/api/login";
+    
+    private final Gson gson = new Gson();
+    
+    @Setter
+    private UserAuthenticationService userAuthenticationService;
+    
+    @Override
+    public void init(final FilterConfig filterConfig) {
+    }
+    
+    @Override
+    public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
+        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
+        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
+        if (LOGIN_URI.equals(httpRequest.getRequestURI())) {
+            handleLogin(httpRequest, httpResponse);
+        } else {
+            String accessToken = httpRequest.getHeader("Access-Token");
+            if (!Strings.isNullOrEmpty(accessToken) && accessToken.equals(userAuthenticationService.getToken())) {
+                filterChain.doFilter(httpRequest, httpResponse);
+            } else {
+                respondWithUnauthorized(httpResponse);
+            }
+        }
+    }
+    
+    @Override
+    public void destroy() {
+    }
+    
+    private void handleLogin(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse) {
+        try {
+            UserAccount user = gson.fromJson(httpRequest.getReader(), UserAccount.class);
+            AuthenticationResult authenticationResult = userAuthenticationService.checkUser(user);
+            if (null != authenticationResult && authenticationResult.isSuccess()) {
+                httpResponse.setContentType("application/json");
+                httpResponse.setCharacterEncoding("UTF-8");
+                Map<String, Object> result = new HashMap<>();
+                result.put("username", authenticationResult.getUsername());
+                result.put("accessToken", userAuthenticationService.getToken());
+                result.put("isGuest", authenticationResult.isGuest());
+                httpResponse.getWriter().write(gson.toJson(ResponseResultUtil.build(result)));
+            } else {
+                respondWithUnauthorized(httpResponse);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        
+    }
+    
+    private void respondWithUnauthorized(final HttpServletResponse httpResponse) throws IOException {
+        httpResponse.setContentType("application/json");
+        httpResponse.setCharacterEncoding("UTF-8");
+        httpResponse.getWriter().write(new Gson().toJson(ResponseResultUtil.handleUnauthorizedException("Unauthorized.")));
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationResult.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationResult.java
new file mode 100644
index 0000000..8758f43
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationResult.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.security;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Authentication result.
+ **/
+@Getter
+@RequiredArgsConstructor
+public final class AuthenticationResult {
+    
+    private final String username;
+
+    private final String password;
+    
+    private final boolean success;
+    
+    private final boolean isGuest;
+    
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAccount.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAccount.java
new file mode 100644
index 0000000..3fe02f3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAccount.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.security;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * User account.
+ */
+@Getter
+@Setter
+public final class UserAccount {
+    
+    private String username;
+    
+    private String password;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAuthenticationService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAuthenticationService.java
new file mode 100644
index 0000000..b41d7d3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAuthenticationService.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.security;
+
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import lombok.Setter;
+import org.apache.commons.codec.binary.Base64;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * User authentication service.
+ */
+@Component
+@ConfigurationProperties(prefix = "auth")
+@Setter
+public final class UserAuthenticationService {
+    
+    private String rootUsername;
+    
+    private String rootPassword;
+    
+    private String guestUsername;
+    
+    private String guestPassword;
+    
+    private final Base64 base64 = new Base64();
+    
+    private Gson gson = new Gson();
+    
+    /**
+     * Check user.
+     *
+     * @param userAccount user account
+     * @return check success or failure
+     */
+    public AuthenticationResult checkUser(final UserAccount userAccount) {
+        if (null == userAccount || Strings.isNullOrEmpty(userAccount.getUsername()) || Strings.isNullOrEmpty(userAccount.getPassword())) {
+            return new AuthenticationResult(null, null, false, false);
+        }
+        if (rootUsername.equals(userAccount.getUsername()) && rootPassword.equals(userAccount.getPassword())) {
+            return new AuthenticationResult(rootUsername, rootPassword, true, false);
+        }
+        if (guestUsername.equals(userAccount.getUsername()) && guestPassword.equals(userAccount.getPassword())) {
+            return new AuthenticationResult(guestUsername, guestPassword, true, true);
+        }
+        return new AuthenticationResult(null ,null, false, false);
+    }
+    
+    /**
+     * Get user authentication token.
+     *
+     * @return authentication token
+     */
+    public String getToken() {
+        return base64.encodeToString(gson.toJson(this).getBytes());
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceDataSourceConfigurationService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceDataSourceConfigurationService.java
new file mode 100644
index 0000000..0135623
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceDataSourceConfigurationService.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfigurations;
+
+import java.util.Optional;
+
+/**
+ * Event trace data source configuration service.
+ */
+public interface EventTraceDataSourceConfigurationService {
+    
+    /**
+     * Load all event trace data source configurations.
+     *
+     * @return all event trace data source configuration
+     */
+    EventTraceDataSourceConfigurations loadAll();
+    
+    /**
+     * Load event trace data source configuration.
+     * 
+     * @param name name of event trace data source configuration
+     * @return event trace data source configuration
+     */
+    EventTraceDataSourceConfiguration load(String name);
+    
+    /**
+     * Find event trace data source configuration.
+     *
+     * @param name name of event trace data source configuration
+     * @param configs event trace data source configurations
+     * @return event trace data source configuration
+     */
+    EventTraceDataSourceConfiguration find(String name, EventTraceDataSourceConfigurations configs);
+    
+    /**
+     * Load activated event trace data source configuration.
+     * 
+     * @return activated event trace data source configuration
+     */
+    Optional<EventTraceDataSourceConfiguration> loadActivated();
+    
+    /**
+     * Add event trace data source configuration.
+     * 
+     * @param config event trace data source configuration
+     * @return success to add or not
+     */
+    boolean add(EventTraceDataSourceConfiguration config);
+    
+    /**
+     * Delete event trace data source configuration.
+     *
+     * @param name name of event trace data source configuration
+     */
+    void delete(String name);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceHistoryService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceHistoryService.java
new file mode 100644
index 0000000..9a64552
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceHistoryService.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service;
+
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.springframework.data.domain.Page;
+
+/**
+ * Event trace history service.
+ */
+public interface EventTraceHistoryService {
+    
+    /**
+     * Find job execution events.
+     *
+     * @param findJobExecutionEventsRequest query params
+     * @return job execution events
+     */
+    Page<JobExecutionEvent> findJobExecutionEvents(FindJobExecutionEventsRequest findJobExecutionEventsRequest);
+    
+    /**
+     * Find job status trace events.
+     *
+     * @param findJobStatusTraceEventsRequest query params
+     * @return job status trace events
+     */
+    Page<JobStatusTraceEvent> findJobStatusTraceEvents(FindJobStatusTraceEventsRequest findJobStatusTraceEventsRequest);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/JobAPIService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/JobAPIService.java
new file mode 100644
index 0000000..01008f5
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/JobAPIService.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobConfigurationAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobOperateAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ServerStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ShardingOperateAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ShardingStatisticsAPI;
+
+public interface JobAPIService {
+    
+    /**
+     * Job configuration API.
+     *
+     * @return job configuration API
+     */
+    JobConfigurationAPI getJobConfigurationAPI();
+    
+    /**
+     * Job operate API.
+     *
+     * @return Job operate API
+     */
+    JobOperateAPI getJobOperatorAPI();
+    
+    /**
+     * Sharding operate API.
+     *
+     * @return sharding operate API
+     */
+    ShardingOperateAPI getShardingOperateAPI();
+    
+    /**
+     * Job statistics API.
+     *
+     * @return job statistics API
+     */
+    JobStatisticsAPI getJobStatisticsAPI();
+    
+    /**
+     * Servers statistics API.
+     *
+     * @return server statistics API
+     */
+    ServerStatisticsAPI getServerStatisticsAPI();
+    
+    /**
+     * Sharding statistics API.
+     *
+     * @return sharding statistics API
+     */
+    ShardingStatisticsAPI getShardingStatisticsAPI();
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/RegistryCenterConfigurationService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/RegistryCenterConfigurationService.java
new file mode 100644
index 0000000..9aad0d8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/RegistryCenterConfigurationService.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfigurations;
+
+import java.util.Optional;
+
+/**
+ * Registry center configuration service.
+ */
+public interface RegistryCenterConfigurationService {
+    
+    /**
+     * Load all registry center configurations.
+     *
+     * @return all registry center configurations
+     */
+    RegistryCenterConfigurations loadAll();
+    
+    /**
+     * Load registry center configuration.
+     *
+     * @param name name of registry center configuration
+     * @return registry center configuration
+     */
+    RegistryCenterConfiguration load(String name);
+    
+    /**
+     * Find registry center configuration.
+     * 
+     * @param name name of registry center configuration
+     * @param configs registry center configurations
+     * @return registry center configuration
+     */
+    RegistryCenterConfiguration find(String name, RegistryCenterConfigurations configs);
+    
+    /**
+     * Load activated registry center configuration.
+     *
+     * @return activated registry center configuration
+     */
+    Optional<RegistryCenterConfiguration> loadActivated();
+    
+    /**
+     * Add registry center configuration.
+     *
+     * @param config registry center configuration
+     * @return success to add or not
+     */
+    boolean add(RegistryCenterConfiguration config);
+    
+    /**
+     * Delete registry center configuration.
+     *
+     * @param name name of registry center configuration
+     */
+    void delete(String name);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceDataSourceConfigurationServiceImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceDataSourceConfigurationServiceImpl.java
new file mode 100644
index 0000000..b3a80d9
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceDataSourceConfigurationServiceImpl.java
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service.impl;
+
+import org.apache.shardingsphere.elasticjob.ui.config.DynamicDataSourceConfig;
+import org.apache.shardingsphere.elasticjob.ui.domain.DataSourceFactory;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfigurations;
+import org.apache.shardingsphere.elasticjob.ui.domain.GlobalConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.repository.ConfigurationsXmlRepository;
+import org.apache.shardingsphere.elasticjob.ui.repository.impl.ConfigurationsXmlRepositoryImpl;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceDataSourceConfigurationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.sql.DataSource;
+import java.util.Optional;
+
+/**
+ * Event trace data source configuration service implementation.
+ */
+@Service
+public final class EventTraceDataSourceConfigurationServiceImpl implements EventTraceDataSourceConfigurationService {
+    
+    private ConfigurationsXmlRepository configurationsXmlRepository = new ConfigurationsXmlRepositoryImpl();
+    
+    @Autowired
+    private DynamicDataSourceConfig.DynamicDataSource dynamicDataSource;
+    
+    @Override
+    public EventTraceDataSourceConfigurations loadAll() {
+        return loadGlobal().getEventTraceDataSourceConfigurations();
+    }
+    
+    @Override
+    public EventTraceDataSourceConfiguration load(final String name) {
+        GlobalConfiguration configs = loadGlobal();
+        EventTraceDataSourceConfiguration result = find(name, configs.getEventTraceDataSourceConfigurations());
+        setActivated(configs, result);
+        // Activate the dataSource by data source name for spring boot
+        DynamicDataSourceConfig.DynamicDataSourceContextHolder.setDataSourceName(name);
+        return result;
+    }
+    
+    @Override
+    public EventTraceDataSourceConfiguration find(final String name, final EventTraceDataSourceConfigurations configs) {
+        for (EventTraceDataSourceConfiguration each : configs.getEventTraceDataSourceConfiguration()) {
+            if (name.equals(each.getName())) {
+                return each;
+            }
+        }
+        return null;
+    }
+    
+    private void setActivated(final GlobalConfiguration configs, final EventTraceDataSourceConfiguration toBeConnectedConfig) {
+        EventTraceDataSourceConfiguration activatedConfig = findActivatedDataSourceConfiguration(configs);
+        if (!toBeConnectedConfig.equals(activatedConfig)) {
+            if (null != activatedConfig) {
+                activatedConfig.setActivated(false);
+            }
+            toBeConnectedConfig.setActivated(true);
+            configurationsXmlRepository.save(configs);
+        }
+    }
+    
+    @Override
+    public Optional<EventTraceDataSourceConfiguration> loadActivated() {
+        return Optional.ofNullable(findActivatedDataSourceConfiguration(loadGlobal()));
+    }
+    
+    private EventTraceDataSourceConfiguration findActivatedDataSourceConfiguration(final GlobalConfiguration configs) {
+        for (EventTraceDataSourceConfiguration each : configs.getEventTraceDataSourceConfigurations().getEventTraceDataSourceConfiguration()) {
+            if (each.isActivated()) {
+                return each;
+            }
+        }
+        return null;
+    }
+    
+    @Override
+    public boolean add(final EventTraceDataSourceConfiguration config) {
+        GlobalConfiguration configs = loadGlobal();
+        boolean result = configs.getEventTraceDataSourceConfigurations().getEventTraceDataSourceConfiguration().add(config);
+        if (result) {
+            configurationsXmlRepository.save(configs);
+        }
+        DataSource dataSource = DataSourceFactory.createDataSource(config);
+        dynamicDataSource.addDataSource(config.getName(), dataSource);
+        return result;
+    }
+    
+    @Override
+    public void delete(final String name) {
+        GlobalConfiguration configs = loadGlobal();
+        EventTraceDataSourceConfiguration toBeRemovedConfig = find(name, configs.getEventTraceDataSourceConfigurations());
+        if (null != toBeRemovedConfig) {
+            configs.getEventTraceDataSourceConfigurations().getEventTraceDataSourceConfiguration().remove(toBeRemovedConfig);
+            configurationsXmlRepository.save(configs);
+        }
+    }
+    
+    private GlobalConfiguration loadGlobal() {
+        GlobalConfiguration result = configurationsXmlRepository.load();
+        if (null == result.getEventTraceDataSourceConfigurations()) {
+            result.setEventTraceDataSourceConfigurations(new EventTraceDataSourceConfigurations());
+        }
+        return result;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceHistoryServiceImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceHistoryServiceImpl.java
new file mode 100644
index 0000000..d80e1a5
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceHistoryServiceImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service.impl;
+
+import com.google.common.base.Strings;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.ui.dao.search.JobExecutionLogRepository;
+import org.apache.shardingsphere.elasticjob.ui.dao.search.JobStatusTraceLogRepository;
+import org.apache.shardingsphere.elasticjob.ui.domain.JobExecutionLog;
+import org.apache.shardingsphere.elasticjob.ui.domain.JobStatusTraceLog;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.BasePageRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceHistoryService;
+import org.apache.shardingsphere.elasticjob.ui.util.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Component;
+
+import javax.persistence.criteria.Predicate;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Event trace history service implementation.
+ */
+@Slf4j
+@Component
+public final class EventTraceHistoryServiceImpl implements EventTraceHistoryService {
+    
+    @Autowired
+    private JobExecutionLogRepository jobExecutionLogRepository;
+    
+    @Autowired
+    private JobStatusTraceLogRepository jobStatusTraceLogRepository;
+    
+    @Override
+    public Page<JobExecutionEvent> findJobExecutionEvents(final FindJobExecutionEventsRequest findJobExecutionEventsRequest) {
+        Example<JobExecutionLog> jobExecutionLogExample = getExample(findJobExecutionEventsRequest, JobExecutionLog.class);
+        Specification<JobExecutionLog> specification = getSpecWithExampleAndDate(jobExecutionLogExample, findJobExecutionEventsRequest.getStart(),
+            findJobExecutionEventsRequest.getEnd(), "startTime");
+
+        Page<JobExecutionLog> page = jobExecutionLogRepository.findAll(specification, getPageable(findJobExecutionEventsRequest, JobExecutionLog.class));
+        return new PageImpl<>(page.get().map(JobExecutionLog::toJobExecutionEvent).collect(Collectors.toList()), page.getPageable(), page.getTotalElements());
+    }
+    
+    @Override
+    public Page<JobStatusTraceEvent> findJobStatusTraceEvents(final FindJobStatusTraceEventsRequest findJobStatusTraceEventsRequest) {
+        Example<JobStatusTraceLog> jobStatusTraceLogExample = getExample(findJobStatusTraceEventsRequest, JobStatusTraceLog.class);
+        Specification<JobStatusTraceLog> specification = getSpecWithExampleAndDate(jobStatusTraceLogExample, findJobStatusTraceEventsRequest.getStart(),
+            findJobStatusTraceEventsRequest.getEnd(), "creationTime");
+        Page<JobStatusTraceLog> page = jobStatusTraceLogRepository.findAll(specification, getPageable(findJobStatusTraceEventsRequest, JobStatusTraceLog.class));
+        return new PageImpl<>(page.get().map(JobStatusTraceLog::toJobStatusTraceEvent).collect(Collectors.toList()), page.getPageable(), page.getTotalElements());
+    }
+    
+    private <T> Pageable getPageable(final BasePageRequest pageRequest, final Class<T> clazz) {
+        int page = 0;
+        int perPage = BasePageRequest.DEFAULT_PAGE_SIZE;
+        if (pageRequest.getPageNumber() > 0 && pageRequest.getPageSize() > 0) {
+            page = pageRequest.getPageNumber() - 1;
+            perPage = pageRequest.getPageSize();
+        }
+        return PageRequest.of(page, perPage, getSort(pageRequest, clazz));
+    }
+    
+    private <T> Sort getSort(final BasePageRequest pageRequest, final Class<T> clazz) {
+        Sort sort = Sort.unsorted();
+        boolean sortFieldIsPresent = Arrays.stream(clazz.getDeclaredFields())
+            .map(Field::getName)
+            .anyMatch(e -> e.equals(pageRequest.getSortBy()));
+        if (!sortFieldIsPresent) {
+            return sort;
+        }
+        if (!Strings.isNullOrEmpty(pageRequest.getSortBy())) {
+            Sort.Direction order = Sort.Direction.ASC;
+            try {
+                order = Sort.Direction.valueOf(pageRequest.getOrderType());
+            } catch (IllegalArgumentException ignored) {
+            }
+            sort = Sort.by(order, pageRequest.getSortBy());
+        }
+        return sort;
+    }
+    
+    private <T> Specification<T> getSpecWithExampleAndDate(final Example<T> example, final Date from, final Date to, final String field) {
+        return (Specification<T>) (root, query, builder) -> {
+            final List<Predicate> predicates = new ArrayList<>();
+            if (from != null) {
+                predicates.add(builder.greaterThan(root.get(field), from));
+            }
+            if (to != null) {
+                predicates.add(builder.lessThan(root.get(field), to));
+            }
+            predicates.add(QueryByExamplePredicateBuilder.getPredicate(root, builder, example));
+            return builder.and(predicates.toArray(new Predicate[0]));
+        };
+    }
+    
+    private <T> Example<T> getExample(final Object source, final Class<T> clazz) {
+        T instance = BeanUtils.newInstance(clazz);
+        BeanUtils.copyProperties(source, instance);
+        return Example.of(instance);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/JobAPIServiceImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/JobAPIServiceImpl.java
new file mode 100644
index 0000000..d135341
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/JobAPIServiceImpl.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service.impl;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobAPIFactory;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobConfigurationAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobOperateAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ServerStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ShardingOperateAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ShardingStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.service.JobAPIService;
+import org.apache.shardingsphere.elasticjob.ui.util.SessionRegistryCenterConfiguration;
+import org.springframework.stereotype.Service;
+
+/**
+ * Job API service implementation.
+ */
+@Service
+public final class JobAPIServiceImpl implements JobAPIService {
+    
+    @Override
+    public JobConfigurationAPI getJobConfigurationAPI() {
+        RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+        return JobAPIFactory.createJobConfigurationAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+    }
+    
+    @Override
+    public JobOperateAPI getJobOperatorAPI() {
+        RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+        return JobAPIFactory.createJobOperateAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+    }
+    
+    @Override
+    public ShardingOperateAPI getShardingOperateAPI() {
+        RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+        return JobAPIFactory.createShardingOperateAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+    }
+    
+    @Override
+    public JobStatisticsAPI getJobStatisticsAPI() {
+        RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+        return JobAPIFactory.createJobStatisticsAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+    }
+    
+    @Override
+    public ServerStatisticsAPI getServerStatisticsAPI() {
+        RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+        return JobAPIFactory.createServerStatisticsAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+    }
+    
+    @Override
+    public ShardingStatisticsAPI getShardingStatisticsAPI() {
+        RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+        return JobAPIFactory.createShardingStatisticsAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/RegistryCenterConfigurationServiceImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/RegistryCenterConfigurationServiceImpl.java
new file mode 100644
index 0000000..ddbb47e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/RegistryCenterConfigurationServiceImpl.java
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service.impl;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.GlobalConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfigurations;
+import org.apache.shardingsphere.elasticjob.ui.repository.ConfigurationsXmlRepository;
+import org.apache.shardingsphere.elasticjob.ui.repository.impl.ConfigurationsXmlRepositoryImpl;
+import org.apache.shardingsphere.elasticjob.ui.service.RegistryCenterConfigurationService;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+/**
+ * Registry center configuration service implementation.
+ */
+@Service
+public final class RegistryCenterConfigurationServiceImpl implements RegistryCenterConfigurationService {
+    
+    private ConfigurationsXmlRepository configurationsXmlRepository = new ConfigurationsXmlRepositoryImpl();
+    
+    @Override
+    public RegistryCenterConfigurations loadAll() {
+        return loadGlobal().getRegistryCenterConfigurations();
+    }
+    
+    @Override
+    public RegistryCenterConfiguration load(final String name) {
+        GlobalConfiguration configs = loadGlobal();
+        RegistryCenterConfiguration result = find(name, configs.getRegistryCenterConfigurations());
+        setActivated(configs, result);
+        return result;
+    }
+    
+    @Override
+    public RegistryCenterConfiguration find(final String name, final RegistryCenterConfigurations configs) {
+        for (RegistryCenterConfiguration each : configs.getRegistryCenterConfiguration()) {
+            if (name.equals(each.getName())) {
+                return each;
+            }
+        }
+        return null;
+    }
+    
+    private void setActivated(final GlobalConfiguration configs, final RegistryCenterConfiguration toBeConnectedConfig) {
+        RegistryCenterConfiguration activatedConfig = findActivatedRegistryCenterConfiguration(configs);
+        if (!toBeConnectedConfig.equals(activatedConfig)) {
+            if (null != activatedConfig) {
+                activatedConfig.setActivated(false);
+            }
+            toBeConnectedConfig.setActivated(true);
+            configurationsXmlRepository.save(configs);
+        }
+    }
+    
+    @Override
+    public Optional<RegistryCenterConfiguration> loadActivated() {
+        return Optional.ofNullable(findActivatedRegistryCenterConfiguration(loadGlobal()));
+    }
+    
+    private RegistryCenterConfiguration findActivatedRegistryCenterConfiguration(final GlobalConfiguration configs) {
+        for (RegistryCenterConfiguration each : configs.getRegistryCenterConfigurations().getRegistryCenterConfiguration()) {
+            if (each.isActivated()) {
+                return each;
+            }
+        }
+        return null;
+    }
+    
+    @Override
+    public boolean add(final RegistryCenterConfiguration config) {
+        GlobalConfiguration configs = loadGlobal();
+        boolean result = configs.getRegistryCenterConfigurations().getRegistryCenterConfiguration().add(config);
+        if (result) {
+            configurationsXmlRepository.save(configs);
+        }
+        return result;
+    }
+    
+    @Override
+    public void delete(final String name) {
+        GlobalConfiguration configs = loadGlobal();
+        RegistryCenterConfiguration toBeRemovedConfig = find(name, configs.getRegistryCenterConfigurations());
+        if (null != toBeRemovedConfig) {
+            configs.getRegistryCenterConfigurations().getRegistryCenterConfiguration().remove(toBeRemovedConfig);
+            configurationsXmlRepository.save(configs);
+        }
+    }
+    
+    private GlobalConfiguration loadGlobal() {
+        GlobalConfiguration result = configurationsXmlRepository.load();
+        if (null == result.getRegistryCenterConfigurations()) {
+            result.setRegistryCenterConfigurations(new RegistryCenterConfigurations());
+        }
+        return result;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/BeanUtils.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/BeanUtils.java
new file mode 100644
index 0000000..0566471
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/BeanUtils.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.util;
+
+import org.springframework.cglib.beans.BeanMap;
+
+import java.util.Map;
+import java.util.Objects;
+
+public class BeanUtils extends org.springframework.beans.BeanUtils {
+    
+    /**
+     * return a new instance by specified java type.
+     *
+     * @param clazz java type class
+     * @param <T>   java type
+     * @return new instance
+     */
+    public static <T> T newInstance(final Class<T> clazz) {
+        return instantiateClass(clazz);
+    }
+    
+    /**
+     * map to java object.
+     *
+     * @param map  source map
+     * @param type class
+     * @param <T>  target java type
+     * @return java object
+     */
+    public static <T> T toBean(final Map<String, Object> map, final Class<T> type) {
+        if (Objects.isNull(map)) {
+            return null;
+        }
+        T bean = newInstance(type);
+        BeanMap beanMap = BeanMap.create(bean);
+        beanMap.putAll(map);
+        return bean;
+    }
+    
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtils.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtils.java
new file mode 100644
index 0000000..1c4aa10
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtils.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.io.File;
+
+/**
+ * Home folder Utils.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class HomeFolderUtils {
+    
+    private static final String USER_HOME = System.getProperty("user.home");
+    
+    private static final String CONSOLE_ROOT_FOLDER = ".elasticjob-console";
+    
+    /**
+     * Get file path in home folder.
+     * 
+     * @param fileName file name
+     * @return file path in home folder
+     */
+    public static String getFilePathInHomeFolder(final String fileName) {
+        return String.format("%s%s", getHomeFolder(), fileName);
+    }
+    
+    /**
+     * Create home folder if not existed.
+     */
+    public static void createHomeFolderIfNotExisted() {
+        File file = new File(getHomeFolder());
+        if (!file.exists()) {
+            file.mkdirs();
+        }
+    }
+    
+    private static String getHomeFolder() {
+        return String.format("%s%s%s%s", USER_HOME, File.separator, CONSOLE_ROOT_FOLDER, File.separator);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionEventTraceDataSourceConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionEventTraceDataSourceConfiguration.java
new file mode 100644
index 0000000..1445b7d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionEventTraceDataSourceConfiguration.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.ui.config.DynamicDataSourceConfig;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfiguration;
+
+/**
+ * Event trace data source configuration in session.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class SessionEventTraceDataSourceConfiguration {
+    
+    private static EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration;
+    
+    /**
+     * Set event trace data source configuration.
+     *
+     * @param eventTraceDataSourceConfiguration event trace data source configuration
+     */
+    public static void setDataSourceConfiguration(final EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration) {
+        DynamicDataSourceConfig.DynamicDataSourceContextHolder.setDataSourceName(eventTraceDataSourceConfiguration.getName());
+        SessionEventTraceDataSourceConfiguration.eventTraceDataSourceConfiguration = eventTraceDataSourceConfiguration;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionRegistryCenterConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionRegistryCenterConfiguration.java
new file mode 100644
index 0000000..74fe0c2
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionRegistryCenterConfiguration.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+
+/**
+ * Registry center configuration configuration.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class SessionRegistryCenterConfiguration {
+    
+    private static RegistryCenterConfiguration regCenterConfig;
+    
+    /**
+     * Get registry center configuration.
+     *
+     * @return registry center configuration
+     */
+    public static RegistryCenterConfiguration getRegistryCenterConfiguration() {
+        return regCenterConfig;
+    }
+    
+    /**
+     * Set registry center configuration.
+     * 
+     * @param regCenterConfig registry center configuration
+     */
+    public static void setRegistryCenterConfiguration(final RegistryCenterConfiguration regCenterConfig) {
+        SessionRegistryCenterConfiguration.regCenterConfig = regCenterConfig;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java
new file mode 100644
index 0000000..d4bd7c0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceFactory;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceDataSourceConfigurationService;
+import org.apache.shardingsphere.elasticjob.ui.util.SessionEventTraceDataSourceConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+/**
+ * Event trace data source RESTful API.
+ */
+@RestController
+@RequestMapping("/data-source")
+public final class EventTraceDataSourceController {
+    
+    public static final String DATA_SOURCE_CONFIG_KEY = "data_source_config_key";
+    
+    private EventTraceDataSourceConfigurationService eventTraceDataSourceConfigurationService;
+    
+    @Autowired
+    public EventTraceDataSourceController(final EventTraceDataSourceConfigurationService eventTraceDataSourceConfigurationService) {
+        this.eventTraceDataSourceConfigurationService = eventTraceDataSourceConfigurationService;
+    }
+    
+    /**
+     * Judge whether event trace data source is activated.
+     *
+     * @param request HTTP request
+     * @return event trace data source is activated or not
+     */
+    @GetMapping("/activated")
+    public boolean activated(@Context final HttpServletRequest request) {
+        return eventTraceDataSourceConfigurationService.loadActivated().isPresent();
+    }
+    
+    /**
+     * Load event trace data source configuration.
+     *
+     * @param request HTTP request
+     * @return event trace data source configurations
+     */
+    @GetMapping(produces = MediaType.APPLICATION_JSON)
+    public Collection<EventTraceDataSourceConfiguration> load(@Context final HttpServletRequest request) {
+        eventTraceDataSourceConfigurationService.loadActivated().ifPresent(eventTraceDataSourceConfig -> setDataSourceNameToSession(eventTraceDataSourceConfig, request.getSession()));
+        return eventTraceDataSourceConfigurationService.loadAll().getEventTraceDataSourceConfiguration();
+    }
+    
+    /**
+     * Add event trace data source configuration.
+     *
+     * @param config event trace data source configuration
+     * @return success to added or not
+     */
+    @PostMapping(produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+    public boolean add(@RequestBody final EventTraceDataSourceConfiguration config) {
+        return eventTraceDataSourceConfigurationService.add(config);
+    }
+    
+    /**
+     * Delete event trace data source configuration.
+     *
+     * @param config event trace data source configuration
+     */
+    @DeleteMapping(consumes = MediaType.APPLICATION_JSON)
+    public void delete(@RequestBody final EventTraceDataSourceConfiguration config) {
+        eventTraceDataSourceConfigurationService.delete(config.getName());
+    }
+    
+    /**
+     * Test event trace data source connection.
+     *
+     * @param config  event trace data source configuration
+     * @param request HTTP request
+     * @return success or not
+     */
+    @PostMapping(value = "/connectTest", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+    public boolean connectTest(@RequestBody final EventTraceDataSourceConfiguration config, @Context final HttpServletRequest request) {
+        return setDataSourceNameToSession(config, request.getSession());
+    }
+    
+    /**
+     * Connect event trace data source.
+     *
+     * @param config  event trace data source
+     * @param request HTTP request
+     * @return success or not
+     */
+    @PostMapping(value = "/connect", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+    public boolean connect(@RequestBody final EventTraceDataSourceConfiguration config, @Context final HttpServletRequest request) {
+        boolean isConnected = setDataSourceNameToSession(eventTraceDataSourceConfigurationService.find(config.getName(), eventTraceDataSourceConfigurationService.loadAll()), request.getSession());
+        if (isConnected) {
+            eventTraceDataSourceConfigurationService.load(config.getName());
+        }
+        return isConnected;
+    }
+    
+    private boolean setDataSourceNameToSession(final EventTraceDataSourceConfiguration dataSourceConfig, final HttpSession session) {
+        session.setAttribute(DATA_SOURCE_CONFIG_KEY, dataSourceConfig);
+        try {
+            EventTraceDataSourceFactory.createEventTraceDataSource(dataSourceConfig.getDriver(), dataSourceConfig.getUrl(), dataSourceConfig.getUsername(), dataSourceConfig.getPassword());
+            SessionEventTraceDataSourceConfiguration.setDataSourceConfiguration((EventTraceDataSourceConfiguration) session.getAttribute(DATA_SOURCE_CONFIG_KEY));
+        // CHECKSTYLE:OFF
+        } catch (final Exception ex) {
+        // CHECKSTYLE:ON
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceHistoryController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceHistoryController.java
new file mode 100644
index 0000000..c8499e1
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceHistoryController.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.response.BasePageResponse;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceHistoryService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.core.MediaType;
+
+/**
+ * Event trace history RESTful API.
+ */
+@RestController
+@RequestMapping("/event-trace")
+public final class EventTraceHistoryController {
+    
+    @Autowired
+    private EventTraceHistoryService eventTraceHistoryService;
+    
+    /**
+     * Find job execution events.
+     *
+     * @param requestParams query criteria
+     * @return job execution event trace result
+     */
+    @GetMapping(value = "/execution", produces = MediaType.APPLICATION_JSON)
+    public BasePageResponse<JobExecutionEvent> findJobExecutionEvents(final FindJobExecutionEventsRequest requestParams) {
+        Page<JobExecutionEvent> jobExecutionEvents = eventTraceHistoryService.findJobExecutionEvents(requestParams);
+        return BasePageResponse.of(jobExecutionEvents);
+    }
+    
+    /**
+     * Find job status trace events.
+     *
+     * @param requestParams query criteria
+     * @return job status trace result
+     */
+    @GetMapping(value = "/status", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+    public BasePageResponse<JobStatusTraceEvent> findJobStatusTraceEvents(final FindJobStatusTraceEventsRequest requestParams) {
+        Page<JobStatusTraceEvent> jobStatusTraceEvents = eventTraceHistoryService.findJobStatusTraceEvents(requestParams);
+        return BasePageResponse.of(jobStatusTraceEvents);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobConfigController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobConfigController.java
new file mode 100644
index 0000000..65c876b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobConfigController.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.lite.internal.config.pojo.JobConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.ui.service.JobAPIService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.core.MediaType;
+
+/**
+ * Job configuration RESTful API.
+ */
+@RestController
+@RequestMapping("/jobs/config")
+public final class JobConfigController {
+    
+    private JobAPIService jobAPIService;
+    
+    @Autowired
+    public JobConfigController(final JobAPIService jobAPIService) {
+        this.jobAPIService = jobAPIService;
+    }
+    
+    /**
+     * Get job configuration.
+     *
+     * @param jobName job name
+     * @return job configuration
+     */
+    @GetMapping(value = "/{jobName}", produces = MediaType.APPLICATION_JSON)
+    public JobConfigurationPOJO getJobConfig(@PathVariable("jobName") final String jobName) {
+        return jobAPIService.getJobConfigurationAPI().getJobConfiguration(jobName);
+    }
+    
+    /**
+     * Update job configuration.
+     *
+     * @param jobConfiguration job configuration
+     */
+    @PutMapping(consumes = MediaType.APPLICATION_JSON)
+    public void updateJobConfig(@RequestBody final JobConfigurationPOJO jobConfiguration) {
+        jobAPIService.getJobConfigurationAPI().updateJobConfiguration(jobConfiguration);
+    }
+    
+    /**
+     * Remove job configuration.
+     *
+     * @param jobName job name
+     */
+    @DeleteMapping("/{jobName}")
+    public void removeJob(@PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobConfigurationAPI().removeJobConfiguration(jobName);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobOperationController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobOperationController.java
new file mode 100644
index 0000000..f5ba118
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobOperationController.java
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.domain.JobBriefInfo;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.domain.ShardingInfo;
+import org.apache.shardingsphere.elasticjob.ui.service.JobAPIService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+/**
+ * Job operation RESTful API.
+ */
+@RestController
+@RequestMapping("/jobs")
+public final class JobOperationController {
+    
+    private JobAPIService jobAPIService;
+    
+    @Autowired
+    public JobOperationController(final JobAPIService jobAPIService) {
+        this.jobAPIService = jobAPIService;
+    }
+    
+    /**
+     * Get jobs total count.
+     * 
+     * @return jobs total count
+     */
+    @GetMapping("/count")
+    public int getJobsTotalCount() {
+        return jobAPIService.getJobStatisticsAPI().getJobsTotalCount();
+    }
+    
+    /**
+     * Get all jobs brief info.
+     * 
+     * @return all jobs brief info
+     */
+    @GetMapping(produces = MediaType.APPLICATION_JSON)
+    public Collection<JobBriefInfo> getAllJobsBriefInfo() {
+        return jobAPIService.getJobStatisticsAPI().getAllJobsBriefInfo();
+    }
+    
+    /**
+     * Trigger job.
+     * 
+     * @param jobName job name
+     */
+    @PostMapping("/{jobName}/trigger")
+    public void triggerJob(@PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobOperatorAPI().trigger(jobName);
+    }
+    
+    /**
+     * Disable job.
+     * 
+     * @param jobName job name
+     */
+    @PostMapping(value = "/{jobName}/disable")
+    public void disableJob(@PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobOperatorAPI().disable(jobName, null);
+    }
+    
+    /**
+     * Enable job.
+     *
+     * @param jobName job name
+     */
+    @PostMapping(value = "/{jobName}/enable")
+    public void enableJob(@PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobOperatorAPI().enable(jobName, null);
+    }
+    
+    /**
+     * Shutdown job.
+     * 
+     * @param jobName job name
+     */
+    @PostMapping(value = "/{jobName}/shutdown")
+    public void shutdownJob(@PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobOperatorAPI().shutdown(jobName, null);
+    }
+    
+    /**
+     * Get sharding info.
+     * 
+     * @param jobName job name
+     * @return sharding info
+     */
+    @GetMapping(value = "/{jobName}/sharding", produces = MediaType.APPLICATION_JSON)
+    public Collection<ShardingInfo> getShardingInfo(@PathVariable("jobName") final String jobName) {
+        return jobAPIService.getShardingStatisticsAPI().getShardingInfo(jobName);
+    }
+    
+    /**
+     * Disable sharding.
+     *
+     * @param jobName job name
+     * @param item sharding item
+     */
+    @PostMapping(value = "/{jobName}/sharding/{item}/disable")
+    public void disableSharding(@PathVariable("jobName") final String jobName, @PathVariable("item") final String item) {
+        jobAPIService.getShardingOperateAPI().disable(jobName, item);
+    }
+    
+    /**
+     * Enable sharding.
+     *
+     * @param jobName job name
+     * @param item sharding item
+     */
+    @PostMapping(value = "/{jobName}/sharding/{item}/enable")
+    public void enableSharding(@PathVariable("jobName") final String jobName, @PathVariable("item") final String item) {
+        jobAPIService.getShardingOperateAPI().enable(jobName, item);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java
new file mode 100644
index 0000000..9225b91
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.internal.reg.RegistryCenterFactory;
+import org.apache.shardingsphere.elasticjob.reg.exception.RegException;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.service.RegistryCenterConfigurationService;
+import org.apache.shardingsphere.elasticjob.ui.util.SessionRegistryCenterConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+/**
+ * Registry center RESTful API.
+ */
+@RestController
+@RequestMapping("/registry-center")
+public final class RegistryCenterController {
+    
+    public static final String REG_CENTER_CONFIG_KEY = "reg_center_config_key";
+    
+    private RegistryCenterConfigurationService regCenterService;
+    
+    @Autowired
+    public RegistryCenterController(final RegistryCenterConfigurationService regCenterService) {
+        this.regCenterService = regCenterService;
+    }
+    
+    /**
+     * Judge whether registry center is activated.
+     *
+     * @return registry center is activated or not
+     */
+    @GetMapping("/activated")
+    public boolean activated() {
+        return regCenterService.loadActivated().isPresent();
+    }
+    
+    /**
+     * Load configuration from registry center.
+     *
+     * @param request HTTP request
+     * @return registry center configurations
+     */
+    @GetMapping(produces = MediaType.APPLICATION_JSON)
+    public Collection<RegistryCenterConfiguration> load(final HttpServletRequest request) {
+        regCenterService.loadActivated().ifPresent(regCenterConfig -> setRegistryCenterNameToSession(regCenterConfig, request.getSession()));
+        return regCenterService.loadAll().getRegistryCenterConfiguration();
+    }
+    
+    /**
+     * Add registry center.
+     *
+     * @param config registry center configuration
+     * @return success to add or not
+     */
+    @PostMapping(produces = MediaType.APPLICATION_JSON)
+    public boolean add(@RequestBody final RegistryCenterConfiguration config) {
+        return regCenterService.add(config);
+    }
+    
+    /**
+     * Delete registry center.
+     *
+     * @param config registry center configuration
+     */
+    @DeleteMapping(consumes = MediaType.APPLICATION_JSON)
+    public void delete(@RequestBody final RegistryCenterConfiguration config) {
+        regCenterService.delete(config.getName());
+    }
+    
+    /**
+     * Connect to registry center.
+     *
+     * @param config  config of registry center
+     * @param request HTTP request
+     * @return connected or not
+     */
+    @PostMapping(value = "/connect", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
+    public boolean connect(@RequestBody final RegistryCenterConfiguration config, @Context final HttpServletRequest request) {
+        boolean isConnected = setRegistryCenterNameToSession(regCenterService.find(config.getName(), regCenterService.loadAll()), request.getSession());
+        if (isConnected) {
+            regCenterService.load(config.getName());
+        }
+        return isConnected;
+    }
+    
+    private boolean setRegistryCenterNameToSession(final RegistryCenterConfiguration regCenterConfig, final HttpSession session) {
+        session.setAttribute(REG_CENTER_CONFIG_KEY, regCenterConfig);
+        try {
+            RegistryCenterFactory.createCoordinatorRegistryCenter(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+            SessionRegistryCenterConfiguration.setRegistryCenterConfiguration((RegistryCenterConfiguration) session.getAttribute(REG_CENTER_CONFIG_KEY));
+        } catch (final RegException ex) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/ServerOperationController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/ServerOperationController.java
new file mode 100644
index 0000000..2a36f66
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/ServerOperationController.java
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.domain.JobBriefInfo;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.domain.ServerBriefInfo;
+import org.apache.shardingsphere.elasticjob.ui.service.JobAPIService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+/**
+ * Server operation RESTful API.
+ */
+@RestController
+@RequestMapping("/servers")
+public final class ServerOperationController {
+    
+    private JobAPIService jobAPIService;
+    
+    @Autowired
+    public ServerOperationController(final JobAPIService jobAPIService) {
+        this.jobAPIService = jobAPIService;
+    }
+    
+    /**
+     * Get servers total count.
+     * 
+     * @return servers total count
+     */
+    @GetMapping("/count")
+    public int getServersTotalCount() {
+        return jobAPIService.getServerStatisticsAPI().getServersTotalCount();
+    }
+    
+    /**
+     * Get all servers brief info.
+     * 
+     * @return all servers brief info
+     */
+    @GetMapping(produces = MediaType.APPLICATION_JSON)
+    public Collection<ServerBriefInfo> getAllServersBriefInfo() {
+        return jobAPIService.getServerStatisticsAPI().getAllServersBriefInfo();
+    }
+    
+    /**
+     * Disable server.
+     *
+     * @param serverIp server IP address
+     */
+    @PostMapping("/{serverIp}/disable")
+    public void disableServer(@PathVariable("serverIp") final String serverIp) {
+        jobAPIService.getJobOperatorAPI().disable(null, serverIp);
+    }
+    
+    /**
+     * Enable server.
+     *
+     * @param serverIp server IP address
+     */
+    @PostMapping("/{serverIp}/enable")
+    public void enableServer(@PathVariable("serverIp") final String serverIp) {
+        jobAPIService.getJobOperatorAPI().enable(null, serverIp);
+    }
+    
+    /**
+     * Shutdown server.
+     *
+     * @param serverIp server IP address
+     */
+    @PostMapping("/{serverIp}/shutdown")
+    public void shutdownServer(@PathVariable("serverIp") final String serverIp) {
+        jobAPIService.getJobOperatorAPI().shutdown(null, serverIp);
+    }
+    
+    /**
+     * Remove server.
+     *
+     * @param serverIp server IP address
+     */
+    @DeleteMapping("/{serverIp}")
+    public void removeServer(@PathVariable("serverIp") final String serverIp) {
+        jobAPIService.getJobOperatorAPI().remove(null, serverIp);
+    }
+    
+    /**
+     * Get jobs.
+     *
+     * @param serverIp server IP address
+     * @return Job brief info
+     */
+    @GetMapping(value = "/{serverIp}/jobs", produces = MediaType.APPLICATION_JSON)
+    public Collection<JobBriefInfo> getJobs(@PathVariable("serverIp") final String serverIp) {
+        return jobAPIService.getJobStatisticsAPI().getJobsBriefInfo(serverIp);
+    }
+    
+    /**
+     * Disable server job.
+     * 
+     * @param serverIp server IP address
+     * @param jobName job name
+     */
+    @PostMapping(value = "/{serverIp}/jobs/{jobName}/disable")
+    public void disableServerJob(@PathVariable("serverIp") final String serverIp, @PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobOperatorAPI().disable(jobName, serverIp);
+    }
+    
+    /**
+     * Enable server job.
+     *
+     * @param serverIp server IP address
+     * @param jobName job name
+     */
+    @PostMapping("/{serverIp}/jobs/{jobName}/enable")
+    public void enableServerJob(@PathVariable("serverIp") final String serverIp, @PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobOperatorAPI().enable(jobName, serverIp);
+    }
+    
+    /**
+     * Shutdown server job.
+     *
+     * @param serverIp server IP address
+     * @param jobName job name
+     */
+    @PostMapping("/{serverIp}/jobs/{jobName}/shutdown")
+    public void shutdownServerJob(@PathVariable("serverIp") final String serverIp, @PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobOperatorAPI().shutdown(jobName, serverIp);
+    }
+    
+    /**
+     * Remove server job.
+     *
+     * @param serverIp server IP address
+     * @param jobName job name
+     */
+    @DeleteMapping("/{serverIp}/jobs/{jobName}")
+    public void removeServerJob(@PathVariable("serverIp") final String serverIp, @PathVariable("jobName") final String jobName) {
+        jobAPIService.getJobOperatorAPI().remove(jobName, serverIp);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/filter/CORSFilter.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/filter/CORSFilter.java
new file mode 100644
index 0000000..95c0869
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/filter/CORSFilter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.filter;
+
+import org.springframework.http.HttpStatus;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * CORS filter.
+ */
+public final class CORSFilter implements Filter {
+    
+    @Override
+    public void init(final FilterConfig filterConfig) {
+    }
+    
+    @Override
+    public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
+        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
+        response.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
+        response.setHeader("Access-Control-Max-Age", "3600");
+        response.setHeader("Access-Control-Allow-Credentials", "true");
+        response.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
+        if ("OPTIONS".equals(request.getMethod())) {
+            response.setStatus(HttpStatus.OK.value());
+        } else {
+            filterChain.doFilter(request, response);
+        }
+    }
+    
+    @Override
+    public void destroy() {
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResult.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResult.java
new file mode 100644
index 0000000..b01b109
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResult.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Restful Response result.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public final class ResponseResult<T> implements Serializable {
+    
+    private static final long serialVersionUID = 8144393142115317354L;
+    
+    private boolean success = true;
+    
+    private int errorCode;
+    
+    private String errorMsg;
+    
+    private T model;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResultUtil.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResultUtil.java
new file mode 100644
index 0000000..0422956
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResultUtil.java
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.response;
+
+import com.google.gson.Gson;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.ui.exception.JobConsoleException;
+
+/**
+ * Response result utility.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ResponseResultUtil {
+    
+    /**
+     * Build the successful response without data model.
+     *
+     * @return response result
+     */
+    public static ResponseResult success() {
+        return build(null);
+    }
+    
+    /**
+     * Build the successful response with data model.
+     *
+     * @param model data model
+     * @param <T> data model type
+     * @return response result
+     */
+    public static <T> ResponseResult<T> build(final T model) {
+        ResponseResult<T> result = new ResponseResult<>();
+        result.setSuccess(true);
+        result.setModel(model);
+        return result;
+    }
+    
+    /**
+     * Build the response from json.
+     *
+     * @param responseResultJson response result json string
+     * @return response result
+     */
+    public static ResponseResult buildFromJson(final String responseResultJson) {
+        return new Gson().fromJson(responseResultJson, ResponseResult.class);
+    }
+    
+    /**
+     * Build the error response of illegal argument exception.
+     *
+     * @param errorMsg error message
+     * @return response result
+     */
+    public static ResponseResult handleIllegalArgumentException(final String errorMsg) {
+        ResponseResult result = new ResponseResult<>();
+        result.setSuccess(false);
+        result.setErrorCode(JobConsoleException.INVALID_PARAM);
+        result.setErrorMsg(errorMsg);
+        return result;
+    }
+    
+    /**
+     * Build the error response of unauthorized exception.
+     *
+     * @param errorMsg error message
+     * @return response result
+     */
+    public static ResponseResult handleUnauthorizedException(final String errorMsg) {
+        ResponseResult result = new ResponseResult<>();
+        result.setSuccess(false);
+        result.setErrorCode(JobConsoleException.NO_RIGHT);
+        result.setErrorMsg(errorMsg);
+        return result;
+    }
+    
+    /**
+     * Build the error response of ShardingSphere UI exception.
+     *
+     * @param exception ShardingSphere UI exception
+     * @return response result
+     */
+    public static ResponseResult handleShardingSphereUIException(final JobConsoleException exception) {
+        ResponseResult result = new ResponseResult<>();
+        result.setSuccess(false);
+        result.setErrorCode(exception.getErrorCode());
+        result.setErrorMsg(exception.getMessage());
+        return result;
+    }
+    
+    /**
+     * Build the error response of uncaught exception.
+     *
+     * @param errorMsg error message
+     * @return response result
+     */
+    public static ResponseResult handleUncaughtException(final String errorMsg) {
+        ResponseResult result = new ResponseResult<>();
+        result.setSuccess(false);
+        result.setErrorCode(JobConsoleException.SERVER_ERROR);
+        result.setErrorMsg(errorMsg);
+        return result;
+    }
+    
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties b/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties
index 51e047a..f4f0513 100644
--- a/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties
+++ b/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties
@@ -15,7 +15,16 @@
 # limitations under the License.
 #
 
-server.port=8088
+server.port=8899
 
-user.admin.username=admin
-user.admin.password=admin
+auth.root_username=root
+auth.root_password=root
+auth.guest_username=guest
+auth.guest_password=guest
+
+spring.datasource.default.driver-class-name=org.h2.Driver
+spring.datasource.default.url=jdbc:h2:mem:
+spring.datasource.default.username=sa
+spring.datasource.default.password=
+spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect
+spring.jpa.show-sql=false
diff --git a/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTest.java b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTest.java
new file mode 100644
index 0000000..558be6b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.search;
+
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceHistoryService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
+import org.springframework.data.domain.Page;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Date;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@Import(RDBJobEventSearchTestConfiguration.class)
+public final class RDBJobEventSearchTest {
+    
+    @Autowired
+    private EventTraceHistoryService eventTraceHistoryService;
+    
+    @Test
+    public void assertFindJobExecutionEventsWithPageSizeAndNumber() {
+        Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest());
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(50, 1));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(50));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(100, 5));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(100));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(100, 6));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(0));
+    }
+    
+    @Test
+    public void assertFindJobExecutionEventsWithErrorPageSizeAndNumber() {
+        Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(-1, -1, null, null, null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+    }
+    
+    @Test
+    public void assertFindJobExecutionEventsWithSort() {
+        Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, "jobName", "ASC", null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        assertThat(result.getContent().get(0).getJobName(), is("test_job_1"));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, "jobName", "DESC", null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        assertThat(result.getContent().get(0).getJobName(), is("test_job_99"));
+    }
+    
+    @Test
+    public void assertFindJobExecutionEventsWithErrorSort() {
+        Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, "jobName", "ERROR_SORT", null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        assertThat(result.getContent().get(0).getJobName(), is("test_job_1"));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, "notExistField", "ASC", null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+    }
+    
+    @Test
+    public void assertFindJobExecutionEventsWithTime() {
+        Date now = new Date();
+        Date tenMinutesBefore = new Date(now.getTime() - 10 * 60 * 1000);
+        Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, tenMinutesBefore, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, now, null));
+        assertThat(result.getTotalElements(), is(0L));
+        assertThat(result.getContent().size(), is(0));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, null, tenMinutesBefore));
+        assertThat(result.getTotalElements(), is(0L));
+        assertThat(result.getContent().size(), is(0));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, null, now));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, tenMinutesBefore, now));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+    }
+    
+    @Test
+    public void assertFindJobExecutionEventsWithFields() {
+        FindJobExecutionEventsRequest findJobExecutionEventsRequest = new FindJobExecutionEventsRequest(10, 1, null, null, null, null);
+        findJobExecutionEventsRequest.setIsSuccess(true);
+        Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(findJobExecutionEventsRequest);
+        assertThat(result.getTotalElements(), is(250L));
+        assertThat(result.getContent().size(), is(10));
+        findJobExecutionEventsRequest.setIsSuccess(null);
+        findJobExecutionEventsRequest.setJobName("test_job_1");
+        result = eventTraceHistoryService.findJobExecutionEvents(findJobExecutionEventsRequest);
+        assertThat(result.getTotalElements(), is(1L));
+        assertThat(result.getContent().size(), is(1));
+    }
+    
+    @Test
+    public void assertFindJobExecutionEventsWithErrorFields() {
+        Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+    }
+    
+    @Test
+    public void assertFindJobStatusTraceEventsWithPageSizeAndNumber() {
+        Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(50, 1, null, null, null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(50));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(100, 5, null, null, null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(100));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(100, 6, null, null, null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(0));
+    }
+    
+    @Test
+    public void assertFindJobStatusTraceEventsWithErrorPageSizeAndNumber() {
+        Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(-1, -1));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+    }
+    
+    @Test
+    public void assertFindJobStatusTraceEventsWithSort() {
+        Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, "jobName", "ASC", null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        assertThat(result.getContent().get(0).getJobName(), is("test_job_1"));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, "jobName", "DESC", null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        assertThat(result.getContent().get(0).getJobName(), is("test_job_99"));
+    }
+    
+    @Test
+    public void assertFindJobStatusTraceEventsWithErrorSort() {
+        Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, "jobName", "ERROR_SORT", null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        assertThat(result.getContent().get(0).getJobName(), is("test_job_1"));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, "notExistField", "ASC", null, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+    }
+    
+    @Test
+    public void assertFindJobStatusTraceEventsWithTime() {
+        Date now = new Date();
+        Date tenMinutesBefore = new Date(now.getTime() - 10 * 60 * 1000);
+        Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, tenMinutesBefore, null));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, now, null));
+        assertThat(result.getTotalElements(), is(0L));
+        assertThat(result.getContent().size(), is(0));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, null, tenMinutesBefore));
+        assertThat(result.getTotalElements(), is(0L));
+        assertThat(result.getContent().size(), is(0));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, null, now));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+        result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, tenMinutesBefore, now));
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+    }
+    
+    @Test
+    public void assertFindJobStatusTraceEventsWithFields() {
+        FindJobStatusTraceEventsRequest findJobStatusTraceEventsRequest = new FindJobStatusTraceEventsRequest(10, 1);
+        findJobStatusTraceEventsRequest.setJobName("test_job_1");
+        Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(findJobStatusTraceEventsRequest);
+        assertThat(result.getTotalElements(), is(1L));
+        assertThat(result.getContent().size(), is(1));
+    }
+    
+    @Test
+    public void assertFindJobStatusTraceEventsWithErrorFields() {
+        FindJobStatusTraceEventsRequest findJobStatusTraceEventsRequest = new FindJobStatusTraceEventsRequest(10, 1);
+        Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(findJobStatusTraceEventsRequest);
+        assertThat(result.getTotalElements(), is(500L));
+        assertThat(result.getContent().size(), is(10));
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTestConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTestConfiguration.java
new file mode 100644
index 0000000..16b5f08
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTestConfiguration.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.search;
+
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.tracing.rdb.storage.RDBJobEventStorage;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceHistoryService;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.TestConfiguration;
+
+import javax.sql.DataSource;
+import java.sql.SQLException;
+
+@TestConfiguration
+public class RDBJobEventSearchTestConfiguration implements InitializingBean {
+    
+    @Autowired
+    private EventTraceHistoryService eventTraceHistoryService;
+    
+    @Autowired
+    private DataSource dataSource;
+    
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        initStorage();
+    }
+    
+    private void initStorage() throws SQLException {
+        eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1));
+        eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1));
+        RDBJobEventStorage storage = new RDBJobEventStorage(dataSource);
+        for (int i = 1; i <= 500L; i++) {
+            JobExecutionEvent startEvent = new JobExecutionEvent("localhost", "127.0.0.1", "fake_task_id", "test_job_" + i, JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);
+            storage.addJobExecutionEvent(startEvent);
+            if (i % 2 == 0) {
+                JobExecutionEvent successEvent = startEvent.executionSuccess();
+                storage.addJobExecutionEvent(successEvent);
+            }
+            storage.addJobStatusTraceEvent(new JobStatusTraceEvent(
+                    "test_job_" + i,
+                    "fake_failed_failover_task_id",
+                    "fake_slave_id",
+                    JobStatusTraceEvent.Source.LITE_EXECUTOR,
+                    "FAILOVER",
+                    "0",
+                    JobStatusTraceEvent.State.TASK_FAILED,
+                    "message is empty."
+            ));
+        }
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/rdb/RDBStatisticRepositoryTest.java b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/rdb/RDBStatisticRepositoryTest.java
new file mode 100644
index 0000000..f5f0419
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/rdb/RDBStatisticRepositoryTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics.rdb;
+
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.JobRegisterStatisticsRepository;
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.JobRunningStatisticsRepository;
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.StatisticInterval;
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.TaskResultStatisticsRepository;
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.TaskRunningStatisticsRepository;
+import org.apache.shardingsphere.elasticjob.ui.domain.JobRegisterStatistics;
+import org.apache.shardingsphere.elasticjob.ui.domain.JobRunningStatistics;
+import org.apache.shardingsphere.elasticjob.ui.domain.TaskResultStatistics;
+import org.apache.shardingsphere.elasticjob.ui.domain.TaskRunningStatistics;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.Date;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+@SpringBootTest
+@RunWith(SpringJUnit4ClassRunner.class)
+public class RDBStatisticRepositoryTest {
+    
+    @Autowired
+    private TaskResultStatisticsRepository taskResultStatisticsRepository;
+    
+    @Autowired
+    private TaskRunningStatisticsRepository taskRunningStatisticsRepository;
+    
+    @Autowired
+    private JobRegisterStatisticsRepository jobRegisterStatisticsRepository;
+    
+    @Autowired
+    private JobRunningStatisticsRepository jobRunningStatisticsRepository;
+    
+    @Test
+    public void assertAddTaskResultStatistics() {
+        for (StatisticInterval each : StatisticInterval.values()) {
+            TaskResultStatistics taskResultStatistics = new TaskResultStatistics(100L, 0L, each.name(), new Date());
+            assertTrue(taskResultStatistics.equals(taskResultStatisticsRepository.save(taskResultStatistics)));
+        }
+    }
+    
+    @Test
+    public void assertAddTaskRunningStatistics() {
+        TaskRunningStatistics taskRunningStatistics = new TaskRunningStatistics(100, new Date());
+        assertTrue(taskRunningStatistics.equals(taskRunningStatisticsRepository.save(taskRunningStatistics)));
+    }
+    
+    @Test
+    public void assertAddJobRunningStatistics() {
+        JobRunningStatistics jobRunningStatistics = new JobRunningStatistics(100, new Date());
+        assertTrue(jobRunningStatistics.equals(jobRunningStatisticsRepository.save(jobRunningStatistics)));
+    }
+    
+    @Test
+    public void assertAddJobRegisterStatistics() {
+        JobRegisterStatistics jobRegisterStatistics = new JobRegisterStatistics(100, new Date());
+        assertTrue(jobRegisterStatistics.equals(jobRegisterStatisticsRepository.save(jobRegisterStatistics)));
+    }
+    
+    @Test
+    public void assertFindTaskResultStatisticsWhenTableIsEmpty() {
+        Date now = new Date();
+        assertThat(taskResultStatisticsRepository.findTaskResultStatistics(now, StatisticInterval.MINUTE.name()).size(), is(0));
+        assertThat(taskResultStatisticsRepository.findTaskResultStatistics(now, StatisticInterval.HOUR.name()).size(), is(0));
+        assertThat(taskResultStatisticsRepository.findTaskResultStatistics(now, StatisticInterval.DAY.name()).size(), is(0));
+    }
+    
+    @Test
+    public void assertFindTaskResultStatisticsWithDifferentFromDate() {
+        Date now = new Date();
+        Date yesterday = getYesterday();
+        for (StatisticInterval each : StatisticInterval.values()) {
+            taskResultStatisticsRepository.save(new TaskResultStatistics(100L, 0L, each.name(), yesterday));
+            taskResultStatisticsRepository.save(new TaskResultStatistics(100L, 0L, each.name(), now));
+            assertThat(taskResultStatisticsRepository.findTaskResultStatistics(yesterday, each.name()).size(), is(2));
+            assertThat(taskResultStatisticsRepository.findTaskResultStatistics(now, each.name()).size(), is(1));
+        }
+    }
+    
+    @Test
+    public void assertGetSummedTaskResultStatisticsWhenTableIsEmpty() {
+        for (StatisticInterval each : StatisticInterval.values()) {
+            TaskResultStatistics po = taskResultStatisticsRepository.getSummedTaskResultStatistics(new Date(), each.name());
+            assertThat(po.getSuccessCount(), nullValue());
+            assertThat(po.getFailedCount(), nullValue());
+        }
+    }
+    
+    @Test
+    public void assertGetSummedTaskResultStatistics() {
+        for (StatisticInterval each : StatisticInterval.values()) {
+            Date date = new Date();
+            taskResultStatisticsRepository.save(new TaskResultStatistics(100L, 2L, each.name(), date));
+            taskResultStatisticsRepository.save(new TaskResultStatistics(200L, 5L, each.name(), date));
+            TaskResultStatistics po = taskResultStatisticsRepository.getSummedTaskResultStatistics(date, each.name());
+            assertThat(po.getSuccessCount(), is(300L));
+            assertThat(po.getFailedCount(), is(7L));
+        }
+    }
+
+    @Test
+    public void assertFindTaskRunningStatisticsWhenTableIsEmpty() {
+        assertThat(taskRunningStatisticsRepository.findTaskRunningStatistics(new Date()).size(), is(0));
+    }
+    
+    @Test
+    public void assertFindTaskRunningStatisticsWithDifferentFromDate() {
+        Date now = new Date();
+        Date yesterday = getYesterday();
+        taskRunningStatisticsRepository.deleteAll();
+        taskRunningStatisticsRepository.save(new TaskRunningStatistics(100, yesterday));
+        taskRunningStatisticsRepository.save(new TaskRunningStatistics(100, now));
+        assertThat(taskRunningStatisticsRepository.findTaskRunningStatistics(yesterday).size(), is(2));
+        assertThat(taskRunningStatisticsRepository.findTaskRunningStatistics(now).size(), is(1));
+    }
+    
+    @Test
+    public void assertFindJobRunningStatisticsWhenTableIsEmpty() {
+        assertThat(jobRunningStatisticsRepository.findJobRunningStatistics(new Date()).size(), is(0));
+    }
+    
+    @Test
+    public void assertFindJobRunningStatisticsWithDifferentFromDate() {
+        Date now = new Date();
+        Date yesterday = getYesterday();
+        jobRunningStatisticsRepository.deleteAll();
+        jobRunningStatisticsRepository.save(new JobRunningStatistics(100, yesterday));
+        jobRunningStatisticsRepository.save(new JobRunningStatistics(100, now));
+        assertThat(jobRunningStatisticsRepository.findJobRunningStatistics(yesterday).size(), is(2));
+        assertThat(jobRunningStatisticsRepository.findJobRunningStatistics(now).size(), is(1));
+    }
+    
+    @Test
+    public void assertFindJobRegisterStatisticsWhenTableIsEmpty() {
+        assertThat(jobRegisterStatisticsRepository.findJobRegisterStatistics(new Date()).size(), is(0));
+    }
+    
+    @Test
+    public void assertFindJobRegisterStatisticsWithDifferentFromDate() {
+        Date now = new Date();
+        Date yesterday = getYesterday();
+        jobRegisterStatisticsRepository.save(new JobRegisterStatistics(100, yesterday));
+        jobRegisterStatisticsRepository.save(new JobRegisterStatistics(100, now));
+        assertThat(jobRegisterStatisticsRepository.findJobRegisterStatistics(yesterday).size(), is(2));
+        assertThat(jobRegisterStatisticsRepository.findJobRegisterStatistics(now).size(), is(1));
+    }
+    
+    private Date getYesterday() {
+        return new Date(new Date().getTime() - 24 * 60 * 60 * 1000);
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtilsTest.java b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtilsTest.java
new file mode 100644
index 0000000..590c9f8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtilsTest.java
@@ -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.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.util;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public final class HomeFolderUtilsTest {
+    
+    private static final String HOME_FOLDER = System.getProperty("user.home") + File.separator + ".elasticjob-console" + File.separator;
+    
+    @Test
+    public void assertGetFilePathInHomeFolder() {
+        assertThat(HomeFolderUtils.getFilePathInHomeFolder("test_file"), is(HOME_FOLDER + "test_file"));
+    }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/config/index.js b/shardingsphere-elasticjob-ui-frontend/config/index.js
index fdce0d8..38637c9 100644
--- a/shardingsphere-elasticjob-ui-frontend/config/index.js
+++ b/shardingsphere-elasticjob-ui-frontend/config/index.js
@@ -28,7 +28,7 @@ module.exports = {
     assetsPublicPath: '/',
     proxyTable: {
       '/api': {
-        target: 'http://localhost:8089',
+        target: 'http://localhost:8899',
         changeOrigin: true,
         pathRewrite: {
           '^/api': '/api'
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
index cdd3b6e..ad569ac 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
@@ -20,38 +20,47 @@ export default {
     home: 'Home',
     menuData: [
       {
-        title: 'Config Center',
+        title: 'Global settings',
         child: [
           {
-            title: 'Config Server',
-            href: '/config-center'
+            title: 'Registry center',
+            href: '/registry-center'
           },
           {
-            title: 'Rule Config',
-            href: '/rule-config'
+            title: 'Event trace data source',
+            href: '/data-source'
           }
         ]
       },
       {
-        title: 'Registry Center',
+        title: 'Job operation',
         child: [
           {
-            title: 'Registry Server',
-            href: '/registry-center'
+            title: 'Job dimension',
+            href: '/operation-jobs'
           },
           {
-            title: 'Runtime Status',
-            href: '/runtime-status'
+            title: 'Server dimension',
+            href: '/operation-servers'
           }
         ]
       },
       {
-        title: 'Data scaling',
-        href: '/data-scaling'
+        title: 'Job history',
+        child: [
+          {
+            title: 'Job trace',
+            href: '/history-trace'
+          },
+          {
+            title: 'History status',
+            href: '/history-status'
+          }
+        ]
       },
       {
-        title: 'Cluster state',
-        href: '/cluster-state'
+        title: 'Help',
+        href: '/job-help'
       }
     ],
     connected: 'Connected',
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
index 7d16891..d860c3d 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
@@ -20,38 +20,47 @@ export default {
     home: '主页',
     menuData: [
       {
-        title: '配置中心',
+        title: '全局配置',
         child: [
           {
-            title: '服务列表',
-            href: '/config-center'
+            title: '注册中心配置',
+            href: '/registry-center'
           },
           {
-            title: '配置管理',
-            href: '/rule-config'
+            title: '事件追踪数据源配置',
+            href: '/data-source'
           }
         ]
       },
       {
-        title: '注册中心',
+        title: '作业操作',
         child: [
           {
-            title: '服务列表',
-            href: '/registry-center'
+            title: '作业维度',
+            href: '/operation-jobs'
           },
           {
-            title: '运行状态',
-            href: '/runtime-status'
+            title: '服务器维度',
+            href: '/operation-servers'
           }
         ]
       },
       {
-        title: '数据扩容',
-        href: '/data-scaling'
+        title: '作业历史',
+        child: [
+          {
+            title: '历史轨迹',
+            href: '/history-trace'
+          },
+          {
+            title: '历史状态',
+            href: '/history-status'
+          }
+        ]
       },
       {
-        title: '节点状态',
-        href: '/cluster-state'
+        title: '帮助',
+        href: '/job-help'
       }
     ],
     connect: '已连接',


[shardingsphere-elasticjob-ui] 10/11: Fixes checkstyle

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit 46f6743969a2ca9024ee56a2cf8e8ea983c5f984
Author: menghaoranss <lo...@163.com>
AuthorDate: Fri Jul 17 18:43:40 2020 +0800

    Fixes checkstyle
---
 .../src/views/data-source/module/dataSource.vue    |  2 +-
 .../src/views/help/index.vue                       | 22 +++++++++++-----------
 .../registry-center/module/registryCenter.vue      |  6 +++---
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue
index 3da97a7..10ccf74 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue
@@ -22,8 +22,8 @@
         class="btn-plus"
         type="primary"
         icon="el-icon-plus"
-        @click="add"
         :disabled="isGuest"
+        @click="add"
       >{{ $t("dataSource.btnTxt") }}</el-button>
     </div>
     <div class="table-wrap">
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/help/index.vue b/shardingsphere-elasticjob-ui-frontend/src/views/help/index.vue
index a6874d8..9c8762b 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/views/help/index.vue
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/help/index.vue
@@ -18,22 +18,22 @@
 <template>
   <div class="help-content">
     <section class="content">
-      <h2>{{$t('help.design_concept_title')}}</h2>
+      <h2>{{ $t('help.design_concept_title') }}</h2>
       <ol>
-        <li>{{$t('help.design_concept_info_1')}}</li>
-        <li>{{$t('help.design_concept_info_2')}}</li>
+        <li>{{ $t('help.design_concept_info_1') }}</li>
+        <li>{{ $t('help.design_concept_info_2') }}</li>
       </ol>
-      <h2>{{$t('help.major_features_title')}}</h2>
+      <h2>{{ $t('help.major_features_title') }}</h2>
       <ol>
-        <li>{{$t('help.major_features_info_1')}}</li>
-        <li>{{$t('help.major_features_info_2')}}</li>
-        <li>{{$t('help.major_features_info_3')}}</li>
-        <li>{{$t('help.major_features_info_4')}}</li>
-        <li>{{$t('help.major_features_info_5')}}</li>
+        <li>{{ $t('help.major_features_info_1') }}</li>
+        <li>{{ $t('help.major_features_info_2') }}</li>
+        <li>{{ $t('help.major_features_info_3') }}</li>
+        <li>{{ $t('help.major_features_info_4') }}</li>
+        <li>{{ $t('help.major_features_info_5') }}</li>
       </ol>
-      <h2>{{$t('help.unsupported_title')}}</h2>
+      <h2>{{ $t('help.unsupported_title') }}</h2>
       <ol>
-        <li>{{$t('help.unsupported_info')}}</li>
+        <li>{{ $t('help.unsupported_info') }}</li>
       </ol>
     </section>
   </div>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
index d762f6e..338dea2 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/registry-center/module/registryCenter.vue
@@ -22,8 +22,8 @@
         class="btn-plus"
         type="primary"
         icon="el-icon-plus"
-        @click="add"
         :disabled="isGuest"
+        @click="add"
       >{{ $t("registryCenter.btnTxt") }}</el-button>
     </div>
     <div class="table-wrap">
@@ -47,8 +47,8 @@
                 type="primary"
                 icon="el-icon-link"
                 size="small"
-                @click="handleConnect(scope.row)"
                 :disabled="isGuest"
+                @click="handleConnect(scope.row)"
               />
             </el-tooltip>
             <el-tooltip
@@ -61,8 +61,8 @@
                 size="small"
                 type="danger"
                 icon="el-icon-delete"
-                @click="handlerDel(scope.row)"
                 :disabled="isGuest"
+                @click="handlerDel(scope.row)"
               />
             </el-tooltip>
           </template>


[shardingsphere-elasticjob-ui] 05/11: Refactor event trace data source

Posted by ki...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kimmking pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git

commit e78f320b4aa31cfa67adeec90b4468a269410054
Author: menghaoranss <lo...@163.com>
AuthorDate: Fri Jul 17 15:23:38 2020 +0800

    Refactor event trace data source
---
 .../controller/EventTraceDataSourceController.java |  27 +-
 .../src/lang/en-US.js                              |  30 +-
 .../src/lang/zh-CN.js                              |  34 ++-
 .../src/router/index.js                            |   6 +
 .../{router/index.js => views/data-source/api.js}  |  31 +-
 .../src/views/data-source/index.vue                |  33 +++
 .../src/views/data-source/module/dataSource.vue    | 317 +++++++++++++++++++++
 7 files changed, 410 insertions(+), 68 deletions(-)

diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java
index d4bd7c0..4923a63 100644
--- a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java
@@ -21,6 +21,8 @@ import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfig
 import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceFactory;
 import org.apache.shardingsphere.elasticjob.ui.service.EventTraceDataSourceConfigurationService;
 import org.apache.shardingsphere.elasticjob.ui.util.SessionEventTraceDataSourceConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.web.response.ResponseResult;
+import org.apache.shardingsphere.elasticjob.ui.web.response.ResponseResultUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -39,7 +41,7 @@ import java.util.Collection;
  * Event trace data source RESTful API.
  */
 @RestController
-@RequestMapping("/data-source")
+@RequestMapping("/api/data-source")
 public final class EventTraceDataSourceController {
     
     public static final String DATA_SOURCE_CONFIG_KEY = "data_source_config_key";
@@ -68,10 +70,10 @@ public final class EventTraceDataSourceController {
      * @param request HTTP request
      * @return event trace data source configurations
      */
-    @GetMapping(produces = MediaType.APPLICATION_JSON)
-    public Collection<EventTraceDataSourceConfiguration> load(@Context final HttpServletRequest request) {
+    @GetMapping("/load")
+    public ResponseResult<Collection<EventTraceDataSourceConfiguration>> load(@Context final HttpServletRequest request) {
         eventTraceDataSourceConfigurationService.loadActivated().ifPresent(eventTraceDataSourceConfig -> setDataSourceNameToSession(eventTraceDataSourceConfig, request.getSession()));
-        return eventTraceDataSourceConfigurationService.loadAll().getEventTraceDataSourceConfiguration();
+        return ResponseResultUtil.build(eventTraceDataSourceConfigurationService.loadAll().getEventTraceDataSourceConfiguration());
     }
     
     /**
@@ -80,9 +82,9 @@ public final class EventTraceDataSourceController {
      * @param config event trace data source configuration
      * @return success to added or not
      */
-    @PostMapping(produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
-    public boolean add(@RequestBody final EventTraceDataSourceConfiguration config) {
-        return eventTraceDataSourceConfigurationService.add(config);
+    @PostMapping("/add")
+    public ResponseResult<Boolean> add(@RequestBody final EventTraceDataSourceConfiguration config) {
+        return ResponseResultUtil.build(eventTraceDataSourceConfigurationService.add(config));
     }
     
     /**
@@ -91,8 +93,9 @@ public final class EventTraceDataSourceController {
      * @param config event trace data source configuration
      */
     @DeleteMapping(consumes = MediaType.APPLICATION_JSON)
-    public void delete(@RequestBody final EventTraceDataSourceConfiguration config) {
+    public ResponseResult delete(@RequestBody final EventTraceDataSourceConfiguration config) {
         eventTraceDataSourceConfigurationService.delete(config.getName());
+        return ResponseResultUtil.success();
     }
     
     /**
@@ -103,8 +106,8 @@ public final class EventTraceDataSourceController {
      * @return success or not
      */
     @PostMapping(value = "/connectTest", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
-    public boolean connectTest(@RequestBody final EventTraceDataSourceConfiguration config, @Context final HttpServletRequest request) {
-        return setDataSourceNameToSession(config, request.getSession());
+    public ResponseResult<Boolean> connectTest(@RequestBody final EventTraceDataSourceConfiguration config, @Context final HttpServletRequest request) {
+        return ResponseResultUtil.build(setDataSourceNameToSession(config, request.getSession()));
     }
     
     /**
@@ -115,12 +118,12 @@ public final class EventTraceDataSourceController {
      * @return success or not
      */
     @PostMapping(value = "/connect", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
-    public boolean connect(@RequestBody final EventTraceDataSourceConfiguration config, @Context final HttpServletRequest request) {
+    public ResponseResult<Boolean> connect(@RequestBody final EventTraceDataSourceConfiguration config, @Context final HttpServletRequest request) {
         boolean isConnected = setDataSourceNameToSession(eventTraceDataSourceConfigurationService.find(config.getName(), eventTraceDataSourceConfigurationService.loadAll()), request.getSession());
         if (isConnected) {
             eventTraceDataSourceConfigurationService.load(config.getName());
         }
-        return isConnected;
+        return ResponseResultUtil.build(isConnected);
     }
     
     private boolean setDataSourceNameToSession(final EventTraceDataSourceConfiguration dataSourceConfig, final HttpSession session) {
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
index 6dd2484..7dff279 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
@@ -135,19 +135,18 @@ export default {
       digest: 'Please enter a digest'
     }
   },
-  configCenter: {
+  dataSource: {
     btnTxt: 'ADD',
-    configDialog: {
-      title: 'Add a config center',
-      editTitle: 'Edit config center',
+    addDialog: {
+      title: 'Add a data source',
       name: 'Name',
-      centerType: 'Instance Type',
-      address: 'Address',
-      orchestrationName: 'Orchestration Name',
-      namespaces: 'Namespace',
-      digest: 'Digest',
+      driver: 'Driver',
+      url: 'Url',
+      username: 'Username',
+      password: 'Password',
       btnConfirmTxt: 'Confirm',
-      btnCancelTxt: 'Cancel'
+      btnCancelTxt: 'Cancel',
+      btnConnectTestTxt: 'Test connect'
     },
     table: {
       operate: 'Operate',
@@ -157,12 +156,11 @@ export default {
       operateEdit: 'Edit'
     },
     rules: {
-      name: 'Please enter the name of the config center',
-      address: 'Please enter the config center Address',
-      namespaces: 'Please enter a Namespace',
-      centerType: 'Please select a Center Type',
-      orchestrationName: 'Please enter a Orchestration Name',
-      digest: 'Please enter a digest'
+      name: 'Please enter the name of the data source',
+      driver: 'Please enter the driver of the data source',
+      url: 'Please enter the url of the data source',
+      username: 'Please enter the username of the data source',
+      password: 'Please enter the password of the data source'
     }
   },
   runtimeStatus: {
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
index d860c3d..7e02847 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
@@ -135,34 +135,32 @@ export default {
       digest: '请输入登录凭证'
     }
   },
-  configCenter: {
+  dataSource: {
     btnTxt: '添加',
-    configDialog: {
-      title: '添加配置中心',
-      editTitle: '编辑配置中心',
-      name: '配置中心名称',
-      centerType: '配置中心类型',
-      address: '配置中心地址',
-      orchestrationName: '数据治理实例',
-      namespaces: '命名空间',
-      digest: '登录凭证',
+    addDialog: {
+      title: '添加事件追踪数据源',
+      name: '数据源名称',
+      driver: '数据源驱动',
+      url: '数据源连接地址',
+      username: '数据源用户名',
+      password: '数据源密码',
       btnConfirmTxt: '确定',
-      btnCancelTxt: '取消'
+      btnCancelTxt: '取消',
+      btnConnectTestTxt: '测试连接'
     },
     table: {
       operate: '操作',
       operateConnect: '连接',
-      operateConnected: '已激活',
+      operateConnected: '已连接',
       operateDel: '删除',
       operateEdit: '编辑'
     },
     rules: {
-      name: '请输入配置中心名称',
-      centerType: '请选择配置中心类型',
-      namespaces: '请输入命名空间',
-      address: '请选输入配置中心地址',
-      orchestrationName: '请输入数据治理实例名称',
-      digest: '请输入登录凭证'
+      name: '请输入数据源名称',
+      driver: '请输入数据源驱动',
+      url: '请输入数据源连接地址',
+      username: '请输入数据源用户名',
+      password: '请输入数据源密码'
     }
   },
   runtimeStatus: {
diff --git a/shardingsphere-elasticjob-ui-frontend/src/router/index.js b/shardingsphere-elasticjob-ui-frontend/src/router/index.js
index 898163c..f8780fa 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/router/index.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/router/index.js
@@ -32,6 +32,12 @@ export const constantRouterMap = [
     hidden: true,
     name: 'Registry center'
   },
+  {
+    path: '/data-source',
+    component: () => import('@/views/data-source'),
+    hidden: true,
+    name: 'Data source'
+  },
 ]
 
 export default new Router({
diff --git a/shardingsphere-elasticjob-ui-frontend/src/router/index.js b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/api.js
similarity index 61%
copy from shardingsphere-elasticjob-ui-frontend/src/router/index.js
copy to shardingsphere-elasticjob-ui-frontend/src/views/data-source/api.js
index 898163c..a0743c1 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/router/index.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/api.js
@@ -15,26 +15,13 @@
  * limitations under the License.
  */
 
-import Vue from 'vue'
-import Router from 'vue-router'
+import API from '@/utils/api'
 
-Vue.use(Router)
-
-export const constantRouterMap = [
-  {
-    path: '/login',
-    component: () => import('@/views/login'),
-    hidden: true
-  },
-  {
-    path: '/registry-center',
-    component: () => import('@/views/registry-center'),
-    hidden: true,
-    name: 'Registry center'
-  },
-]
-
-export default new Router({
-  scrollBehavior: () => ({ y: 0 }),
-  routes: constantRouterMap
-})
+export default {
+  load: (params = {}) => API.get(`/api/data-source/load`, params),
+  delete: (params = {}) => API.delete(`/api/data-source`, params),
+  add: (params = {}) => API.post(`/api/data-source/add`, params),
+  getRegCenterActivated: (params = {}) => API.get(`/api/data-source/activated`, params),
+  connect: (params = {}) => API.post(`/api/data-source/connect`, params),
+  connectTest: (params = {}) => API.post(`/api/data-source/connectTest`, params)
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/data-source/index.vue b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/index.vue
new file mode 100644
index 0000000..70cffeb
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/index.vue
@@ -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.
+  -->
+
+<template>
+  <s-data-source />
+</template>
+
+<script>
+import SDataSource from './module/dataSource'
+export default {
+  name: 'DataSource',
+  components: {
+    SDataSource
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+</style>
diff --git a/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue
new file mode 100644
index 0000000..c9a9f6e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-frontend/src/views/data-source/module/dataSource.vue
@@ -0,0 +1,317 @@
+<!--
+  - 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.
+  -->
+
+<template>
+  <el-row class="box-card">
+    <div class="btn-group">
+      <el-button
+        class="btn-plus"
+        type="primary"
+        icon="el-icon-plus"
+        @click="add"
+      >{{ $t("dataSource.btnTxt") }}</el-button>
+    </div>
+    <div class="table-wrap">
+      <el-table :data="tableData" border style="width: 100%">
+        <el-table-column
+          v-for="(item, index) in column"
+          :key="index"
+          :prop="item.prop"
+          :label="item.label"
+          :width="item.width"
+        />
+        <el-table-column :label="$t('dataSource.table.operate')" fixed="right" width="200">
+          <template slot-scope="scope">
+            <el-tooltip
+              :content="!scope.row.activated ? $t('dataSource.table.operateConnect'): $t('dataSource.table.operateConnected')"
+              class="item"
+              effect="dark"
+              placement="top"
+            >
+              <el-button
+                type="primary"
+                icon="el-icon-link"
+                size="small"
+                @click="handleConnect(scope.row)"
+              />
+            </el-tooltip>
+            <el-tooltip
+              :content="$t('dataSource.table.operateDel')"
+              class="item"
+              effect="dark"
+              placement="top"
+            >
+              <el-button
+                size="small"
+                type="danger"
+                icon="el-icon-delete"
+                @click="handlerDel(scope.row)"
+              />
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="pagination">
+        <el-pagination
+          :total="total"
+          :current-page="currentPage"
+          background
+          layout="prev, pager, next"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
+    <el-dialog
+      :title="$t('dataSource.addDialog.title')"
+      :visible.sync="regustDialogVisible"
+      width="1010px"
+    >
+      <el-form ref="form" :model="form" :rules="rules" label-width="170px">
+        <el-form-item :label="$t('dataSource.addDialog.name')" prop="name">
+          <el-input :placeholder="$t('dataSource.rules.name')" v-model="form.name" autocomplete="off" />
+        </el-form-item>
+        <el-form-item :label="$t('dataSource.addDialog.driver')" prop="driver">
+          <el-input
+            :placeholder="$t('dataSource.rules.driver')"
+            v-model="form.driver"
+            autocomplete="off"
+          />
+        </el-form-item>
+        <el-form-item :label="$t('dataSource.addDialog.url')" prop="url">
+          <el-input
+            :placeholder="$t('dataSource.rules.url')"
+            v-model="form.url"
+            autocomplete="off"
+          />
+        </el-form-item>
+        <el-form-item :label="$t('dataSource.addDialog.username')" prop="username">
+          <el-input
+            :placeholder="$t('dataSource.rules.username')"
+            v-model="form.username"
+            autocomplete="off"
+          />
+        </el-form-item>
+        <el-form-item :label="$t('dataSource.addDialog.password')">
+          <el-input
+            :placeholder="$t('dataSource.rules.password')"
+            v-model="form.password"
+            autocomplete="off"
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="regustDialogVisible = false">{{ $t("dataSource.addDialog.btnCancelTxt") }}</el-button>
+        <el-button
+          type="primary"
+          @click="connectTest('form')"
+        >{{ $t("dataSource.addDialog.btnConnectTestTxt") }}</el-button>
+        <el-button
+          type="primary"
+          @click="onConfirm('form')"
+        >{{ $t("dataSource.addDialog.btnConfirmTxt") }}</el-button>
+      </div>
+    </el-dialog>
+
+  </el-row>
+</template>
+<script>
+import { mapActions } from 'vuex'
+import clone from 'lodash/clone'
+import API from '../api'
+export default {
+  name: 'DataSource',
+  data() {
+    return {
+      regustDialogVisible: false,
+      column: [
+        {
+          label: this.$t('dataSource').addDialog.name,
+          prop: 'name'
+        },
+        {
+          label: this.$t('dataSource').addDialog.driver,
+          prop: 'driver'
+        },
+        {
+          label: this.$t('dataSource').addDialog.url,
+          prop: 'url'
+        },
+        {
+          label: this.$t('dataSource').addDialog.username,
+          prop: 'username'
+        },
+        {
+          label: this.$t('dataSource').addDialog.password,
+          prop: 'password'
+        }
+      ],
+      form: {
+        name: '',
+        driver: '',
+        url: '',
+        username: '',
+        password: ''
+      },
+      rules: {
+        name: [
+          {
+            required: true,
+            message: this.$t('dataSource').rules.name,
+            trigger: 'change'
+          }
+        ],
+        driver: [
+          {
+            required: true,
+            message: this.$t('dataSource').rules.driver,
+            trigger: 'change'
+          }
+        ],
+        url: [
+          {
+            required: true,
+            message: this.$t('dataSource').rules.url,
+            trigger: 'change'
+          }
+        ],
+        username: [
+          {
+            required: true,
+            message: this.$t('dataSource').rules.username,
+            trigger: 'change'
+          }
+        ],
+        password: [
+          {
+            required: true,
+            message: this.$t('dataSource').rules.password,
+            trigger: 'change'
+          }
+        ]
+      },
+      tableData: [],
+      cloneTableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: null
+    }
+  },
+  created() {
+    this.load()
+  },
+  methods: {
+    ...mapActions(['setRegCenterActivated']),
+    handleCurrentChange(val) {
+      const data = clone(this.cloneTableData)
+      this.tableData = data.splice(val - 1, this.pageSize)
+    },
+    load() {
+      API.load().then(res => {
+        const data = res.model
+        this.total = data.length
+        this.cloneTableData = clone(res.model)
+        this.tableData = data.splice(0, this.pageSize)
+      })
+      //this.getRegCenterActivated()
+    },
+    getRegCenterActivated() {
+      API.getRegCenterActivated().then(res => {
+        this.setRegCenterActivated(res.model.name)
+      })
+    },
+    handleConnect(row) {
+      if (row.activated) {
+        this.$notify({
+          title: this.$t('common').notify.title,
+          message: this.$t('common').connected,
+          type: 'success'
+        })
+      } else {
+        const params = {
+          name: row.name
+        }
+        API.connect(params).then(res => {
+          this.$notify({
+            title: this.$t('common').notify.title,
+            message: this.$t('common').notify.conSucMessage,
+            type: 'success'
+          })
+          this.load()
+        })
+      }
+    },
+    handlerDel(row) {
+      const params = {
+        name: row.name
+      }
+      API.delete(params).then(res => {
+        this.$notify({
+          title: this.$t('common').notify.title,
+          message: this.$t('common').notify.delSucMessage,
+          type: 'success'
+        })
+        this.load()
+      })
+    },
+    onConfirm(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          API.add(this.form).then(res => {
+            this.regustDialogVisible = false
+            this.$notify({
+              title: this.$t('common').notify.title,
+              message: this.$t('common').notify.addSucMessage,
+              type: 'success'
+            })
+            this.load()
+          })
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    connectTest(formName) {
+      this.$refs[formName].validate(valid => {
+        if (valid) {
+          API.connectTest(this.form).then(res => {
+            this.$notify({
+              title: this.$t('common').notify.title,
+              message: this.$t('common').notify.addSucMessage,
+              type: 'success'
+            })
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    add() {
+      this.regustDialogVisible = true
+    }
+  }
+}
+</script>
+<style lang='scss' scoped>
+.btn-group {
+  margin-bottom: 20px;
+}
+.pagination {
+  float: right;
+  margin: 10px -10px 10px 0;
+}
+</style>