TT#20509 PBXConfig: As a Customer, I want to see a list of all PBXGroups

Change-Id: Ib4c4256b07ec177609fccab8ad42f695b7cef5d8
changes/53/17753/5
Hans-Peter Herzog 8 years ago
parent 54c0aa0f71
commit 54c98fc188

@ -1,56 +1,71 @@
import Vue from 'vue';
import { getJsonBody } from './utils';
import { getNumbers } from './user';
export function getGroups(options) {
var assumedRows = 1000;
export function getAllPbxSubscribers() {
return new Promise((resolve, reject)=>{
Vue.http.get('/api/subscribers', {
params: {
is_pbx_group: true
}
}).then((result)=>{
var groups = [];
var body = JSON.parse(result.body);
if(_.isArray(body["_embedded"]["ngcp:subscribers"])) {
body['_embedded']['ngcp:subscribers'].forEach((group)=>{
groups.push(group);
var params = {};
Promise.resolve().then(()=>{
return Vue.http.get('/api/subscribers', {
params: _.assign(params, {
page: 1,
rows: assumedRows,
})
});
}).then((res)=>{
let body = getJsonBody(res.body);
if(body.total_count > assumedRows) {
return Vue.http.get('/api/subscribers', {
params: _.assign(params, {
page: 1,
rows: body.total_count,
})
});
} else {
return Promise.resolve(body);
}
resolve(groups);
}).then(($subscribers)=>{
let subscribers = _.get($subscribers, '_embedded.ngcp:subscribers', []);
let pilot = null;
let seats = [];
let groups = [];
subscribers.forEach((subscriber)=>{
if(subscriber.is_pbx_group) {
groups.push(subscriber);
} else if(subscriber.is_pbx_pilot) {
pilot = subscriber;
} else {
seats.push(subscriber);
}
});
resolve({
pilot: pilot,
groups: groups,
seats: seats
});
}).catch((err)=>{
reject(err);
});
});
}
export function createGroup(options) {
}
export function saveGroup(options) {
}
export function getSeats() {
}
export function createSeat() {
}
export function saveSeat() {
}
export function getDevices() {
}
export function createDevice() {
}
export function saveDevice() {
export function getPbxConfiguration() {
return new Promise((resolve, reject)=>{
Promise.all([
getAllPbxSubscribers(),
getNumbers()
]).then((result)=>{
resolve({
pilot: result[0].pilot,
seats: result[0].seats,
groups: result[0].groups,
numbers: result[1]
});
}).catch((err)=>{
reject(err);
});
});
}

@ -2,6 +2,8 @@
import _ from 'lodash';
import Vue from 'vue';
var assumedNumbers = 1000;
export function login(username, password) {
return new Promise((resolve, reject)=>{
var jwt = null;
@ -68,8 +70,36 @@ export function getCapabilities() {
export function getNumbers() {
return new Promise((resolve, reject)=>{
Vue.http.get('/api/numbers').then((result)=>{
resolve(result);
let params = {};
let path = '/api/numbers';
Promise.resolve().then(()=>{
return Vue.http.get(path, {
params: _.assign(params, {
page: 1,
rows: assumedNumbers,
})
});
}).then((res)=>{
let body = JSON.parse(res.body);
if(body.total_count > assumedNumbers) {
return Vue.http.get(path, {
params: _.assign(params, {
page: 1,
rows: body.total_count,
})
});
} else {
return Promise.resolve(res);
}
}).then((res)=>{
let body = JSON.parse(res.body);
let numbers = [];
if(_.isArray(body["_embedded"]["ngcp:numbers"])) {
body['_embedded']['ngcp:numbers'].forEach((number)=>{
numbers.push(number);
});
}
resolve(numbers);
}).catch((err)=>{
reject(err);
});

@ -0,0 +1,26 @@
<template>
<q-chip pointing="left" color="primary" class="csc-number-chip">
<span class="number-pilot">{{ item.primary_number | number(item.pbx_extension) }}</span>
<span class="number-ext">{{ item.pbx_extension }}</span>
</q-chip>
</template>
<script>
import { QChip } from 'quasar-framework'
export default {
name: 'csc-number-chip',
props: ['item'],
data () {
return {}
},
components: {
QChip
}
}
</script>
<style>
.csc-number-chip .number-ext {
font-weight: bold;
}
</style>

@ -69,11 +69,11 @@
:label="$t('navigation.pbxConfiguration.title')"
:sublabel="$t('navigation.pbxConfiguration.subTitle')">
<q-side-link item to="/user/pbx-configuration/groups">
<q-item-side icon="fa-group"/>
<q-item-side icon="group"/>
<q-item-main :label="$t('navigation.pbxConfiguration.groups')"/>
</q-side-link>
<q-side-link item to="/user/pbx-configuration/seats">
<q-item-side icon="fa-home"/>
<q-item-side icon="person"/>
<q-item-main :label="$t('navigation.pbxConfiguration.seats')"/>
</q-side-link>
<q-side-link item to="/user/pbx-configuration/devices">

@ -0,0 +1,191 @@
<template>
<q-card class="csc-card-collapsible csc-pbx-group">
<q-card-title>
<q-icon name="group" color="primary" size="22px"/>
<span class="csc-pbx-group-title">{{ group.display_name }}</span>
<q-chip pointing="left" color="primary">
{{ $t('pbxConfig.extension') }}: <span class="csc-important">{{ group.pbx_extension }}</span>
</q-chip>
</q-card-title>
<q-card-main>
<q-field :label="$t('pbxConfig.groupName')">
<q-input v-model="name" readonly/>
</q-field>
<q-field :label="$t('pbxConfig.extension')">
<q-input v-model="extension" readonly />
</q-field>
<q-field :label="$t('pbxConfig.huntPolicy')">
<q-select v-model="huntPolicy" :options="huntPolicyOptions" readonly radio />
</q-field>
<q-field :label="$t('pbxConfig.huntTimeout')">
<q-input v-model="huntTimeout" readonly suffix="s" readonly/>
</q-field>
<q-field :label="$t('pbxConfig.primaryNumber')">
<q-input v-model="primaryNumber" readonly disabled />
</q-field>
<q-field :label="$t('pbxConfig.aliasNumbers')">
<q-select v-model="aliasNumbers" :options="allAliasNumbers" multiple chips readonly clearable />
</q-field>
<q-field :label="$t('pbxConfig.seats')">
<q-select v-model="assignedSeats" :options="allSeats" multiple chips readonly clearable />
</q-field>
</q-card-main>
<q-card-actions>
</q-card-actions>
</q-card>
</template>
<script>
import CscNumberChip from '../../card/CscNumberChip'
import numberFilter from '../../../filters/number'
import {
QCard,
QCardTitle,
QCardMain,
QCardActions,
QField,
QInput,
QIcon,
QSelect,
QChip
} from 'quasar-framework'
export default {
name: 'csc-pbx-group',
props: ['group'],
data () {
return {}
},
components: {
QCard,
QCardTitle,
QCardMain,
QCardActions,
QField,
QInput,
QIcon,
QSelect,
QChip,
CscNumberChip
},
computed: {
name() {
return this.group.display_name;
},
extension() {
return this.group.pbx_extension;
},
huntPolicy() {
return this.group.pbx_hunt_policy;
},
huntTimeout() {
return this.group.pbx_hunt_timeout;
},
primaryNumber() {
return numberFilter(this.group.primary_number);
},
aliasNumbers() {
let numbers = [];
if(this.group.alias_numbers) {
this.group.alias_numbers.forEach((number)=>{
numbers.push(number.number_id);
});
}
return numbers;
},
huntPolicyOptions() {
return [
{
label: this.$t('pbxConfig.serialRinging'),
value: 'serial'
},
{
label: this.$t('pbxConfig.parallelRinging'),
value: 'parallel'
},
{
label: this.$t('pbxConfig.randomRinging'),
value: 'random'
},
{
label: this.$t('pbxConfig.circularRinging'),
value: 'circular'
}
];
},
assignedSeats() {
let seats = [];
if(this.group.seats) {
this.group.seats.forEach((seat)=>{
seats.push(seat.id);
});
}
return seats;
},
allSeats() {
let seats = [];
if(this.$store.getters['pbxConfig/seats']) {
this.$store.getters['pbxConfig/seats'].forEach((seat)=>{
seats.push({
label: seat.display_name,
sublabel: this.$t('pbxConfig.extension') + ': ' + seat.pbx_extension,
value: seat.id
});
});
}
return seats;
},
allPrimaryNumbers() {
let numbers = [];
if(this.$store.getters['pbxConfig/numbers']) {
this.$store.getters['pbxConfig/numbers'].forEach((number)=>{
if(number.is_primary) {
numbers.push({
label: numberFilter(number),
value: number.id
});
}
});
}
return numbers;
},
allAliasNumbers() {
let numbers = [];
if(this.$store.getters['pbxConfig/numbers']) {
this.$store.getters['pbxConfig/numbers'].forEach((number)=>{
if(!number.is_primary) {
let owner = this.$t('pbxConfig.allocatedByNobody');
if(number.subscriber !== null && number.subscriber.display_name !== null &&
number.subscriber.is_pbx_group) {
owner = this.$t('pbxConfig.allocatedBy', {
type: this.$t('pbxConfig.group'),
name: number.subscriber.display_name
});
} else if (number.subscriber !== null && number.subscriber.display_name !== null) {
owner = this.$t('pbxConfig.allocatedBy', {
type: this.$t('pbxConfig.seat'),
name: number.subscriber.display_name
});
}
numbers.push({
label: numberFilter(number),
sublabel: owner,
value: number.id
});
}
});
}
return numbers;
}
}
}
</script>
<style>
.csc-pbx-group .csc-pbx-group-title {
padding-left: 8px;
}
.csc-important {
font-weight: bold;
}
</style>

@ -1,17 +1,22 @@
<template>
<csc-page title="PBX Groups"></csc-page>
<csc-page title="Groups">
<csc-pbx-group v-for="group in groups" :group="group" />
</csc-page>
</template>
<script>
import CscPage from '../../CscPage'
import CscNumberChip from '../../card/CscNumberChip'
import CscPbxGroup from './CscPbxGroup'
import { QChip, QCard, QCardSeparator, QCardTitle, QCardMain,
QIcon, QPopover, QList, QItem, QItemMain } from 'quasar-framework'
QIcon, QPopover, QList, QItem, QItemMain, QField, QInput } from 'quasar-framework'
import { mapState } from 'vuex'
export default {
components: {
CscPage,
CscNumberChip,
QChip,
QCard,
QCardSeparator,
@ -21,29 +26,25 @@
QPopover,
QList,
QItem,
QItemMain
QItemMain,
QField,
QInput,
CscPbxGroup
},
mounted() {
this.$store.dispatch('pbxGroups/load').then(()=>{
}).catch((err)=>{
});
this.$store.dispatch('pbxConfig/listGroups');
},
data () {
return {}
},
computed: {
...mapState({
groups: state => state.pbxGroups.groups,
})
},
groups() {
return this.$store.getters['pbxConfig/groups'];
}
}
}
</script>
<style lang="stylus">
@import '../../../../src/themes/app.variables.styl';
.number {
color: $primary;
}
</style>

@ -1,18 +1,52 @@
<template>
<csc-page title="Seats"></csc-page>
<csc-page title="Seats">
<q-card v-for="seat in seats" class="pbx-seat">
<q-card-title>
<q-icon name="person" color="primary" size="22px"/>
<span class="pbx-seat-title">{{ seat.display_name }}</span>
<csc-number-chip :item="seat" />
</q-card-title>
</q-card>
</csc-page>
</template>
<script>
import CscPage from '../../CscPage'
import CscNumberChip from '../../card/CscNumberChip'
import { QChip, QCard, QCardSeparator, QCardTitle, QCardMain,
QIcon, QPopover, QList, QItem, QItemMain } from 'quasar-framework'
export default {
mounted() {
this.$store.dispatch('pbxConfig/listSeats');
},
data () {
return {}
},
components: {
CscPage
CscPage,
CscNumberChip,
QChip,
QCard,
QCardSeparator,
QCardTitle,
QCardMain,
QIcon,
QPopover,
QList,
QItem,
QItemMain
},
computed: {
seats() {
return this.$store.getters['pbxConfig/seats'];
}
}
}
</script>
<style>
.pbx-seat .pbx-seat-title {
padding-left: 8px;
}
</style>

@ -1,4 +1,20 @@
export default function(number) {
return '+' + number.cc + number.ac + number.sn;
import _ from 'lodash';
import { normalizeNumber } from './number-format'
export default function(number, extension) {
let constructedNumber = "" + number.cc + number.ac + number.sn;
let normalizedNumber = normalizeNumber(constructedNumber);
let finalNumber;
if(_.isString(normalizedNumber)) {
finalNumber = normalizedNumber;
} else {
finalNumber = constructedNumber;
}
if(extension) {
return finalNumber.replace(new RegExp(extension + '$'), '');
} else {
return finalNumber;
}
}

@ -127,5 +127,22 @@
"number": "Number",
"endCall": "End Call",
"endCallDialog": "You are about to end the current call. Are you sure?"
},
"pbxConfig": {
"seat": "Seat",
"seats": "Seats",
"group": "Group",
"extension": "Extension",
"groupName": "Name",
"huntPolicy": "Hunt Policy",
"huntTimeout": "Hunt Timeout",
"primaryNumber": "Primary Number",
"aliasNumbers": "Alias Numbers",
"serialRinging": "Serial Ringing",
"parallelRinging": "Parallel Ringing",
"randomRinging": "Random Ringing",
"circularRinging": "Circular Ringing",
"allocatedByNobody": "Free",
"allocatedBy": "Allocated by {type} {name}"
}
}

@ -8,7 +8,7 @@ import CallForwardModule from './call-forward'
import CallModule from './call'
import ConversationsModule from './conversations'
import LayoutModule from './layout'
import PbxGroupsModule from './pbx-groups'
import PbxConfigModule from './pbx-config'
import ReminderModule from './reminder'
import UserModule from './user'
@ -21,7 +21,7 @@ export const store = new Vuex.Store({
call: CallModule,
conversations: ConversationsModule,
layout: LayoutModule,
pbxGroups: PbxGroupsModule,
pbxConfig: PbxConfigModule,
reminder: ReminderModule,
user: UserModule
}

@ -0,0 +1,92 @@
import _ from 'lodash';
import { getPbxConfiguration } from '../api/pbx-config'
export default {
namespaced: true,
state: {
pilot: null,
groups: {},
groupsOrdered: [],
seats: {},
seatsOrdered: [],
numbers: []
},
getters: {
groups(state, getters) {
return state.groupsOrdered;
},
seats(state, getters) {
return state.seatsOrdered;
},
numbers(state, getters) {
return state.numbers;
},
aliasNumbers(state, getters) {
}
},
mutations: {
show: function(state, options) {
state.groups = options.groups;
},
listAll(state, all) {
state.pilot = all.pilot;
state.groups = {};
state.groupsOrdered = [];
state.seats = {};
state.seatsOrdered = [];
all.groups.forEach((group)=>{
state.groups[group.id] = group;
state.groupsOrdered.push(group);
});
all.seats.forEach((seat)=>{
seat.pbx_group_ids.forEach((groupId)=>{
let group = state.groups[groupId];
let seats = _.get(group, 'seats', []);
seats.push(seat);
_.set(group, 'seats', seats);
let groups = _.get(seat, 'groups', []);
groups.push(group);
_.set(seat, 'groups', groups);
});
state.seats[seat.id] = seat;
state.seatsOrdered.push(seat);
});
if(_.isArray(all.numbers) && all.numbers.length > 0) {
all.numbers.forEach((number)=>{
if(_.has(state.groups, number.subscriber_id)) {
number.subscriber = state.groups[number.subscriber_id];
} else if (_.has(state.seats, number.subscriber_id)) {
number.subscriber = state.seats[number.subscriber_id];
} else if (state.pilot.id === number.subscriber_id) {
number.subscriber = state.pilot;
} else {
number.subscriber = null;
}
});
state.numbers = all.numbers;
}
}
},
actions: {
listSeats(context, options) {
return new Promise((resolve, reject)=>{
getPbxConfiguration().then((config)=>{
context.commit('listAll', config);
}).catch((err)=>{
console.log(err);
});
});
},
listGroups(context, options) {
return new Promise((resolve, reject)=>{
getPbxConfiguration().then((config)=>{
context.commit('listAll', config);
}).catch((err)=>{
console.log(err);
});
});
}
}
};

@ -1,31 +0,0 @@
import { getGroups } from '../api/pbx-config'
export default {
namespaced: true,
state: {
groups: [],
page: 1
},
getters: {
},
mutations: {
show: function(state, options) {
state.groups = options.groups;
}
},
actions: {
load: function(context, options) {
return new Promise((resolve, reject)=>{
getGroups().then((groups)=>{
context.commit('show', {
groups: groups
});
}).catch((err)=>{
reject(err);
});
});
}
}
};

@ -0,0 +1,46 @@
'use strict';
import PbxConfig from '../../src/store/pbx-config';
import { assert } from 'chai';
describe('PBX Configuration Store', () => {
it('should list all PBX Groups', () => {
let state = {};
let data = {
pilot: {},
seats: [
{
id: 2,
pbx_group_ids: []
},
{
id: 3,
pbx_group_ids: []
}
],
groups: [
{
id: 4
},
{
id: 5
}
],
numbers: [
{
id: 6
},
{
id: 7
}
]
};
PbxConfig.mutations.listAll(state, data);
assert.equal(state.seats[2], data.seats[0]);
assert.equal(state.seats[3], data.seats[1]);
assert.equal(state.groups[4], data.groups[0]);
assert.equal(state.groups[5], data.groups[1]);
assert.deepEqual(state.numbers, data.numbers);
});
});
Loading…
Cancel
Save