TT#20518 PBXConfig: As a Customer, I want to see a list of all PBX Devices

Change-Id: Ia7971b4e1b6183b6aa5b2ad90ce4f1883371763e
changes/47/20647/3
Hans-Peter Herzog 8 years ago
parent f128aece3d
commit d5e7a0bdea

@ -0,0 +1,69 @@
'use strict';
import _ from 'lodash';
import Vue from 'vue';
import { getJsonBody } from './utils'
export function getAllDevices(options) {
return new Promise((resolve, reject)=>{
let rows = _.get(options, 'rows', 25);
let page = _.get(options, 'page', 1);
Vue.http.get('/api/pbxdevices/', null, {
params: {
rows: rows,
page: page
}
}).then((result)=>{
let body = getJsonBody(result.body);
let totalCount = body.totalCount;
let lastPage = Math.ceil(totalCount / rows);
let items = _.get(body, '_embedded.ngcp:pbxdevices');
resolve({
lastPage: lastPage,
items: items
});
}).catch((err)=>{
reject(err);
});
});
}
export function getAllProfiles() {
return new Promise((resolve, reject)=>{
Vue.http.get('/api/pbxdeviceprofiles/').then((result)=>{
let body = getJsonBody(result.body);
resolve(_.get(body, '_embedded.ngcp:pbxdeviceprofiles'));
}).catch((err)=>{
reject(err);
});
});
}
export function getAllModels() {
return new Promise((resolve, reject)=>{
Vue.http.get('/api/pbxdevicemodels/').then((result)=>{
let body = getJsonBody(result.body);
resolve(_.get(body, '_embedded.ngcp:pbxdevicemodels'));
}).catch((err)=>{
reject(err);
});
});
}
export function getDeviceList() {
return new Promise((resolve, reject)=>{
Promise.all([
getAllDevices(),
getAllProfiles(),
getAllModels()
]).then((results)=>{
resolve({
devices: results[0],
profiles: results[1],
models: results[2]
});
}).catch((err)=>{
reject(err);
});
});
}

@ -47,7 +47,7 @@
.page {
position: relative;
padding: 30px;
padding: 60px;
padding-top: 100px;
margin: 0px;
}
@ -61,6 +61,7 @@
.page .page-title {
padding: 30px;
padding-left: 60px;
z-index: 1000;
right: 0;
background: -moz-linear-gradient(top, rgba(255,255,255,1) 44%, rgba(255,255,255,0.86) 71%, rgba(255,255,255,0) 100%);

@ -0,0 +1,71 @@
<template>
<q-card class="csc-entity csc-pbx-device shadow-1">
<q-card-title>
<q-icon name="fa-fax" color="secondary" size="24px"/>
<span class="csc-entity-title-text">{{ device.station_name }}</span>
<q-btn :icon="titleIcon" :small="isMobile" color="primary" slot="right" flat @click="toggleMain()" />
</q-card-title>
<q-card-main v-if="expanded">
<q-field :label="$t('pbxConfig.deviceStationName')">
<q-input v-model="device.station_name" readonly />
</q-field>
<q-field :label="$t('pbxConfig.deviceIdentifier')">
<q-input v-model="device.identifier" readonly />
</q-field>
<q-field :label="$t('pbxConfig.deviceModel')">
<q-select v-model="device.model.id" :options="modelOptions" clearable disable />
</q-field>
</q-card-main>
</q-card>
</template>
<script>
import { QCard, QCardTitle, QCardMain, QCollapsible,
QIcon, QField, QInput, QSelect, QBtn } from 'quasar-framework'
export default {
name: 'csc-pbx-device',
props: {
device: {
type: Object,
required: true
},
modelOptions: {
type: Object,
required: true
},
loading: {
type: Boolean,
default: false
}
},
components: {
QCard, QCardTitle, QCardMain, QCollapsible,
QIcon, QField, QInput, QSelect, QBtn
},
data () {
return {
expanded: false
}
},
computed: {
titleIcon() {
if(!this.expanded) {
return 'keyboard arrow down';
}
else {
return 'keyboard arrow up';
}
}
},
methods: {
toggleMain() {
this.expanded = !this.expanded;
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/app.common'
</style>

@ -0,0 +1,44 @@
<template>
<csc-page :title="$t('pbxConfig.devicesTitle')">
<div v-if="isListLoadingVisible" class="row justify-center">
<q-spinner-dots color="primary" :size="40" />
</div>
<csc-pbx-device v-for="device in devices" :key="device.id"
:device="device" :modelOptions="modelOptions" />
<div v-if="devices.length === 0 && !isListRequesting" class="row justify-center csc-no-entities">
{{ $t('pbxConfig.noDevices') }}
</div>
</csc-page>
</template>
<script>
import { mapGetters } from 'vuex'
import CscPage from '../../CscPage'
import CscPbxDevice from './CscPbxDevice'
import { QSpinnerDots } from 'quasar-framework'
export default {
data () {
return {
}
},
mounted() {
this.$store.dispatch('pbxConfig/listDevices');
},
components: {
CscPage,
CscPbxDevice,
QSpinnerDots
},
computed: {
...mapGetters('pbxConfig', [
'devices',
'modelOptions',
'isListRequesting',
'isListLoadingVisible'
])
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
</style>

@ -1,12 +1,13 @@
<template>
<q-card class="csc-pbx-group">
<q-card-title class="cursor-pointer" @click="toggleMain()">
<q-icon name="group" color="primary" size="24px"/>
<span v-if="!expanded" class="csc-pbx-group-title">{{ group.display_name }}</span>
<q-chip v-if="!expanded" pointing="left" color="primary" class="gt-md">
<q-card class="csc-entity csc-pbx-group shadow-1">
<q-card-title class="csc-entity-title">
<q-icon name="group" color="secondary" size="24px"/>
<span class="csc-entity-title-text">{{ group.display_name }}</span>
<q-chip v-if="!expanded" pointing="left" color="primary" class="gt-md cursor-pointer">
{{ $t('pbxConfig.extension') }}: <span class="csc-important">{{ group.pbx_extension }}</span>
</q-chip>
<q-icon :name="titleIcon" color="primary" size="22px" slot="right"/>
<q-btn :icon="titleIcon" :small="isMobile" color="primary" slot="right" flat @click="toggleMain()" />
<q-btn icon="delete" :small="isMobile" color="negative" slot="right" flat @click="remove()" />
</q-card-title>
<q-card-main v-if="expanded" class="transition-generic">
<q-field :label="$t('pbxConfig.groupName')">
@ -36,10 +37,6 @@
:after="seatButtons" @change="seatChange" />
</q-field>
</q-card-main>
<q-card-actions align="center">
<q-btn flat :small="isMobile" :round="isMobile"
color="negative" icon="delete" @click="remove()">Delete</q-btn>
</q-card-actions>
<q-inner-loading :visible="isLoading">
<q-spinner-mat size="60px" color="primary"></q-spinner-mat>
</q-inner-loading>
@ -130,7 +127,7 @@
return this.loading;
},
titleIcon() {
if(this.expanded) {
if(!this.expanded) {
return 'keyboard arrow down';
}
else {
@ -301,12 +298,7 @@
},
methods: {
toggleMain() {
if(this.expanded) {
this.expanded = false;
}
else {
this.expanded = true;
}
this.expanded = !this.expanded;
},
remove() {
this.$emit('remove', this.groupModel);
@ -395,13 +387,5 @@
</script>
<style lang="stylus" rel="stylesheet/stylus">
.csc-pbx-group {
position: relative;
}
.csc-pbx-group .csc-pbx-group-title {
padding-left: 8px;
}
.csc-important {
font-weight: bold;
}
@import '../../../themes/app.common'
</style>

@ -1,5 +1,5 @@
<template>
<q-card class="csc-pbx-group-add-form">
<q-card class="csc-pbx-group-add-form shadow-1">
<q-card-title>
<q-icon name="add" color="primary" size="22px"/>
<span>{{ $t('pbxConfig.addGroup') }}</span>

@ -1,25 +1,22 @@
<template>
<csc-page id="csc-page-pbx-groups" title="Groups">
<csc-page :title="$t('pbxConfig.groupsTitle')">
<csc-pbx-group-add-form v-show="addFormEnabled" ref="addForm" @save="addGroup" @cancel="disableAddForm"
:loading="isAdding" :alias-number-options="aliasNumberOptions"
:seat-options="seatOptions" :hunt-policy-options="huntPolicyOptions"/>
<q-card v-show="!addFormEnabled" flat>
<q-card-actions align="center">
<q-btn color="primary" icon="add" flat @click="enableAddForm">
{{ $t('pbxConfig.addGroup') }}
</q-btn>
</q-card-actions>
</q-card>
<q-card v-if="isListRequesting && !listLoadingSilently" flat>
<q-card-actions align="center">
<q-spinner-dots color="primary" :size="40"/>
</q-card-actions>
</q-card>
<div v-show="!addFormEnabled" class="row justify-center ">
<q-btn color="primary" icon="add" flat @click="enableAddForm">{{ $t('pbxConfig.addGroup') }}</q-btn>
</div>
<div v-if="isListLoadingVisible" class="row justify-center">
<q-spinner-dots color="primary" :size="40" />
</div>
<csc-pbx-group v-for="group in groups" :key="group.id" :group="group" :alias-number-options="aliasNumberOptions"
:seat-options="seatOptions" :hunt-policy-options="huntPolicyOptions" @remove="removeGroup"
:loading="isItemLoading(group.id)" @save-name="setGroupName" @save-extension="setGroupExtension"
@save-hunt-policy="setGroupHuntPolicy" @save-hunt-timeout="setGroupHuntTimeout"
@save-alias-numbers="updateAliasNumbers" @save-seats="updateSeats" />
<div v-if="groups.length === 0 && !isListRequesting" class="row justify-center csc-no-entities">
{{ $t('pbxConfig.noGroups') }}
</div>
</csc-page>
</template>
@ -95,10 +92,10 @@
'updateItemId',
'isRemoving',
'removeItemId',
'isListRequesting',
'listState',
'listError',
'listLoadingSilently'
'isListRequesting',
'isListLoadingVisible'
])
},
watch: {

@ -1,12 +1,13 @@
<template>
<q-card class="csc-pbx-seat">
<q-card-title class="cursor-pointer" @click="toggleMain()">
<q-icon name="person" color="primary" size="24px"/>
<span v-if="!expanded" class="csc-pbx-seat-title">{{ seat.display_name }}</span>
<q-card class="csc-entity csc-pbx-seat shadow-1">
<q-card-title class="csc-entity-title">
<q-icon name="person" color="secondary" size="24px"/>
<span class="csc-entity-title-text">{{ seat.display_name }}</span>
<q-chip v-if="!expanded" pointing="left" color="primary" class="gt-md">
{{ $t('pbxConfig.extension') }}: <span class="csc-important">{{ seat.pbx_extension }}</span>
</q-chip>
<q-icon :name="titleIcon" color="primary" size="22px" slot="right"/>
<q-btn :icon="titleIcon" :small="isMobile" color="primary" slot="right" flat @click="toggleMain()" />
<q-btn icon="delete" :small="isMobile" color="negative" slot="right" flat @click="remove()" />
</q-card-title>
<q-card-main v-if="expanded" class="transition-generic">
<q-field :label="$t('pbxConfig.seatName')">
@ -28,10 +29,6 @@
:after="groupButtons" @change="groupChange" />
</q-field>
</q-card-main>
<q-card-actions align="center">
<q-btn flat :small="isMobile" :round="isMobile"
color="negative" icon="delete" @click="remove()">Delete</q-btn>
</q-card-actions>
<q-inner-loading :visible="isLoading">
<q-spinner-mat size="60px" color="primary"></q-spinner-mat>
</q-inner-loading>
@ -113,7 +110,7 @@
return this.loading;
},
titleIcon() {
if(this.expanded) {
if(!this.expanded) {
return 'keyboard arrow down';
}
else {
@ -232,12 +229,7 @@
},
methods: {
toggleMain() {
if(this.expanded) {
this.expanded = false;
}
else {
this.expanded = true;
}
this.expanded = !this.expanded;
},
remove() {
this.$emit('remove', this.seatModel);
@ -309,13 +301,5 @@
</script>
<style lang="stylus" rel="stylesheet/stylus">
.csc-pbx-seat {
position: relative;
}
.csc-pbx-seat .csc-pbx-seat-title {
padding-left: 8px;
}
.csc-important {
font-weight: bold;
}
@import '../../../themes/app.common'
</style>

@ -1,5 +1,5 @@
<template>
<q-card class="csc-pbx-seat-add-form">
<q-card class="csc-pbx-seat-add-form shadow-1">
<q-card-title>
<q-icon name="add" color="primary" size="22px"/>
<span>{{ $t('pbxConfig.addSeat') }}</span>

@ -1,24 +1,21 @@
<template>
<csc-page title="Seats">
<csc-page :title="$t('pbxConfig.seatsTitle')">
<csc-pbx-seat-add-form v-show="addFormEnabled" ref="addForm" :alias-number-options="aliasNumberOptions"
:group-options="groupOptions" :loading="isAdding" @save="addSeat"
@cancel="disableAddForm" />
<q-card v-show="!addFormEnabled" flat>
<q-card-actions align="center">
<q-btn color="primary" icon="add" flat @click="enableAddForm">
{{ $t('pbxConfig.addSeat') }}
</q-btn>
</q-card-actions>
</q-card>
<q-card v-if="isListRequesting && !listLoadingSilently" flat>
<q-card-actions align="center">
<q-spinner-dots color="primary" :size="40"/>
</q-card-actions>
</q-card>
<div v-show="!addFormEnabled" class="row justify-center">
<q-btn color="primary" icon="add" flat @click="enableAddForm">{{ $t('pbxConfig.addSeat') }}</q-btn>
</div>
<div v-if="isListLoadingVisible" class="row justify-center">
<q-spinner-dots color="primary" :size="40" />
</div>
<csc-pbx-seat v-for="seat in seats" :key="seat.id" :seat="seat" :alias-number-options="aliasNumberOptions"
:group-options="groupOptions" @remove="removeSeat" :loading="isItemLoading(seat.id)"
@save-name="setSeatName" @save-extension="setSeatExtension"
@save-alias-numbers="updateAliasNumbers" @save-groups="updateGroups" />
<div v-if="seats.length === 0 && !isListRequesting" class="row justify-center csc-no-entities">
{{ $t('pbxConfig.noSeats') }}
</div>
</csc-page>
</template>
@ -62,10 +59,10 @@
'updateItemId',
'isRemoving',
'removeItemId',
'isListRequesting',
'listState',
'listError',
'listLoadingSilently'
'isListRequesting',
'isListLoadingVisible'
]),
groupOptions() {
let groups = [];

@ -1,18 +0,0 @@
<template>
<csc-page title="Devices"></csc-page>
</template>
<script>
import CscPage from '../../CscPage'
export default {
data () {
return {}
},
components: {
CscPage
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
</style>

@ -249,6 +249,15 @@
"addSeat": "Add Seat",
"removeSeat": "Remove seat",
"removeSeatTitle": "Remove seat",
"removeSeatText": "You are about to remove seat \"{seat}\""
"removeSeatText": "You are about to remove seat \"{seat}\"",
"devicesTitle": "Devices",
"deviceStationName": "Station name",
"deviceIdentifier": "MAC address",
"deviceModel": "Model",
"groupsTitle": "Groups",
"seatsTitle": "Seats",
"noDevices": "No devices created yet",
"noGroups": "No groups created yet",
"noSeats": "No seats created yet"
}
}

@ -9,9 +9,9 @@ import CallBlockingIncoming from './components/pages/CallBlocking/Incoming'
import CallBlockingOutgoing from './components/pages/CallBlocking/Outgoing'
import CallBlockingPrivacy from './components/pages/CallBlocking/Privacy'
import Reminder from './components/pages/Reminder';
import PbxConfigurationGroups from './components/pages/PbxConfiguration/Groups'
import PbxConfigurationSeats from './components/pages/PbxConfiguration/Seats'
import PbxConfigurationDevices from './components/pages/PbxConfiguration/Devices'
import PbxConfigurationGroups from './components/pages/PbxConfiguration/CscPbxGroups'
import PbxConfigurationSeats from './components/pages/PbxConfiguration/CscPbxSeats'
import PbxConfigurationDevices from './components/pages/PbxConfiguration/CscPbxDevices'
import Login from './components/Login'
import Error404 from './components/Error404'

@ -5,6 +5,7 @@ import { getPbxConfiguration, addGroup,
removeGroup, addSeat, removeSeat, setGroupName,
setGroupExtension, setGroupHuntPolicy, setGroupHuntTimeout,
updateGroupSeats, setSeatName, setSeatExtension, updateSeatGroups } from '../../api/pbx-config'
import { getDeviceList } from '../../api/pbx-devices'
export default {
listGroups(context, silent) {
@ -159,5 +160,17 @@ export default {
}).catch((err)=>{
context.commit('removeItemFailed', err.message);
});
},
listDevices(context) {
return new Promise((resolve, reject)=>{
context.commit('deviceListRequesting');
getDeviceList().then((result)=>{
context.commit('deviceListSucceeded', result);
resolve();
}).catch((err)=>{
context.commit('deviceListFailed', err.message);
reject(err);
});
});
}
}

@ -40,6 +40,12 @@ export default {
isListRequesting(state) {
return state.listState === RequestState.requesting;
},
isListLoadingSilently(state) {
return (state.listLoadingSilently === true);
},
isListLoadingVisible(state, getters) {
return getters.isListRequesting && !getters.isListLoadingSilently;
},
listState(state) {
return state.listState;
},
@ -99,5 +105,18 @@ export default {
},
removeError(state) {
return state.removeError;
},
devices(state) {
return state.devicesOrdered;
},
modelOptions(state) {
let modelOptions = [];
state.modelsOrdered.forEach((model)=>{
modelOptions.push({
label: model.vendor + " " + model.model,
value: model.id
});
});
return modelOptions;
}
}

@ -106,5 +106,35 @@ export default {
delete state.groupsOrdered[index];
}
});
},
deviceListRequesting(state, silent) {
state.listState = RequestState.requesting;
state.listError = null;
state.listLoadingSilently = silent;
},
deviceListSucceeded(state, data) {
state.listState = RequestState.succeeded;
state.listError = null;
state.devicesOrdered = data.devices.items;
state.profilesOrdered = data.profiles;
state.modelsOrdered = data.models;
state.devicesOrdered.forEach((device)=>{
state.profilesOrdered.forEach((profile)=>{
if(device.profile_id === profile.id) {
device.profile = profile;
}
});
});
state.devicesOrdered.forEach((device)=>{
state.modelsOrdered.forEach((model)=>{
if(device.profile.device_id === model.id) {
device.model = model;
}
});
});
},
deviceListFailed(state, error) {
state.listState = RequestState.failed;
state.listError = error;
}
}

@ -10,6 +10,12 @@ export default {
seatsOrdered: [],
numbers: [],
numbersMap : {},
devicesOrdered: [],
devices: {},
profilesOrdered: [],
profiles: {},
modelsOrdered: [],
models: {},
listState: RequestState.initiated,
listError: null,
listLoadingSilently: false,

@ -0,0 +1,32 @@
@import 'quasar.variables'
.csc-no-entities
margin 15px
color $secondary
.csc-important
font-weight bold
.csc-entity
position relative
.q-btn
.on-left
margin 0
.csc-entity-title .q-chip-main {
color white
}
.csc-entity-title-text
padding-left 6px
.q-card-title
color $secondary
.q-card-title-extra
.q-btn
padding-left 8px
padding-right 8px
Loading…
Cancel
Save