TT#28063 Destinations grouped by SourceSets

What has been done:
- TT#35420, CallForwarding: Implement the UI for sourceset tabs
- TT#35421, CallForwarding: Implement the UI for listing of sources
- TT#35422, CallForwarding: Implement API methods
- TT#35423, CallForwarding: For sources list, implement component
  methods/computations and store mutations/actions
- TT#35433, CallForwarding: For sourceset tabs, implement component
  methods/computations and store mutations/actions

Change-Id: I0747c45778a9db068f77422f316eb7522e3cb14c
changes/82/20682/8
raxelsen 7 years ago committed by Hans-Peter Herzog
parent 6809615e46
commit 77b84d6329

@ -35,7 +35,11 @@ export function getSourcesets(id) {
return Promise.resolve(result);
}
}).then(result => {
resolve(getJsonBody(result.body)._embedded['ngcp:cfsourcesets']);
let sourcesets = [];
if (getJsonBody(result.body)._embedded) {
sourcesets = getJsonBody(result.body)._embedded['ngcp:cfsourcesets'];
}
resolve(sourcesets);
}).catch(err => {
reject(err);
});
@ -90,36 +94,69 @@ export function getDestinationsets(id) {
});
}
export function loadEverybodyDestinations(options) {
return new Promise((resolve, reject)=>{
export function loadDestinations(options) {
return new Promise((resolve, reject) => {
Promise.resolve().then(() => {
return getSourcesets(options.subscriberId);
}).then((sourcesets) => {
let sourcesetsCollection = [{
id: null,
name: null
}];
let destinationPromises = [];
sourcesets.map((sourceset) => {
sourcesetsCollection.push({
id: sourceset.id,
name: sourceset.name
})
});
sourcesetsCollection.forEach((sourceset) => {
destinationPromises.push(
getDestinationsBySourcesetId({
timeset: options.timeset,
sourceset_id: sourceset.id,
sourceset_name: sourceset.name,
subscriberId: options.subscriberId
})
)
});
resolve(Promise.all(destinationPromises));
}).catch((err) => {
reject(err);
});
});
}
export function getDestinationsBySourcesetId(options) {
return new Promise((resolve, reject) => {
let cfuTimeset = null;
let cfnaTimeset = null;
let cfbTimeset = null;
Promise.resolve().then(()=>{
Promise.resolve().then(() => {
return getMappings(options.subscriberId);
}).then((mappings)=>{
}).then((mappings) => {
let cfuPromises = [];
let cfnaPromises = [];
let cfbPromises = [];
if(_.has(mappings, 'cfu') && _.isArray(mappings.cfu) && mappings.cfu.length > 0) {
mappings.cfu.forEach((cfuMapping)=>{
if (cfuMapping.timeset === options.timeset && cfuMapping.sourceset_id === null) {
mappings.cfu.forEach((cfuMapping) => {
if (cfuMapping.timeset === options.timeset && cfuMapping.sourceset_id === options.sourceset_id) {
cfuTimeset = cfuMapping.timeset_id;
cfuPromises.push(getDestinationsetById(cfuMapping.destinationset_id));
}
});
}
if(_.has(mappings, 'cfna') && _.isArray(mappings.cfna) && mappings.cfna.length > 0) {
mappings.cfna.forEach((cfnaMapping)=>{
if (cfnaMapping.timeset === options.timeset && cfnaMapping.sourceset_id === null) {
mappings.cfna.forEach((cfnaMapping) => {
if (cfnaMapping.timeset === options.timeset && cfnaMapping.sourceset_id === options.sourceset_id) {
cfnaTimeset = cfnaMapping.timeset_id;
cfnaPromises.push(getDestinationsetById(cfnaMapping.destinationset_id));
}
});
}
if(_.has(mappings, 'cfb') && _.isArray(mappings.cfb) && mappings.cfb.length > 0) {
mappings.cfb.forEach((cfbMapping)=>{
if (cfbMapping.timeset === options.timeset && cfbMapping.sourceset_id === null) {
mappings.cfb.forEach((cfbMapping) => {
if (cfbMapping.timeset === options.timeset && cfbMapping.sourceset_id === options.sourceset_id) {
cfbTimeset = cfbMapping.timeset_id;
cfbPromises.push(getDestinationsetById(cfbMapping.destinationset_id));
}
@ -130,15 +167,19 @@ export function loadEverybodyDestinations(options) {
Promise.all(cfnaPromises),
Promise.all(cfbPromises)
]);
}).then((res)=>{
addNameIdAndTerminating({ group: res[0], groupName: 'cfu', timesetId: cfuTimeset });
addNameIdAndTerminating({ group: res[1], groupName: 'cfna', timesetId: cfnaTimeset });
addNameIdAndTerminating({ group: res[2], groupName: 'cfb', timesetId: cfbTimeset });
}).then((result) => {
addNameIdAndTerminating({ group: result[0], groupName: 'cfu', timesetId: cfuTimeset });
addNameIdAndTerminating({ group: result[1], groupName: 'cfna', timesetId: cfnaTimeset });
addNameIdAndTerminating({ group: result[2], groupName: 'cfb', timesetId: cfbTimeset });
resolve({
online: res[0],
offline: res[1],
busy: res[2]
});
sourcesetId: options.sourceset_id,
sourcesetName: options.sourceset_name,
destinationGroups: {
online: result[0],
offline: result[1],
busy: result[2]
}
})
}).catch((err)=>{
reject(err);
});
@ -282,7 +323,7 @@ export function addDestinationToEmptyGroup(options) {
let updatedMappings = mappings[options.groupName];
updatedMappings.push({
destinationset_id: destinationsetId,
sourceset_id: null,
sourceset_id: options.sourcesetId,
timeset_id: options.timesetId
});
return addNewMapping({

@ -8,10 +8,6 @@
import CscPage from '../../CscPage'
import CscCallForwardTimeset from './CscCallForwardTimeset'
export default {
data () {
return {
}
},
components: {
CscPage,
CscCallForwardTimeset
@ -20,6 +16,4 @@
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/quasar.variables.styl'
</style>

@ -1,33 +1,61 @@
<template>
<csc-page :title="$t('pages.callForward.titles.always')">
<csc-call-forward-destinations :timeset="alwaysTimeset" :destinations="destinations">
</csc-call-forward-destinations>
<csc-sourcesets v-if="destinationsLoaded" :sourcesets="sourcesets"
:destinations="destinations" :timesetName="timesetName" />
</csc-page>
</template>
<script>
import { mapState } from 'vuex'
import { mapState, mapGetters } from 'vuex'
import {
startLoading,
stopLoading,
showGlobalError
} from '../../../helpers/ui'
import CscPage from '../../CscPage'
import CscCallForwardDestinations from './CscCallForwardDestinations'
import CscSourcesets from './CscSourcesets'
export default {
data () {
return {}
return {
timesetName: null // In API layer the actual value used is null
}
},
components: {
CscPage,
CscCallForwardDestinations
CscSourcesets
},
created() {
this.$store.dispatch('callForward/loadEverybodyDestinations', {
this.$store.dispatch('callForward/loadDestinations', {
timeset: null
});
this.$store.dispatch('callForward/loadSourcesets');
},
computed: {
...mapState('callForward', [
'destinations'
'destinations',
'sourcesets',
'loadDestinationState',
'loadDestinationError'
]),
...mapGetters('callForward', [
'destinationsLoaded'
]),
alwaysTimeset() {
return null;
destinationsLoaded() {
return this.destinations.length > 0;
}
},
watch: {
loadDestinationState(state) {
if (state === 'requesting') {
startLoading();
}
else if (state === 'failed') {
stopLoading();
showGlobalError(this.loadDestinationError);
}
else if (state === 'succeeded') {
stopLoading();
}
}
}
}

@ -8,10 +8,6 @@
import CscPage from '../../CscPage'
import CscCallForwardTimeset from './CscCallForwardTimeset'
export default {
data () {
return {
}
},
components: {
CscPage,
CscCallForwardTimeset
@ -20,6 +16,4 @@
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/quasar.variables.styl'
</style>

@ -49,7 +49,8 @@
'groupName',
'priority',
'timeset',
'timesetId'
'timesetId',
'sourcesetId'
],
data () {
return {
@ -140,7 +141,8 @@
form: this.destinationForm,
destinations: this.destinations,
timeset: this.timeset,
timesetId: this.timesetId
timesetId: this.timesetId,
sourcesetId: this.sourcesetId
});
}
}

@ -5,18 +5,21 @@
:group="destinations.online"
group-name="cfu"
:timeset="timeset"
:sourceset="sourceset"
icon="smartphone" />
<csc-destinations :title="$t('pages.callForward.whenBusy')"
class="csc-destinations"
:group="destinations.busy"
group-name="cfb"
:timeset="timeset"
:sourceset="sourceset"
icon="phonelink_ring" />
<csc-destinations :title="$t('pages.callForward.whenOffline')"
class="csc-destinations"
:group="destinations.offline"
group-name="cfna"
:timeset="timeset"
:sourceset="sourceset"
icon="phonelink_erase" />
</div>
</template>
@ -30,6 +33,7 @@
name: 'csc-call-forward-destinations',
props: [
'timeset',
'sourceset',
'destinations'
],
data () {
@ -63,7 +67,7 @@
},
methods: {
reloadDestinations(timeset) {
this.$store.dispatch('callForward/loadEverybodyDestinations', {
this.$store.dispatch('callForward/loadDestinations', {
timeset: timeset
});
},

@ -1,8 +1,10 @@
<template>
<div>
<div v-if="showTimesAndDestinations">
<csc-call-forward-times :times="timesetTimes" :timesetName="timesetName" ref="times"></csc-call-forward-times>
<csc-call-forward-destinations :timeset="timesetName" :destinations="destinations" />
<csc-call-forward-times :times="timesetTimes"
:timesetName="timesetName" ref="times"></csc-call-forward-times>
<csc-sourcesets v-if="destinationsLoaded" :sourcesets="sourcesets"
:destinations="destinations" :timesetName="timesetName" />
</div>
<q-card flat>
<div v-if="timesetHasDuplicate">
@ -41,22 +43,25 @@
{{ $t('pages.callForward.times.timesetNotDefined', { timeset: timesetName }) }}
</q-alert>
</div>
<csc-add-time-form v-if="activeTimeForm && !timesetExists"
type="new" :title="getAddLabel"
:timeset="timesetName"
ref="addTimeNew" />
<csc-add-time-form v-if="activeTimeForm && !timesetExists" type="new"
:title="getAddLabel" :timeset="timesetName" ref="addTimeNew" />
</q-card>
</div>
</template>
<script>
import { mapState, mapGetters } from 'vuex'
import { startLoading, stopLoading,
showGlobalError, showToast } from '../../../helpers/ui'
import { QAlert, QCard } from 'quasar-framework'
import {
startLoading,
stopLoading,
showGlobalError,
showToast
} from '../../../helpers/ui'
import CscCallForwardDestinations from './CscCallForwardDestinations'
import CscCallForwardTimes from './CscCallForwardTimes'
import CscAddTimeForm from './CscAddTimeForm'
import CscSourcesets from './CscSourcesets'
export default {
name: 'csc-call-forward-timeset',
props: [
@ -74,6 +79,7 @@
CscCallForwardDestinations,
CscCallForwardTimes,
CscAddTimeForm,
CscSourcesets,
QAlert,
QCard
},
@ -87,12 +93,17 @@
'timesetIsCompatible',
'timesetHasReverse',
'timesetExists',
'activeTimeForm'
'activeTimeForm',
'sourcesets',
'loadDestinationState'
]),
...mapGetters('callForward', [
'resetTimeError',
'addTimeError',
'showDefinedAlert'
'showDefinedAlert',
'destinationsLoaded',
'showTimesAndDestinations',
'loadDestinationError'
]),
labelReset() {
return this.$t('pages.callForward.times.resetTimeset', {
@ -103,12 +114,6 @@
return this.$t('pages.callForward.times.addTimeset', {
timeset: this.timesetName
});
},
showTimesAndDestinations() {
return this.timesetIsCompatible &&
!this.timesetHasReverse &&
!this.timesetHasDuplicate &&
this.timesetExists;
}
},
methods: {
@ -118,8 +123,11 @@
addTimeset() {
this.$store.commit('callForward/setActiveTimeForm', true);
},
loadSourcesets() {
this.$store.dispatch('callForward/loadSourcesets');
},
loadDestinations() {
this.$store.dispatch('callForward/loadEverybodyDestinations', {
this.$store.dispatch('callForward/loadDestinations', {
timeset: this.timesetName
});
},
@ -133,6 +141,7 @@
this.$store.commit('callForward/resetTimesetState');
this.loadTimes();
this.loadDestinations();
this.loadSourcesets();
},
resetAlerts() {
this.showAlertDuplicate = true;
@ -187,6 +196,18 @@
if (!state) {
this.resetAlerts();
}
},
loadDestinationState(state) {
if (state === 'requesting') {
startLoading();
}
else if (state === 'failed') {
stopLoading();
showGlobalError(this.loadDestinationError);
}
else if (state === 'succeeded') {
stopLoading();
}
}
}
}

@ -15,7 +15,7 @@
/>
</div>
</q-list>
<csc-add-destination-form v-bind="lastDestinationset" />
<csc-add-destination-form v-bind="lastDestinationset" :sourcesetId="sourceset" />
</div>
</template>
@ -31,7 +31,8 @@
'icon',
'group',
'groupName',
'timeset'
'timeset',
'sourceset'
],
components: {
QList,

@ -0,0 +1,111 @@
<template>
<q-tabs no-pane-border inverted>
<q-tab v-for="(sourceset, index) in destinations" :default="index === 0"
:count="destinationsCount(sourceset.destinationGroups)"
:key="sourceset.sourcesetId || 0" slot="title"
:name="sourceset.sourcesetName || 'Everybody'" icon="people"
:label="sourceset.sourcesetName || 'Everybody'" />
<q-tab-pane v-for="sourceset in destinations"
:key="sourceset.sourcesetId || 0"
:name="sourceset.sourcesetName || 'Everybody'">
<div class="sources-section" v-if="sourceset.sourcesetId">
<div class="sources-title">
<q-icon name="contact_phone" class="sources-icon" />
{{ $t('pages.callForward.titles.sources') }}
</div>
<q-list no-border>
<q-item highlight separator
v-for="source in sourcesetSources(sourceset.sourcesetId)"
class="source-item">
{{ source.source }}
</q-item>
</q-list>
</div>
<csc-call-forward-destinations
:sourceset="sourceset.sourcesetId"
:timeset="timesetName"
:destinations="sourceset.destinationGroups" />
</q-tab-pane>
</q-tabs>
</template>
<script>
import CscCallForwardDestinations from './CscCallForwardDestinations'
import {
QTabs,
QTab,
QTabPane,
QBtn,
QList,
QItem,
QIcon
} from 'quasar-framework'
export default {
name: 'csc-sourcesets',
props: [
'destinations',
'sourcesets',
'timesetName'
],
components: {
CscCallForwardDestinations,
QTabs,
QTab,
QTabPane,
QBtn,
QList,
QItem,
QIcon
},
methods: {
sourcesetSources(id) {
return this.sourcesets.filter((sourceset) => {
return sourceset.id === id;
})[0].sources;
},
destinationsCount(groups) {
let groupCollection = [
{ name: 'busy', length: 0 },
{ name: 'offline', length: 0 },
{ name: 'online', length: 0 }
];
groupCollection.forEach((group) => {
if (groups[group.name].length > 0) {
let count = 0;
groups[group.name].forEach((destinationSet) => {
count += destinationSet.destinations.length;
});
group.length = count;
}
});
return groupCollection[0].length + groupCollection[1].length + groupCollection[2].length;
},
tabId(id) {
return id === null ? 0 : id;
},
tabName(name) {
return name === null ? 'Everybody' : name;
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/quasar.variables.styl'
.q-item-highlight.source-item:hover
background-color lighten($primary, 70%)
.q-item.source-item
padding 0
.sources-section
padding 30px 0 20px 0
.sources-title
color $secondary
font-size 16px
.sources-icon
margin-right 5px
</style>

@ -131,7 +131,8 @@
"titles": {
"always": "Always",
"companyHours": "Company Hours",
"afterHours": "After Hours"
"afterHours": "After Hours",
"sources": "Sources"
},
"buttons": {
"addNumber": "Add Number",
@ -170,6 +171,7 @@
"resetSuccessMessage": "Reset of timesets completed",
"addTimeSuccessMessage": "Created new timeset",
"addTimeErrorMessage": "An error occured while trying to create the timeset. Please try again.",
"loadDestinationErrorMessage": "An error occured while trying to load the destinations. Please try again.",
"noTimeSet": "no time set",
"addTimeButton": "Add Time",
"timesetIncompatible": "The {timeset} timeset contains incompatible values. You can resolve this by resetting the {timeset} timeset.",

@ -3,11 +3,11 @@
import _ from 'lodash';
import { i18n } from '../i18n';
import { getSourcesets,
import {
getSourcesets,
getDestinationsets,
getTimesets,
getMappings,
loadEverybodyDestinations,
deleteDestinationFromDestinationset,
addDestinationToDestinationset,
addDestinationToEmptyGroup,
@ -20,7 +20,9 @@ import { getSourcesets,
deleteTimesetById,
resetTimesetByName,
createTimesetWithTime,
appendTimeToTimeset } from '../api/call-forward';
appendTimeToTimeset,
loadDestinations
} from '../api/call-forward';
const RequestState = {
button: 'button',
@ -33,14 +35,13 @@ export default {
namespaced: true,
state: {
mappings: null,
sourcesets: null,
sourcesets: [],
sourceset: [],
timesets: null,
destinationsets: null,
destinations: {
online: [],
busy: [],
offline: []
},
destinations: [],
loadDestinationState: RequestState.button,
loadDestinationError: null,
removeDestinationState: RequestState.button,
removeDestinationError: null,
lastRemovedDestination: null,
@ -112,7 +113,21 @@ export default {
},
showDefinedAlert(state) {
return !state.timesetExists && !state.activeTimeForm && state.addTimeState !== 'succeeded';
},
destinationsLoaded(state) {
return state.destinations.length > 0;
},
showTimesAndDestinations(state) {
return state.timesetIsCompatible &&
!state.timesetHasReverse &&
!state.timesetHasDuplicate &&
state.timesetExists;
},
loadDestinationError(state) {
return state.loadDestinationError ||
i18n.t('pages.callForward.times.loadDestinationErrorMessage');
}
},
mutations: {
loadMappings(state, result) {
@ -261,6 +276,21 @@ export default {
state.timesetHasDuplicate = false;
state.activeTimeForm = false;
state.addTimeState = RequestState.button;
},
setSourceset(state, result) {
state.sourceset = result;
},
loadDestinationRequesting(state) {
state.loadDestinationState = RequestState.requesting;
state.loadDestinationError = null;
},
loadDestinationSucceeded(state) {
state.loadDestinationState = RequestState.succeeded;
state.loadDestinationError = null;
},
loadDestinationFailed(state, error) {
state.loadDestinationState = RequestState.failed;
state.loadDestinationError = error;
}
},
actions: {
@ -304,14 +334,6 @@ export default {
});
});
},
loadEverybodyDestinations(context, options) {
loadEverybodyDestinations({
subscriberId: localStorage.getItem('subscriberId'),
timeset: options.timeset
}).then((result)=>{
context.commit('loadDestinations', result);
});
},
deleteDestinationFromDestinationset(context, options) {
let removedDestination = options.removeDestination;
context.commit('removeDestinationRequesting');
@ -358,7 +380,8 @@ export default {
data: form,
groupName: context.getters.getGroupName,
id: context.getters.getDestinationsetId,
timesetId: timeset
timesetId: timeset,
sourcesetId: options.sourcesetId
};
if (options.destinations) {
return new Promise(() => {
@ -514,6 +537,18 @@ export default {
}).catch((err) => {
context.commit('addTimeFailed', err.message);
});
},
loadDestinations(context, options) {
context.commit('loadDestinationRequesting');
loadDestinations({
timeset: options.timeset,
subscriberId: context.getters.getSubscriberId
}).then((result) => {
context.commit('loadDestinations', result);
context.commit('loadDestinationSucceeded');
}).catch((err) => {
context.commit('loadDestinationFailed', err.message);
});
}
}
};

Loading…
Cancel
Save