This is an automated email from the ASF dual-hosted git repository. zhaoyanan pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-shardingsphere-benchmark.git
commit e6e1fb4127ac3ae69da6eb74e84970dc76fbf69c Author: wqzwh <[email protected]> AuthorDate: Thu Sep 26 15:28:22 2019 +0800 feature:add ui-frontend project --- web/.babelrc | 27 ++ web/.editorconfig | 9 + web/.eslintignore | 4 + web/.eslintrc.js | 297 +++++++++++++++++++++ web/.gitignore | 17 ++ web/.postcssrc.js | 27 ++ web/README.md | 17 ++ web/build/build.js | 58 ++++ web/build/check-versions.js | 71 +++++ web/build/utils.js | 125 +++++++++ web/build/vue-loader.conf.js | 22 ++ web/build/webpack.base.conf.js | 119 +++++++++ web/build/webpack.dev.conf.js | 131 +++++++++ web/build/webpack.prod.conf.js | 152 +++++++++++ web/config/dev.env.js | 24 ++ web/config/index.js | 100 +++++++ web/config/prod.env.js | 21 ++ web/favicon.ico | Bin 0 -> 9662 bytes web/favicon.png | Bin 0 -> 24930 bytes web/index.html | 32 +++ web/package.json | 87 ++++++ web/src/App.vue | 18 ++ web/src/assets/logo.png | Bin 0 -> 24930 bytes web/src/assets/logo_top.png | Bin 0 -> 8832 bytes web/src/components/Container/index.vue | 185 +++++++++++++ web/src/components/Footer/index.vue | 24 ++ web/src/main.js | 15 ++ web/src/router/index.js | 37 +++ web/src/utils/line.js | 50 ++++ web/src/utils/mixin.js | 69 +++++ web/src/utils/utils.js | 11 + web/src/views/mysql-vs-sharding/index.vue | 64 +++++ .../sharding-proxy-master-slave-sharding/index.vue | 64 +++++ .../views/sharding-proxy-master-slave/index.vue | 64 +++++ .../index.vue | 64 +++++ web/static/.gitkeep | 0 web/static/404.html | 31 +++ 37 files changed, 2036 insertions(+) diff --git a/web/.babelrc b/web/.babelrc new file mode 100644 index 0000000..f261300 --- /dev/null +++ b/web/.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/web/.editorconfig b/web/.editorconfig new file mode 100644 index 0000000..9d08a1a --- /dev/null +++ b/web/.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/web/.eslintignore b/web/.eslintignore new file mode 100644 index 0000000..e1fcc9c --- /dev/null +++ b/web/.eslintignore @@ -0,0 +1,4 @@ +/build/ +/config/ +/dist/ +/*.js diff --git a/web/.eslintrc.js b/web/.eslintrc.js new file mode 100644 index 0000000..a588840 --- /dev/null +++ b/web/.eslintrc.js @@ -0,0 +1,297 @@ +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/no-parsing-error': [2, { 'x-invalid-end-tag': false }], + 'vue/html-indent': [ + 'off', + 2, + { + attribute: 1, + baseIndent: 1, + closeBracket: 0, + alignAttributesVertically: true, + ignores: [] + } + ], + 'no-tabs': 'off', + '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: [0, 2], + // 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/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..6bc0c43 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,17 @@ +.DS_Store +node_modules/ +node/ +/dist/ +/coverage/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln diff --git a/web/.postcssrc.js b/web/.postcssrc.js new file mode 100644 index 0000000..dc9c58f --- /dev/null +++ b/web/.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/web/README.md b/web/README.md new file mode 100644 index 0000000..be27161 --- /dev/null +++ b/web/README.md @@ -0,0 +1,17 @@ +# incubator-shardingsphere-benchmark-ui-frontend" + +## Build Setup + +```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 +``` diff --git a/web/build/build.js b/web/build/build.js new file mode 100644 index 0000000..b6d0ada --- /dev/null +++ b/web/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/web/build/check-versions.js b/web/build/check-versions.js new file mode 100644 index 0000000..b07e6e8 --- /dev/null +++ b/web/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/web/build/utils.js b/web/build/utils.js new file mode 100644 index 0000000..5c6cf79 --- /dev/null +++ b/web/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/web/build/vue-loader.conf.js b/web/build/vue-loader.conf.js new file mode 100644 index 0000000..9c30005 --- /dev/null +++ b/web/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/web/build/webpack.base.conf.js b/web/build/webpack.base.conf.js new file mode 100644 index 0000000..76b5575 --- /dev/null +++ b/web/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/web/build/webpack.dev.conf.js b/web/build/webpack.dev.conf.js new file mode 100644 index 0000000..3dd767e --- /dev/null +++ b/web/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('favicon.png'), + title: 'sharding-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/web/build/webpack.prod.conf.js b/web/build/webpack.prod.conf.js new file mode 100644 index 0000000..58b5373 --- /dev/null +++ b/web/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('favicon.png'), + title: 'sharding-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/web/config/dev.env.js b/web/config/dev.env.js new file mode 100644 index 0000000..58340ed --- /dev/null +++ b/web/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/web/config/index.js b/web/config/index.js new file mode 100644 index 0000000..ceb6f12 --- /dev/null +++ b/web/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:8088', + 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/web/config/prod.env.js b/web/config/prod.env.js new file mode 100644 index 0000000..00279d4 --- /dev/null +++ b/web/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/web/favicon.ico b/web/favicon.ico new file mode 100644 index 0000000..83655b2 Binary files /dev/null and b/web/favicon.ico differ diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 0000000..209bb49 Binary files /dev/null and b/web/favicon.png differ diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..364ecc1 --- /dev/null +++ b/web/index.html @@ -0,0 +1,32 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ 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>Sharding Performance monitoring</title> +</head> + +<body> + <div id="app"></div> + <!-- built files will be auto injected --> +</body> + +</html> diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..c237062 --- /dev/null +++ b/web/package.json @@ -0,0 +1,87 @@ +{ + "name": "incubator-shardingsphere-benchmark-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" + }, + "dependencies": { + "echarts": "^4.3.0", + "vue-echarts": "^4.0.4", + "iview": "^3.5.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", + "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", + "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", + "mini-css-extract-plugin": "^0.6.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", + "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/web/src/App.vue b/web/src/App.vue new file mode 100644 index 0000000..28de323 --- /dev/null +++ b/web/src/App.vue @@ -0,0 +1,18 @@ +<template> + <div id="app"> + <Container> + <router-view /> + </Container> + </div> +</template> + +<script> +import Container from '@/components/Container' + +export default { + name: 'App', + components: { + Container + } +} +</script> diff --git a/web/src/assets/logo.png b/web/src/assets/logo.png new file mode 100644 index 0000000..209bb49 Binary files /dev/null and b/web/src/assets/logo.png differ diff --git a/web/src/assets/logo_top.png b/web/src/assets/logo_top.png new file mode 100644 index 0000000..ff22614 Binary files /dev/null and b/web/src/assets/logo_top.png differ diff --git a/web/src/components/Container/index.vue b/web/src/components/Container/index.vue new file mode 100644 index 0000000..1b2e15a --- /dev/null +++ b/web/src/components/Container/index.vue @@ -0,0 +1,185 @@ +<template> + <div class="layout"> + <Layout> + <Sider + ref="side1" + v-model="isCollapsed" + :collapsed-width="78" + class="layout-sider" + hide-trigger + collapsible + > + <div class="i-layout-sider-logo i-layout-sider-logo-dark"> + <a href="/" target="_self" class="i-link i-link-color"> + <img class="logo" src="../../assets/logo_top.png" /> + <img class="collapse-logo" src="../../assets/logo.png" alt="logo" /> + </a> + </div> + <Menu :class="menuitemClasses" active-name="1-2" theme="dark" width="auto"> + <router-link to="mysql-vs-sharding"> + <MenuItem name="1-2"> + <Tooltip content="mysqlVsSharding" placement="right"> + <span>mysqlVsSharding</span> + </Tooltip> + </MenuItem> + </router-link> + <router-link to="sharding-proxy-master-slave"> + <MenuItem name="1-3"> + <Tooltip content="shardingProxyMasterSlave" placement="right"> + <span>shardingProxyMasterSlave</span> + </Tooltip> + </MenuItem> + </router-link> + <router-link to="sharding-proxy-master-slave-sharding"> + <MenuItem name="1-4"> + <Tooltip content="shardingProxyMasterSlaveSharding" placement="right"> + <span>shardingProxyMasterSlaveSharding</span> + </Tooltip> + </MenuItem> + </router-link> + <router-link to="sharding-proxy-single-database-single-table"> + <MenuItem name="1-5"> + <Tooltip content="shardingProxySingleDatabaseSingleTable" placement="right"> + <span>shardingProxySingleDatabaseSingleTable</span> + </Tooltip> + </MenuItem> + </router-link> + </Menu> + </Sider> + <Layout style="margin-left: 200px;"> + <Header :style="{padding: 0}" class="layout-header-bar"> + <!-- <Icon + :class="rotateIcon" + :style="{margin: '0 20px', color: '#f6ca9d', cursor: 'pointer'}" + size="24" + type="md-menu" + @click.native="collapsedSider" + />--> + </Header> + <Content> + <slot /> + </Content> + <v-footer /> + </Layout> + </Layout> + </div> +</template> +<script> +import Footer from '../Footer/index.vue' +export default { + name: 'Container', + components: { + 'v-footer': Footer + }, + data() { + return { + isCollapsed: false + } + }, + computed: { + rotateIcon() { + return ['menu-icon', this.isCollapsed ? 'rotate-icon' : ''] + }, + menuitemClasses() { + return ['menu-item', this.isCollapsed ? 'collapsed-menu' : ''] + } + }, + methods: { + collapsedSider() { + // this.$refs.side1.toggleCollapse() + } + } +} +</script> +<style scoped> +.layout { + background: #f5f7f9; + position: relative; + overflow: hidden; +} +a { + color: #fff; +} +.layout-header-bar { + background: #fff; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); +} +.layout-logo-left { + width: 90%; + height: 30px; + background: #5b6270; + border-radius: 3px; + margin: 15px auto; +} +.menu-icon { + transition: all 0.3s; +} +.rotate-icon { + transform: rotate(-90deg); +} +.menu-item { + background: #1d1e23; +} +.menu-item span { + display: inline-block; + width: 130px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: bottom; + transition: width 0.2s ease 0.2s; +} +.menu-item i { + transform: translateX(0px); + transition: font-size 0.2s ease, transform 0.2s ease; + vertical-align: middle; + font-size: 16px; +} +.collapsed-menu span { + width: 0px; + transition: width 0.2s ease; +} +.collapsed-menu i { + transform: translateX(5px); + transition: font-size 0.2s ease 0.2s, transform 0.2s ease 0.2s; + vertical-align: middle; + font-size: 22px; +} +.i-layout-sider-logo { + height: 63px; + line-height: 63px; + text-align: center; + border-bottom: 1px solid #f8f8f9; +} +.i-layout-sider-logo-dark { + border-bottom: 1px solid #101117; + background: #1d1e23; +} +.i-layout-sider-logo img { + height: 54%; + vertical-align: middle; +} +.layout-header-bar { + background: #1d1e23; + background: linear-gradient(90deg, #1d1e23, #3f4045); +} +.layout-sider { + background: #1d1e23; + z-index: 99; + position: fixed; + left: 0; + height: 100%; +} +.layout-sider .ivu-layout-sider-children { + background: #1d1e23 !important; +} +.ivu-layout-sider-collapsed .logo { + display: none; +} +.ivu-layout-sider-collapsed .collapse-logo { + display: inline-block; +} +.collapse-logo { + display: none; +} +</style> \ No newline at end of file diff --git a/web/src/components/Footer/index.vue b/web/src/components/Footer/index.vue new file mode 100644 index 0000000..0c4b903 --- /dev/null +++ b/web/src/components/Footer/index.vue @@ -0,0 +1,24 @@ +<template> + <div class="footer-wrapper"> + Copyright + <i class="icon-copyright iconfont" /> 2016 - 2018 The Apache Software Foundation, Licensed under the Apache License, Version 2.0. + </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/web/src/main.js b/web/src/main.js new file mode 100644 index 0000000..f6104a4 --- /dev/null +++ b/web/src/main.js @@ -0,0 +1,15 @@ +import Vue from 'vue' +import App from './App' +import router from './router' + +import iView from 'iview' +import 'iview/dist/styles/iview.css' + +Vue.config.productionTip = false + +Vue.use(iView) + +new Vue({ + router, + render: h => h(App) +}).$mount('#app') diff --git a/web/src/router/index.js b/web/src/router/index.js new file mode 100644 index 0000000..7441fce --- /dev/null +++ b/web/src/router/index.js @@ -0,0 +1,37 @@ +import Vue from 'vue' +import Router from 'vue-router' +Vue.use(Router) + +export const constantRouterMap = [ + { + path: '*', + redirect: '/mysql-vs-sharding' + }, + { + path: '/mysql-vs-sharding', + component: () => import('@/views/mysql-vs-sharding/index'), + hidden: true + }, + { + path: '/sharding-proxy-master-slave', + component: () => import('@/views/sharding-proxy-master-slave/index'), + hidden: true + }, + { + path: '/sharding-proxy-master-slave-sharding', + component: () => + import('@/views/sharding-proxy-master-slave-sharding/index'), + hidden: true + }, + { + path: '/sharding-proxy-single-database-single-table', + component: () => + import('@/views/sharding-proxy-single-database-single-table/index'), + hidden: true + } +] + +export default new Router({ + scrollBehavior: () => ({ y: 0 }), + routes: constantRouterMap +}) diff --git a/web/src/utils/line.js b/web/src/utils/line.js new file mode 100644 index 0000000..bf30a09 --- /dev/null +++ b/web/src/utils/line.js @@ -0,0 +1,50 @@ +const color = ['#2D8CF0', '#9A66E4', '#19BE6B', '#FF9900', '#E46CBB'] +const getLineOptions = (name, xAxis, legend, series) => { + return { + color, + grid: { + left: '2%', + right: '2%', + bottom: '6%', + containLabel: true + }, + tooltip: { + trigger: 'axis', + formatter(d) { + let html = `` + for (const v of d) { + html += `<div style="display:inline-block;margin: 10px;font-size: 14px;"> + <p><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${ + v.color + };"></span>${v.seriesName}</p> + <p>Throughtput: ${v.data.Throughout}</p> + <p>Samples: ${v.data.Samples}</p> + <p>Err: ${v.data.Err}</p> + <p>Max: ${v.data.Max}</p> + <p>Min: ${v.data.Min}</p> + </div>` + } + return html + } + }, + xAxis: { + name: '(TEST TIMES)/DAY', + nameLocation: 'middle', + nameGap: 30, + type: 'category', + boundaryGap: false, + data: xAxis[name] + }, + yAxis: { + name: 'TPS', + type: 'value' + }, + legend: { + data: legend[name], + right: '2%' + }, + series: series[name] + } +} + +export { getLineOptions } diff --git a/web/src/utils/mixin.js b/web/src/utils/mixin.js new file mode 100644 index 0000000..1100e77 --- /dev/null +++ b/web/src/utils/mixin.js @@ -0,0 +1,69 @@ +const mountedMixin = { + data() { + return { + legend: {}, + series: {}, + desc: {}, + xAxis: {} + } + }, + mounted() { + const map = [] + const legend = {} + const series = {} + const desc = {} + const xAxis = {} + for (const v in this.data) { + map.push(v) + if (v !== 'DESC') { + legend[v] = [] + series[v] = [] + xAxis[v] = [] + } + } + for (const m of map) { + if (Object.prototype.toString.call(this.data[m]) === '[object Array]') { + for (const mm of this.data[m]) { + legend[m].push(mm.type) + const data = [] + for (const mmm of Object.keys(mm.data)) { + if (xAxis[m].length !== mm.data.length) { + xAxis[m].push(mmm) + } + data.push({ + ...mm.data[mmm], + value: mm.data[mmm].Throughout + }) + } + series[m].push({ + name: mm.type, + type: 'line', + data + }) + } + } else { + for (const k of map) { + if (k !== m) { + desc[k] = { + mysqlVerison: this.data[m]['mysqlVerison'], + // 'ShardingSphere-proxy': this.data[m]['ShardingSphere-proxy'], + tableNumber: this.data[m]['tableNumber'], + // DataVolume: this.data[m]['DataVolume'], + // X: this.data[m]['X'], + // Y: this.data[m]['Y'], + sceneDescription: this.data[m]['sceneDescription'], + sqlExample: this.data[m][k].SqlExample + // ComparativeType: this.data[m][k].ComparativeType + } + } + } + } + } + this.legend = legend + this.series = series + this.desc = desc + this.xAxis = xAxis + } +} + +export { mountedMixin } diff --git a/web/src/utils/utils.js b/web/src/utils/utils.js new file mode 100644 index 0000000..1f7851a --- /dev/null +++ b/web/src/utils/utils.js @@ -0,0 +1,11 @@ +import mysqlVsShardingproxy from '../../../report/data_json/mysql_vs_shardingproxy.json' +import shardingProxyMasterSlaveSharding from '../../../report/data_json/sharding_proxy_master_slave_sharding.json' +import shardingProxyMasterSlave from '../../../report/data_json/sharding_proxy_master_slave.json' +import shardingProxySingleDatabaseSingleTable from '../../../report/data_json/sharding_proxy_single_database_single_table.json' + +export { + mysqlVsShardingproxy, + shardingProxyMasterSlaveSharding, + shardingProxyMasterSlave, + shardingProxySingleDatabaseSingleTable +} diff --git a/web/src/views/mysql-vs-sharding/index.vue b/web/src/views/mysql-vs-sharding/index.vue new file mode 100644 index 0000000..5125c39 --- /dev/null +++ b/web/src/views/mysql-vs-sharding/index.vue @@ -0,0 +1,64 @@ +<template> + <Row :gutter="16" style="background:#eee; padding:20px"> + <Col v-for="(value, name, index) in series" :key="index" class="col-item" span="24"> + <Card :bordered="false"> + <p slot="title" style="font-size: 18px">{{ name.toLowerCase() }} throughtout compare</p> + <v-chart :options="getOptions(name)" /> + <Form :label-width="140"> + <FormItem + v-for="(value, name,indx) in desc[name]" + :label="`${name}:`" + :key="indx" + >{{ value }}</FormItem> + </Form> + </Card> + </Col> + </Row> +</template> + +<script> +import ECharts from 'vue-echarts' +import 'echarts/lib/chart/line' +import 'echarts/lib/component/tooltip' +import 'echarts/lib/component/legend' +import 'echarts/lib/component/title' +import { mysqlVsShardingproxy } from '../../utils/utils' +import { mountedMixin } from '../../utils/mixin' +import { getLineOptions } from '../../utils/line' + +export default { + name: 'Home', + components: { + 'v-chart': ECharts + }, + mixins: [mountedMixin], + data() { + return { + data: mysqlVsShardingproxy + } + }, + methods: { + getOptions(name) { + return getLineOptions(name, this.xAxis, this.legend, this.series) + } + } +} +</script> +<style> +.echarts { + width: 100%; + height: 400px; +} +.col-item { + margin-bottom: 16px; +} +.ivu-form-item { + margin-bottom: 10px !important; +} +.ivu-form-item-label { + font-size: 15px !important; +} +.ivu-form-item-content { + font-size: 14px !important; +} +</style> \ No newline at end of file diff --git a/web/src/views/sharding-proxy-master-slave-sharding/index.vue b/web/src/views/sharding-proxy-master-slave-sharding/index.vue new file mode 100644 index 0000000..19cbef9 --- /dev/null +++ b/web/src/views/sharding-proxy-master-slave-sharding/index.vue @@ -0,0 +1,64 @@ +<template> + <Row :gutter="16" style="background:#eee; padding:20px"> + <Col v-for="(value, name, index) in series" :key="index" class="col-item" span="24"> + <Card :bordered="false"> + <p slot="title" style="font-size: 18px">{{ name.toLowerCase() }} throughtout compare</p> + <v-chart :options="getOptions(name)" /> + <Form :label-width="140"> + <FormItem + v-for="(value, name,indx) in desc[name]" + :label="`${name}:`" + :key="indx" + >{{ value }}</FormItem> + </Form> + </Card> + </Col> + </Row> +</template> + +<script> +import ECharts from 'vue-echarts' +import 'echarts/lib/chart/line' +import 'echarts/lib/component/tooltip' +import 'echarts/lib/component/legend' +import 'echarts/lib/component/title' +import { shardingProxyMasterSlaveSharding } from '../../utils/utils' +import { mountedMixin } from '../../utils/mixin' +import { getLineOptions } from '../../utils/line' + +export default { + name: 'Home', + components: { + 'v-chart': ECharts + }, + mixins: [mountedMixin], + data() { + return { + data: shardingProxyMasterSlaveSharding + } + }, + methods: { + getOptions(name) { + return getLineOptions(name, this.xAxis, this.legend, this.series) + } + } +} +</script> +<style> +.echarts { + width: 100%; + height: 400px; +} +.col-item { + margin-bottom: 16px; +} +.ivu-form-item { + margin-bottom: 10px !important; +} +.ivu-form-item-label { + font-size: 15px !important; +} +.ivu-form-item-content { + font-size: 14px !important; +} +</style> \ No newline at end of file diff --git a/web/src/views/sharding-proxy-master-slave/index.vue b/web/src/views/sharding-proxy-master-slave/index.vue new file mode 100644 index 0000000..1be9b47 --- /dev/null +++ b/web/src/views/sharding-proxy-master-slave/index.vue @@ -0,0 +1,64 @@ +<template> + <Row :gutter="16" style="background:#eee; padding:20px"> + <Col v-for="(value, name, index) in series" :key="index" class="col-item" span="24"> + <Card :bordered="false"> + <p slot="title" style="font-size: 18px">{{ name.toLowerCase() }} throughtout compare</p> + <v-chart :options="getOptions(name)" /> + <Form :label-width="140"> + <FormItem + v-for="(value, name,indx) in desc[name]" + :label="`${name}:`" + :key="indx" + >{{ value }}</FormItem> + </Form> + </Card> + </Col> + </Row> +</template> + +<script> +import ECharts from 'vue-echarts' +import 'echarts/lib/chart/line' +import 'echarts/lib/component/tooltip' +import 'echarts/lib/component/legend' +import 'echarts/lib/component/title' +import { shardingProxyMasterSlave } from '../../utils/utils' +import { mountedMixin } from '../../utils/mixin' +import { getLineOptions } from '../../utils/line' + +export default { + name: 'Home', + components: { + 'v-chart': ECharts + }, + mixins: [mountedMixin], + data() { + return { + data: shardingProxyMasterSlave + } + }, + methods: { + getOptions(name) { + return getLineOptions(name, this.xAxis, this.legend, this.series) + } + } +} +</script> +<style> +.echarts { + width: 100%; + height: 400px; +} +.col-item { + margin-bottom: 16px; +} +.ivu-form-item { + margin-bottom: 10px !important; +} +.ivu-form-item-label { + font-size: 15px !important; +} +.ivu-form-item-content { + font-size: 14px !important; +} +</style> \ No newline at end of file diff --git a/web/src/views/sharding-proxy-single-database-single-table/index.vue b/web/src/views/sharding-proxy-single-database-single-table/index.vue new file mode 100644 index 0000000..ae7b588 --- /dev/null +++ b/web/src/views/sharding-proxy-single-database-single-table/index.vue @@ -0,0 +1,64 @@ +<template> + <Row :gutter="16" style="background:#eee; padding:20px"> + <Col v-for="(value, name, index) in series" :key="index" class="col-item" span="24"> + <Card :bordered="false"> + <p slot="title" style="font-size: 18px">{{ name.toLowerCase() }} throughtout compare</p> + <v-chart :options="getOptions(name)" /> + <Form :label-width="140"> + <FormItem + v-for="(value, name,indx) in desc[name]" + :label="`${name}:`" + :key="indx" + >{{ value }}</FormItem> + </Form> + </Card> + </Col> + </Row> +</template> + +<script> +import ECharts from 'vue-echarts' +import 'echarts/lib/chart/line' +import 'echarts/lib/component/tooltip' +import 'echarts/lib/component/legend' +import 'echarts/lib/component/title' +import { shardingProxySingleDatabaseSingleTable } from '../../utils/utils' +import { mountedMixin } from '../../utils/mixin' +import { getLineOptions } from '../../utils/line' + +export default { + name: 'Home', + components: { + 'v-chart': ECharts + }, + mixins: [mountedMixin], + data() { + return { + data: shardingProxySingleDatabaseSingleTable + } + }, + methods: { + getOptions(name) { + return getLineOptions(name, this.xAxis, this.legend, this.series) + } + } +} +</script> +<style> +.echarts { + width: 100%; + height: 400px; +} +.col-item { + margin-bottom: 16px; +} +.ivu-form-item { + margin-bottom: 10px !important; +} +.ivu-form-item-label { + font-size: 15px !important; +} +.ivu-form-item-content { + font-size: 14px !important; +} +</style> \ No newline at end of file diff --git a/web/static/.gitkeep b/web/static/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/web/static/404.html b/web/static/404.html new file mode 100644 index 0000000..5a0ea23 --- /dev/null +++ b/web/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>sharding-ui</title> +</head> + +<body> + <div>404</div> +</body> + +</html>
