What has been done: - TT#40522, Investigate and discover necessary API endpoints - TT#40523, Implement speed dial page, navigation menu entry and home page box - TT#40525, Implement UI display for list of speed dials - TT#40524, Implement API method for fetching speed dial slots 0-9 - TT#40526, Implement loading animation and error alert - TT#41016, Implement test API speed dial method Change-Id: I0b6fc4dab08913948bb8acf9c136bd56fe89da01changes/61/22561/8
parent
8e4fb6446b
commit
6117c5f6fe
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { getFieldList } from './common'
|
||||||
|
|
||||||
|
export function getSpeedDials(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
getFieldList({
|
||||||
|
path: 'api/speeddials/' + id,
|
||||||
|
field: 'speeddials'
|
||||||
|
}).then((result) => {
|
||||||
|
let sortedResult = _.sortBy(result, ['slot']);
|
||||||
|
resolve(sortedResult);
|
||||||
|
}).catch((err) => {
|
||||||
|
reject(err.body.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUnassignedSlots(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let slots = ["*0", "*1", "*2", "*3", "*4", "*5", "*6", "*7", "*8", "*9"];
|
||||||
|
Promise.resolve().then(() => {
|
||||||
|
return getSpeedDials(id);
|
||||||
|
}).then((assignedSlots) => {
|
||||||
|
// TODO: Split into own testable function that takes slots and
|
||||||
|
// unassigned slots, and outputs slotOptions array ready to be
|
||||||
|
// consumed by q-select
|
||||||
|
let unassignedSlots = _.difference(slots, assignedSlots.map((slot) => {
|
||||||
|
return slot.slot;
|
||||||
|
}));
|
||||||
|
resolve(unassignedSlots);
|
||||||
|
}).catch((err) => {
|
||||||
|
reject(err.body.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<csc-page class="csc-list-page">
|
||||||
|
<q-list
|
||||||
|
no-border
|
||||||
|
inset-separator
|
||||||
|
sparse
|
||||||
|
multiline
|
||||||
|
>
|
||||||
|
<q-item
|
||||||
|
v-for="(assigned, index) in assignedSlots"
|
||||||
|
:key="index"
|
||||||
|
class="csc-entity"
|
||||||
|
>
|
||||||
|
<q-item-side
|
||||||
|
icon="touch app"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
<q-item-main>
|
||||||
|
<q-item-tile label>
|
||||||
|
<span class="csc-entity-title">
|
||||||
|
{{ $t('speedDial.whenIDial', { slot: assigned.slot }) }}
|
||||||
|
</span>
|
||||||
|
</q-item-tile>
|
||||||
|
<q-item-tile sublabel>
|
||||||
|
{{ $t('speedDial.ring') }}
|
||||||
|
{{ assigned.destination | destinationFormat }}
|
||||||
|
</q-item-tile>
|
||||||
|
</q-item-main>
|
||||||
|
<q-item-side
|
||||||
|
right
|
||||||
|
class="csc-item-buttons"
|
||||||
|
>
|
||||||
|
<q-item-tile>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
icon="delete"
|
||||||
|
color="negative"
|
||||||
|
slot="right"
|
||||||
|
@click="deleteAssignment(index)"
|
||||||
|
/>
|
||||||
|
</q-item-tile>
|
||||||
|
</q-item-side>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
<div
|
||||||
|
v-if="assignedSlots.length === 0"
|
||||||
|
class="row justify-center"
|
||||||
|
>
|
||||||
|
{{ $t('speedDial.noResultsMessage') }}
|
||||||
|
</div>
|
||||||
|
</csc-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
import {
|
||||||
|
startLoading,
|
||||||
|
stopLoading,
|
||||||
|
showGlobalError
|
||||||
|
} from '../../helpers/ui'
|
||||||
|
import CscPage from '../CscPage'
|
||||||
|
import {
|
||||||
|
QList,
|
||||||
|
QItem,
|
||||||
|
QItemMain,
|
||||||
|
QItemTile,
|
||||||
|
QItemSide,
|
||||||
|
QChip,
|
||||||
|
QBtn
|
||||||
|
} from 'quasar-framework'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CscPage,
|
||||||
|
QList,
|
||||||
|
QItem,
|
||||||
|
QItemMain,
|
||||||
|
QItemTile,
|
||||||
|
QItemSide,
|
||||||
|
QChip,
|
||||||
|
QBtn
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.$store.dispatch('speedDial/loadSpeedDials');
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters('speedDial', [
|
||||||
|
'assignedSlots',
|
||||||
|
'speedDialLoadingState',
|
||||||
|
'speedDialLoadingError'
|
||||||
|
])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
deleteAssignment(index) {
|
||||||
|
console.log('deleteAssignment(), index', index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
speedDialLoadingState(state) {
|
||||||
|
if (state === 'requesting') {
|
||||||
|
startLoading();
|
||||||
|
}
|
||||||
|
else if (state === 'failed') {
|
||||||
|
stopLoading();
|
||||||
|
showGlobalError(this.speedDialLoadingError);
|
||||||
|
}
|
||||||
|
else if (state === 'succeeded') {
|
||||||
|
stopLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" rel="stylesheet/stylus">
|
||||||
|
</style>
|
@ -0,0 +1,62 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { i18n } from '../i18n';
|
||||||
|
import { RequestState } from './common'
|
||||||
|
import {
|
||||||
|
getSpeedDials
|
||||||
|
} from '../api/speed-dial';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state: {
|
||||||
|
assignedSlots: [],
|
||||||
|
slotOptions: [],
|
||||||
|
speedDialLoadingState: RequestState.initiated,
|
||||||
|
speedDialError: null
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
reminderLoadingState(state) {
|
||||||
|
return state.reminderLoadingState;
|
||||||
|
},
|
||||||
|
reminderError(state) {
|
||||||
|
return state.reminderError;
|
||||||
|
},
|
||||||
|
subscriberId(state, getters, rootState, rootGetters) {
|
||||||
|
return rootGetters['user/getSubscriberId'];
|
||||||
|
},
|
||||||
|
assignedSlots(state) {
|
||||||
|
return state.assignedSlots;
|
||||||
|
},
|
||||||
|
speedDialLoadingState(state) {
|
||||||
|
return state.speedDialLoadingState;
|
||||||
|
},
|
||||||
|
speedDialLoadingError(state) {
|
||||||
|
return state.speedDialLoadingError || i18n.t('speedDial.loadSpeedDialErrorMessage');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
speedDialRequesting(state) {
|
||||||
|
state.speedDialLoadingState = RequestState.requesting;
|
||||||
|
state.speedDialLoadingError = null;
|
||||||
|
},
|
||||||
|
speedDialSucceeded(state, slots) {
|
||||||
|
state.speedDialLoadingState = RequestState.succeeded;
|
||||||
|
state.assignedSlots = slots;
|
||||||
|
state.speedDialLoadingError = null;
|
||||||
|
},
|
||||||
|
speedDialFailed(state, error) {
|
||||||
|
state.speedDialLoadingState = RequestState.failed;
|
||||||
|
state.speedDialLoadingError = error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
loadSpeedDials(context) {
|
||||||
|
context.commit('speedDialRequesting');
|
||||||
|
getSpeedDials(context.getters.subscriberId).then((slots) => {
|
||||||
|
context.commit('speedDialSucceeded', slots);
|
||||||
|
}).catch((error) => {
|
||||||
|
context.commit('speedDialFailed', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
import VueResource from 'vue-resource';
|
||||||
|
import {
|
||||||
|
getFieldList
|
||||||
|
} from '../../src/api/common';
|
||||||
|
import {
|
||||||
|
getSpeedDials
|
||||||
|
} from '../../src/api/speed-dial';
|
||||||
|
import { assert } from 'chai';
|
||||||
|
|
||||||
|
Vue.use(VueResource);
|
||||||
|
|
||||||
|
describe('Speed Dials', function(){
|
||||||
|
|
||||||
|
const subscriberId = 123;
|
||||||
|
|
||||||
|
it('should get list of subscriber specific speed dials', function(done){
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
"_links" : {
|
||||||
|
"collection" : {
|
||||||
|
"href" : "/api/speeddials/"
|
||||||
|
},
|
||||||
|
"curies" : {
|
||||||
|
"href" : "http://purl.org/sipwise/ngcp-api/#rel-{rel}",
|
||||||
|
"name" : "ngcp",
|
||||||
|
"templated" : true
|
||||||
|
},
|
||||||
|
"ngcp:journal" : [
|
||||||
|
{
|
||||||
|
"href" : "/api/speeddials/323/journal/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ngcp:speeddials" : [
|
||||||
|
{
|
||||||
|
"href" : "/api/speeddials/323"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ngcp:subscribers" : [
|
||||||
|
{
|
||||||
|
"href" : "/api/subscribers/323"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"profile" : {
|
||||||
|
"href" : "http://purl.org/sipwise/ngcp-api/"
|
||||||
|
},
|
||||||
|
"self" : {
|
||||||
|
"href" : "/api/speeddials/323"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"speeddials" : [
|
||||||
|
{
|
||||||
|
"destination" : "sip:439965050@10.15.17.240",
|
||||||
|
"slot" : "*9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination" : "sip:22222222@10.15.17.240",
|
||||||
|
"slot" : "*0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination" : "sip:43665522@10.15.17.240",
|
||||||
|
"slot" : "*3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let fieldList = [
|
||||||
|
{
|
||||||
|
"destination" : "sip:22222222@10.15.17.240",
|
||||||
|
"slot" : "*0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination" : "sip:43665522@10.15.17.240",
|
||||||
|
"slot" : "*3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"destination" : "sip:439965050@10.15.17.240",
|
||||||
|
"slot" : "*9"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
Vue.http.interceptors = [];
|
||||||
|
Vue.http.interceptors.unshift((request, next)=>{
|
||||||
|
next(request.respondWith(JSON.stringify(data), {
|
||||||
|
status: 200
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
getSpeedDials(subscriberId).then((result)=>{
|
||||||
|
assert.deepEqual(result, fieldList);
|
||||||
|
done();
|
||||||
|
}).catch((err)=>{
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in new issue