From 3b25cc26a3a64f62c1b112668d09e8033a4a3d0a Mon Sep 17 00:00:00 2001 From: Hans-Peter Herzog Date: Fri, 26 Jul 2019 10:24:33 +0200 Subject: [PATCH] TT#56391 ManagerSecretary: As a PBXAdmin, I want to manage manager secretary configurations - Navigate to a separate page to manage manager secretary configurations - Create new configuration - Update existing configuration by adding and removing numbers - Remove existing configuration Change-Id: I61a7c6ea384cd58854f96fbe2c20f26a09feef6d --- src/api/pbx-ms-configs.js | 95 +++++++ src/components/layouts/MainMenu.vue | 11 + .../PbxConfiguration/CscPbxCallQueue.vue | 243 +--------------- .../pages/PbxConfiguration/CscPbxMsConfig.vue | 213 ++++++++++++++ .../CscPbxMsConfigAddForm.vue | 214 ++++++++++++++ .../PbxConfiguration/CscPbxMsConfigs.vue | 242 ++++++++++++++++ .../PbxConfiguration/CscPbxSoundSetSound.vue | 9 - .../PbxConfiguration/CscPbxSoundSets.vue | 11 - src/locales/en.json | 13 +- src/routes.js | 9 + src/store/index.js | 4 +- src/store/pbx-callqueues.js | 6 +- src/store/pbx-ms-configs.js | 269 ++++++++++++++++++ src/store/pbx.js | 35 +++ 14 files changed, 1106 insertions(+), 268 deletions(-) create mode 100644 src/api/pbx-ms-configs.js create mode 100644 src/components/pages/PbxConfiguration/CscPbxMsConfig.vue create mode 100644 src/components/pages/PbxConfiguration/CscPbxMsConfigAddForm.vue create mode 100644 src/components/pages/PbxConfiguration/CscPbxMsConfigs.vue create mode 100644 src/store/pbx-ms-configs.js diff --git a/src/api/pbx-ms-configs.js b/src/api/pbx-ms-configs.js new file mode 100644 index 00000000..4fe436e6 --- /dev/null +++ b/src/api/pbx-ms-configs.js @@ -0,0 +1,95 @@ + +import _ from 'lodash'; +import { + 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 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 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 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); + }); + }); +} + diff --git a/src/components/layouts/MainMenu.vue b/src/components/layouts/MainMenu.vue index a3a321d9..2e5a6fff 100644 --- a/src/components/layouts/MainMenu.vue +++ b/src/components/layouts/MainMenu.vue @@ -203,6 +203,17 @@ :label="$t('navigation.pbxConfiguration.soundSets')" /> + + + + diff --git a/src/components/pages/PbxConfiguration/CscPbxCallQueue.vue b/src/components/pages/PbxConfiguration/CscPbxCallQueue.vue index a39dffee..cf66635a 100644 --- a/src/components/pages/PbxConfiguration/CscPbxCallQueue.vue +++ b/src/components/pages/PbxConfiguration/CscPbxCallQueue.vue @@ -95,126 +95,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/src/components/pages/PbxConfiguration/CscPbxMsConfigAddForm.vue b/src/components/pages/PbxConfiguration/CscPbxMsConfigAddForm.vue new file mode 100644 index 00000000..f9884cb4 --- /dev/null +++ b/src/components/pages/PbxConfiguration/CscPbxMsConfigAddForm.vue @@ -0,0 +1,214 @@ + + + + + diff --git a/src/components/pages/PbxConfiguration/CscPbxMsConfigs.vue b/src/components/pages/PbxConfiguration/CscPbxMsConfigs.vue new file mode 100644 index 00000000..f5a2eb77 --- /dev/null +++ b/src/components/pages/PbxConfiguration/CscPbxMsConfigs.vue @@ -0,0 +1,242 @@ + + + + + diff --git a/src/components/pages/PbxConfiguration/CscPbxSoundSetSound.vue b/src/components/pages/PbxConfiguration/CscPbxSoundSetSound.vue index 8f4f4043..8cba54d1 100644 --- a/src/components/pages/PbxConfiguration/CscPbxSoundSetSound.vue +++ b/src/components/pages/PbxConfiguration/CscPbxSoundSetSound.vue @@ -256,15 +256,6 @@ this.selectedFile = this.resetFile(); } } - // uploadFileState(state) { - // if (state === 'succeeded') { - // showToast(this.$t('pbxConfig.toasts.uploadSoundFileToast', { handle: this.item.handle })); - // this.resetFile(); - // } - // else if (state === 'failed' && this.uploadProgress > 0) { - // this.resetFile(); - // } - // } } } diff --git a/src/components/pages/PbxConfiguration/CscPbxSoundSets.vue b/src/components/pages/PbxConfiguration/CscPbxSoundSets.vue index ac6275ec..a8333e78 100644 --- a/src/components/pages/PbxConfiguration/CscPbxSoundSets.vue +++ b/src/components/pages/PbxConfiguration/CscPbxSoundSets.vue @@ -186,17 +186,6 @@ } }, watch: { - // addState(state) { - // if (state === 'succeeded') { - // this.disableAddForm(); - // showToast(this.$t('pbxConfig.toasts.addedSoundSetToast', { name: this.lastAddedSoundSet })); - // } - // }, - // updateState(state) { - // if (state === 'succeeded') { - // showToast(this.$t('pbxConfig.toasts.changedFieldToast', this.lastUpdatedField)); - // } - // } } } diff --git a/src/locales/en.json b/src/locales/en.json index 983c087d..bb4cd9d6 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -105,7 +105,8 @@ "seats": "Seats", "devices": "Devices", "callQueues": "Call Queues", - "soundSets": "Sound Sets" + "soundSets": "Sound Sets", + "msConfigs": "Manager Secretary" }, "voicebox": { "title": "Voicebox", @@ -486,7 +487,15 @@ "deviceCreationToast": "Created device {device} successfully", "deviceUpdateToast": "Updated {field} for device {device} successfully", "deviceRemovalToast": "Removed device {device} successfully", - "deviceLampsAndKeys": "Lamps/Keys" + "deviceLampsAndKeys": "Lamps/Keys", + "msConfigCreationIndicationLabel": "Add Config", + "msConfigCreationLabel": "Create Config", + "msConfigSubscriberSelectionLabel": "Select a manager", + "msConfigNumberSelectionLabel": "Select secretary numbers", + "msConfigNumbersLabel": "Secretary numbers", + "msConfigNoSecretaryNumbers": "No numbers assigned", + "msConfigRemovalDialogTitle": "Remove manager secretary config", + "msConfigRemovalDialogText": "You are about to remove config for {msConfig}" }, "callBlocking": { "privacyEnabledToast": "Your number is hidden to the callee", diff --git a/src/routes.js b/src/routes.js index 77936452..be5305f2 100644 --- a/src/routes.js +++ b/src/routes.js @@ -19,6 +19,7 @@ import PbxConfigurationSeats from './components/pages/PbxConfiguration/CscPbxSea import PbxConfigurationDevices from './components/pages/PbxConfiguration/CscPbxDevices' import PbxConfigurationCallQueues from './components/pages/PbxConfiguration/CscPbxCallQueues' import PbxConfigurationSoundSets from './components/pages/PbxConfiguration/CscPbxSoundSets' +import PbxConfigurationMsConfigs from './components/pages/PbxConfiguration/CscPbxMsConfigs' import Voicebox from './components/pages/Voicebox/Voicebox'; import Login from './components/Login' import Error404 from './components/Error404' @@ -147,6 +148,14 @@ export default [ subtitle: i18n.t('navigation.pbxConfiguration.soundSets') } }, + { + path: 'pbx-configuration/ms-configs', + component: PbxConfigurationMsConfigs, + meta: { + title: i18n.t('navigation.pbxConfiguration.title'), + subtitle: i18n.t('navigation.pbxConfiguration.msConfigs') + } + }, { path: 'voicebox', component: Voicebox, diff --git a/src/store/index.js b/src/store/index.js index 679f2ea2..d1cf3dbd 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -14,6 +14,7 @@ import PbxGroupsModule from './pbx-groups' import PbxDevicesModule from './pbx-devices' import PbxCallQueuesModule from './pbx-callqueues' import PbxSoundSetsModule from './pbx-soundsets' +import PbxMsConfigsModule from './pbx-ms-configs' import ReminderModule from './reminder' import SpeedDialModule from './speed-dial' @@ -51,7 +52,8 @@ export const store = new Vuex.Store({ pbxGroups: PbxGroupsModule, pbxDevices: PbxDevicesModule, pbxCallQueues: PbxCallQueuesModule, - pbxSoundSets: PbxSoundSetsModule + pbxSoundSets: PbxSoundSetsModule, + pbxMsConfigs: PbxMsConfigsModule }, getters: { diff --git a/src/store/pbx-callqueues.js b/src/store/pbx-callqueues.js index 28728c9c..c09f466e 100644 --- a/src/store/pbx-callqueues.js +++ b/src/store/pbx-callqueues.js @@ -79,15 +79,15 @@ export default { return ''; }, getCallQueueRemovingName(state) { - let subscriber = state.subscriberMap[state.callQueueRemoving.id]; + let subscriber = _.get(state.subscriberMap, _.get(state.callQueueRemoving, 'id', null), null); return _.get(subscriber, 'display_name', ''); }, getCallQueueCreatingName(state) { - let subscriber = state.subscriberMap[state.callQueueCreationData.subscriber_id]; + let subscriber = _.get(state.subscriberMap, _.get(state.callQueueCreationData, 'subscriber_id', null), null); return _.get(subscriber, 'display_name', ''); }, getCallQueueUpdatingName(state) { - let subscriber = state.subscriberMap[state.callQueueUpdating.id]; + let subscriber = _.get(state.subscriberMap, _.get(state.callQueueUpdating, 'id', null), null); return _.get(subscriber, 'display_name', ''); }, getCallQueueUpdatingField(state) { diff --git a/src/store/pbx-ms-configs.js b/src/store/pbx-ms-configs.js new file mode 100644 index 00000000..baf7d23b --- /dev/null +++ b/src/store/pbx-ms-configs.js @@ -0,0 +1,269 @@ +'use strict'; + +import { + router +} from '../router' +import Vue from 'vue' +import _ from 'lodash' +import { + CreationState, + RequestState +} from "./common"; +import { + getMsConfigList, + createMsConfig, + removeMsConfig, + setSecretaryNumber +} from "../api/pbx-ms-configs"; +import { + i18n +} from "../i18n"; + +export default { + namespaced: true, + state: { + msConfigListState: RequestState.initiated, + msConfigListVisible: true, + msConfigList: [], + msConfigMap: {}, + msConfigSelected: null, + msConfigCreationState: CreationState.initiated, + msConfigCreationData: null, + msConfigCreationError: null, + msConfigUpdateState: RequestState.initiated, + msConfigUpdating: null, + msConfigUpdatingField: null, + msConfigUpdateError: null, + msConfigRemovalState: RequestState.initiated, + msConfigRemoving: null, + msConfigRemovalError: null, + subscriberMap: {} + }, + getters: { + isMsConfigListRequesting(state) { + return state.msConfigListState === RequestState.requesting; + }, + isMsConfigAddFormEnabled(state) { + return state.msConfigCreationState !== CreationState.initiated && + state.msConfigCreationState !== CreationState.created; + }, + isMsConfigCreating(state) { + return state.msConfigCreationState === CreationState.creating; + }, + isMsConfigUpdating(state) { + return state.msConfigUpdateState === RequestState.requesting; + }, + isMsConfigRemoving(state) { + return state.msConfigRemoving === RequestState.requesting; + }, + isMsConfigLoading(state) { + return (id)=>{ + return (state.msConfigRemovalState === RequestState.requesting && + state.msConfigRemoving !== null && state.msConfigRemoving.id === id) || + (state.msConfigUpdateState === RequestState.requesting && + state.msConfigUpdating !== null && state.msConfigUpdating.id === id); + }; + }, + isMsConfigExpanded(state) { + return (id)=>{ + return state.msConfigSelected !== null && state.msConfigSelected.id === id; + }; + }, + getMsConfigRemoveDialogMessage(state) { + if(state.msConfigRemoving !== null) { + return i18n.t('pbxConfig.msConfigRemovalDialogText', { + msConfig: state.subscriberMap[state.msConfigRemoving.id].display_name + }); + } + return ''; + }, + getMsConfigRemovingName(state) { + let subscriber = _.get(state.subscriberMap, _.get(state.msConfigRemoving, 'id', null), null); + return _.get(subscriber, 'display_name', ''); + }, + getMsConfigCreatingName(state) { + let subscriber = _.get(state.subscriberMap, _.get(state.msConfigCreationData, 'subscriberId', null), null); + return _.get(subscriber, 'display_name', ''); + }, + getMsConfigUpdatingName(state) { + let subscriber = _.get(state.subscriberMap, _.get(state.msConfigUpdating, 'id', null), null); + return _.get(subscriber, 'display_name', ''); + }, + getMsConfigUpdatingField(state) { + return state.msConfigUpdatingField; + }, + getMsConfigRemovalDialogMessage(state, getters) { + if(getters.isMsConfigRemoving) { + return i18n.t('pbxConfig.msConfigRemovalDialogMessage', { + msConfig: getters.getMsConfigRemovingName + }); + } + return ''; + }, + getMsConfigCreationToastMessage(state, getters) { + return i18n.t('pbxConfig.msConfigCreationToast', { + msConfig: getters.getMsConfigCreatingName + }); + }, + getMsConfigUpdateToastMessage(state, getters) { + return i18n.t('pbxConfig.msConfigUpdateToast', { + msConfig: getters.getMsConfigUpdatingName, + field: getters.getMsConfigUpdatingField + }); + }, + getMsConfigRemovalToastMessage(state, getters) { + return i18n.t('pbxConfig.msConfigRemovalToast', { + msConfig: getters.getMsConfigRemovingName + }); + } + }, + mutations: { + msConfigListRequesting(state, options) { + state.msConfigListState = RequestState.requesting; + if(!options.listVisible) { + state.msConfigList = []; + state.msConfigMap = {}; + state.msConfigListVisible = false; + } + else { + state.msConfigListVisible = true; + } + }, + msConfigListSucceeded(state, msConfigList) { + state.msConfigListState = RequestState.succeeded; + state.msConfigList = _.get(msConfigList, 'msConfigs.items', []); + state.msConfigList.forEach((msConfig) => { + Vue.set(state.msConfigMap, msConfig.id, msConfig); + }); + _.get(msConfigList, 'subscribers.items', []).forEach((subscriber) => { + Vue.set(state.subscriberMap, subscriber.id, subscriber); + }); + state.msConfigListVisible = true; + }, + msConfigCreationRequesting(state, data) { + state.msConfigCreationState = CreationState.creating; + state.msConfigCreationData = data; + }, + msConfigCreationSucceeded(state) { + state.msConfigCreationState = CreationState.created; + }, + msConfigCreationFailed(state, err) { + state.msConfigCreationState = CreationState.error; + state.msConfigCreationError = err; + }, + msConfigRemovalRequesting(state, msConfigId) { + state.msConfigRemovalState = RequestState.requesting; + if(msConfigId) { + state.msConfigRemoving = state.msConfigMap[msConfigId]; + } + }, + msConfigRemovalCanceled(state) { + state.msConfigRemovalState = RequestState.initiated; + state.msConfigRemoving = null; + }, + msConfigRemovalSucceeded(state) { + state.msConfigRemovalState = RequestState.succeeded; + }, + msConfigRemovalFailed(state, err) { + state.msConfigRemovalState = RequestState.failed; + state.msConfigRemovalError = err; + }, + msConfigUpdateRequesting(state, options) { + state.msConfigUpdateState = RequestState.requesting; + state.msConfigUpdating = state.msConfigMap[options.msConfigId]; + state.msConfigUpdatingField = options.field; + }, + msConfigUpdateSucceeded(state, preferences) { + state.msConfigUpdateState = RequestState.succeeded; + if(preferences) { + for(let i = 0; i < state.msConfigList.length; i++) { + if(state.msConfigList[i].id === preferences.id) { + state.msConfigList[i] = preferences; + } + } + Vue.delete(state.msConfigMap, preferences.id); + Vue.set(state.msConfigMap, preferences.id, preferences); + } + }, + msConfigUpdateFailed(state, err) { + state.msConfigUpdateState = RequestState.failed; + state.msConfigUpdateError = err; + }, + enableMsConfigAddForm(state) { + state.msConfigCreationState = CreationState.input; + }, + disableMsConfigAddForm(state) { + state.msConfigCreationState = CreationState.initiated; + }, + expandMsConfig(state, msConfigId) { + state.msConfigSelected = state.msConfigMap[msConfigId]; + }, + collapseMsConfig(state) { + state.msConfigSelected = null; + } + }, + actions: { + loadMsConfigList(context, options) { + return new Promise((resolve)=>{ + let listVisible = _.get(options, 'listVisible', false); + let selectedId = _.get(options, 'selectedId', null); + context.commit('msConfigListRequesting', { + listVisible: listVisible + }); + getMsConfigList().then((msConfigList)=>{ + context.commit('msConfigListSucceeded', msConfigList); + if(selectedId !== null) { + context.commit('expandMsConfig', msConfigList); + context.commit('highlightMsConfig', msConfigList); + } + resolve(); + }).catch(()=>{ + resolve(); + context.commit('msConfigListSucceeded'); + }); + }); + }, + createMsConfig(context, msConfigData) { + context.commit('msConfigCreationRequesting', msConfigData); + createMsConfig(msConfigData).then(()=>{ + return context.dispatch('loadMsConfigList',{ + listVisible: true + }); + }).then(()=>{ + context.commit('msConfigCreationSucceeded'); + }).catch((err)=>{ + console.debug(err); + context.commit('msConfigCreationFailed', err.message); + }); + }, + removeMsConfig(context) { + context.commit('msConfigRemovalRequesting'); + removeMsConfig(context.state.msConfigRemoving.id).then(()=>{ + return context.dispatch('loadMsConfigList',{ + listVisible: true + }); + }).then(()=>{ + context.commit('msConfigRemovalSucceeded'); + }).catch((err)=>{ + console.debug(err); + context.commit('msConfigRemovalFailed', err.message); + }); + }, + setSecretaryNumbers(context, options) { + context.commit('msConfigUpdateRequesting', { + msConfigId: options.msConfigId, + field: i18n.t('pbxConfig.msConfigNumbersLabel') + }); + setSecretaryNumber(options).then((preferences)=>{ + context.commit('msConfigUpdateSucceeded', preferences); + }).catch((err)=>{ + console.debug(err); + context.commit('msConfigUpdateFailed', err.message); + }); + }, + jumpToMsConfig(context, subscriber) { + router.push({path: '/user/pbx-configuration/ms-configs'}); + context.commit('expandMsConfig', subscriber.id); + } + } +}; diff --git a/src/store/pbx.js b/src/store/pbx.js index 4dd81ef8..8b439fa9 100644 --- a/src/store/pbx.js +++ b/src/store/pbx.js @@ -18,6 +18,7 @@ import { import { loadDeviceModel } from "../api/pbx-devices"; +import {getNumbers} from "../api/user"; export default { namespaced: true, @@ -25,6 +26,7 @@ export default { pilot: null, numberList: [], numberMapById: {}, + numberListState: RequestState.initiated, groupList: [], groupMapById: {}, seatList: [], @@ -59,6 +61,16 @@ export default { }); return options; }, + getFullNumberOptions(state) { + let options = []; + state.numberList.forEach((number)=>{ + options.push({ + label: numberFilter(number), + value: numberFilter(number) + }); + }); + return options; + }, getSeatOptions(state) { let options = []; state.seatList.forEach((seat)=>{ @@ -133,13 +145,20 @@ export default { }, isSubscribersRequesting(state) { return state.subscriberListState === RequestState.requesting; + }, + isNumbersRequesting(state) { + return state.numberListState === RequestState.requesting; } }, mutations: { pilotSucceeded(state, pilotItem) { state.pilot = pilotItem; }, + numbersRequesting(state) { + state.numberListState = RequestState.requesting; + }, numbersSucceeded(state, numberList) { + state.numberListState = RequestState.succeeded; state.numberList = _.get(numberList, 'items', []); state.numberMapById = {}; state.numberList.forEach((number)=>{ @@ -250,6 +269,22 @@ export default { }); }); } + }, + loadNumbers(context) { + if(context.state.numberList.length === 0 && + context.state.numberListState !== RequestState.requesting) { + context.commit('numbersRequesting'); + getNumbers({ + all: true + }).then((numbers)=>{ + context.commit('numbersSucceeded', numbers); + }).catch((err)=>{ + console.debug(err); + context.commit('numbersSucceeded', { + items: [] + }); + }); + } } } };