TT#28062 Change order of destination

What has been done:
- TT#30679, CallForwarding: Implement UI icons and flow
- TT#30395, CallForwarding: Implement api requests
- TT#30680, CallForwarding: Implement store and state management

What is remaining (if we deem it necessary):
- TT#30763, CallForwarding: Create unit test

Change-Id: I0fb606327c12075a72eff43c901a2881b2af9981
changes/22/18522/11
raxelsen 8 years ago committed by Hans-Peter Herzog
parent 38d68c1d6e
commit 8666f25670

@ -119,9 +119,9 @@ export function loadAlwaysEverybodyDestinations(subscriberId) {
Promise.all(cfbPromises) Promise.all(cfbPromises)
]); ]);
}).then((res)=>{ }).then((res)=>{
computeLowestPriorityAndAddGroupName(res[0], 'cfu'); addGroupNames(res[0], 'cfu');
computeLowestPriorityAndAddGroupName(res[1], 'cfna'); addGroupNames(res[1], 'cfna');
computeLowestPriorityAndAddGroupName(res[2], 'cfb'); addGroupNames(res[2], 'cfb');
resolve({ resolve({
online: res[0], online: res[0],
offline: res[1], offline: res[1],
@ -133,10 +133,8 @@ export function loadAlwaysEverybodyDestinations(subscriberId) {
}); });
} }
export function computeLowestPriorityAndAddGroupName(group, groupName) { export function addGroupNames(group, groupName) {
group.forEach(destinationset => { group.forEach(destinationset => {
let lowest = _.maxBy(destinationset.destinations, 'priority') || { priority: 1 };
destinationset.lowestPriority = lowest.priority;
destinationset.groupName = groupName; destinationset.groupName = groupName;
}); });
return group; return group;
@ -147,6 +145,9 @@ export function getDestinationsetById(id) {
Vue.http.get('/api/cfdestinationsets/' + id).then((res)=>{ Vue.http.get('/api/cfdestinationsets/' + id).then((res)=>{
let destinationset = getJsonBody(res.body); let destinationset = getJsonBody(res.body);
delete destinationset['_links']; delete destinationset['_links'];
destinationset.destinations.sort((a, b) => {
return parseFloat(a.priority) - parseFloat(b.priority);
});
resolve(destinationset); resolve(destinationset);
}).catch((err)=>{ }).catch((err)=>{
reject(err); reject(err);
@ -274,8 +275,11 @@ export function addNewMapping(options) {
'Content-Type': 'application/json-patch+json' 'Content-Type': 'application/json-patch+json'
}; };
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let mappingsToSend = [{ destinationset_id: options.destinationsetId, let mappingsToSend = [{
sourceset_id: null, timeset_id: null }]; destinationset_id: options.destinationsetId,
sourceset_id: null,
timeset_id: null
}];
Vue.http.patch('/api/cfmappings/' + options.subscriberId, [{ Vue.http.patch('/api/cfmappings/' + options.subscriberId, [{
op: 'replace', op: 'replace',
path: '/' + options.group, path: '/' + options.group,
@ -287,3 +291,88 @@ export function addNewMapping(options) {
}); });
}); });
} }
export function changePositionOfDestination(options) {
let headers = {
'Content-Type': 'application/json-patch+json'
};
return new Promise((resolve, reject) => {
Vue.http.patch('/api/cfdestinationsets/' + options.id, [{
op: 'replace',
path: '/destinations',
value: options.destinations
}], { headers: headers }).then(result => {
resolve(result);
}).catch(err => {
reject(err);
});
});
}
export function moveDestinationUp(options) {
return new Promise((resolve, reject)=> {
Promise.resolve().then(() => {
let getPromises = [];
getPromises.push(getDestinationsetById(options.prevId));
getPromises.push(getDestinationsetById(options.id));
return Promise.all(getPromises);
}).then((destinationsets) => {
let updatePromises = [];
let lastDestinationPrevId = _.findLast(destinationsets[0].destinations) || {};
let lowestPriorityPrevId = lastDestinationPrevId.priority || 1;
let prevDestinations = destinationsets[0].destinations;
let currentDestinations = destinationsets[1].destinations;
let prevDestinationsMoveToIndex = prevDestinations.length < 2 ?
1 : prevDestinations.length-2;
options.destination.priority = lowestPriorityPrevId;
prevDestinations.splice(prevDestinationsMoveToIndex, 0, options.destination);
currentDestinations.shift();
updatePromises.push(addDestinationToDestinationset({
id: options.prevId,
data: prevDestinations
}));
updatePromises.push(deleteDestinationFromDestinationset({
id: options.id,
data: currentDestinations
}));
return Promise.all(updatePromises);
}).then(() => {
resolve();
}).catch((err) => {
reject(err);
});
});
}
export function moveDestinationDown(options) {
return new Promise((resolve, reject)=> {
Promise.resolve().then(() => {
let getPromises = [];
getPromises.push(getDestinationsetById(options.nextId));
getPromises.push(getDestinationsetById(options.id));
return Promise.all(getPromises);
}).then((destinationsets) => {
let updatePromises = [];
let firstDestinationNextId = _.head(destinationsets[0].destinations) || {};
let highestPriorityNextId = firstDestinationNextId.priority || 1;
let nextDestinations = destinationsets[0].destinations;
let currentDestinations = destinationsets[1].destinations;
options.destination.priority = highestPriorityNextId;
nextDestinations.splice(1, 0, options.destination);
currentDestinations.pop();
updatePromises.push(addDestinationToDestinationset({
id: options.nextId,
data: nextDestinations
}));
updatePromises.push(deleteDestinationFromDestinationset({
id: options.id,
data: currentDestinations
}));
return Promise.all(updatePromises);
}).then(() => {
resolve();
}).catch((err) => {
reject(err);
});
});
}

@ -41,6 +41,7 @@
<script> <script>
import _ from 'lodash'
import { startLoading, stopLoading, import { startLoading, stopLoading,
showGlobalError, showToast } from '../../../helpers/ui' showGlobalError, showToast } from '../../../helpers/ui'
import { normalizeTerminationInput } from '../../../filters/number-format' import { normalizeTerminationInput } from '../../../filters/number-format'
@ -128,12 +129,13 @@
}, },
methods: { methods: {
enableForm(type) { enableForm(type) {
let lastDestination = _.findLast(this.destinations) || {};
this.formEnabled = true; this.formEnabled = true;
this.$store.dispatch('callForward/setFormType', type); this.$store.dispatch('callForward/setFormType', type);
this.$store.dispatch('callForward/setActiveForm', this.groupName); this.$store.dispatch('callForward/setActiveForm', this.groupName);
this.$store.dispatch('callForward/setDestinationsetId', this.id); this.$store.dispatch('callForward/setDestinationsetId', this.id);
this.$store.dispatch('callForward/setGroupName', this.groupName); this.$store.dispatch('callForward/setGroupName', this.groupName);
this.$store.dispatch('callForward/setPriority', this.priority); this.$store.dispatch('callForward/setPriority', lastDestination.priority || 1);
if (type === 'voicebox') { if (type === 'voicebox') {
this.destinationForm.destination = 'Voicemail'; this.destinationForm.destination = 'Voicemail';
} else if (type === 'fax2mail') { } else if (type === 'fax2mail') {

@ -25,8 +25,24 @@
</span> </span>
</div> </div>
</q-item-main> </q-item-main>
<q-item-side right> <q-item-side class="dest-btns" right>
<q-btn color="negative" flat icon="delete" <span v-if="destinations.length > 1">
<q-btn flat
:class="{btnhidden: hasNoDownOption(index)}"
color="secondary"
icon="keyboard_arrow_down"
@click="moveDestination('down', index)">
</q-btn>
<q-btn flat
:class="{btnhidden: hasNoUpOption(index)}"
color="secondary"
icon="keyboard_arrow_up"
@click="moveDestination('up', index)">
</q-btn>
</span>
<q-btn flat
color="negative"
icon="delete"
@click="deleteDestination(index)"> @click="deleteDestination(index)">
{{ $t('buttons.remove') }} {{ $t('buttons.remove') }}
</q-btn> </q-btn>
@ -36,16 +52,20 @@
</template> </template>
<script> <script>
import { mapState } from 'vuex'
import numberFormat from '../../../filters/number-format' import numberFormat from '../../../filters/number-format'
import _ from 'lodash' import _ from 'lodash'
import { showToast } from '../../../helpers/ui' import { startLoading, stopLoading,
showGlobalError, showToast } from '../../../helpers/ui'
import { QItem, QItemMain, QItemSide, Toast, import { QItem, QItemMain, QItemSide, Toast,
Dialog, QBtn } from 'quasar-framework' Dialog, QBtn } from 'quasar-framework'
export default { export default {
name: 'csc-destination', name: 'csc-destination',
props: [ props: [
'destinations', 'destinations',
'id' 'id',
'prevDestId',
'nextDestId'
], ],
components: { components: {
QItem, QItem,
@ -56,8 +76,39 @@
QBtn QBtn
}, },
computed: { computed: {
...mapState('callForward', [
'changeDestinationState',
'changeDestinationError'
])
},
watch: {
changeDestinationState(state) {
if (state === 'failed') {
stopLoading();
showGlobalError(this.changeDestinationError);
} else if (state === 'succeeded') {
stopLoading();
}
}
}, },
methods: { methods: {
hasNoDownOption(index) {
return index === this.destinations.length-1 && !this.nextDestId;
},
hasNoUpOption(index) {
return index === 0 && !this.prevDestId;
},
moveDestination(direction, index) {
startLoading();
this.$store.dispatch('callForward/changePositionOfDestination', {
destinations: this.destinations,
id: this.id,
index: index,
direction: direction,
nextId: this.nextDestId,
prevId: this.prevDestId
});
},
isNumber(destination) { isNumber(destination) {
let dest = destination.split(/:|@/); let dest = destination.split(/:|@/);
if (dest[2] === 'fax2mail.local') { if (dest[2] === 'fax2mail.local') {
@ -110,4 +161,10 @@
.dest-row .dest-row
.dest-values .dest-values
font-weight 500 font-weight 500
.dest-btns
display inline-block
.btnhidden
opacity 0
.btnvisible
opacity 1
</style> </style>

@ -13,8 +13,10 @@
</div> </div>
</q-item> </q-item>
</div> </div>
<div v-else v-for="destinationset in group"> <div v-else v-for="(destinationset, index) in group">
<csc-destination v-bind="destinationset"> <csc-destination v-bind="destinationset"
:prev-dest-id="previousDestinationsetId(index)"
:next-dest-id="nextDestinationsetId(index)">
</csc-destination> </csc-destination>
</div> </div>
</q-list> </q-list>
@ -52,9 +54,18 @@
lastDestinationset() { lastDestinationset() {
let destinationset = _.findLast(this.group) || {}; let destinationset = _.findLast(this.group) || {};
destinationset.groupName = this.groupName; destinationset.groupName = this.groupName;
destinationset.priority = destinationset.lowestPriority || 1;
return destinationset; return destinationset;
} }
},
methods: {
previousDestinationsetId(index) {
let destinationset = this.group[index-1] || {};
return destinationset.id || null;
},
nextDestinationsetId(index) {
let destinationset = this.group[index+1] || {};
return destinationset.id || null;
}
} }
} }
</script> </script>

@ -1,16 +1,16 @@
'use strict'; 'use strict';
import _ from 'lodash'; import { getSourcesets, getDestinationsets,
import _ from 'lodash';
import { getSourcesets,
getDestinationsets,
getTimesets, getTimesets,
getMappings, getMappings,
loadAlwaysEverybodyDestinations, loadAlwaysEverybodyDestinations,
deleteDestinationFromDestinationset, deleteDestinationFromDestinationset,
addDestinationToDestinationset, addDestinationToDestinationset,
addDestinationToEmptyGroup, addDestinationToEmptyGroup,
addDestinationToExistingGroup } from '../api/call-forward'; addDestinationToExistingGroup,
changePositionOfDestination,
moveDestinationUp,
moveDestinationDown } from '../api/call-forward';
const AddDestinationState = { const AddDestinationState = {
button: 'button', button: 'button',
@ -19,6 +19,13 @@ const AddDestinationState = {
failed: 'failed' failed: 'failed'
}; };
const ChangeDestinationState = {
button: 'button',
requesting: 'requesting',
succeeded: 'succeeded',
failed: 'failed'
};
export default { export default {
namespaced: true, namespaced: true,
state: { state: {
@ -33,6 +40,8 @@ export default {
}, },
addDestinationState: AddDestinationState.button, addDestinationState: AddDestinationState.button,
addDestinationError: null, addDestinationError: null,
changeDestinationState: ChangeDestinationState.button,
changeDestinationError: null,
activeForm: '', activeForm: '',
formType: '', formType: '',
destinationsetId: '', destinationsetId: '',
@ -125,6 +134,18 @@ export default {
addDestinationFailed(state, error) { addDestinationFailed(state, error) {
state.addDestinationState = AddDestinationState.failed; state.addDestinationState = AddDestinationState.failed;
state.addDestinationError = error; state.addDestinationError = error;
},
changeDestinationRequesting(state) {
state.changeDestinationState = ChangeDestinationState.requesting;
state.changeDestinationError = null;
},
changeDestinationSucceeded(state) {
state.changeDestinationState = ChangeDestinationState.succeeded;
state.changeDestinationError = null;
},
changeDestinationFailed(state, error) {
state.changeDestinationState = ChangeDestinationState.failed;
state.changeDestinationError = error;
} }
}, },
actions: { actions: {
@ -234,6 +255,64 @@ export default {
}); });
} }
}, },
changePositionOfDestination(context, options) {
let clonedDestinations = _.cloneDeep(options.destinations);
let clonedDestination = _.clone(options.destinations[options.index]);
let lastIndex = clonedDestinations.length < 1 ?
0 : clonedDestinations.length - 1;
context.commit('changeDestinationRequesting');
if (options.direction === 'up' && options.prevId && options.index === 0) {
return new Promise((resolve, reject) => {
moveDestinationUp({
prevId: options.prevId,
id: options.id,
destination: clonedDestination
}).then(() => {
context.commit('changeDestinationSucceeded');
context.dispatch('loadAlwaysEverybodyDestinations');
}).catch((err) => {
context.commit('changeDestinationFailed', err.message);
});
});
} else if (options.direction === 'down' && options.nextId && options.index === lastIndex) {
return new Promise((resolve, reject) => {
moveDestinationDown({
nextId: options.nextId,
id: options.id,
destination: clonedDestination
}).then(() => {
context.commit('changeDestinationSucceeded');
context.dispatch('loadAlwaysEverybodyDestinations');
}).catch((err) => {
context.commit('changeDestinationFailed', err.message);
});
});
} else {
let adjacentDestination = options.direction === 'up' ?
options.destinations[options.index-1] :
options.destinations[options.index+1];
let adjacentPriority = adjacentDestination ?
adjacentDestination.priority : 1;
let adjacentIndex = options.direction === 'up' ?
options.index - 1 :
options.index + 1;
clonedDestinations.splice(options.index, 1);
clonedDestinations.splice(adjacentIndex, 0, clonedDestination);
clonedDestinations[adjacentIndex].priority = adjacentPriority;
return new Promise((resolve, reject) => {
changePositionOfDestination({
destinations: clonedDestinations,
id: options.id,
subscriberId: context.getters.getSubscriberId
}).then(() => {
context.commit('changeDestinationSucceeded');
context.dispatch('loadAlwaysEverybodyDestinations');
}).catch((err) => {
context.commit('changeDestinationFailed', err.message);
});
});
}
},
setActiveForm(context, value) { setActiveForm(context, value) {
context.commit('setActiveForm', value); context.commit('setActiveForm', value);
}, },

Loading…
Cancel
Save