TT#88909 Migrate Quasar to version 1.14.0

- Migrated external lib injection in boot files
- Replaced vue-resource by axios
- Applied more restrictive linting rules for Vue.js
- Replaced npm by yarn
- Removed old chrome release from test environment
- Refactor Voicebox Settings
- Refactor SpeedDial
- Refactor Reminder
- Refactor Call Blocking
- Refactor Call Forward
- Integrate jest test framework
- Remove mocha test runner
- Refactor User Settings
- Refactor PBX Configuration
- Refactor Call

Change-Id: I9b2ea327e7959fb5e78d1bd53a4156ecb1c5f191
mr9.1.1
Hans-Peter Herzog 5 years ago
parent 08b813dae1
commit 235f0ff30c

@ -1,5 +1,19 @@
{
"presets": [["es2015", {"modules": false}], "stage-2"],
"plugins": ["transform-runtime"],
"comments": false
"plugins": ["@babel/plugin-syntax-dynamic-import"],
"env": {
"test": {
"plugins": ["dynamic-import-node"],
"presets": [
[
"@babel/preset-env",
{
"modules": "commonjs",
"targets": {
"node": "current"
}
}
]
]
}
}
}

@ -2,11 +2,8 @@ root = true
[*]
charset = utf-8
indent_style = space
indent_style = tab
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[package.json]
indent_size = 2

@ -1,3 +1,6 @@
build/*.js
config/*.js
dist/*.js
/dist
/src-bex/www
/src-capacitor
/src-cordova
/.quasar
/node_modules

@ -1,38 +1,89 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
es6: true
},
extends: [
'eslint:recommended'
],
plugins: [
'html',
'import'
],
globals: {
'cdk': true,
'cordova': true,
'DEV': true,
'PROD': true,
'__THEME': true
},
rules: {
'arrow-parens': 0,
'one-var': 0,
'import/first': 0,
'import/named': 2,
'import/namespace': 2,
'import/default': 2,
'import/export': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'brace-style': [2, 'stroustrup', {'allowSingleLine': true}],
"no-console": 0
}
};
// https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
// This option interrupts the configuration hierarchy at this file
// Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
root: true,
parserOptions: {
parser: 'babel-eslint',
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
sourceType: 'module' // Allows for the use of imports
},
env: {
browser: true
},
// Rules order is important, please avoid shuffling them
extends: [
// Base ESLint recommended rules
// 'eslint:recommended',
// Uncomment any of the lines below to choose desired strictness,
// but leave only one uncommented!
// See https://eslint.vuejs.org/rules/#available-rules
'plugin:vue/essential', // Priority A: Essential (Error Prevention)
'plugin:vue/strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
'plugin:vue/recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
'standard'
],
plugins: [
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file
// required to lint *.vue files
'vue',
],
globals: {
'ga': true, // Google Analytics
'cordova': true,
'__statics': true,
'process': true,
'Capacitor': true,
'chrome': true
},
// add your custom rules here
rules: {
// allow async-await
'generator-star-spacing': 'off',
// allow paren-less arrow functions
'arrow-parens': 'off',
'one-var': 'off',
'import/first': 'off',
'import/named': 'error',
'import/namespace': 'error',
'import/default': 'error',
'import/export': 'error',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
'prefer-promise-reject-errors': 'off',
'no-tabs': 'off',
'no-trailing-spaces': 'off',
// allow debugger during development only
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'indent': [
'error',
'tab'
],
'vue/script-indent': [
'error',
'tab'
],
'vue/html-indent': [
'error',
'tab'
]
},
"overrides": [
{
"files": ["*.vue"],
"rules": {
"indent": "off"
}
}
]
}

43
.gitignore vendored

@ -1,19 +1,38 @@
.DS_Store
.thumbs.db
.vscode
node_modules/
dist/
npm-debug.log*
cordova/platforms
cordova/plugins
node_modules
# Quasar core related directories
.quasar
/dist
# Cordova related directories and files
/src-cordova/node_modules
/src-cordova/platforms
/src-cordova/plugins
/src-cordova/www
# Junit reports
t/TESTS*
# Capacitor related directories and files
/src-capacitor/www
/src-capacitor/node_modules
# BEX related directories and files
/src-bex/www
/src-bex/js/core
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# IntelliJ
# Editor directories and files
.idea
*.iml
*.suo
*.ntvs*
*.njsproj
*.sln
csc/
/src/config.js
src/config.js
/junit.xml
/test/jest/coverage

@ -1,2 +0,0 @@
save-prefix =
registry = https://npm-registry.sipwise.com/

@ -0,0 +1,8 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: [
// to edit target browsers: use "browserslist" field in package.json
require('autoprefixer')
]
}

@ -0,0 +1,18 @@
const fs = require('fs-extra')
let extend = undefined
/**
* The .babelrc file has been created to assist Jest for transpiling.
* You should keep your application's babel rules in this file.
*/
if (fs.existsSync('./.babelrc')) {
extend = './.babelrc'
}
module.exports = {
presets: [
'@quasar/babel-preset-app'
],
extends: extend
}

@ -1,91 +0,0 @@
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)
}

@ -1,13 +0,0 @@
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'
}
}

@ -1,3 +0,0 @@
/* eslint-disable */
require('eventsource-polyfill')
require('webpack-hot-middleware/client?noInfo=true&reload=true')

@ -1,68 +0,0 @@
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;
webpackConfig.watchOptions = {
ignored: [
'build',
'config',
'debian',
'dist',
'node_modules',
't',
'templates'
]
}
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()
}
})

@ -1,7 +0,0 @@
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')

@ -1,86 +0,0 @@
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)
})
}
})

@ -1,108 +0,0 @@
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].[hash].js',
chunkFilename: 'js/[id].[chunkhash].js'
},
resolve: {
extensions: ['.js', '.vue', '.json'],
modules: [
resolve('src'),
resolve('node_modules')
],
alias: config.aliases
},
module: {
rules: [
{
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
}
}

@ -1,43 +0,0 @@
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
}
})

@ -1,78 +0,0 @@
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']
})
]
})

@ -1,6 +0,0 @@
var merge = require('webpack-merge')
var prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})

@ -1,65 +0,0 @@
var path = require('path')
module.exports = {
// Webpack aliases
aliases: {
'quasar-frameworks': path.resolve(__dirname, '../node_modules/quasar-framework/'),
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: false,
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': ''
}
}
}
*/

@ -1,3 +0,0 @@
module.exports = {
NODE_ENV: '"production"'
}

2
debian/control vendored

@ -6,7 +6,7 @@ Homepage: https://www.sipwise.com/
Standards-Version: 3.9.8
Build-Depends:
debhelper-compat (= 12),
npm,
yarnpkg,
Package: ngcp-csc-ui
Architecture: all

4
debian/rules vendored

@ -7,7 +7,7 @@
dh "$@"
override_dh_auto_install:
npm ci
yarnpkg install
cp src/config.template.js src/config.js
npm run build
yarnpkg run build
mv dist csc

6
env/Dockerfile vendored

@ -5,16 +5,16 @@ FROM docker.mgm.sipwise.com/sipwise-buster:latest
# 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 2020-06-17
ENV REFRESHED_AT 2020-08-27
# files that get-code generates
COPY env/sources.list.d/builddeps.list /etc/apt/sources.list.d/
COPY env/sources.list.d/preferences /etc/apt/preferences.d/
RUN apt-get update && \
apt-get install --assume-yes \
npm \
apt-get install --assume-yes --no-install-recommends \
nodejs \
yarnpkg \
&& \
apt-get clean

6
env/run_csc_ui vendored

@ -36,16 +36,16 @@ echo "App config '${app_config}' is OK."
echo "JFYI, important components versions:"
echo -n "node --version : " && node --version
echo -n "npm --version : " && npm --version
echo -n "yarn --version : " && yarnpkg --version
echo "Configuring Vue.js/Quasar dev environment, running 'npm ci'..."
if ! npm ci ; then
if ! yarnpkg install ; then
echo "ERROR: cannot install all npm dependencies. Aborting."
exit 1
fi
echo "Starting Quasar dev environment, running 'npm run dev'..."
if ! npm run dev; then
if ! yarnpkg run dev ; then
echo "ERROR: cannot run quasar dev environment. Aborting."
exit 1
fi

@ -0,0 +1,62 @@
module.exports = {
globals: {
__DEV__: true
},
setupFilesAfterEnv: [
'<rootDir>/test/jest/jest.setup.js'
],
// noStackTrace: true,
// bail: true,
// cache: false,
// verbose: true,
// watch: true,
collectCoverage: true,
coverageDirectory: '<rootDir>/test/jest/coverage',
collectCoverageFrom: [
'<rootDir>/src/**/*.vue',
'<rootDir>/src/**/*.js',
'<rootDir>/src/**/*.ts',
'<rootDir>/src/**/*.jsx'
],
coverageThreshold: {
global: {
// branches: 50,
// functions: 50,
// lines: 50,
// statements: 50
}
},
testMatch: [
'<rootDir>/test/jest/__tests__/**/*.spec.js',
'<rootDir>/test/jest/__tests__/**/*.test.js',
'<rootDir>/src/**/__tests__/*_jest.spec.js'
],
moduleFileExtensions: [
'vue',
'js',
'json'
],
moduleNameMapper: {
'^vue$': '<rootDir>/node_modules/vue/dist/vue.common.js',
'^test-utils$': '<rootDir>/node_modules/@vue/test-utils/dist/vue-test-utils.js',
'^quasar$': '<rootDir>/node_modules/quasar/dist/quasar.common.js',
'^~/(.*)$': '<rootDir>/$1',
'^src/(.*)$': '<rootDir>/src/$1',
'.*css$': '<rootDir>/test/jest/utils/stub.css'
},
transform: {
'.*\\.vue$': 'vue-jest',
'.*\\.js$': 'babel-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub'
// use these if NPM is being flaky
// '.*\\.vue$': '<rootDir>/node_modules/@quasar/quasar-app-extension-testing-unit-jest/node_modules/vue-jest',
// '.*\\.js$': '<rootDir>/node_modules/@quasar/quasar-app-extension-testing-unit-jest/node_modules/babel-jest'
},
transformIgnorePatterns: [
'<rootDir>/node_modules/(?!quasar/lang)'
],
snapshotSerializers: [
'<rootDir>/node_modules/jest-serializer-vue'
],
reporters: ['default', 'jest-junit']
}

@ -0,0 +1,36 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": [
"src/*"
],
"app/*": [
"*"
],
"components/*": [
"src/components/*"
],
"layouts/*": [
"src/layouts/*"
],
"pages/*": [
"src/pages/*"
],
"assets/*": [
"src/assets/*"
],
"boot/*": [
"src/boot/*"
],
"vue$": [
"node_modules/vue/dist/vue.esm.js"
]
}
},
"exclude": [
"dist",
".quasar",
"node_modules"
]
}

@ -1,59 +0,0 @@
'use strict';
var _ = require('lodash');
var webpackCsc = require('./build/webpack.base.conf');
webpackCsc.module.rules.shift();
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
}
});
};

10295
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,93 +1,71 @@
{
"name": "ngcp-csc-ui",
"productName": "Customer Self-Care Web UI",
"version": "0.3.1",
"description": "Customer Self-Care Web UI",
"version": "0.0.1",
"description": "A Quasar Framework app",
"productName": "Customer Self-Care Web Interface",
"author": "Hans-Peter Herzog <hherzog@sipwise.com>",
"private": true,
"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",
"test": "karma start ./karma.js --single-run",
"dev-test": "karma start ./karma.js",
"dev-docker": "docker pull docker.mgm.sipwise.com/ngcp-csc-ui-env-buster; docker run --rm -p 8080:8080 -i -t -v $(pwd):/code:rw docker.mgm.sipwise.com/ngcp-csc-ui-env-buster:latest env/run_csc_ui $1"
"lint": "eslint --ext .js,.vue ./",
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
"build": "./node_modules/@quasar/cli/bin/quasar build",
"dev": "./node_modules/@quasar/cli/bin/quasar dev",
"dev:docker": "docker pull docker.mgm.sipwise.com/ngcp-csc-ui-env-buster; docker run --rm -p 8080:8080 -i -t -v $(pwd):/code:rw docker.mgm.sipwise.com/ngcp-csc-ui-env-buster:latest env/run_csc_ui $1",
"test:unit": "jest --updateSnapshot",
"test:unit:coverage": "jest --coverage",
"test:unit:watch": "jest --watch",
"test:unit:watchAll": "jest --watchAll",
"serve:test:coverage": "quasar serve test/jest/coverage/lcov-report/ --port 8788",
"concurrently:dev:jest": "concurrently \"quasar dev\" \"jest --watch\""
},
"dependencies": {
"babel-runtime": "^6.25.0",
"quasar-extras": "0.x",
"quasar-framework": "0.14.9",
"uuid": "3.2.1",
"vue": "^2.5.0",
"vue-i18n": "7.3.2",
"vue-password-strength-meter": "1.7.2",
"vue-resource": "1.3.4",
"vue-router": "^2.5.0",
"vuelidate": "0.7.4",
"vuex": "2.5.0",
"vuex-router-sync": "4.3.2",
"zxcvbn": "4.4.2"
"@quasar/extras": "^1.9.5",
"axios": "^0.18.1",
"core-js": "^3.6.5",
"file-saver": "^2.0.2",
"jest-junit": "^11.1.0",
"jwt-decode": "^2.2.0",
"load-script": "^1.0.0",
"lodash": "^4.17.20",
"moment": "^2.27.0",
"quasar": "^1.14.0",
"vue-i18n": "^8.0.0",
"vue-password-strength-meter": "^1.7.2",
"vue-resource": "^1.5.1",
"vue-scrollto": "^2.18.2",
"vuelidate": "^0.7.5",
"zxcvbn": "^4.4.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",
"crypto-browserify": "3.12.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",
"file-saver": "1.3.3",
"friendly-errors-webpack-plugin": "^1.1.3",
"glob": "^7.1.2",
"google-libphonenumber": "3.0.7",
"html-webpack-plugin": "^2.30.1",
"http-proxy-middleware": "0.19.1",
"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",
"load-script": "1.0.0",
"lodash": "4.17.15",
"mocha": "^4.0.0",
"moment": "2.22.2",
"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-scrollto": "2.11.0",
"vue-style-loader": "^3.0.3",
"vue-template-compiler": "^2.5.0",
"webpack": "^3.6.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-hot-middleware": "^2.19.1",
"webpack-merge": "^4.1.0"
"@quasar/app": "^2.1.0",
"@quasar/cli": "^1.1.0",
"@quasar/quasar-app-extension-testing": "^1.0.0",
"@quasar/quasar-app-extension-testing-unit-jest": "^1.0.1",
"babel-eslint": "^10.0.1",
"eslint": "^6.8.0",
"eslint-config-standard": "^14.1.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^6.1.2",
"parseuri": "^0.0.6"
},
"browserslist": [
"last 10 Chrome versions",
"last 10 Firefox versions",
"last 4 Edge versions",
"last 7 Safari versions",
"last 8 Android versions",
"last 8 ChromeAndroid versions",
"last 8 FirefoxAndroid versions",
"last 10 iOS versions",
"last 5 Opera versions"
],
"engines": {
"node": ">= 10.18.1",
"npm": ">= 6.13.4",
"yarn": ">= 1.21.1"
}
}

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -0,0 +1,17 @@
self.addEventListener('notificationclick', function (event) {
event.notification.close()
var promiseChain = clients.matchAll({
type: 'window',
includeUncontrolled: true
}).then((windowClients) => {
var matchingClient = null
for (var i = 0; i < windowClients.length; i++) {
var windowClient = windowClients[i]
if (windowClient.url === event.notification.data.url) {
return windowClient.focus()
}
}
})
event.waitUntil(promiseChain)
})

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

@ -0,0 +1,214 @@
/*
* This file runs in a Node context (it's NOT transpiled by Babel), so use only
* the ES6 features that are supported by your Node version. https://node.green/
*/
// Configuration for your app
// https://quasar.dev/quasar-cli/quasar-conf-js
/* eslint-env node */
module.exports = function (/* ctx */) {
return {
// https://quasar.dev/quasar-cli/supporting-ts
supportTS: false,
// https://quasar.dev/quasar-cli/prefetch-feature
// preFetch: true,
// app boot file (/src/boot)
// --> boot files are part of "main.js"
// https://quasar.dev/quasar-cli/boot-files
boot: [
'config',
'filters',
'vuelidate',
'i18n',
// 'axios',
'vue-resource',
'routes',
'components',
'vue-scrollto',
'constants'
],
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
css: [
'app.fonts.styl',
'app.common.styl',
'app.styl'
],
// https://github.com/quasarframework/quasar/tree/dev/extras
extras: [
// 'ionicons-v4',
// 'mdi-v5',
'fontawesome-v5',
// 'eva-icons',
// 'themify',
// 'line-awesome',
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
'roboto-font', // optional, you are not bound to it
'material-icons' // optional, you are not bound to it
],
// Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
build: {
vueRouterMode: 'hash', // available values: 'hash', 'history'
// transpile: false,
// Add dependencies for transpiling with Babel (Array of string/regex)
// (from node_modules, which are by default not transpiled).
// Applies only if "transpile" is set to true.
// transpileDependencies: [],
// rtl: false, // https://quasar.dev/options/rtl-support
// preloadChunks: true,
// showProgress: false,
// gzip: true,
// analyze: true,
// Options below are automatically set depending on the env, set them if you want to override
// extractCSS: false,
// https://quasar.dev/quasar-cli/handling-webpack
extendWebpack (cfg) {
cfg.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /node_modules/
})
}
},
// Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-devServer
devServer: {
https: false,
port: 8080,
open: true // opens browser window automatically
},
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
framework: {
iconSet: 'material-icons', // Quasar icon set
lang: 'en-us', // Quasar language pack
config: {},
// Possible values for "importStrategy":
// * 'auto' - (DEFAULT) Auto-import needed Quasar components & directives
// * 'all' - Manually specify what to import
importStrategy: 'auto',
// For special cases outside of where "auto" importStrategy can have an impact
// (like functional components as one of the examples),
// you can manually specify Quasar components/directives to be available everywhere:
//
// components: [],
// directives: [],
// Quasar plugins
plugins: [
'Notify',
'Dialog',
'SessionStorage',
'LocalStorage',
'Dark'
]
},
// animations: 'all', // --- includes all animations
// https://quasar.dev/options/animations
animations: [],
// https://quasar.dev/quasar-cli/developing-ssr/configuring-ssr
ssr: {
pwa: false
},
// https://quasar.dev/quasar-cli/developing-pwa/configuring-pwa
pwa: {
workboxPluginMode: 'GenerateSW', // 'GenerateSW' or 'InjectManifest'
workboxOptions: {}, // only for GenerateSW
manifest: {
name: 'Customer Self-Care Web Interface',
short_name: 'Customer Self-Care Web Interface',
description: 'A Quasar Framework app',
display: 'standalone',
orientation: 'portrait',
background_color: '#ffffff',
theme_color: '#027be3',
icons: [
{
src: 'icons/icon-128x128.png',
sizes: '128x128',
type: 'image/png'
},
{
src: 'icons/icon-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'icons/icon-256x256.png',
sizes: '256x256',
type: 'image/png'
},
{
src: 'icons/icon-384x384.png',
sizes: '384x384',
type: 'image/png'
},
{
src: 'icons/icon-512x512.png',
sizes: '512x512',
type: 'image/png'
}
]
}
},
// Full list of options: https://quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
cordova: {
// noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
},
// Full list of options: https://quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
capacitor: {
hideSplashscreen: true
},
// Full list of options: https://quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
electron: {
bundler: 'packager', // 'packager' or 'builder'
packager: {
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
// OS X / Mac App Store
// appBundleId: '',
// appCategoryType: '',
// osxSign: '',
// protocol: 'myapp://path',
// Windows only
// win32metadata: { ... }
},
builder: {
// https://www.electron.build/configuration/configuration
appId: 'ngcp-csc-ui'
},
// More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration
nodeIntegration: true,
extendWebpack (/* cfg */) {
// do something with Electron main process Webpack cfg
// chainWebpack also available besides this extendWebpack
}
}
}
}

@ -0,0 +1,14 @@
{
"@quasar/testing": {
"harnesses": [
"unit-jest"
]
},
"@quasar/testing-unit-jest": {
"babel": "babelrc",
"options": [
"scripts",
"SFC"
]
}
}

@ -0,0 +1,5 @@
{
"unit-jest": {
"runnerCommand": "jest"
}
}

@ -1,24 +1,10 @@
<template>
<div id="q-app">
<router-view/>
</div>
<div id="q-app">
<router-view />
</div>
</template>
<script>
import {
QTransition
} from 'quasar-framework'
export default {
components: {
QTransition
}
}
export default {
name: 'App'
}
</script>
<style>
.q-field-icon,
.q-item-icon {
font-size: 24px;
}
</style>

@ -1,223 +1,219 @@
import _ from 'lodash';
import Vue from 'vue';
import _ from 'lodash'
import Vue from 'vue'
import {
enableBlockIn,
disableBlockIn,
getPreferences,
addToBlockInList,
editBlockInList,
removeFromBlockInList,
enableBlockOut,
disableBlockOut,
addToBlockOutList,
editBlockOutList,
removeFromBlockOutList,
enablePrivacy,
disablePrivacy
} from './subscriber';
export function enableIncomingCallBlocking(id) {
return enableBlockIn(id);
}
export function disableIncomingCallBlocking(id) {
return disableBlockIn(id);
}
export function getIncomingCallBlocking(id) {
return new Promise((resolve, reject)=>{
getPreferences(id).then((result)=>{
resolve({
enabled: result.block_in_mode,
list: result.block_in_list,
blockAnonymous: result.block_in_clir
});
}).catch((err)=>{
reject(err);
});
});
}
export function addNumberToIncomingList(id, number) {
return new Promise((resolve, reject)=>{
if(_.isEmpty(number)) {
reject(new Error('Number may not be empty'));
}
else {
addToBlockInList(id, number).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
}
});
}
export function editNumberFromIncomingList(id, index, number) {
return new Promise((resolve, reject)=>{
editBlockInList(id, index, number).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function removeNumberFromIncomingList(id, index) {
return new Promise((resolve, reject)=>{
removeFromBlockInList(id, index).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function enableOutgoingCallBlocking(id) {
return enableBlockOut(id);
}
export function disableOutgoingCallBlocking(id) {
return disableBlockOut(id);
}
export function getOutgoingCallBlocking(id) {
return new Promise((resolve, reject)=>{
getPreferences(id).then((result)=>{
resolve({
enabled: result.block_out_mode,
list: result.block_out_list
});
}).catch((err)=>{
reject(err);
});
});
}
export function addNumberToOutgoingList(id, number) {
return new Promise((resolve, reject)=>{
if(_.isEmpty(number)) {
reject(new Error('Number may not be empty'));
}
else {
addToBlockOutList(id, number).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
}
});
}
export function editNumberFromOutgoingList(id, index, number) {
return new Promise((resolve, reject)=>{
editBlockOutList(id, index, number).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function removeNumberFromOutgoingList(id, index) {
return new Promise((resolve, reject)=>{
removeFromBlockOutList(id, index).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function enablePrivacyCallBlocking(id) {
return enablePrivacy(id);
}
export function disablePrivacyCallBlocking(id) {
return disablePrivacy(id);
}
export function getPrivacyCallBlocking(id) {
return new Promise((resolve, reject)=>{
getPreferences(id).then((result)=>{
resolve(result.clir);
}).catch((err)=>{
reject(err);
});
});
}
export function removeNumberFromList(id, field, value) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return getPreferences(id);
}).then((result)=>{
var prefs = _.cloneDeep(result);
delete prefs._links;
prefs[field] = _.get(prefs, field, []).filter((number) => {
return number !== value;
});
return Vue.http.put('api/subscriberpreferences/' + id, prefs);
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function removeFromIncomingListByNumber(id, number) {
return new Promise((resolve, reject) => {
removeNumberFromList(id, 'block_in_list', number).then(() => {
resolve()
}).catch((err) => {
reject(err);
});
});
}
export function removeFromOutgoingListByNumber(id, number) {
return new Promise((resolve, reject) => {
removeNumberFromList(id, 'block_out_list', number).then(() => {
resolve()
}).catch((err) => {
reject(err);
});
});
}
export function toggleNumberInBothLists(options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getPreferences(options.id);
}).then((result) => {
let prefs = _.cloneDeep(result);
delete prefs._links;
prefs['block_in_list'] = _.get(prefs, 'block_in_list', []);
prefs['block_out_list'] = _.get(prefs, 'block_out_list', []);
if (options.block_in_list === 'add') {
prefs['block_in_list'] = [options.number].concat(prefs['block_in_list']);
}
else if (options.block_in_list === 'remove') {
prefs['block_in_list'] = prefs['block_in_list'].filter((number) => {
return number !== options.number;
});
}
if (options.block_out_list === 'add') {
prefs['block_out_list'] = [options.number].concat(prefs['block_out_list']);
}
else if (options.block_out_list === 'remove') {
prefs['block_out_list'] = prefs['block_out_list'].filter((number) => {
return number !== options.number;
});
}
return Vue.http.put('api/subscriberpreferences/' + options.id, prefs);
}).then(() => {
resolve();
}).catch((err) => {
reject(err);
});
});
enableBlockIn,
disableBlockIn,
getPreferences,
addToBlockInList,
editBlockInList,
removeFromBlockInList,
enableBlockOut,
disableBlockOut,
addToBlockOutList,
editBlockOutList,
removeFromBlockOutList,
enablePrivacy,
disablePrivacy
} from './subscriber'
export function enableIncomingCallBlocking (id) {
return enableBlockIn(id)
}
export function disableIncomingCallBlocking (id) {
return disableBlockIn(id)
}
export function getIncomingCallBlocking (id) {
return new Promise((resolve, reject) => {
getPreferences(id).then((result) => {
resolve({
enabled: result.block_in_mode,
list: result.block_in_list,
blockAnonymous: result.block_in_clir
})
}).catch((err) => {
reject(err)
})
})
}
export function addNumberToIncomingList (id, number) {
return new Promise((resolve, reject) => {
if (_.isEmpty(number)) {
reject(new Error('Number may not be empty'))
} else {
addToBlockInList(id, number).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
}
})
}
export function editNumberFromIncomingList (id, index, number) {
return new Promise((resolve, reject) => {
editBlockInList(id, index, number).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function removeNumberFromIncomingList (id, index) {
return new Promise((resolve, reject) => {
removeFromBlockInList(id, index).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function enableOutgoingCallBlocking (id) {
return enableBlockOut(id)
}
export function disableOutgoingCallBlocking (id) {
return disableBlockOut(id)
}
export function getOutgoingCallBlocking (id) {
return new Promise((resolve, reject) => {
getPreferences(id).then((result) => {
resolve({
enabled: result.block_out_mode,
list: result.block_out_list
})
}).catch((err) => {
reject(err)
})
})
}
export function addNumberToOutgoingList (id, number) {
return new Promise((resolve, reject) => {
if (_.isEmpty(number)) {
reject(new Error('Number may not be empty'))
} else {
addToBlockOutList(id, number).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
}
})
}
export function editNumberFromOutgoingList (id, index, number) {
return new Promise((resolve, reject) => {
editBlockOutList(id, index, number).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function removeNumberFromOutgoingList (id, index) {
return new Promise((resolve, reject) => {
removeFromBlockOutList(id, index).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function enablePrivacyCallBlocking (id) {
return enablePrivacy(id)
}
export function disablePrivacyCallBlocking (id) {
return disablePrivacy(id)
}
export function getPrivacyCallBlocking (id) {
return new Promise((resolve, reject) => {
getPreferences(id).then((result) => {
resolve(result.clir)
}).catch((err) => {
reject(err)
})
})
}
export function removeNumberFromList (id, field, value) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getPreferences(id)
}).then((result) => {
var prefs = _.cloneDeep(result)
delete prefs._links
prefs[field] = _.get(prefs, field, []).filter((number) => {
return number !== value
})
return Vue.http.put('api/subscriberpreferences/' + id, prefs)
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function removeFromIncomingListByNumber (id, number) {
return new Promise((resolve, reject) => {
removeNumberFromList(id, 'block_in_list', number).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function removeFromOutgoingListByNumber (id, number) {
return new Promise((resolve, reject) => {
removeNumberFromList(id, 'block_out_list', number).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function toggleNumberInBothLists (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getPreferences(options.id)
}).then((result) => {
const prefs = _.cloneDeep(result)
delete prefs._links
prefs.block_in_list = _.get(prefs, 'block_in_list', [])
prefs.block_out_list = _.get(prefs, 'block_out_list', [])
if (options.block_in_list === 'add') {
prefs.block_in_list = [options.number].concat(prefs.block_in_list)
} else if (options.block_in_list === 'remove') {
prefs.block_in_list = prefs.block_in_list.filter((number) => {
return number !== options.number
})
}
if (options.block_out_list === 'add') {
prefs.block_out_list = [options.number].concat(prefs.block_out_list)
} else if (options.block_out_list === 'remove') {
prefs.block_out_list = prefs.block_out_list.filter((number) => {
return number !== options.number
})
}
return Vue.http.put('api/subscriberpreferences/' + options.id, prefs)
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}

File diff suppressed because it is too large Load Diff

@ -1,228 +1,223 @@
import _ from 'lodash';
import Vue from 'vue';
import _ from 'lodash'
import Vue from 'vue'
import {
getJsonBody
} from './utils';
getJsonBody
} from './utils'
export const LIST_DEFAULT_PAGE = 1;
export const LIST_DEFAULT_ROWS = 25;
export const LIST_ALL_ROWS = 1000;
export const LIST_DEFAULT_PAGE = 1
export const LIST_DEFAULT_ROWS = 25
export const LIST_ALL_ROWS = 1000
const PATCH_HEADERS = {
'Content-Type': 'application/json-patch+json',
'Prefer': 'return=minimal'
};
'Content-Type': 'application/json-patch+json',
Prefer: 'return=minimal'
}
const GET_HEADERS = {
'Accept': 'application/json'
};
Accept: 'application/json'
}
export class ApiResponseError extends Error {
constructor (code, message) {
super()
this.code = code
this.status = code
this.message = message
}
}
export function getList (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge({
all: false,
params: {
page: LIST_DEFAULT_PAGE,
rows: LIST_DEFAULT_ROWS
},
headers: GET_HEADERS
}, options)
Promise.resolve().then(() => {
if (options.all === true) {
options.params.rows = LIST_ALL_ROWS
}
return Vue.http.get(options.path, {
params: options.params,
headers: options.headers
})
}).then((res) => {
const body = getJsonBody(res.body)
if (options.all === true && body.total_count > LIST_ALL_ROWS) {
return Vue.http.get(options.path, {
params: _.merge(options.params, {
rows: body.total_count
}),
headers: options.headers
})
} else {
return Promise.resolve(res)
}
}).then((res) => {
const body = getJsonBody(res.body)
const totalCount = _.get(body, 'total_count', 0)
let lastPage = Math.ceil(totalCount / options.params.rows)
if (options.all === true) {
lastPage = 1
}
if (lastPage === 0) {
lastPage = null
}
const items = _.get(body, options.root, [])
for (let i = 0; i < items.length; i++) {
items[i] = normalizeEntity(items[i])
}
resolve({
items: items,
lastPage: lastPage
})
}).catch((err) => {
reject(err)
})
})
}
export function get (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge({
headers: GET_HEADERS
}, options)
const requestOptions = {
headers: options.headers,
params: options.params
}
if (options.blob === true) {
requestOptions.responseType = 'blob'
}
return Vue.http.get(options.path, requestOptions).then((result) => {
let body = null
if (options.blob === true) {
body = URL.createObjectURL(result.body)
} else {
body = normalizeEntity(getJsonBody(result.body))
}
resolve(body)
}).catch((err) => {
const code = _.get(err, 'body.code', null)
const message = _.get(err, 'body.message', null)
if (code !== null && message !== null) {
reject(new ApiResponseError(err.body.code, err.body.message))
} else {
reject(err)
}
})
})
}
export function patch (operation, options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge({
headers: PATCH_HEADERS
}, options)
const body = {
op: operation,
path: '/' + options.fieldPath
}
if (options.value !== undefined) {
body.value = options.value
}
Vue.http.patch(options.path, [body], {
headers: options.headers
}).then((result) => {
resolve(result)
}).catch((err) => {
const code = _.get(err, 'body.code', null)
const message = _.get(err, 'body.message', null)
if (code !== null && message !== null) {
reject(new ApiResponseError(err.body.code, err.body.message))
} else {
reject(err)
}
})
})
}
export function patchReplace (options) {
return patch('replace', options)
}
export function patchAdd (options) {
return patch('add', options)
}
export function patchRemove (options) {
return patch('remove', options)
}
export function patchFull (operation, options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
headers: {
Prefer: 'return=representation'
}
})
patch(operation, options).then((result) => {
resolve(getJsonBody(result.body))
}).catch((err) => {
reject(err)
})
})
}
export function patchReplaceFull (options) {
return patchFull('replace', options)
}
export function patchAddFull (options) {
return patchFull('add', options)
}
export function patchRemoveFull (options) {
return patchFull('remove', options)
}
export function getFieldList (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge({
headers: GET_HEADERS
}, options)
Vue.http.get(options.path, {
headers: options.headers
}).then((result) => {
const fieldList = getJsonBody(result.body)[options.field]
resolve(fieldList)
}).catch((err) => {
reject(err)
})
})
}
export function normalizeEntity (entity) {
if (entity && entity._links) {
delete entity._links
}
return entity
}
constructor(code, message) {
super();
this.code = code;
this.status = code;
this.message = message;
}
}
export function getList(options) {
return new Promise((resolve, reject) => {
options = options || {};
options = _.merge({
all: false,
params: {
page: LIST_DEFAULT_PAGE,
rows: LIST_DEFAULT_ROWS
},
headers: GET_HEADERS
}, options);
Promise.resolve().then(() => {
if(options.all === true) {
options.params.rows = LIST_ALL_ROWS;
}
return Vue.http.get(options.path, {
params: options.params,
headers: options.headers
});
}).then((res) => {
let body = getJsonBody(res.body);
if(options.all === true && body.total_count > LIST_ALL_ROWS) {
return Vue.http.get(options.path, {
params: _.merge(options.params, {
rows: body.total_count
}),
headers: options.headers
});
}
else {
return Promise.resolve(res);
}
}).then((res) => {
let body = getJsonBody(res.body);
let totalCount = _.get(body, 'total_count', 0);
let lastPage = Math.ceil( totalCount / options.params.rows );
if(options.all === true) {
lastPage = 1;
}
if(lastPage === 0) {
lastPage = null;
}
let items = _.get(body, options.root, []);
for(let i = 0; i < items.length; i++) {
items[i] = normalizeEntity(items[i]);
}
resolve({
items: items,
lastPage: lastPage
});
}).catch((err) => {
reject(err);
});
});
}
export function get(options) {
return new Promise((resolve, reject) => {
options = options || {};
options = _.merge({
headers: GET_HEADERS
}, options);
let requestOptions ={
headers: options.headers,
params: options.params
};
if(options.blob === true) {
requestOptions.responseType = 'blob';
}
return Vue.http.get(options.path, requestOptions).then((result) => {
let body = null;
if(options.blob === true) {
body = URL.createObjectURL(result.body);
}
else {
body = normalizeEntity(getJsonBody(result.body));
}
resolve(body);
}).catch((err) => {
let code = _.get(err, 'body.code', null);
let message = _.get(err, 'body.message', null);
if(code !== null && message !== null) {
reject(new ApiResponseError(err.body.code, err.body.message));
}
else {
reject(err);
}
});
});
}
export function patch(operation, options) {
return new Promise((resolve, reject) => {
options = options || {};
options = _.merge({
headers: PATCH_HEADERS
}, options);
let body = {
op: operation,
path: '/'+ options.fieldPath
};
if(options.value !== void(0)) {
body.value = options.value;
}
Vue.http.patch(options.path, [body], {
headers: options.headers
}).then((result) => {
resolve(result);
}).catch((err) => {
let code = _.get(err, 'body.code', null);
let message = _.get(err, 'body.message', null);
if(code !== null && message !== null) {
reject(new ApiResponseError(err.body.code, err.body.message));
}
else {
reject(err);
}
});
});
}
export function patchReplace(options) {
return patch('replace', options);
}
export function patchAdd(options) {
return patch('add', options);
}
export function patchRemove(options) {
return patch('remove', options);
}
export function patchFull(operation, options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
headers: {
Prefer: 'return=representation'
}
});
patch(operation, options).then((result)=>{
resolve(getJsonBody(result.body));
}).catch((err)=>{
reject(err);
});
});
}
export function patchReplaceFull(options) {
return patchFull('replace', options);
}
export function patchAddFull(options) {
return patchFull('add', options);
}
export function patchRemoveFull(options) {
return patchFull('remove', options);
}
export function getFieldList(options) {
return new Promise((resolve, reject) => {
options = options || {};
options = _.merge({
headers: GET_HEADERS
}, options);
Vue.http.get(options.path, {
headers: options.headers
}).then((result) => {
let fieldList = getJsonBody(result.body)[options.field];
resolve(fieldList);
}).catch((err) => {
reject(err);
});
});
}
export function normalizeEntity(entity) {
if(entity && entity._links) {
delete entity._links;
}
return entity;
}
export function getAsBlob(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
blob: true
});
get(options).then((body)=>{
resolve(body);
}).catch((err)=>{
reject(err);
});
});
export function getAsBlob (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
blob: true
})
get(options).then((body) => {
resolve(body)
}).catch((err) => {
reject(err)
})
})
}

@ -1,21 +1,21 @@
import _ from 'lodash';
import Vue from 'vue';
import _ from 'lodash'
import Vue from 'vue'
export function createFax(options) {
return new Promise((resolve, reject) => {
var formData = new FormData();
var fields = _.clone(options);
delete fields.file;
var json = JSON.stringify(fields);
formData.append('json', json);
if (options.file) {
formData.append('faxfile', options.file);
}
Vue.http.post('api/faxes/', formData).then(() => {
resolve();
}).catch((err)=>{
reject(err);
});
});
export function createFax (options) {
return new Promise((resolve, reject) => {
var formData = new FormData()
var fields = _.clone(options)
delete fields.file
var json = JSON.stringify(fields)
formData.append('json', json)
if (options.file) {
formData.append('faxfile', options.file)
}
Vue.http.post('api/faxes/', formData).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}

@ -1,114 +1,106 @@
import _ from 'lodash'
import {
saveAs
saveAs
} from 'file-saver'
import Vue from 'vue'
import {
getIncomingCallBlocking,
getOutgoingCallBlocking
getIncomingCallBlocking,
getOutgoingCallBlocking
} from './call-blocking'
import {
getList
getList
} from './common'
export function getConversations(options) {
return new Promise((resolve, reject) => {
let type = _.get(options, 'type', null);
let from = _.get(options, 'from', null);
let to = _.get(options, 'to', null);
let params ={
subscriber_id: _.get(options, 'subscriberId'),
order_by: _.get(options, 'order_by', 'timestamp'),
order_by_direction: 'desc',
no_count: true,
tz: 'UTC',
page: _.get(options, 'page', 1),
rows: _.get(options, 'rows', 25)
};
if (type !== null) {
params.type = type;
}
if (from !== null){
params.from = from;
}
if (to !== null){
params.to = to;
}
getList({
path: 'api/conversations/',
root: '_embedded.ngcp:conversations',
params: params,
all: false
}).then((list)=>{
resolve(list);
}).catch((err)=>{
reject(err);
});
});
export function getConversations (options) {
return new Promise((resolve, reject) => {
const type = _.get(options, 'type', null)
const params = {
subscriber_id: _.get(options, 'subscriberId'),
order_by: _.get(options, 'order_by', 'timestamp'),
order_by_direction: 'desc',
no_count: true,
tz: 'UTC',
page: _.get(options, 'page', 1),
rows: _.get(options, 'rows', 25)
}
if (type !== null) {
params.type = type
}
getList({
path: 'api/conversations/',
root: '_embedded.ngcp:conversations',
params: params,
all: false
}).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function downloadVoiceMail(id) {
return new Promise((resolve, reject) => {
Vue.http.get('api/voicemailrecordings/' + id, { responseType: 'blob' })
.then((res) => {
return res.blob();
}).then(voicemail => {
saveAs((voicemail), "voicemail-" + id + '.wav');
resolve();
}).catch((err)=>{
reject(err);
});
});
export function downloadVoiceMail (id) {
return new Promise((resolve, reject) => {
Vue.http.get('api/voicemailrecordings/' + id, { responseType: 'blob' })
.then((res) => {
return res.blob()
}).then(voicemail => {
saveAs((voicemail), 'voicemail-' + id + '.wav')
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function downloadFax(id) {
return new Promise((resolve, reject) => {
Vue.http.get('api/faxrecordings/' + id, { responseType: 'blob' })
.then((res) => {
return res.blob();
}).then(fax => {
saveAs((fax), "fax-" + id + '.tif');
resolve();
}).catch((err)=>{
reject(err);
});
});
export function downloadFax (id) {
return new Promise((resolve, reject) => {
Vue.http.get('api/faxrecordings/' + id, { responseType: 'blob' })
.then((res) => {
return res.blob()
}).then(fax => {
saveAs((fax), 'fax-' + id + '.tif')
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function playVoiceMail(options) {
return new Promise((resolve, reject) => {
let params = { format: options.format };
Vue.http.get(`api/voicemailrecordings/${options.id}`, { params: params, responseType: 'blob' })
.then((res) => {
resolve(URL.createObjectURL(res.body));
}).catch((err)=>{
reject(err);
});
});
export function playVoiceMail (options) {
return new Promise((resolve, reject) => {
const params = { format: options.format }
Vue.http.get(`api/voicemailrecordings/${options.id}`, { params: params, responseType: 'blob' })
.then((res) => {
resolve(URL.createObjectURL(res.body))
}).catch((err) => {
reject(err)
})
})
}
export function getIncomingBlocked(id) {
return new Promise((resolve, reject) => {
getIncomingCallBlocking(id).then((list) => {
resolve(list)
}).catch((err) => {
reject(err);
});
});
export function getIncomingBlocked (id) {
return new Promise((resolve, reject) => {
getIncomingCallBlocking(id).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function getOutgoingBlocked(id) {
return new Promise((resolve, reject) => {
getOutgoingCallBlocking(id).then((list) => {
resolve(list)
}).catch((err) => {
reject(err);
});
});
export function getOutgoingBlocked (id) {
return new Promise((resolve, reject) => {
getOutgoingCallBlocking(id).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export async function deleteVoicemail(id) {
const res = await Vue.http.delete('api/voicemails/' + id)
return res.status >= 200
export async function deleteVoicemail (id) {
const res = await Vue.http.delete('api/voicemails/' + id)
return res.status >= 200
}

@ -1,53 +1,53 @@
import _ from 'lodash';
import _ from 'lodash'
import {
addPreference,
addPreferenceFull,
getAllPreferences,
getSubscriber
} from "./subscriber";
addPreference,
addPreferenceFull,
getAllPreferences,
getSubscriber
} from './subscriber'
export function getCallQueues() {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return getAllPreferences({
all: true
});
}).then((preferencesList)=>{
resolve({
items: _.get(preferencesList, 'items', []).filter((preferences)=>{
return _.get(preferences, 'cloud_pbx_callqueue', false)
})
});
}).catch((err)=>{
reject(err);
});
});
export function getCallQueues () {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getAllPreferences({
all: true
})
}).then((preferencesList) => {
resolve({
items: _.get(preferencesList, 'items', []).filter((preferences) => {
return _.get(preferences, 'cloud_pbx_callqueue', false)
})
})
}).catch((err) => {
reject(err)
})
})
}
export function getCallQueueList() {
return new Promise((resolve, reject)=>{
let callQueues = [];
Promise.resolve().then(()=>{
return getCallQueues();
}).then(($callQueues)=>{
callQueues = $callQueues;
let subscriberPromises = [];
callQueues.items.forEach((callQueue)=>{
subscriberPromises.push(getSubscriber(callQueue.id));
});
return Promise.all(subscriberPromises);
}).then((subscribers)=>{
resolve({
subscribers: {
items: subscribers
},
callQueues: callQueues
});
}).catch((err)=>{
reject(err);
});
});
export function getCallQueueList () {
return new Promise((resolve, reject) => {
let callQueues = []
Promise.resolve().then(() => {
return getCallQueues()
}).then(($callQueues) => {
callQueues = $callQueues
const subscriberPromises = []
callQueues.items.forEach((callQueue) => {
subscriberPromises.push(getSubscriber(callQueue.id))
})
return Promise.all(subscriberPromises)
}).then((subscribers) => {
resolve({
subscribers: {
items: subscribers
},
callQueues: callQueues
})
}).catch((err) => {
reject(err)
})
})
}
/**
@ -56,51 +56,50 @@ export function getCallQueueList() {
* @param options.queue_wrap_up_time
* @return {Promise}
*/
export function createCallQueue(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return Promise.all([
addPreference(options.subscriber_id, 'cloud_pbx_callqueue', true),
addPreference(options.subscriber_id, 'max_queue_length', options.max_queue_length),
addPreference(options.subscriber_id, 'queue_wrap_up_time', options.queue_wrap_up_time)
]);
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
export function createCallQueue (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return Promise.all([
addPreference(options.subscriber_id, 'cloud_pbx_callqueue', true),
addPreference(options.subscriber_id, 'max_queue_length', options.max_queue_length),
addPreference(options.subscriber_id, 'queue_wrap_up_time', options.queue_wrap_up_time)
])
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function removeCallQueue(subscriber_id) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return addPreference(subscriber_id, 'cloud_pbx_callqueue', false);
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
export function removeCallQueue (subscriberId) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return addPreference(subscriberId, 'cloud_pbx_callqueue', false)
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function setCallQueueMaxLength(options) {
return new Promise((resolve, reject)=>{
addPreferenceFull(options.callQueueId, 'max_queue_length', options.maxQueueLength).then((preferences)=>{
resolve(preferences);
}).catch((err)=>{
reject(err);
});
});
export function setCallQueueMaxLength (options) {
return new Promise((resolve, reject) => {
addPreferenceFull(options.callQueueId, 'max_queue_length', options.maxQueueLength).then((preferences) => {
resolve(preferences)
}).catch((err) => {
reject(err)
})
})
}
export function setCallQueueWrapUpTime(options) {
return new Promise((resolve, reject)=>{
addPreferenceFull(options.callQueueId, 'queue_wrap_up_time', options.queueWrapUpTime).then((preferences)=>{
resolve(preferences);
}).catch((err)=>{
reject(err);
});
});
export function setCallQueueWrapUpTime (options) {
return new Promise((resolve, reject) => {
addPreferenceFull(options.callQueueId, 'queue_wrap_up_time', options.queueWrapUpTime).then((preferences) => {
resolve(preferences)
}).catch((err) => {
reject(err)
})
})
}

@ -1,235 +1,233 @@
import _ from 'lodash';
import Vue from 'vue';
import _ from 'lodash'
import Vue from 'vue'
import {
getSubscribers
} from './subscriber';
import uuid from 'uuid';
getSubscribers
} from './subscriber'
import uuid from 'uuid'
import {
getList,
get,
patchAdd,
patchRemove
getList,
get,
patchAdd,
patchRemove
} from './common'
export const createId = uuid.v4;
export const PBX_CONFIG_ORDER_BY = 'create_timestamp';
export const PBX_CONFIG_ORDER_DIRECTION = 'desc';
export function getPilot(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
params: {
is_pbx_group: 0,
is_pbx_pilot: 1,
rows: 1
}
});
getSubscribers(options).then((subscribers)=>{
if (subscribers.items.length === 1) {
resolve(subscribers.items[0]);
}
else {
resolve(null);
}
}).catch((err)=>{
reject(err);
});
});
export const createId = uuid.v4
export const PBX_CONFIG_ORDER_BY = 'create_timestamp'
export const PBX_CONFIG_ORDER_DIRECTION = 'desc'
export function getPilot (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
params: {
is_pbx_group: 0,
is_pbx_pilot: 1,
rows: 1
}
})
getSubscribers(options).then((subscribers) => {
if (subscribers.items.length === 1) {
resolve(subscribers.items[0])
} else {
resolve(null)
}
}).catch((err) => {
reject(err)
})
})
}
export function getProfiles(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
path: 'api/pbxdeviceprofiles/',
root: '_embedded.ngcp:pbxdeviceprofiles'
});
getList(options).then((list)=>{
resolve(list);
}).catch((err)=>{
reject(err);
});
});
export function getProfiles (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
path: 'api/pbxdeviceprofiles/',
root: '_embedded.ngcp:pbxdeviceprofiles'
})
getList(options).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function getAllProfiles() {
return getProfiles({
all: true
});
export function getAllProfiles () {
return getProfiles({
all: true
})
}
export function getModel(id) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return get({
path: 'api/pbxdevicemodels/' + id
});
}).then((model)=> {
resolve(model);
}).catch((err)=>{
reject(err);
});
});
export function getModel (id) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return get({
path: 'api/pbxdevicemodels/' + id
})
}).then((model) => {
resolve(model)
}).catch((err) => {
reject(err)
})
})
}
export function getModelFrontImage(id) {
return new Promise((resolve)=>{
Vue.http.get('api/pbxdevicemodelimages/' + id, {
responseType: 'blob',
params: {
type: 'front'
}
}).then((res)=>{
resolve({
id: id,
url: URL.createObjectURL(res.body),
blob: res.body
});
}).catch(()=>{
resolve({
id: id,
url: null,
blob: null
});
});
});
export function getModelFrontImage (id) {
return new Promise((resolve) => {
Vue.http.get('api/pbxdevicemodelimages/' + id, {
responseType: 'blob',
params: {
type: 'front'
}
}).then((res) => {
resolve({
id: id,
url: URL.createObjectURL(res.body),
blob: res.body
})
}).catch(() => {
resolve({
id: id,
url: null,
blob: null
})
})
})
}
export function getAllSoundSets(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
path: 'api/soundsets/',
root: '_embedded.ngcp:soundsets',
all: true
});
getList(options).then((list)=>{
resolve(list);
}).catch((err)=>{
reject(err);
});
});
export function getAllSoundSets (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
path: 'api/soundsets/',
root: '_embedded.ngcp:soundsets',
all: true
})
getList(options).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function removeSoundSet(id) {
return Vue.http.delete('api/soundsets/' + id);
export function removeSoundSet (id) {
return Vue.http.delete('api/soundsets/' + id)
}
export function getSoundSet(id) {
return new Promise((resolve, reject)=>{
get({
path: 'api/soundsets/' + id
}).then((soundSet)=>{
resolve(soundSet);
}).catch((err)=>{
reject(err);
});
});
export function getSoundSet (id) {
return new Promise((resolve, reject) => {
get({
path: 'api/soundsets/' + id
}).then((soundSet) => {
resolve(soundSet)
}).catch((err) => {
reject(err)
})
})
}
export function editSoundSetFields(id, fields) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return getSoundSet(id);
}).then((result)=>{
let prefs = Object.assign(result, fields);
delete fields._links;
return Vue.http.put('api/soundsets/' + id, prefs);
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
export function editSoundSetFields (id, fields) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getSoundSet(id)
}).then((result) => {
const prefs = Object.assign(result, fields)
delete fields._links
return Vue.http.put('api/soundsets/' + id, prefs)
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function createSoundSet(soundSet) {
return new Promise((resolve, reject)=>{
Vue.http.post('api/soundsets/', soundSet).then(() => {
resolve();
}).catch((err)=>{
reject(err);
});
});
export function createSoundSet (soundSet) {
return new Promise((resolve, reject) => {
Vue.http.post('api/soundsets/', soundSet).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function setSoundSetName(id, value) {
return editSoundSetFields(id, { name: value });
export function setSoundSetName (id, value) {
return editSoundSetFields(id, { name: value })
}
export function setSoundSetDescription(id, value) {
return editSoundSetFields(id, { description: value });
export function setSoundSetDescription (id, value) {
return editSoundSetFields(id, { description: value })
}
export function playSoundFile(options) {
return new Promise((resolve, reject)=>{
let params = { format: options.format };
Vue.http.get(`api/soundfilerecordings/${options.id}`, { params: params, responseType: 'blob' })
.then((res) => {
resolve(URL.createObjectURL(res.body));
}).catch((err) => {
reject(err);
});
});
export function playSoundFile (options) {
return new Promise((resolve, reject) => {
const params = { format: options.format }
Vue.http.get(`api/soundfilerecordings/${options.id}`, { params: params, responseType: 'blob' })
.then((res) => {
resolve(URL.createObjectURL(res.body))
}).catch((err) => {
reject(err)
})
})
}
export function uploadSoundFile(options, onProgress) {
return new Promise((resolve, reject) => {
let formData = new FormData();
let loopplay = options.item.loopplay ? 1 : 2;
let fields = {
loopplay: loopplay,
filename: options.file.name,
set_id: options.item.set_id,
handle: options.item.handle,
};
let json = JSON.stringify(fields);
let requestKey = `previous-${options.item.handle}-request`;
formData.append('json', json);
if (options.file) {
formData.append('soundfile', options.file);
}
Vue.http.post('api/soundfiles/', formData, {
before(request) {
Vue[requestKey] = request;
},
progress(e) {
if (e.lengthComputable) {
onProgress(Math.ceil((e.loaded / e.total ) * 100));
}
}
}).then(() => {
resolve();
}).catch((err) => {
reject(err);
});
});
export function uploadSoundFile (options, onProgress) {
return new Promise((resolve, reject) => {
const formData = new FormData()
const loopplay = options.item.loopplay ? 1 : 2
const fields = {
loopplay: loopplay,
filename: options.file.name,
set_id: options.item.set_id,
handle: options.item.handle
}
const json = JSON.stringify(fields)
const requestKey = `previous-${options.item.handle}-request`
formData.append('json', json)
if (options.file) {
formData.append('soundfile', options.file)
}
Vue.http.post('api/soundfiles/', formData, {
before (request) {
Vue[requestKey] = request
},
progress (e) {
if (e.lengthComputable) {
onProgress(Math.ceil((e.loaded / e.total) * 100))
}
}
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function setSubscriberSoundSet(id, soundSet) {
return new Promise((resolve, reject)=>{
let promise;
let path = 'api/subscriberpreferences/' + id;
let fieldPath = 'contract_sound_set';
if(soundSet === null || soundSet === void(0)) {
promise = patchRemove({
path: path,
fieldPath: 'contract_sound_set'
});
}
else {
promise = patchAdd({
path: path,
fieldPath: fieldPath,
value: soundSet
});
}
promise.then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
export function setSubscriberSoundSet (id, soundSet) {
return new Promise((resolve, reject) => {
let promise
const path = 'api/subscriberpreferences/' + id
const fieldPath = 'contract_sound_set'
if (soundSet === null || soundSet === undefined) {
promise = patchRemove({
path: path,
fieldPath: 'contract_sound_set'
})
} else {
promise = patchAdd({
path: path,
fieldPath: fieldPath,
value: soundSet
})
}
promise.then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}

@ -1,183 +1,179 @@
import {
getModel,
getModelFrontImage,
PBX_CONFIG_ORDER_BY,
PBX_CONFIG_ORDER_DIRECTION
} from "./pbx-config";
import _ from "lodash";
getModel,
getModelFrontImage,
PBX_CONFIG_ORDER_BY,
PBX_CONFIG_ORDER_DIRECTION
} from './pbx-config'
import _ from 'lodash'
import {
getList,
patchReplace,
patchReplaceFull
} from "./common";
import Vue from "vue";
getList,
patchReplace,
patchReplaceFull
} from './common'
import Vue from 'vue'
export function getDevices(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
path: 'api/pbxdevices/',
root: '_embedded.ngcp:pbxdevices'
});
getList(options).then((list)=>{
resolve(list);
}).catch((err)=>{
reject(err);
});
});
export function getDevices (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
path: 'api/pbxdevices/',
root: '_embedded.ngcp:pbxdevices'
})
getList(options).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function getDeviceList(options) {
return new Promise((resolve, reject)=>{
let params = {
page: options.page,
profile_id: options.profile_id,
identifier: options.identifier,
station_name: options.station_name,
order_by: PBX_CONFIG_ORDER_BY,
order_by_direction: PBX_CONFIG_ORDER_DIRECTION
};
if (params.profile_id === null || params.profile_id === undefined || params.profile_id === "") {
delete params['profile_id'];
}
if (params.identifier === null || params.identifier === undefined || params.identifier === "") {
delete params['identifier'];
}
else {
params.identifier = "*" + params.identifier + "*"
}
if (params.station_name === null || params.station_name === undefined || params.station_name === "") {
delete params['station_name'];
}
else {
params.station_name = "*" + params.station_name + "*"
}
getDevices({
params: params
}).then((devices)=>{
resolve(devices);
}).catch((err)=>{
reject(err);
});
});
export function getDeviceList (options) {
return new Promise((resolve, reject) => {
const params = {
page: options.page,
profile_id: options.profile_id,
identifier: options.identifier,
station_name: options.station_name,
order_by: PBX_CONFIG_ORDER_BY,
order_by_direction: PBX_CONFIG_ORDER_DIRECTION
}
if (params.profile_id === null || params.profile_id === undefined || params.profile_id === '') {
delete params.profile_id
}
if (params.identifier === null || params.identifier === undefined || params.identifier === '') {
delete params.identifier
} else {
params.identifier = '*' + params.identifier + '*'
}
if (params.station_name === null || params.station_name === undefined || params.station_name === '') {
delete params.station_name
} else {
params.station_name = '*' + params.station_name + '*'
}
getDevices({
params: params
}).then((devices) => {
resolve(devices)
}).catch((err) => {
reject(err)
})
})
}
export function createDevice(deviceData) {
return new Promise((resolve, reject)=>{
Vue.http.post('api/pbxdevices/', {
station_name: deviceData.stationName,
identifier: deviceData.identifier,
profile_id: deviceData.profile
}).then((res)=>{
resolve(res);
}).catch((err)=>{
if (err.status >= 400) {
reject(new Error(err.body.message));
}
else {
reject(err);
}
});
});
export function createDevice (deviceData) {
return new Promise((resolve, reject) => {
Vue.http.post('api/pbxdevices/', {
station_name: deviceData.stationName,
identifier: deviceData.identifier,
profile_id: deviceData.profile
}).then((res) => {
resolve(res)
}).catch((err) => {
if (err.status >= 400) {
reject(new Error(err.body.message))
} else {
reject(err)
}
})
})
}
export function removeDevice(id) {
return new Promise((resolve, reject)=>{
Vue.http.delete('api/pbxdevices/' + id).then(()=>{
resolve();
}).catch((err)=>{
if (err.status >= 400) {
reject(new Error(err.body.message));
}
else {
reject(err);
}
});
});
export function removeDevice (id) {
return new Promise((resolve, reject) => {
Vue.http.delete('api/pbxdevices/' + id).then(() => {
resolve()
}).catch((err) => {
if (err.status >= 400) {
reject(new Error(err.body.message))
} else {
reject(err)
}
})
})
}
export function setDeviceStationName(deviceId, stationName) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return patchReplaceFull({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'station_name',
value: stationName
});
}).then((device)=>{
resolve(device);
}).catch((err)=>{
reject(err);
});
});
export function setDeviceStationName (deviceId, stationName) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return patchReplaceFull({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'station_name',
value: stationName
})
}).then((device) => {
resolve(device)
}).catch((err) => {
reject(err)
})
})
}
export function setDeviceIdentifier(deviceId, identifier) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return patchReplaceFull({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'identifier',
value: identifier
});
}).then((device)=>{
resolve(device);
}).catch((err)=>{
reject(err);
});
});
export function setDeviceIdentifier (deviceId, identifier) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return patchReplaceFull({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'identifier',
value: identifier
})
}).then((device) => {
resolve(device)
}).catch((err) => {
reject(err)
})
})
}
export function setDeviceProfile(deviceId, profileId) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return patchReplace({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'lines',
value: []
});
}).then(()=>{
return patchReplaceFull({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'profile_id',
value: profileId
});
}).then((device)=>{
resolve(device);
}).catch((err)=>{
reject(err);
});
});
export function setDeviceProfile (deviceId, profileId) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return patchReplace({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'lines',
value: []
})
}).then(() => {
return patchReplaceFull({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'profile_id',
value: profileId
})
}).then((device) => {
resolve(device)
}).catch((err) => {
reject(err)
})
})
}
export function setDeviceKeys(deviceId, keys) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return patchReplaceFull({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'lines',
value: keys
});
}).then((device)=>{
resolve(device);
}).catch((err)=>{
reject(err);
});
});
export function setDeviceKeys (deviceId, keys) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return patchReplaceFull({
path: 'api/pbxdevices/' + deviceId,
fieldPath: 'lines',
value: keys
})
}).then((device) => {
resolve(device)
}).catch((err) => {
reject(err)
})
})
}
export function loadDeviceModel(modelId) {
return new Promise((resolve, reject)=>{
Promise.all([
getModel(modelId),
getModelFrontImage(modelId)
]).then((res)=>{
resolve({
model: res[0],
modelImage: res[1]
});
}).catch((err)=>{
reject(err);
});
});
export function loadDeviceModel (modelId) {
return new Promise((resolve, reject) => {
Promise.all([
getModel(modelId),
getModelFrontImage(modelId)
]).then((res) => {
resolve({
model: res[0],
modelImage: res[1]
})
}).catch((err) => {
reject(err)
})
})
}

@ -1,281 +1,279 @@
import _ from "lodash";
import _ from 'lodash'
import {
createSubscriber,
deleteSubscriber,
getFullSubscribers,
getSubscriberAndPreferences,
getSubscribers,
setDisplayName,
setPbxExtension, setPbxGroupMemberIds,
setPbxHuntPolicy,
setPbxHuntTimeout, setSubscriberNumbers
} from "./subscriber";
createSubscriber,
deleteSubscriber,
getFullSubscribers,
getSubscriberAndPreferences,
getSubscribers,
setDisplayName,
setPbxExtension, setPbxGroupMemberIds,
setPbxHuntPolicy,
setPbxHuntTimeout, setSubscriberNumbers
} from './subscriber'
import {
getAllSoundSets,
getPilot,
getSoundSet,
createId,
PBX_CONFIG_ORDER_BY,
PBX_CONFIG_ORDER_DIRECTION,
setSubscriberSoundSet
} from "./pbx-config";
getAllSoundSets,
getPilot,
getSoundSet,
createId,
PBX_CONFIG_ORDER_BY,
PBX_CONFIG_ORDER_DIRECTION,
setSubscriberSoundSet
} from './pbx-config'
import {
assignNumbers,
getNumbers
} from "./user";
assignNumbers,
getNumbers
} from './user'
import {
getSeatsOnly
} from "./pbx-seats";
getSeatsOnly
} from './pbx-seats'
export function getGroups(options) {
return new Promise((resolve, reject)=>{
let result = {
subscribers: {
items: []
},
preferences: {
items: []
},
soundSets: {
items: []
}
};
options = options || {};
options = _.merge(options, {
params: {
is_pbx_group: 1,
is_pbx_pilot: 0
}
});
Promise.resolve().then(()=>{
return Promise.all([
getFullSubscribers(options),
getAllSoundSets()
]);
}).then(($result)=> {
result.groups = $result[0].subscribers;
result.preferences.items = $result[0].preferences;
result.soundSets = $result[1];
resolve(result);
}).catch((err)=>{
reject(err);
});
});
export function getGroups (options) {
return new Promise((resolve, reject) => {
const result = {
subscribers: {
items: []
},
preferences: {
items: []
},
soundSets: {
items: []
}
}
options = options || {}
options = _.merge(options, {
params: {
is_pbx_group: 1,
is_pbx_pilot: 0
}
})
Promise.resolve().then(() => {
return Promise.all([
getFullSubscribers(options),
getAllSoundSets()
])
}).then(($result) => {
result.groups = $result[0].subscribers
result.preferences.items = $result[0].preferences
result.soundSets = $result[1]
resolve(result)
}).catch((err) => {
reject(err)
})
})
}
export function getGroupsOnly(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
params: {
is_pbx_group: 1,
is_pbx_pilot: 0
}
});
Promise.resolve().then(()=>{
return getSubscribers(options);
}).then((result)=> {
resolve(result);
}).catch((err)=>{
reject(err);
});
});
export function getGroupsOnly (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
params: {
is_pbx_group: 1,
is_pbx_pilot: 0
}
})
Promise.resolve().then(() => {
return getSubscribers(options)
}).then((result) => {
resolve(result)
}).catch((err) => {
reject(err)
})
})
}
export function getGroupList(options) {
return new Promise((resolve, reject)=>{
let page = _.get(options, 'page', 1);
Promise.all([
getGroups({
params: {
page: page,
order_by: PBX_CONFIG_ORDER_BY,
order_by_direction: PBX_CONFIG_ORDER_DIRECTION
}
}),
getSeatsOnly({
all: true
}),
getPilot(),
getNumbers()
]).then((result)=>{
resolve({
groups: result[0].groups,
preferences: result[0].preferences,
soundSets: result[0].soundSets,
seats: result[1],
pilot: result[2],
numbers: result[3]
});
}).catch((err)=>{
reject(err);
});
});
export function getGroupList (options) {
return new Promise((resolve, reject) => {
const page = _.get(options, 'page', 1)
Promise.all([
getGroups({
params: {
page: page,
order_by: PBX_CONFIG_ORDER_BY,
order_by_direction: PBX_CONFIG_ORDER_DIRECTION
}
}),
getSeatsOnly({
all: true
}),
getPilot(),
getNumbers()
]).then((result) => {
resolve({
groups: result[0].groups,
preferences: result[0].preferences,
soundSets: result[0].soundSets,
seats: result[1],
pilot: result[2],
numbers: result[3]
})
}).catch((err) => {
reject(err)
})
})
}
export function createGroup(group) {
return new Promise((resolve, reject)=>{
let subscriberId;
Promise.resolve().then(()=>{
return createSubscriber({
username: _.kebabCase(group.name),
password: createId(),
is_pbx_group: true,
display_name: group.name,
pbx_extension: group.extension,
pbx_hunt_policy: group.huntPolicy,
pbx_hunt_timeout: group.huntTimeout,
pbx_groupmember_ids: group.seats
});
}).then(($subscriberId)=>{
subscriberId = $subscriberId;
if(group.soundSet !== null && group.soundSet !== void(0)) {
return getSoundSet(group.soundSet);
}
else {
return Promise.resolve(null);
}
}).then((soundSet)=>{
let promises = [
assignNumbers(group.aliasNumbers, subscriberId)
];
if(soundSet !== null) {
promises.push(setSubscriberSoundSet(subscriberId, soundSet.name));
}
return Promise.all(promises);
}).then(()=>{
resolve(subscriberId);
}).catch((err)=>{
reject(err);
});
});
export function createGroup (group) {
return new Promise((resolve, reject) => {
let subscriberId
Promise.resolve().then(() => {
return createSubscriber({
username: _.kebabCase(group.name),
password: createId(),
is_pbx_group: true,
display_name: group.name,
pbx_extension: group.extension,
pbx_hunt_policy: group.huntPolicy,
pbx_hunt_timeout: group.huntTimeout,
pbx_groupmember_ids: group.seats
})
}).then(($subscriberId) => {
subscriberId = $subscriberId
if (group.soundSet !== null && group.soundSet !== undefined) {
return getSoundSet(group.soundSet)
} else {
return Promise.resolve(null)
}
}).then((soundSet) => {
const promises = [
assignNumbers(group.aliasNumbers, subscriberId)
]
if (soundSet !== null) {
promises.push(setSubscriberSoundSet(subscriberId, soundSet.name))
}
return Promise.all(promises)
}).then(() => {
resolve(subscriberId)
}).catch((err) => {
reject(err)
})
})
}
export function removeGroup(id) {
return deleteSubscriber(id);
export function removeGroup (id) {
return deleteSubscriber(id)
}
export function setGroupName(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setDisplayName(options.groupId, options.groupName);
}).then(()=>{
return getSubscriberAndPreferences(options.groupId);
}).then((result)=>{
resolve({
group: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setGroupName (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setDisplayName(options.groupId, options.groupName)
}).then(() => {
return getSubscriberAndPreferences(options.groupId)
}).then((result) => {
resolve({
group: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
export function setGroupExtension(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setPbxExtension(options.groupId, options.groupExtension);
}).then(()=>{
return getSubscriberAndPreferences(options.groupId);
}).then((result)=>{
resolve({
group: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setGroupExtension (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setPbxExtension(options.groupId, options.groupExtension)
}).then(() => {
return getSubscriberAndPreferences(options.groupId)
}).then((result) => {
resolve({
group: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
export function setGroupHuntPolicy(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setPbxHuntPolicy(options.groupId, options.groupHuntPolicy);
}).then(()=>{
return getSubscriberAndPreferences(options.groupId);
}).then((result)=>{
resolve({
group: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setGroupHuntPolicy (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setPbxHuntPolicy(options.groupId, options.groupHuntPolicy)
}).then(() => {
return getSubscriberAndPreferences(options.groupId)
}).then((result) => {
resolve({
group: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
export function setGroupHuntTimeout(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setPbxHuntTimeout(options.groupId, options.groupHuntTimeout);
}).then(()=>{
return getSubscriberAndPreferences(options.groupId);
}).then((result)=>{
resolve({
group: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setGroupHuntTimeout (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setPbxHuntTimeout(options.groupId, options.groupHuntTimeout)
}).then(() => {
return getSubscriberAndPreferences(options.groupId)
}).then((result) => {
resolve({
group: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
export function setGroupNumbers(options) {
return new Promise((resolve, reject)=>{
setSubscriberNumbers({
subscriberId: options.groupId,
pilotId: options.pilotId,
assignedNumbers: options.assignedNumbers,
unassignedNumbers: options.unassignedNumbers
}).then((result)=>{
resolve(result);
}).catch((err)=>{
reject(err);
});
});
export function setGroupNumbers (options) {
return new Promise((resolve, reject) => {
setSubscriberNumbers({
subscriberId: options.groupId,
pilotId: options.pilotId,
assignedNumbers: options.assignedNumbers,
unassignedNumbers: options.unassignedNumbers
}).then((result) => {
resolve(result)
}).catch((err) => {
reject(err)
})
})
}
export function setGroupSeats(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setPbxGroupMemberIds(options.groupId, options.seatIds);
}).then(()=>{
return getSubscriberAndPreferences(options.groupId);
}).then((result)=>{
resolve({
group: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setGroupSeats (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setPbxGroupMemberIds(options.groupId, options.seatIds)
}).then(() => {
return getSubscriberAndPreferences(options.groupId)
}).then((result) => {
resolve({
group: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
export function setGroupSoundSet(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
if(options.soundSetId !== null && options.soundSetId !== void(0)) {
return getSoundSet(options.soundSetId);
}
else {
return Promise.resolve(null);
}
}).then((soundSet)=>{
let soundSetName = _.get(soundSet, 'name', null);
return setSubscriberSoundSet(options.groupId, soundSetName);
}).then(()=>{
return getSubscriberAndPreferences(options.groupId);
}).then((result)=>{
resolve({
group: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setGroupSoundSet (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
if (options.soundSetId !== null && options.soundSetId !== undefined) {
return getSoundSet(options.soundSetId)
} else {
return Promise.resolve(null)
}
}).then((soundSet) => {
const soundSetName = _.get(soundSet, 'name', null)
return setSubscriberSoundSet(options.groupId, soundSetName)
}).then(() => {
return getSubscriberAndPreferences(options.groupId)
}).then((result) => {
resolve({
group: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}

@ -1,95 +1,94 @@
import _ from 'lodash';
import _ from 'lodash'
import {
addPreference,
addPreferenceFull,
getAllPreferences,
getSubscriber,
} from "./subscriber";
addPreference,
addPreferenceFull,
getAllPreferences,
getSubscriber
} from './subscriber'
export function getMsConfigs() {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return getAllPreferences({
all: true
});
}).then((preferencesList)=>{
resolve({
items: _.get(preferencesList, 'items', []).filter((preferences)=>{
return _.get(preferences, 'manager_secretary', false)
})
});
}).catch((err)=>{
reject(err);
});
});
export function getMsConfigs () {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getAllPreferences({
all: true
})
}).then((preferencesList) => {
resolve({
items: _.get(preferencesList, 'items', []).filter((preferences) => {
return _.get(preferences, 'manager_secretary', false)
})
})
}).catch((err) => {
reject(err)
})
})
}
export function getMsConfigList() {
return new Promise((resolve, reject)=>{
let msConfigs = [];
Promise.resolve().then(()=>{
return getMsConfigs();
}).then(($msConfigs)=>{
msConfigs = $msConfigs;
let subscriberPromises = [];
msConfigs.items.forEach((msConfig)=>{
subscriberPromises.push(getSubscriber(msConfig.id));
});
return Promise.all(subscriberPromises);
}).then((subscribers)=>{
resolve({
subscribers: {
items: subscribers
},
msConfigs: msConfigs
});
}).catch((err)=>{
reject(err);
});
});
export function getMsConfigList () {
return new Promise((resolve, reject) => {
let msConfigs = []
Promise.resolve().then(() => {
return getMsConfigs()
}).then(($msConfigs) => {
msConfigs = $msConfigs
const subscriberPromises = []
msConfigs.items.forEach((msConfig) => {
subscriberPromises.push(getSubscriber(msConfig.id))
})
return Promise.all(subscriberPromises)
}).then((subscribers) => {
resolve({
subscribers: {
items: subscribers
},
msConfigs: msConfigs
})
}).catch((err) => {
reject(err)
})
})
}
export function createMsConfig(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return Promise.all([
addPreference(options.subscriberId, 'manager_secretary', true),
addPreference(options.subscriberId, 'secretary_numbers', options.secretaryNumbers)
]);
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
export function createMsConfig (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return Promise.all([
addPreference(options.subscriberId, 'manager_secretary', true),
addPreference(options.subscriberId, 'secretary_numbers', options.secretaryNumbers)
])
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function removeMsConfig(subscriberId) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return Promise.all([
addPreference(subscriberId, 'manager_secretary', false),
addPreference(subscriberId, 'secretary_numbers', [])
]);
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
export function removeMsConfig (subscriberId) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return Promise.all([
addPreference(subscriberId, 'manager_secretary', false),
addPreference(subscriberId, 'secretary_numbers', [])
])
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function setSecretaryNumber(options) {
return new Promise((resolve, reject)=>{
let numbers = _.get(options, 'secretaryNumbers', []);
Promise.resolve().then(()=>{
return addPreferenceFull(options.msConfigId, 'secretary_numbers', numbers);
}).then((prefs)=>{
resolve(prefs);
}).catch((err)=>{
reject(err);
});
});
export function setSecretaryNumber (options) {
return new Promise((resolve, reject) => {
const numbers = _.get(options, 'secretaryNumbers', [])
Promise.resolve().then(() => {
return addPreferenceFull(options.msConfigId, 'secretary_numbers', numbers)
}).then((prefs) => {
resolve(prefs)
}).catch((err) => {
reject(err)
})
})
}

@ -1,156 +1,155 @@
import {
createSubscriber,
deleteSubscriber,
getFullSubscribers,
getSubscriberAndPreferences, getSubscribers,
setDisplayName,
setPbxExtension,
setPbxWebPassword,
setPbxGroupIds,
setSubscriberNumbers,
setPreferenceIntraPbx,
getPreferences
} from "./subscriber";
import _ from "lodash";
createSubscriber,
deleteSubscriber,
getFullSubscribers,
getSubscriberAndPreferences, getSubscribers,
setDisplayName,
setPbxExtension,
setPbxWebPassword,
setPbxGroupIds,
setSubscriberNumbers,
setPreferenceIntraPbx,
getPreferences
} from './subscriber'
import _ from 'lodash'
import {
getAllSoundSets,
getPilot,
getSoundSet,
createId,
PBX_CONFIG_ORDER_BY,
PBX_CONFIG_ORDER_DIRECTION,
setSubscriberSoundSet
} from "./pbx-config";
getAllSoundSets,
getPilot,
getSoundSet,
createId,
PBX_CONFIG_ORDER_BY,
PBX_CONFIG_ORDER_DIRECTION,
setSubscriberSoundSet
} from './pbx-config'
import {
assignNumbers,
getNumbers
} from "./user";
assignNumbers,
getNumbers
} from './user'
import {
getGroupsOnly
} from "./pbx-groups";
getGroupsOnly
} from './pbx-groups'
export function getSeats(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
params: {
is_pbx_group: 0,
is_pbx_pilot: 0
}
});
Promise.resolve().then(()=>{
return Promise.all([
getFullSubscribers(options),
getAllSoundSets()
]);
}).then((result)=> {
resolve({
subscribers: result[0].subscribers,
preferences: {
items: result[0].preferences
},
soundSets: result[1]
});
}).catch((err)=>{
reject(err);
});
});
export function getSeats (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
params: {
is_pbx_group: 0,
is_pbx_pilot: 0
}
})
Promise.resolve().then(() => {
return Promise.all([
getFullSubscribers(options),
getAllSoundSets()
])
}).then((result) => {
resolve({
subscribers: result[0].subscribers,
preferences: {
items: result[0].preferences
},
soundSets: result[1]
})
}).catch((err) => {
reject(err)
})
})
}
export function getSeatsOnly(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
params: {
is_pbx_group: 0,
is_pbx_pilot: 0
}
});
Promise.resolve().then(()=>{
return getSubscribers(options);
}).then((result)=> {
resolve(result);
}).catch((err)=>{
reject(err);
});
});
export function getSeatsOnly (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
params: {
is_pbx_group: 0,
is_pbx_pilot: 0
}
})
Promise.resolve().then(() => {
return getSubscribers(options)
}).then((result) => {
resolve(result)
}).catch((err) => {
reject(err)
})
})
}
export function getSeatList(options) {
return new Promise((resolve, reject)=>{
let page = _.get(options, 'page', 1);
let display_name = _.get(options, 'display_name', null);
let params = {
page: page,
order_by: PBX_CONFIG_ORDER_BY,
order_by_direction: PBX_CONFIG_ORDER_DIRECTION
}
Promise.all([
getSeats({
params: display_name ? _.merge({
display_name: display_name
}, params) : params
}),
getGroupsOnly({
all: true
}),
getPilot(),
getNumbers()
]).then((result) => {
resolve({
seats: result[0].subscribers,
preferences: result[0].preferences,
soundSets: result[0].soundSets,
groups: result[1],
pilot: result[2],
numbers: result[3]
});
}).catch((err) => {
reject(err);
});
});
export function getSeatList (options) {
return new Promise((resolve, reject) => {
const page = _.get(options, 'page', 1)
const displayName = _.get(options, 'display_name', null)
const params = {
page: page,
order_by: PBX_CONFIG_ORDER_BY,
order_by_direction: PBX_CONFIG_ORDER_DIRECTION
}
Promise.all([
getSeats({
params: displayName ? _.merge({
display_name: displayName
}, params) : params
}),
getGroupsOnly({
all: true
}),
getPilot(),
getNumbers()
]).then((result) => {
resolve({
seats: result[0].subscribers,
preferences: result[0].preferences,
soundSets: result[0].soundSets,
groups: result[1],
pilot: result[2],
numbers: result[3]
})
}).catch((err) => {
reject(err)
})
})
}
export function createSeat(seat) {
return new Promise((resolve, reject)=>{
let subscriberId;
Promise.resolve().then(()=>{
return createSubscriber({
username: _.kebabCase(seat.name),
password: createId(),
display_name: seat.name,
webpassword: seat.webPassword.length > 0 ? seat.webPassword : null,
is_pbx_group: false,
pbx_extension: seat.extension,
pbx_group_ids: seat.groups
});
}).then(($subscriberId)=>{
subscriberId = $subscriberId;
setSeatIntraPbx(subscriberId, seat.clirIntrapbx);
if(seat.soundSet !== null && seat.soundSet !== void(0)) {
return getSoundSet(seat.soundSet);
}
else {
return Promise.resolve(null);
}
}).then((soundSet)=>{
let promises = [
assignNumbers(seat.aliasNumbers, subscriberId)
];
if(soundSet !== null) {
promises.push(setSubscriberSoundSet(subscriberId, soundSet.name));
}
return Promise.all(promises);
}).then(()=>{
resolve(subscriberId);
}).catch((err)=>{
reject(err);
});
});
export function createSeat (seat) {
return new Promise((resolve, reject) => {
let subscriberId
Promise.resolve().then(() => {
return createSubscriber({
username: _.kebabCase(seat.name),
password: createId(),
display_name: seat.name,
webpassword: seat.webPassword.length > 0 ? seat.webPassword : null,
is_pbx_group: false,
pbx_extension: seat.extension,
pbx_group_ids: seat.groups
})
}).then(($subscriberId) => {
subscriberId = $subscriberId
setSeatIntraPbx(subscriberId, seat.clirIntrapbx)
if (seat.soundSet !== null && seat.soundSet !== undefined) {
return getSoundSet(seat.soundSet)
} else {
return Promise.resolve(null)
}
}).then((soundSet) => {
const promises = [
assignNumbers(seat.aliasNumbers, subscriberId)
]
if (soundSet !== null) {
promises.push(setSubscriberSoundSet(subscriberId, soundSet.name))
}
return Promise.all(promises)
}).then(() => {
resolve(subscriberId)
}).catch((err) => {
reject(err)
})
})
}
export function removeSeat(id) {
return deleteSubscriber(id);
export function removeSeat (id) {
return deleteSubscriber(id)
}
/**
@ -158,21 +157,21 @@ export function removeSeat(id) {
* @param options.seatId
* @param options.seatName
*/
export function setSeatName(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setDisplayName(options.seatId, options.seatName);
}).then(()=>{
return getSubscriberAndPreferences(options.seatId);
}).then((result)=>{
resolve({
seat: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setSeatName (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setDisplayName(options.seatId, options.seatName)
}).then(() => {
return getSubscriberAndPreferences(options.seatId)
}).then((result) => {
resolve({
seat: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
/**
@ -180,21 +179,21 @@ export function setSeatName(options) {
* @param options.seatId
* @param options.seatExtension
*/
export function setSeatExtension(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setPbxExtension(options.seatId, options.seatExtension);
}).then(()=>{
return getSubscriberAndPreferences(options.seatId);
}).then((result)=>{
resolve({
seat: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setSeatExtension (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setPbxExtension(options.seatId, options.seatExtension)
}).then(() => {
return getSubscriberAndPreferences(options.seatId)
}).then((result) => {
resolve({
seat: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
/**
@ -202,29 +201,29 @@ export function setSeatExtension(options) {
* @param options.seatId
* @param options.seatWebPassword
*/
export function setSeatWebPassword(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setPbxWebPassword(options.seatId, options.seatWebPassword);
}).then(()=>{
return getSubscriberAndPreferences(options.seatId);
}).then((result)=>{
resolve({
seat: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setSeatWebPassword (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setPbxWebPassword(options.seatId, options.seatWebPassword)
}).then(() => {
return getSubscriberAndPreferences(options.seatId)
}).then((result) => {
resolve({
seat: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
/**
* @param seatId
* @param clirIntrapbx
*/
export function setSeatIntraPbx(seatId, clirIntrapbx) {
return setPreferenceIntraPbx(seatId, clirIntrapbx);
export function setSeatIntraPbx (seatId, clirIntrapbx) {
return setPreferenceIntraPbx(seatId, clirIntrapbx)
}
/**
@ -232,21 +231,21 @@ export function setSeatIntraPbx(seatId, clirIntrapbx) {
* @param options.seatId
* @param options.groupIds
*/
export function setSeatGroups(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return setPbxGroupIds(options.seatId, options.groupIds);
}).then(()=>{
return getSubscriberAndPreferences(options.seatId);
}).then((result)=>{
resolve({
seat: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setSeatGroups (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return setPbxGroupIds(options.seatId, options.groupIds)
}).then(() => {
return getSubscriberAndPreferences(options.seatId)
}).then((result) => {
resolve({
seat: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
/**
@ -257,19 +256,19 @@ export function setSeatGroups(options) {
* @param options.unassignedNumbers
* @return {Promise<any>}
*/
export function setSeatNumbers(options) {
return new Promise((resolve, reject)=>{
setSubscriberNumbers({
subscriberId: options.seatId,
pilotId: options.pilotId,
assignedNumbers: options.assignedNumbers,
unassignedNumbers: options.unassignedNumbers
}).then((result)=>{
resolve(result);
}).catch((err)=>{
reject(err);
});
});
export function setSeatNumbers (options) {
return new Promise((resolve, reject) => {
setSubscriberNumbers({
subscriberId: options.seatId,
pilotId: options.pilotId,
assignedNumbers: options.assignedNumbers,
unassignedNumbers: options.unassignedNumbers
}).then((result) => {
resolve(result)
}).catch((err) => {
reject(err)
})
})
}
/**
@ -277,39 +276,37 @@ export function setSeatNumbers(options) {
* @param options.seatId
* @param options.soundSetId
*/
export function setSeatSoundSet(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
if(options.soundSetId !== null && options.soundSetId !== void(0)) {
return getSoundSet(options.soundSetId);
}
else {
return Promise.resolve(null);
}
}).then((soundSet)=>{
let soundSetName = _.get(soundSet, 'name', null);
return setSubscriberSoundSet(options.seatId, soundSetName);
}).then(()=>{
return getSubscriberAndPreferences(options.seatId);
}).then((result)=>{
resolve({
seat: result.subscriber,
preferences: result.preferences
});
}).catch((err)=>{
reject(err);
});
});
export function setSeatSoundSet (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
if (options.soundSetId !== null && options.soundSetId !== undefined) {
return getSoundSet(options.soundSetId)
} else {
return Promise.resolve(null)
}
}).then((soundSet) => {
const soundSetName = _.get(soundSet, 'name', null)
return setSubscriberSoundSet(options.seatId, soundSetName)
}).then(() => {
return getSubscriberAndPreferences(options.seatId)
}).then((result) => {
resolve({
seat: result.subscriber,
preferences: result.preferences
})
}).catch((err) => {
reject(err)
})
})
}
/**
* @param seatId
*/
export async function getSeatPreferences(seatId) {
try {
return await getPreferences(seatId);
}
catch(err){
return err;
}
export async function getSeatPreferences (seatId) {
try {
return await getPreferences(seatId)
} catch (err) {
return err
}
}

@ -1,229 +1,228 @@
import _ from "lodash";
import _ from 'lodash'
import {
getList,
patchReplaceFull,
getAsBlob,
get
} from "./common";
getList,
patchReplaceFull,
getAsBlob,
get
} from './common'
import {
PBX_CONFIG_ORDER_BY,
PBX_CONFIG_ORDER_DIRECTION
} from "./pbx-config";
import Vue from "vue";
PBX_CONFIG_ORDER_BY,
PBX_CONFIG_ORDER_DIRECTION
} from './pbx-config'
import Vue from 'vue'
import {
Platform
} from 'quasar-framework'
export function getSoundSets(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
path: 'api/soundsets/',
root: '_embedded.ngcp:soundsets'
});
getList(options).then((list)=>{
resolve(list);
}).catch((err)=>{
reject(err);
});
});
}
export function getSoundSetList(options) {
return new Promise((resolve, reject)=>{
let params = {
page: options.page,
order_by: PBX_CONFIG_ORDER_BY,
order_by_direction: PBX_CONFIG_ORDER_DIRECTION
};
getSoundSets({
params: params
}).then((soundSets)=>{
resolve({
soundSets: soundSets
});
}).catch((err)=>{
reject(err);
});
});
}
export function createSoundSet(soundSet) {
return new Promise((resolve, reject)=>{
Vue.http.post('api/soundsets/', soundSet).then(() => {
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function removeSoundSet(soundSetId) {
return new Promise((resolve, reject)=>{
Vue.http.delete('api/soundsets/' + soundSetId).then(()=>{
resolve();
}).catch((err)=>{
if (err.status >= 400) {
reject(new Error(err.body.message));
}
else {
reject(err);
}
});
});
}
export function setSoundSetProperty(soundSetId, property, value) {
return new Promise((resolve, reject)=>{
patchReplaceFull({
path: 'api/soundsets/' + soundSetId,
fieldPath: property,
value: value
}).then((soundSet)=>{
resolve(soundSet);
}).catch((err)=>{
reject(err);
});
});
}
export function setAsDefault(soundSetId) {
return setSoundSetProperty(soundSetId, 'contract_default', true);
}
export function unsetAsDefault(soundSetId) {
return setSoundSetProperty(soundSetId, 'contract_default', false);
}
export function setSoundSetName(soundSetId, name) {
return setSoundSetProperty(soundSetId, 'name', name);
}
export function setSoundSetDescription(soundSetId, description) {
return setSoundSetProperty(soundSetId, 'description', description);
}
export function getSoundHandles(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
path: 'api/soundhandles/',
root: '_embedded.ngcp:soundhandles'
});
getList(options).then((list)=>{
resolve(list);
}).catch((err)=>{
reject(err);
});
});
}
export function getAllSoundHandles(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
all: true
});
getSoundHandles(options).then((list)=>{
resolve(list);
}).catch((err)=>{
reject(err);
});
});
}
export function getSoundFiles(options) {
return new Promise((resolve, reject)=>{
options = options || {};
options = _.merge(options, {
path: 'api/soundfiles/',
root: '_embedded.ngcp:soundfiles',
});
getList(options).then((list)=>{
resolve(list);
}).catch((err)=>{
reject(err);
});
});
}
export function getAllSoundFilesBySoundSetId(soundSetId) {
return new Promise((resolve, reject)=>{
getSoundFiles({
all: true,
params: {
set_id: soundSetId
}
}).then((soundFiles)=>{
resolve(soundFiles);
}).catch((err)=>{
reject(err);
});
});
}
export function getSoundFile(options) {
return new Promise((resolve, reject)=>{
getAsBlob({
path: 'api/soundfilerecordings/' + options.id,
params: {
format: Platform.mozilla ? 'ogg' : 'mp3'
}
}).then((result)=>{
resolve(result);
}).catch((err)=>{
reject(err);
});
});
}
export function uploadSoundFile(options) {
return new Promise((resolve, reject)=>{
let formData = new FormData();
formData.append('json', JSON.stringify({
loopplay: true,
filename: options.soundFileData.name,
set_id: options.soundSetId,
handle: options.soundHandle,
}));
formData.append('soundfile', options.soundFileData);
Vue.http.post('api/soundfiles/', formData, {
before(request) {
options.initialized(request);
},
progress(progressEvent) {
if (progressEvent.lengthComputable) {
options.progressed(Math.ceil((progressEvent.loaded / progressEvent.total) * 100));
}
}
}).then((res) => {
let fileId = _.last(res.headers.get('location').split(/\//));
return Promise.all([
get({ path: 'api/soundfiles/' + fileId }),
getSoundFile({ id: fileId })
]);
}).then((res)=>{
resolve({
soundFile: res[0],
soundFileUrl: res[1]
});
}).catch((err) => {
reject(err);
});
});
}
export function setLoopPlay(options) {
return new Promise((resolve, reject)=>{
console.log(options);
patchReplaceFull({
path: 'api/soundfiles/' + options.soundFileId,
fieldPath: 'loopplay',
value: (options.loopPlay === true)? 'true' : 'false'
}).then((soundFile)=>{
resolve(soundFile);
}).catch((err)=>{
reject(err);
});
});
Platform
} from 'quasar'
export function getSoundSets (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
path: 'api/soundsets/',
root: '_embedded.ngcp:soundsets'
})
getList(options).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function getSoundSetList (options) {
return new Promise((resolve, reject) => {
const params = {
page: options.page,
order_by: PBX_CONFIG_ORDER_BY,
order_by_direction: PBX_CONFIG_ORDER_DIRECTION
}
getSoundSets({
params: params
}).then((soundSets) => {
resolve({
soundSets: soundSets
})
}).catch((err) => {
reject(err)
})
})
}
export function createSoundSet (soundSet) {
return new Promise((resolve, reject) => {
Vue.http.post('api/soundsets/', soundSet).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function removeSoundSet (soundSetId) {
return new Promise((resolve, reject) => {
Vue.http.delete('api/soundsets/' + soundSetId).then(() => {
resolve()
}).catch((err) => {
if (err.status >= 400) {
reject(new Error(err.body.message))
} else {
reject(err)
}
})
})
}
export function setSoundSetProperty (soundSetId, property, value) {
return new Promise((resolve, reject) => {
patchReplaceFull({
path: 'api/soundsets/' + soundSetId,
fieldPath: property,
value: value
}).then((soundSet) => {
resolve(soundSet)
}).catch((err) => {
reject(err)
})
})
}
export function setAsDefault (soundSetId) {
return setSoundSetProperty(soundSetId, 'contract_default', true)
}
export function unsetAsDefault (soundSetId) {
return setSoundSetProperty(soundSetId, 'contract_default', false)
}
export function setSoundSetName (soundSetId, name) {
return setSoundSetProperty(soundSetId, 'name', name)
}
export function setSoundSetDescription (soundSetId, description) {
return setSoundSetProperty(soundSetId, 'description', description)
}
export function getSoundHandles (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
path: 'api/soundhandles/',
root: '_embedded.ngcp:soundhandles'
})
getList(options).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function getAllSoundHandles (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
all: true
})
getSoundHandles(options).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function getSoundFiles (options) {
return new Promise((resolve, reject) => {
options = options || {}
options = _.merge(options, {
path: 'api/soundfiles/',
root: '_embedded.ngcp:soundfiles'
})
getList(options).then((list) => {
resolve(list)
}).catch((err) => {
reject(err)
})
})
}
export function getAllSoundFilesBySoundSetId (soundSetId) {
return new Promise((resolve, reject) => {
getSoundFiles({
all: true,
params: {
set_id: soundSetId
}
}).then((soundFiles) => {
resolve(soundFiles)
}).catch((err) => {
reject(err)
})
})
}
export function getSoundFile (options) {
return new Promise((resolve, reject) => {
getAsBlob({
path: 'api/soundfilerecordings/' + options.id,
params: {
format: Platform.mozilla ? 'ogg' : 'mp3'
}
}).then((result) => {
resolve(result)
}).catch((err) => {
reject(err)
})
})
}
export function uploadSoundFile (options) {
return new Promise((resolve, reject) => {
const formData = new FormData()
formData.append('json', JSON.stringify({
loopplay: true,
filename: options.soundFileData.name,
set_id: options.soundSetId,
handle: options.soundHandle
}))
formData.append('soundfile', options.soundFileData)
Vue.http.post('api/soundfiles/', formData, {
before (request) {
options.initialized(request)
},
progress (progressEvent) {
if (progressEvent.lengthComputable) {
options.progressed(Math.ceil((progressEvent.loaded / progressEvent.total) * 100))
}
}
}).then((res) => {
const fileId = _.last(res.headers.get('location').split(/\//))
return Promise.all([
get({ path: 'api/soundfiles/' + fileId }),
getSoundFile({ id: fileId })
])
}).then((res) => {
resolve({
soundFile: res[0],
soundFileUrl: res[1]
})
}).catch((err) => {
reject(err)
})
})
}
export function setLoopPlay (options) {
return new Promise((resolve, reject) => {
console.log(options)
patchReplaceFull({
path: 'api/soundfiles/' + options.soundFileId,
fieldPath: 'loopplay',
value: (options.loopPlay === true) ? 'true' : 'false'
}).then((soundFile) => {
resolve(soundFile)
}).catch((err) => {
reject(err)
})
})
}

@ -2,97 +2,96 @@
import _ from 'lodash'
import Vue from 'vue'
import {
getList,
patchReplace
getList,
patchReplace
} from './common'
export function createReminder(subscriberId) {
return new Promise((resolve, reject) => {
Vue.http.post('api/reminders/', {
subscriber_id: subscriberId,
time: '00:00',
recur: 'never',
active: false
}).then((result) => {
let parts = result.headers.get('Location').split('/');
resolve(_.last(parts));
}).catch((err) => {
reject(err);
});
});
export function createReminder (subscriberId) {
return new Promise((resolve, reject) => {
Vue.http.post('api/reminders/', {
subscriber_id: subscriberId,
time: '00:00',
recur: 'never',
active: false
}).then((result) => {
const parts = result.headers.get('Location').split('/')
resolve(_.last(parts))
}).catch((err) => {
reject(err)
})
})
}
export function getFirstReminder(subscriberId) {
return new Promise((resolve, reject) => {
getList({
path: 'api/reminders/',
root: '_embedded.ngcp:reminders',
params: {
page: 1,
rows: 1,
subscriber_id: subscriberId
}
}).then((reminders)=>{
resolve(_.get(reminders, 'items.0', null));
}).catch((err)=>{
reject(err);
});
});
export function getFirstReminder (subscriberId) {
return new Promise((resolve, reject) => {
getList({
path: 'api/reminders/',
root: '_embedded.ngcp:reminders',
params: {
page: 1,
rows: 1,
subscriber_id: subscriberId
}
}).then((reminders) => {
resolve(_.get(reminders, 'items.0', null))
}).catch((err) => {
reject(err)
})
})
}
export function getReminder(subscriberId) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return getFirstReminder(subscriberId);
}).then((reminder)=>{
if(reminder === null) {
return createAndGetReminder(subscriberId);
}
else {
return Promise.resolve(reminder);
}
}).then((reminder)=>{
resolve(reminder);
}).catch((err)=>{
reject(err);
});
});
export function getReminder (subscriberId) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getFirstReminder(subscriberId)
}).then((reminder) => {
if (reminder === null) {
return createAndGetReminder(subscriberId)
} else {
return Promise.resolve(reminder)
}
}).then((reminder) => {
resolve(reminder)
}).catch((err) => {
reject(err)
})
})
}
export function createAndGetReminder(subscriberId) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return createReminder(subscriberId);
}).then(()=>{
return getFirstReminder(subscriberId);
}).then((reminder)=>{
resolve(reminder);
}).catch((err)=>{
reject(err);
});
});
export function createAndGetReminder (subscriberId) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return createReminder(subscriberId)
}).then(() => {
return getFirstReminder(subscriberId)
}).then((reminder) => {
resolve(reminder)
}).catch((err) => {
reject(err)
})
})
}
export function setReminderActive(reminderId, active) {
return patchReplace({
path: 'api/reminders/' + reminderId,
fieldPath: 'active',
value: active
});
export function setReminderActive (reminderId, active) {
return patchReplace({
path: 'api/reminders/' + reminderId,
fieldPath: 'active',
value: active
})
}
export function setReminderTime(reminderId, time) {
return patchReplace({
path: 'api/reminders/' + reminderId,
fieldPath: 'time',
value: time
});
export function setReminderTime (reminderId, time) {
return patchReplace({
path: 'api/reminders/' + reminderId,
fieldPath: 'time',
value: time
})
}
export function setReminderRecurrence(reminderId, reccurence) {
return patchReplace({
path: 'api/reminders/' + reminderId,
fieldPath: 'recur',
value: reccurence
});
export function setReminderRecurrence (reminderId, reccurence) {
return patchReplace({
path: 'api/reminders/' + reminderId,
fieldPath: 'recur',
value: reccurence
})
}

@ -1,48 +1,48 @@
import config from '../config'
import Vue from 'vue';
import { getJsonBody } from './utils';
import Vue from 'vue'
import { getJsonBody } from './utils'
export function create() {
return new Promise((resolve, reject)=>{
Vue.http.post('api/rtcsessions/').then((res)=>{
resolve(res);
}).catch((err)=>{
reject(err);
});
});
export function create () {
return new Promise((resolve, reject) => {
Vue.http.post('api/rtcsessions/').then((res) => {
resolve(res)
}).catch((err) => {
reject(err)
})
})
}
export function getByUrl(url) {
return new Promise((resolve, reject)=>{
Vue.http.get(url).then((res)=>{
resolve(getJsonBody(res.body));
}).catch((err)=>{
reject(err);
});
});
export function getByUrl (url) {
return new Promise((resolve, reject) => {
Vue.http.get(url).then((res) => {
resolve(getJsonBody(res.body))
}).catch((err) => {
reject(err)
})
})
}
export function createSession() {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
return create();
}).then((res)=>{
return getByUrl(config.baseHttpUrl + res.headers.get('Location'));
}).then((res)=>{
resolve(res);
}).catch((err)=>{
reject(err);
});
});
export function createSession () {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return create()
}).then((res) => {
return getByUrl(config.baseHttpUrl + res.headers.get('Location'))
}).then((res) => {
resolve(res)
}).catch((err) => {
reject(err)
})
})
}
export function createSessionToken() {
return new Promise((resolve, reject)=>{
createSession().then((res)=>{
resolve(res.rtc_browser_token);
}).catch((err)=>{
reject(err);
});
});
export function createSessionToken () {
return new Promise((resolve, reject) => {
createSession().then((res) => {
resolve(res.rtc_browser_token)
}).catch((err) => {
reject(err)
})
})
}

@ -1,92 +1,92 @@
import _ from 'lodash'
import Vue from 'vue';
import { i18n } from '../i18n';
import Vue from 'vue'
import { i18n } from 'src/boot/i18n'
import { getFieldList } from './common'
export function getSpeedDialsById(id) {
return new Promise((resolve, reject) => {
getFieldList({
path: 'api/speeddials/' + id,
field: 'speeddials'
}).then((result) => {
let sortedResult = _.sortBy(result, ['slot']);
resolve(sortedResult);
}).catch((err) => {
reject(err.body.message);
});
});
export function getSpeedDialsById (id) {
return new Promise((resolve, reject) => {
getFieldList({
path: 'api/speeddials/' + id,
field: 'speeddials'
}).then((result) => {
const sortedResult = _.sortBy(result, ['slot'])
resolve(sortedResult)
}).catch((err) => {
reject(err.body.message)
})
})
}
export function getUnassignedSlots(id) {
return new Promise((resolve, reject) => {
let slots = ["*0", "*1", "*2", "*3", "*4", "*5", "*6", "*7", "*8", "*9"];
Promise.resolve().then(() => {
return getSpeedDialsById(id);
}).then((assignedSlots) => {
let unassignedSlots = _.difference(slots, assignedSlots.map((slot) => {
return slot.slot;
}));
let slotOptions = [];
unassignedSlots.forEach((slot) => {
slotOptions.push({
label: `${i18n.t('speedDial.slot')} ${slot}`,
value: slot
});
});
resolve(slotOptions);
}).catch((err) => {
reject(err.body.message);
});
});
export function getUnassignedSlots (id) {
return new Promise((resolve, reject) => {
const slots = ['*0', '*1', '*2', '*3', '*4', '*5', '*6', '*7', '*8', '*9']
Promise.resolve().then(() => {
return getSpeedDialsById(id)
}).then((assignedSlots) => {
const unassignedSlots = _.difference(slots, assignedSlots.map((slot) => {
return slot.slot
}))
const slotOptions = []
unassignedSlots.forEach((slot) => {
slotOptions.push({
label: `${i18n.t('speedDial.slot')} ${slot}`,
value: slot
})
})
resolve(slotOptions)
}).catch((err) => {
reject(err.body.message)
})
})
}
export function unassignSpeedDialSlot(options) {
return new Promise((resolve, reject) => {
let updatedAssignedSlots = _.without(options.slots, options.slot);
let headers = {
'Content-Type': 'application/json-patch+json'
};
Vue.http.patch('api/speeddials/' + options.id, [{
op: 'replace',
path: '/speeddials',
value: updatedAssignedSlots
}], { headers: headers }).then(() => {
resolve();
}).catch((err) => {
reject(err.body.message);
});
});
export function unassignSpeedDialSlot (options) {
return new Promise((resolve, reject) => {
const updatedAssignedSlots = _.without(options.slots, options.slot)
const headers = {
'Content-Type': 'application/json-patch+json'
}
Vue.http.patch('api/speeddials/' + options.id, [{
op: 'replace',
path: '/speeddials',
value: updatedAssignedSlots
}], { headers: headers }).then(() => {
resolve()
}).catch((err) => {
reject(err.body.message)
})
})
}
export function addSlotToSpeedDials(options) {
return new Promise((resolve, reject) => {
let headers = {
'Content-Type': 'application/json-patch+json'
};
Vue.http.patch('api/speeddials/' + options.id, [{
op: 'replace',
path: '/speeddials',
value: options.slots
}], { headers: headers }).then(() => {
resolve();
}).catch((err) => {
reject(err.body.message);
});
});
export function addSlotToSpeedDials (options) {
return new Promise((resolve, reject) => {
const headers = {
'Content-Type': 'application/json-patch+json'
}
Vue.http.patch('api/speeddials/' + options.id, [{
op: 'replace',
path: '/speeddials',
value: options.slots
}], { headers: headers }).then(() => {
resolve()
}).catch((err) => {
reject(err.body.message)
})
})
}
export function assignSpeedDialSlot(options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getSpeedDialsById(options.id);
}).then((result) => {
let concatSlots = result.concat(options.slot);
return addSlotToSpeedDials({ id: options.id, slots: concatSlots });
}).then(() => {
resolve();
}).catch((err) => {
reject(err);
});
});
export function assignSpeedDialSlot (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getSpeedDialsById(options.id)
}).then((result) => {
const concatSlots = result.concat(options.slot)
return addSlotToSpeedDials({ id: options.id, slots: concatSlots })
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}

File diff suppressed because it is too large Load Diff

@ -1,142 +1,140 @@
import _ from 'lodash';
import Vue from 'vue';
import _ from 'lodash'
import Vue from 'vue'
import {
get,
getList,
patchReplace
get,
getList,
patchReplace
} from './common'
export function login(username, password) {
return new Promise((resolve, reject)=>{
let jwt = null;
let 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)=>{
if(err.status && err.status >= 400) {
reject(new Error(err.body.message));
}
else {
reject(err);
}
});
});
export function login (username, password) {
return new Promise((resolve, reject) => {
let jwt = null
let 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) => {
if (err.status && err.status >= 400) {
reject(new Error(err.body.message))
} else {
reject(err)
}
})
})
}
export function getUserData(id) {
return new Promise((resolve, reject)=>{
return Promise.all([
getSubscriberById(id),
getCapabilities(id),
getFaxServerSettingsById(id)
]).then((results)=>{
results[1].faxactive = results[2]
resolve({
subscriber: results[0],
capabilities: results[1]
});
}).catch((err)=>{
reject(err);
});
});
export function getUserData (id) {
return new Promise((resolve, reject) => {
return Promise.all([
getSubscriberById(id),
getCapabilities(id),
getFaxServerSettingsById(id)
]).then((results) => {
results[1].faxactive = results[2]
resolve({
subscriber: results[0],
capabilities: results[1]
})
}).catch((err) => {
reject(err)
})
})
}
export function getSubscriberById(id) {
return new Promise((resolve, reject)=>{
get({
path: 'api/subscribers/' + id
}).then((body)=>{
resolve(body);
}).catch((err)=>{
reject(err);
});
});
export function getSubscriberById (id) {
return new Promise((resolve, reject) => {
get({
path: 'api/subscribers/' + id
}).then((body) => {
resolve(body)
}).catch((err) => {
reject(err)
})
})
}
export function getCapabilities() {
return new Promise((resolve, reject)=>{
getList({
path: 'api/capabilities/',
root: '_embedded.ngcp:capabilities',
all: true
}).then((capabilityList)=>{
let capabilities = {};
if(_.isArray(capabilityList.items)) {
capabilityList.items.forEach((capability)=>{
capabilities[capability.name] = capability.enabled;
});
}
resolve(capabilities);
}).catch((err)=>{
reject(err);
});
});
export function getCapabilities () {
return new Promise((resolve, reject) => {
getList({
path: 'api/capabilities/',
root: '_embedded.ngcp:capabilities',
all: true
}).then((capabilityList) => {
const capabilities = {}
if (_.isArray(capabilityList.items)) {
capabilityList.items.forEach((capability) => {
capabilities[capability.name] = capability.enabled
})
}
resolve(capabilities)
}).catch((err) => {
reject(err)
})
})
}
export function assignNumber(numberId, subscriberId) {
return new Promise((resolve, reject)=>{
patchReplace({
path: 'api/numbers/' + numberId,
fieldPath: 'subscriber_id',
value: subscriberId
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
export function assignNumber (numberId, subscriberId) {
return new Promise((resolve, reject) => {
patchReplace({
path: 'api/numbers/' + numberId,
fieldPath: 'subscriber_id',
value: subscriberId
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function assignNumbers(numberIds, subscriberId) {
return new Promise((resolve, reject)=>{
if(_.isArray(numberIds) && numberIds.length > 0) {
let assignNumberRequests = [];
numberIds.forEach((numberId)=>{
assignNumberRequests.push(assignNumber(numberId, subscriberId));
});
Promise.all(assignNumberRequests).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
}
else {
resolve();
}
});
export function assignNumbers (numberIds, subscriberId) {
return new Promise((resolve, reject) => {
if (_.isArray(numberIds) && numberIds.length > 0) {
const assignNumberRequests = []
numberIds.forEach((numberId) => {
assignNumberRequests.push(assignNumber(numberId, subscriberId))
})
Promise.all(assignNumberRequests).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
} else {
resolve()
}
})
}
export function getNumbers() {
return new Promise((resolve, reject)=>{
getList({
path: 'api/numbers/',
root: '_embedded.ngcp:numbers',
all: true
}).then((numberList)=>{
resolve(numberList);
}).catch((err)=>{
reject(err);
});
});
export function getNumbers () {
return new Promise((resolve, reject) => {
getList({
path: 'api/numbers/',
root: '_embedded.ngcp:numbers',
all: true
}).then((numberList) => {
resolve(numberList)
}).catch((err) => {
reject(err)
})
})
}
export function getFaxServerSettingsById(id) {
return new Promise((resolve, reject) => {
get({
path: 'api/faxserversettings/' + id
}).then((body)=>{
resolve(body.active);
}).catch((err)=>{
reject(err);
});
});
export function getFaxServerSettingsById (id) {
return new Promise((resolve, reject) => {
get({
path: 'api/faxserversettings/' + id
}).then((body) => {
resolve(body.active)
}).catch((err) => {
reject(err)
})
})
}

@ -1,15 +1,13 @@
import _ from 'lodash'
import _ from 'lodash';
export function getJsonBody(body) {
if(_.isString(body)) {
try {
return JSON.parse(body);
}
catch(err) {
return body;
}
}
return body;
export function getJsonBody (body) {
if (_.isString(body)) {
try {
return JSON.parse(body)
} catch (err) {
return body
}
}
return body
}

@ -1,161 +1,160 @@
import _ from 'lodash'
import Vue from 'vue';
import Vue from 'vue'
import {
get,
getList,
patchReplace
get,
getList,
patchReplace
} from './common'
export function getVoiceboxSettings(subscriberId) {
return new Promise((resolve, reject) => {
get({
path: `api/voicemailsettings/${subscriberId}`
}).then((result)=>{
let settings = _.clone(result);
delete settings._links;
resolve(settings);
}).catch((err)=>{
reject(err);
});
});
export function getVoiceboxSettings (subscriberId) {
return new Promise((resolve, reject) => {
get({
path: `api/voicemailsettings/${subscriberId}`
}).then((result) => {
const settings = _.clone(result)
delete settings._links
resolve(settings)
}).catch((err) => {
reject(err)
})
})
}
export function setVoiceboxDelete(options) {
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'delete',
value: options.value
});
export function setVoiceboxDelete (options) {
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'delete',
value: options.value
})
}
export function setVoiceboxAttach(options) {
return new Promise((resolve, reject)=>{
Promise.resolve().then(()=>{
if(options.value === false) {
return setVoiceboxDelete(options);
}
else {
return Promise.resolve();
}
}).then(()=>{
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'attach',
value: options.value
});
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
export function setVoiceboxAttach (options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
if (options.value === false) {
return setVoiceboxDelete(options)
} else {
return Promise.resolve()
}
}).then(() => {
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'attach',
value: options.value
})
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function setVoiceboxPin(options) {
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'pin',
value: options.value
});
export function setVoiceboxPin (options) {
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'pin',
value: options.value
})
}
export function setVoiceboxEmail(options) {
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'email',
value: options.value
});
export function setVoiceboxEmail (options) {
return patchReplace({
path: `api/voicemailsettings/${options.subscriberId}`,
fieldPath: 'email',
value: options.value
})
}
export function getVoiceboxGreetingByType(options) {
return new Promise((resolve, reject) => {
getList({
path: 'api/voicemailgreetings/',
root: '_embedded.ngcp:voicemailgreetings',
params: { subscriber_id: options.id, type: options.type }
}).then((result) => {
resolve(result);
}).catch((err)=>{
reject(err);
});
});
export function getVoiceboxGreetingByType (options) {
return new Promise((resolve, reject) => {
getList({
path: 'api/voicemailgreetings/',
root: '_embedded.ngcp:voicemailgreetings',
params: { subscriber_id: options.id, type: options.type }
}).then((result) => {
resolve(result)
}).catch((err) => {
reject(err)
})
})
}
export function deleteVoiceboxGreetingById(id) {
return new Promise((resolve, reject) => {
Vue.http.delete(`api/voicemailgreetings/${id}`).then(() => {
resolve();
}).catch((err)=>{
reject(err);
});
});
export function deleteVoiceboxGreetingById (id) {
return new Promise((resolve, reject) => {
Vue.http.delete(`api/voicemailgreetings/${id}`).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function createNewGreeting(formData, onProgress, type) {
return new Promise((resolve, reject) => {
let requestKey = `previous${_.capitalize(type)}Request`;
Vue.http.post('api/voicemailgreetings/', formData, {
before(request) {
Vue[requestKey] = request;
},
progress(e) {
if (e.lengthComputable) {
onProgress(Math.ceil((e.loaded / e.total ) * 100));
}
}
}).then(() => {
resolve();
}).catch((err)=>{
reject(err);
});
});
export function createNewGreeting (formData, onProgress, type) {
return new Promise((resolve, reject) => {
const requestKey = `previous${_.capitalize(type)}Request`
Vue.http.post('api/voicemailgreetings/', formData, {
before (request) {
Vue[requestKey] = request
},
progress (e) {
if (e.lengthComputable) {
onProgress(Math.ceil((e.loaded / e.total) * 100))
}
}
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function uploadGreeting(options) {
return new Promise((resolve, reject) => {
let formData = new FormData();
let fields = _.clone(options.data);
delete fields.file;
let json = JSON.stringify(fields);
formData.append('json', json);
if (options.data.file) {
formData.append('greetingfile', options.data.file);
}
Promise.resolve().then(() => {
return getVoiceboxGreetingByType({
id: options.data.subscriber_id,
type: options.data.dir
});
}).then((greetings) => {
if (_.some(greetings.items, { dir: options.data.dir })) {
deleteVoiceboxGreetingById(greetings.items[0].id);
}
return createNewGreeting(formData, options.onProgress, options.data.dir);
}).then(() => {
resolve();
}).catch((err) => {
reject(err);
});
});
export function uploadGreeting (options) {
return new Promise((resolve, reject) => {
const formData = new FormData()
const fields = _.clone(options.data)
delete fields.file
const json = JSON.stringify(fields)
formData.append('json', json)
if (options.data.file) {
formData.append('greetingfile', options.data.file)
}
Promise.resolve().then(() => {
return getVoiceboxGreetingByType({
id: options.data.subscriber_id,
type: options.data.dir
})
}).then((greetings) => {
if (_.some(greetings.items, { dir: options.data.dir })) {
deleteVoiceboxGreetingById(greetings.items[0].id)
}
return createNewGreeting(formData, options.onProgress, options.data.dir)
}).then(() => {
resolve()
}).catch((err) => {
reject(err)
})
})
}
export function abortPreviousRequest(name) {
return new Promise((resolve) => {
let requestKey = `previous${_.capitalize(name)}Request`;
Vue[requestKey].abort();
resolve();
});
export function abortPreviousRequest (name) {
return new Promise((resolve) => {
const requestKey = `previous${_.capitalize(name)}Request`
Vue[requestKey].abort()
resolve()
})
}
export function playGreeting(options) {
return new Promise((resolve, reject)=>{
let params = { format: options.format };
Vue.http.get(`api/voicemailgreetings/${options.id}`, { params: params, responseType: 'blob' })
.then((res) => {
resolve(URL.createObjectURL(res.body));
}).catch((err) => {
reject(err);
});
});
export function playGreeting (options) {
return new Promise((resolve, reject) => {
const params = { format: options.format }
Vue.http.get(`api/voicemailgreetings/${options.id}`, { params: params, responseType: 'blob' })
.then((res) => {
resolve(URL.createObjectURL(res.body))
}).catch((err) => {
reject(err)
})
})
}

@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="67.407623mm"
height="62.908276mm"
viewBox="0 0 238.84591 222.90334"
id="svg3570"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="quasar-logo-full.svg">
<defs
id="defs3572" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="-39.753589"
inkscape:cy="27.706388"
inkscape:document-units="px"
inkscape:current-layer="g4895-4-4"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1056"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata3575">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-277.71988,-312.33911)">
<g
id="g4895-4-4"
transform="translate(1419.0442,398.9018)">
<g
transform="translate(-29.620665,-4)"
id="g4579-2-20">
<g
id="g4445-2-0"
transform="translate(12.499948,7.809312)">
<g
inkscape:export-ydpi="44.860481"
inkscape:export-xdpi="44.860481"
inkscape:export-filename="/home/emanuele/Desktop/logo1.png"
transform="translate(-712.85583,-503.26814)"
id="g4561-6-7-0">
<g
transform="translate(16.233481,0)"
style="font-style:normal;font-weight:normal;font-size:50.25774765px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#263238;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="flowRoot4513-6-6-08">
<path
d="m -402.73125,631.46823 q -0.6125,0.0438 -1.3125,0.0875 -0.65625,0 -1.4,0 l -9.31875,0 q -12.81875,0 -12.81875,-8.44375 l 0,-13.475 q 0,-8.26875 12.6,-8.26875 l 9.75625,0 q 12.6,0 12.6,8.26875 l 0,13.475 q 0,5.03125 -4.4625,7.04375 l 3.10625,2.14375 q 1.35625,0.83125 1.35625,1.70625 0,0.875 -0.7,1.3125 -0.65625,0.48125 -1.88125,0.48125 -0.30625,0 -0.7875,-0.13125 -0.4375,-0.0875 -1.05,-0.48125 l -5.6875,-3.71875 z m 5.38125,-21.74375 q 0,-4.76875 -7.9625,-4.76875 l -9.58125,0 q -7.9625,0 -7.9625,4.76875 l 0,13.3875 q 0,4.94375 8.3125,4.94375 l 8.88125,0 q 8.3125,0 8.3125,-4.94375 l 0,-13.3875 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:43.75px;font-family:'Neuropol X';-inkscape-font-specification:'Neuropol X';text-align:start;letter-spacing:5px;word-spacing:0px;text-anchor:start;fill:#263238;fill-opacity:1"
id="path3428" />
<path
d="m -368.0585,631.64323 q -11.2875,0 -11.2875,-6.9125 l 0,-12.73125 q 0,-1.8375 2.31875,-1.8375 2.31875,0 2.31875,1.8375 l 0,12.775 q 0,3.325 6.475,3.325 l 8.3125,0 q 6.475,0 6.475,-3.325 l 0,-12.775 q 0,-1.8375 2.31875,-1.8375 2.3625,0 2.3625,1.8375 l 0,12.73125 q 0,6.9125 -11.2875,6.9125 l -8.00625,0 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:43.75px;font-family:'Neuropol X';-inkscape-font-specification:'Neuropol X';text-align:start;letter-spacing:5px;word-spacing:0px;text-anchor:start;fill:#263238;fill-opacity:1"
id="path3430" />
<path
d="m -327.2833,631.64323 q -9.3625,0 -9.3625,-5.81875 l 0,-2.49375 q 0,-5.775 9.3625,-5.775 l 18.59375,0 0,-0.65625 q 0,-3.0625 -5.38125,-3.0625 l -6.16875,0 q -2.1875,0 -2.1875,-1.70625 0,-1.75 2.1875,-1.75 l 6.16875,0 q 9.93125,0 9.93125,6.51875 l 0,8.575 q 0,6.16875 -9.5375,6.16875 l -13.60625,0 z m 13.34375,-3.4125 q 5.25,0 5.25,-2.8875 l 0,-4.76875 -18.24375,0 q -5.11875,0 -5.11875,2.66875 l 0,2.275 q 0,2.7125 5.11875,2.7125 l 12.99375,0 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:43.75px;font-family:'Neuropol X';-inkscape-font-specification:'Neuropol X';text-align:start;letter-spacing:5px;word-spacing:0px;text-anchor:start;fill:#263238;fill-opacity:1"
id="path3432" />
<path
d="m -262.77031,626.74323 q 0,4.9 -9.975,4.9 l -17.0625,0 q -2.1875,0 -2.1875,-1.70625 0,-1.70625 2.1875,-1.70625 l 17.0625,0 q 5.38125,0 5.38125,-1.4875 l 0,-2.45 q 0,-1.4875 -5.38125,-1.4875 l -9.0125,0 q -9.975,0 -9.975,-4.76875 l 0,-2.05625 q 0,-5.6 10.28125,-5.6 l 5.99375,0 q 2.23125,0 2.23125,1.75 0,0.875 -0.6125,1.3125 -0.56875,0.39375 -1.61875,0.39375 l -5.99375,0 q -5.73125,0 -5.73125,2.14375 l 0,1.925 q 0,1.79375 5.6875,1.79375 l 9.0125,0 q 9.7125,0 9.7125,4.4625 l 0,2.58125 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:43.75px;font-family:'Neuropol X';-inkscape-font-specification:'Neuropol X';text-align:start;letter-spacing:5px;word-spacing:0px;text-anchor:start;fill:#263238;fill-opacity:1"
id="path3434" />
<path
d="m -241.91709,631.64323 q -9.3625,0 -9.3625,-5.81875 l 0,-2.49375 q 0,-5.775 9.3625,-5.775 l 18.59375,0 0,-0.65625 q 0,-3.0625 -5.38125,-3.0625 l -6.16875,0 q -2.1875,0 -2.1875,-1.70625 0,-1.75 2.1875,-1.75 l 6.16875,0 q 9.93125,0 9.93125,6.51875 l 0,8.575 q 0,6.16875 -9.5375,6.16875 l -13.60625,0 z m 13.34375,-3.4125 q 5.25,0 5.25,-2.8875 l 0,-4.76875 -18.24375,0 q -5.11875,0 -5.11875,2.66875 l 0,2.275 q 0,2.7125 5.11875,2.7125 l 12.99375,0 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:43.75px;font-family:'Neuropol X';-inkscape-font-specification:'Neuropol X';text-align:start;letter-spacing:5px;word-spacing:0px;text-anchor:start;fill:#263238;fill-opacity:1"
id="path3436" />
<path
d="m -205.62285,617.33698 q 0,-6.95625 11.2875,-6.95625 l 3.36875,0 q 2.23125,0 2.23125,1.79375 0,1.79375 -2.23125,1.79375 l -3.54375,0 q -6.475,0 -6.475,3.28125 l 0,12.775 q 0,1.8375 -2.31875,1.8375 -2.31875,0 -2.31875,-1.8375 l 0,-12.6875 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:43.75px;font-family:'Neuropol X';-inkscape-font-specification:'Neuropol X';text-align:start;letter-spacing:5px;word-spacing:0px;text-anchor:start;fill:#263238;fill-opacity:1"
id="path3438" />
</g>
</g>
</g>
</g>
<g
id="g5443-0-1-5-1-9"
transform="matrix(0.55595317,0,0,0.55595317,-521.93484,-328.66104)"
inkscape:export-filename="/home/emanuele/Desktop/logo1.png"
inkscape:export-xdpi="44.860481"
inkscape:export-ydpi="44.860481">
<g
inkscape:export-ydpi="3.4165223"
inkscape:export-xdpi="3.4165223"
transform="matrix(0.09527033,0,0,0.09527033,-1695.2716,706.62921)"
id="g8856-6-1-1-9-0-1-9">
<circle
r="1485"
cy="-1361.2571"
cx="8317.3574"
id="circle8858-1-3-7-6-5-3-0"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:50;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:export-xdpi="10.031387"
inkscape:export-ydpi="10.031387" />
<path
inkscape:export-ydpi="10.031387"
inkscape:export-xdpi="10.031387"
style="opacity:1;fill:#263238;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 8560.3823,-1361.3029 a 242.947,242.947 0 0 1 -242.947,242.948 242.947,242.947 0 0 1 -242.947,-242.948 242.947,242.947 0 0 1 242.947,-242.946 242.947,242.947 0 0 1 242.947,242.946 z"
id="path8860-5-4-8-2-9-0-9"
inkscape:connector-curvature="0" />
<path
id="path8862-5-5-9-1-3-6-3"
d="m 9395.8755,-1984.028 a 1245.372,1245.372 0 0 0 -190.8415,-249.4971 l -280.8618,162.1556 c -87.542,-74.7796 -187.0349,-132.0588 -293.2407,-169.9527 -95.8868,97.1766 -172.0602,205.7604 -226.9672,323.8487 312.6411,-21.2772 635.5313,91.8725 935.2898,326.0721 l 176.7612,-102.0532 a 1245.372,1245.372 0 0 0 -120.1398,-290.5734 z"
clip-path="none"
mask="none"
style="fill:#1976d2;fill-opacity:1"
inkscape:connector-curvature="0"
inkscape:transform-center-x="-514.04855"
inkscape:transform-center-y="-444.04649" />
<path
inkscape:transform-center-y="265.80217"
inkscape:transform-center-x="-689.63727"
inkscape:connector-curvature="0"
style="fill:#42a5f5;fill-opacity:1"
mask="none"
clip-path="none"
d="m 9395.9474,-738.70387 a 1245.372,1245.372 0 0 0 120.6501,-290.02213 l -280.8618,-162.1557 c 20.99,-113.2034 20.8488,-228.0063 0.563,-338.9302 -132.1008,-34.4521 -264.2238,-46.1283 -393.9448,-34.635 174.7471,260.1165 238.2017,596.32248 185.2582,973.02076 l 176.7612,102.05309 a 1245.372,1245.372 0 0 0 191.5741,-249.33082 z"
id="path8864-4-8-1-2-4-4-4" />
<path
id="path8866-7-5-5-0-6-4-7"
d="m 8317.501,-115.97954 a 1245.372,1245.372 0 0 0 311.4916,-40.52501 l 0,-324.31131 c 108.5321,-38.42382 207.8837,-95.94755 293.8037,-168.97752 -36.214,-131.6287 -92.1636,-251.88868 -166.9776,-358.48372 -137.894,281.39369 -397.3296,504.44998 -750.0316,646.9487 l 0,204.10623 a 1245.372,1245.372 0 0 0 311.7139,41.24263 z"
clip-path="none"
mask="none"
style="fill:#1976d2;fill-opacity:1"
inkscape:connector-curvature="0"
inkscape:transform-center-x="-117.49007"
inkscape:transform-center-y="639.34029" />
<path
inkscape:transform-center-y="444.04652"
inkscape:transform-center-x="514.04857"
inkscape:connector-curvature="0"
style="fill:#42a5f5;fill-opacity:1"
mask="none"
clip-path="none"
d="m 7238.9827,-738.57936 a 1245.372,1245.372 0 0 0 190.8415,249.49714 l 280.8618,-162.15566 c 87.5421,74.77965 187.0349,132.05879 293.2407,169.95271 95.8868,-97.17659 172.0602,-205.76036 226.9672,-323.8487 -312.6411,21.27714 -635.5313,-91.87254 -935.2898,-326.07203 l -176.7612,102.0531 a 1245.372,1245.372 0 0 0 120.1398,290.57344 z"
id="path8868-6-7-4-7-2-7-3" />
<path
id="path8870-5-3-9-3-5-5-1"
d="m 7238.9108,-1983.9035 a 1245.372,1245.372 0 0 0 -120.6501,290.0221 l 280.8618,162.1557 c -20.99,113.2035 -20.8488,228.0063 -0.563,338.9302 132.1008,34.4521 264.2238,46.1283 393.9448,34.635 -174.7471,-260.1165 -238.2017,-596.3225 -185.2582,-973.0207 l -176.7612,-102.0532 a 1245.372,1245.372 0 0 0 -191.5741,249.3309 z"
clip-path="none"
mask="none"
style="fill:#1976d2;fill-opacity:1"
inkscape:connector-curvature="0"
inkscape:transform-center-x="689.63729"
inkscape:transform-center-y="-265.80221" />
<path
inkscape:transform-center-y="-639.34032"
inkscape:transform-center-x="117.49005"
inkscape:connector-curvature="0"
style="fill:#42a5f5;fill-opacity:1"
mask="none"
clip-path="none"
d="m 8317.3572,-2606.6279 a 1245.372,1245.372 0 0 0 -311.4915,40.525 l -1e-4,324.3113 c -108.5321,38.4239 -207.8837,95.9476 -293.8037,168.9776 36.214,131.6287 92.1637,251.8886 166.9776,358.4837 137.894,-281.3937 397.3296,-504.45 750.0316,-646.9487 l 1e-4,-204.1063 a 1245.372,1245.372 0 0 0 -311.714,-41.2426 z"
id="path8872-6-3-2-1-3-3-7" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

@ -0,0 +1,31 @@
import {
getLocal,
setLocal,
deleteLocal
} from 'src/storage'
export function getJwt () {
return getLocal('jwt')
}
export function hasJwt () {
return getJwt() !== null
}
export function setJwt (jwt) {
setLocal('jwt', jwt)
}
export function deleteJwt () {
deleteLocal('jwt')
deleteLocal('subscriberId')
}
export function setSubscriberId (subscriberId) {
setLocal('subscriberId', subscriberId)
}
export function getSubscriberId () {
return getLocal('subscriberId')
}

@ -0,0 +1,23 @@
import axios from 'axios'
import {
getJwt,
hasJwt
} from 'src/auth'
export default ({ Vue, store, app }) => {
const http = axios.create({
baseURL: app.config.baseHttpUrl
})
http.interceptors.request.use(function (config) {
if (hasJwt()) {
config.headers.Authorization = 'Bearer ' + getJwt()
}
return config
}, function (error) {
return Promise.reject(error)
})
Vue.http = http
Vue.$http = http
store.$http = http
}

@ -0,0 +1,18 @@
import QItemMain from 'src/components/quasar-legacy/QItemMain'
import QItemSide from 'src/components/quasar-legacy/QItemSide'
import QCollapsible from 'src/components/quasar-legacy/QCollapsible'
import QAlert from 'src/components/quasar-legacy/QAlert'
import QResizeObservable from 'src/components/quasar-legacy/QResizeObservable'
import QModal from 'src/components/quasar-legacy/QModal'
import QPopover from 'src/components/quasar-legacy/QPopover'
export default ({ Vue }) => {
Vue.component('q-item-main', QItemMain)
Vue.component('q-item-side', QItemSide)
Vue.component('q-collapsible', QCollapsible)
Vue.component('q-alert', QAlert)
Vue.component('q-resize-observable', QResizeObservable)
Vue.component('q-modal', QModal)
Vue.component('q-popover', QPopover)
}

@ -0,0 +1,13 @@
import Vue from 'vue'
import config from 'src/config'
Vue.use({
install (Vue, options) {
Vue.$config = config
}
})
export default ({ app }) => {
app.config = config
}

@ -0,0 +1,9 @@
export default ({ Vue, app }) => {
Vue.prototype.$faxQualityOptions = [
{ label: app.i18n.t('communication.quality.normal'), value: 'normal' },
{ label: app.i18n.t('communication.quality.fine'), value: 'fine' },
{ label: app.i18n.t('communication.quality.super'), value: 'super' }
]
Vue.prototype.$faxQualityOptionsDefault = Vue.prototype.$faxQualityOptions[0]
}

@ -0,0 +1,31 @@
import Vue from 'vue'
import NumberFilter from 'src/filters/number'
import NumberFormatFilter, {
normalizeDestination
} from 'src/filters/number-format'
import DateFilter, {
smartTime,
time
} from 'src/filters/date'
import {
startCase
} from 'src/filters/string'
import WholeCurrency from 'src/filters/currency'
import {
displayName
} from 'src/filters/subscriber'
export default () => {
Vue.filter('number', NumberFilter)
Vue.filter('readableDate', DateFilter)
Vue.filter('numberFormat', NumberFormatFilter)
Vue.filter('destinationFormat', normalizeDestination)
Vue.filter('smartTime', smartTime)
Vue.filter('startCase', startCase)
Vue.filter('wholeCurrency', WholeCurrency)
Vue.filter('seatName', displayName)
Vue.filter('groupName', displayName)
Vue.filter('displayName', displayName)
Vue.filter('time', time)
}

@ -0,0 +1,31 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import {
messages
} from 'src/i18n'
import {
hasSession,
getSession,
setSession
} from 'src/storage'
Vue.use(VueI18n)
export const defaultLocale = 'en-US'
export const i18n = new VueI18n({
locale: defaultLocale,
fallbackLocale: defaultLocale,
messages
})
export default ({ app, store }) => {
app.i18n = i18n
store.$i18n = i18n
if (!hasSession('locale')) {
setSession('locale', navigator.language)
}
i18n.locale = getSession('locale') + ''
store.commit('user/changeSessionLocaleSucceeded', i18n.locale)
}

@ -0,0 +1,54 @@
import routes from 'src/router/routes'
import _ from 'lodash'
import {
Dark
} from 'quasar'
import {
getJwt, getSubscriberId,
hasJwt
} from 'src/auth'
export default ({ app, router, store }) => {
router.beforeEach((to, from, next) => {
if (!hasJwt() && to.path !== '/login') {
next({
path: '/login'
})
} else if (hasJwt() && to.path === '/login') {
next({
path: '/'
})
} else if (hasJwt() && to.path === '/conference') {
next({
path: '/conference/room123'
})
} else {
next()
}
})
router.afterEach((to, from) => {
const mainTitle = app.i18n.t('title')
let title = _.get(to, 'meta.title', '')
const subTitle = _.get(to, 'meta.subtitle', '')
if (mainTitle !== '') {
title = mainTitle + ' - ' + title
}
if (subTitle !== '') {
title = title + ' - ' + subTitle
}
document.title = title
store.commit('routeChanged', to)
})
if (hasJwt()) {
store.commit('user/loginSucceeded', {
jwt: getJwt(),
subscriberId: getSubscriberId()
})
}
store.$router = router
router.addRoutes(routes(app))
Dark.set(true)
}

@ -0,0 +1,20 @@
import VueResource from 'vue-resource'
import {
getJwt,
hasJwt
} from 'src/auth'
export default ({ Vue, app }) => {
Vue.use(VueResource)
Vue.http.options.root = app.config.baseHttpUrl
Vue.http.interceptors.push(function (request, next) {
if (hasJwt()) {
request.headers.set('Authorization', 'Bearer ' + getJwt())
}
if (request.method === 'POST' && (request.body === undefined || request.body === null)) {
request.body = {}
}
next()
})
}

@ -0,0 +1,6 @@
import VueScrollTo from 'vue-scrollto'
export default ({ Vue }) => {
Vue.use(VueScrollTo)
}

@ -0,0 +1,6 @@
import Vuelidate from 'vuelidate'
export default ({ Vue, store }) => {
Vue.use(Vuelidate)
}

@ -1,41 +1,34 @@
<template>
<div
class="csc-alert-error row no-vert-gutter no-wrap"
>
<div
class="col col-2"
>
<q-icon
name="error"
size="32px"
color="white"
/>
</div>
<div
class="csc-alert-error-text"
>
<slot />
</div>
</div>
<div
class="csc-alert-error row no-vert-gutter no-wrap"
>
<div
class="col col-2"
>
<q-icon
name="error"
size="32px"
color="white"
/>
</div>
<div
class="csc-alert-error-text"
>
<slot />
</div>
</div>
</template>
<script>
import {
QIcon
} from 'quasar-framework'
export default {
name: 'csc-alert-error',
data () {
return {}
},
components: {
QIcon
}
}
export default {
name: 'CscAlertError',
data () {
return {}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables'
.csc-alert-error
background-color $negative
padding $flex-gutter-md

@ -1,41 +1,34 @@
<template>
<div
class="csc-alert-info row no-vert-gutter no-wrap"
>
<div
class="csc-alert-icon ol col-2"
>
<q-icon
name="info"
size="32px"
color="white"
/>
</div>
<div
class="csc-alert-info-text col-10"
>
<slot />
</div>
</div>
<div
class="csc-alert-info row no-vert-gutter no-wrap"
>
<div
class="csc-alert-icon ol col-2"
>
<q-icon
name="info"
size="32px"
color="white"
/>
</div>
<div
class="csc-alert-info-text col-10"
>
<slot />
</div>
</div>
</template>
<script>
import {
QIcon
} from 'quasar-framework'
export default {
name: 'csc-alert-info',
data () {
return {}
},
components: {
QIcon
}
}
export default {
name: 'CscAlertInfo',
data () {
return {}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables'
.csc-alert-info
background-color $info
padding $flex-gutter-md

@ -1,174 +1,181 @@
<template>
<div class="audio-player">
<audio
:src="fileUrl"
ref="audio"
preload="auto"
@timeupdate="timeUpdate"
/>
<div class="control-btns">
<q-btn
v-if="pausable"
:disable="disable"
round
flat
small
color="primary"
:icon="playPauseIcon"
@click="toggle()"
/>
<q-btn
v-else
:disable="disable || playing"
round
flat
small
color="primary"
icon="play_arrow"
@click="playLoad()"
/>
<q-btn
:disable="disable || !pausable && !playing"
round
flat
small
color="primary"
icon="stop"
@click="stop()"
/>
</div>
<q-progress
class="progress-bar"
:percentage="progressPercentage"
stripe
animate
color="primary"
/>
</div>
<q-item
class="no-padding"
>
<audio
ref="audio"
:src="fileUrl"
preload="auto"
@timeupdate="timeUpdate"
/>
<q-item-section
class="no-padding"
side
>
<q-btn
v-if="!playing"
flat
dense
color="primary"
icon="play_arrow"
:disable="disable"
@click="playLoad()"
/>
<q-btn
v-if="playing"
flat
dense
color="primary"
icon="pause"
:disable="disable"
@click="toggle()"
/>
</q-item-section>
<q-item-section
class="no-padding q-mr-sm"
side
>
<q-btn
:disable="disable"
flat
dense
color="primary"
icon="stop"
@click="stop()"
/>
</q-item-section>
<q-item-section
class="no-padding"
>
<q-linear-progress
:value="progressPercentage"
instant-feedback
color="primary"
/>
</q-item-section>
</q-item>
</template>
<script>
import {
QProgress,
QBtn
} from 'quasar-framework'
export default {
name: 'csc-audio-player',
props: [
'fileUrl',
'loaded',
'disable',
'pausable'
],
mounted() {
this.$refs.audio.addEventListener('play', ()=> {
this.playing = true;
});
this.$refs.audio.addEventListener('playing', ()=> {
this.playing = true;
});
this.$refs.audio.addEventListener('ended', ()=> {
this.playing = false;
this.stop();
});
this.$refs.audio.addEventListener('canplay', ()=> {
if (!this.paused && this.playing) {
this.$refs.audio.play();
}
});
},
components: {
QProgress,
QBtn
},
data () {
return {
playing: false,
paused: false,
progressPercentage: 0
}
},
computed: {
playPauseIcon() {
return this.playing ? 'pause': 'play_arrow';
},
isLoaded() {
return this.loaded || this.fileUrl;
}
},
methods: {
play() {
let playPromise = this.$refs.audio.play();
if(playPromise && playPromise.then) {
playPromise.then(()=>{
this.playing = true;
this.paused = false;
this.$emit('playing');
}).catch(()=>{
this.playing = true;
this.paused = false;
this.$emit('loading');
});
}
else {
this.playing = true;
this.paused = false;
this.$emit('playing');
}
},
pause() {
this.$refs.audio.pause();
this.playing = false;
this.paused = true;
},
stop() {
this.$refs.audio.currentTime = 0;
this.pause();
this.$emit('stopped');
},
setPlayingTrue() {
this.playing = true;
},
setPausedFalse() {
this.paused = false;
},
timeUpdate() {
this.progressPercentage = this.$refs.audio.currentTime * 100 / this.$refs.audio.duration;
},
load() {
this.$emit('load');
},
toggle() {
if (this.$refs.audio.paused) {
this.playLoad();
}
else {
this.pause();
}
},
playLoad() {
if (!this.isLoaded) {
this.load();
}
else if (this.$refs.audio.paused) {
this.play();
}
}
},
watch: {
fileUrl() {
if(this.fileUrl) {
this.play();
}
}
}
}
export default {
name: 'CscAudioPlayer',
props: {
fileUrl: {
type: String,
default: null
},
loaded: {
type: Boolean,
default: false
},
disable: {
type: Boolean,
default: false
},
pausable: {
type: Boolean,
default: false
}
},
data () {
return {
playing: false,
paused: false,
progressPercentage: 0
}
},
computed: {
playPauseIcon () {
return this.playing ? 'pause' : 'play_arrow'
},
isLoaded () {
return this.loaded || this.fileUrl
}
},
watch: {
fileUrl () {
if (this.fileUrl) {
this.play()
}
}
},
mounted () {
this.$refs.audio.addEventListener('play', () => {
this.playing = true
})
this.$refs.audio.addEventListener('playing', () => {
this.playing = true
})
this.$refs.audio.addEventListener('ended', () => {
this.playing = false
this.stop()
})
this.$refs.audio.addEventListener('canplay', () => {
if (!this.paused && this.playing) {
this.$refs.audio.play()
}
})
},
methods: {
play () {
const playPromise = this.$refs.audio.play()
if (playPromise && playPromise.then) {
playPromise.then(() => {
this.playing = true
this.paused = false
this.$emit('playing')
}).catch(() => {
this.playing = true
this.paused = false
this.$emit('loading')
})
} else {
this.playing = true
this.paused = false
this.$emit('playing')
}
},
pause () {
this.$refs.audio.pause()
this.playing = false
this.paused = true
},
stop () {
this.$refs.audio.currentTime = 0
this.pause()
this.$emit('stopped')
},
setPlayingTrue () {
this.playing = true
},
setPausedFalse () {
this.paused = false
},
timeUpdate () {
this.progressPercentage = this.$refs.audio.currentTime / this.$refs.audio.duration
},
load () {
this.$emit('load')
},
toggle () {
if (this.$refs.audio.paused) {
this.playLoad()
} else {
this.pause()
}
},
playLoad () {
if (!this.isLoaded) {
this.load()
} else if (this.$refs.audio.paused) {
this.play()
}
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/app.common'
.audio-player
width 100%
display flex

@ -1,111 +1,107 @@
<template>
<div class="csc-dialpad row justify-center">
<div
class="column"
>
<div
v-if="showBackspaceButton || showClearButton"
class="csc-dialpad-btn-group csc-dialpad-btn-group-special"
>
<div
v-if="showBackspaceButton"
class="csc-dialpad-btn"
>
<q-btn
color="primary"
round
small
@click="remove()"
icon="backspace"
/>
</div>
<div
v-if="showClearButton"
class="csc-dialpad-btn"
>
<q-btn
color="primary"
round
small
@click="removeAll()"
icon="cancel"
/>
</div>
</div>
<div
class="csc-dialpad-btn-group"
v-for="(keyRow, rowIndex) in keys"
:key="rowIndex"
>
<div
class="csc-dialpad-btn csc-dialpad-btn-main"
v-for="(key, keyIndex) in keyRow"
:key="rowIndex + ':' + keyIndex"
>
<q-btn
color="default"
round
small
@click="click(key)"
>
{{ key }}
</q-btn>
</div>
</div>
</div>
</div>
<div class="csc-dialpad row justify-center">
<div
class="column"
>
<div
v-if="showBackspaceButton || showClearButton"
class="csc-dialpad-btn-group csc-dialpad-btn-group-special"
>
<div
v-if="showBackspaceButton"
class="csc-dialpad-btn"
>
<q-btn
color="primary"
round
small
icon="backspace"
@click="remove()"
/>
</div>
<div
v-if="showClearButton"
class="csc-dialpad-btn"
>
<q-btn
color="primary"
round
small
icon="cancel"
@click="removeAll()"
/>
</div>
</div>
<div
v-for="(keyRow, rowIndex) in keys"
:key="rowIndex"
class="csc-dialpad-btn-group"
>
<div
v-for="(key, keyIndex) in keyRow"
:key="rowIndex + ':' + keyIndex"
class="csc-dialpad-btn csc-dialpad-btn-main"
>
<q-btn
color="default"
round
small
@click="click(key)"
>
{{ key }}
</q-btn>
</div>
</div>
</div>
</div>
</template>
<script>
import platformMixin from '../mixins/platform'
import {
QBtn,
QIcon
} from 'quasar-framework'
export default {
name: 'csc-call-dialpad',
data () {
return {}
},
props: [
'showBackspaceButton',
'showClearButton'
],
components: {
QBtn,
QIcon
},
mixins: [
platformMixin
],
computed: {
keys() {
return [
['1','2','3'],
['4','5','6'],
['7','8','9'],
['*','0','#'],
['+']
];
}
},
methods: {
click(value) {
this.$emit('click', value);
},
remove() {
this.$emit('remove');
},
removeAll() {
this.$emit('remove-all');
}
}
}
import platformMixin from '../mixins/platform'
export default {
name: 'CscCallDialpad',
mixins: [
platformMixin
],
props: {
showBackspaceButton: {
type: Boolean,
default: false
},
showClearButton: {
type: Boolean,
default: false
}
},
data () {
return {}
},
computed: {
keys () {
return [
['1', '2', '3'],
['4', '5', '6'],
['7', '8', '9'],
['*', '0', '#'],
['+']
]
}
},
methods: {
click (value) {
this.$emit('click', value)
},
remove () {
this.$emit('remove')
},
removeAll () {
this.$emit('remove-all')
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables.styl'
.csc-dialpad
padding 16px
padding-bottom 0

@ -1,12 +1,12 @@
<template>
<csc-dialog
ref="dialog"
:value="value"
:loading="loading"
title-icon="vpn_key"
title="Change password"
ref="dialog"
@input="$emit('input')"
class="csc-pbx-password-dialog"
@input="$emit('input')"
>
<div
slot="content"
@ -34,17 +34,14 @@
</csc-dialog>
</template>
<script>
import {
QBtn
} from 'quasar-framework'
import CscChangePasswordForm from './form/CscChangePasswordForm'
import CscDialog from './CscDialog'
export default {
name: 'csc-change-password-dialog',
name: 'CscChangePasswordDialog',
components: {
CscDialog,
CscChangePasswordForm,
QBtn
CscChangePasswordForm
},
props: {
value: {
@ -60,12 +57,12 @@ export default {
validationSucceeded (payload) {
this.$emit('change-password', payload)
},
open(){
this.$refs.dialog.open();
this.$refs.changePasswordForm.resetForm();
open () {
this.$refs.dialog.open()
this.$refs.changePasswordForm.resetForm()
},
close(){
this.$refs.dialog.close();
close () {
this.$refs.dialog.close()
}
}
}

@ -1,69 +1,78 @@
<template>
<csc-dialog
ref="dialogComp"
:title="title"
:titleIcon="titleIcon"
:opened="opened"
@close="onClose()"
>
<div
slot="content"
>
{{ message }}
</div>
<q-btn
slot="actions"
:icon="titleIcon"
color="primary"
flat
@click="confirm"
>
{{ $t('buttons.confirm') }}
</q-btn>
</csc-dialog>
<csc-dialog
ref="dialogComp"
:title="title"
:title-icon="titleIcon"
:opened="opened"
@close="onClose()"
>
<div
slot="content"
>
{{ message }}
</div>
<q-btn
slot="actions"
:icon="titleIcon"
color="primary"
flat
@click="confirm"
>
{{ $t('buttons.confirm') }}
</q-btn>
</csc-dialog>
</template>
<script>
import {
QBtn
} from 'quasar-framework'
import CscDialog from './CscDialog'
export default {
name: 'csc-confirm-dialog',
data () {
return {
}
},
props: [
'title',
'titleIcon',
'message',
'opened'
],
components: {
QBtn,
CscDialog
},
methods: {
open() {
this.$refs.dialogComp.open();
},
close() {
this.$refs.dialogComp.close();
},
onClose(){
this.$emit('closed');
},
cancel() {
this.close();
this.$emit('cancel');
},
confirm() {
this.close();
this.$emit('confirm');
}
}
}
import CscDialog from './CscDialog'
export default {
name: 'CscConfirmDialog',
components: {
CscDialog
},
props: {
title: {
type: String,
default: ''
},
titleIcon: {
type: String,
default: ''
},
message: {
type: String,
default: ''
},
opened: {
type: Boolean,
default: false
}
},
data () {
return {
}
},
methods: {
open () {
this.$refs.dialogComp.open()
},
close () {
this.$refs.dialogComp.close()
},
onClose () {
this.$emit('closed')
},
cancel () {
this.close()
this.$emit('cancel')
},
confirm () {
this.close()
this.$emit('confirm')
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">

@ -1,105 +1,102 @@
<template>
<q-modal
ref="modal"
minimized
>
<div
class="csc-dialog csc-share-dialog"
>
<div
class="csc-dialog-title"
>
<q-icon
v-if="titleIcon"
:name="titleIcon"
size="24px"
/>
<span
class="csc-dialog-title-text"
>{{ title }}</span>
</div>
<div
class="csc-dialog-content"
>
<slot
name="content"
/>
</div>
<div
class="csc-dialog-actions row justify-end no-wrap"
>
<q-btn
icon="clear"
color="default"
flat
@click="cancel"
>
{{ $t('buttons.cancel') }}
</q-btn>
<slot
name="actions"
/>
</div>
</div>
</q-modal>
<q-dialog
ref="modal"
minimized
>
<div
class="csc-dialog csc-share-dialog"
>
<div
class="csc-dialog-title"
>
<q-icon
v-if="titleIcon"
:name="titleIcon"
size="24px"
/>
<span
class="csc-dialog-title-text"
>{{ title }}</span>
</div>
<div
class="csc-dialog-content"
>
<slot
name="content"
/>
</div>
<div
class="csc-dialog-actions row justify-end no-wrap"
>
<q-btn
icon="clear"
color="default"
flat
@click="cancel"
>
{{ $t('buttons.cancel') }}
</q-btn>
<slot
name="actions"
/>
</div>
</div>
</q-dialog>
</template>
<script>
import {
QModal,
QBtn,
QIcon
} from 'quasar-framework'
export default {
name: 'csc-dialog',
data () {
return {
export default {
name: 'CscDialog',
props: {
title: {
type: String,
default: ''
},
titleIcon: {
type: String,
default: ''
},
opened: {
type: Boolean,
default: false
}
},
data () {
return {
}
},
mounted() {
if(this.opened) {
this.open();
}
},
props: [
'title',
'titleIcon',
'opened'
],
components: {
QModal,
QBtn,
QIcon
},
watch: {
opened(opened) {
if(opened) {
this.open();
}
else {
this.close();
}
}
},
methods: {
open() {
this.$refs.modal.open();
},
close() {
this.$refs.modal.close();
this.$emit('close');
},
cancel() {
this.close();
this.$emit('cancel');
}
}
}
}
},
watch: {
opened (opened) {
if (opened) {
this.open()
} else {
this.close()
}
}
},
mounted () {
if (this.opened) {
this.open()
}
},
methods: {
open () {
this.$refs.modal.show()
},
close () {
this.$refs.modal.hide()
this.$emit('close')
},
cancel () {
this.close()
this.$emit('cancel')
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables.styl'
.csc-dialog
max-width 480px
background-color $body-background

@ -0,0 +1,46 @@
<template>
<q-banner
:class="bannerClasses"
inline-actions
>
<template
v-if="icon !== null && icon !== undefined"
v-slot:avatar
>
<q-icon
:name="icon"
color="dark"
size="24px"
/>
</template>
<slot />
<template
v-slot:action
>
<slot
name="action"
/>
</template>
</q-banner>
</template>
<script>
export default {
name: 'CscInlineAlert',
props: {
icon: {
type: String,
default: null
},
color: {
type: String,
default: 'primary'
}
},
computed: {
bannerClasses () {
return ['text-dark', 'bg-' + this.color]
}
}
}
</script>

@ -0,0 +1,27 @@
<template>
<csc-inline-alert
icon="alert"
color="negative"
v-bind="$attrs"
v-on="$listeners"
>
<slot />
<template
v-slot:action
>
<slot
name="action"
/>
</template>
</csc-inline-alert>
</template>
<script>
import CscInlineAlert from 'components/CscInlineAlert'
export default {
name: 'CscInlineAlertAlert',
components: {
CscInlineAlert
}
}
</script>

@ -0,0 +1,27 @@
<template>
<csc-inline-alert
icon="info"
color="info"
v-bind="$attrs"
v-on="$listeners"
>
<slot />
<template
v-slot:action
>
<slot
name="action"
/>
</template>
</csc-inline-alert>
</template>
<script>
import CscInlineAlert from 'components/CscInlineAlert'
export default {
name: 'CscInlineAlertInfo',
components: {
CscInlineAlert
}
}
</script>

@ -0,0 +1,27 @@
<template>
<csc-inline-alert
icon="warning"
color="warning"
v-bind="$attrs"
v-on="$listeners"
>
<slot />
<template
v-slot:action
>
<slot
name="action"
/>
</template>
</csc-inline-alert>
</template>
<script>
import CscInlineAlert from 'components/CscInlineAlert'
export default {
name: 'CscInlineAlertWarning',
components: {
CscInlineAlert
}
}
</script>

@ -0,0 +1,62 @@
<template>
<q-list
no-border
>
<q-expansion-item
ref="languageCollapsible"
v-model="expanded"
:label="languageLabel"
>
<q-list
no-border
>
<q-item
v-for="(language, index) in languageLabels"
:key="index"
v-close-popup
clickable
@click="changeSessionLanguage(language[0])"
>
<q-item-main
:label="language[1]"
/>
</q-item>
</q-list>
</q-expansion-item>
</q-list>
</template>
<script>
import {
mapActions
} from 'vuex'
export default {
name: 'CscLanguageMenu',
props: {
languageLabel: {
type: String,
required: true
},
languageLabels: {
type: Array,
required: true
}
},
data () {
return {
expanded: false
}
},
methods: {
...mapActions('user', [
'changeSessionLanguage'
])
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.csc-language-selection
.q-item-side-right
color white
</style>

@ -1,22 +1,18 @@
<template>
<div
class="csc-list"
>
<slot />
</div>
<div
class="csc-list"
>
<slot />
</div>
</template>
<script>
export default {
name: "csc-list",
data () {
return {
export default {
name: 'CscList',
data () {
return {
}
}
}
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/app.common';
</style>

@ -1,41 +1,37 @@
<template>
<div
class="csc-list-action-button"
>
<q-btn
dark
flat
:icon="icon"
:color="color"
:disable="disable"
@click="$emit('click')"
>
{{ label }}
</q-btn>
</div>
<q-btn
flat
:icon="icon"
:color="color"
:disable="disable"
:label="label"
@click="$emit('click')"
/>
</template>
<script>
import {
QBtn
} from 'quasar-framework'
export default {
name: 'csc-list-action-button',
components: {
QBtn
},
data () {
return {}
},
props: [
'disable',
'icon',
'color',
'label'
]
}
export default {
name: 'CscListActionButton',
props: {
disable: {
type: Boolean,
default: false
},
icon: {
type: String,
default: ''
},
color: {
type: String,
default: ''
},
label: {
type: String,
default: ''
}
},
data () {
return {}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables.styl'
</style>

@ -1,53 +1,45 @@
<template>
<div
class="csc-list-actions row justify-center"
>
<q-slide-transition
appear
>
<slot
name="slot1"
/>
</q-slide-transition>
<q-slide-transition
appear
>
<slot
name="slot2"
/>
</q-slide-transition>
<q-slide-transition
appear
>
<slot
name="slot3"
/>
</q-slide-transition>
</div>
<div>
<q-slide-transition
appear
>
<slot
name="slot1"
/>
</q-slide-transition>
<q-slide-transition
appear
>
<slot
name="slot2"
/>
</q-slide-transition>
<q-slide-transition
appear
>
<slot
name="slot3"
/>
</q-slide-transition>
</div>
</template>
<script>
import {
QSlideTransition
} from 'quasar-framework'
export default {
name: 'csc-list-actions',
data () {
return {}
},
props: [
'label'
],
components: {
QSlideTransition
},
methods: {
}
}
export default {
name: 'CscListActions',
props: {
label: {
type: String,
default: ''
}
},
data () {
return {}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables.styl'
.csc-list-actions
margin-bottom $flex-gutter-sm
</style>

@ -1,45 +1,36 @@
<template>
<q-slide-transition>
<div
class="csc-add-button row justify-center"
>
<q-btn
color="primary"
icon="add"
flat
@click="click"
>
{{ label }}
</q-btn>
</div>
</q-slide-transition>
<q-slide-transition>
<div
class="csc-add-button row justify-center"
>
<q-btn
color="primary"
icon="add"
flat
@click="click"
>
{{ label }}
</q-btn>
</div>
</q-slide-transition>
</template>
<script>
import {
QSlideTransition,
QBtn
} from 'quasar-framework'
export default {
name: 'csc-list-add-button',
data () {
return {}
},
props: [
'label'
],
components: {
QSlideTransition,
QBtn
},
methods: {
click() {
this.$emit('click');
}
}
}
export default {
name: 'CscListAddButton',
props: {
label: {
type: String,
default: ''
}
},
data () {
return {}
},
methods: {
click () {
this.$emit('click')
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables.styl'
</style>

@ -1,145 +1,136 @@
<template>
<div
:class="itemClasses"
>
<div
class="csc-list-item-head row items-center"
@click="toggle"
>
<div
v-if="!image"
class="csc-list-item-head-icon"
>
<q-icon
:name="icon"
size="24px"
/>
</div>
<div
class="csc-list-item-head-image"
v-if="image"
>
<img
:src="image"
/>
</div>
<div
class="csc-list-item-head-title col"
>
<slot
name="title"
/>
</div>
<div
class="csc-list-item-head-menu"
>
<csc-fade-down>
<q-btn
icon="more_vert"
color="primary"
flat
>
<q-popover
ref="popoverMenu"
>
<q-list
no-border
link
>
<slot
name="menu"
/>
</q-list>
</q-popover>
</q-btn>
</csc-fade-down>
</div>
</div>
<q-slide-transition>
<div
v-if="expanded"
class="csc-list-item-body"
>
<div
class="csc-list-item-body-content"
>
<slot
name="body"
/>
</div>
</div>
</q-slide-transition>
<csc-object-spinner
v-if="loading"
:loading="loading"
/>
</div>
<div
:class="itemClasses"
>
<div
class="csc-list-item-head row items-center"
@click="toggle"
>
<div
v-if="!image"
class="csc-list-item-head-icon"
>
<q-icon
:name="icon"
size="24px"
/>
</div>
<div
v-if="image"
class="csc-list-item-head-image"
>
<img
:src="image"
>
</div>
<div
class="csc-list-item-head-title col"
>
<slot
name="title"
/>
</div>
<div
class="csc-list-item-head-menu"
>
<q-btn
icon="more_vert"
color="primary"
flat
dense
@click.stop="moreMenu=true"
/>
<q-menu
ref="moreMenu"
v-model="moreMenu"
>
<q-list>
<slot
name="menu"
/>
</q-list>
</q-menu>
</div>
</div>
<q-slide-transition>
<div
v-if="expanded"
class="csc-list-item-body"
>
<div
class="csc-list-item-body-content"
>
<slot
name="body"
/>
</div>
</div>
</q-slide-transition>
<csc-object-spinner
v-if="loading"
:loading="loading"
/>
</div>
</template>
<script>
import {
QIcon,
QPopover,
QBtn,
QSlideTransition,
QList
} from 'quasar-framework'
import CscFadeDown from "./transitions/CscFadeDown";
import CscFade from "./transitions/CscFade";
import CscZoom from "./transitions/CscZoom";
import CscFadeIn from "./transitions/CscFadeIn";
import CscObjectSpinner from "./CscObjectSpinner";
export default {
name: "csc-list-item",
props: [
'icon',
'image',
'expanded',
'loading',
'odd'
],
data () {
return {}
},
components: {
CscFade,
CscFadeDown,
CscZoom,
CscFadeIn,
CscObjectSpinner,
QIcon,
QPopover,
QBtn,
QSlideTransition,
QList
},
computed: {
itemClasses() {
let classes = ['csc-list-item', 'transition-generic'];
if(this.expanded) {
classes.push('csc-list-item-expanded');
}
if(this.odd) {
classes.push('csc-list-item-background');
}
return classes;
}
},
methods: {
toggle() {
this.$emit('toggle', !this.expanded);
},
closePopoverMenu() {
if(this.$refs.popoverMenu) {
this.$refs.popoverMenu.close();
}
}
}
}
import CscObjectSpinner from './CscObjectSpinner'
export default {
name: 'CscListItem',
components: {
CscObjectSpinner
},
props: {
icon: {
type: String,
default: ''
},
image: {
type: String,
default: ''
},
expanded: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
odd: {
type: Boolean,
default: false
}
},
data () {
return {
moreMenu: false
}
},
computed: {
itemClasses () {
const classes = ['csc-list-item', 'transition-generic']
if (this.expanded) {
classes.push('csc-list-item-expanded')
}
if (this.odd) {
classes.push('csc-list-item-background')
}
return classes
}
},
methods: {
toggle () {
this.$emit('toggle', !this.expanded)
},
closePopoverMenu () {
this.moreMenu = false
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/app.common';
.csc-list-item-title-value,
.csc-list-item-title-keyword
margin-right $flex-gutter-xs

@ -1,19 +1,18 @@
<template>
<div
class="csc-list-item-subtitle"
>
<slot
/>
</div>
<div
class="csc-list-item-subtitle"
>
<slot />
</div>
</template>
<script>
export default {
name: 'csc-list-item-subtitle',
data () {
return {}
}
}
export default {
name: 'CscListItemSubtitle',
data () {
return {}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">

@ -1,35 +1,34 @@
<template>
<div
class="csc-list-item-title"
>
<q-icon
v-if="icon"
:name="icon"
:color="iconColor"
size="24px"
/>
<slot
/>
</div>
<div
class="csc-list-item-title"
>
<q-icon
v-if="icon"
:name="icon"
:color="iconColor"
size="24px"
/>
<slot />
</div>
</template>
<script>
import {
QIcon
} from 'quasar-framework'
export default {
name: 'csc-list-item-title',
props: [
'icon',
'iconColor'
],
components: {
QIcon
},
data () {
return {}
}
}
export default {
name: 'CscListItemTitle',
props: {
icon: {
type: String,
default: ''
},
iconColor: {
type: String,
default: ''
}
},
data () {
return {}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">

@ -1,44 +1,45 @@
<template>
<q-item
@click="click"
>
<q-item-side
:icon="icon"
:color="iconColor"
/>
<q-item-main>
<slot />
</q-item-main>
</q-item>
<q-item
v-close-popup
clickable
@click="click"
>
<q-item-section
side
>
<q-icon
:name="icon"
:color="iconColor"
/>
</q-item-section>
<q-item-section>
<slot />
</q-item-section>
</q-item>
</template>
<script>
import {
QItem,
QItemSide,
QItemMain
} from 'quasar-framework'
export default {
name: 'csc-list-menu-item',
data () {
return {}
},
props: [
'icon',
'iconColor',
'popover'
],
components: {
QItem,
QItemSide,
QItemMain
},
methods: {
click() {
this.$emit('click');
}
}
}
export default {
name: 'CscListMenuItem',
props: {
icon: {
type: String,
default: ''
},
iconColor: {
type: String,
default: ''
}
},
data () {
return {}
},
methods: {
click () {
this.$emit('click')
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">

@ -1,24 +1,22 @@
<template>
<div
class="row justify-center"
>
<csc-spinner />
</div>
<div
class="row justify-center"
>
<csc-spinner
size="48px"
/>
</div>
</template>
<script>
import CscSpinner from './CscSpinner'
export default {
name: 'csc-list-spinner',
data () {
return {}
},
components: {
CscSpinner
}
}
import CscSpinner from './CscSpinner'
export default {
name: 'CscListSpinner',
components: {
CscSpinner
},
data () {
return {}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables.styl'
</style>

File diff suppressed because one or more lines are too long

@ -0,0 +1,95 @@
<template>
<q-list>
<template
v-for="(item, index) in items"
>
<q-expansion-item
v-if="item.visible && item.children && item.children.length > 0"
:key="index"
:label="item.label"
:icon="item.icon"
:content-inset-level="1"
group="cscMainMenu"
class="text-weight-bold"
>
<q-list>
<template
v-for="(child, childIndex) in item.children"
>
<q-item
v-if="child.visible"
:key="childIndex"
:to="child.to"
>
<q-item-section
avatar
>
<q-icon
:name="child.icon"
/>
</q-item-section>
<q-item-section
no-wrap
>
<q-item-label
class="text-weight-bold"
>
{{ child.label }}
</q-item-label>
<q-item-label
v-if="child.sublabel !== undefined"
class="text-weight-light text-subtitle2"
>
{{ child.sublabel }}
</q-item-label>
</q-item-section>
</q-item>
</template>
</q-list>
</q-expansion-item>
<q-item
v-else-if="item.visible"
:key="index"
:to="item.to"
>
<q-item-section
avatar
>
<q-icon
:name="item.icon"
/>
</q-item-section>
<q-item-section
no-wrap
>
<q-item-label
class="text-weight-bold"
>
{{ item.label }}
</q-item-label>
<q-item-label
v-if="item.sublabel !== undefined"
class="text-weight-light text-subtitle2"
>
{{ item.sublabel }}
</q-item-label>
</q-item-section>
</q-item>
</template>
</q-list>
</template>
<script>
export default {
name: 'CscMainMenu',
props: {
items: {
type: Array,
default: () => []
}
},
data () {
return {}
}
}
</script>

@ -0,0 +1,74 @@
<template>
<div>
<div
v-if="!menuMinimized"
class="q-pr-md q-pl-md q-pt-xs q-pb-xs text-subtitle2"
>
{{ $t('navigation.newFeatures.header.title') }}
</div>
<csc-main-menu
:items="items"
/>
</div>
</template>
<script>
import {
mapGetters
} from 'vuex'
import CscMainMenu from 'components/CscMainMenu'
export default {
name: 'CscMainMenuNewFeatures',
components: {
CscMainMenu
},
props: {
callStateTitle: {
type: String,
default: ''
},
callStateSubtitle: {
type: String,
default: ''
},
isCallForward: {
type: Boolean,
default: false
},
isCallBlocking: {
type: Boolean,
default: false
},
isPbxAdmin: {
type: Boolean,
default: false
},
isPbxConfiguration: {
type: Boolean,
default: false
},
menuMinimized: {
type: Boolean,
default: false
}
},
data () {
return {}
},
computed: {
...mapGetters('user', [
'isRtcEngineUiVisible'
]),
items () {
return [
{
to: '/user/new-call-forward',
icon: 'phone_forwarded',
label: this.$t('navigation.callForward.title'),
visible: true
}
]
}
}
}
</script>

@ -0,0 +1,190 @@
<template>
<csc-main-menu
:items="items"
/>
</template>
<script>
import {
mapGetters
} from 'vuex'
import CscMainMenu from 'components/CscMainMenu'
export default {
name: 'CscMainMenuTop',
components: {
CscMainMenu
},
props: {
callStateTitle: {
type: String,
default: ''
},
callStateSubtitle: {
type: String,
default: ''
},
isCallForward: {
type: Boolean,
default: false
},
isCallBlocking: {
type: Boolean,
default: false
},
isPbxAdmin: {
type: Boolean,
default: false
},
isPbxConfiguration: {
type: Boolean,
default: false
}
},
data () {
return {}
},
computed: {
...mapGetters('user', [
'isRtcEngineUiVisible'
]),
items () {
return [
{
to: '/user/home',
icon: 'call',
label: this.callStateTitle,
sublabel: this.callStateSubtitle,
visible: this.isRtcEngineUiVisible
},
{
to: '/conference',
icon: 'videocam',
label: this.$t('navigation.conference.title'),
visible: this.isRtcEngineUiVisible
},
{
to: '/user/conversations',
icon: 'question_answer',
label: this.$t('navigation.conversations.title'),
sublabel: this.$t('navigation.conversations.subTitle'),
visible: true
},
{
icon: 'phone_forwarded',
label: this.$t('navigation.callForward.title'),
opened: this.isCallForward,
visible: true,
children: [
{
to: '/user/call-forward/always',
icon: 'check_circle',
label: this.$t('navigation.callForward.always'),
visible: true
},
{
to: '/user/call-forward/company-hours',
icon: 'schedule',
label: this.$t('navigation.callForward.companyHours'),
visible: true
},
{
to: '/user/call-forward/after-hours',
icon: 'watch_later',
label: this.$t('navigation.callForward.afterHours'),
visible: true
}
]
},
{
icon: 'block',
label: this.$t('navigation.callBlocking.title'),
opened: this.isCallBlocking,
visible: true,
children: [
{
to: '/user/call-blocking/incoming',
icon: 'call_received',
label: this.$t('navigation.callBlocking.incoming'),
visible: true
},
{
to: '/user/call-blocking/outgoing',
icon: 'call_made',
label: this.$t('navigation.callBlocking.outgoing'),
visible: true
},
{
to: '/user/call-blocking/privacy',
icon: 'fas fa-user-secret',
label: this.$t('navigation.callBlocking.privacy'),
visible: true
}
]
},
{
to: '/user/reminder',
icon: 'notification_important',
label: this.$t('navigation.reminder.title'),
visible: true
},
{
to: '/user/speeddial',
icon: 'touch_app',
label: this.$t('navigation.speeddial.title'),
visible: true
},
{
to: '/user/voicebox',
icon: 'voicemail',
label: this.$t('navigation.voicebox.title'),
visible: true
},
{
icon: 'miscellaneous_services',
label: this.$t('navigation.pbxConfiguration.title'),
visible: this.isPbxAdmin,
opened: this.isPbxConfiguration,
children: [
{
to: '/user/pbx-configuration/seats',
icon: 'person',
label: this.$t('navigation.pbxConfiguration.seats'),
visible: true
},
{
to: '/user/pbx-configuration/groups',
icon: 'group',
label: this.$t('navigation.pbxConfiguration.groups'),
visible: true
},
{
to: '/user/pbx-configuration/devices',
icon: 'fas fa-fax',
label: this.$t('navigation.pbxConfiguration.devices'),
visible: true
},
{
to: '/user/pbx-configuration/call-queues',
icon: 'filter_none',
label: this.$t('navigation.pbxConfiguration.callQueues'),
visible: true
},
{
to: '/user/pbx-configuration/sound-sets',
icon: 'queue_music',
label: this.$t('navigation.pbxConfiguration.soundSets'),
visible: true
},
{
to: '/user/pbx-configuration/ms-configs',
icon: 'arrow_forward',
label: this.$t('navigation.pbxConfiguration.msConfigs'),
visible: true
}
]
}
]
}
}
}
</script>

@ -1,215 +1,208 @@
<template>
<div
:class="componentClasses"
:style="componentStyles"
>
<div
v-show="loading"
class="csc-media-spinner"
>
<q-spinner-dots
color="primary"
:size="24"
/>
</div>
<video
ref="media"
class="csc-media-video"
autoplay
playsinline
:width="mediaWidth"
:height="mediaHeight"
:style="mediaStyles"
:muted="muted"
@click="fitMedia"
@resize="fitMedia"
></video>
</div>
<div
:class="componentClasses"
:style="componentStyles"
>
<div
v-show="loading"
class="csc-media-spinner"
>
<q-spinner-dots
color="primary"
:size="24"
/>
</div>
<video
ref="media"
class="csc-media-video"
autoplay
playsinline
:width="mediaWidth"
:height="mediaHeight"
:style="mediaStyles"
:muted="muted"
@click="fitMedia"
@resize="fitMedia"
/>
</div>
</template>
<script>
import _ from 'lodash';
import {
QSpinnerDots,
QIcon
} from 'quasar-framework'
export default {
name: 'csc-media',
props: [
'stream',
'muted',
'preview',
'width'
],
data () {
return {
loading: true,
mediaHeight: 0,
mediaWidth: 0,
mediaTop: 0,
mediaLeft: 0
}
},
mounted () {
this.assignStream(this.stream);
let fitMedia = ()=>{ this.fitMedia(); };
this.$root.$on('window-resized', fitMedia);
this.$root.$on('content-resized', fitMedia);
this.$root.$on('orientation-changed', fitMedia);
this.$refs.media.addEventListener('playing', ()=>{
this.loading = false;
this.fitMedia();
});
},
components: {
QSpinnerDots,
QIcon
},
methods: {
reset() {
if (this.$refs.media) {
this.$refs.media.pause();
this.$refs.media.srcObject = null;
this.$refs.media.load();
}
},
assignStream(stream) {
if(stream !== null && stream !== undefined) {
this.loading = true;
if(_.isObject(stream) && _.isObject(this.$refs.media) &&
!_.isUndefined(this.$refs.media.srcObject)) {
this.$refs.media.srcObject = stream;
}
else if(_.isObject(stream) && _.isObject(this.$refs.media) &&
!_.isUndefined(this.$refs.media.mozSrcObject)) {
this.$refs.media.mozSrcObject = stream;
}
else if(_.isObject(stream) && _.isObject(this.$refs.media) &&
_.isObject(URL) && _.isFunction(URL.createObjectURL)) {
this.$refs.media.src = URL.createObjectURL(stream);
}
}
},
fitMediaToParent() {
if(this.$refs.media && this.$refs.media &&
this.$refs.media.videoWidth && this.$refs.media.videoHeight &&
typeof(this.$refs.media.videoWidth) === 'number' &&
typeof(this.$refs.media.videoHeight) === 'number') {
let parentAspectRatio = this.$parent.$el.clientWidth / this.$parent.$el.clientHeight;
let isParentLandscape = parentAspectRatio >= 1;
let isParentPortrait = !isParentLandscape;
let videoAspectRatio = this.$refs.media.videoWidth / this.$refs.media.videoHeight;
let isVideoLandscape = videoAspectRatio >= 1;
let isVideoPortrait = !isVideoLandscape;
if(isParentLandscape && isVideoLandscape && parentAspectRatio > videoAspectRatio) {
this.mediaWidth = this.$parent.$el.clientWidth;
this.mediaHeight = this.$parent.$el.clientWidth / videoAspectRatio;
this.mediaLeft = 0;
this.mediaTop = (this.$parent.$el.clientHeight - this.mediaHeight) / 2;
}
else if (isParentLandscape && isVideoLandscape && parentAspectRatio < videoAspectRatio) {
this.mediaWidth = this.$parent.$el.clientHeight * videoAspectRatio;
this.mediaHeight = this.$parent.$el.clientHeight;
this.mediaLeft = (this.$parent.$el.clientWidth - this.mediaWidth) / 2;
this.mediaTop = 0;
}
else if (isParentLandscape && isVideoPortrait) {
this.mediaWidth = this.$parent.$el.clientHeight * videoAspectRatio;
this.mediaHeight = this.$parent.$el.clientHeight;
this.mediaLeft = (this.$parent.$el.clientWidth - this.mediaWidth) / 2;
this.mediaTop = 0;
}
else if(isParentPortrait && isVideoPortrait && parentAspectRatio < videoAspectRatio) {
this.mediaWidth = this.$parent.$el.clientHeight * videoAspectRatio;
this.mediaHeight = this.$parent.$el.clientHeight;
this.mediaLeft = (this.$parent.$el.clientWidth - this.mediaWidth) / 2;
this.mediaTop = 0;
}
else if(isParentPortrait && isVideoPortrait && parentAspectRatio > videoAspectRatio) {
this.mediaWidth = this.$parent.$el.clientWidth;
this.mediaHeight = this.$parent.$el.clientWidth / videoAspectRatio;
this.mediaLeft = 0;
this.mediaTop = (this.$parent.$el.clientHeight - this.mediaHeight) / 2;
}
else if (isParentPortrait && isVideoLandscape) {
this.mediaWidth = this.$parent.$el.clientWidth;
this.mediaHeight = this.$parent.$el.clientWidth / videoAspectRatio;
this.mediaLeft = 0;
this.mediaTop = (this.$parent.$el.clientHeight - this.mediaHeight) / 2;
}
else {
this.mediaWidth = this.$parent.$el.clientWidth;
this.mediaHeight = this.$parent.$el.clientHeight;
this.mediaLeft = 0;
this.mediaTop = 0;
}
}
},
fitMediaHeightToParent() {
if(this.$refs.media && this.$refs.media &&
this.$refs.media.videoWidth && this.$refs.media.videoHeight &&
typeof(this.$refs.media.videoWidth) === 'number' &&
typeof(this.$refs.media.videoHeight) === 'number') {
let videoAspectRatio = this.$refs.media.videoWidth / this.$refs.media.videoHeight;
this.mediaWidth = this.width;
this.mediaHeight = this.mediaWidth / videoAspectRatio;
this.mediaLeft = 0;
this.mediaTop = 0;
}
},
fitMedia() {
if(this.preview) {
this.fitMediaHeightToParent();
}
else {
this.fitMediaToParent();
}
},
toggleAudio(muted){
this.$refs.media.muted = muted;
}
},
watch: {
stream(stream) {
this.assignStream(stream);
},
muted(muted) {
this.$refs.media.muted = muted;
},
preview() {
this.$nextTick(()=>{
this.fitMedia();
});
}
},
computed: {
componentClasses(){
return ['csc-media'];
},
mediaStyles() {
let styles = {};
styles.left = this.mediaLeft + 'px';
styles.top = this.mediaTop + 'px';
return styles;
},
componentStyles() {
let styles = {};
if(this.preview) {
styles.width = this.mediaWidth + 'px';
styles.height = this.mediaHeight + 'px';
}
else {
styles.width = '100%';
styles.height = '100%';
}
return styles;
}
}
}
import _ from 'lodash'
export default {
name: 'CscMedia',
props: {
stream: {
type: MediaStream,
default: null
},
muted: {
type: Boolean,
default: false
},
preview: {
type: Boolean,
default: false
},
width: {
type: Number,
default: null
}
},
data () {
return {
loading: true,
mediaHeight: 0,
mediaWidth: 0,
mediaTop: 0,
mediaLeft: 0
}
},
computed: {
componentClasses () {
return ['csc-media']
},
mediaStyles () {
const styles = {}
styles.left = this.mediaLeft + 'px'
styles.top = this.mediaTop + 'px'
return styles
},
componentStyles () {
const styles = {}
if (this.preview) {
styles.width = this.mediaWidth + 'px'
styles.height = this.mediaHeight + 'px'
} else {
styles.width = '100%'
styles.height = '100%'
}
return styles
}
},
watch: {
stream (stream) {
this.assignStream(stream)
},
muted (muted) {
this.$refs.media.muted = muted
},
preview () {
this.$nextTick(() => {
this.fitMedia()
})
}
},
mounted () {
this.assignStream(this.stream)
const fitMedia = () => { this.fitMedia() }
this.$root.$on('window-resized', fitMedia)
this.$root.$on('content-resized', fitMedia)
this.$root.$on('orientation-changed', fitMedia)
this.$refs.media.addEventListener('playing', () => {
this.loading = false
this.fitMedia()
})
},
methods: {
reset () {
if (this.$refs.media) {
this.$refs.media.pause()
this.$refs.media.srcObject = null
this.$refs.media.load()
}
},
assignStream (stream) {
if (stream !== null && stream !== undefined) {
this.loading = true
if (_.isObject(stream) && _.isObject(this.$refs.media) &&
!_.isUndefined(this.$refs.media.srcObject)) {
this.$refs.media.srcObject = stream
} else if (_.isObject(stream) && _.isObject(this.$refs.media) &&
!_.isUndefined(this.$refs.media.mozSrcObject)) {
this.$refs.media.mozSrcObject = stream
} else if (_.isObject(stream) && _.isObject(this.$refs.media) &&
_.isObject(URL) && _.isFunction(URL.createObjectURL)) {
this.$refs.media.src = URL.createObjectURL(stream)
}
}
},
fitMediaToParent () {
if (this.$refs.media && this.$refs.media &&
this.$refs.media.videoWidth && this.$refs.media.videoHeight &&
typeof (this.$refs.media.videoWidth) === 'number' &&
typeof (this.$refs.media.videoHeight) === 'number') {
const parentAspectRatio = this.$parent.$el.clientWidth / this.$parent.$el.clientHeight
const isParentLandscape = parentAspectRatio >= 1
const isParentPortrait = !isParentLandscape
const videoAspectRatio = this.$refs.media.videoWidth / this.$refs.media.videoHeight
const isVideoLandscape = videoAspectRatio >= 1
const isVideoPortrait = !isVideoLandscape
if (isParentLandscape && isVideoLandscape && parentAspectRatio > videoAspectRatio) {
this.mediaWidth = this.$parent.$el.clientWidth
this.mediaHeight = this.$parent.$el.clientWidth / videoAspectRatio
this.mediaLeft = 0
this.mediaTop = (this.$parent.$el.clientHeight - this.mediaHeight) / 2
} else if (isParentLandscape && isVideoLandscape && parentAspectRatio < videoAspectRatio) {
this.mediaWidth = this.$parent.$el.clientHeight * videoAspectRatio
this.mediaHeight = this.$parent.$el.clientHeight
this.mediaLeft = (this.$parent.$el.clientWidth - this.mediaWidth) / 2
this.mediaTop = 0
} else if (isParentLandscape && isVideoPortrait) {
this.mediaWidth = this.$parent.$el.clientHeight * videoAspectRatio
this.mediaHeight = this.$parent.$el.clientHeight
this.mediaLeft = (this.$parent.$el.clientWidth - this.mediaWidth) / 2
this.mediaTop = 0
} else if (isParentPortrait && isVideoPortrait && parentAspectRatio < videoAspectRatio) {
this.mediaWidth = this.$parent.$el.clientHeight * videoAspectRatio
this.mediaHeight = this.$parent.$el.clientHeight
this.mediaLeft = (this.$parent.$el.clientWidth - this.mediaWidth) / 2
this.mediaTop = 0
} else if (isParentPortrait && isVideoPortrait && parentAspectRatio > videoAspectRatio) {
this.mediaWidth = this.$parent.$el.clientWidth
this.mediaHeight = this.$parent.$el.clientWidth / videoAspectRatio
this.mediaLeft = 0
this.mediaTop = (this.$parent.$el.clientHeight - this.mediaHeight) / 2
} else if (isParentPortrait && isVideoLandscape) {
this.mediaWidth = this.$parent.$el.clientWidth
this.mediaHeight = this.$parent.$el.clientWidth / videoAspectRatio
this.mediaLeft = 0
this.mediaTop = (this.$parent.$el.clientHeight - this.mediaHeight) / 2
} else {
this.mediaWidth = this.$parent.$el.clientWidth
this.mediaHeight = this.$parent.$el.clientHeight
this.mediaLeft = 0
this.mediaTop = 0
}
}
},
fitMediaHeightToParent () {
if (this.$refs.media && this.$refs.media &&
this.$refs.media.videoWidth && this.$refs.media.videoHeight &&
typeof (this.$refs.media.videoWidth) === 'number' &&
typeof (this.$refs.media.videoHeight) === 'number') {
const videoAspectRatio = this.$refs.media.videoWidth / this.$refs.media.videoHeight
this.mediaWidth = this.width
this.mediaHeight = this.mediaWidth / videoAspectRatio
this.mediaLeft = 0
this.mediaTop = 0
}
},
fitMedia () {
if (this.preview) {
this.fitMediaHeightToParent()
} else {
this.fitMediaToParent()
}
},
toggleAudio (muted) {
this.$refs.media.muted = muted
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../themes/quasar.variables'
.csc-media
position relative
overflow hidden

@ -0,0 +1,22 @@
<template>
<q-btn
icon="more_vert"
color="primary"
flat
dense
@click.stop.prevent
>
<csc-popup-menu>
<slot />
</csc-popup-menu>
</q-btn>
</template>
<script>
import CscPopupMenu from 'components/CscPopupMenu'
export default {
name: 'CscMoreMenu',
components: {
CscPopupMenu
}
}
</script>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save