- Initial vue + vuex + vue-router + webpack + quasar setup - Added karma test runner - Added shrinkwrap file - Added junit reporter - Fetch subscriber - Fetch capabilities - Added Dockerfile + testrunner - Added development script for ngcp Change-Id: Ia9e58412d2b71c7e541f3d764f8fda747522c7e6changes/00/16000/14
parent
402d7ea6e1
commit
99bd2371fb
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"presets": [["es2015", {"modules": false}], "stage-2"],
|
||||||
|
"plugins": ["transform-runtime"],
|
||||||
|
"comments": false
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[package.json]
|
||||||
|
indent_size = 2
|
@ -0,0 +1,3 @@
|
|||||||
|
build/*.js
|
||||||
|
config/*.js
|
||||||
|
dist/*.js
|
@ -0,0 +1,39 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
parser: 'babel-eslint',
|
||||||
|
parserOptions: {
|
||||||
|
sourceType: 'module'
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
browser: true
|
||||||
|
},
|
||||||
|
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
|
||||||
|
extends: [
|
||||||
|
'standard'
|
||||||
|
],
|
||||||
|
// required to lint *.vue files
|
||||||
|
plugins: [
|
||||||
|
'html',
|
||||||
|
'import'
|
||||||
|
],
|
||||||
|
globals: {
|
||||||
|
'cordova': true,
|
||||||
|
'DEV': true,
|
||||||
|
'PROD': true,
|
||||||
|
'__THEME': true
|
||||||
|
},
|
||||||
|
// add your custom rules here
|
||||||
|
'rules': {
|
||||||
|
// allow paren-less arrow functions
|
||||||
|
'arrow-parens': 0,
|
||||||
|
'one-var': 0,
|
||||||
|
'import/first': 0,
|
||||||
|
'import/named': 2,
|
||||||
|
'import/namespace': 2,
|
||||||
|
'import/default': 2,
|
||||||
|
'import/export': 2,
|
||||||
|
// allow debugger during development
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||||
|
'brace-style': [2, 'stroustrup', { 'allowSingleLine': true }]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
.DS_Store
|
||||||
|
.thumbs.db
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
npm-debug.log*
|
||||||
|
cordova/platforms
|
||||||
|
cordova/plugins
|
||||||
|
|
||||||
|
# Junit reports
|
||||||
|
t/TESTS*
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
csc/
|
@ -0,0 +1,2 @@
|
|||||||
|
save-prefix =
|
||||||
|
registry = https://npm-registry.sipwise.com/
|
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"blocks": "never",
|
||||||
|
"brackets": "never",
|
||||||
|
"colons": "never",
|
||||||
|
"colors": "always",
|
||||||
|
"commaSpace": "always",
|
||||||
|
"commentSpace": "always",
|
||||||
|
"cssLiteral": "never",
|
||||||
|
"depthLimit": false,
|
||||||
|
"duplicates": true,
|
||||||
|
"efficient": "always",
|
||||||
|
"extendPref": false,
|
||||||
|
"globalDupe": true,
|
||||||
|
"indentPref": 2,
|
||||||
|
"leadingZero": "never",
|
||||||
|
"maxErrors": false,
|
||||||
|
"maxWarnings": false,
|
||||||
|
"mixed": false,
|
||||||
|
"namingConvention": false,
|
||||||
|
"namingConventionStrict": false,
|
||||||
|
"none": "never",
|
||||||
|
"noImportant": false,
|
||||||
|
"parenSpace": "never",
|
||||||
|
"placeholder": false,
|
||||||
|
"prefixVarsWithDollar": "always",
|
||||||
|
"quotePref": "single",
|
||||||
|
"semicolons": "never",
|
||||||
|
"sortOrder": false,
|
||||||
|
"stackedProperties": "never",
|
||||||
|
"trailingWhitespace": "never",
|
||||||
|
"universal": "never",
|
||||||
|
"valid": true,
|
||||||
|
"zeroUnits": "never",
|
||||||
|
"zIndexNormalize": false
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
var
|
||||||
|
ExtractTextPlugin = require('extract-text-webpack-plugin'),
|
||||||
|
autoprefixer = require('autoprefixer'),
|
||||||
|
purify = require('purify-css'),
|
||||||
|
glob = require('glob'),
|
||||||
|
path = require('path'),
|
||||||
|
fs = require('fs')
|
||||||
|
|
||||||
|
module.exports.postcss = [autoprefixer()]
|
||||||
|
|
||||||
|
module.exports.styleLoaders = function (options) {
|
||||||
|
options = options || {}
|
||||||
|
|
||||||
|
function generateLoaders (loaders) {
|
||||||
|
if (options.postcss) {
|
||||||
|
loaders.splice(1, 0, 'postcss')
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourceLoader = loaders.map(function (loader) {
|
||||||
|
var extraParamChar
|
||||||
|
if (/\?/.test(loader)) {
|
||||||
|
loader = loader.replace(/\?/, '-loader?')
|
||||||
|
extraParamChar = '&'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
loader = loader + '-loader'
|
||||||
|
extraParamChar = '?'
|
||||||
|
}
|
||||||
|
return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
|
||||||
|
}).join('!')
|
||||||
|
|
||||||
|
if (options.extract) {
|
||||||
|
return ExtractTextPlugin.extract({
|
||||||
|
use: sourceLoader,
|
||||||
|
fallback: 'vue-style-loader'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ['vue-style-loader', sourceLoader].join('!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
css: generateLoaders(['css']),
|
||||||
|
less: generateLoaders(['css', 'less']),
|
||||||
|
sass: generateLoaders(['css', 'sass?indentedSyntax']),
|
||||||
|
scss: generateLoaders(['css', 'sass']),
|
||||||
|
styl: generateLoaders(['css', 'stylus']),
|
||||||
|
stylus: generateLoaders(['css', 'stylus'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.styleRules = function (options) {
|
||||||
|
var output = []
|
||||||
|
var loaders = exports.styleLoaders(options)
|
||||||
|
for (var extension in loaders) {
|
||||||
|
var loader = loaders[extension]
|
||||||
|
output.push({
|
||||||
|
test: new RegExp('\\.' + extension + '$'),
|
||||||
|
loader: loader
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSize (size) {
|
||||||
|
return (size / 1024).toFixed(2) + 'kb'
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.purify = function(cb) {
|
||||||
|
var css = glob.sync(path.join(__dirname, '../dist/**/*.css'))
|
||||||
|
var js = glob.sync(path.join(__dirname, '../dist/**/*.js'))
|
||||||
|
|
||||||
|
Promise.all(css.map(function (file) {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
console.log('\n Purifying ' + path.relative(path.join(__dirname, '../dist'), file).bold + '...')
|
||||||
|
purify(js, [file], {minify: true}, function (purified) {
|
||||||
|
var oldSize = fs.statSync(file).size
|
||||||
|
fs.writeFileSync(file, purified)
|
||||||
|
var newSize = fs.statSync(file).size
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
' * Reduced size by ' + ((1 - newSize / oldSize) * 100).toFixed(2) + '%, from ' +
|
||||||
|
getSize(oldSize) + ' to ' + getSize(newSize) + '.'
|
||||||
|
)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
.then(cb)
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
var
|
||||||
|
config = require('../config'),
|
||||||
|
theme = process.argv[2] || config.defaultTheme
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
dev: process.env.NODE_ENV === 'development',
|
||||||
|
prod: process.env.NODE_ENV === 'production',
|
||||||
|
|
||||||
|
platform: {
|
||||||
|
theme: theme,
|
||||||
|
cordovaAssets: './cordova/platforms/' + (theme === 'mat' ? 'android' : 'ios') + '/platform_www'
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
require('eventsource-polyfill')
|
||||||
|
require('webpack-hot-middleware/client?noInfo=true&reload=true')
|
@ -0,0 +1,57 @@
|
|||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
|
require('colors')
|
||||||
|
|
||||||
|
var
|
||||||
|
shell = require('shelljs'),
|
||||||
|
path = require('path'),
|
||||||
|
env = require('./env-utils'),
|
||||||
|
css = require('./css-utils'),
|
||||||
|
config = require('../config'),
|
||||||
|
webpack = require('webpack'),
|
||||||
|
webpackConfig = require('./webpack.prod.conf'),
|
||||||
|
targetPath = path.join(__dirname, '../dist')
|
||||||
|
|
||||||
|
console.log(' WARNING!'.bold)
|
||||||
|
console.log(' Do NOT use VueRouter\'s "history" mode if')
|
||||||
|
console.log(' building for Cordova or Electron.\n')
|
||||||
|
|
||||||
|
require('./script.clean.js')
|
||||||
|
console.log((' Building Quasar App with "' + env.platform.theme + '" theme...\n').bold)
|
||||||
|
|
||||||
|
shell.mkdir('-p', targetPath)
|
||||||
|
shell.cp('-R', 'src/statics', targetPath)
|
||||||
|
|
||||||
|
function finalize () {
|
||||||
|
console.log((
|
||||||
|
'\n Build complete with "' + env.platform.theme.bold + '" theme in ' +
|
||||||
|
'"/dist"'.bold + ' folder.\n').cyan)
|
||||||
|
|
||||||
|
console.log(' Built files are meant to be served over an HTTP server.'.bold)
|
||||||
|
console.log(' Opening index.html over file:// won\'t work.'.bold)
|
||||||
|
}
|
||||||
|
|
||||||
|
webpackConfig.watch = (process.env['CSC_WATCH'])? true : false;
|
||||||
|
|
||||||
|
webpack(webpackConfig, function (err, stats) {
|
||||||
|
if (err) throw err
|
||||||
|
|
||||||
|
process.stdout.write(stats.toString({
|
||||||
|
colors: true,
|
||||||
|
modules: false,
|
||||||
|
children: false,
|
||||||
|
chunks: false,
|
||||||
|
chunkModules: false
|
||||||
|
}) + '\n')
|
||||||
|
|
||||||
|
if (stats.hasErrors()) {
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.build.purifyCSS) {
|
||||||
|
css.purify(finalize)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
finalize()
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,7 @@
|
|||||||
|
var
|
||||||
|
shell = require('shelljs'),
|
||||||
|
path = require('path')
|
||||||
|
|
||||||
|
shell.rm('-rf', path.resolve(__dirname, '../dist/*'))
|
||||||
|
shell.rm('-rf', path.resolve(__dirname, '../dist/.*'))
|
||||||
|
console.log(' Cleaned build artifacts.\n')
|
@ -0,0 +1,86 @@
|
|||||||
|
process.env.NODE_ENV = 'development'
|
||||||
|
|
||||||
|
require('colors')
|
||||||
|
|
||||||
|
var
|
||||||
|
path = require('path'),
|
||||||
|
express = require('express'),
|
||||||
|
webpack = require('webpack'),
|
||||||
|
env = require('./env-utils'),
|
||||||
|
config = require('../config'),
|
||||||
|
opn = require('opn'),
|
||||||
|
proxyMiddleware = require('http-proxy-middleware'),
|
||||||
|
webpackConfig = require('./webpack.dev.conf'),
|
||||||
|
app = express(),
|
||||||
|
port = process.env.PORT || config.dev.port,
|
||||||
|
uri = 'http://localhost:' + port
|
||||||
|
|
||||||
|
console.log(' Starting dev server with "' + (process.argv[2] || env.platform.theme).bold + '" theme...')
|
||||||
|
console.log(' Will listen at ' + uri.bold)
|
||||||
|
if (config.dev.openBrowser) {
|
||||||
|
console.log(' Browser will open when build is ready.\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
var compiler = webpack(webpackConfig)
|
||||||
|
|
||||||
|
// Define HTTP proxies to your custom API backend
|
||||||
|
// https://github.com/chimurai/http-proxy-middleware
|
||||||
|
var proxyTable = config.dev.proxyTable
|
||||||
|
|
||||||
|
var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||||
|
publicPath: webpackConfig.output.publicPath,
|
||||||
|
quiet: true
|
||||||
|
})
|
||||||
|
|
||||||
|
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
|
||||||
|
log: function () {}
|
||||||
|
})
|
||||||
|
|
||||||
|
// force page reload when html-webpack-plugin template changes
|
||||||
|
compiler.plugin('compilation', function (compilation) {
|
||||||
|
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
|
||||||
|
hotMiddleware.publish({ action: 'reload' })
|
||||||
|
cb()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// proxy requests like API. See /config/index.js -> dev.proxyTable
|
||||||
|
// https://github.com/chimurai/http-proxy-middleware
|
||||||
|
Object.keys(proxyTable).forEach(function (context) {
|
||||||
|
var options = proxyTable[context]
|
||||||
|
if (typeof options === 'string') {
|
||||||
|
options = { target: options }
|
||||||
|
}
|
||||||
|
app.use(proxyMiddleware(context, options))
|
||||||
|
})
|
||||||
|
|
||||||
|
// handle fallback for HTML5 history API
|
||||||
|
app.use(require('connect-history-api-fallback')())
|
||||||
|
|
||||||
|
// serve webpack bundle output
|
||||||
|
app.use(devMiddleware)
|
||||||
|
|
||||||
|
// enable hot-reload and state-preserving
|
||||||
|
// compilation error display
|
||||||
|
app.use(hotMiddleware)
|
||||||
|
|
||||||
|
// serve pure static assets
|
||||||
|
var staticsPath = path.posix.join(webpackConfig.output.publicPath, 'statics/')
|
||||||
|
app.use(staticsPath, express.static('./src/statics'))
|
||||||
|
|
||||||
|
// try to serve Cordova statics for Play App
|
||||||
|
app.use(express.static(env.platform.cordovaAssets))
|
||||||
|
|
||||||
|
module.exports = app.listen(port, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// open browser if set so in /config/index.js
|
||||||
|
if (config.dev.openBrowser) {
|
||||||
|
devMiddleware.waitUntilValid(function () {
|
||||||
|
opn(uri)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,108 @@
|
|||||||
|
var
|
||||||
|
path = require('path'),
|
||||||
|
webpack = require('webpack'),
|
||||||
|
config = require('../config'),
|
||||||
|
cssUtils = require('./css-utils'),
|
||||||
|
env = require('./env-utils'),
|
||||||
|
merge = require('webpack-merge'),
|
||||||
|
projectRoot = path.resolve(__dirname, '../'),
|
||||||
|
ProgressBarPlugin = require('progress-bar-webpack-plugin'),
|
||||||
|
useCssSourceMap =
|
||||||
|
(env.dev && config.dev.cssSourceMap) ||
|
||||||
|
(env.prod && config.build.productionSourceMap)
|
||||||
|
|
||||||
|
function resolve (dir) {
|
||||||
|
return path.join(__dirname, '..', dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
app: './src/main.js'
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, '../dist'),
|
||||||
|
publicPath: config[env.prod ? 'build' : 'dev'].publicPath,
|
||||||
|
filename: 'js/[name].js',
|
||||||
|
chunkFilename: 'js/[id].[chunkhash].js'
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.vue', '.json'],
|
||||||
|
modules: [
|
||||||
|
resolve('src'),
|
||||||
|
resolve('node_modules')
|
||||||
|
],
|
||||||
|
alias: config.aliases
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
// { // eslint
|
||||||
|
// enforce: 'pre',
|
||||||
|
// test: /\.(vue|js)$/,
|
||||||
|
// loader: 'eslint-loader',
|
||||||
|
// include: projectRoot,
|
||||||
|
// exclude: /node_modules/,
|
||||||
|
// options: {
|
||||||
|
// formatter: require('eslint-friendly-formatter')
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
include: projectRoot,
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loader: 'vue-loader',
|
||||||
|
options: {
|
||||||
|
postcss: cssUtils.postcss,
|
||||||
|
loaders: merge({js: 'babel-loader'}, cssUtils.styleLoaders({
|
||||||
|
sourceMap: useCssSourceMap,
|
||||||
|
extract: env.prod
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.json$/,
|
||||||
|
loader: 'json-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: 'img/[name].[hash:7].[ext]'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: 'fonts/[name].[hash:7].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': config[env.prod ? 'build' : 'dev'].env,
|
||||||
|
'DEV': env.dev,
|
||||||
|
'PROD': env.prod,
|
||||||
|
'__THEME': '"' + env.platform.theme + '"'
|
||||||
|
}),
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
minimize: env.prod,
|
||||||
|
options: {
|
||||||
|
context: path.resolve(__dirname, '../src'),
|
||||||
|
postcss: cssUtils.postcss
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new ProgressBarPlugin({
|
||||||
|
format: config.progressFormat
|
||||||
|
})
|
||||||
|
],
|
||||||
|
performance: {
|
||||||
|
hints: false
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
var
|
||||||
|
config = require('../config'),
|
||||||
|
webpack = require('webpack'),
|
||||||
|
merge = require('webpack-merge'),
|
||||||
|
cssUtils = require('./css-utils'),
|
||||||
|
baseWebpackConfig = require('./webpack.base.conf'),
|
||||||
|
HtmlWebpackPlugin = require('html-webpack-plugin'),
|
||||||
|
FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||||
|
|
||||||
|
// add hot-reload related code to entry chunks
|
||||||
|
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
|
||||||
|
baseWebpackConfig.entry[name] = ['./build/hot-reload.js', baseWebpackConfig.entry[name]]
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = merge(baseWebpackConfig, {
|
||||||
|
// eval-source-map is faster for development
|
||||||
|
devtool: '#cheap-module-eval-source-map',
|
||||||
|
devServer: {
|
||||||
|
historyApiFallback: true,
|
||||||
|
noInfo: true
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: cssUtils.styleRules({
|
||||||
|
sourceMap: config.dev.cssSourceMap,
|
||||||
|
postcss: true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new webpack.NoEmitOnErrorsPlugin(),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: 'index.html',
|
||||||
|
template: 'src/index.html',
|
||||||
|
inject: true
|
||||||
|
}),
|
||||||
|
new FriendlyErrorsPlugin({
|
||||||
|
clearConsole: config.dev.clearConsoleOnRebuild
|
||||||
|
})
|
||||||
|
],
|
||||||
|
performance: {
|
||||||
|
hints: false
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,78 @@
|
|||||||
|
var
|
||||||
|
path = require('path'),
|
||||||
|
config = require('../config'),
|
||||||
|
cssUtils = require('./css-utils'),
|
||||||
|
webpack = require('webpack'),
|
||||||
|
merge = require('webpack-merge'),
|
||||||
|
baseWebpackConfig = require('./webpack.base.conf'),
|
||||||
|
ExtractTextPlugin = require('extract-text-webpack-plugin'),
|
||||||
|
HtmlWebpackPlugin = require('html-webpack-plugin'),
|
||||||
|
OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||||
|
|
||||||
|
module.exports = merge(baseWebpackConfig, {
|
||||||
|
module: {
|
||||||
|
rules: cssUtils.styleRules({
|
||||||
|
sourceMap: config.build.productionSourceMap,
|
||||||
|
extract: true,
|
||||||
|
postcss: true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
devtool: config.build.productionSourceMap ? '#source-map' : false,
|
||||||
|
plugins: [
|
||||||
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
|
sourceMap: config.build.productionSourceMap,
|
||||||
|
minimize: true,
|
||||||
|
compress: {
|
||||||
|
warnings: false
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
// Compress extracted CSS. We are using this plugin so that possible
|
||||||
|
// duplicated CSS from different components can be deduped.
|
||||||
|
new OptimizeCSSPlugin({
|
||||||
|
cssProcessorOptions: {
|
||||||
|
safe: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
// extract css into its own file
|
||||||
|
new ExtractTextPlugin({
|
||||||
|
filename: '[name].[contenthash].css'
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: path.resolve(__dirname, '../dist/index.html'),
|
||||||
|
template: 'src/index.html',
|
||||||
|
inject: true,
|
||||||
|
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'
|
||||||
|
}),
|
||||||
|
// split vendor js into its own file
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'vendor',
|
||||||
|
minChunks: function (module, count) {
|
||||||
|
// any required modules inside node_modules are extracted to vendor
|
||||||
|
return (
|
||||||
|
module.resource &&
|
||||||
|
/\.js$/.test(module.resource) &&
|
||||||
|
(
|
||||||
|
module.resource.indexOf('quasar') > -1 ||
|
||||||
|
module.resource.indexOf(
|
||||||
|
path.join(__dirname, '../node_modules')
|
||||||
|
) === 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
// extract webpack runtime and module manifest to its own file in order to
|
||||||
|
// prevent vendor hash from being updated whenever app bundle is updated
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'manifest',
|
||||||
|
chunks: ['vendor']
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
@ -0,0 +1,6 @@
|
|||||||
|
var merge = require('webpack-merge')
|
||||||
|
var prodEnv = require('./prod.env')
|
||||||
|
|
||||||
|
module.exports = merge(prodEnv, {
|
||||||
|
NODE_ENV: '"development"'
|
||||||
|
})
|
@ -0,0 +1,64 @@
|
|||||||
|
var path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Webpack aliases
|
||||||
|
aliases: {
|
||||||
|
quasar: path.resolve(__dirname, '../node_modules/quasar-framework/'),
|
||||||
|
src: path.resolve(__dirname, '../src'),
|
||||||
|
assets: path.resolve(__dirname, '../src/assets'),
|
||||||
|
'@': path.resolve(__dirname, '../src/components'),
|
||||||
|
variables: path.resolve(__dirname, '../src/themes/quasar.variables.styl')
|
||||||
|
},
|
||||||
|
|
||||||
|
// Progress Bar Webpack plugin format
|
||||||
|
// https://github.com/clessg/progress-bar-webpack-plugin#options
|
||||||
|
progressFormat: ' [:bar] ' + ':percent'.bold + ' (:msg)',
|
||||||
|
|
||||||
|
// Default theme to build with ('ios' or 'mat')
|
||||||
|
defaultTheme: 'mat',
|
||||||
|
|
||||||
|
build: {
|
||||||
|
env: require('./prod.env'),
|
||||||
|
publicPath: '',
|
||||||
|
productionSourceMap: (process.env['CSC_SOURCE_MAP'])? true : false,
|
||||||
|
|
||||||
|
// Remove unused CSS
|
||||||
|
// Disable it if it has side-effects for your specific app
|
||||||
|
purifyCSS: true
|
||||||
|
},
|
||||||
|
dev: {
|
||||||
|
env: require('./dev.env'),
|
||||||
|
cssSourceMap: true,
|
||||||
|
// auto open browser or not
|
||||||
|
openBrowser: true,
|
||||||
|
publicPath: '/',
|
||||||
|
port: 8080,
|
||||||
|
|
||||||
|
// If for example you are using Quasar Play
|
||||||
|
// to generate a QR code then on each dev (re)compilation
|
||||||
|
// you need to avoid clearing out the console, so set this
|
||||||
|
// to "false", otherwise you can set it to "true" to always
|
||||||
|
// have only the messages regarding your last (re)compilation.
|
||||||
|
clearConsoleOnRebuild: false,
|
||||||
|
|
||||||
|
// Proxy your API if using any.
|
||||||
|
// Also see /build/script.dev.js and search for "proxy api requests"
|
||||||
|
// https://github.com/chimurai/http-proxy-middleware
|
||||||
|
proxyTable: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* proxyTable example:
|
||||||
|
*
|
||||||
|
proxyTable: {
|
||||||
|
// proxy all requests starting with /api
|
||||||
|
'/api': {
|
||||||
|
target: 'https://some.address.com/api',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
'^/api': ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
NODE_ENV: '"production"'
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
usr/share/ngcp-csc
|
@ -0,0 +1 @@
|
|||||||
|
csc usr/share/ngcp-csc
|
@ -1,6 +1,12 @@
|
|||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
# Uncomment this to turn on verbose mode.
|
# Uncomment this to turn on verbose mode.
|
||||||
# export DH_VERBOSE=1
|
# export DH_VERBOSE=1
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@
|
dh "$@"
|
||||||
|
|
||||||
|
override_dh_auto_install:
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
mv dist csc
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CSC_SYS_PATH="/usr/share/ngcp-csc/csc"
|
||||||
|
CSC_TMP_PATH="/usr/share/ngcp-csc/csc.orig"
|
||||||
|
CSC_PATH="$PWD/dist"
|
||||||
|
|
||||||
|
if [ ! -e "$CSC_SYS_PATH" ]; then
|
||||||
|
mkdir -p "$CSC_SYS_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CSC_LINK_TARGET=""
|
||||||
|
if [ -L "$CSC_SYS_PATH" ]; then
|
||||||
|
CSC_LINK_TARGET=$(readlink "$CSC_SYS_PATH")
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARGS="$*";
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
reset)
|
||||||
|
if [ -L "$CSC_SYS_PATH" ]; then
|
||||||
|
rm "$CSC_SYS_PATH"
|
||||||
|
echo "Removed link to development version $CSC_SYS_PATH -> $CSC_LINK_TARGET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$CSC_TMP_PATH" ]; then
|
||||||
|
mv "$CSC_TMP_PATH" "$CSC_SYS_PATH"
|
||||||
|
echo "Restored release version $CSC_TMP_PATH -> $CSC_SYS_PATH"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
i=0
|
||||||
|
while [ "$i" -lt "$#" ]; do
|
||||||
|
next=$(("$i + 1"))
|
||||||
|
case "${ARGS[$i]}" in
|
||||||
|
-p)
|
||||||
|
if [ "${ARGS[$next]}" != "" ]; then
|
||||||
|
CSC_PATH="${ARGS[$next]}"
|
||||||
|
else
|
||||||
|
echo "Path to development version must not be empty" >&2
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "Invalid option ${ARGS[$i]}" >&2
|
||||||
|
exit 1;
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
i=$(("$i + 1"))
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -d "$CSC_PATH" ]; then
|
||||||
|
echo "Path to development version is not a directory '$CSC_PATH'" >&2
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -L "$CSC_SYS_PATH" -a ! -d "$CSC_TMP_PATH" ]; then
|
||||||
|
mv "$CSC_SYS_PATH" "$CSC_TMP_PATH"
|
||||||
|
ln -s -f "$CSC_PATH" "$CSC_SYS_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Link to development version $CSC_SYS_PATH -> $(readlink ${CSC_SYS_PATH})"
|
||||||
|
echo "Release temporary moved to $CSC_TMP_PATH"
|
||||||
|
;;
|
||||||
|
esac
|
@ -0,0 +1,56 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var webpackCsc = require('./build/webpack.base.conf');
|
||||||
|
|
||||||
|
module.exports = function(config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
files: [
|
||||||
|
'./t/**/*.js'
|
||||||
|
],
|
||||||
|
frameworks: ['mocha'],
|
||||||
|
plugins : [
|
||||||
|
'karma-mocha',
|
||||||
|
'karma-webpack',
|
||||||
|
'karma-chrome-launcher',
|
||||||
|
'karma-firefox-launcher',
|
||||||
|
'karma-junit-reporter',
|
||||||
|
],
|
||||||
|
browsers: ['ChromeWebRTC', 'FirefoxWebRTC'],
|
||||||
|
customLaunchers: {
|
||||||
|
ChromeWebRTC: {
|
||||||
|
base: 'Chrome',
|
||||||
|
flags: [
|
||||||
|
'--disable-web-security',
|
||||||
|
'--use-fake-device-for-media-stream',
|
||||||
|
'--use-fake-ui-for-media-stream',
|
||||||
|
'--ignore-certificate-errors',
|
||||||
|
'--no-sandbox',
|
||||||
|
'--disable-gpu'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
FirefoxWebRTC: {
|
||||||
|
base: 'Firefox',
|
||||||
|
prefs: {
|
||||||
|
'media.navigator.permission.disabled': true,
|
||||||
|
'media.navigator.streams.fake': true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reporters: [
|
||||||
|
'progress',
|
||||||
|
'junit'
|
||||||
|
],
|
||||||
|
junitReporter: {
|
||||||
|
outputDir: './t/'
|
||||||
|
},
|
||||||
|
preprocessors: {
|
||||||
|
'./src/**/*.js': ['webpack'],
|
||||||
|
'./t/**/*.js': ['webpack']
|
||||||
|
},
|
||||||
|
webpack: {
|
||||||
|
module: webpackCsc.module,
|
||||||
|
plugins: webpackCsc.plugins
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"name": "ngcp-csc-ui",
|
||||||
|
"productName": "Customer Self-Care Web UI",
|
||||||
|
"version": "0.0.6",
|
||||||
|
"description": "Customer Self-Care Web UI",
|
||||||
|
"author": "Hans-Peter Herzog <hherzog@sipwise.com>",
|
||||||
|
"scripts": {
|
||||||
|
"clean": "node build/script.clean.js",
|
||||||
|
"dev": "node build/script.dev.js",
|
||||||
|
"build": "node build/script.build.js mat",
|
||||||
|
"dev-build": "CSC_SOURCE_MAP=1 CSC_WATCH=1 node build/script.build.js mat",
|
||||||
|
"lint": "eslint --ext .js,.vue src",
|
||||||
|
"test": "karma start ./karma.js --single-run"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-html": "0.0.7",
|
||||||
|
"ansi-regex": "^3.0.0",
|
||||||
|
"babel-runtime": "^6.25.0",
|
||||||
|
"core-js": "^2.5.1",
|
||||||
|
"html-entities": "^1.2.1",
|
||||||
|
"lodash": "^4.17.4",
|
||||||
|
"quasar-extras": "0.x",
|
||||||
|
"quasar-framework": "^0.14.4",
|
||||||
|
"strip-ansi": "^4.0.0",
|
||||||
|
"vue": "~2.3.4",
|
||||||
|
"vue-i18n": "^7.3.0",
|
||||||
|
"vue-resource": "^1.3.4",
|
||||||
|
"vue-router": "^2.7.0",
|
||||||
|
"vuex": "^2.4.1",
|
||||||
|
"vuex-router-sync": "^4.3.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"autoprefixer": "^6.4.0",
|
||||||
|
"babel-core": "^6.0.0",
|
||||||
|
"babel-eslint": "^7.0.0",
|
||||||
|
"babel-loader": "^7.1.2",
|
||||||
|
"babel-plugin-transform-runtime": "^6.0.0",
|
||||||
|
"babel-preset-es2015": "^6.0.0",
|
||||||
|
"babel-preset-stage-2": "^6.0.0",
|
||||||
|
"chai": "^4.1.2",
|
||||||
|
"colors": "^1.1.2",
|
||||||
|
"connect-history-api-fallback": "^1.1.0",
|
||||||
|
"css-loader": "^0.28.7",
|
||||||
|
"es6-promise": "^4.1.1",
|
||||||
|
"eslint": "^4.8.0",
|
||||||
|
"eslint-config-standard": "^10.2.1",
|
||||||
|
"eslint-friendly-formatter": "^3.0.0",
|
||||||
|
"eslint-loader": "^1.9.0",
|
||||||
|
"eslint-plugin-html": "^3.2.2",
|
||||||
|
"eslint-plugin-import": "^2.7.0",
|
||||||
|
"eslint-plugin-node": "^5.2.0",
|
||||||
|
"eslint-plugin-promise": "^3.5.0",
|
||||||
|
"eslint-plugin-standard": "^3.0.1",
|
||||||
|
"eventsource-polyfill": "^0.9.6",
|
||||||
|
"express": "^4.16.1",
|
||||||
|
"extract-text-webpack-plugin": "^3.0.0",
|
||||||
|
"file-loader": "^0.11.1",
|
||||||
|
"friendly-errors-webpack-plugin": "^1.1.3",
|
||||||
|
"glob": "^7.1.2",
|
||||||
|
"html-webpack-plugin": "^2.30.1",
|
||||||
|
"http-proxy-middleware": "^0.17.0",
|
||||||
|
"json-loader": "^0.5.7",
|
||||||
|
"karma": "^1.7.1",
|
||||||
|
"karma-chrome-launcher": "^2.2.0",
|
||||||
|
"karma-firefox-launcher": "^1.0.1",
|
||||||
|
"karma-junit-reporter": "^1.2.0",
|
||||||
|
"karma-mocha": "^1.3.0",
|
||||||
|
"karma-webpack": "^2.0.4",
|
||||||
|
"mocha": "^4.0.0",
|
||||||
|
"opn": "^5.0.0",
|
||||||
|
"optimize-css-assets-webpack-plugin": "^3.2.0",
|
||||||
|
"postcss-loader": "^1.0.0",
|
||||||
|
"progress-bar-webpack-plugin": "^1.10.0",
|
||||||
|
"purify-css": "^1.2.6",
|
||||||
|
"shelljs": "^0.7.0",
|
||||||
|
"stylus": "^0.54.5",
|
||||||
|
"stylus-loader": "^3.0.1",
|
||||||
|
"url-loader": "^0.5.7",
|
||||||
|
"vue-loader": "^13.0.5",
|
||||||
|
"vue-style-loader": "^3.0.3",
|
||||||
|
"vue-template-compiler": "~2.3.4",
|
||||||
|
"webpack": "^3.6.0",
|
||||||
|
"webpack-dev-middleware": "^1.12.0",
|
||||||
|
"webpack-hot-middleware": "^2.19.1",
|
||||||
|
"webpack-merge": "^4.1.0"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div id="q-app">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { QTransition } from 'quasar'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
QTransition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.q-field-icon,
|
||||||
|
.q-item-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export function getGroups(options) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
Promise.props({
|
||||||
|
numbers: Vue.http.get('/api/numbers'),
|
||||||
|
subscribers: Vue.http.get('/api/subscribers', {
|
||||||
|
params: {
|
||||||
|
is_pbx_group: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).then((result)=>{
|
||||||
|
|
||||||
|
}).then(()=>{
|
||||||
|
resolve();
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createGroup(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveGroup(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSeats() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSeat() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveSeat() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDevices() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createDevice() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveDevice() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export function login(username, password) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
var jwt = null;
|
||||||
|
var subscriberId = null;
|
||||||
|
Vue.http.post('/login_jwt', {
|
||||||
|
username: username,
|
||||||
|
password: password
|
||||||
|
}).then((result)=>{
|
||||||
|
jwt = result.body.jwt;
|
||||||
|
subscriberId = result.body.subscriber_id + "";
|
||||||
|
resolve({
|
||||||
|
jwt: jwt,
|
||||||
|
subscriberId: subscriberId,
|
||||||
|
});
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserData(id) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
return Promise.all([
|
||||||
|
getSubscriberById(id),
|
||||||
|
getCapabilities(),
|
||||||
|
getNumbers()
|
||||||
|
]).then((results)=>{
|
||||||
|
resolve({
|
||||||
|
subscriber: results[0],
|
||||||
|
capabilities: results[1],
|
||||||
|
numbers: results[2]
|
||||||
|
});
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSubscriberById(id) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
Vue.http.get('/api/subscribers/' + id).then((result)=>{
|
||||||
|
var body = JSON.parse(result.body);
|
||||||
|
resolve(body);
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCapabilities() {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
Vue.http.get('/api/capabilities').then((result)=>{
|
||||||
|
var capabilities = {};
|
||||||
|
var body = JSON.parse(result.body);
|
||||||
|
if(_.isArray(body["_embedded"]["ngcp:capabilities"])) {
|
||||||
|
body['_embedded']['ngcp:capabilities'].forEach((capability)=>{
|
||||||
|
capabilities[capability.name] = capability.enabled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
resolve(capabilities);
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNumbers() {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
Vue.http.get('/api/numbers').then((result)=>{
|
||||||
|
// Todo: Check format of numbers
|
||||||
|
resolve();
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,10 @@
|
|||||||
|
<template>
|
||||||
|
<div>404 NotFound</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<q-layout>
|
||||||
|
<div id="csc-login" class="row">
|
||||||
|
<div class="column col-lg-4 col-xl-4 col-md-3 gt-sm"></div>
|
||||||
|
<div class="column col-12 col-md-6 col-lg-4 col-xl-4">
|
||||||
|
<q-card>
|
||||||
|
<q-card-title>
|
||||||
|
<q-icon name="" />{{ $t('login_title') }}
|
||||||
|
<span slot="subtitle"></span>
|
||||||
|
</q-card-title>
|
||||||
|
<q-card-main>
|
||||||
|
<q-field icon="fa-user-circle" :helper="$t('username_helper')" :count="128">
|
||||||
|
<q-input type="text" max-length="128" :float-label="$t('username')" clearable v-model="username"/>
|
||||||
|
</q-field>
|
||||||
|
<q-field icon="fa-lock" :helper="$t('password_helper')" :count="32">
|
||||||
|
<q-input type="password" max-length="32" :float-label="$t('password')" clearable v-model="password"/>
|
||||||
|
</q-field>
|
||||||
|
</q-card-main>
|
||||||
|
<q-card-actions class="pull-right">
|
||||||
|
<q-btn flat icon-right="fa-arrow-right" color="primary" @click="login()">{{ $t('login_button') }}</q-btn>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
<div class="column col-lg-4 col-xl-4 col-md-3 gt-sm"></div>
|
||||||
|
</div>
|
||||||
|
</q-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { startLoading, stopLoading, showGlobalError } from '../helpers/ui'
|
||||||
|
import {
|
||||||
|
QLayout,
|
||||||
|
QCard,
|
||||||
|
QCardTitle,
|
||||||
|
QCardSeparator,
|
||||||
|
QCardMain,
|
||||||
|
QField,
|
||||||
|
QInput,
|
||||||
|
QCardActions,
|
||||||
|
QBtn,
|
||||||
|
QIcon,
|
||||||
|
Loading,
|
||||||
|
Alert } from 'quasar'
|
||||||
|
export default {
|
||||||
|
name: 'login',
|
||||||
|
components: {
|
||||||
|
QLayout,
|
||||||
|
QCard,
|
||||||
|
QCardTitle,
|
||||||
|
QCardSeparator,
|
||||||
|
QCardMain,
|
||||||
|
QField,
|
||||||
|
QInput,
|
||||||
|
QCardActions,
|
||||||
|
QBtn,
|
||||||
|
QIcon
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
user: '',
|
||||||
|
pass: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
login() {
|
||||||
|
startLoading();
|
||||||
|
this.$store.dispatch('user/login').then(()=>{
|
||||||
|
stopLoading();
|
||||||
|
this.$router.push({path : '/'});
|
||||||
|
}).catch((err)=>{
|
||||||
|
stopLoading();
|
||||||
|
showGlobalError(this.$i18n.t('login_error'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
username: {
|
||||||
|
get () {
|
||||||
|
return this.$store.state.user.username;
|
||||||
|
},
|
||||||
|
set (value) {
|
||||||
|
this.$store.commit('user/updateUsername', value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
get () {
|
||||||
|
return this.$store.state.user.password;
|
||||||
|
},
|
||||||
|
set (value) {
|
||||||
|
this.$store.commit('user/updatePassword', value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#csc-login {
|
||||||
|
padding-top: 15%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#csc-login .q-card-container {
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,230 @@
|
|||||||
|
<template>
|
||||||
|
<q-layout ref="layout" view="lHr LpR lFr" :right-breakpoint="1100">
|
||||||
|
<q-toolbar slot="header">
|
||||||
|
<q-btn flat @click="$refs.layout.toggleLeft()">
|
||||||
|
<q-icon name="menu"/>
|
||||||
|
</q-btn>
|
||||||
|
<q-toolbar-title>
|
||||||
|
{{ $t('title') }}
|
||||||
|
<span slot="subtitle"></span>
|
||||||
|
</q-toolbar-title>
|
||||||
|
<q-btn flat @click="" icon-right="fa-user-circle">
|
||||||
|
<span id="user-login-as">{{ $t('loggedInAs') }}</span><span id="user-name">{{ getUsername }}</span>
|
||||||
|
<q-popover ref="popover">
|
||||||
|
<q-list item-separator link>
|
||||||
|
<q-item @click="logout()">
|
||||||
|
<q-item-main label="Logout" />
|
||||||
|
<q-item-side icon="exit to app"/>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-popover>
|
||||||
|
</q-btn>
|
||||||
|
</q-toolbar>
|
||||||
|
<q-list id="main-menu" slot="left" no-border link inset-delimiter>
|
||||||
|
<q-side-link item to="/user/conversations">
|
||||||
|
<q-item-side icon="question answer"></q-item-side>
|
||||||
|
<q-item-main :label="$t('mainNavigation.conversations.title')"
|
||||||
|
:sublabel="$t('mainNavigation.conversations.subTitle')"/>
|
||||||
|
</q-side-link>
|
||||||
|
<q-collapsible :opened="isCallForward" intend icon="fa-angle-double-right"
|
||||||
|
:label="$t('mainNavigation.callForward.title')"
|
||||||
|
:sublabel="$t('mainNavigation.callForward.subTitle')">
|
||||||
|
<q-side-link item to="/user/call-forward/always">
|
||||||
|
<q-item-side icon="check circle"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.callForward.always')"/>
|
||||||
|
</q-side-link>
|
||||||
|
<q-side-link item to="/user/call-forward/company-hours">
|
||||||
|
<q-item-side icon="schedule"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.callForward.companyHours')"/>
|
||||||
|
</q-side-link>
|
||||||
|
<q-side-link item to="/user/call-forward/after-hours">
|
||||||
|
<q-item-side icon="watch later"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.callForward.afterHours')"/>
|
||||||
|
</q-side-link>
|
||||||
|
</q-collapsible>
|
||||||
|
<q-collapsible :opened="isCallBlocking" intend icon="fa-ban"
|
||||||
|
:label="$t('mainNavigation.callBlocking.title')"
|
||||||
|
:sublabel="$t('mainNavigation.callBlocking.subTitle')">
|
||||||
|
<q-side-link item to="/user/call-blocking/incoming">
|
||||||
|
<q-item-side icon="fa-arrow-circle-o-left"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.callBlocking.incoming')"/>
|
||||||
|
</q-side-link>
|
||||||
|
<q-side-link item to="/user/call-blocking/outgoing">
|
||||||
|
<q-item-side icon="fa-arrow-circle-o-right"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.callBlocking.outgoing')"/>
|
||||||
|
</q-side-link>
|
||||||
|
<q-side-link item to="/user/call-blocking/privacy">
|
||||||
|
<q-item-side icon="fa-user-secret"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.callBlocking.privacy')"/>
|
||||||
|
</q-side-link>
|
||||||
|
</q-collapsible>
|
||||||
|
<q-side-link item to="/user/reminder">
|
||||||
|
<q-item-side icon="fa-bell"/>
|
||||||
|
<q-item-main
|
||||||
|
label="Reminder"
|
||||||
|
sublabel="Set your personal alarm"/>
|
||||||
|
</q-side-link>
|
||||||
|
<q-collapsible v-if="isPbxAdmin" :opened="isPbxConfiguration" intend icon="fa-gear"
|
||||||
|
:label="$t('mainNavigation.pbxConfiguration.title')"
|
||||||
|
:sublabel="$t('mainNavigation.pbxConfiguration.subTitle')">
|
||||||
|
<q-side-link item to="/user/pbx-configuration/groups">
|
||||||
|
<q-item-side icon="fa-group"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.pbxConfiguration.groups')"/>
|
||||||
|
</q-side-link>
|
||||||
|
<q-side-link item to="/user/pbx-configuration/seats">
|
||||||
|
<q-item-side icon="fa-home"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.pbxConfiguration.seats')"/>
|
||||||
|
</q-side-link>
|
||||||
|
<q-side-link item to="/user/pbx-configuration/devices">
|
||||||
|
<q-item-side icon="fa-fax"/>
|
||||||
|
<q-item-main :label="$t('mainNavigation.pbxConfiguration.devices')"/>
|
||||||
|
</q-side-link>
|
||||||
|
</q-collapsible>
|
||||||
|
</q-list>
|
||||||
|
<q-fixed-position corner="top-right" :offset="[20, 20]">
|
||||||
|
<q-fab color="primary" icon="question answer" active-icon="clear" direction="left" flat>
|
||||||
|
<q-fab-action color="primary" @click="" icon="fa-fax" flat>
|
||||||
|
<q-tooltip anchor="bottom middle" self="top middle" :offset="[0, 15]">{{ $t('sendFax') }}</q-tooltip>
|
||||||
|
</q-fab-action>
|
||||||
|
<q-fab-action color="primary" @click="" icon="fa-send" flat>
|
||||||
|
<q-tooltip anchor="bottom middle" self="top middle" :offset="[0, 15]">{{ $t('sendSms') }}</q-tooltip>
|
||||||
|
</q-fab-action>
|
||||||
|
<q-fab-action v-bind:color="(rtcEngineConnected)?'primary':'light'" @click="startCall" icon="fa-phone" flat>
|
||||||
|
<q-tooltip anchor="bottom middle" self="top middle" :offset="[0, 15]">{{ $t('startCall') }}</q-tooltip>
|
||||||
|
</q-fab-action>
|
||||||
|
</q-fab>
|
||||||
|
</q-fixed-position>
|
||||||
|
<router-view />
|
||||||
|
</q-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { startLoading, stopLoading, showGlobalError } from '../../helpers/ui'
|
||||||
|
import { mapState, mapGetters } from 'vuex'
|
||||||
|
import {
|
||||||
|
QLayout,
|
||||||
|
QToolbar,
|
||||||
|
QToolbarTitle,
|
||||||
|
QBtn,
|
||||||
|
QIcon,
|
||||||
|
QList,
|
||||||
|
QListHeader,
|
||||||
|
QItem,
|
||||||
|
QItemSide,
|
||||||
|
QItemMain,
|
||||||
|
QPopover,
|
||||||
|
QFab,
|
||||||
|
QFabAction,
|
||||||
|
QFixedPosition,
|
||||||
|
QTooltip,
|
||||||
|
QSideLink,
|
||||||
|
QTransition,
|
||||||
|
QCollapsible
|
||||||
|
} from 'quasar'
|
||||||
|
export default {
|
||||||
|
name: 'default',
|
||||||
|
mounted: function() {
|
||||||
|
this.$refs.layout.showLeft();
|
||||||
|
// this.$store.dispatch('connectRtcEngine');
|
||||||
|
},
|
||||||
|
created: function() {
|
||||||
|
this.$store.dispatch('user/initUser');
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
QLayout,
|
||||||
|
QToolbar,
|
||||||
|
QToolbarTitle,
|
||||||
|
QBtn,
|
||||||
|
QIcon,
|
||||||
|
QList,
|
||||||
|
QListHeader,
|
||||||
|
QItem,
|
||||||
|
QItemSide,
|
||||||
|
QItemMain,
|
||||||
|
QPopover,
|
||||||
|
QFab,
|
||||||
|
QFabAction,
|
||||||
|
QFixedPosition,
|
||||||
|
QTooltip,
|
||||||
|
QSideLink,
|
||||||
|
QTransition,
|
||||||
|
QCollapsible
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('user', ['getUsername', 'isPbxAdmin']),
|
||||||
|
...mapState({
|
||||||
|
rtcEngineConnected: state => state.rtcEngineConnected,
|
||||||
|
isCallForward: state => _.startsWith(state.route.path, '/user/call-forward'),
|
||||||
|
isCallBlocking: state => _.startsWith(state.route.path, '/user/call-blocking'),
|
||||||
|
isPbxConfiguration: state => _.startsWith(state.route.path, '/user/pbx-configuration')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
logout() {
|
||||||
|
startLoading();
|
||||||
|
this.$store.dispatch('user/logout').then(()=>{
|
||||||
|
stopLoading();
|
||||||
|
this.$router.push({path: '/login'});
|
||||||
|
})
|
||||||
|
},
|
||||||
|
startCall() {
|
||||||
|
if(!this.$store.state.rtcEngineConnected) {
|
||||||
|
showGlobalError(this.$t('rtcEngineDisconnected'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
navigate(path) {
|
||||||
|
this.$router.push({path: path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#main-menu {
|
||||||
|
padding-top:60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu .q-item-side {
|
||||||
|
min-width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu .q-item {
|
||||||
|
padding: 12px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu .router-link-active,
|
||||||
|
#main-menu .q-item:hover {
|
||||||
|
background-color: #475360;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu .q-item .q-item-sublabel {
|
||||||
|
color: #5b7086;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu .q-item .q-item-main,
|
||||||
|
#main-menu .q-item .q-item-side {
|
||||||
|
color: #ADB3B8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu .q-collapsible-sub-item {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-menu .q-collapsible-sub-item .q-item {
|
||||||
|
padding-left: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user-login-as {
|
||||||
|
display: inline-block;
|
||||||
|
text-transform: none;
|
||||||
|
color: #c5eab4;
|
||||||
|
}
|
||||||
|
#user-login-as:after {
|
||||||
|
content: " ";
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
#user-name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>CallBlocking Incoming</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>CallBlocking Outgoing</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>CallBlocking Privacy</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>CallForward AfterHours</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>CallForward Always</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>CallForward CompanyHours</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>Conversations</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>PBX Devices</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>PBX Groups</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>PBX Seats</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div>Reminder</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
import { Loading, Alert } from 'quasar'
|
||||||
|
|
||||||
|
export function startLoading() {
|
||||||
|
Loading.show({ delay: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopLoading() {
|
||||||
|
Loading.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showGlobalError(message) {
|
||||||
|
const alert = Alert.create({
|
||||||
|
html: message,
|
||||||
|
position: 'top-center',
|
||||||
|
enter: 'bounceIn',
|
||||||
|
leave: 'fadeOut'
|
||||||
|
});
|
||||||
|
setTimeout(()=>{ alert.dismiss(); }, 2000);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import Vue from 'vue'
|
||||||
|
import VueI18n from 'vue-i18n'
|
||||||
|
|
||||||
|
Vue.use(VueI18n);
|
||||||
|
|
||||||
|
export const locales = {
|
||||||
|
en: require('./locales/en')
|
||||||
|
};
|
||||||
|
|
||||||
|
export const i18n = new VueI18n({
|
||||||
|
locale: localStorage.getItem('lang') || navigator.language || navigator.userLanguage,
|
||||||
|
fallbackLocale: 'en',
|
||||||
|
messages: locales
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<meta name="msapplication-tap-highlight" content="no">
|
||||||
|
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||||
|
|
||||||
|
<title>Quasar App</title>
|
||||||
|
<link rel="icon" href="statics/quasar-logo.png" type="image/x-icon">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="q-app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"title": "Sipwise Customer Portal",
|
||||||
|
"login_title": "Customer Self Care Portal",
|
||||||
|
"login_button": "Sign In",
|
||||||
|
"login_error": "Wrong username or password",
|
||||||
|
"username": "Username",
|
||||||
|
"username_helper": "Web-Username, SIP-URI",
|
||||||
|
"password": "Password",
|
||||||
|
"password_helper": "Web-Password",
|
||||||
|
"rtcEngineDisconnected": "You can not start a call. Service ist currently unavailable.",
|
||||||
|
"startCall": "Start Call",
|
||||||
|
"sendSms": "Send SMS",
|
||||||
|
"sendFax": "Send Fax",
|
||||||
|
"mainNavigation": {
|
||||||
|
"conversations":{
|
||||||
|
"title": "Conversations",
|
||||||
|
"subTitle": "Calls, SMS, VoiceMails"
|
||||||
|
},
|
||||||
|
"callForward":{
|
||||||
|
"title": "Call Forward",
|
||||||
|
"subTitle": "Control your calls",
|
||||||
|
"always": "Always",
|
||||||
|
"companyHours": "Company Hours",
|
||||||
|
"afterHours": "After Hours"
|
||||||
|
},
|
||||||
|
"callBlocking": {
|
||||||
|
"title": "Call Blocking",
|
||||||
|
"subTitle": "Block numbers",
|
||||||
|
"incoming": "Incoming",
|
||||||
|
"outgoing": "Outgoing",
|
||||||
|
"privacy": "Privacy"
|
||||||
|
},
|
||||||
|
"reminder": {
|
||||||
|
"title": "Reminder"
|
||||||
|
},
|
||||||
|
"pbxConfiguration":{
|
||||||
|
"title": "PBX Configuration",
|
||||||
|
"subTitle": "Groups, Devices",
|
||||||
|
"groups": "Groups",
|
||||||
|
"seats": "Seats",
|
||||||
|
"devices": "Devices"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"loggedInAs": "Logged in as"
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
// === DEFAULT / CUSTOM STYLE ===
|
||||||
|
// WARNING! always comment out ONE of the two require() calls below.
|
||||||
|
// 1. use next line to activate CUSTOM STYLE (./src/themes)
|
||||||
|
require(`./themes/app.${__THEME}.styl`)
|
||||||
|
// 2. or, use next line to activate DEFAULT QUASAR STYLE
|
||||||
|
// require(`quasar/dist/quasar.${__THEME}.css`)
|
||||||
|
// ==============================
|
||||||
|
|
||||||
|
// Uncomment the following lines if you need IE11/Edge support
|
||||||
|
// require(`quasar/dist/quasar.ie`)
|
||||||
|
// require(`quasar/dist/quasar.ie.${__THEME}.css`)
|
||||||
|
|
||||||
|
import _ from 'lodash'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import VueResource from 'vue-resource'
|
||||||
|
import Quasar from 'quasar'
|
||||||
|
import { store } from './store'
|
||||||
|
import { i18n, locales } from './i18n'
|
||||||
|
import router from './router'
|
||||||
|
import { sync } from 'vuex-router-sync'
|
||||||
|
|
||||||
|
Vue.use(VueResource);
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
Vue.use(Quasar); // Install Quasar Framework
|
||||||
|
|
||||||
|
|
||||||
|
if (__THEME === 'mat') {
|
||||||
|
require('quasar-extras/roboto-font')
|
||||||
|
}
|
||||||
|
import 'quasar-extras/material-icons'
|
||||||
|
// import 'quasar-extras/ionicons'
|
||||||
|
import 'quasar-extras/fontawesome'
|
||||||
|
import 'quasar-extras/animate'
|
||||||
|
|
||||||
|
sync(store, router);
|
||||||
|
|
||||||
|
Vue.http.interceptors.push(function(request, next) {
|
||||||
|
var jwt = localStorage.getItem('jwt');
|
||||||
|
if(!_.isEmpty(jwt)) {
|
||||||
|
request.headers.set('Authorization', 'Bearer ' + jwt);
|
||||||
|
}
|
||||||
|
if(request.method === 'POST' && _.isEmpty(request.body)) {
|
||||||
|
request.body = {};
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
Quasar.start(() => {
|
||||||
|
new Vue({
|
||||||
|
el: '#q-app',
|
||||||
|
i18n,
|
||||||
|
store,
|
||||||
|
router,
|
||||||
|
render: h => h(require('./App.vue').default)
|
||||||
|
})
|
||||||
|
});
|
@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
import Vue from 'vue'
|
||||||
|
import VueRouter from 'vue-router'
|
||||||
|
import { store } from './store'
|
||||||
|
import routes from './routes'
|
||||||
|
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
var router = new VueRouter({
|
||||||
|
/*
|
||||||
|
* NOTE! VueRouter "history" mode DOESN'T works for Cordova builds,
|
||||||
|
* it is only to be used only for websites.
|
||||||
|
*
|
||||||
|
* If you decide to go with "history" mode, please also open /config/index.js
|
||||||
|
* and set "build.publicPath" to something other than an empty string.
|
||||||
|
* Example: '/' instead of current ''
|
||||||
|
*
|
||||||
|
* If switching back to default "hash" mode, don't forget to set the
|
||||||
|
* build publicPath back to '' so Cordova builds work again.
|
||||||
|
*/
|
||||||
|
routes: routes
|
||||||
|
});
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if (!store.getters['user/isLogged'] && to.path !== '/login') {
|
||||||
|
next({
|
||||||
|
path: '/login'
|
||||||
|
});
|
||||||
|
} else if (store.getters['user/isLogged'] && to.path === '/login') {
|
||||||
|
next({
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
@ -0,0 +1,64 @@
|
|||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: '/user',
|
||||||
|
component: require('./components/layouts/Default').default,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'conversations',
|
||||||
|
component: require('./components/pages/Conversations').default,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'call-forward/always',
|
||||||
|
component: require('./components/pages/CallForward/Always').default,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'call-forward/company-hours',
|
||||||
|
component: require('./components/pages/CallForward/CompanyHours').default
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'call-forward/after-hours',
|
||||||
|
component: require('./components/pages/CallForward/AfterHours').default
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'call-blocking/incoming',
|
||||||
|
component: require('./components/pages/CallBlocking/Incoming').default
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'call-blocking/outgoing',
|
||||||
|
component: require('./components/pages/CallBlocking/Outgoing').default
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'call-blocking/privacy',
|
||||||
|
component: require('./components/pages/CallBlocking/Privacy').default
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'reminder',
|
||||||
|
component: require('./components/pages/Reminder').default},
|
||||||
|
{
|
||||||
|
path: 'pbx-configuration/groups',
|
||||||
|
component: require('./components/pages/PbxConfiguration/Groups').default
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'pbx-configuration/seats',
|
||||||
|
component: require('./components/pages/PbxConfiguration/Seats').default
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'pbx-configuration/devices',
|
||||||
|
component: require('./components/pages/PbxConfiguration/Devices').default
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/login',
|
||||||
|
component: require('./components/Login').default
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
redirect: {path:'/user/conversations'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '*',
|
||||||
|
component: require('./components/Error404').default
|
||||||
|
}
|
||||||
|
]
|
After Width: | Height: | Size: 7.0 KiB |
@ -0,0 +1,105 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import _ from 'lodash'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import Vuex from 'vuex'
|
||||||
|
// import cdk from 'cdk';
|
||||||
|
|
||||||
|
var rtcEngineClient = null;
|
||||||
|
var rtcEngineNetwork = null;
|
||||||
|
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
|
export const store = new Vuex.Store({
|
||||||
|
modules: {
|
||||||
|
user: require('./user').UserModule
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
rtcEngineConnected: false
|
||||||
|
},
|
||||||
|
getters: {},
|
||||||
|
mutations: {
|
||||||
|
disconnectRtcEngine(state) {
|
||||||
|
state.rtcEngineConnected = false;
|
||||||
|
},
|
||||||
|
connectRtcEngine(state) {
|
||||||
|
state.rtcEngineConnected = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
createRtcEngineSession(context) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
Promise.resolve().then(()=>{
|
||||||
|
return Vue.http.post('/api/rtcsessions/');
|
||||||
|
}).then((res)=>{
|
||||||
|
return Vue.http.get(res.headers.get('Location'));
|
||||||
|
}).then((res)=>{
|
||||||
|
return res.json();
|
||||||
|
}).then((body)=>{
|
||||||
|
localStorage.setItem('rtcEngineSession', body.rtc_browser_token);
|
||||||
|
resolve(localStorage.getItem('rtcEngineSession'));
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
connectRtcEngine(context, options) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
|
||||||
|
var force = _.get(options, 'force', false);
|
||||||
|
var isConnected = rtcEngineClient instanceof cdk.Client && _.isEmpty(rtcEngineClient.disconnectReason);
|
||||||
|
|
||||||
|
if(isConnected && !force) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
Promise.resolve().then(()=>{
|
||||||
|
return context.dispatch('disconnectRtcEngine');
|
||||||
|
}).then(()=>{
|
||||||
|
return context.dispatch('createRtcEngineSession');
|
||||||
|
}).then((sessionToken)=>{
|
||||||
|
rtcEngineClient = new cdk.Client({
|
||||||
|
url: 'wss://' + window.location.host + '/rtc/api',
|
||||||
|
userSession: sessionToken
|
||||||
|
});
|
||||||
|
rtcEngineClient.onConnect(()=>{
|
||||||
|
rtcEngineNetwork = rtcEngineClient.getNetworkByTag('sip');
|
||||||
|
rtcEngineNetwork.onConnect(()=>{
|
||||||
|
context.commit('connectRtcEngine');
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
rtcEngineNetwork.onDisconnect(()=>{
|
||||||
|
context.commit('disconnectRtcEngine');
|
||||||
|
reject(new Error('NetworkError: ' + rtcEngineNetwork.disconnectReason));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
rtcEngineClient.onDisconnect(()=>{
|
||||||
|
context.commit('disconnectRtcEngine');
|
||||||
|
reject(new Error('ClientError: ' + rtcEngineClient.disconnectReason));
|
||||||
|
});
|
||||||
|
}).catch((err)=>{
|
||||||
|
context.commit('disconnectRtcEngine');
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
disconnectRtcEngine(context) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
context.commit('disconnectRtcEngine');
|
||||||
|
localStorage.removeItem('rtcEngineSession');
|
||||||
|
if(rtcEngineClient instanceof cdk.Client && _.isEmpty(rtcEngineClient.disconnectReason)) {
|
||||||
|
rtcEngineClient.onDisconnect(()=>{
|
||||||
|
rtcEngineClient = null;
|
||||||
|
rtcEngineNetwork = null;
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
rtcEngineClient.disconnect();
|
||||||
|
} else {
|
||||||
|
rtcEngineClient = null;
|
||||||
|
rtcEngineNetwork = null;
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
import { getGroups } from '../../api/pbx-config'
|
||||||
|
|
||||||
|
export const PbxGroups = {
|
||||||
|
state: {
|
||||||
|
groups: [],
|
||||||
|
page: 1
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
showGroups: function(state, options) {
|
||||||
|
state.groups = options.groups;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
loadGroups: function(context, options) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
getGroups().then((groups)=>{
|
||||||
|
context.commit('showGroups', {
|
||||||
|
groups: groups
|
||||||
|
});
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,106 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { login, getCapabilities, getUserData} from '../api/user';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
// import cdk from 'cdk';
|
||||||
|
|
||||||
|
var rtcEngineClient = '';
|
||||||
|
|
||||||
|
export const UserModule = {
|
||||||
|
namespaced: true,
|
||||||
|
state: {
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
jwt: localStorage.getItem('jwt') || null,
|
||||||
|
subscriberId: localStorage.getItem('subscriberId') || null,
|
||||||
|
loggedUsername: '',
|
||||||
|
subscriber: null,
|
||||||
|
capabilities: null,
|
||||||
|
numbers: null
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
isLogged(state, getters) {
|
||||||
|
return !_.isEmpty(state.jwt) && !_.isEmpty(state.subscriberId);
|
||||||
|
},
|
||||||
|
getUsername(state, getters) {
|
||||||
|
if(state.subscriber !== null && !_.isEmpty(state.subscriber.display_name)) {
|
||||||
|
return state.subscriber.display_name;
|
||||||
|
} else if (state.subscriber !== null) {
|
||||||
|
return state.subscriber.username + "@" + state.subscriber.domain;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isAdmin(state, getters) {
|
||||||
|
return state.subscriber !== null && state.subscriber.administrative;
|
||||||
|
},
|
||||||
|
isPbxAdmin(state, getters) {
|
||||||
|
return getters.isAdmin && state.capabilities !== null && state.capabilities.cloudpbx;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
login(state, options) {
|
||||||
|
state.jwt = options.jwt;
|
||||||
|
state.subscriberId = options.subscriberId;
|
||||||
|
},
|
||||||
|
setUserData(state, options) {
|
||||||
|
state.subscriber = options.subscriber;
|
||||||
|
state.capabilities = options.capabilities;
|
||||||
|
state.numbers = options.numbers;
|
||||||
|
},
|
||||||
|
logout(state) {
|
||||||
|
state.jwt = null;
|
||||||
|
state.subscriberId = null;
|
||||||
|
},
|
||||||
|
updatePassword (state, password) {
|
||||||
|
state.password = password;
|
||||||
|
},
|
||||||
|
updateUsername (state, username) {
|
||||||
|
state.username = username;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
login(context) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
login(context.state.username, context.state.password).then((result)=>{
|
||||||
|
localStorage.setItem('jwt', result.jwt);
|
||||||
|
localStorage.setItem('subscriberId', result.subscriberId);
|
||||||
|
context.commit('login', {
|
||||||
|
jwt: localStorage.getItem('jwt'),
|
||||||
|
subscriberId: localStorage.getItem('subscriberId')
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
logout(context) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
localStorage.removeItem('jwt');
|
||||||
|
localStorage.removeItem('subscriberId');
|
||||||
|
context.dispatch('disconnectRtcEngine', null, {root: true}).then(()=>{
|
||||||
|
context.commit('disconnectRtcEngine');
|
||||||
|
});
|
||||||
|
context.commit('logout');
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
initUser(context) {
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
getUserData(localStorage.getItem('subscriberId')).then((result)=>{
|
||||||
|
context.commit('setUserData', {
|
||||||
|
subscriber: result.subscriber,
|
||||||
|
capabilities: result.capabilities,
|
||||||
|
numbers: result.numbers
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
}).catch((err)=>{
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
// This file is included in the build if src/main.js imports it.
|
||||||
|
// Otherwise the default iOS CSS file is bundled.
|
||||||
|
// Check "DEFAULT / CUSTOM STYLE" in src/main.js
|
||||||
|
|
||||||
|
// App Shared Variables
|
||||||
|
// --------------------------------------------------
|
||||||
|
// Shared Stylus variables go in the app.variables.styl file
|
||||||
|
@import 'app.variables'
|
||||||
|
|
||||||
|
// Quasar iOS Design Stylus
|
||||||
|
// --------------------------------------------------
|
||||||
|
// Custom App variables must be declared before importing Quasar.
|
||||||
|
// Quasar will use its default values when a custom variable isn't provided.
|
||||||
|
@import '~quasar-framework/dist/quasar.ios.styl'
|
@ -0,0 +1,21 @@
|
|||||||
|
// This file is included in the build if src/main.js imports it.
|
||||||
|
// Otherwise the default Material CSS file is bundled.
|
||||||
|
// Check "DEFAULT / CUSTOM STYLE" in src/main.js
|
||||||
|
|
||||||
|
// App Shared Variables
|
||||||
|
// --------------------------------------------------
|
||||||
|
// Shared Stylus variables go in the app.variables.styl file
|
||||||
|
@import 'app.variables'
|
||||||
|
|
||||||
|
// Quasar Material Design Stylus
|
||||||
|
// --------------------------------------------------
|
||||||
|
// Custom App variables must be declared before importing Quasar.
|
||||||
|
// Quasar will use its default values when a custom variable isn't provided.
|
||||||
|
@import '~quasar-framework/dist/quasar.mat.styl'
|
||||||
|
|
||||||
|
.q-fab-active-icon.material-icons,
|
||||||
|
.q-fab-icon.material-icons {
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
// This file is included in the build if src/main.js imports
|
||||||
|
// either app.mat.styl or app.ios.styl.
|
||||||
|
// Check "DEFAULT / CUSTOM STYLE" in src/main.js
|
||||||
|
|
||||||
|
// App Shared Variables
|
||||||
|
// --------------------------------------------------
|
||||||
|
// To customize the look and feel of this app, you can override
|
||||||
|
// the Stylus variables found in Quasar's source Stylus files. Setting
|
||||||
|
// variables before Quasar's Stylus will use these variables rather than
|
||||||
|
// Quasar's default Stylus variable values. Stylus variables specific
|
||||||
|
// to the themes belong in either the app.ios.styl or app.mat.styl files.
|
||||||
|
|
||||||
|
|
||||||
|
// App Shared Color Variables
|
||||||
|
// --------------------------------------------------
|
||||||
|
// It's highly recommended to change the default colors
|
||||||
|
// to match your app's branding.
|
||||||
|
|
||||||
|
$primary = #66A648
|
||||||
|
$secondary = #26A69A
|
||||||
|
$tertiary = #555
|
||||||
|
|
||||||
|
$neutral = #E0E1E2
|
||||||
|
$positive = #21BA45
|
||||||
|
$negative = #DB2828
|
||||||
|
$info = #31CCEC
|
||||||
|
$warning = #F2C037
|
||||||
|
|
||||||
|
$toolbar-background = #66A648
|
||||||
|
$toolbar-min-height = 60px
|
||||||
|
|
||||||
|
$layout-header-shadow = $no-shadow
|
||||||
|
|
||||||
|
$layout-aside-shadow = $no-shadow
|
||||||
|
$layout-aside-left-width = 260px
|
||||||
|
$layout-aside-background = #32404E
|
||||||
|
|
||||||
|
$layout-footer-shadow = $no-shadow
|
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Webpack alias "variables" points to this file.
|
||||||
|
// So you can import it in your app's *.vue files
|
||||||
|
// inside the <style> tag like below.
|
||||||
|
//
|
||||||
|
// NOTICE that you need lang="styl"
|
||||||
|
//
|
||||||
|
// <style lang="styl">
|
||||||
|
// @import '~variables'
|
||||||
|
// ........
|
||||||
|
// </style>
|
||||||
|
|
||||||
|
|
||||||
|
// First we load app's Stylus variables
|
||||||
|
@import 'app.variables'
|
||||||
|
|
||||||
|
// Then we load Quasar Stylus variables.
|
||||||
|
// Any variables defined in "app.variables.styl"
|
||||||
|
// will override Quasar's ones.
|
||||||
|
//
|
||||||
|
// NOTICE that we only import Core Quasar Variables
|
||||||
|
// like colors, media breakpoints, and so.
|
||||||
|
// No component variable will be included.
|
||||||
|
@import '~quasar/dist/core.variables'
|
@ -0,0 +1,63 @@
|
|||||||
|
# DOCKER_NAME=ngcp-csc-ui-stretch
|
||||||
|
FROM docker.mgm.sipwise.com/sipwise-stretch:latest
|
||||||
|
|
||||||
|
# Important! Update this no-op ENV variable when this Dockerfile
|
||||||
|
# is updated with the current date. It will force refresh of all
|
||||||
|
# of the base images and things like `apt-get update` won't be using
|
||||||
|
# old cached versions when the Dockerfile is built.
|
||||||
|
ENV REFRESHED_AT 2017-10-06
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
ENV DISPLAY=:0
|
||||||
|
|
||||||
|
# files that get-code generates
|
||||||
|
COPY t/sources.list.d/builddeps.list /etc/apt/sources.list.d/
|
||||||
|
COPY t/sources.list.d/preferences /etc/apt/preferences.d/
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install --assume-yes \
|
||||||
|
devscripts \
|
||||||
|
firefox-esr \
|
||||||
|
gtk2-engines-pixbuf \
|
||||||
|
libgconf-2-4 \
|
||||||
|
net-tools \
|
||||||
|
nodejs \
|
||||||
|
wget \
|
||||||
|
xterm \
|
||||||
|
xvfb
|
||||||
|
|
||||||
|
RUN wget -q https://deb.sipwise.com/files/google-chrome-stable_59.0.3071.115-1_amd64.deb
|
||||||
|
RUN dpkg --force-depends -i google-chrome-stable_59.0.3071.115-1_amd64.deb || true
|
||||||
|
RUN apt-get --assume-yes -f install
|
||||||
|
|
||||||
|
RUN echo "cd /code && ./t/testrunner" >/root/.bash_history
|
||||||
|
|
||||||
|
# we cannot use /code/ here otherwise it will be 'mounted over' with following 'docker run'
|
||||||
|
ADD package.json /tmp/
|
||||||
|
ADD npm-shrinkwrap.json /tmp/
|
||||||
|
ADD README.md /tmp/
|
||||||
|
WORKDIR /tmp
|
||||||
|
RUN npm install /tmp
|
||||||
|
|
||||||
|
WORKDIR /code
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Instructions for usage
|
||||||
|
# ----------------------
|
||||||
|
# When you want to build the base image from scratch
|
||||||
|
# (jump to the next section if you don't want to build yourself!):
|
||||||
|
#
|
||||||
|
# you need to put the proper NGCP sources at t/sources.list.d/builddeps.list
|
||||||
|
# for instance, trunk:
|
||||||
|
# echo "deb https://deb.sipwise.com/autobuild/ release-trunk-stretch main" > t/sources.list.d/builddeps.list
|
||||||
|
#
|
||||||
|
# NOTE: run the following command from root folder of git repository:
|
||||||
|
# % docker build --tag="ngcp-csc-ui-stretch" -f ./t/Dockerfile .
|
||||||
|
# % docker run --rm -i -t -v $(pwd):/code:ro ngcp-csc-ui-stretch:latest bash
|
||||||
|
#
|
||||||
|
# Use the existing docker image:
|
||||||
|
# % docker pull docker.mgm.sipwise.com/ngcp-csc-ui-stretch
|
||||||
|
# NOTE: run the following command from root folder of git repository:
|
||||||
|
# % docker run --rm -i -t -v $(pwd):/code:ro -v /results docker.mgm.sipwise.com/ngcp-csc-ui-stretch:latest bash
|
||||||
|
#
|
||||||
|
# Inside docker:
|
||||||
|
# cd /code && ./t/testrunner
|
||||||
|
################################################################################
|
@ -0,0 +1,17 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { UserModule } from '../../src/store/user';
|
||||||
|
import { assert } from 'chai';
|
||||||
|
|
||||||
|
describe('UserModule', ()=>{
|
||||||
|
|
||||||
|
it('should login', ()=>{
|
||||||
|
var state = {};
|
||||||
|
UserModule.mutations.login(state, {
|
||||||
|
jwt: 'abc123',
|
||||||
|
subscriberId: 123
|
||||||
|
});
|
||||||
|
assert.equal(state.jwt, 'abc123');
|
||||||
|
assert.equal(state.subscriberId, '123');
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if ! [ -f /.dockerenv ] && ! grep -q 'devices:/docker' /proc/1/cgroup ; then
|
||||||
|
echo "Not running inside docker, exiting to avoid data damage." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
echo "### Starting display server"
|
||||||
|
Xvfb -ac :0 -screen 0 1280x1024x16 &
|
||||||
|
trap 'killall -9 Xvfb' EXIT
|
||||||
|
|
||||||
|
echo "### Copying and moving files"
|
||||||
|
cp -Rf . /tmp/code
|
||||||
|
ln -s /tmp/node_modules /tmp/code/node_modules
|
||||||
|
cd /tmp/code/
|
||||||
|
|
||||||
|
echo "################################################################################"
|
||||||
|
echo "Finished main setup, now running tests ..."
|
||||||
|
|
||||||
|
npm test
|
||||||
|
|
||||||
|
echo "### Moving JUnit XML files to /results"
|
||||||
|
mv /tmp/code/t/*.xml /results
|
||||||
|
|
||||||
|
echo "Finished test execution, test execution returned with exit code."
|
||||||
|
echo "################################################################################"
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<!-- Configure "view" prop for QLayout -->
|
||||||
|
<q-layout>
|
||||||
|
<q-toolbar slot="header">
|
||||||
|
<!-- opens drawer below
|
||||||
|
<button class="hide-on-drawer-visible" @click="$refs.drawer.open()">
|
||||||
|
<i>menu</i>
|
||||||
|
</button>
|
||||||
|
-->
|
||||||
|
<q-toolbar-title>
|
||||||
|
Title
|
||||||
|
</q-toolbar-title>
|
||||||
|
</q-toolbar>
|
||||||
|
|
||||||
|
<!-- Navigation Tabs
|
||||||
|
<q-tabs slot="navigation">
|
||||||
|
<q-route-tab slot="title" icon="view_quilt" to="/layout/about" replace hide="icon" label="About" />
|
||||||
|
<q-route-tab slot="title" icon="view_day" to="/layout/toolbar" replace hide="icon" label="Toolbar" />
|
||||||
|
<q-route-tab slot="title" icon="view_day" to="/layout/tabs" replace label="Tabs" />
|
||||||
|
<q-route-tab slot="title" icon="input" to="/layout/drawer" replace label="Drawer" />
|
||||||
|
</q-tabs>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Left Side Panel
|
||||||
|
<div slot="left">
|
||||||
|
<q-list no-border link inset-delimiter>
|
||||||
|
<q-list-header>Essential Links</q-list-header>
|
||||||
|
<q-item>
|
||||||
|
<q-item-side icon="school" />
|
||||||
|
<q-item-main label="Docs" sublabel="quasar-framework.org" />
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-side icon="record_voice_over" />
|
||||||
|
<q-item-main label="Forum" sublabel="forum.quasar-framework.org" />
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-side icon="chat" />
|
||||||
|
<q-item-main label="Gitter Channel" sublabel="Quasar Lobby" />
|
||||||
|
</q-item>
|
||||||
|
<q-item>
|
||||||
|
<q-item-side icon="rss feed" />
|
||||||
|
<q-item-main label="Twitter" sublabel="@quasarframework" />
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Right Side Panel
|
||||||
|
<div slot="right">
|
||||||
|
...
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<router-view />
|
||||||
|
|
||||||
|
<!-- Footer
|
||||||
|
<q-toolbar slot="footer">
|
||||||
|
...
|
||||||
|
</q-toolbar>
|
||||||
|
-->
|
||||||
|
</q-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<!-- if you want automatic padding use "layout-padding" class -->
|
||||||
|
<div class="layout-padding">
|
||||||
|
<!-- your content -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
Loading…
Reference in new issue