TT#37651 Change station name of PBXDevice

What has been done:
- TT#37664, Extend field to also have write ability and save/reset
  functionality
- TT#37668, Implement loading animation
- TT#37666, Implement success toast
- TT#38006, Implement error message alert

Change-Id: I0801077859091b3a3b183c1b0150215a47d45b2a
changes/29/21629/8
raxelsen 7 years ago committed by Hans-Peter Herzog
parent 0c98a79946
commit 7cb906c7be

@ -8,12 +8,12 @@ import { LIST_ALL_ROWS } from './common';
export function getMappings(id) {
return new Promise((resolve, reject) => {
Vue.http.get('api/cfmappings/' + id).then(result => {
Vue.http.get('api/cfmappings/' + id).then((result) => {
let jsonBody = getJsonBody(result.body);
delete jsonBody._links;
delete jsonBody.cfs;
resolve(getJsonBody(result.body));
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -24,7 +24,7 @@ export function getSourcesets(id) {
Promise.resolve().then(() => {
return Vue.http.get('api/cfsourcesets/',
{ params: { subscriber_id: id, page: 1, rows: LIST_ALL_ROWS } })
}).then(result => {
}).then((result) => {
let totalCount = getJsonBody(result.body).total_count;
if (totalCount > LIST_ALL_ROWS) {
return Vue.http.get('api/cfsourcesets/',
@ -34,13 +34,13 @@ export function getSourcesets(id) {
else {
return Promise.resolve(result);
}
}).then(result => {
}).then((result) => {
let sourcesets = [];
if (getJsonBody(result.body)._embedded) {
sourcesets = getJsonBody(result.body)._embedded['ngcp:cfsourcesets'];
}
resolve(sourcesets);
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -51,7 +51,7 @@ export function getTimesets(id) {
Promise.resolve().then(() => {
return Vue.http.get('api/cftimesets/',
{ params: { subscriber_id: id, page: 1, rows: LIST_ALL_ROWS } })
}).then(result => {
}).then((result) => {
let totalCount = getJsonBody(result.body).total_count;
if (totalCount > LIST_ALL_ROWS) {
return Vue.http.get('api/cftimesets/',
@ -65,7 +65,7 @@ export function getTimesets(id) {
let response = getJsonBody(result.body)._embedded || [];
let timesets = response['ngcp:cftimesets'] || [];
resolve(timesets);
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -76,7 +76,7 @@ export function getDestinationsets(id) {
Promise.resolve().then(() => {
return Vue.http.get('api/cfdestinationsets/',
{ params: { subscriber_id: id, page: 1, rows: LIST_ALL_ROWS } })
}).then(result => {
}).then((result) => {
let totalCount = getJsonBody(result.body).total_count;
if (totalCount > LIST_ALL_ROWS) {
return Vue.http.get('api/cfdestinationsets/',
@ -86,9 +86,9 @@ export function getDestinationsets(id) {
else {
return Promise.resolve(result);
}
}).then(result => {
}).then((result) => {
resolve(getJsonBody(result.body)._embedded['ngcp:cfdestinationsets']);
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -236,7 +236,7 @@ export function deleteDestinationFromDestinationset(options) {
op: 'replace',
path: '/destinations',
value: options.data
}], { headers: headers }).then(result => {
}], { headers: headers }).then((result) => {
if (options.deleteDestinationset) {
deleteDestinationsetById(options.id).then((res) => {
resolve(res);
@ -247,7 +247,7 @@ export function deleteDestinationFromDestinationset(options) {
else {
resolve(result);
}
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -255,9 +255,9 @@ export function deleteDestinationFromDestinationset(options) {
export function deleteDestinationsetById(id) {
return new Promise((resolve, reject) => {
Vue.http.delete('api/cfdestinationsets/' + id).then(result => {
Vue.http.delete('api/cfdestinationsets/' + id).then((result) => {
resolve(result);
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -272,9 +272,9 @@ export function addDestinationToDestinationset(options) {
op: 'replace',
path: '/destinations',
value: options.data
}], { headers: headers }).then(result => {
}], { headers: headers }).then((result) => {
resolve(result);
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -284,9 +284,9 @@ export function addNewDestinationset() {
let destinationsetName = `csc-${Date.now()}`;
return new Promise((resolve, reject) => {
Vue.http.post('api/cfdestinationsets/', { name: destinationsetName })
.then(response => {
.then((response) => {
resolve(_.last(_.split(response.headers.get('Location'), '/')));
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -343,32 +343,30 @@ export function addDestinationToEmptyGroup(options) {
}
export function addNewMapping(options) {
let headers = { 'Content-Type': 'application/json-patch+json' };
return new Promise((resolve, reject) => {
let headers = { 'Content-Type': 'application/json-patch+json' };
Vue.http.patch('api/cfmappings/' + options.subscriberId, [{
op: 'replace',
path: '/' + options.group,
value: options.mappings
}], { headers: headers }).then(result => {
}], { headers: headers }).then((result) => {
resolve(result);
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
}
export function changePositionOfDestination(options) {
let headers = {
'Content-Type': 'application/json-patch+json'
};
return new Promise((resolve, reject) => {
let headers = { 'Content-Type': 'application/json-patch+json' };
Vue.http.patch('api/cfdestinationsets/' + options.id, [{
op: 'replace',
path: '/destinations',
value: options.destinations
}], { headers: headers }).then(result => {
}], { headers: headers }).then((result) => {
resolve(result);
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -586,7 +584,7 @@ export function deleteTimeFromTimeset(options) {
value: options.times
}], { headers: headers }).then((result) => {
resolve(result);
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -596,7 +594,7 @@ export function deleteTimesetById(id) {
return new Promise((resolve, reject) => {
Vue.http.delete('api/cftimesets/' + id).then(() => {
resolve();
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -631,7 +629,7 @@ export function addTimeToTimeset(options) {
value: options.times
}], { headers: headers }).then(() => {
resolve();
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -640,9 +638,9 @@ export function addTimeToTimeset(options) {
export function addNewTimeset(timesetName) {
return new Promise((resolve, reject) => {
Vue.http.post('api/cftimesets/', { name: timesetName })
.then(response => {
.then((response) => {
resolve(_.last(_.split(response.headers.get('Location'), '/')));
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -725,7 +723,7 @@ export function getTimesByTimesetId(id) {
let timeset = getJsonBody(res.body);
delete timeset['_links'];
resolve(timeset.times);
}).catch((err)=>{
}).catch((err) => {
reject(err);
});
});
@ -752,7 +750,7 @@ export function getSourcesBySourcesetId(id) {
Vue.http.get('api/cfsourcesets/' + id).then((res)=>{
let sourceset = getJsonBody(res.body);
resolve(sourceset.sources);
}).catch((err)=>{
}).catch((err) => {
reject(err);
});
});
@ -769,7 +767,7 @@ export function addSourceToSourceset(options) {
value: options.sources
}], { headers: headers }).then(() => {
resolve();
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -801,7 +799,7 @@ export function createSourcesetWithSource(options) {
}]
}).then(() => {
resolve();
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -811,7 +809,7 @@ export function deleteSourcesetById(id) {
return new Promise((resolve, reject) => {
Vue.http.delete('api/cfsourcesets/' + id).then(() => {
resolve();
}).catch(err => {
}).catch((err) => {
reject(err);
});
});
@ -838,7 +836,7 @@ export function deleteSourceFromSourcesetByIndex(options) {
value: sources
}], { headers: headers }).then(() => {
resolve();
}).catch(err => {
}).catch((err) => {
reject(err);
});
});

@ -456,3 +456,10 @@ export function updateDeviceKeys(deviceId, keys) {
});
}
export function setStationName(options) {
return patchReplace({
path: 'api/pbxdevices/' + options.id,
fieldPath: 'station_name',
value: options.station_name
});
}

@ -6,32 +6,95 @@
</q-item-tile>
</q-item-side>
<q-item-main :style="{zIndex: 10}">
<q-item-tile v-if="!expanded" label>{{ device.station_name }}</q-item-tile>
<q-item-tile v-if="!expanded" sublabel><span class="gt-sm">Model: </span>{{ name }}</q-item-tile>
<q-item-tile v-if="!expanded" sublabel><span class="gt-sm">MAC address: </span>{{ device.identifier }}</q-item-tile>
<q-item-tile v-if="expanded" class="csc-pbx-device-content">
<q-item-tile
v-if="!expanded"
label
>
{{ device.station_name }}
</q-item-tile>
<q-item-tile
v-if="!expanded"
sublabel
>
<span class="gt-sm">
Model:
</span>
{{ name }}
</q-item-tile>
<q-item-tile
v-if="!expanded"
sublabel
>
<span class="gt-sm">
MAC address:
</span>
{{ device.identifier }}
</q-item-tile>
<q-item-tile
v-if="expanded"
class="csc-pbx-device-content"
>
<q-field :label="$t('pbxConfig.deviceStationName')">
<q-input v-model="device.station_name" readonly />
<q-input
v-model="changes.stationName"
:after="stationNameButtons"
@keyup.enter="saveStationName"
/>
</q-field>
<q-field :label="$t('pbxConfig.deviceIdentifier')">
<q-input v-model="device.identifier" readonly />
<q-field
:label="$t('pbxConfig.deviceIdentifier')"
>
<q-input
v-model="device.identifier"
readonly
/>
</q-field>
<q-field :label="$t('pbxConfig.deviceModel')">
<p>{{ name }}</p>
</q-field>
<csc-pbx-device-config :device="device" :groupsAndSeatsOptions="groupsAndSeatsOptions" :loading="loading"
@loadGroupsAndSeats="loadGroupsAndSeats()" @keysChanged="keysChanged"
:subscribers="subscribers" />
<csc-pbx-device-config
:device="device"
:groupsAndSeatsOptions="groupsAndSeatsOptions"
:loading="loading"
@loadGroupsAndSeats="loadGroupsAndSeats()"
@keysChanged="keysChanged"
:subscribers="subscribers"
/>
</q-item-tile>
</q-item-main>
<q-item-side right class="csc-item-buttons" :style="{zIndex: 11}">
<q-item-side
right
class="csc-item-buttons"
:style="{zIndex: 11}"
>
<q-item-tile>
<q-btn :icon="titleIcon" :big="isMobile" color="primary" slot="right" flat @click="toggleMain()" />
<q-btn icon="delete" :big="isMobile" color="negative" slot="right" flat @click="remove()" />
<q-btn
:icon="titleIcon"
:big="isMobile"
color="primary"
slot="right"
flat
@click="toggleMain()"
/>
<q-btn
icon="delete"
:big="isMobile"
color="negative"
slot="right"
flat
@click="remove()"
/>
</q-item-tile>
</q-item-side>
<q-inner-loading v-if="loading" :visible="loading" :style="{zIndex: 12}">
<q-spinner-mat size="60px" color="primary"></q-spinner-mat>
<q-inner-loading
v-if="loading"
:visible="loading"
:style="{zIndex: 12}"
>
<q-spinner-mat
size="60px"
color="primary"
/>
</q-inner-loading>
</q-item>
</template>
@ -61,7 +124,8 @@
data () {
return {
expanded: false,
modalOpened: false
modalOpened: false,
changes: this.getDevice()
}
},
computed: {
@ -84,6 +148,41 @@
},
name() {
return _.get(this.device, 'profile.name', '...');
},
stationNameButtons() {
let buttons = [];
let self = this;
if(this.stationNameHasChanges) {
buttons.push({
icon: 'check',
error: false,
handler (event) {
event.stopPropagation();
self.saveStationName();
}
}, {
icon: 'clear',
error: false,
handler (event) {
event.stopPropagation();
self.resetStationName();
}
}
);
}
return buttons;
},
stationName() {
return this.device.station_name;
},
deviceModel() {
return {
id: this.changes.id,
station_name: this.changes.stationName
}
},
stationNameHasChanges() {
return this.stationName !== this.changes.stationName;
}
},
mounted() {
@ -104,6 +203,23 @@
device: this.device,
keys: keys
});
},
getDevice() {
return {
id: this.device.id,
stationName: this.device.station_name
}
},
resetStationName() {
this.changes.stationName = this.device.station_name;
},
saveStationName() {
this.$emit('save-station-name', this.deviceModel);
}
},
watch: {
device() {
this.changes = this.getDevice();
}
}
}

@ -2,29 +2,69 @@
<div class="row justify-center">
<div v-if="formEnabled" class="col col-md-6 col-sm-12">
<q-field>
<q-input v-model="data.station_name" :disabled="loading" :readonly="loading" autofocus
:float-label="$t('pbxConfig.deviceStationName')" clearable />
<q-input
v-model="data.station_name"
:disabled="loading"
:readonly="loading"
autofocus
:float-label="$t('pbxConfig.deviceStationName')"
clearable
/>
</q-field>
<q-field>
<q-input v-model="data.identifier" :disabled="loading" :readonly="loading"
:float-label="$t('pbxConfig.deviceIdentifier')" clearable />
<q-input
v-model="data.identifier"
:disabled="loading"
:readonly="loading"
:float-label="$t('pbxConfig.deviceIdentifier')"
clearable
/>
</q-field>
<q-field>
<csc-pbx-model-select :profiles="profiles" :modelImages="modelImages"
@opened="modelSelectOpened()" @select="selectProfile" />
<csc-pbx-model-select
:profiles="profiles"
:modelImages="modelImages"
:label="$t('pbxConfig.deviceModel')"
@opened="modelSelectOpened()"
@select="selectProfile"
/>
</q-field>
<div class="row justify-center form-actions">
<q-btn v-if="!loading" flat color="secondary"
icon="clear" @click="cancel()">{{ $t('buttons.cancel') }}</q-btn>
<q-btn v-if="!loading" flat color="primary"
icon="done" @click="save()">{{ $t('buttons.save') }}</q-btn>
<div
class="row justify-center form-actions"
>
<q-btn
v-if="!loading"
flat color="secondary"
icon="clear"
@click="cancel()"
>{{ $t('buttons.cancel') }}</q-btn>
<q-btn
v-if="!loading"
flat color="primary"
icon="done"
@click="save()"
>{{ $t('buttons.save') }}</q-btn>
</div>
</div>
<div v-else class="row justify-center">
<q-btn color="primary" icon="add" flat @click="enableForm()">Add device</q-btn>
<div
v-else
class="row justify-center"
>
<q-btn
color="primary"
icon="add"
flat
@click="enableForm()"
>Add device</q-btn>
</div>
<q-inner-loading v-show="loading" :visible="loading">
<q-spinner-mat size="60px" color="primary" />
<q-inner-loading
v-show="loading"
:visible="loading"
>
<q-spinner-mat
size="60px"
color="primary"
/>
</q-inner-loading>
</div>
</template>

@ -363,8 +363,9 @@
},
watch: {
device() {
this.openKeyOverlay(this.selectedKey, this.selectedKeyIndex);
this.$forceUpdate();
if(this.keyOverlayActive) {
this.selectedLine = this.getLineByKey(this.selectedKeyIndex);
}
}
}
}

@ -1,6 +1,5 @@
<template>
<csc-page
:title="$t('pbxConfig.devicesTitle')"
class="csc-list-page"
>
<q-list
@ -38,7 +37,8 @@
@change="changePage"
/>
</div>
<div v-if="isListLoadingVisible"
<div
v-if="isListLoadingVisible"
class="row justify-center"
>
<q-spinner-dots
@ -48,7 +48,8 @@
</div>
</q-item-main>
</q-item>
<csc-pbx-device v-for="device in devices"
<csc-pbx-device
v-for="device in devices"
:key="device.id"
:device="device"
:loading="isDeviceLoading(device.id)"
@ -57,6 +58,7 @@
@remove="removeDevice"
@loadGroupsAndSeats="loadGroupsAndSeats()"
@deviceKeysChanged="deviceKeysChanged"
@save-station-name="setStationName"
/>
</q-list>
<div
@ -124,7 +126,10 @@
'profileOptions',
'listProfilesState',
'listProfilesError',
'modelImages'
'modelImages',
'updatedDevice',
'updatedDeviceSucceeded',
'updatedDeviceError'
]),
noDeviceMessage() {
if (this.profile) {
@ -197,6 +202,9 @@
this.$store.dispatch('pbxConfig/listDevices', {
page: 1
});
},
setStationName(device) {
this.$store.dispatch('pbxConfig/setStationName', device);
}
},
watch: {
@ -209,7 +217,7 @@
},
updatedDeviceKey(data) {
if(data !== null) {
showToast(this.$t('pbxConfig.toasts.updatedDeviceKeys',{
showToast(this.$t('pbxConfig.toasts.updatedDeviceKeys', {
name: data.device.station_name
}));
}
@ -231,14 +239,24 @@
if (state === 'failed') {
showGlobalError(this.listProfilesError);
}
},
updatedDeviceSucceeded(succeeded) {
if(succeeded === true) {
showToast(this.$t('pbxConfig.toasts.updatedStationName', {
name: this.updatedDevice.station_name
}));
}
},
updatedDeviceError(err) {
if (err !== null) {
showGlobalError(err);
}
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.filter-model-select
margin 16px 16px 8px 16px
</style>

@ -25,7 +25,7 @@
</q-popover>
</div>
<div v-if="selectedProfile.device_id != null" class="csc-pbx-model-image">
<img :src="frontImageUrl(selectedProfile.device_id)" />
<img :src="frontImageUrl(selectedProfile.device_id)" class="csc-pbx-model-select-preview" />
</div>
</div>
</template>
@ -96,7 +96,7 @@
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/quasar.variables';
.csc-pbx-model-list
.q-item-avatar
img
@ -105,7 +105,12 @@
.csc-pbx-model-image
margin-top 16px
text-align center
img
width: 25%
@media (max-width: $breakpoint-sm)
img
width: 50%
width 40%
</style>

@ -79,7 +79,8 @@
'lastRemovedSeat',
'lastUpdatedField',
'updateAliasNumbersState',
'updateGroupsAndSeatsState'
'updateGroupsAndSeatsState',
'updateState'
]),
groupOptions() {
let groups = [];

@ -295,6 +295,7 @@
"removedSeatToast": "Removed seat {seat}",
"removedDeviceToast": "Removed device {name}",
"updatedDeviceKeys": "Updated keys of device {name}",
"updatedStationName": "Updated station name to {name}",
"createdDevice": "Created device {name} successfully"
},
"removeDevice": "Remove device",

@ -1,9 +1,14 @@
'use strict';
import _ from 'lodash';
import { assignNumbers } from '../../api/user';
import { addGroup, removeGroup, addSeat, removeSeat, setGroupName,
import {
assignNumbers
} from '../../api/user';
import {
addGroup,
removeGroup,
addSeat,
removeSeat,
setGroupName,
setGroupExtension,
setGroupHuntPolicy,
setGroupHuntTimeout,
@ -20,7 +25,8 @@ import { addGroup, removeGroup, addSeat, removeSeat, setGroupName,
getSeatList,
getDeviceList,
getDevice,
getAllGroupsAndSeats
getAllGroupsAndSeats,
setStationName
} from '../../api/pbx-config'
export default {
@ -287,18 +293,22 @@ export default {
}).catch((err)=>{
context.commit('updateDeviceKeyFailed', data.device.id, err);
});
},
listProfiles(context) {
context.commit('listProfilesRequesting');
getProfiles({ all: true }).then((profiles)=>{
context.commit('listProfilesSucceeded', profiles);
}).catch((err)=>{
context.commit('listProfilesFailed', err.message);
});
},
setStationName(context, device) {
context.commit('updateStationNameRequesting', device);
setStationName(device).then(() => {
context.commit('updateStationNameSucceeded');
context.dispatch('loadDevice', device.id);
}).catch((err) => {
context.commit('updateStationNameFailed', err.message);
});
}
// filterDevices(context, params) {
// context.commit('deviceListRequesting', {
// silent: false
// });
// filterDeviceList(params).then((devices)=>{
// context.commit('deviceListSucceeded', devices);
// devices.items.forEach((device)=>{
// context.dispatch('loadDevice', device.id);
// });
// }).catch((err)=>{
// context.commit('deviceListFailed', err.message);
// });
// }
}

@ -141,7 +141,7 @@ export default {
return state.listLastPage;
},
isDeviceLoading(state) {
return (id)=>{
return (id) => {
return state.deviceStates[id + ""] === RequestState.requesting;
}
},
@ -250,7 +250,19 @@ export default {
listProfilesError(state) {
return state.listError;
},
updatedStationName(state) {
return state.updatedStationName;
},
modelImages(state) {
return state.modelImages;
},
updatedDevice(state) {
return state.updatedDevice;
},
updatedDeviceSucceeded(state) {
return state.updatedDeviceState === 'succeeded';
},
updatedDeviceError(state) {
return state.updatedDeviceError;
}
}

@ -285,5 +285,18 @@ export default {
listProfilesFailed(state, error) {
state.listProfilesState = RequestState.failed;
state.listProfilesError = error;
},
updateStationNameRequesting(state, deviceId) {
state.updatedDevice = deviceId;
state.updatedDeviceState = RequestState.requesting;
state.updatedDeviceError = null;
},
updateStationNameSucceeded(state) {
state.updatedDeviceState = RequestState.succeeded;
state.updatedDeviceError = null;
},
updateStationNameFailed(state, error) {
state.updatedDeviceState = RequestState.failed;
state.updatedDeviceError = error;
}
}

@ -51,6 +51,9 @@ export default {
createDeviceError: null,
listProfilesState: RequestState.initiated,
listProfilesError: null,
updatedDevice: null,
updatedDeviceState: RequestState.initiated,
updatedDeviceError: null,
modelImageStates: {},
modelImageErrors: {},
modelImages: {},

Loading…
Cancel
Save