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
changes/09/32009/2
Hans-Peter Herzog 6 years ago
parent fa5486e61f
commit 3b25cc26a3

@ -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);
});
});
}

@ -203,6 +203,17 @@
:label="$t('navigation.pbxConfiguration.soundSets')" :label="$t('navigation.pbxConfiguration.soundSets')"
/> />
</q-side-link> </q-side-link>
<q-side-link
item
to="/user/pbx-configuration/ms-configs"
>
<q-item-side
icon="arrow_forward"
/>
<q-item-main
:label="$t('navigation.pbxConfiguration.msConfigs')"
/>
</q-side-link>
</q-collapsible> </q-collapsible>
</q-list> </q-list>
</template> </template>

@ -95,126 +95,6 @@
</q-field> </q-field>
</template> </template>
</csc-list-item> </csc-list-item>
<!--<q-item-->
<!--:class="itemClasses"-->
<!--&gt;-->
<!--<q-item-side-->
<!--v-if="!expanded"-->
<!--&gt;-->
<!--<q-icon-->
<!--size="24px"-->
<!--name="queue"-->
<!--color="white"-->
<!--/>-->
<!--</q-item-side>-->
<!--<q-item-main>-->
<!--<q-item-tile-->
<!--v-if="!expanded"-->
<!--class="csc-item-title"-->
<!--label-->
<!--&gt;-->
<!--<q-icon-->
<!--v-if="subscriber.is_pbx_group"-->
<!--size="24px"-->
<!--name="group"-->
<!--color="white"-->
<!--/>-->
<!--<q-icon-->
<!--v-else-->
<!--size="24px"-->
<!--name="person"-->
<!--color="white"-->
<!--/>-->
<!--<span class="csc-item-label">{{ subscriber.display_name }}</span>-->
<!--</q-item-tile>-->
<!--<q-item-tile-->
<!--v-if="!expanded"-->
<!--class="csc-item-subtitle"-->
<!--sublabel-->
<!--&gt;-->
<!--<span class="csc-item-label">{{ $t('pbxConfig.queueLength') }}:</span>-->
<!--<span class="csc-item-value">{{ subscriber.max_queue_length }}</span>-->
<!--</q-item-tile>-->
<!--<q-item-tile-->
<!--v-if="!expanded"-->
<!--class="csc-item-subtitle"-->
<!--sublabel-->
<!--&gt;-->
<!--<span class="csc-item-label">{{ $t('pbxConfig.wrapUpTime') }}:</span>-->
<!--<span class="csc-item-value">{{ subscriber.queue_wrap_up_time }}</span>-->
<!--</q-item-tile>-->
<!--<q-item-tile-->
<!--class="csc-list-item-main"-->
<!--v-if="expanded"-->
<!--&gt;-->
<!--<q-field-->
<!--:label="$t('pbxConfig.queueExtensionName')"-->
<!--&gt;-->
<!--<q-input-->
<!--dark-->
<!--readonly-->
<!--:value="subscriber.display_name"-->
<!--/>-->
<!--</q-field>-->
<!--<q-field-->
<!--:label="$t('pbxConfig.queueLength')"-->
<!--:error-label="queueLengthErrorMessage"-->
<!--&gt;-->
<!--<q-input-->
<!--dark-->
<!--:suffix="$t('pbxConfig.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-->
<!--:label="$t('pbxConfig.wrapUpTime')"-->
<!--:error-label="wrapUpTimeErrorMessage"-->
<!--&gt;-->
<!--<q-input-->
<!--dark-->
<!--v-model="changes.queue_wrap_up_time"-->
<!--:after="wrapUpTimeButtons"-->
<!--:suffix="$t('pbxConfig.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-item-tile>-->
<!--</q-item-main>-->
<!--<q-item-side-->
<!--right-->
<!--class="csc-list-actions-pinned"-->
<!--&gt;-->
<!--<q-item-tile>-->
<!--<q-btn-->
<!--v-if="expanded"-->
<!--icon="delete"-->
<!--:big="isMobile"-->
<!--color="negative"-->
<!--flat-->
<!--@click="remove()"-->
<!--/>-->
<!--<q-btn-->
<!--:icon="titleIcon"-->
<!--:big="isMobile"-->
<!--:color="caretColor"-->
<!--flat-->
<!--@click="toggleMain()"-->
<!--/>-->
<!--</q-item-tile>-->
<!--</q-item-side>-->
<!--<csc-object-spinner-->
<!--v-if="loading"-->
<!--:loading="loading"-->
<!--/>-->
<!--</q-item>-->
</template> </template>
<script> <script>
@ -355,128 +235,7 @@
maxValue: this.$v.changes.queue_wrap_up_time.$params.maxValue.max maxValue: this.$v.changes.queue_wrap_up_time.$params.maxValue.max
}); });
} }
}, }
// highlighted() {
// return this.expanded && this.highlight && !this.highlightCollapsed;
// },
// itemClasses() {
// let classes = ['csc-list-item', 'csc-pbx-call-queue'];
// if (this.highlighted) {
// classes.push('csc-item-expanded');
// classes.push('csc-item-highlight');
// }
// else if (this.expanded) {
// classes.push('csc-item-expanded');
// }
// else {
// classes.push('csc-item-collapsed');
// }
// return classes;
// },
// isMobile() {
// return Platform.is.mobile;
// },
// titleIcon() {
// if(!this.expanded) {
// return 'keyboard arrow down';
// }
// else {
// 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 + "";
// },
// isLoading() {
// return this.loading;
// },
// configModel() {
// return {
// id: this.subscriber.id,
// max_queue_length: this.changes.max_queue_length,
// queue_wrap_up_time: this.changes.queue_wrap_up_time
// }
// },
// caretColor() {
// return this.highlighted ? 'white' : 'primary';
// }
}, },
methods: { methods: {
remove() { remove() {

@ -0,0 +1,213 @@
<template>
<csc-list-item
ref="listItem"
icon="arrow_forward"
:odd="odd"
:loading="loading"
:expanded="expanded"
@toggle="toggle"
>
<template
slot="title"
>
<csc-list-item-title
:icon="getTitleIcon"
>
{{ subscriber | displayName }}
</csc-list-item-title>
<q-slide-transition>
<csc-list-item-subtitle
v-if="!expanded"
>
<template
v-if="currentSecretaryNumbers.length > 0"
>
{{ $t('pbxConfig.msConfigNumbersLabel')}}:
<span
v-for="number in currentSecretaryNumbers"
:key="number"
class="csc-list-item-title-keyword"
>
<q-icon
name="call"
size="16px"
/>
{{ number }}
</span>
</template>
<template
v-else
>
<span
>
<q-icon
name="info"
color="info"
size="24px"
/>
{{ $t('pbxConfig.msConfigNoSecretaryNumbers') }}
</span>
</template>
</csc-list-item-subtitle>
</q-slide-transition>
</template>
<template slot="menu">
<csc-list-menu-item
icon="delete"
icon-color="negative"
@click="remove"
>
{{ $t('buttons.remove') }}
</csc-list-menu-item>
</template>
<template
slot="body"
>
<q-field
:label="$t('pbxConfig.msConfigNumbersLabel')"
>
<q-select
dark
multiple
chips
v-model="changes.secretaryNumbers"
:disable="loading || numberOptionsLoading"
:readonly="loading"
:float-label="$t('pbxConfig.msConfigNumberSelectionLabel')"
:options="numberOptions"
/>
<csc-fade>
<csc-form-save-button
v-if="hasSecretaryNumbersChanged"
@click="saveSecretaryNumbers"
/>
</csc-fade>
<csc-fade>
<csc-form-reset-button
v-if="hasSecretaryNumbersChanged"
@click="resetSecretaryNumbers"
/>
</csc-fade>
</q-field>
</template>
</csc-list-item>
</template>
<script>
import _ from 'lodash'
import {
QSlideTransition,
QField,
QInput,
QIcon,
QSelect
} from 'quasar-framework'
import CscFade from "../../transitions/CscFade";
import CscObjectSpinner from "../../CscObjectSpinner";
import CscListItem from "../../CscListItem";
import CscListItemTitle from "../../CscListItemTitle";
import CscListItemSubtitle from "../../CscListItemSubtitle";
import CscListMenuItem from "../../CscListMenuItem";
import CscFormSaveButton from "../../form/CscFormSaveButton";
import CscFormResetButton from "../../form/CscFormResetButton";
export default {
name: 'csc-pbx-call-queue',
props: [
'odd',
'expanded',
'msConfig',
'subscriber',
'loading',
'numberOptions',
'numberOptionsLoading'
],
data () {
return {
changes: this.getDefaultData()
}
},
components: {
CscFormResetButton,
CscFormSaveButton,
CscListItem,
CscListItemTitle,
CscListItemSubtitle,
CscObjectSpinner,
CscListMenuItem,
QSlideTransition,
QField,
QInput,
CscFade,
QIcon,
QSelect
},
mounted() {
this.$emit('ready');
},
validations: {
changes: {
}
},
computed: {
getTitleIcon() {
let icon = 'person';
if(this.subscriber.is_pbx_group) {
icon = 'group';
}
else if (this.subscriber.is_pbx_pilot) {
icon = 'person_outline';
}
return icon;
},
hasSecretaryNumbersChanged() {
let changedSecretaryNumbers = _.get(this.changes, 'secretaryNumbers', []).sort();
let currentSecretaryNumbers = this.currentSecretaryNumbers.sort();
return !_.isEqual(changedSecretaryNumbers, currentSecretaryNumbers);
},
currentSecretaryNumbers() {
return _.get(this.msConfig, 'secretary_numbers', []);
}
},
methods: {
remove() {
if(this.$refs.listItem) {
this.$refs.listItem.closePopoverMenu();
}
this.$emit('remove', this.msConfig.id);
},
toggle() {
if(this.expanded) {
this.$emit('collapse');
}
else {
this.$emit('expand');
}
},
getDefaultData() {
return {
secretaryNumbers: _.clone(_.get(this.msConfig, 'secretary_numbers', []))
}
},
resetSecretaryNumbers() {
this.changes.secretaryNumbers = this.getDefaultData().secretaryNumbers;
},
saveSecretaryNumbers() {
if(this.hasSecretaryNumbersChanged) {
this.$emit('save-secretary-numbers', {
msConfigId: this.msConfig.id,
secretaryNumbers: this.changes.secretaryNumbers
});
}
}
},
watch: {
msConfig() {
this.changes = this.getDefaultData();
},
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/quasar.variables';
</style>

@ -0,0 +1,214 @@
<template>
<div
class="csc-form csc-pbx-ms-config-add-form"
>
<q-field>
<q-select
dark
v-model="data.subscriberId"
:disable="loading || subscriberOptionsLoading"
:readonly="loading"
:stack-label="$t('pbxConfig.msConfigSubscriberSelectionLabel')"
:options="subscriberOptions"
/>
</q-field>
<q-field>
<q-select
dark
multiple
chips
clearable
v-model="data.secretaryNumbers"
:disable="loading || numberOptionsLoading"
:readonly="loading"
:float-label="$t('pbxConfig.msConfigNumberSelectionLabel')"
:options="numberOptions"
/>
</q-field>
<!--<q-field-->
<!--:error-label="maxQueueLengthErrorMessage"-->
<!--&gt;-->
<!--<q-input-->
<!--dark-->
<!--v-model="data.max_queue_length"-->
<!--:error="$v.data.max_queue_length.$error"-->
<!--:disable="loading"-->
<!--:readonly="loading"-->
<!--:float-label="$t('pbxConfig.queueLength')"-->
<!--default="3"-->
<!--@input="$v.data.max_queue_length.$touch"-->
<!--/>-->
<!--</q-field>-->
<!--<q-field-->
<!--:error-label="wrapUpTimeErrorMessage"-->
<!--&gt;-->
<!--<q-input-->
<!--dark-->
<!--v-model="data.queue_wrap_up_time"-->
<!--:error="$v.data.queue_wrap_up_time.$error"-->
<!--:disable="loading"-->
<!--:readonly="loading"-->
<!--:float-label="$t('pbxConfig.wrapUpTime')"-->
<!--:suffix="$t('pbxConfig.seconds')"-->
<!--@input="$v.data.queue_wrap_up_time.$touch"-->
<!--/>-->
<!--</q-field>-->
<div
class="csc-form-actions row justify-center"
>
<q-btn
flat
v-if="!loading"
color="default"
icon="clear"
@click="cancel()"
>
{{ $t('buttons.cancel') }}
</q-btn>
<q-btn
flat
v-if="!loading"
:disable="$v.data.$invalid || !this.secretaryNumbersIsValid"
color="primary"
icon="arrow_forward"
@click="save()"
>
{{ $t('pbxConfig.msConfigCreationLabel') }}
</q-btn>
</div>
<csc-object-spinner
v-if="loading"
:loading="loading"
/>
</div>
</template>
<script>
import _ from 'lodash'
import {
required,
// maxValue,
// minValue,
// numeric
} from 'vuelidate/lib/validators'
import {
QCard,
QCardTitle,
QCardMain,
QCardActions,
QCardSeparator,
QBtn,
QInnerLoading,
QSpinnerMat,
QField,
QInput,
QSelect,
QIcon
} from 'quasar-framework'
import CscObjectSpinner from "../../CscObjectSpinner"
export default {
name: 'csc-pbx-ms-config-add-form',
props: [
'loading',
'subscriberOptions',
'subscriberOptionsLoading',
'numberOptions',
'numberOptionsLoading'
],
components: {
CscObjectSpinner,
QCard,
QCardTitle,
QCardMain,
QCardActions,
QCardSeparator,
QBtn,
QInnerLoading,
QSpinnerMat,
QField,
QInput,
QSelect,
QIcon
},
validations: {
data: {
subscriberId: {
required
}
}
},
data () {
return {
data: this.getDefaults()
}
},
mounted() {
this.$emit('ready');
},
computed: {
// maxQueueLengthErrorMessage() {
// if (!this.$v.data.max_queue_length.numeric) {
// return this.$t('validationErrors.numeric', {
// field: this.$t('pbxConfig.queueLength'),
// });
// }
// else if (!this.$v.data.max_queue_length.minValue) {
// return this.$t('validationErrors.minValueSecond', {
// field: this.$t('pbxConfig.queueLength'),
// minValue: this.$v.data.max_queue_length.$params.minValue.min
// });
// }
// else if (!this.$v.data.max_queue_length.maxValue) {
// return this.$t('validationErrors.maxValueSecond', {
// field: this.$t('pbxConfig.queueLength'),
// maxValue: this.$v.data.max_queue_length.$params.maxValue.max
// });
// }
// },
// wrapUpTimeErrorMessage() {
// if (!this.$v.data.queue_wrap_up_time.numeric) {
// return this.$t('validationErrors.numeric', {
// field: this.$t('pbxConfig.wrapUpTime'),
// });
// }
// else if (!this.$v.data.queue_wrap_up_time.minValue) {
// return this.$t('validationErrors.minValueSecond', {
// field: this.$t('pbxConfig.wrapUpTime'),
// minValue: this.$v.data.queue_wrap_up_time.$params.minValue.min
// });
// }
// else if (!this.$v.data.queue_wrap_up_time.maxValue) {
// return this.$t('validationErrors.maxValueSecond', {
// field: this.$t('pbxConfig.wrapUpTime'),
// maxValue: this.$v.data.queue_wrap_up_time.$params.maxValue.max
// });
// }
// }
secretaryNumbersIsValid() {
return _.get(this.data, 'secretaryNumbers.length', 0) > 0;
}
},
methods: {
getDefaults() {
return {
subscriberId: null,
secretaryNumbers: []
}
},
cancel() {
this.$emit('cancel');
},
save() {
this.$emit('submit', this.data);
},
reset() {
this.data = this.getDefaults();
this.$v.$reset();
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/app.common.styl';
</style>

@ -0,0 +1,242 @@
<template>
<csc-page
:is-list="true"
>
<csc-list-actions>
<csc-list-action-button
v-if="!isMsConfigAddFormEnabled"
slot="slot1"
icon="add"
color="primary"
:label="$t('pbxConfig.msConfigCreationIndicationLabel')"
@click="enableMsConfigAddForm"
/>
</csc-list-actions>
<q-slide-transition>
<div
v-if="isMsConfigAddFormEnabled"
class="row justify-center"
>
<csc-pbx-ms-config-add-form
class="csc-list-form col-xs-12 col-md-6"
:loading="isMsConfigCreating"
:subscriber-options="getSubscriberOptions"
:subscriber-options-loading="isSubscribersRequesting"
:number-options="getFullNumberOptions"
:numbers-options-loading="isNumbersRequesting"
@cancel="disableMsConfigAddForm"
@submit="createMsConfig"
@ready="addFormReady"
/>
</div>
</q-slide-transition>
<csc-list-spinner
v-if="isMsConfigListRequesting && !msConfigListVisible"
/>
<csc-list
v-if="!isMsConfigListRequesting || msConfigListVisible"
>
<csc-fade
v-for="(msConfig, index) in msConfigList"
:key="'csc-fade-'+msConfig.id"
>
<csc-pbx-ms-config
:key="msConfig.id"
:odd="(index % 2) === 0"
:loading="isMsConfigLoading(msConfig.id)"
:expanded="isMsConfigExpanded(msConfig.id)"
:msConfig="msConfig"
:subscriber="subscriberMap[msConfig.id]"
:number-options="getFullNumberOptions"
:numbers-options-loading="isNumbersRequesting"
@remove="openMsConfigRemovalDialog"
@expand="expandMsConfig(msConfig.id)"
@collapse="collapseMsConfig"
@ready="addFormReady"
@save-secretary-numbers="setSecretaryNumbers"
/>
</csc-fade>
</csc-list>
<csc-remove-dialog
ref="removeDialog"
:title="$t('pbxConfig.msConfigRemovalDialogTitle')"
:message="getMsConfigRemoveDialogMessage"
@remove="removeMsConfig"
@cancel="closeMsConfigRemovalDialog"
/>
</csc-page>
</template>
<script>
import CscPage from '../../CscPage'
import CscPbxMsConfig from './CscPbxMsConfig'
import CscPbxMsConfigAddForm from './CscPbxMsConfigAddForm'
import CscRemoveDialog from '../../CscRemoveDialog'
import CscListSpinner from '../../CscListSpinner'
import CscListActions from '../../CscListActions'
import {
mapState,
mapActions,
mapGetters,
mapMutations
} from 'vuex'
// import {
// CreationState,
// RequestState
// } from "../../../store/common"
// import {
// showGlobalError,
// showToast
// } from '../../../helpers/ui'
import {
QField,
QInput,
QIcon,
QSelect,
QChip,
QList,
QItem,
QItemSide,
QItemMain,
QItemTile,
QSpinnerDots,
QBtn,
QSlideTransition
} from 'quasar-framework'
import CscSpinner from "../../CscSpinner";
import CscList from "../../CscList";
import CscFade from "../../transitions/CscFade";
import CscListActionButton from "../../CscListActionButton";
export default {
components: {
CscListActionButton,
CscFade,
CscList,
CscSpinner,
CscPage,
CscPbxMsConfig,
CscPbxMsConfigAddForm,
CscRemoveDialog,
QField,
QInput,
QIcon,
QSelect,
QChip,
QList,
QItem,
QItemSide,
QItemMain,
QItemTile,
QSpinnerDots,
QBtn,
QSlideTransition,
CscListSpinner,
CscListActions
},
data () {
return {
}
},
mounted() {
this.loadMsConfigList();
},
computed: {
...mapGetters('pbx', [
'isSubscribersRequesting',
'getSubscriberOptions',
'isNumbersRequesting',
'getFullNumberOptions'
]),
...mapState('pbxMsConfigs', [
'msConfigList',
'msConfigListVisible',
'subscriberMap',
'msConfigCreationState',
'msConfigUpdateState',
'msConfigRemovalState',
'msConfigCreationError',
'msConfigUpdateError',
'msConfigRemovalError'
]),
...mapGetters('pbxMsConfigs', [
'isMsConfigListRequesting',
'isMsConfigAddFormEnabled',
'isMsConfigCreating',
'getMsConfigRemoveDialogMessage',
'isMsConfigLoading',
'isMsConfigExpanded',
'getMsConfigCreationToastMessage',
'getMsConfigUpdateToastMessage',
'getMsConfigRemovalToastMessage'
])
},
methods: {
...mapActions('pbx', [
'loadSubscribers',
'loadNumbers'
]),
...mapMutations('pbxMsConfigs', [
'enableMsConfigAddForm',
'disableMsConfigAddForm',
'msConfigRemovalRequesting',
'msConfigRemovalCanceled',
'expandMsConfig',
'collapseMsConfig'
]),
...mapActions('pbxMsConfigs', [
'loadMsConfigList',
'createMsConfig',
'removeMsConfig',
'setSecretaryNumbers'
]),
openMsConfigRemovalDialog(msConfigId) {
if(this.$refs.removeDialog) {
this.$refs.removeDialog.open();
}
this.msConfigRemovalRequesting(msConfigId);
},
closeMsConfigRemovalDialog() {
if(this.$refs.removeDialog) {
this.$refs.removeDialog.close();
}
this.msConfigRemovalCanceled();
},
addFormReady() {
this.loadSubscribers();
this.loadNumbers();
}
},
watch: {
// msConfigCreationState(state) {
// if(state === CreationState.created) {
// this.$scrollTo(this.$parent.$el);
// showToast(this.getMsConfigCreationToastMessage);
// }
// else if(state === CreationState.error) {
// showGlobalError(this.msConfigCreationError);
// }
// },
// msConfigUpdateState(state) {
// if(state === RequestState.succeeded) {
// showToast(this.getMsConfigUpdateToastMessage);
// }
// else if(state === RequestState.failed) {
// showGlobalError(this.msConfigUpdateError);
// }
// },
// msConfigRemovalState(state) {
// if(state === RequestState.succeeded) {
// this.$scrollTo(this.$parent.$el);
// showToast(this.getMsConfigRemovalToastMessage);
// }
// else if(state === RequestState.failed) {
// showGlobalError(this.msConfigRemovalError);
// }
// }
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/quasar.variables.styl';
</style>

@ -256,15 +256,6 @@
this.selectedFile = this.resetFile(); 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();
// }
// }
} }
} }
</script> </script>

@ -186,17 +186,6 @@
} }
}, },
watch: { 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));
// }
// }
} }
} }
</script> </script>

@ -105,7 +105,8 @@
"seats": "Seats", "seats": "Seats",
"devices": "Devices", "devices": "Devices",
"callQueues": "Call Queues", "callQueues": "Call Queues",
"soundSets": "Sound Sets" "soundSets": "Sound Sets",
"msConfigs": "Manager Secretary"
}, },
"voicebox": { "voicebox": {
"title": "Voicebox", "title": "Voicebox",
@ -486,7 +487,15 @@
"deviceCreationToast": "Created device {device} successfully", "deviceCreationToast": "Created device {device} successfully",
"deviceUpdateToast": "Updated {field} for device {device} successfully", "deviceUpdateToast": "Updated {field} for device {device} successfully",
"deviceRemovalToast": "Removed 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": { "callBlocking": {
"privacyEnabledToast": "Your number is hidden to the callee", "privacyEnabledToast": "Your number is hidden to the callee",

@ -19,6 +19,7 @@ import PbxConfigurationSeats from './components/pages/PbxConfiguration/CscPbxSea
import PbxConfigurationDevices from './components/pages/PbxConfiguration/CscPbxDevices' import PbxConfigurationDevices from './components/pages/PbxConfiguration/CscPbxDevices'
import PbxConfigurationCallQueues from './components/pages/PbxConfiguration/CscPbxCallQueues' import PbxConfigurationCallQueues from './components/pages/PbxConfiguration/CscPbxCallQueues'
import PbxConfigurationSoundSets from './components/pages/PbxConfiguration/CscPbxSoundSets' import PbxConfigurationSoundSets from './components/pages/PbxConfiguration/CscPbxSoundSets'
import PbxConfigurationMsConfigs from './components/pages/PbxConfiguration/CscPbxMsConfigs'
import Voicebox from './components/pages/Voicebox/Voicebox'; import Voicebox from './components/pages/Voicebox/Voicebox';
import Login from './components/Login' import Login from './components/Login'
import Error404 from './components/Error404' import Error404 from './components/Error404'
@ -147,6 +148,14 @@ export default [
subtitle: i18n.t('navigation.pbxConfiguration.soundSets') 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', path: 'voicebox',
component: Voicebox, component: Voicebox,

@ -14,6 +14,7 @@ import PbxGroupsModule from './pbx-groups'
import PbxDevicesModule from './pbx-devices' import PbxDevicesModule from './pbx-devices'
import PbxCallQueuesModule from './pbx-callqueues' import PbxCallQueuesModule from './pbx-callqueues'
import PbxSoundSetsModule from './pbx-soundsets' import PbxSoundSetsModule from './pbx-soundsets'
import PbxMsConfigsModule from './pbx-ms-configs'
import ReminderModule from './reminder' import ReminderModule from './reminder'
import SpeedDialModule from './speed-dial' import SpeedDialModule from './speed-dial'
@ -51,7 +52,8 @@ export const store = new Vuex.Store({
pbxGroups: PbxGroupsModule, pbxGroups: PbxGroupsModule,
pbxDevices: PbxDevicesModule, pbxDevices: PbxDevicesModule,
pbxCallQueues: PbxCallQueuesModule, pbxCallQueues: PbxCallQueuesModule,
pbxSoundSets: PbxSoundSetsModule pbxSoundSets: PbxSoundSetsModule,
pbxMsConfigs: PbxMsConfigsModule
}, },
getters: { getters: {

@ -79,15 +79,15 @@ export default {
return ''; return '';
}, },
getCallQueueRemovingName(state) { 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', ''); return _.get(subscriber, 'display_name', '');
}, },
getCallQueueCreatingName(state) { 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', ''); return _.get(subscriber, 'display_name', '');
}, },
getCallQueueUpdatingName(state) { 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', ''); return _.get(subscriber, 'display_name', '');
}, },
getCallQueueUpdatingField(state) { getCallQueueUpdatingField(state) {

@ -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);
}
}
};

@ -18,6 +18,7 @@ import {
import { import {
loadDeviceModel loadDeviceModel
} from "../api/pbx-devices"; } from "../api/pbx-devices";
import {getNumbers} from "../api/user";
export default { export default {
namespaced: true, namespaced: true,
@ -25,6 +26,7 @@ export default {
pilot: null, pilot: null,
numberList: [], numberList: [],
numberMapById: {}, numberMapById: {},
numberListState: RequestState.initiated,
groupList: [], groupList: [],
groupMapById: {}, groupMapById: {},
seatList: [], seatList: [],
@ -59,6 +61,16 @@ export default {
}); });
return options; return options;
}, },
getFullNumberOptions(state) {
let options = [];
state.numberList.forEach((number)=>{
options.push({
label: numberFilter(number),
value: numberFilter(number)
});
});
return options;
},
getSeatOptions(state) { getSeatOptions(state) {
let options = []; let options = [];
state.seatList.forEach((seat)=>{ state.seatList.forEach((seat)=>{
@ -133,13 +145,20 @@ export default {
}, },
isSubscribersRequesting(state) { isSubscribersRequesting(state) {
return state.subscriberListState === RequestState.requesting; return state.subscriberListState === RequestState.requesting;
},
isNumbersRequesting(state) {
return state.numberListState === RequestState.requesting;
} }
}, },
mutations: { mutations: {
pilotSucceeded(state, pilotItem) { pilotSucceeded(state, pilotItem) {
state.pilot = pilotItem; state.pilot = pilotItem;
}, },
numbersRequesting(state) {
state.numberListState = RequestState.requesting;
},
numbersSucceeded(state, numberList) { numbersSucceeded(state, numberList) {
state.numberListState = RequestState.succeeded;
state.numberList = _.get(numberList, 'items', []); state.numberList = _.get(numberList, 'items', []);
state.numberMapById = {}; state.numberMapById = {};
state.numberList.forEach((number)=>{ 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: []
});
});
}
} }
} }
}; };

Loading…
Cancel
Save