TT#47389 Change queue length of subscriber

What has been done:
- TT#47389, CallQueueConfig: As a PBXAdmin, I want to change the queue
length of a CallQueueConfiguration
- TT#47390, CallQueueConfig: As a PBXAdmin, I want to change the wrap
up time of a CallQueueConfiguration

Change-Id: I29e585c90d974e7294302d22b6e1a7a254caf8ef
changes/32/25132/8
raxelsen 7 years ago
parent c8d522d19f
commit 2fbd048c76

@ -17,7 +17,10 @@ import {
getSubscribers, getSubscribers,
getSubscriber, getSubscriber,
getSubscribersByCallQueueEnabled, getSubscribersByCallQueueEnabled,
addNewCallQueueConfig addNewCallQueueConfig,
setQueueLength,
setWrapUpTime,
getPreferences
} from './subscriber'; } from './subscriber';
import uuid from 'uuid'; import uuid from 'uuid';
import { getList, get, patchReplace } from './common' import { getList, get, patchReplace } from './common'
@ -554,3 +557,33 @@ export function addCallQueueConfig(id, config) {
}); });
}); });
} }
export function getConfig(id) {
return new Promise((resolve, reject)=>{
let $subscriber = {};
Promise.resolve().then(()=>{
return getSubscriber(id);
}).then((subscriber) => {
$subscriber = subscriber;
return getPreferences(id);
}).then((prefs) => {
resolve({
id: _.get($subscriber, 'id', null),
display_name: _.get($subscriber, 'display_name', null),
is_pbx_group: _.get($subscriber, 'is_pbx_group', null),
max_queue_length: _.get(prefs, 'max_queue_length', 5),
queue_wrap_up_time: _.get(prefs, 'queue_wrap_up_time', 10)
});
}).catch((err)=>{
reject(err);
});
});
}
export function setQueueLengthConfig(id, queueLength) {
return setQueueLength(id, queueLength);
}
export function setWrapUpTimeConfig(id, wrapUpTime) {
return setWrapUpTime(id, wrapUpTime);
}

@ -336,3 +336,28 @@ export function getSubscribersByCallQueueEnabled() {
export function addNewCallQueueConfig(id, config) { export function addNewCallQueueConfig(id, config) {
return Vue.http.put('api/subscriberpreferences/' + id, config); return Vue.http.put('api/subscriberpreferences/' + id, config);
} }
export function editCallQueuePreference(id, config) {
return new Promise((resolve, reject)=>{
let $prefs = Object.assign(config, { cloud_pbx_callqueue: true });
Promise.resolve().then(()=>{
return getPreferences(id);
}).then((result)=>{
var prefs = Object.assign(result, $prefs);
delete prefs._links;
return Vue.http.put('api/subscriberpreferences/' + id, prefs);
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
}
export function setQueueLength(id, queueLength) {
return editCallQueuePreference(id, { max_queue_length: queueLength });
}
export function setWrapUpTime(id, wrapUpTime) {
return editCallQueuePreference(id, { queue_wrap_up_time: wrapUpTime });
}

@ -224,7 +224,6 @@
this.$refs.faxUpload.value = ''; this.$refs.faxUpload.value = '';
}, },
processFile(event) { processFile(event) {
console.log('processFile()');
let file = event.target.files[0]; let file = event.target.files[0];
let fileName = file ? file.name : ''; let fileName = file ? file.name : '';
let fileNameSplit = fileName.split('.'); let fileNameSplit = fileName.split('.');

@ -267,7 +267,6 @@
this.$store.dispatch('callBlocking/addNumber' + this.suffix, number); this.$store.dispatch('callBlocking/addNumber' + this.suffix, number);
}, },
saveNumber(data) { saveNumber(data) {
console.log(data);
this.$store.dispatch('callBlocking/editNumber' + this.suffix, data); this.$store.dispatch('callBlocking/editNumber' + this.suffix, data);
}, },
removeNumberDialog(index) { removeNumberDialog(index) {

@ -53,7 +53,8 @@
v-if="expanded" v-if="expanded"
> >
<q-field <q-field
:label="$t('pbxConfig.queueExtensionName')"> :label="$t('pbxConfig.queueExtensionName')"
>
<q-input <q-input
dark dark
readonly readonly
@ -61,21 +62,33 @@
/> />
</q-field> </q-field>
<q-field <q-field
:label="$t('pbxConfig.queueLength')"> :label="$t('pbxConfig.queueLength')"
:error-label="queueLengthErrorMessage"
>
<q-input <q-input
dark dark
readonly
:value="subscriber.max_queue_length"
suffix="callers" suffix="callers"
v-model="changes.max_queue_length"
:after="queueLengthButtons"
@keyup.enter="saveQueueLength"
@input="$v.changes.max_queue_length.$touch"
@blur="$v.changes.max_queue_length.$touch"
:error="$v.changes.max_queue_length.$error"
/> />
</q-field> </q-field>
<q-field <q-field
:label="$t('pbxConfig.wrapUpTime')"> :label="$t('pbxConfig.wrapUpTime')"
:error-label="wrapUpTimeErrorMessage"
>
<q-input <q-input
dark dark
readonly v-model="changes.queue_wrap_up_time"
:value="subscriber.queue_wrap_up_time" :after="wrapUpTimeButtons"
suffix="seconds" suffix="seconds"
@keyup.enter="saveWrapUpTime"
@input="$v.changes.queue_wrap_up_time.$touch"
@blur="$v.changes.queue_wrap_up_time.$touch"
:error="$v.changes.queue_wrap_up_time.$error"
/> />
</q-field> </q-field>
</q-item-tile> </q-item-tile>
@ -94,10 +107,22 @@
/> />
</q-item-tile> </q-item-tile>
</q-item-side> </q-item-side>
<q-inner-loading :visible="isLoading">
<q-spinner-mat
size="60px"
color="primary"
/>
</q-inner-loading>
</q-item> </q-item>
</template> </template>
<script> <script>
import { showGlobalError } from '../../../helpers/ui'
import {
minValue,
maxValue,
numeric
} from 'vuelidate/lib/validators'
import { import {
QField, QField,
QInput, QInput,
@ -107,16 +132,20 @@
QItem, QItem,
QItemSide, QItemSide,
QItemMain, QItemMain,
QItemTile QItemTile,
QInnerLoading,
QSpinnerMat
} from 'quasar-framework' } from 'quasar-framework'
export default { export default {
name: 'csc-pbx-call-queue', name: 'csc-pbx-call-queue',
props: [ props: [
'subscriber' 'subscriber',
'loading'
], ],
data () { data () {
return { return {
expanded: false expanded: false,
changes: this.getConfig()
} }
}, },
components: { components: {
@ -127,9 +156,63 @@
QItem, QItem,
QItemSide, QItemSide,
QItemMain, QItemMain,
QItemTile QItemTile,
QInnerLoading,
QSpinnerMat
},
validations: {
changes: {
max_queue_length: {
numeric,
minValue: minValue(1),
maxValue: maxValue(99999)
},
queue_wrap_up_time: {
numeric,
minValue: minValue(1),
maxValue: maxValue(99999)
}
}
}, },
computed: { computed: {
queueLengthErrorMessage() {
if (!this.$v.changes.max_queue_length.numeric) {
return this.$t('validationErrors.numeric', {
field: this.$t('pbxConfig.queueLength'),
});
}
else if (!this.$v.changes.max_queue_length.minValue) {
return this.$t('validationErrors.minValueSecond', {
field: this.$t('pbxConfig.queueLength'),
minValue: this.$v.changes.max_queue_length.$params.minValue.min
});
}
else if (!this.$v.changes.max_queue_length.maxValue) {
return this.$t('validationErrors.maxValueSecond', {
field: this.$t('pbxConfig.queueLength'),
maxValue: this.$v.changes.max_queue_length.$params.maxValue.max
});
}
},
wrapUpTimeErrorMessage() {
if (!this.$v.changes.queue_wrap_up_time.numeric) {
return this.$t('validationErrors.numeric', {
field: this.$t('pbxConfig.wrapUpTime'),
});
}
else if (!this.$v.changes.queue_wrap_up_time.minValue) {
return this.$t('validationErrors.minValueSecond', {
field: this.$t('pbxConfig.wrapUpTime'),
minValue: this.$v.changes.queue_wrap_up_time.$params.minValue.min
});
}
else if (!this.$v.changes.queue_wrap_up_time.maxValue) {
return this.$t('validationErrors.maxValueSecond', {
field: this.$t('pbxConfig.wrapUpTime'),
maxValue: this.$v.changes.queue_wrap_up_time.$params.maxValue.max
});
}
},
itemClasses() { itemClasses() {
let classes = ['csc-list-item', 'csc-pbx-call-queue']; let classes = ['csc-list-item', 'csc-pbx-call-queue'];
if (this.expanded) { if (this.expanded) {
@ -150,11 +233,129 @@
else { else {
return 'keyboard arrow up'; return 'keyboard arrow up';
} }
},
wrapUpTimeButtons() {
let buttons = [];
let self = this;
if (this.wrapUpTimeHasChanged && this.$v.changes.queue_wrap_up_time.$error) {
buttons.push({
icon: 'clear',
error: true,
handler (event) {
event.stopPropagation();
self.resetWrapUpTime();
}
}
);
}
else if (this.wrapUpTimeHasChanged) {
buttons.push({
icon: 'check',
error: false,
handler (event) {
event.stopPropagation();
self.saveWrapUpTime();
}
}, {
icon: 'clear',
error: false,
handler (event) {
event.stopPropagation();
self.resetWrapUpTime();
}
}
);
}
return buttons;
},
wrapUpTime() {
return this.subscriber.queue_wrap_up_time;
},
wrapUpTimeHasChanged() {
return this.wrapUpTime + "" !== this.changes.queue_wrap_up_time + "";
},
queueLengthButtons() {
let buttons = [];
let self = this;
if (this.queueLengthHasChanged && this.$v.changes.max_queue_length.$error) {
buttons.push({
icon: 'clear',
error: true,
handler (event) {
event.stopPropagation();
self.resetQueueLength();
}
}
);
}
else if (this.queueLengthHasChanged) {
buttons.push({
icon: 'check',
error: false,
handler (event) {
event.stopPropagation();
self.saveQueueLength();
}
}, {
icon: 'clear',
error: false,
handler (event) {
event.stopPropagation();
self.resetQueueLength();
}
}
);
}
return buttons;
},
queueLength() {
return this.subscriber.max_queue_length;
},
queueLengthHasChanged() {
return this.queueLength + "" !== this.changes.max_queue_length + "";
},
configModel() {
return {
id: this.subscriber.id,
max_queue_length: this.changes.max_queue_length,
queue_wrap_up_time: this.changes.queue_wrap_up_time
}
},
isLoading() {
return this.loading;
} }
}, },
methods: { methods: {
toggleMain() { toggleMain() {
this.expanded = !this.expanded; this.expanded = !this.expanded;
},
getConfig() {
return {
max_queue_length: this.subscriber.max_queue_length,
queue_wrap_up_time: this.subscriber.queue_wrap_up_time
}
},
resetWrapUpTime() {
this.changes.queue_wrap_up_time = this.subscriber.queue_wrap_up_time;
},
saveWrapUpTime() {
if (this.$v.changes.$invalid) {
showGlobalError(this.$t('validationErrors.generic'));
}
else {
this.$emit('save-wrap-up-time', this.configModel);
}
},
resetQueueLength() {
this.changes.max_queue_length = this.subscriber.max_queue_length;
},
saveQueueLength() {
if (this.$v.changes.$invalid) {
showGlobalError(this.$t('validationErrors.generic'));
}
else {
this.$emit('save-queue-length', this.configModel);
}
} }
}, },
watch: { watch: {

@ -49,6 +49,9 @@
v-for="(subscriber, index) in callQueueGroupsAndSeats" v-for="(subscriber, index) in callQueueGroupsAndSeats"
:key="index" :key="index"
:subscriber="subscriber" :subscriber="subscriber"
:loading="isItemLoading(subscriber.id)"
@save-queue-length="setQueueLength"
@save-wrap-up-time="setWrapUpTime"
/> />
</q-list> </q-list>
</div> </div>
@ -115,7 +118,9 @@
'isListRequesting', 'isListRequesting',
'callQueueGroupsAndSeatsOptions', 'callQueueGroupsAndSeatsOptions',
'isAdding', 'isAdding',
'addState' 'addState',
'isUpdating',
'updateItemId'
]), ]),
isMobile() { isMobile() {
return Platform.is.mobile; return Platform.is.mobile;
@ -142,6 +147,15 @@
}, },
resetAddForm() { resetAddForm() {
this.$refs.addForm.reset(); this.$refs.addForm.reset();
},
setQueueLength(subscriber) {
this.$store.dispatch('pbxConfig/setQueueLength', subscriber);
},
setWrapUpTime(subscriber) {
this.$store.dispatch('pbxConfig/setWrapUpTime', subscriber);
},
isItemLoading(subscriberId) {
return (this.isUpdating && this.updateItemId + "" === subscriberId + "");
} }
}, },
watch: { watch: {

@ -32,7 +32,10 @@ import {
getGroup, getGroup,
getSeat, getSeat,
getCallQueueConfigurations, getCallQueueConfigurations,
addCallQueueConfig addCallQueueConfig,
setQueueLengthConfig,
setWrapUpTimeConfig,
getConfig
} from '../../api/pbx-config' } from '../../api/pbx-config'
export default { export default {
@ -440,5 +443,42 @@ export default {
}).catch((err) => { }).catch((err) => {
context.commit('addItemFailed', err.message); context.commit('addItemFailed', err.message);
}); });
},
reloadConfig(context, config) {
return new Promise((resolve, reject) => {
context.commit('configReloading', config);
getConfig(config.id).then(($config) => {
context.commit('configReloaded', $config);
}).catch((err)=>{
context.commit('configReloadingFailed', {
config: config,
error: err.message
});
}).then(()=>{
resolve();
}).catch((err)=>{
reject(err);
});
});
},
setQueueLength(context, subscriber) {
context.commit('updateItemRequesting', subscriber);
setQueueLengthConfig(subscriber.id, subscriber.max_queue_length).then(() => {
return context.dispatch('reloadConfig', subscriber);
}).then(()=>{
context.commit('updateItemSucceeded');
}).catch((err) => {
context.commit('updateItemFailed', err.message);
});
},
setWrapUpTime(context, subscriber) {
context.commit('updateItemRequesting', subscriber);
setWrapUpTimeConfig(subscriber.id, subscriber.queue_wrap_up_time).then(() => {
return context.dispatch('reloadConfig', subscriber);
}).then(()=>{
context.commit('updateItemSucceeded');
}).catch((err) => {
context.commit('updateItemFailed', err.message);
});
} }
} }

@ -297,7 +297,7 @@ export default {
return state.chipStationNameFilter; return state.chipStationNameFilter;
}, },
callQueueGroupsAndSeats(state) { callQueueGroupsAndSeats(state) {
return state.callQueueGroupsAndSeats; return state.callQueueGroupsAndSeatsOrdered;
}, },
assignableGroupsAndSeatsOptions(state, getters) { assignableGroupsAndSeatsOptions(state, getters) {
return getters.groupsAndSeatsOptions.filter((option) => { return getters.groupsAndSeatsOptions.filter((option) => {
@ -305,7 +305,7 @@ export default {
}); });
}, },
callQueueGroupsAndSeatsOptions(state, getters) { callQueueGroupsAndSeatsOptions(state, getters) {
let ids = state.callQueueGroupsAndSeats.map((item) => { let ids = _.map(state.callQueueGroupsAndSeats, (item) => {
return item.id; return item.id;
}); });
let options = getters.assignableGroupsAndSeatsOptions let options = getters.assignableGroupsAndSeatsOptions
@ -314,5 +314,12 @@ export default {
} }
); );
return options; return options;
},
configItemById(state) {
return (id) => {
return state.callQueueGroupsAndSeats.filter((item) => {
return item.id === id;
})
}
} }
} }

@ -410,15 +410,43 @@ export default {
state.listLoadingSilently = _.get(options, 'silent', false); state.listLoadingSilently = _.get(options, 'silent', false);
state.listState = RequestState.requesting; state.listState = RequestState.requesting;
state.listError = null; state.listError = null;
state.callQueueGroupsAndSeats = []; state.callQueueGroupsAndSeats = {};
state.callQueueGroupsAndSeatsOrdered = [];
}, },
callQueueListSucceeded(state, data) { callQueueListSucceeded(state, data) {
state.listState = RequestState.succeeded; state.listState = RequestState.succeeded;
state.listError = null; state.listError = null;
state.callQueueGroupsAndSeats = data.items; state.callQueueGroupsAndSeats = {};
state.callQueueGroupsAndSeatsOrdered = [];
data.items.forEach((config)=>{
state.callQueueGroupsAndSeats[config.id] = config;
state.callQueueGroupsAndSeatsOrdered.push(config);
});
state.callQueueGroupsAndSeats = _.filter(state.callQueueGroupsAndSeats, (item) => {
return (item !== (undefined || null || ''));
});
}, },
callQueueListFailed(state, error) { callQueueListFailed(state, error) {
state.listState = RequestState.failed; state.listState = RequestState.failed;
state.listError = error; state.listError = error;
},
configReloading(state, config) {
state.configReloadingState = RequestState.requesting;
state.configReloadingError = null;
state.configReloading = config;
},
configReloaded(state, config) {
state.configReloadingState = RequestState.succeeded;
state.configReloadingError = null;
Vue.set(state.callQueueGroupsAndSeats, config.id, config);
for (let i = 0; i < state.callQueueGroupsAndSeatsOrdered.length; i++) {
if (state.callQueueGroupsAndSeatsOrdered[i].id === config.id) {
state.callQueueGroupsAndSeatsOrdered[i] = config;
}
}
},
configReloadingFailed(state, err) {
state.configReloadingState = RequestState.failed;
state.configReloadingError = err;
} }
} }

@ -70,5 +70,9 @@ export default {
chipModelFilter: null, chipModelFilter: null,
chipMacAddressFilter: null, chipMacAddressFilter: null,
chipStationNameFilter: null, chipStationNameFilter: null,
callQueueGroupsAndSeats: [] callQueueGroupsAndSeats: {},
callQueueGroupsAndSeatsOrdered: [],
configReloading: null,
configReloadingState: RequestState.initiated,
configReloadingError: null
} }

@ -58,12 +58,14 @@ describe('PBX Configuration Store', () => {
items: [ items: [
{ {
display_name: "123", display_name: "123",
id: 123,
is_pbx_group: false, is_pbx_group: false,
max_queue_length: "10", max_queue_length: "10",
queue_wrap_up_time: "5" queue_wrap_up_time: "5"
}, },
{ {
display_name: "456", display_name: "456",
id: 456,
is_pbx_group: false, is_pbx_group: false,
max_queue_length: "5", max_queue_length: "5",
queue_wrap_up_time: "10" queue_wrap_up_time: "10"

Loading…
Cancel
Save